KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ivata > groupware > business > mail > MailImpl


1 /*
2  * Copyright (c) 2001 - 2005 ivata limited.
3  * All rights reserved.
4  * -----------------------------------------------------------------------------
5  * ivata groupware may be redistributed under the GNU General Public
6  * License as published by the Free Software Foundation;
7  * version 2 of the License.
8  *
9  * These programs are free software; you can redistribute them and/or
10  * modify them under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; version 2 of the License.
12  *
13  * These programs are distributed in the hope that they will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  * See the GNU General Public License in the file LICENSE.txt for more
18  * details.
19  *
20  * If you would like a copy of the GNU General Public License write to
21  *
22  * Free Software Foundation, Inc.
23  * 59 Temple Place - Suite 330
24  * Boston, MA 02111-1307, USA.
25  *
26  *
27  * To arrange commercial support and licensing, contact ivata at
28  * http://www.ivata.com/contact.jsp
29  * -----------------------------------------------------------------------------
30  * $Log: MailImpl.java,v $
31  * Revision 1.6.2.1 2005/10/08 17:36:37 colinmacleod
32  * SettingDateFormatter now requires SecuritySession in constructor.
33  *
34  * Revision 1.6 2005/04/29 02:48:20 colinmacleod
35  * Data bugfixes.
36  * Changed primary key back to Integer.
37  *
38  * Revision 1.5 2005/04/27 15:20:09 colinmacleod
39  * Now implements Serializable.
40  *
41  * Revision 1.4 2005/04/22 10:59:12 colinmacleod
42  * Added logging when there is no mail
43  * server and reordered this file alphabetically.
44  *
45  * Revision 1.3 2005/04/10 20:10:08 colinmacleod
46  * Added new themes.
47  * Changed id type to String.
48  * Changed i tag to em and b tag to strong.
49  * Improved PicoContainerFactory with NanoContainer scripts.
50  *
51  * Revision 1.2 2005/04/09 17:20:00 colinmacleod
52  * Changed copyright text to GPL v2 explicitly.
53  *
54  * Revision 1.1.1.1 2005/03/10 17:51:15 colinmacleod
55  * Restructured ivata op around Hibernate/PicoContainer.
56  * Renamed ivata groupware.
57  *
58  * Revision 1.6 2004/11/12 15:57:23 colinmacleod
59  * Removed dependencies on SSLEXT.
60  * Moved Persistence classes to ivata masks.
61  *
62  * Revision 1.5 2004/11/03 17:15:38 colinmacleod
63  * added addUserEmailAddresses method.
64  * Improved setUesrAliases to check telecom addresses in the person.
65  *
66  * Revision 1.4 2004/09/30 15:09:33 colinmacleod
67  * Bug fixes
68  *
69  * Revision 1.3 2004/07/18 21:59:24 colinmacleod
70  * Removed Person from User - now you need to use addressbook/persistence manager to find the person (makes the app run faster.)
71  *
72  * Revision 1.2 2004/07/13 19:48:12 colinmacleod
73  * Moved project to POJOs from EJBs.
74  * Applied PicoContainer to services layer (replacing session EJBs).
75  * Applied Hibernate to persistence layer (replacing entity EJBs).
76  *
77  * Revision 1.1 2004/03/27 10:31:26 colinmacleod
78  * Split off business logic from remote facades to POJOs.
79  *
80  * Revision 1.6 2004/03/21 21:16:39 colinmacleod
81  * Shortened name to ivata op.
82  *
83  * Revision 1.5 2004/03/21 20:51:51 colinmacleod
84  * Change SecurityServer into interface.
85  * Added checking of mail server.
86  *
87  * Revision 1.4 2004/03/10 22:43:13 colinmacleod
88  * Added security server exception handling.
89  *
90  * Revision 1.3 2004/02/10 19:57:26 colinmacleod
91  * Changed email address.
92  *
93  * Revision 1.2 2004/02/01 22:07:32 colinmacleod
94  * Added full names to author tags
95  *
96  * Revision 1.1.1.1 2004/01/27 20:59:56 colinmacleod
97  * Moved ivata openportal to SourceForge..
98  *
99  * Revision 1.6 2003/12/12 13:24:34 jano
100  * fixing webmail functionality
101  *
102  * Revision 1.5 2003/11/03 11:31:06 jano
103  * commiting webmail,
104  * tryinjg to fix deploying problem
105  *
106  * Revision 1.4 2003/10/28 13:27:51 jano
107  * commiting webmail,
108  * still fixing compile and building openGroupware project
109  *
110  * Revision 1.3 2003/10/15 14:13:00 jano
111  * converting to XDoclet
112  *
113  * Revision 1.2 2003/10/15 14:11:33 colin
114  * fixing for XDoclet
115  *
116  * Revision 1.25 2003/07/15 06:43:40 peter
117  * fixed the last fix
118  *
119  * Revision 1.24 2003/07/15 06:01:59 peter
120  * fixed message text bugs and composed attachments size bug
121  *
122  * Revision 1.23 2003/07/14 15:04:22 jano
123  * peter: fixed invisible attachments problem
124  *
125  * Revision 1.22 2003/07/14 14:52:24 jano
126  * fixing bug in mailBean
127  *
128  * Revision 1.21 2003/07/11 06:31:06 peter
129  * fixed text logic in alternative multiparts
130  *
131  * Revision 1.20 2003/07/07 13:43:32 peter
132  * fixed getAttachment for cases with fileName
133  *
134  * Revision 1.19 2003/06/22 21:28:10 peter
135  * re-fixed attachment handling for multipart cases
136  *
137  * Revision 1.18 2003/06/20 18:31:03 peter
138  * added incorrectly composed mail forwards and self contained attachment like email handling
139  *
140  * Revision 1.17 2003/06/19 10:06:08 jano
141  * add check boxies in registration proces of customer
142  *
143  * Revision 1.16 2003/06/02 06:30:19 peter
144  * create reply and forward message fixed
145  *
146  * Revision 1.15 2003/05/28 05:41:21 peter
147  * added fileName as secondary attachments identifier, when contentId not present
148  *
149  * Revision 1.14 2003/05/27 17:15:12 peter
150  * getAttachment fixed, private getAttachment methnod added
151  *
152  * Revision 1.13 2003/05/15 08:21:12 peter
153  * fixed addMultipart logic - some multipart types weren't included
154  *
155  * Revision 1.12 2003/05/14 11:22:07 peter
156  * fixed bug: getDOFromJavamailMessage was called after folder closed in appendAttachmnets
157  *
158  * Revision 1.11 2003/05/13 15:24:18 peter
159  * attachment compose changes
160  *
161  * Revision 1.10 2003/05/12 16:31:13 peter
162  * attachment compose changes
163  *
164  * Revision 1.9 2003/04/01 17:58:52 colin
165  * removed boolean from InternetAddress constructor (marked as private in my JVM)
166  *
167  * Revision 1.8 2003/03/25 16:18:30 peter
168  * fixed email address validation
169  *
170  * Revision 1.7 2003/03/25 08:23:29 jano
171  * if there is no message in folder -> return null
172  * and validate the email addresses
173  *
174  * Revision 1.6 2003/03/14 10:26:46 jano
175  * adding backdoor man functionality
176  * backdoor man = briezky
177  *
178  * Revision 1.5 2003/03/03 16:57:12 colin
179  * converted localization to automatic paths
180  * added labels
181  * added mandatory fieldName attribute
182  *
183  * Revision 1.4 2003/02/28 10:23:27 peter
184  * fixed handling of plain - one part messages in getDOFromJavaMailMessage
185  *
186  * Revision 1.3 2003/02/27 17:23:09 peter
187  * Changed the return type of getAttachment to FileContentDO
188  *
189  * Revision 1.2 2003/02/25 11:53:33 colin
190  * bugfixes and minor restructuring
191  *
192  * Revision 1.1 2003/02/24 19:09:24 colin
193  * moved to business
194  *
195  * Revision 1.38 2003/02/20 20:26:15 colin
196  * improved validation by adding ValidationField and ValidationException
197  *
198  * Revision 1.37 2003/02/04 17:39:21 colin
199  * copyright notice
200  *
201  * Revision 1.36 2003/01/15 15:43:56 colin
202  * re-implemented:
203  * forwarding/replying (also to multiple messages)
204  * moving messages
205  *
206  * Revision 1.35 2002/11/20 09:21:23 peter
207  * removed duplicated function contents getDOFrom... (Jbuilder bug)
208  *
209  * Revision 1.34 2002/11/17 20:01:24 colin
210  * speed improvements in findMessagesInFolder...
211  *
212  * Revision 1.33 2002/11/12 09:12:38 colin
213  * structural changes. currently mail bean composes and reads messages but
214  * attachment & thread handling not active
215  *
216  * Revision 1.32 2002/10/25 08:31:44 peter
217  * mailFolderSent setting name changed to emailFolderSent
218  *
219  * Revision 1.31 2002/10/23 12:44:37 jano
220  * using new method for get System userName
221  *
222  * Revision 1.30 2002/10/23 09:18:59 jano
223  * there is a new method for generating SystemUserName
224  *
225  * Revision 1.29 2002/10/18 09:18:48 colin
226  * check users to make sure they are enabled before sending them mail
227  *
228  * Revision 1.28 2002/10/14 11:15:46 peter
229  * fixed a bug in (precomposed) send method, the cc fields work now
230  *
231  * Revision 1.27 2002/10/11 10:05:38 jano
232  * add PREFIX to user name for difren site
233  *
234  * Revision 1.26 2002/10/10 14:03:57 peter
235  * changes due to demo version
236  *
237  * Revision 1.25 2002/10/01 05:59:47 peter
238  * modifications in (precomposed) send method
239  *
240  * Revision 1.24 2002/09/17 07:26:24 peter
241  * working version
242  *
243  * Revision 1.23 2002/09/16 16:26:40 peter
244  * the attachments stuff works....
245  *
246  * Revision 1.22 2002/09/13 13:59:17 peter
247  * appendMessages and setDO methods tuned...
248  * it still doesn't work properly
249  *
250  * Revision 1.21 2002/09/12 15:55:25 peter
251  * tuned createMessage and setDO
252  *
253  * Revision 1.20 2002/09/12 07:26:19 colin
254  * added vacation message and user alias methods
255  *
256  * Revision 1.19 2002/09/11 15:57:48 peter
257  * finished createMessage and setDO, debugging needed yet
258  *
259  * Revision 1.18 2002/09/11 11:33:12 peter
260  * moveMessage works, works on createMessage and setDO
261  *
262  * Revision 1.17 2002/09/10 15:38:51 peter
263  * MailBean: works on methods
264  *
265  * Revision 1.16 2002/09/10 14:18:51 peter
266  * MailBean: works on methods
267  *
268  * Revision 1.15 2002/09/10 08:20:16 peter
269  * MailBean: added moveMessage method
270  *
271  * Revision 1.14 2002/09/09 16:07:37 peter
272  * added and modified methods in mail/MailBean
273  *
274  * Revision 1.13 2002/09/09 08:27:24 colin
275  * changed mail bean from stateful to stateless
276  * added new MailSession class
277  *
278  * Revision 1.12 2002/08/30 09:50:31 colin
279  * changed canUser... methods to just can...
280  *
281  * Revision 1.11 2002/08/29 12:23:06 peter
282  * mail display works...
283  *
284  * Revision 1.10 2002/08/27 15:26:25 peter
285  * worked on getDO, should be finished
286  *
287  * Revision 1.9 2002/08/26 15:30:14 peter
288  * MessageDO integration, not finished yet
289  *
290  * Revision 1.8 2002/08/26 11:15:47 peter
291  * added getDo and the basic methods work
292  *
293  * Revision 1.7 2002/08/23 08:09:37 peter
294  * design for MailBean methods, display so far
295  *
296  * Revision 1.6 2002/08/16 12:35:22 peter
297  * fiixed a minor bug in getMessage method
298  *
299  * Revision 1.5 2002/08/16 11:59:00 peter
300  * new mail accessing methods
301  *
302  * Revision 1.4 2002/08/11 11:37:50 colin
303  * added routines to handle server activation and passivisation
304  *
305  * Revision 1.3 2002/07/26 13:08:06 colin
306  * first version with mail server support
307  *
308  * Revision 1.2 2002/07/15 13:29:27 jano
309  * added CreateException
310  *
311  * Revision 1.1 2002/07/15 07:51:04 colin
312  * added new Mail EJB and local interface to settings
313  * -----------------------------------------------------------------------------
314  */

315 package com.ivata.groupware.business.mail;
316
317 import java.io.ByteArrayOutputStream JavaDoc;
318 import java.io.File JavaDoc;
319 import java.io.IOException JavaDoc;
320 import java.io.InputStream JavaDoc;
321 import java.io.Serializable JavaDoc;
322 import java.text.MessageFormat JavaDoc;
323 import java.util.Arrays JavaDoc;
324 import java.util.Calendar JavaDoc;
325 import java.util.Collection JavaDoc;
326 import java.util.Date JavaDoc;
327 import java.util.GregorianCalendar JavaDoc;
328 import java.util.Iterator JavaDoc;
329 import java.util.List JavaDoc;
330 import java.util.Set JavaDoc;
331 import java.util.TreeMap JavaDoc;
332 import java.util.Vector JavaDoc;
333
334 import javax.activation.DataHandler JavaDoc;
335 import javax.activation.DataSource JavaDoc;
336 import javax.activation.FileDataSource JavaDoc;
337 import javax.mail.Address JavaDoc;
338 import javax.mail.AuthenticationFailedException JavaDoc;
339 import javax.mail.Flags JavaDoc;
340 import javax.mail.Folder JavaDoc;
341 import javax.mail.FolderNotFoundException JavaDoc;
342 import javax.mail.Message JavaDoc;
343 import javax.mail.MessagingException JavaDoc;
344 import javax.mail.NoSuchProviderException JavaDoc;
345 import javax.mail.Part JavaDoc;
346 import javax.mail.Session JavaDoc;
347 import javax.mail.Store JavaDoc;
348 import javax.mail.Transport JavaDoc;
349 import javax.mail.internet.AddressException JavaDoc;
350 import javax.mail.internet.InternetAddress JavaDoc;
351 import javax.mail.internet.MimeBodyPart JavaDoc;
352 import javax.mail.internet.MimeMessage JavaDoc;
353 import javax.mail.internet.MimeMultipart JavaDoc;
354 import javax.mail.internet.MimePart JavaDoc;
355
356 import org.apache.log4j.Logger;
357
358 import com.ivata.groupware.admin.security.server.SecurityServer;
359 import com.ivata.groupware.admin.security.server.SecurityServerException;
360 import com.ivata.groupware.admin.security.server.SecuritySession;
361 import com.ivata.groupware.admin.security.user.UserDO;
362 import com.ivata.groupware.admin.setting.Settings;
363 import com.ivata.groupware.admin.setting.SettingsDataTypeException;
364 import com.ivata.groupware.business.addressbook.AddressBook;
365 import com.ivata.groupware.business.addressbook.person.PersonDO;
366 import com.ivata.groupware.business.addressbook.telecomaddress.TelecomAddressConstants;
367 import com.ivata.groupware.business.addressbook.telecomaddress.TelecomAddressDO;
368 import com.ivata.groupware.business.drive.file.FileContentDO;
369 import com.ivata.groupware.business.drive.file.FileDO;
370 import com.ivata.groupware.business.mail.message.MessageDO;
371 import com.ivata.groupware.business.mail.message.MessageNotFoundException;
372 import com.ivata.groupware.business.mail.server.MailServer;
373 import com.ivata.groupware.business.mail.server.NoMailServerException;
374 import com.ivata.groupware.business.mail.session.MailSession;
375 import com.ivata.groupware.util.SettingDateFormatter;
376 import com.ivata.groupware.web.format.EmailAddressFormatter;
377 import com.ivata.groupware.web.format.SanitizerFormat;
378 import com.ivata.mask.Mask;
379 import com.ivata.mask.MaskFactory;
380 import com.ivata.mask.util.SerializedByteArray;
381 import com.ivata.mask.util.StringHandling;
382 import com.ivata.mask.util.SystemException;
383 import com.ivata.mask.validation.ValidationError;
384 import com.ivata.mask.validation.ValidationErrors;
385 import com.ivata.mask.web.format.CharacterEntityFormat;
386 import com.ivata.mask.web.format.FormatConstants;
387 import com.ivata.mask.web.format.HTMLFormatter;
388 import com.ivata.mask.web.format.LineBreakFormat;
389 import com.ivata.mask.web.tag.webgui.list.ListColumnComparator;
390
391
392 /**
393  * <p>This session bean provides an interface to the mail system. Every mail
394  * operation for retrieving deleting and sending messages takes place in this
395  * class.</p>
396  *
397  * @since 2002-07-12
398  * @author Colin MacLeod
399  * <a HREF='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
400  * @author Peter Illes
401  * @version $Revision: 1.6.2.1 $
402  */

403 public class MailImpl implements Mail, Serializable JavaDoc {
404     /**
405      * <p>Used to return both the HTML & plain text parts of a message in
406      * <code>createThreadMessage</code>.</p>
407      */

408     private class MessageTextParts {
409         public MimeBodyPart JavaDoc HTMLPart = null;
410         public MimeBodyPart JavaDoc textPart = null;
411     }
412
413     /**
414      * Logger for this class.
415      */

416     private static Logger logger = Logger.getLogger(MailImpl.class);
417     private AddressBook addressBook;
418     private SettingDateFormatter dateFormatter = null;
419     private MailServer mailServer;
420     MaskFactory maskFactory;
421     /**
422      * <p>
423      * Settings implementation. Used to retrieve the email address host.
424      * </p>
425      */

426     private Settings settings;
427
428
429     /**
430      * <p>
431      * Initialize the mail implementation.
432      * </p>
433      *
434      * @param securityServer A valid security server for the current site. If
435      * this is not an instance of {@link com.ivata.groupware.business.mail.server.MailServer}
436      * the mail implementation will not be usable.
437      * @param persistenceManager This is used to save/access data from the
438      * persistence store.
439      * @param addressBook This is used to read contacts email details.
440      * @param settings Contains user defined settings and preferences.
441      * @param dateFormatter Used to format mail dates and times.
442      * @param idDispenser
443      */

444     public MailImpl(SecurityServer securityServer,
445             AddressBook addressBook,
446             Settings settings,
447             MaskFactory maskFactory) {
448         assert (securityServer != null);
449         if (securityServer instanceof MailServer) {
450             this.mailServer = (MailServer) securityServer;
451         } else {
452             logger.warn("Security server class ("
453                     + securityServer.getClass().getName()
454                     + ") is not a mail server class.");
455         }
456         this.settings = settings;
457         this.addressBook = addressBook;
458         this.maskFactory = maskFactory;
459     }
460     private void checkDateFormatter(SecuritySession securitySession) {
461         if (dateFormatter == null) {
462             dateFormatter = new SettingDateFormatter(securitySession,
463                 settings);
464         }
465     }
466     /**
467      * <p>Add a composed message to the drafts folder for later sending.</p>
468      *
469      * @param mailSession valid mail session to which the user should already be
470      * logged in.
471      * @param messageDO data object containing full details of the
472      * message to be added to the drafts.
473      * @return new <code>MessageDO</code> with the <code>id</code> set to the
474      * current value in the mail system.
475      */

476     public MessageDO addMessageToDraftsFolder(final MailSession mailSession,
477             final MessageDO messageDO) throws SystemException {
478         checkDateFormatter(mailSession);
479
480         Store JavaDoc store = mailServer.connectStore(mailSession);
481         try {
482             Session JavaDoc javaMailSession;
483             try {
484                 javaMailSession = mailSession.getJavaMailSession();
485             } catch (java.security.NoSuchProviderException JavaDoc e1) {
486                 throw new SystemException(e1);
487             }
488
489             // get the drafts folder in case we want to copy over an older mail
490
Folder JavaDoc draftsFolder = openDraftsFolder(store, mailSession);
491
492             MimeMessage JavaDoc newMessage = setDOToJavaMailMessage(javaMailSession,
493                     draftsFolder, messageDO);
494
495             newMessage.setSentDate(Calendar.getInstance().getTime());
496
497             // append the new message to the drafts folder
498
Message JavaDoc[] messages = { newMessage };
499
500                 draftsFolder.appendMessages(messages);
501
502             // note the new id
503
messageDO.setMessageID(((MimeMessage JavaDoc) draftsFolder.getMessage(
504                     draftsFolder.getMessageCount())).getMessageID());
505
506             // only now can we delete/expunge the old mail from the drafts folder
507
draftsFolder.expunge();
508             draftsFolder.close(true);
509         } catch (MessagingException JavaDoc e1) {
510             throw new SystemException(e1);
511         } finally {
512             try {
513                 store.close();
514             } catch (MessagingException JavaDoc e) {
515                 logger.error("Messaging exception on closing the store", e);
516             }
517         }
518
519         return messageDO;
520     }
521
522     /**
523      * <p>Recursive routine used for building up all attachments in the
524      * <code>MessageDO<code> provided.</p>
525      *
526      * @param messagePart the multipart part or message to process.
527      * @param messageDO the data object to add results to.
528      * @throws GroupwareException if there is a <code>MailMessagingException</code> or
529      * <code>IOException</code>.
530      */

531     private void addMultiPart(final Part JavaDoc messagePart,
532             final MessageDO messageDO)
533             throws SystemException {
534         String JavaDoc outputText = "";
535         MimeMultipart JavaDoc content;
536         MimeBodyPart JavaDoc subPart;
537
538         List JavaDoc messageTextParts = new Vector JavaDoc();
539
540         try {
541             content = (MimeMultipart JavaDoc) messagePart.getContent();
542
543             //go through all the subParts
544
for (int i = 0; i < content.getCount(); i++) {
545                 subPart = (MimeBodyPart JavaDoc) content.getBodyPart(i);
546
547                 // when multipart/alternative and no text found in parent call,
548
// store the text of the parts to select the best one after the loop
549
if (messagePart.isMimeType("multipart/alternative") &&
550                         subPart.isMimeType("text/*") &&
551                         StringHandling.isNullOrEmpty(messageDO.getText())) {
552                     messageTextParts.add(subPart);
553                 } else if (messagePart.isMimeType("multipart/*")) {
554                     // other multipart types
555
if (StringHandling.isNullOrEmpty(messageDO.getText()) &&
556                             (subPart.getDisposition() == null) &&
557                             (subPart.getFileName() == null)) {
558                         if (subPart.isMimeType("text/*")) {
559                             messageTextParts.add(subPart);
560                         } else if (subPart.isMimeType("multipart/*")) {
561                             addMultiPart((Part JavaDoc) subPart, messageDO);
562                         } else {
563                             addPart(subPart, messageDO);
564                         }
565                     } else {
566                         if (subPart.isMimeType("multipart/*")) {
567                             addMultiPart((Part JavaDoc) subPart, messageDO);
568                         } else {
569                             addPart(subPart, messageDO);
570                         }
571                     }
572                 }
573             }
574
575             // looking for best message text
576
if (!messageTextParts.isEmpty()) {
577                 String JavaDoc HTML = null;
578                 String JavaDoc text = null;
579
580                 // let's choose the best text
581
for (Iterator JavaDoc i = messageTextParts.iterator(); i.hasNext();) {
582                     subPart = (MimeBodyPart JavaDoc) i.next();
583
584                     if (subPart.isMimeType("text/HTML")) {
585                         HTML = (String JavaDoc) subPart.getContent();
586                     } else if (subPart.isMimeType("text/plain")) {
587                         text = (String JavaDoc) subPart.getContent();
588                     }
589                      // TODO: we could use text/enriched too
590
}
591
592                 if (HTML != null) {
593                     messageDO.setText(HTML);
594                     messageDO.setFormat(FormatConstants.FORMAT_HTML);
595                 } else if (text != null) {
596                     messageDO.setText(text);
597                     messageDO.setFormat(FormatConstants.FORMAT_TEXT);
598                 }
599             }
600         } catch (MessagingException JavaDoc e) {
601             throw new SystemException(e);
602         } catch (java.io.IOException JavaDoc e) {
603             throw new SystemException(e);
604         }
605     }
606
607     /**
608      * <p>Add a part of a multi-part message to the attachments of the message
609      * data object.</p>
610      *
611      * @param part the message part to process.
612      * @param messageDO the data object to add results to.
613      * @throws GroupwareException if there is a <code>MessagingException</code> or an
614      * <code>IOException</code>.
615      */

616     private void addPart(final MimePart JavaDoc part,
617             final MessageDO messageDO)
618         throws SystemException {
619         FileDO attachment = new FileDO();
620
621         try {
622             attachment.setMimeType(part.getContentType());
623             attachment.setSize(new Integer JavaDoc(part.getSize()));
624
625             String JavaDoc contentId = part.getContentID();
626             String JavaDoc name = part.getFileName();
627
628             // return with empty hands if no identifier, the attachment will be
629
// impossible to locate
630
if ((contentId == null) && (name == null)) {
631                 return;
632             }
633
634             // prefer contentId as identifier and name as the display info
635
attachment.setName((contentId != null) ? contentId : name);
636             attachment.setComment((name != null) ? name : contentId);
637         } catch (MessagingException JavaDoc e) {
638             throw new SystemException(e);
639         }
640
641         messageDO.getAttachments().add(attachment);
642     }
643
644     /**
645      * <p>Internal helper to add a message to the sent mail folder. This should
646      * be called <em><u>after</u></em> sending the mail.</p>
647      */

648     private void addToSentFolder(final MailSession mailSession,
649             final MimeMessage JavaDoc message)
650             throws SystemException {
651         Folder JavaDoc sentFolder;
652
653         Store JavaDoc store = mailServer.connectStore(mailSession);
654         try {
655             String JavaDoc sentFolderName = settings.getStringSetting(
656                     mailSession,
657                     "emailFolderSent",
658                     mailSession.getUser());
659             sentFolder = mailServer.getFolder(mailSession, store, sentFolderName);
660
661             if (!sentFolder.exists()) {
662                 try {
663                     if (!sentFolder.create(Folder.HOLDS_MESSAGES)) {
664                         throw new SystemException(
665                             "There was no sent folder for you on this server, "
666                             + "and ivata mail could not create one.<br>Please "
667                             + "contact your administrator.");
668                     }
669                 } catch (MessagingException JavaDoc e1) {
670                     throw new SystemException(e1);
671                 }
672             }
673
674             Message JavaDoc[] messages = { message };
675
676             try {
677                 sentFolder.appendMessages(messages);
678             } catch (MessagingException JavaDoc eAppend) {
679                 throw new SystemException(
680                     "There was an error adding your message to the sent "
681                     + "messages folder: " +
682                     eAppend.getMessage(),
683                     eAppend);
684             }
685         } catch (MessagingException JavaDoc eNoSent) {
686             throw new SystemException("Sent folder not available in store. " +
687                 eNoSent.getMessage(),
688                 eNoSent);
689         } catch (SettingsDataTypeException e) {
690             throw new SystemException(e);
691         } finally {
692             try {
693                 store.close();
694             } catch (MessagingException JavaDoc e) {
695                 logger.error("Messaging exception on closing the store", e);
696             }
697         }
698     }
699
700     /**
701      * <p>
702      * Add appropriate user addresses given a list of user aliases.
703      * </p>
704      *
705      * @param securitySession valid security session.
706      * @param userName name of the user who owns teh aliases.
707      * @param userAliases a <code>Collection</code> of <code>String</code>
708      * instances containing the local part of the different email aliases
709      * this user has. If the user has no aliaes, an empty collection should
710      * be provided.
711      * @param telecomAddresess a <code>Collection</code> containing all the
712      * user's existing email addresses, as <code>TelecomAddressDO</code>
713      * instances.
714      */

715     public void addUserAliasEmailAddresses(final SecuritySession securitySession,
716             final String JavaDoc userName,
717             final Collection JavaDoc userAliases,
718             final Collection JavaDoc telecomAddresses,
719             final String JavaDoc emailAddressHost)
720             throws SystemException {
721         checkDateFormatter(securitySession);
722         Iterator JavaDoc telecomAddressIterator = telecomAddresses.iterator();
723         List JavaDoc currentAddresses = new Vector JavaDoc();
724         while (telecomAddressIterator.hasNext()) {
725             TelecomAddressDO thisTelecomAddress = (TelecomAddressDO)
726                 telecomAddressIterator.next();
727             if (!StringHandling.isNullOrEmpty(thisTelecomAddress.getAddress())
728                     && (thisTelecomAddress.getType() == TelecomAddressConstants.TYPE_EMAIL)) {
729                 currentAddresses.add(thisTelecomAddress.getAddress());
730             }
731         }
732
733         // if the person has no email address, give him/her one
734
// check there is at least one alias - the following routine will
735
// do the rest
736
// we make it conditional because you might not always want to have
737
// user@host as your email address - this way, you can specify a
738
// different one
739
if ((currentAddresses.size() == 0)
740                 && (userAliases.size() == 0)) {
741             userAliases.add(userName);
742         }
743
744         // go thro' all aliases and create email addreses from them
745
Iterator JavaDoc aliasIterator = userAliases.iterator();
746         while(aliasIterator.hasNext()) {
747             String JavaDoc alias = (String JavaDoc) aliasIterator.next();
748             String JavaDoc aliasAddress = alias + "@" + emailAddressHost;
749             // if it is already there, move on...
750
if (currentAddresses.contains(aliasAddress)) {
751                 continue;
752             }
753             TelecomAddressDO newAddress = new TelecomAddressDO();
754             newAddress.setAddress(aliasAddress);
755             newAddress.setType(TelecomAddressConstants.TYPE_EMAIL);
756             newAddress.setNumber(telecomAddresses.size());
757             telecomAddresses.add(newAddress);
758         }
759     }
760
761     /**
762      * <p>Append attachments to a message located in the drafts folder.</p>
763      *
764      * @param mailSession valid mail session to which the user should already be
765      * logged in.
766      * @param id the unique identifier of the message to which we want to append
767      * attachments.
768      * @param attachments <code>List</code> of <code>String</code>s -
769      * filenames of files waiting in upload directory.
770      * @return <code>null</code> when the operation failed, otherwise the new
771      * message id.
772      * @exception MessageNotFoundException if the folder doesn't exist, or there
773      * is no matching mail in this folder.
774      *
775      * @ejb.interface-method
776      * view-type = "remote"
777      */

778     public MessageDO appendAttachments(final MailSession mailSession,
779             final String JavaDoc id,
780             final List JavaDoc attachments) throws SystemException {
781         checkDateFormatter(mailSession);
782         String JavaDoc newId = null;
783         UserDO user = mailSession.getUser();
784         Store JavaDoc store = mailServer.connectStore(mailSession);
785
786         try {
787             String JavaDoc siteHome = settings.getStringSetting(mailSession,
788                 "siteHome", user);
789             String JavaDoc uploadDirectory = siteHome + "/users/" +
790                 mailSession.authenticator.getPasswordAuthentication()
791                                          .getUserName() + "/upload/files/";
792
793             Session JavaDoc javaMailSession;
794
795             try {
796                 javaMailSession = mailSession.getJavaMailSession();
797             } catch (SecurityServerException e) {
798                 throw new SystemException(e);
799             } catch (java.security.NoSuchProviderException JavaDoc e) {
800                 throw new SystemException(e);
801             }
802
803             Folder JavaDoc draftsFolder = openDraftsFolder(store, mailSession);
804             MimeMessage JavaDoc oldMessage = findJavaMailMessageByFolderMessageId(draftsFolder,
805                     id);
806             int i;
807             MimeBodyPart JavaDoc newPart;
808             MimeMultipart JavaDoc newMessageContent = new MimeMultipart JavaDoc();
809             MimeMultipart JavaDoc oldMessageContent;
810             MimeMessage JavaDoc newMessage = copyJavaMailMessage(javaMailSession,
811                     oldMessage);
812
813             // when the message is already multipart/mixed, no probs...
814
if (oldMessage.isMimeType("multipart/mixed")) {
815                 oldMessageContent = (MimeMultipart JavaDoc) oldMessage.getContent();
816
817                 for (i = 0; i < oldMessageContent.getCount(); i++) {
818                     newPart = (MimeBodyPart JavaDoc) oldMessageContent.getBodyPart(i);
819                     newMessageContent.addBodyPart(newPart);
820                 }
821             } else {
822                 // create the first part from the old message, attachments will be appended
823
newPart = new MimeBodyPart JavaDoc();
824                 newPart.setContent(oldMessage.getContent(),
825                     oldMessage.getContentType());
826                 newPart.setHeader("Content-Type", oldMessage.getContentType());
827                 newMessageContent.addBodyPart(newPart);
828             }
829
830             // add the attachments, passed as fileNames of files in upload dir
831
for (Iterator JavaDoc attachmentsIterator = attachments.iterator();
832                     attachmentsIterator.hasNext();) {
833                 File JavaDoc attachment = new File JavaDoc(uploadDirectory,
834                         (String JavaDoc) attachmentsIterator.next());
835
836                 // process the file in upload directory
837
if (attachment.canRead()) {
838                     newPart = new MimeBodyPart JavaDoc();
839                     newPart.setFileName(attachment.getName());
840                     newPart.setDisposition(Part.ATTACHMENT);
841
842                     DataSource JavaDoc dataSource = new FileDataSource JavaDoc(attachment);
843                     newPart.setDataHandler(new DataHandler JavaDoc(dataSource));
844                     newPart.setHeader("Content-Type",
845                         dataSource.getContentType());
846                     newPart.setHeader("Content-Transfer-Encoding", "base64");
847                     newMessageContent.addBodyPart(newPart);
848                 }
849             }
850
851             newMessage.setContent(newMessageContent);
852             newMessage.setHeader("Content-Type",
853                 newMessageContent.getContentType());
854
855             // first append the new message
856
Message JavaDoc[] messages = { newMessage };
857
858             draftsFolder.appendMessages(messages);
859
860             // note the new id
861
newId = ((MimeMessage JavaDoc) draftsFolder.getMessage(draftsFolder.getMessageCount())).getMessageID();
862
863             // only now is it safe to delete the old message
864
oldMessage.setFlag(Flags.Flag.DELETED, true);
865             draftsFolder.expunge();
866
867             // now it's safe to delete the files in upload dir, they're in the new multipart
868
for (Iterator JavaDoc attachmentsIterator = attachments.iterator();
869                     attachmentsIterator.hasNext();) {
870                 File JavaDoc attachment = new File JavaDoc(uploadDirectory,
871                         (String JavaDoc) attachmentsIterator.next());
872
873                 if (attachment.canWrite()) {
874                     attachment.delete();
875                 }
876             }
877
878             // MessageDO returnDO = getDOFromJavaMailMessage(newMessage, true);
879
MessageDO returnDO = getDOFromJavaMailMessage(
880                     findJavaMailMessageByFolderMessageId(
881                     draftsFolder, newId), true);
882             draftsFolder.close(true);
883             return returnDO;
884         } catch (MessagingException JavaDoc em) {
885             throw new SystemException(em);
886         } catch (IOException JavaDoc eio) {
887             throw new SystemException(eio);
888         } finally {
889             try {
890                 store.close();
891             } catch (MessagingException JavaDoc e) {
892                 logger.error("Messaging exception on closing the store", e);
893             }
894         }
895     }
896
897     /**
898      * <p>
899      * Check we have a valid mail server.
900      * </p>
901      *
902      * @throws NoMailServerException if there is no mail server.
903      */

904     private void checkMailServer() throws SystemException {
905         if (mailServer == null) {
906             logger.warn("No mail server found.");
907             throw new NoMailServerException();
908         }
909     }
910
911     /**
912      * <p>Helper method. Converts recipients from a collection of
913      * <code>PersonDO</code>, <code>UserDO</code> or <code>String<code>
914      * instances into an array of email addresses.</p>
915      * @param securitySession TODO
916      * @param addresses a <code>Collection</code> containing all of the email
917      * addresses to convert. These can either be as <code>String<code>
918      * instances or <code>PersonDO<code> instances, where the default
919      * email address for each person is taken.
920      *
921      * @return array or <code>InternetAddress</code> instances for each of the
922      * input parameters.
923      */

924     private InternetAddress JavaDoc[] convertAddresses(final SecuritySession securitySession,
925             final Collection JavaDoc addresses)
926             throws SystemException {
927         InternetAddress JavaDoc[] returnAddresses = new InternetAddress JavaDoc[addresses.size()];
928
929         // prerequisites check we got given something to convert
930
if (addresses == null) {
931             return returnAddresses;
932         }
933
934         int index = 0;
935
936         for (Iterator JavaDoc i = addresses.iterator(); i.hasNext();) {
937             Object JavaDoc item = i.next();
938             String JavaDoc addressString = null;
939
940             if (PersonDO.class.isInstance(item)) {
941                 PersonDO person = (PersonDO) item;
942
943                 addressString = person.getEmailAddress();
944             } else if (UserDO.class.isInstance(item)) {
945                 UserDO user = (UserDO) item;
946                 PersonDO person = addressBook.findPersonByUserName(securitySession,
947                         user.getName());
948
949                 // only set the address for users who are not disabled
950
if (user.isEnabled()) {
951                     addressString = person.getEmailAddress();
952                 }
953             } else {
954                 if (!String JavaDoc.class.isInstance(item)) {
955                     throw new SystemException("Cannot convert item of class '" +
956                         item.getClass() + "' into an email address.");
957                 }
958
959                 addressString = (String JavaDoc) item;
960             }
961
962             // ignore empty addresses
963
if (!StringHandling.isNullOrEmpty(addressString)) {
964                 try {
965                     returnAddresses[index++] = new InternetAddress JavaDoc(addressString);
966                 } catch (AddressException JavaDoc eAddress) {
967                     throw new SystemException(
968                         "ERROR in MailBean: cannot convert internet address '"
969                             + addressString
970                             + "': "
971                             + eAddress.getMessage(),
972                             eAddress);
973                 }
974             }
975         }
976
977         return returnAddresses;
978     }
979
980     /**
981      * <p>Copy the fields of an old <code>MimeMessage</code> to a new one.</p>
982      *
983      * <p><strong>Note:</strong> this method does not copy the content. Both the text
984      * and the message attachments (if any) must be set individually.</p>
985      *
986      * @param javaMailSession valid <em>JavaMail</em> session to which the user
987      * should already be logged in.
988      * @param message a valid message filled out with values to copy.
989      * @return a valid <em>JavaMail</em> message ready with <code>recipients</code>,
990      * <code>from</code> and <code>subject</code> fields matching
991      * <code>message</code>.
992      */

993     private MimeMessage JavaDoc copyJavaMailMessage(final Session JavaDoc javaMailSession,
994             final MimeMessage JavaDoc message)
995             throws SystemException {
996         MimeMessage JavaDoc newMessage = new MimeMessage JavaDoc(javaMailSession);
997
998         try {
999             newMessage.setRecipients(Message.RecipientType.TO,
1000                message.getRecipients(Message.RecipientType.TO));
1001            newMessage.setRecipients(Message.RecipientType.CC,
1002                message.getRecipients(Message.RecipientType.CC));
1003            newMessage.setRecipients(Message.RecipientType.BCC,
1004                message.getRecipients(Message.RecipientType.BCC));
1005            newMessage.addFrom(message.getFrom());
1006            newMessage.setSubject(message.getSubject());
1007        } catch (MessagingException JavaDoc e) {
1008            throw new SystemException(e);
1009        }
1010
1011        return newMessage;
1012    }
1013
1014    /**
1015     * <p>Convert a <em>JavaMail</em> message to an <em>ivata groupware</em> dependent
1016     * value object.</p>
1017     *
1018     * @param message a valid <em>JavaMail</em> message to be converted.
1019     * @param includeContent <code>true</code> if the <code>text</code> and
1020     * attachments of the message should also be set, otherwise
1021     * <code>false</code>.
1022     * @return message data object with the values filled out to match
1023     * the <em>JavaMail</em> object.
1024     */

1025    private MessageDO createDOFromJavaMailMessage(final MimeMessage JavaDoc message,
1026            final boolean includeContent)
1027            throws SystemException {
1028        // right - we got here, so that means we have a message
1029
MessageDO messageDO = new MessageDO();
1030        try {
1031            //setting the fields of the MessageDO:
1032
if (message.getFolder() != null) {
1033                messageDO.setFolderName(message.getFolder().getName());
1034            }
1035
1036            if (message.getReceivedDate() != null) {
1037                GregorianCalendar JavaDoc receivedDate = new GregorianCalendar JavaDoc();
1038
1039                receivedDate.setTime(message.getReceivedDate());
1040                messageDO.setReceived(receivedDate);
1041            }
1042
1043            if (message.getRecipients(Message.RecipientType.TO) != null) {
1044                messageDO.setRecipients(Arrays.asList(toStringArray(
1045                            message.getRecipients(Message.RecipientType.TO))));
1046            }
1047
1048            if (message.getRecipients(Message.RecipientType.CC) != null) {
1049                messageDO.setRecipientsCC(Arrays.asList(toStringArray(
1050                            message.getRecipients(Message.RecipientType.CC))));
1051            }
1052
1053            if (message.getRecipients(Message.RecipientType.BCC) != null) {
1054                messageDO.setRecipientsBCC(Arrays.asList(toStringArray(
1055                            message.getRecipients(Message.RecipientType.BCC))));
1056            }
1057
1058            if (message.getFrom() != null) {
1059                messageDO.setSenders(Arrays.asList(toStringArray(
1060                            message.getFrom())));
1061            }
1062
1063            if (message.getSentDate() != null) {
1064                GregorianCalendar JavaDoc sentDate = new GregorianCalendar JavaDoc();
1065
1066                sentDate.setTime(message.getSentDate());
1067                messageDO.setSent(sentDate);
1068            }
1069
1070            messageDO.setSize(new Integer JavaDoc(message.getSize()));
1071            messageDO.setSubject(message.getSubject());
1072
1073            // message content handling - not always done for efficiency in lists
1074
if (includeContent) {
1075                Integer JavaDoc format;
1076                String JavaDoc text;
1077
1078                // create new, empty List for our attachments
1079
messageDO.setAttachments(new Vector JavaDoc());
1080
1081                // if it is a multipart message (has attachments), pass control to
1082
// recursive routine to go thro' them all
1083
if (message.isMimeType("multipart/*")) {
1084                    addMultiPart(message, messageDO);
1085
1086                    // here are types with textual content
1087
} else if (message.isMimeType("text/*") ||
1088                        message.isMimeType("message/*")) {
1089                    // if it is not multipart, we're just left with text or HTML
1090
if (message.isMimeType("text/HTML")) {
1091                        // simple message with HTML content
1092
messageDO.setFormat(FormatConstants.FORMAT_HTML);
1093                    } else {
1094                        // anything else with simple content should have text content
1095
messageDO.setFormat(FormatConstants.FORMAT_TEXT);
1096                    }
1097
1098                    messageDO.setText((String JavaDoc) message.getContent());
1099
1100                    // other (not correct?) types, as self-contained attachments...
1101
} else {
1102                    messageDO.setFormat(FormatConstants.FORMAT_TEXT);
1103                    messageDO.setText("");
1104                    addPart(message, messageDO);
1105                }
1106            }
1107            messageDO.setMessageID(message.getMessageID());
1108        } catch (MessagingException JavaDoc e) {
1109            throw new SystemException(e);
1110        } catch (IOException JavaDoc e) {
1111            throw new SystemException(e);
1112        }
1113
1114        return messageDO;
1115    }
1116
1117    /**
1118     * <p>Create a new mail folder.</p>
1119     *
1120     * @param mailSession valid mail session to which the user should already be
1121     * logged in.
1122     * @param folderName the full path name of the folder to create.
1123     *
1124     * @ejb.interface-method
1125     * view-type = "remote"
1126     */

1127    public void createFolder(final MailSession mailSession,
1128            final String JavaDoc folderName)
1129            throws SystemException {
1130        assert (mailSession != null);
1131        checkDateFormatter(mailSession);
1132
1133        Session JavaDoc javaMailSession;
1134
1135        try {
1136            javaMailSession = mailSession.getJavaMailSession();
1137        } catch (AuthenticationFailedException JavaDoc e) {
1138            throw new SystemException(
1139                "User is no longer authorized to use this server: " +
1140                e.getMessage(),
1141                e);
1142        } catch (MessagingException JavaDoc e) {
1143            throw new SystemException(e);
1144        } catch (SecurityServerException e) {
1145            throw new SystemException(e);
1146        } catch (java.security.NoSuchProviderException JavaDoc e) {
1147            throw new SystemException(e);
1148        }
1149
1150        Store JavaDoc store = mailServer.connectStore(mailSession);
1151        try {
1152            if (folderName == null) {
1153                throw new SystemException(
1154                    "ERROR in MailBean.createFolder: folderName is null");
1155            }
1156
1157            Folder JavaDoc folder = mailServer.getFolder(mailSession, store, folderName);
1158
1159            if (!folder.create(Folder.HOLDS_MESSAGES)) {
1160                throw new SystemException(
1161                    "ERROR in MailBean.createFolder: could not create folder '" +
1162                    folderName + "'");
1163            }
1164        } catch (MessagingException JavaDoc e) {
1165            throw new SystemException(e);
1166        } finally {
1167            try {
1168                store.close();
1169            } catch (MessagingException JavaDoc e) {
1170                logger.error("Messaging exception on closing the store", e);
1171            }
1172        }
1173    }
1174
1175
1176    /**
1177     * <p>Helper method for <code>createThreadMethod</code>.</p>
1178     *
1179     * <p>Create a new message in the drafts folder from an existing one,
1180     * resulting in a forwarded message.</p>
1181     *
1182     * @param mailSession valid mail session to which the user should already be
1183     * logged in.
1184     * @param folderName the name of the folder to copy existing messages from.
1185     * @param messageIds the unique identifier of the messages to be extended.
1186     * Can be <code>null</code> if a new message is requeested. When
1187     * forwarding, multiple address identifiers may be specified otherwise
1188     * (if editing a draft message or replying) only one message identifier
1189     * should be set in the list.
1190     * @param thread set to one of the constants in {@link MailConstants
1191     * MailConstants}.
1192     * @return populated message data object matching the required
1193     * message, and with the <code>id</code> set to the message in the
1194     * drafts folder.
1195     */

1196    private MimeMessage JavaDoc createForwardedMessage(final MailSession mailSession,
1197            final Folder JavaDoc folder,
1198            final List JavaDoc messageIds)
1199            throws SystemException {
1200        checkDateFormatter(mailSession);
1201        try {
1202            Session JavaDoc javaMailSession;
1203            try {
1204                javaMailSession = mailSession.getJavaMailSession();
1205            } catch (java.security.NoSuchProviderException JavaDoc e1) {
1206                throw new SystemException(e1);
1207            }
1208            UserDO user = mailSession.getUser();
1209
1210            // if this is HTML, we'll need to store multipart data
1211
MessageTextParts messageTextParts = null;
1212
1213            // first go thro' all the messages and see if there are _any_ which
1214
// are multipart
1215
boolean isMultipart = false;
1216            int format = FormatConstants.FORMAT_TEXT;
1217
1218            for (Iterator JavaDoc i = messageIds.iterator(); i.hasNext();) {
1219                String JavaDoc id = (String JavaDoc) i.next();
1220                MimeMessage JavaDoc oldMessage = findJavaMailMessageByFolderMessageId(folder,
1221                        id);
1222
1223                // is this multipart?
1224
if (oldMessage.isMimeType("multipart/*")) {
1225                    isMultipart = true;
1226
1227                    // try to find an HTML subpart
1228
messageTextParts = getMultiPartText(oldMessage);
1229
1230                    if (messageTextParts.HTMLPart != null) {
1231                        format = FormatConstants.FORMAT_HTML;
1232
1233                        // no need to check any further...
1234
break;
1235                    }
1236                }
1237            }
1238
1239            // text header/prefix depends on the format
1240
String JavaDoc messageHeader;
1241
1242            if (format == FormatConstants.FORMAT_HTML) {
1243                messageHeader = settings.getStringSetting(mailSession,
1244                        "emailHeaderForwardHTML",
1245                        user);
1246            } else {
1247                messageHeader = settings.getStringSetting(mailSession,
1248                        "emailHeaderForwardText",
1249                        user);
1250            }
1251
1252            MimeMessage JavaDoc newMessage = new MimeMessage JavaDoc(javaMailSession);
1253            StringBuffer JavaDoc subject = new StringBuffer JavaDoc();
1254            String JavaDoc subjectPrefix = settings.getStringSetting(mailSession,
1255                    "emailSubjectForwardPrefix",
1256                    user);
1257            String JavaDoc subjectSeperator = settings.getStringSetting(mailSession,
1258                    "emailSubjectForwardSeperator",
1259                    user);
1260
1261            subject.append(subjectPrefix);
1262
1263            StringBuffer JavaDoc messageText = new StringBuffer JavaDoc();
1264
1265            // we'll format the reply text, if it is text & this is HTML
1266
CharacterEntityFormat characterEntities = new CharacterEntityFormat();
1267
1268            // go thro' all of the old ids again, this time to add the content
1269
int index = 0;
1270
1271            for (Iterator JavaDoc i = messageIds.iterator(); i.hasNext(); ++index) {
1272                String JavaDoc id = (String JavaDoc) i.next();
1273                MimeMessage JavaDoc oldMessage = findJavaMailMessageByFolderMessageId(folder,
1274                        id);
1275
1276                // prepend Re: or Fwd: unless the previous subject already starts like this
1277
String JavaDoc oldSubject = StringHandling.getNotNull(oldMessage.getSubject(),
1278                        getNullString());
1279
1280                // if there is a fwd: prefix check this message doesn't start with
1281
// that
1282
if ((subjectPrefix != null) &&
1283                        (oldSubject.startsWith(subjectPrefix))) {
1284                    oldSubject = oldSubject.substring(subjectPrefix.length());
1285                }
1286
1287                // if there is more than one forwarded message, append separator
1288
// between the subjects
1289
if ((index > 0) && !oldSubject.equals("")) {
1290                    subject.append(subjectSeperator);
1291                }
1292
1293                subject.append(oldSubject);
1294
1295                // locate the multipart in the new message, for multiparts
1296
String JavaDoc oldMessageText = null;
1297                int oldFormat = FormatConstants.FORMAT_TEXT;
1298
1299                if (oldMessage.isMimeType("multipart/*")) {
1300                    // if there is an HTML text, use that
1301
if (messageTextParts.HTMLPart != null) {
1302                        oldMessageText = (String JavaDoc) messageTextParts.HTMLPart.getContent();
1303                        oldFormat = FormatConstants.FORMAT_HTML;
1304                    } else if (messageTextParts.textPart != null) {
1305                        oldMessageText = (String JavaDoc) messageTextParts.textPart.getContent();
1306                    }
1307                } else {
1308                    oldMessageText = (String JavaDoc) oldMessage.getContent();
1309                }
1310
1311                // if we have to build the text with a prefix/header, do that
1312
if ((oldMessageText != null) && (messageHeader != null)) {
1313                    messageText.append(formatMessageHeader(messageHeader,
1314                            oldMessage));
1315                }
1316
1317                if (oldMessageText != null) {
1318                    // we have to watch it if the old format wasn't HTML before
1319
if ((format == FormatConstants.FORMAT_HTML) &&
1320                            !(oldFormat == FormatConstants.FORMAT_HTML)) {
1321                        messageText.append("<pre>\n");
1322                        oldMessageText = characterEntities.format(oldMessageText);
1323                    }
1324
1325                    messageText.append(oldMessageText);
1326
1327                    if ((format == FormatConstants.FORMAT_HTML) &&
1328                            !(oldFormat == FormatConstants.FORMAT_HTML)) {
1329                        messageText.append("\n</pre>\n");
1330                    }
1331                }
1332            }
1333
1334            if (format == FormatConstants.FORMAT_HTML) {
1335                // we want to work with copies of the original texts,
1336
// create a new HTML content multipart
1337
MimeMultipart JavaDoc newTextContent = createHTMLContent(messageText.toString());
1338
1339                // set the multipart/alternative as the content of the base part
1340
newMessage.setContent(newTextContent);
1341                newMessage.setHeader("Content-Type",
1342                    newTextContent.getContentType());
1343
1344                // plain text replies and forwards are easier
1345
} else {
1346                newMessage.setContent(messageText.toString(), "text/plain");
1347            }
1348
1349            return newMessage;
1350        } catch (MessagingException JavaDoc e) {
1351            throw new SystemException(e);
1352        } catch (IOException JavaDoc e) {
1353            throw new SystemException(e);
1354        }
1355    }
1356
1357    /**
1358     * <p>Create text content of a message, if the text is <code>HTML</code>
1359     * format. This actually creates an alternative multipart type, and loads
1360     * both the <code>HTML</code> content and the equivalent plain text.</p>
1361     *
1362     * @param hTMLText the new HTML text of the body content
1363     * @exception MessagingException thrown by <code>MimeBodyPart.setContent</code>
1364     * @return the newx content of the alternative multipart message content.
1365     */

1366    private MimeMultipart JavaDoc createHTMLContent(final String JavaDoc hTMLText)
1367        throws MessagingException JavaDoc {
1368        // HTML desired, the base part will be multipart/alternative
1369
MimeMultipart JavaDoc newTextContent = new MimeMultipart JavaDoc("alternative");
1370
1371        // the richer format the last, so plain text first
1372
MimeBodyPart JavaDoc mimePart = new MimeBodyPart JavaDoc();
1373        SanitizerFormat sanitizer = new SanitizerFormat();
1374
1375        sanitizer.setSourceName("user input");
1376        sanitizer.setTextOnly(true);
1377        mimePart.setContent(sanitizer.format(hTMLText), "text/plain");
1378        mimePart.setHeader("Content-Type", "text/plain");
1379        newTextContent.addBodyPart(mimePart);
1380
1381        // TODO: this is not efficient - it parses the HTML tree twice :-(
1382
// replace with HTMLParser calls directly
1383
// the HTML part now
1384
mimePart = new MimeBodyPart JavaDoc();
1385        sanitizer.setTextOnly(false);
1386        mimePart.setContent(sanitizer.format(hTMLText), "text/HTML");
1387        mimePart.setHeader("Content-Type", "text/HTML");
1388        newTextContent.addBodyPart(mimePart);
1389
1390        return newTextContent;
1391    }
1392
1393    /**
1394     * <p>Helper method for <code>createThreadMethod</code>.</p>
1395     *
1396     * <p>Create a new message in the drafts folder from an existing one,
1397     * resulting in a message which replies to the original one.</p>
1398     *
1399     * @param mailSession valid mail session to which the user should already be
1400     * logged in.
1401     * @param folderName the name of the folder to copy existing messages from.
1402     * @param messageIds the unique identifier of the messages to be extended.
1403     * Can be <code>null</code> if a new message is requeested. When
1404     * forwarding, multiple address identifiers may be specified otherwise
1405     * (if editing a draft message or replying) only one message identifier
1406     * should be set in the list.
1407     * @param thread set to one of the congstants in {@link MailConstants
1408     * MailConstants}.
1409     * @return populated message data object matching the required
1410     * message, and with the <code>id</code> set to the message in the
1411     * drafts folder.
1412     */

1413    private MimeMessage JavaDoc createReplyMessage(final MailSession mailSession,
1414            final Folder JavaDoc folder,
1415            final String JavaDoc id,
1416            final Integer JavaDoc thread)
1417            throws SystemException {
1418        try {
1419            UserDO user = mailSession.getUser();
1420            Session JavaDoc javaMailSession;
1421            try {
1422                javaMailSession = mailSession.getJavaMailSession();
1423            } catch (java.security.NoSuchProviderException JavaDoc e) {
1424                throw new SystemException(e);
1425            }
1426
1427            MimeMessage JavaDoc oldMessage = this.findJavaMailMessageByFolderMessageId(folder,
1428                    id);
1429
1430            // if this is HTML, we'll need to store multipart data
1431
MessageTextParts messageTextParts = null;
1432
1433            // we will build the subject up using a prefix (possibly)
1434
StringBuffer JavaDoc subject = new StringBuffer JavaDoc();
1435            String JavaDoc subjectPrefix = null;
1436
1437            // there may also be a text prefix (= header)
1438
StringBuffer JavaDoc messageText = new StringBuffer JavaDoc();
1439            String JavaDoc oldMessageText = null;
1440            String JavaDoc messageHeader = null;
1441
1442            // we'll format the reply text
1443
HTMLFormatter formatter = new HTMLFormatter();
1444
1445            // mail API methods for reply, replyall
1446
MimeMessage JavaDoc newMessage = (MimeMessage JavaDoc) oldMessage.reply(MailConstants.THREAD_REPLY_ALL.equals(
1447                        thread));
1448
1449            // emailReplyIndent means '> ' (without the quotes)
1450
// note: HTML formatting might remove this below!!
1451
LineBreakFormat lineBreaks = new LineBreakFormat();
1452
1453            lineBreaks.setPrepend(settings.getStringSetting(mailSession,
1454                    "emailReplyIndent",
1455                    user));
1456            formatter.add(lineBreaks);
1457
1458            // first the subject prefix
1459
subjectPrefix = settings.getStringSetting(mailSession,
1460                    "emailSubjectReplyPrefix",
1461                    user);
1462
1463            // for the reply we want to make a new multipart, if
1464
// this is an HTML mail
1465
if (oldMessage.isMimeType("multipart/*")) {
1466                messageHeader = settings.getStringSetting(mailSession,
1467                        "emailHeaderReplyHTML",
1468                        user);
1469                messageTextParts = getMultiPartText(oldMessage);
1470            } else {
1471                messageHeader = settings.getStringSetting(mailSession,
1472                        "emailHeaderReplyText",
1473                        user);
1474            }
1475
1476            // prepend Re: unless the previous subject already starts like this
1477
String JavaDoc oldSubject = StringHandling.getNotNull(oldMessage.getSubject(),
1478                    getNullString());
1479
1480            if ((subjectPrefix != null) &&
1481                    (!oldSubject.startsWith(subjectPrefix))) {
1482                subject.append(subjectPrefix);
1483            }
1484
1485            subject.append(oldSubject);
1486            newMessage.setSubject(subject.toString());
1487
1488            // locate the multipart in the new message, for multiparts
1489
int format = FormatConstants.FORMAT_TEXT;
1490
1491            if (oldMessage.isMimeType("multipart/*")) {
1492                // if there is an HTML text, use that
1493
if (messageTextParts.HTMLPart != null) {
1494                    oldMessageText = (String JavaDoc) messageTextParts.HTMLPart.getContent();
1495                    format = FormatConstants.FORMAT_HTML;
1496                } else if (messageTextParts.textPart != null) {
1497                    oldMessageText = (String JavaDoc) messageTextParts.textPart.getContent();
1498                }
1499            } else {
1500                oldMessageText = (String JavaDoc) oldMessage.getContent();
1501            }
1502
1503            // if we have to build the text with a prefix/header, do that
1504
if ((oldMessageText != null) && (messageHeader != null)) {
1505                messageText.append(formatMessageHeader(messageHeader, oldMessage));
1506            }
1507
1508            if (oldMessageText != null) {
1509                messageText.append(oldMessageText);
1510            }
1511
1512            if (format == FormatConstants.FORMAT_HTML) {
1513                // we want to work with copies of the original texts,
1514
// create a new HTML content multipart
1515
MimeMultipart JavaDoc newTextContent = createHTMLContent(messageText.toString());
1516
1517                // set the multipart/alternative as the content of the base part
1518
newMessage.setContent(newTextContent);
1519                newMessage.setHeader("Content-Type",
1520                    newTextContent.getContentType());
1521
1522                // plain text replies and forwards are easier
1523
} else {
1524                newMessage.setContent(messageText.toString(), "text/plain");
1525            }
1526
1527            return newMessage;
1528        } catch (MessagingException JavaDoc e) {
1529            throw new SystemException(e);
1530        } catch (IOException JavaDoc e) {
1531            throw new SystemException(e);
1532        }
1533    }
1534
1535    /**
1536     * <p>Create a new message in the drafts folder from an existing one,
1537     * based on a 'thread'. The thread indicates that the message is a:<br/>
1538     * <ul>
1539     * <li>reply to all recipients of a previous message</li>
1540     * <li>reply to one recipient of a previous message</li>
1541     * <li>previous message(s) forwarded to new recipients</li>
1542     * <li>an existing (draft) message being altered for resending</li>
1543     * </ul></p>
1544     *
1545     * <p>This new message in the drafts folder can then be used to store
1546     * attachments or for reviewing before sending.</p>
1547     *
1548     * @param mailSession valid mail session to which the user should already be
1549     * logged in.
1550     * @param folderName the name of the folder to copy existing messages from.
1551     * @param messageIds the unique identifier of the messages to be extended.
1552     * Can be <code>null</code> if a new message is requeested. When
1553     * forwarding, multiple address identifiers may be specified otherwise
1554     * (if editing a draft message or replying) only one message identifier
1555     * should be set in the list.
1556     * @param thread set to one of the constants in {@link MailConstants
1557     * MailConstants}.
1558     * @return populated message data object matching the required
1559     * message, and with the <code>id</code> set to the message in the
1560     * drafts folder.
1561     *
1562     * @ejb.interface-method
1563     * view-type = "remote"
1564     */

1565    public MessageDO createThreadMessage(final MailSession mailSession,
1566            final String JavaDoc folderName,
1567            final List JavaDoc messageIds,
1568            final Integer JavaDoc thread)
1569            throws SystemException {
1570        checkDateFormatter(mailSession);
1571        MimeMessage JavaDoc newMessage = null;
1572        MessageDO messageDO = null;
1573        Session JavaDoc javaMailSession;
1574
1575        try {
1576            javaMailSession = mailSession.getJavaMailSession();
1577        } catch (AuthenticationFailedException JavaDoc e) {
1578            throw new SystemException(
1579                "User is no longer authorized to use this server: " +
1580                e.getMessage(),
1581                e);
1582        } catch (MessagingException JavaDoc e) {
1583            throw new SystemException(e);
1584        } catch (java.security.NoSuchProviderException JavaDoc e) {
1585            throw new SystemException(e);
1586        }
1587
1588        Store JavaDoc store = mailServer.connectStore(mailSession);
1589        try {
1590            // check if everything's set to create based on thread
1591
if ((folderName == null) || (messageIds == null) ||
1592                    (messageIds.size() == 0) || (thread == null)) {
1593                throw new SystemException(
1594                    "ERROR in MailBean.createThreadMessage: these parameters cannot be empty:" +
1595                    " folderName (specified: '" + folderName +
1596                    "') messageIds (specified: '" + messageIds +
1597                    "') thread (specified: '" + thread + "').");
1598            }
1599
1600            // prerequisite - check this is a forward thread if there are > 1 messages
1601
if ((messageIds.size() > 1) &&
1602                    !MailConstants.THREAD_FORWARD.equals(thread)) {
1603                throw new SystemException("ERROR in MailBean: too many messages (" +
1604                    messageIds.size() +
1605                    ") in thread. Only 'forward' can have multiple messages.");
1606            }
1607
1608            // create a new message appropriate to the thread type requested
1609
Folder JavaDoc folder = mailServer.getFolder(mailSession, store, folderName);
1610
1611            folder.open(Folder.READ_ONLY);
1612
1613            if (MailConstants.THREAD_FORWARD.equals(thread)) {
1614                newMessage = createForwardedMessage(mailSession, folder,
1615                        messageIds);
1616            } else {
1617                String JavaDoc messageId = (String JavaDoc) messageIds.get(0);
1618
1619                if (MailConstants.THREAD_DRAFT.equals(thread)) {
1620                    MimeMessage JavaDoc oldMessage = this.findJavaMailMessageByFolderMessageId(folder,
1621                            messageId);
1622                    newMessage = new MimeMessage JavaDoc(oldMessage);
1623                } else {
1624                    newMessage = createReplyMessage(mailSession, folder,
1625                            messageId, thread);
1626                }
1627            }
1628
1629            // now we should have the new message, let's put it to the drafts folder
1630
Folder JavaDoc draftsFolder = openDraftsFolder(store, mailSession);
1631
1632            messageDO = getDOFromJavaMailMessage(newMessage, true);
1633
1634            Message JavaDoc[] messages = { newMessage };
1635
1636            draftsFolder.appendMessages(messages);
1637            messageDO.setFolderName(draftsFolder.getName());
1638            draftsFolder.close(true);
1639            folder.close(false);
1640        } catch (MessagingException JavaDoc e) {
1641            throw new SystemException(e);
1642        } finally {
1643            try {
1644                store.close();
1645            } catch (MessagingException JavaDoc e) {
1646                logger.error("Messaging exception on closing the store", e);
1647            }
1648        }
1649
1650        return messageDO;
1651    }
1652
1653    /**
1654     * <p>Delete a list of messages from the trash folder.</p>
1655     *
1656     * @param mailSession valid mail session to which the user should already be
1657     * logged in.
1658     * @param ids the unique identifiers (<code>String</code> instances) of the
1659     * messages to be removed.
1660     * @exception MessageNotFoundException if the folder doesn't exist, or there
1661     * is no matching mail in this folder.
1662     *
1663     * @ejb.interface-method
1664     * view-type = "remote"
1665     */

1666    public void deleteMessagesFromTrash(final MailSession mailSession,
1667            final List JavaDoc ids)
1668            throws SystemException {
1669        checkDateFormatter(mailSession);
1670        Store JavaDoc store = mailServer.connectStore(mailSession);
1671        try {
1672            UserDO user = mailSession.getUser();
1673            Session JavaDoc javaMailSession;
1674            try {
1675                javaMailSession = mailSession.getJavaMailSession();
1676            } catch (java.security.NoSuchProviderException JavaDoc e) {
1677                throw new SystemException(e);
1678            }
1679            Folder JavaDoc trashFolder = mailServer.getFolder(mailSession, store,
1680                    settings.getStringSetting(
1681                        mailSession,
1682                        "emailFolderTrash",
1683                        user));
1684
1685            trashFolder.open(Folder.READ_WRITE);
1686
1687            // now mark all the original messages as deleted
1688
for (Iterator JavaDoc i = ids.iterator(); i.hasNext();) {
1689                String JavaDoc id = (String JavaDoc) i.next();
1690                MimeMessage JavaDoc message = findJavaMailMessageByFolderMessageId(trashFolder,
1691                        id);
1692
1693                message.setFlag(Flags.Flag.DELETED, true);
1694            }
1695
1696            trashFolder.expunge();
1697            trashFolder.close(true);
1698        } catch (MessagingException JavaDoc e) {
1699            throw new SystemException(e);
1700        } finally {
1701            try {
1702                store.close();
1703            } catch (MessagingException JavaDoc e) {
1704                logger.error("Messaging exception on closing the store", e);
1705            }
1706        }
1707    }
1708
1709    /**
1710     * <p>Check whether or not a given folder pathname exists.</p>
1711     *
1712     * @param mailSession valid mail session to which the user should already be
1713     * logged in.
1714     * @param folderName the full path name of the folder to check.
1715     * @return <code>true</code> if the folder exists, otherwise <code>false</code>.
1716     *
1717     * @ejb.interface-method
1718     * view-type = "remote"
1719     */

1720    public boolean doesFolderExist(final MailSession mailSession,
1721            final String JavaDoc folderName)
1722            throws SystemException {
1723        assert (mailSession != null);
1724        checkDateFormatter(mailSession);
1725
1726        Session JavaDoc javaMailSession = null;
1727
1728        try {
1729            javaMailSession = mailSession.getJavaMailSession();
1730        } catch (AuthenticationFailedException JavaDoc e) {
1731            throw new SystemException(
1732                "User is no longer authorized to use this server: " +
1733                e.getMessage(),
1734                e);
1735        } catch (MessagingException JavaDoc e) {
1736            throw new SystemException(e);
1737        } catch (SecurityServerException e) {
1738            throw new SystemException(e);
1739        } catch (java.security.NoSuchProviderException JavaDoc e) {
1740            throw new SystemException(e);
1741        }
1742
1743        boolean folderExists = false;
1744
1745        Store JavaDoc store = mailServer.connectStore(mailSession);
1746        try {
1747            if (folderName == null) {
1748                throw new SystemException(
1749                    "ERROR in MailBean.doesFolderExist: folderName is null");
1750            }
1751
1752            Folder JavaDoc folder = mailServer.getFolder(mailSession, store, folderName);
1753
1754            folderExists = folder.exists();
1755        } catch (MessagingException JavaDoc e) {
1756            throw new SystemException(e);
1757        } finally {
1758            try {
1759                store.close();
1760            } catch (MessagingException JavaDoc e) {
1761                logger.error("Messaging exception on closing the store", e);
1762            }
1763        }
1764
1765        return folderExists;
1766    }
1767
1768    /**
1769     * <p>Locate the message in the folder given with the specified unique
1770     * identifier.</p>
1771     *
1772     * @param folder folder to search for the message in.
1773     * @param id the unique identifier of the message.
1774     * @return the message in this folder with the id required, or
1775     * <code>null</code> if no such message exists.
1776     * @exception MessageNotFoundException if the folder doesn't exist, or there
1777     * is no matching mail in this folder.
1778     */

1779    private MimeMessage JavaDoc findJavaMailMessageByFolderMessageId(final Folder JavaDoc folder,
1780            final String JavaDoc id) throws SystemException {
1781        MimeMessage JavaDoc message = null;
1782
1783        // folder name used for errors only
1784
String JavaDoc folderName = (folder == null) ? "[none]" : folder.getName();
1785
1786        try {
1787            // prerequisites, the id cannot be null, and folder must exist and be open
1788
if (StringHandling.isNullOrEmpty(id)) {
1789                throw new MessageNotFoundException(folderName, id,
1790                    "you must specify a valid message id");
1791            } else if (folder == null) {
1792                throw new MessageNotFoundException(folderName, id,
1793                    "you must specify a valid folder");
1794            } else if (!folder.exists()) {
1795                throw new MessageNotFoundException(folderName, id,
1796                    folderName + " does not exist");
1797            } else if (!folder.isOpen()) {
1798                throw new MessageNotFoundException(folderName, id,
1799                    folderName + " is not open");
1800            }
1801
1802            // go thro' each one and compare ids - it's slow but it works
1803
// TODO: - examine ways to cache the mail folders
1804
for (int messageNumber = 1;
1805                    messageNumber <= folder.getMessageCount();
1806                    ++messageNumber) {
1807                MimeMessage JavaDoc messageTest = (MimeMessage JavaDoc) folder.getMessage(messageNumber);
1808
1809                if (id.equals(messageTest.getMessageID())) {
1810                    message = messageTest;
1811
1812                    break;
1813                }
1814            }
1815        } catch (FolderNotFoundException JavaDoc e) {
1816            throw new MessageNotFoundException(folderName, id,
1817                "FolderNotFoundException looking for " + folderName + ": " +
1818                e.getMessage(),
1819                e);
1820        } catch (MessagingException JavaDoc e) {
1821            throw new SystemException(e);
1822        }
1823
1824        return message;
1825    }
1826
1827    /**
1828     * <p>This method retrieves the requested message and sets all the
1829     * attributes of a MessageDO object for use on client side.</p>
1830     *
1831     * @param mailSession valid mail session to which the user should already be
1832     * logged in.
1833     * @param folderName the name of the folder the message is located in.
1834     * @param id the unique identifier of the message.
1835     * @return a MessageDO instance filled up with the messages attributes,
1836     * except the contents of the attachments.
1837     * @exception MessageNotFoundException if the folder doesn't exist, or there
1838     * is no matching mail in this folder.
1839     *
1840     * @ejb.interface-method
1841     * view-type = "remote"
1842     */

1843    public MessageDO findMessageByFolderMessageId(final MailSession mailSession,
1844            final String JavaDoc folderName,
1845            final String JavaDoc id) throws SystemException {
1846        checkDateFormatter(mailSession);
1847        MessageDO messageDO = null;
1848
1849        Store JavaDoc store = mailServer.connectStore(mailSession);
1850        try {
1851            if (folderName == null) {
1852                logger.error(
1853                    "MailBean.findMessageByFolderMessageId(): "
1854                        + "folderName is null.");
1855                return null;
1856            }
1857            // right, we now have to find the message using the folder name and the message number
1858
Folder JavaDoc folder = mailServer.getFolder(mailSession, store, folderName);
1859
1860            // now open the folder
1861
folder.open(Folder.READ_ONLY);
1862
1863            MimeMessage JavaDoc message = findJavaMailMessageByFolderMessageId(folder,
1864                    id);
1865
1866            // if some other program download the message -> we didn't find it so return null
1867
if (message != null) {
1868                messageDO = getDOFromJavaMailMessage(message, true);
1869            }
1870
1871            folder.close(false);
1872        } catch (MessagingException JavaDoc e) {
1873            throw new SystemException(e);
1874        } finally {
1875            try {
1876                store.close();
1877            } catch (MessagingException JavaDoc e) {
1878                logger.error("Messaging exception on closing the store", e);
1879            }
1880        }
1881
1882        return messageDO;
1883    }
1884
1885    /**
1886     * <p>Used in the main folder index page, this method returns the contents
1887     * of a folder as a <code>List</code> of
1888     * <code>MessageDO</code> instances.</p>
1889     *
1890     * <p><strong>Note:</strong> for efficiency reasons, this method does not fill the
1891     * text, format or attachment values of the returned <code>MessageDO</code>
1892     * instance. For that, you must call
1893     * {@link #findMessageByFolderMessageId findMessageByFolderMessageId}.</p>
1894     *
1895     * @param mailSession valid mail session to which the user should already be
1896     * logged in.
1897     * @param folderName the name of the folder to list.
1898     * @param sortBy the field to sort the returned list by. Set to one of the
1899     * <code>SORT_...</code> constants in {@link MailConstants MailConstants}.
1900     * @param sortAscending if <code>true</code> then the messages are sorted in
1901     * ascending order, otherwise (<code>false</code>) they are descending.
1902     * @return <code>List</code> of
1903     * <code>MessageDO</code> instances.
1904     *
1905     * @ejb.interface-method
1906     * view-type = "remote"
1907     */

1908    public List JavaDoc findMessagesInFolder(final MailSession mailSession,
1909            final String JavaDoc folderName,
1910            final Integer JavaDoc sortBy,
1911            final boolean sortAscending)
1912            throws SystemException {
1913        checkDateFormatter(mailSession);
1914        UserDO user = mailSession.getUser();
1915        MessageDO messageDO;
1916        Message JavaDoc[] messages;
1917        int i;
1918
1919        // see if we have a mail session
1920
Session JavaDoc javaMailSession;
1921
1922        // make a tree map to sort the items
1923
ListColumnComparator comparator = new ListColumnComparator(sortAscending);
1924        TreeMap JavaDoc map = new TreeMap JavaDoc(comparator);
1925
1926        // some types must be sorted numerically, rather than alphanumerically
1927
comparator.setSortNumerically(MailConstants.SORT_RECEIVED.equals(sortBy)
1928                || MailConstants.SORT_SENT.equals(sortBy)
1929                || MailConstants.SORT_SIZE.equals(sortBy));
1930
1931        try {
1932            javaMailSession = mailSession.getJavaMailSession();
1933        } catch (MessagingException JavaDoc e) {
1934            throw new SystemException(e);
1935        } catch (java.security.NoSuchProviderException JavaDoc e) {
1936            throw new SystemException(e);
1937        }
1938
1939        Store JavaDoc store = mailServer.connectStore(mailSession);
1940        try {
1941            Folder JavaDoc folderProcessed =
1942                mailServer.getFolder(mailSession, store, folderName);
1943
1944            // go thro and sort the contents
1945
String JavaDoc sentKey;
1946            StringBuffer JavaDoc key = new StringBuffer JavaDoc(32);
1947            GregorianCalendar JavaDoc received;
1948            GregorianCalendar JavaDoc sent;
1949
1950            // first go thro' and make sure there is an ivata message id for each
1951
// message - only necessary for incoming mails where message id
1952
// might not be unique
1953
String JavaDoc inboxFolderName = settings.getStringSetting(mailSession,
1954                    "emailFolderInbox",
1955                    user);
1956
1957            if (folderName.equalsIgnoreCase(inboxFolderName)) {
1958                folderProcessed.open(Folder.READ_WRITE);
1959                messages = folderProcessed.getMessages();
1960
1961                int length = messages.length;
1962
1963                for (i = 0; i < length; i++) {
1964                    MimeMessage JavaDoc message = (MimeMessage JavaDoc) messages[i];
1965
1966                    // check there is an ivata message id in the message id string
1967
String JavaDoc messageId = message.getMessageID();
1968
1969                    if ((messageId == null) ||
1970                            (messageId.indexOf("ivata-") == -1)) {
1971                        // create a new message dependent value object
1972
MessageDO newMessage = createDOFromJavaMailMessage(message, true);
1973                        Integer JavaDoc newId = newMessage.getId();
1974
1975                        if (messageId == null) {
1976                            messageId = "";
1977                        }
1978
1979                        messageId += ("ivata-" + newId);
1980
1981                        MimeMessage JavaDoc ivataMessage = new MimeMessage JavaDoc(message);
1982
1983                        ivataMessage.setHeader("Message-ID", messageId);
1984                        message.setFlag(Flags.Flag.DELETED, true);
1985
1986                        Message JavaDoc[] ivataMessages = { ivataMessage };
1987
1988                        folderProcessed.appendMessages(ivataMessages);
1989                    }
1990                }
1991
1992                // close the folder to save changes and re-open read only
1993
folderProcessed.close(true);
1994            }
1995
1996            // now we can be sure-ish that message ids are unique -
1997
// the only way they can't be unique is if this is not the inbox
1998
// and JavaMail doesn't create a unique id when we make a new mail
1999
folderProcessed.open(Folder.READ_ONLY);
2000            messages = folderProcessed.getMessages();
2001
2002            for (i = 0; i < messages.length; i++) {
2003                MimeMessage JavaDoc message = (MimeMessage JavaDoc) messages[i];
2004
2005                messageDO = getDOFromJavaMailMessage(message, false);
2006                sent = messageDO.getSent();
2007                sentKey = ((sent == null) ? ""
2008                                          : new Long JavaDoc(sent.getTime().getTime()).toString());
2009                key.delete(0, key.capacity());
2010
2011                // which field sorts is determined by the value of sortBy...
2012
if (MailConstants.SORT_FOLDER.equals(sortBy)) {
2013                    key.append(StringHandling.getNotNull(
2014                            messageDO.getFolderName()));
2015                } else if (MailConstants.SORT_ID.equals(sortBy)) {
2016                    key.append(StringHandling.getNotNull(messageDO.getMessageID()));
2017                } else if (MailConstants.SORT_RECEIVED.equals(sortBy)) {
2018                    received = messageDO.getReceived();
2019                    key.append(((received == null) ? ""
2020                                                   : new Long JavaDoc(
2021                            received.getTime().getTime()).toString()));
2022                } else if (MailConstants.SORT_RECIPIENTS.equals(sortBy)) {
2023                    key.append(StringHandling.getNotNull(
2024                            messageDO.getRecipients()));
2025                } else if (MailConstants.SORT_RECIPIENTS_BCC.equals(sortBy)) {
2026                    key.append(StringHandling.getNotNull(
2027                            messageDO.getRecipientsBCC()));
2028                } else if (MailConstants.SORT_RECIPIENTS_CC.equals(sortBy)) {
2029                    key.append(StringHandling.getNotNull(
2030                            messageDO.getRecipientsCC()));
2031                } else if (MailConstants.SORT_SENDERS.equals(sortBy)) {
2032                    key.append(StringHandling.getNotNull(messageDO.getSenders()));
2033                } else if (MailConstants.SORT_SIZE.equals(sortBy)) {
2034                    key.append(StringHandling.getNotNull(messageDO.getSize()));
2035                } else if (!MailConstants.SORT_SENT.equals(sortBy)) {
2036                    // default is subject - note sent date is appended below
2037
key.append(StringHandling.getNotNull(messageDO.getSubject()));
2038                }
2039
2040                // append the sent date to the key for secondary sorting
2041
key.append(sentKey);
2042                map.put(key.toString(), messageDO);
2043            }
2044        } catch (NoSuchProviderException JavaDoc e) {
2045            throw new SystemException(e);
2046        } catch (MessagingException JavaDoc e) {
2047            throw new SystemException(e);
2048        } catch (SettingsDataTypeException e) {
2049            throw new SystemException(e);
2050        } finally {
2051            try {
2052                store.close();
2053            } catch (MessagingException JavaDoc e) {
2054                logger.error("Messaging exception on closing the store", e);
2055            }
2056        }
2057
2058        return new Vector JavaDoc(map.values());
2059    }
2060
2061    /**
2062     * <p>Format a header for a reply, or a forwarded message.</p>
2063     *
2064     * @param messageHeader the header to format.
2065     * @param oldMessage the old message to read data from
2066     * @return formatted message header.
2067     */

2068    private String JavaDoc formatMessageHeader(final String JavaDoc messageHeader,
2069            final MimeMessage JavaDoc oldMessage)
2070            throws SystemException {
2071        Date JavaDoc date;
2072        String JavaDoc oldSentDate;
2073        String JavaDoc oldSubject;
2074
2075        try {
2076            date = oldMessage.getSentDate();
2077            oldSubject = StringHandling.getNotNull(oldMessage.getSubject(),
2078                    getNullString());
2079        } catch (MessagingException JavaDoc e) {
2080            throw new SystemException(e);
2081        }
2082
2083        if (date == null) {
2084            oldSentDate = "";
2085        } else {
2086            oldSentDate = dateFormatter.format(date);
2087        }
2088
2089        EmailAddressFormatter emailFormatter = new EmailAddressFormatter();
2090
2091        try {
2092            // the same four arguments are used in the same order
2093
// for both reply & forward headers in resource files
2094
String JavaDoc oldSenders = StringHandling.getNotNull(emailFormatter.format(
2095                        oldMessage.getFrom()), getNullString());
2096            String JavaDoc oldRecipients = StringHandling.getNotNull(emailFormatter.format(
2097                        oldMessage.getRecipients(MimeMessage.RecipientType.TO)),
2098                    getNullString());
2099            Object JavaDoc[] arguments = {
2100                oldSenders, oldRecipients, oldSubject, oldSentDate
2101            };
2102
2103            return MessageFormat.format(messageHeader, arguments);
2104        } catch (MessagingException JavaDoc e) {
2105            throw new SystemException(e);
2106        }
2107    }
2108
2109    /**
2110     * <p>Retrieve an attachment's content and it's MimeType. This method is
2111     * used to by the download servlet.</p>
2112     *
2113     * @param mailSession valid mail session to which the user should already be
2114     * logged in.
2115     * @param folderName the name of the folder the message is located in.
2116     * @param messageId the unique identifier of the message.
2117     * @param attachmentId the unique identifier of the attachment.
2118     * @return attachment data object containing attachment content
2119     * and mime type.
2120     * @exception MessageNotFoundException if the folder doesn't exist, or there
2121     * is no matching mail in this folder.
2122     *
2123     * @ejb.interface-method
2124     * view-type = "remote"
2125     */

2126    public final FileContentDO getAttachment(final MailSession mailSession,
2127            final String JavaDoc folderName,
2128            final String JavaDoc messageId,
2129            final String JavaDoc attachmentId)
2130            throws SystemException {
2131        checkDateFormatter(mailSession);
2132        FileContentDO attachmentDO = null;
2133
2134        Store JavaDoc store = mailServer.connectStore(mailSession);
2135        try {
2136            // right, we now have to find the message using the folder name and the message number
2137
Folder JavaDoc folder = mailServer.getFolder(mailSession, store, folderName);
2138
2139            // now open the folder
2140
folder.open(Folder.READ_ONLY);
2141
2142            Message JavaDoc message = findJavaMailMessageByFolderMessageId(folder,
2143                    messageId);
2144            InputStream JavaDoc inStream = null;
2145            String JavaDoc mimeType = null;
2146
2147            // prerequisites - the message must be multipart, otherwise it can
2148
// be only a self-contained attachment
2149
if (message.isMimeType("multipart/*")) {
2150                MimeMultipart JavaDoc multiMessage = (MimeMultipart JavaDoc) message.getContent();
2151                MimeBodyPart JavaDoc subPart = getAttachment(multiMessage, attachmentId);
2152                inStream = subPart.getInputStream();
2153                mimeType = subPart.getContentType();
2154            } else {
2155                String JavaDoc withOutAngels = attachmentId.substring(1,
2156                        attachmentId.length() - 1);
2157
2158                if (((message.getFileName() != null) &
2159                        attachmentId.equals(message.getFileName())) ||
2160                        ((message.getFileName() != null) &
2161                        withOutAngels.equals(message.getFileName()))) {
2162                    inStream = message.getInputStream();
2163                    mimeType = message.getContentType();
2164                }
2165            }
2166
2167            if ((inStream != null) && (mimeType != null)) {
2168                int oneByte;
2169
2170                ByteArrayOutputStream JavaDoc outStream = new ByteArrayOutputStream JavaDoc();
2171
2172                while ((oneByte = inStream.read()) != -1) {
2173                    outStream.write(oneByte);
2174                }
2175
2176                attachmentDO = new FileContentDO(new SerializedByteArray(
2177                            outStream.toByteArray()), mimeType);
2178            }
2179
2180            folder.close(false);
2181        } catch (MessagingException JavaDoc e) {
2182            throw new SystemException(e);
2183        } catch (IOException JavaDoc e) {
2184            throw new SystemException(e);
2185        } finally {
2186            try {
2187                store.close();
2188            } catch (MessagingException JavaDoc e) {
2189                logger.error("Messaging exception on closing the store", e);
2190            }
2191        }
2192
2193        return attachmentDO;
2194    }
2195
2196    /**
2197     * <p>This method goes through multiparts recursively looking for a part
2198     * with the given content id
2199     * @param multiPart the <code>MimeMultipart</code> to search
2200     * @param attachmentId the id of the wanted part
2201     * @return <code>MimeBodyPart</code> with the wanted id or <code>null</code>
2202     * when there wasn't such part in the given multipart
2203     * @throws MessagingException
2204     * @throws IOException
2205     */

2206    private MimeBodyPart JavaDoc getAttachment(final MimeMultipart JavaDoc multiPart,
2207            final String JavaDoc attachmentId) throws MessagingException JavaDoc, IOException JavaDoc {
2208        MimeBodyPart JavaDoc attachment = (MimeBodyPart JavaDoc) multiPart.getBodyPart(attachmentId);
2209
2210        // if the attachment was not found in this level, it's more embedded...
2211
if (attachment == null) {
2212            MimeBodyPart JavaDoc embeddedPart;
2213
2214            for (int i = 0; i < multiPart.getCount(); i++) {
2215                embeddedPart = (MimeBodyPart JavaDoc) multiPart.getBodyPart(i);
2216
2217                // go deeper to multiparts
2218
if (embeddedPart.isMimeType("multipart/*")) {
2219                    // done when something returned from recursive call
2220
if ((attachment = getAttachment(
2221                                    (MimeMultipart JavaDoc) embeddedPart.getContent(),
2222                                    attachmentId)) != null) {
2223                        break;
2224                    }
2225                } else if ((embeddedPart.getFileName() != null) &&
2226                        (attachmentId.indexOf(embeddedPart.getFileName()) != -1)) {
2227                    attachment = embeddedPart;
2228
2229                    break;
2230                }
2231            }
2232        }
2233
2234        return attachment;
2235    }
2236
2237    /**
2238     * <p>Convert a <em>JavaMail</em> message to an <em>ivata groupware</em> dependent
2239     * value object.</p>
2240     *
2241     * @param message a valid <em>JavaMail</em> message to be converted.
2242     * @param includeContent <code>true</code> if the <code>text</code> and
2243     * attachments of the message should also be set, otherwise
2244     * <code>false</code>.
2245     * @return message data object with the values filled out to match
2246     * the <em>JavaMail</em> object.
2247     */

2248    private MessageDO getDOFromJavaMailMessage(final MimeMessage JavaDoc message,
2249            final boolean includeContent)
2250            throws SystemException {
2251        // TODO: this is almost the same as the createDO... method just now
2252
// right - we got here, so that means we have a message
2253
MessageDO messageDO = new MessageDO();
2254        try {
2255            //setting the fields of the MessageDO:
2256
if (message.getFolder() != null) {
2257                messageDO.setFolderName(message.getFolder().getName());
2258            }
2259
2260            if (message.getReceivedDate() != null) {
2261                GregorianCalendar JavaDoc receivedDate = new GregorianCalendar JavaDoc();
2262
2263                receivedDate.setTime(message.getReceivedDate());
2264                messageDO.setReceived(receivedDate);
2265            }
2266
2267            if (message.getRecipients(Message.RecipientType.TO) != null) {
2268                messageDO.setRecipients(Arrays.asList(toStringArray(
2269                            message.getRecipients(Message.RecipientType.TO))));
2270            }
2271
2272            if (message.getRecipients(Message.RecipientType.CC) != null) {
2273                messageDO.setRecipientsCC(Arrays.asList(toStringArray(
2274                            message.getRecipients(Message.RecipientType.CC))));
2275            }
2276
2277            if (message.getRecipients(Message.RecipientType.BCC) != null) {
2278                messageDO.setRecipientsBCC(Arrays.asList(toStringArray(
2279                            message.getRecipients(Message.RecipientType.BCC))));
2280            }
2281
2282            if (message.getFrom() != null) {
2283                messageDO.setSenders(Arrays.asList(toStringArray(
2284                            message.getFrom())));
2285            }
2286
2287            if (message.getSentDate() != null) {
2288                GregorianCalendar JavaDoc sentDate = new GregorianCalendar JavaDoc();
2289
2290                sentDate.setTime(message.getSentDate());
2291                messageDO.setSent(sentDate);
2292            }
2293
2294            messageDO.setSize(new Integer JavaDoc(message.getSize()));
2295            messageDO.setSubject(message.getSubject());
2296
2297            // message content handling - not always done for efficiency in lists
2298
if (includeContent) {
2299                Integer JavaDoc format;
2300                String JavaDoc text;
2301
2302                // create new, empty List for our attachments
2303
messageDO.setAttachments(new Vector JavaDoc());
2304
2305                // if it is a multipart message (has attachments), pass control to
2306
// recursive routine to go thro' them all
2307
if (message.isMimeType("multipart/*")) {
2308                    addMultiPart(message, messageDO);
2309
2310                    // here are types with textual content
2311
} else if (message.isMimeType("text/*") ||
2312                        message.isMimeType("message/*")) {
2313                    // if it is not multipart, we're just left with text or HTML
2314
if (message.isMimeType("text/HTML")) {
2315                        // simple message with HTML content
2316
messageDO.setFormat(FormatConstants.FORMAT_HTML);
2317                    } else {
2318                        // anything else with simple content should have text content
2319
messageDO.setFormat(FormatConstants.FORMAT_TEXT);
2320                    }
2321
2322                    messageDO.setText((String JavaDoc) message.getContent());
2323
2324                    // other (not correct?) types, as self-contained attachments...
2325
} else {
2326                    messageDO.setFormat(FormatConstants.FORMAT_TEXT);
2327                    messageDO.setText("");
2328                    addPart(message, messageDO);
2329                }
2330            }
2331            messageDO.setMessageID(message.getMessageID());
2332        } catch (MessagingException JavaDoc e) {
2333            throw new SystemException(e);
2334        } catch (IOException JavaDoc e) {
2335            throw new SystemException(e);
2336        }
2337
2338        return messageDO;
2339    }
2340
2341    /**
2342     * <p>Helper for <code>createThreadMessage</code>. This method processes a
2343     * <em>Multipart</em> message or part and returns just the body parts
2344     * representing text in either plain-text and/or <code>HTML</code> format.</p>
2345     *
2346     * @param message or part to be processed.
2347     * @return the text of the message or part, it's plain text or <code>HTML</code>.
2348     */

2349    private MessageTextParts getMultiPartText(final Part JavaDoc message)
2350            throws SystemException {
2351        MessageTextParts messageTextParts = new MessageTextParts();
2352        MimeMultipart JavaDoc content;
2353        MimeBodyPart JavaDoc subPart;
2354        int i;
2355
2356        try {
2357            content = (MimeMultipart JavaDoc) message.getContent();
2358
2359            //go through all the subParts
2360
for (i = 0; i < content.getCount(); i++) {
2361                subPart = (MimeBodyPart JavaDoc) content.getBodyPart(i);
2362
2363                //when multipart/alternative, we are close to find what we want...
2364
if (message.isMimeType("multipart/alternative")) {
2365                    if (subPart.isMimeType("text/plain") &&
2366                            (messageTextParts.textPart == null)) {
2367                        messageTextParts.textPart = subPart;
2368                    } else if (subPart.isMimeType("text/HTML") &&
2369                            (messageTextParts.HTMLPart == null)) {
2370                        messageTextParts.HTMLPart = subPart;
2371
2372                        // usually the HTML part will come after the plain text
2373
// if the plain text is set, we're all finished
2374
if (messageTextParts.textPart != null) {
2375                            break;
2376                        }
2377                    }
2378                } else {
2379                    // if this is not alternative multipart, recurse to get the text
2380
if (subPart.isMimeType("multipart/*")) {
2381                        messageTextParts = getMultiPartText((Part JavaDoc) subPart);
2382
2383                        // when we are on a text subpart and text not set yet, this
2384
// should be it...
2385
} else if (subPart.isMimeType("text/plain") &&
2386                            (messageTextParts.textPart == null)) {
2387                        messageTextParts.textPart = subPart;
2388                    } else if (subPart.isMimeType("text/HTML") &&
2389                            (messageTextParts.HTMLPart == null)) {
2390                        messageTextParts.HTMLPart = subPart;
2391
2392                        break;
2393                    }
2394                }
2395            }
2396        } catch (MessagingException JavaDoc e) {
2397            throw new SystemException(e);
2398        } catch (java.io.IOException JavaDoc e) {
2399            throw new SystemException(e);
2400        }
2401
2402        return messageTextParts;
2403    }
2404
2405    /**
2406     * <p>Generic string to use when some message text/subject is null.</p>
2407     *
2408     * @return replacement text to use when a message element is null.
2409     */

2410    private String JavaDoc getNullString() {
2411        // TODO: i18n
2412
return "[none]";
2413    }
2414
2415    /**
2416     * <p>Retrieve all of the email aliases for the user provided, on the curent
2417     * email server. The aliases returned each one containing just the 'user' (or
2418     * 'local') part of the email address, before the '@' sign.</p>
2419     *
2420     * @param userName the name of the user for whom to retrieve the email aliases.
2421     * @return a <code>Collection</code> of <code>String</code> instances containing
2422     * the local part of the different email aliases this user has. If the user
2423     * has no aliaes, an empty collection is returned.
2424     */

2425    public List JavaDoc getUserAliases(final SecuritySession securitySession,
2426            final String JavaDoc userName)
2427            throws SystemException {
2428        checkMailServer();
2429        checkDateFormatter(securitySession);
2430
2431        List JavaDoc aliases = null;
2432        aliases = mailServer.getUserAliases(securitySession, userName);
2433
2434        return aliases;
2435    }
2436
2437    /**
2438     * <p>Get the vacation message for the user provided.</p>
2439     *
2440     * <p>The vacation message is a text the user can set, which will be sent
2441     * to all emails received at this address while the user is not present.</p>
2442     *
2443     * @param userName the name of the user for whom to get the vacation message.
2444     * @return the vacation message text for this user. If the user has no
2445     * vacation message set, <code>null</code> is returned.
2446     */

2447    public final String JavaDoc getVacationMessage(final SecuritySession securitySession,
2448            final String JavaDoc userName)
2449            throws SystemException {
2450        checkMailServer();
2451        checkDateFormatter(securitySession);
2452
2453        String JavaDoc vacationMessage = null;
2454        vacationMessage = mailServer.getVacationMessage(securitySession,
2455                userName);
2456
2457        return vacationMessage;
2458    }
2459
2460    /**
2461     * <p>Get the time the specified mail folder was last modified as a
2462     * <code>long</code>. This can then be saved and compared to subsequent
2463     * calls of this method to see if the folder has changed.</p>
2464     *
2465     * @param userName the name of the user for whom to locate the folder.
2466     * @param folderName the name of the folder to locate.
2467     * @return operating system specific timestamp indicating when the
2468     * folder was last changed.
2469     *
2470     * @ejb.interface-method
2471     * view-type = "remote"
2472     */

2473    public final boolean hasNewMessages(final SecuritySession securitySession,
2474            final String JavaDoc userName,
2475            final String JavaDoc folderName)
2476            throws SystemException {
2477        checkMailServer();
2478        if (userName == null) {
2479            throw new SystemException(
2480                "ERROR in MailBean.getFolderModified: userName is null.");
2481        }
2482
2483        if (folderName == null) {
2484            throw new SystemException(
2485                "ERROR in MailBean.getFolderModified: folderName is null.");
2486        }
2487
2488        return mailServer.hasNewMessages(securitySession,
2489                userName, folderName);
2490    }
2491
2492    /**
2493     * <p>Login to the mail system. This method should be called before any other,
2494     * to establish the mail session and store.</p>
2495     *
2496     * @param userName this user name is used to log into the remote system.
2497     * @param password the clear-text password to log into the remote system.
2498     * @throws GroupwareException if the person cannot log in.
2499     * @return the mail session (class <code>Session</code>) in a
2500     * <code>SessionSerializer</code>.
2501     *
2502     * @ejb.interface-method
2503     * view-type = "local"
2504     */

2505    public MailSession login(final UserDO user,
2506            final String JavaDoc password)
2507            throws SystemException {
2508        checkMailServer();
2509        return (MailSession) mailServer.login(user, password);
2510    }
2511
2512    /**
2513     * <p>Move a list of messages from one folder to another.</p>
2514     *
2515     * @param mailSession valid mail session to which the user should already be
2516     * logged in.
2517     * @param folderName the name of the folder the messages are currently located in.
2518     * @param ids the unique identifiers (<code>String</code> instances) of the
2519     * messages to be moved.
2520     * @param targetFolderName the name of the the folder the message will be moved
2521     * to.
2522     * @exception MessageNotFoundException if the folder doesn't exist, or there
2523     * is no matching mail in this folder.
2524     *
2525     * @ejb.interface-method
2526     * view-type = "remote"
2527     */

2528    public void moveMessages(final MailSession mailSession,
2529            final String JavaDoc folderName,
2530            final List JavaDoc ids,
2531            final String JavaDoc targetFolderName) throws SystemException {
2532        Store JavaDoc store = mailServer.connectStore(mailSession);
2533        checkDateFormatter(mailSession);
2534        try {
2535            Folder JavaDoc folder = mailServer.getFolder(mailSession, store, folderName);
2536
2537            folder.open(Folder.READ_WRITE);
2538
2539            Folder JavaDoc targetFolder =
2540                    mailServer.getFolder(mailSession, store, targetFolderName);
2541
2542            if (!targetFolder.exists()) {
2543                targetFolder.create(Folder.HOLDS_MESSAGES);
2544            }
2545
2546            targetFolder.open(Folder.READ_WRITE);
2547
2548            List JavaDoc messages = new Vector JavaDoc();
2549
2550            for (Iterator JavaDoc i = ids.iterator(); i.hasNext();) {
2551                String JavaDoc id = (String JavaDoc) i.next();
2552                MimeMessage JavaDoc message = findJavaMailMessageByFolderMessageId(folder,
2553                        id);
2554
2555                if (message == null) {
2556                    logger.error(
2557                        "MailBean.moveMessage:I couldn't find a message with id"
2558                        + id
2559                        + " in folder '"
2560                        + folder.getName()
2561                        + "'");
2562                } else {
2563                    messages.add(message);
2564                }
2565            }
2566
2567            if (!messages.isEmpty()) {
2568                Message JavaDoc[] messageArray = { };
2569
2570                messageArray = (Message JavaDoc[]) messages.toArray(messageArray);
2571                targetFolder.appendMessages(messageArray);
2572                targetFolder.close(false);
2573
2574                // now mark all the original messages as deleted
2575
for (Iterator JavaDoc i = messages.iterator(); i.hasNext();) {
2576                    Message JavaDoc message = (Message JavaDoc) i.next();
2577
2578                    message.setFlag(Flags.Flag.DELETED, true);
2579                }
2580            }
2581
2582            folder.expunge();
2583            folder.close(true);
2584        } catch (NoSuchProviderException JavaDoc e) {
2585            throw new SystemException(e);
2586        } catch (MessagingException JavaDoc e) {
2587            throw new SystemException(e);
2588        } finally {
2589            try {
2590                store.close();
2591            } catch (MessagingException JavaDoc e) {
2592                logger.error("Messaging exception on closing the store", e);
2593            }
2594        }
2595    }
2596
2597    /**
2598     * <p>Helper method to get the name of the drafts folder from the settings,
2599     * and then open the folder in read-write mode.</p>
2600     *
2601     * @param store connected store.
2602     * @param javaMailSession valid <em>JavaMail</em> session to which the user
2603     * should already be logged in.
2604     * @return opened drafts folder.
2605     * @exception NoSuchProviderException thrown by
2606     * <code>Session.getStore</code> if there is no <em>IMAP</em> store
2607     * available.
2608     * @exception MessagingException throw by <code>JavaMail</code> if there is
2609     * problem locating or opening the drafts folder.
2610     * @exception SettingsDataTypeException if there is a problem accessing the
2611     * setting "emailFolderDrafts".
2612     */

2613    private Folder JavaDoc openDraftsFolder(final Store JavaDoc store,
2614            final MailSession mailSession)
2615            throws SystemException {
2616        assert (store != null);
2617        assert (store.isConnected());
2618        assert (mailSession != null);
2619        checkDateFormatter(mailSession);
2620
2621        UserDO user = mailSession.getUser();
2622
2623        try {
2624            // first get the name of the drafts folder from the settings
2625
String JavaDoc draftsFolderName = settings.getStringSetting(mailSession,
2626                    "emailFolderDrafts",
2627                    user);
2628            Folder JavaDoc draftsFolder =
2629                    mailServer.getFolder(mailSession, store, draftsFolderName);
2630            if (!(draftsFolder.exists() ||
2631                    draftsFolder.create(Folder.HOLDS_MESSAGES))) {
2632                throw new SystemException(
2633                    "ERROR in MailBean.openDraftsFolder: Cannot create drafts folder.");
2634            }
2635
2636            draftsFolder.open(Folder.READ_WRITE);
2637            return draftsFolder;
2638        } catch (MessagingException JavaDoc e) {
2639            throw new SystemException(e);
2640        }
2641    }
2642
2643    /**
2644     * <p>Helper. This method calculates which of an old message's attachments
2645     * are still required and sets the content of the new message on this
2646     * basis.</p>
2647     *
2648     * <p>This method contains functionality from <code>setDO...</code> which
2649     * has been split off to avoid a long <code>if...else</code>.</p>
2650     *
2651     * @param messageDO data object containing the latest changes from
2652     * client-side.
2653     * @param newBasePart the new base part of the message with content
2654     * pre-prepared.
2655     * @param oldMessage previous message retained from drafts folder.
2656     * @param newMessage new message being constructed from the draft message and
2657     * messageDO changes.
2658     */

2659    private void retainAttachments(final MessageDO messageDO,
2660            final MimeBodyPart JavaDoc newBasePart,
2661            final MimeMessage JavaDoc oldMessage,
2662            final MimeMessage JavaDoc newMessage)
2663            throws SystemException {
2664        try {
2665            MimeMultipart JavaDoc newMasterContent = new MimeMultipart JavaDoc();
2666            MimeMultipart JavaDoc oldContent = (MimeMultipart JavaDoc) oldMessage.getContent();
2667
2668            // iterate through all the BodyParts (from 1 as it should be the base part)
2669
for (int j = 1; j < oldContent.getCount(); j++) {
2670                MimeBodyPart JavaDoc mimePart = new MimeBodyPart JavaDoc();
2671
2672                mimePart = (MimeBodyPart JavaDoc) oldContent.getBodyPart(j);
2673
2674                // if there are no attachments to remove, no need to find out if this one has to die
2675
if (messageDO.getAttachments() != null) {
2676                    // look if this BodyPart is in the list of attachments to delete
2677
for (Iterator JavaDoc i = messageDO.getAttachments().iterator();
2678                            i.hasNext();) {
2679                        String JavaDoc id = ((FileDO) i.next()).getName();
2680
2681                        // if it's an embedded message, try with messageId
2682
if ((mimePart.isMimeType("message/*") &&
2683                                (((MimeMessage JavaDoc) mimePart.getContent()).getMessageID()
2684                                      .equals(id))) ||
2685                                ((mimePart.getFileName() != null) &&
2686                                mimePart.getFileName().equals(id)) ||
2687                                ((mimePart.getContentID() != null) &&
2688                                mimePart.getContentID().equals(id))) {
2689                            newMasterContent.addBodyPart(mimePart);
2690                        }
2691                    }
2692                }
2693            }
2694
2695            // if there's at least one attachment left, it's worth to let it be multipart/mixed
2696
// and put the new base as the first part in this multipart
2697
if (newMasterContent.getCount() > 0) {
2698                newMasterContent.addBodyPart(newBasePart, 0);
2699                newMessage.setContent(newMasterContent);
2700
2701                //if there are no attachments, only the base part will be there
2702
} else {
2703                if (messageDO.getFormat() == FormatConstants.FORMAT_HTML) {
2704                    newMessage.setContent((MimeMultipart JavaDoc) newBasePart.getContent());
2705                    newMessage.setHeader("Content-Type",
2706                        newBasePart.getContentType());
2707                } else {
2708                    newMessage.setText(messageDO.getText());
2709                }
2710            }
2711        } catch (MessagingException JavaDoc e) {
2712            throw new SystemException(e);
2713        } catch (IOException JavaDoc e) {
2714            throw new SystemException(e);
2715        }
2716    }
2717
2718    /**
2719     * <p>Send a mime email message that is already composed. If <code>id</code>
2720     * has been set in <code>messageDO</code> it is assumed to point to a
2721     * message in the drafts folder. Attachments are copied from the message
2722     * who match the contents of <code>getAttachmentIds</code>. (All other
2723     * attachments are discarded.)</p>
2724     *
2725     * @param mailSession valid mail session to which the user should already be
2726     * logged in.
2727     * @param messageDO data object containing full details of the
2728     * message to be sent.
2729     *
2730     * @ejb.interface-method
2731     * view-type = "remote"
2732     */

2733    public void send(final MailSession mailSession,
2734            final MessageDO messageDO)
2735            throws SystemException {
2736        checkDateFormatter(mailSession);
2737        Store JavaDoc store = mailServer.connectStore(mailSession);
2738        try {
2739            // if mail is disabled, just get out
2740
if (!settings.getBooleanSetting(mailSession,
2741                    "emailEnable", null)
2742                             .booleanValue()) {
2743                return;
2744            }
2745
2746            Session JavaDoc javaMailSession;
2747            try {
2748                javaMailSession = mailSession.getJavaMailSession();
2749            } catch (SecurityServerException e1) {
2750                throw new SystemException(e1);
2751            } catch (java.security.NoSuchProviderException JavaDoc e1) {
2752                throw new SystemException(e1);
2753            }
2754
2755            // get the drafts folder in case we want to copy over an older mail
2756
Folder JavaDoc draftsFolder = openDraftsFolder(store, mailSession);
2757            MimeMessage JavaDoc newMessage = setDOToJavaMailMessage(javaMailSession,
2758                    draftsFolder, messageDO);
2759
2760            newMessage.setSentDate(Calendar.getInstance().getTime());
2761
2762            // this bit actually sends the message
2763
Transport.send(newMessage);
2764
2765            // add the message to the sent folder
2766
addToSentFolder(mailSession, newMessage);
2767
2768            // only now can we delete/expunge the old mail from the drafts folder
2769
draftsFolder.expunge();
2770            draftsFolder.close(true);
2771        } catch (MessagingException JavaDoc e) {
2772            throw new SystemException(e);
2773        } catch (SettingsDataTypeException e) {
2774            throw new SystemException(e);
2775        } finally {
2776            try {
2777                store.close();
2778            } catch (MessagingException JavaDoc e) {
2779                logger.error("Messaging exception on closing the store", e);
2780            }
2781        }
2782    }
2783
2784    /**
2785     * <p>Send an mime email message without using a data object.</p>
2786     *
2787     * @param mailSession valid mail session to which the user should already be
2788     * logged in.
2789     * @param fromAddress the address of the person sending the mail. This must
2790     * be formatted according to <a
2791     * HREF='http://www.faqs.org/rfcs/rfc822.HTML'>RFC822</a>.
2792     * @param to recipients, a <code>Collection</code> containing instances of
2793     * <code>String</code> or <code>UserDO</code> or
2794     * <code>PersonDO</code>. A mixture of these types is allowed. If the
2795     * type of an instance is <code>String</code>, then it must be formatted
2796     * according to <a HREF='http://www.faqs.org/rfcs/rfc822.HTML'>RFC822</a>.
2797     * Otherwise, if the type is <code>PersonDO</code>, the method
2798     * <code>getEmailAddress</code> must return a valid address string for
2799     * this person.
2800     * @param cc cc recipients. For format, see <code>to</code> parameter.
2801     * @param bcc bcc recipients. For format, see <code>to</code> parameter.
2802     * @param subject clear-text email subject field.
2803     * @param content any valid email content type, as defined by
2804     * <code>MimeMessage</code>.
2805     * @param contentType mime type for the <code>content</code> field, as
2806     * defined by <code>MimeMessage</code>.
2807     * @param addToSentFolder if set to <code>true</code> then the mail is added
2808     * to the sent folder of the current email session.
2809     *
2810     * @ejb.interface-method
2811     * view-type = "both"
2812     */

2813    public void send(final MailSession mailSession,
2814            final String JavaDoc fromAddress,
2815            final Collection JavaDoc to,
2816            final Collection JavaDoc cc,
2817            final Collection JavaDoc bcc,
2818            final String JavaDoc subject,
2819            Object JavaDoc content, String JavaDoc contentType, boolean addToSentFolder)
2820            throws SystemException {
2821        checkDateFormatter(mailSession);
2822        try {
2823            try {
2824                // if mail is disabled, just get out
2825
if (!settings.getBooleanSetting(mailSession, "emailEnable", null)
2826                                 .booleanValue()) {
2827                    return;
2828                }
2829            } catch (SettingsDataTypeException e) {
2830                throw new SystemException(e);
2831            }
2832
2833            // see if we have a mail session
2834
Session JavaDoc javaMailSession;
2835
2836            try {
2837                javaMailSession = mailSession.getJavaMailSession();
2838            } catch (AuthenticationFailedException JavaDoc e) {
2839                throw new SystemException(
2840                    "User is no longer authorized to use this server: " +
2841                    e.getMessage(),
2842                    e);
2843            } catch (MessagingException JavaDoc e) {
2844                throw new SystemException(e);
2845            } catch (SecurityServerException e) {
2846                throw new SystemException(e);
2847            } catch (java.security.NoSuchProviderException JavaDoc e) {
2848                throw new SystemException(e);
2849            }
2850
2851            Store JavaDoc store = javaMailSession.getStore("imap");
2852
2853            if (store == null) {
2854                throw new SystemException(
2855                    "ERROR in MailBean: could not access the mail store");
2856            }
2857
2858            MimeMessage JavaDoc message = new MimeMessage JavaDoc(javaMailSession);
2859
2860            try {
2861                message.setFrom(new InternetAddress JavaDoc(fromAddress));
2862                message.setSubject(subject);
2863                message.setRecipients(MimeMessage.RecipientType.TO,
2864                    convertAddresses(null, to));
2865
2866                if (cc != null) {
2867                    message.setRecipients(MimeMessage.RecipientType.CC,
2868                        convertAddresses(null, cc));
2869                }
2870
2871                if (bcc != null) {
2872                    message.setRecipients(MimeMessage.RecipientType.BCC,
2873                        convertAddresses(null, bcc));
2874                }
2875
2876                message.setContent(content, contentType);
2877                message.setSentDate(Calendar.getInstance().getTime());
2878            } catch (MessagingException JavaDoc e) {
2879                throw new SystemException("Please check your input: " +
2880                    e.getMessage(),
2881                    e);
2882            }
2883
2884            // send it
2885
try {
2886                Transport.send(message);
2887            } catch (MessagingException JavaDoc e) {
2888                throw new SystemException("The message could not be sent: " +
2889                    e.getMessage(),
2890                    e);
2891            }
2892
2893            // add the message to the sent items folder
2894
if (addToSentFolder) {
2895                addToSentFolder(mailSession, message);
2896            }
2897        } catch (NoSuchProviderException JavaDoc e) {
2898            throw new SystemException(e);
2899        }
2900    }
2901
2902    /**
2903     * <p>Convert an <em>ivata groupware</em> message data object into a
2904     * new <em>JavaMail</em> message that's ready to be sent.</p>
2905     *
2906     * <p><strong>Note:</strong> this method will look for an existing message (in the
2907     * drafts folder) to use for the attachments. This is only done if the
2908     * <code>MessageDO</code> has a valid <code>id</code>, and the drafts folder
2909     * provided is not <code>null</code>. The previous mail is marked for
2910     * deletion in the drafts folder, and this can be confirmed by expunging that
2911     * folder and calling <code>close</code> with <code>true</code>. This is
2912     * not done internally as it may depend on further actions (such as adding
2913     * another mail successfully to the folder).</p>
2914     *
2915     * @param javaMailSession valid <em>JavaMail</em> session to which the user
2916     * should already be logged in.
2917     * @param draftsFolder the opened drafts to retrieve a previous message from.
2918     * The previous message is identified by the <code>id</code> attribute
2919     * of the <code>messageDO</code>. If this parameter is <code>null</code>
2920     * then no previous mail is considered.
2921     * @param messageDO a valid message data object with the values
2922     * filled out to match the <em>JavaMail</em> object which will be sent.
2923     * @return a valid <em>JavaMail</em> message ready to be sent.
2924     * @exception MessageNotFoundException if the folder doesn't exist, or there
2925     * is no matching mail in this folder.
2926     */

2927    private MimeMessage JavaDoc setDOToJavaMailMessage(final Session JavaDoc javaMailSession,
2928            final Folder JavaDoc draftsFolder,
2929            final MessageDO messageDO)
2930            throws SystemException {
2931        MimeMessage JavaDoc newMessage = new MimeMessage JavaDoc(javaMailSession);
2932
2933        try {
2934            newMessage.addFrom(convertAddresses(null, messageDO.getSenders()));
2935            newMessage.setSubject(messageDO.getSubject());
2936            newMessage.setRecipients(MimeMessage.RecipientType.TO,
2937                convertAddresses(null, messageDO.getRecipients()));
2938
2939            if (messageDO.getRecipientsCC() != null) {
2940                newMessage.setRecipients(MimeMessage.RecipientType.CC,
2941                    convertAddresses(null, messageDO.getRecipientsCC()));
2942            }
2943
2944            if (messageDO.getRecipientsBCC() != null) {
2945                newMessage.setRecipients(MimeMessage.RecipientType.BCC,
2946                    convertAddresses(null, messageDO.getRecipientsBCC()));
2947            }
2948
2949            newMessage.setSentDate(Calendar.getInstance().getTime());
2950
2951            // first try to identify any existing message we might be copying
2952
MimeMessage JavaDoc oldMessage = null;
2953
2954            if ((messageDO.getMessageID() != null) && (draftsFolder != null)) {
2955                oldMessage = findJavaMailMessageByFolderMessageId(draftsFolder,
2956                        messageDO.getMessageID());
2957            }
2958
2959            MimeBodyPart JavaDoc newBasePart = new MimeBodyPart JavaDoc();
2960
2961            // new base part is needed if the format is HTML or if there were
2962
// previous attachments we want to retain
2963
if (messageDO.getFormat() == FormatConstants.FORMAT_TEXT) {
2964                newBasePart.setText(messageDO.getText());
2965            } else {
2966                // HTML desired, the base part will be multipart/alternative
2967
MimeMultipart JavaDoc newTextContent = createHTMLContent(messageDO.getText());
2968
2969                // set the multipart/alternative as the content of the base part
2970
newBasePart.setContent(newTextContent);
2971                newBasePart.setHeader("Content-Type",
2972                    newTextContent.getContentType());
2973            }
2974
2975            // if the message has no id, or if it had no attachments, then this
2976
// is a fresh new message -
2977
// no need to copy the contents of another message from the
2978
// drafts folder
2979
if ((oldMessage == null) ||
2980                    !oldMessage.isMimeType("multipart/mixed") ||
2981                    (messageDO.getAttachments() == null)) {
2982                // no attachments - simply decide whether we have HTML or just text
2983
if (messageDO.getFormat() == FormatConstants.FORMAT_HTML) {
2984                    newMessage.setContent((MimeMultipart JavaDoc) newBasePart.getContent());
2985                    newMessage.setHeader("Content-Type",
2986                        newBasePart.getContentType());
2987                } else {
2988                    newMessage.setText(messageDO.getText());
2989                }
2990            } else {
2991                // the old message had attachments - we need to examine which
2992
// of them are still required
2993
retainAttachments(messageDO, newBasePart, oldMessage, newMessage);
2994
2995                // mark the old message for deletion
2996
oldMessage.setFlag(Flags.Flag.DELETED, true);
2997            }
2998        } catch (StackOverflowError JavaDoc e) {
2999            e.printStackTrace();
3000        } catch (MessagingException JavaDoc e) {
3001            throw new SystemException(e);
3002        } catch (IOException JavaDoc e) {
3003            throw new SystemException(e);
3004        }
3005
3006        return newMessage;
3007    }
3008
3009    /**
3010     * <p>Helper for <code>createThreadMessage</code>. This method processes a
3011     * <em>Multipart</em> message or part and sets just the body parts
3012     * representing text in either plain-text and/or <code>HTML</code> format.</p>
3013     *
3014     * @param message or part to be processed.
3015     * @param messageTextPartsParam the HTML and plain text parts to set.
3016     */

3017    private void setMultiPartText(final Part JavaDoc message,
3018            final MessageTextParts messageTextPartsParam)
3019            throws SystemException {
3020        MessageTextParts messageTextParts = messageTextPartsParam;
3021        MimeMultipart JavaDoc content;
3022        MimeBodyPart JavaDoc subPart;
3023        int i;
3024
3025        try {
3026            content = (MimeMultipart JavaDoc) message.getContent();
3027
3028            //go through all the subParts
3029
for (i = 0; i < content.getCount(); i++) {
3030                subPart = (MimeBodyPart JavaDoc) content.getBodyPart(i);
3031
3032                //when multipart/alternative, process the HTML subPart (we prefer HTML)
3033
if (message.isMimeType("multipart/alternative")) {
3034                    if (subPart.isMimeType("text/plain") &&
3035                            (messageTextParts.textPart != null)) {
3036                        subPart.setContent(messageTextParts.textPart.getContent(),
3037                            "text/plain");
3038                    } else if (subPart.isMimeType("text/HTML") &&
3039                            (messageTextParts.HTMLPart != null)) {
3040                        subPart.setContent(messageTextParts.HTMLPart.getContent(),
3041                            "text/HTML");
3042
3043                        // usually the HTML part will come after the plain text
3044
break;
3045                    }
3046                }
3047
3048                // when multipart/related, process the first part as primary...,
3049
if (message.isMimeType("multipart/related") ||
3050                        message.isMimeType("multipart/mixed")) {
3051                    // if this is multipart, recurse to get the text
3052
if (subPart.isMimeType("multipart/*")) {
3053                        messageTextParts = getMultiPartText((Part JavaDoc) subPart);
3054                    } else if (subPart.isMimeType("text/plain") &&
3055                            (messageTextParts.textPart == null)) {
3056                        messageTextParts.textPart = subPart;
3057                    } else if (subPart.isMimeType("text/HTML") &&
3058                            (messageTextParts.HTMLPart == null)) {
3059                        messageTextParts.HTMLPart = subPart;
3060
3061                        break;
3062                    }
3063                }
3064            }
3065        } catch (MessagingException JavaDoc e) {
3066            throw new SystemException(e);
3067        } catch (java.io.IOException JavaDoc e) {
3068            throw new SystemException(e);
3069        }
3070    }
3071
3072
3073    /**
3074     * <p>Set all of the email aliases for the user provided, on the curent
3075     * email server. Each alias in the collection should contain just the 'user'
3076     * (or 'local') part of the email address, before the '@' sign.</p>
3077     *
3078     * @param userName the name of the user for whom to retrieve the email aliases.
3079     * @param userAliases a <code>Collection</code> of <code>String</code>
3080     * instances containing the local part of the different email aliases
3081     * this user has. If the user has no aliaes, an empty collection should
3082     * be provided.
3083     */

3084    public final void setUserAliases(final SecuritySession securitySession,
3085            final String JavaDoc userName,
3086            final Collection JavaDoc userAliases)
3087            throws SystemException {
3088        checkMailServer();
3089        checkDateFormatter(securitySession);
3090
3091        // for the aliases which have been removed, remove the email addresses
3092
List JavaDoc currentUserAliases = mailServer.getUserAliases(securitySession,
3093                userName);
3094        PersonDO person = addressBook.findPersonByUserName(securitySession,
3095                userName);
3096        UserDO user = person.getUser();
3097        Set JavaDoc telecomAddresses = person.getTelecomAddresses();
3098
3099        String JavaDoc emailAddressHost =
3100                settings.getStringSetting(
3101                    securitySession,
3102                    "emailAddressHost",
3103                    user);
3104
3105        // now go thro' the current aliases and see which ones have been removed
3106
// to remove the associated email addresses, if any
3107
Iterator JavaDoc currentUserAliasesIterator = currentUserAliases.iterator();
3108        List JavaDoc removedEmailAddresses = new Vector JavaDoc();
3109        List JavaDoc removedEmailTelecomAddresses = new Vector JavaDoc();
3110        List JavaDoc currentEmailAddresses = new Vector JavaDoc();
3111        while (currentUserAliasesIterator.hasNext()) {
3112            String JavaDoc alias = (String JavaDoc) currentUserAliasesIterator.next();
3113            if (!userAliases.contains(alias)) {
3114                removedEmailAddresses.add(alias + "@" + emailAddressHost);
3115            }
3116        }
3117        Iterator JavaDoc telecomAddressIterator = telecomAddresses.iterator();
3118        while (telecomAddressIterator.hasNext()) {
3119            TelecomAddressDO thisTelecomAddress = (TelecomAddressDO)
3120                telecomAddressIterator.next();
3121            if (thisTelecomAddress.getType() == TelecomAddressConstants.TYPE_EMAIL) {
3122                if (removedEmailAddresses.contains(thisTelecomAddress.getAddress())) {
3123                    removedEmailTelecomAddresses.add(thisTelecomAddress);
3124                } else {
3125                    currentEmailAddresses.add(thisTelecomAddress.getAddress());
3126                }
3127            }
3128        }
3129
3130        int sizeBefore = telecomAddresses.size();
3131        if (user.getId() != null) {
3132            addUserAliasEmailAddresses(securitySession, userName, userAliases,
3133                    telecomAddresses, emailAddressHost);
3134        }
3135        int sizeAfter = telecomAddresses.size();
3136
3137        // if some email telecom addresses were removed or added, update the
3138
// person
3139
if ((removedEmailTelecomAddresses.size() > 0)
3140                || (sizeAfter != sizeBefore)) {
3141            Iterator JavaDoc removedEmailTelecomAddressesIterator = removedEmailTelecomAddresses.iterator();
3142            while (removedEmailTelecomAddressesIterator.hasNext()) {
3143                telecomAddresses.remove(removedEmailTelecomAddressesIterator.next());
3144            }
3145            addressBook.amendPerson(securitySession, person);
3146        }
3147
3148        // remove the user name itself from the aliases - if it is included
3149
userAliases.remove(userName);
3150
3151        mailServer.setUserAliases(securitySession, userName, userAliases);
3152    }
3153
3154    /**
3155     * <p>Set the vacation message for the user provided.</p>
3156     *
3157     * <p>The vacation message is a text the user can set, which will be sent
3158     * to all emails received at this address while the user is not present.</p>
3159     *
3160     * @param userName the name of the user for whom to get the vacation message.
3161     * @param vacationMessage vacation message text for this user. If the user
3162     * has no vacation message set, set to <code>null</code>.
3163     */

3164    public final void setVacationMessage(final SecuritySession securitySession,
3165            final String JavaDoc userName,
3166            final String JavaDoc vacationMessage)
3167            throws SystemException {
3168        checkMailServer();
3169        checkDateFormatter(securitySession);
3170        mailServer.setVacationMessage(securitySession, userName, null);
3171    }
3172
3173    /**
3174     * <p>Helper method to convert an array of <code>Address</code> instances to
3175     * strings.</p>
3176     *
3177     * @param addresses non-<code>null</code> array of <code>Address</code>
3178     * instances to be converted to strings.
3179     * @return array of strings representing the <code>Address.toString</code>
3180     * values.
3181     */

3182    private String JavaDoc[] toStringArray(final Address JavaDoc[] addresses) {
3183        int i;
3184        String JavaDoc[] retArray = new String JavaDoc[addresses.length];
3185
3186        for (i = 0; i < addresses.length; i++) {
3187            retArray[i] = addresses[i].toString();
3188        }
3189
3190        return retArray;
3191    }
3192
3193    /**
3194     * <p>Confirm all of the elements of the message are present and valid,
3195     * before the message is sent.</p>
3196     *
3197     * @param messageDO data object to check for consistency and
3198     * completeness.
3199     * @return a collection of validation errors if any of the
3200     * mandatory fields are missing, or if fields contain invalid values.
3201     *
3202     * @ejb.interface-method
3203     * view-type = "remote"
3204     */

3205    public ValidationErrors validate(final SecuritySession securitySession,
3206            final MessageDO messageDO) {
3207        checkDateFormatter(securitySession);
3208        ValidationErrors errors = new ValidationErrors();
3209        Mask mask = maskFactory.getMask(MessageDO.class);
3210
3211        // recipients is mandatory
3212
if ((messageDO.getRecipients() == null) ||
3213                (messageDO.getRecipients().size() == 0)) {
3214            errors.add(new ValidationError(
3215                    "compose",
3216                    Mail.BUNDLE_PATH,
3217                    mask.getField("recipients"),
3218                    "errors.required"));
3219        }
3220
3221        // senders is mandatory
3222
if ((messageDO.getSenders() == null) ||
3223                (messageDO.getSenders().size() == 0)) {
3224            errors.add(new ValidationError(
3225                    "compose",
3226                    Mail.BUNDLE_PATH,
3227                    mask.getField("senders"),
3228                    "errors.required"));
3229        }
3230
3231        // subject is mandatory for now - see todo above
3232
if ((messageDO == null) ||
3233                StringHandling.isNullOrEmpty(messageDO.getSubject())) {
3234            errors.add(new ValidationError(
3235                    "compose",
3236                    Mail.BUNDLE_PATH,
3237                    mask.getField("subject"),
3238                    "errors.required"));
3239        }
3240
3241        // text is mandatory for now - see todo above
3242
if ((messageDO == null) ||
3243                StringHandling.isNullOrEmpty(messageDO.getText())) {
3244            errors.add(new ValidationError(
3245                    "compose",
3246                    Mail.BUNDLE_PATH,
3247                    mask.getField("text"),
3248                    "errors.required"));
3249        }
3250
3251        // validate email adresses
3252
if (messageDO.getRecipients() != null) {
3253            for (Iterator JavaDoc i = messageDO.getRecipients().iterator();
3254                    i.hasNext();) {
3255                String JavaDoc currentRecipient = "";
3256
3257                try {
3258                    currentRecipient = (String JavaDoc) i.next();
3259
3260                    InternetAddress JavaDoc emailAddress = new InternetAddress JavaDoc(currentRecipient,
3261                            true);
3262                } catch (AddressException JavaDoc e) {
3263                    errors.add(new ValidationError(
3264                            "",
3265                            Mail.BUNDLE_PATH,
3266                            mask.getField("to"),
3267                            "errors.mail.wrongEmailAddress",
3268                            Arrays.asList(new String JavaDoc[] { currentRecipient })));
3269                }
3270            }
3271        }
3272
3273        if (messageDO.getRecipientsCC() != null) {
3274            for (Iterator JavaDoc i = messageDO.getRecipientsCC().iterator();
3275                    i.hasNext();) {
3276                String JavaDoc currentRecipientCC = "";
3277
3278                try {
3279                    currentRecipientCC = (String JavaDoc) i.next();
3280
3281                    InternetAddress JavaDoc emailAddress = new InternetAddress JavaDoc(currentRecipientCC,
3282                            true);
3283                } catch (AddressException JavaDoc e) {
3284                    errors.add(new ValidationError(
3285                            "",
3286                            Mail.BUNDLE_PATH,
3287                            mask.getField("cc"),
3288                            "errors.mail.wrongEmailAddress",
3289                            Arrays.asList(new String JavaDoc[] { currentRecipientCC })));
3290                }
3291            }
3292        }
3293
3294        if (messageDO.getRecipientsBCC() != null) {
3295            for (Iterator JavaDoc i = messageDO.getRecipientsBCC().iterator();
3296                    i.hasNext();) {
3297                String JavaDoc currentRecipientBCC = "";
3298
3299                try {
3300                    currentRecipientBCC = (String JavaDoc) i.next();
3301
3302                    InternetAddress JavaDoc emailAddress = new InternetAddress JavaDoc(currentRecipientBCC,
3303                            true);
3304                } catch (AddressException JavaDoc e) {
3305                    errors.add(new ValidationError(
3306                            "",
3307                            Mail.BUNDLE_PATH,
3308                            mask.getField("bcc"),
3309                            "errors.mail.wrongEmailAddress",
3310                            Arrays.asList(new String JavaDoc[] { currentRecipientBCC })));
3311                }
3312            }
3313        }
3314
3315        return errors;
3316    }
3317}
3318
Popular Tags