1   /**
2    * Copyright (c) 2000-2007 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.mail.util;
24  
25  import com.liferay.portal.kernel.servlet.HttpHeaders;
26  import com.liferay.portal.kernel.util.Constants;
27  import com.liferay.portal.kernel.util.ContentTypes;
28  import com.liferay.portal.kernel.util.GetterUtil;
29  import com.liferay.portal.kernel.util.ParamUtil;
30  import com.liferay.portal.kernel.util.StringMaker;
31  import com.liferay.portal.kernel.util.StringPool;
32  import com.liferay.portal.kernel.util.StringUtil;
33  import com.liferay.portal.kernel.util.Validator;
34  import com.liferay.portal.model.Company;
35  import com.liferay.portal.model.User;
36  import com.liferay.portal.service.UserLocalServiceUtil;
37  import com.liferay.portal.theme.ThemeDisplay;
38  import com.liferay.portal.util.PortalUtil;
39  import com.liferay.portal.util.PropsUtil;
40  import com.liferay.portal.util.WebKeys;
41  import com.liferay.portlet.mail.ContentException;
42  import com.liferay.portlet.mail.ContentPathException;
43  import com.liferay.portlet.mail.FolderException;
44  import com.liferay.portlet.mail.MailAccountsException;
45  import com.liferay.portlet.mail.RecipientException;
46  import com.liferay.portlet.mail.StoreException;
47  import com.liferay.portlet.mail.model.MailAttachment;
48  import com.liferay.portlet.mail.model.MailContent;
49  import com.liferay.portlet.mail.model.MailEnvelope;
50  import com.liferay.portlet.mail.model.MailFolder;
51  import com.liferay.portlet.mail.model.MailMessage;
52  import com.liferay.portlet.mail.model.RemoteMailAttachment;
53  import com.liferay.portlet.mail.search.MailDisplayTerms;
54  import com.liferay.portlet.mail.util.multiaccount.MailAccount;
55  import com.liferay.portlet.mail.util.multiaccount.MailAccounts;
56  import com.liferay.portlet.mail.util.multiaccount.MailCache;
57  import com.liferay.util.Http;
58  import com.liferay.util.mail.JavaMailUtil;
59  import com.liferay.util.mail.MailEngine;
60  import com.liferay.util.mail.MailServerException;
61  
62  import com.sun.mail.imap.IMAPFolder;
63  
64  import java.io.IOException;
65  
66  import java.net.SocketException;
67  
68  import java.util.ArrayList;
69  import java.util.Collection;
70  import java.util.Comparator;
71  import java.util.Date;
72  import java.util.Iterator;
73  import java.util.List;
74  import java.util.ListIterator;
75  import java.util.Set;
76  import java.util.TreeSet;
77  import java.util.regex.Matcher;
78  import java.util.regex.Pattern;
79  
80  import javax.activation.DataHandler;
81  import javax.activation.DataSource;
82  
83  import javax.mail.Address;
84  import javax.mail.AuthenticationFailedException;
85  import javax.mail.BodyPart;
86  import javax.mail.FetchProfile;
87  import javax.mail.Flags.Flag;
88  import javax.mail.Flags;
89  import javax.mail.Folder;
90  import javax.mail.Message.RecipientType;
91  import javax.mail.Message;
92  import javax.mail.MessagingException;
93  import javax.mail.Multipart;
94  import javax.mail.Part;
95  import javax.mail.Session;
96  import javax.mail.Store;
97  import javax.mail.Transport;
98  import javax.mail.UIDFolder.FetchProfileItem;
99  import javax.mail.internet.InternetAddress;
100 import javax.mail.internet.MimeBodyPart;
101 import javax.mail.internet.MimeMessage;
102 import javax.mail.internet.MimeMultipart;
103 import javax.mail.search.AndTerm;
104 import javax.mail.search.BodyTerm;
105 import javax.mail.search.DateTerm;
106 import javax.mail.search.FromStringTerm;
107 import javax.mail.search.OrTerm;
108 import javax.mail.search.RecipientStringTerm;
109 import javax.mail.search.SearchTerm;
110 import javax.mail.search.SentDateTerm;
111 import javax.mail.search.SubjectTerm;
112 import javax.mail.util.ByteArrayDataSource;
113 
114 import javax.naming.NamingException;
115 
116 import javax.servlet.http.HttpServletRequest;
117 import javax.servlet.http.HttpSession;
118 
119 import org.apache.commons.collections.map.MultiValueMap;
120 import org.apache.commons.logging.Log;
121 import org.apache.commons.logging.LogFactory;
122 
123 /**
124  * Used as a fascade to the JavaMail API.  All JavaMail objects are wrappered in
125  * model classes and returned out of this utility fascade.
126  *
127  * <a href="MailUtil.java.html"><b><i>View Source</i></b></a>
128  *
129  * @author Alexander Chow
130  *
131  */
132 public class MailUtil {
133 
134     public static final String MAIL_BOX_STYLE =
135         PropsUtil.get(PropsUtil.MAIL_BOX_STYLE);
136 
137     public static final String MAIL_INBOX_NAME =
138         PropsUtil.get(PropsUtil.MAIL_INBOX_NAME);
139 
140     public static final String MAIL_DRAFTS_NAME =
141         MAIL_BOX_STYLE + PropsUtil.get(PropsUtil.MAIL_DRAFTS_NAME);
142 
143     public static final String MAIL_SENT_NAME =
144         MAIL_BOX_STYLE + PropsUtil.get(PropsUtil.MAIL_SENT_NAME);
145 
146     public static final String MAIL_SPAM_NAME =
147         MAIL_BOX_STYLE + PropsUtil.get(PropsUtil.MAIL_SPAM_NAME);
148 
149     public static final String MAIL_TRASH_NAME =
150         MAIL_BOX_STYLE + PropsUtil.get(PropsUtil.MAIL_TRASH_NAME);
151 
152     public static final String[] DEFAULT_FOLDERS = {
153         MAIL_INBOX_NAME, MAIL_DRAFTS_NAME, MAIL_SPAM_NAME, MAIL_SENT_NAME,
154         MAIL_TRASH_NAME
155     };
156 
157     public static void completeMessage(
158             HttpServletRequest req, MailMessage mailMessage, boolean send,
159             String originalId, boolean wasDraft)
160         throws ContentException, ContentPathException, FolderException,
161                MailServerException, RecipientException, StoreException {
162 
163         HttpSession ses = req.getSession();
164 
165         try {
166             if (send && Validator.isNull(mailMessage.getTo()) &&
167                 Validator.isNull(mailMessage.getCc()) &&
168                 Validator.isNull(mailMessage.getBcc())) {
169 
170                 if (_log.isErrorEnabled()) {
171                     _log.error("A message with no recipients cannot be sent");
172                 }
173 
174                 throw new RecipientException();
175             }
176 
177             Message message = new MimeMessage(MailEngine.getSession());
178 
179             message.setFrom(mailMessage.getFrom());
180 
181             if (Validator.isNotNull(mailMessage.getTo())) {
182                 message.setRecipients(
183                     Message.RecipientType.TO,
184                     _resolveAddresses(req, mailMessage.getTo()));
185             }
186 
187             if (Validator.isNotNull(mailMessage.getCc())) {
188                 message.setRecipients(
189                     Message.RecipientType.CC,
190                     _resolveAddresses(req, mailMessage.getCc()));
191             }
192 
193             if (Validator.isNotNull(mailMessage.getBcc())) {
194                 message.setRecipients(
195                     Message.RecipientType.BCC,
196                     _resolveAddresses(req, mailMessage.getBcc()));
197             }
198 
199             if (Validator.isNotNull(mailMessage.getInReplyTo())) {
200                 message.setHeader("In-Reply-To", mailMessage.getInReplyTo());
201             }
202 
203             if (Validator.isNotNull(mailMessage.getReferences())) {
204                 message.setHeader("References", mailMessage.getReferences());
205             }
206 
207             message.setSubject(mailMessage.getSubject());
208 
209             _replaceEmbeddedImages(req, mailMessage, _getAttachmentURL(req));
210 
211             Multipart multipart = new MimeMultipart();
212 
213             BodyPart bodyPart = new MimeBodyPart();
214 
215             bodyPart.setContent(
216                 mailMessage.getBody(), ContentTypes.TEXT_HTML_UTF8);
217 
218             multipart.addBodyPart(bodyPart);
219 
220             List attachments = mailMessage.getAttachments();
221 
222             Iterator itr = attachments.iterator();
223 
224             while (itr.hasNext()) {
225                 MailAttachment mailAttachment = (MailAttachment)itr.next();
226 
227                 DataSource dataSource = new ByteArrayDataSource(
228                     mailAttachment.getContent(),
229                     mailAttachment.getContentType());
230 
231                 BodyPart attachment = new MimeBodyPart();
232 
233                 attachment.setFileName(mailAttachment.getFilename());
234                 attachment.setDataHandler(new DataHandler(dataSource));
235 
236                 if (Validator.isNotNull(mailAttachment.getContentId())) {
237                     attachment.addHeader(
238                         HttpHeaders.CONTENT_ID, mailAttachment.getContentId());
239                 }
240 
241                 multipart.addBodyPart(attachment);
242             }
243 
244             List remoteAttachments = mailMessage.getRemoteAttachments();
245 
246             itr = remoteAttachments.iterator();
247 
248             while (itr.hasNext()) {
249                 RemoteMailAttachment remoteMailAttachment =
250                     (RemoteMailAttachment)itr.next();
251 
252                 Object[] parts = getAttachment(
253                     req, remoteMailAttachment.getContentPath());
254 
255                 DataSource dataSource = new ByteArrayDataSource(
256                     (byte[])parts[0], (String)parts[1]);
257 
258                 BodyPart attachment = new MimeBodyPart();
259 
260                 attachment.setFileName(remoteMailAttachment.getFilename());
261                 attachment.setDataHandler(new DataHandler(dataSource));
262 
263                 multipart.addBodyPart(attachment);
264             }
265 
266             message.setContent(multipart);
267             message.setSentDate(new Date());
268 
269             if (send) {
270                 Transport.send(message);
271             }
272 
273             try {
274                 MailSessionLock.lock(req);
275 
276                 String lastFolderName = getFolderName(req);
277 
278                 IMAPFolder folder = null;
279 
280                 if (send) {
281                     folder = _getFolder(req, MAIL_SENT_NAME);
282 
283                     message.setFlag(Flag.SEEN, true);
284                 }
285                 else {
286                     folder = _getFolder(req, MAIL_DRAFTS_NAME);
287                 }
288 
289                 folder.appendMessages(new Message[] {message});
290 
291                 long origId = GetterUtil.getLong(originalId);
292 
293                 if (wasDraft) {
294                     folder = _getFolder(req, MAIL_DRAFTS_NAME);
295 
296                     Message msg = folder.getMessageByUID(origId);
297 
298                     folder.setFlags(
299                         new Message[] {msg}, new Flags(Flags.Flag.DELETED),
300                         true);
301 
302                     folder.expunge();
303                 }
304                 else if (origId > 0L) {
305                     folder = _getFolder(req, lastFolderName);
306 
307                     Message msg =
308                         folder.getMessageByUID(origId);
309 
310                     folder.setFlags(
311                         new Message[] {msg}, new Flags(Flags.Flag.ANSWERED),
312                         true);
313                 }
314 
315                 // Make sure to explicitly close and open the correct folder
316 
317                 _closeFolder(ses);
318 
319                 setFolder(req, lastFolderName);
320             }
321             finally {
322                 MailSessionLock.unlock(req);
323             }
324         }
325         catch (MessagingException me) {
326             throw new ContentException(me);
327         }
328         catch (NamingException ne) {
329             throw new ContentException(ne);
330         }
331     }
332 
333     public static void createFolder(HttpServletRequest req, String folderName)
334         throws FolderException, MailServerException, StoreException {
335 
336         Folder folder = null;
337 
338         try {
339             MailSessionLock.lock(req);
340 
341             Iterator itr = getFolders(req).iterator();
342 
343             while (itr.hasNext()) {
344                 MailFolder mailFolder = (MailFolder)itr.next();
345 
346                 if (mailFolder.getName().equals(folderName)) {
347                     throw new FolderException(
348                         "Folder " + folderName + " already exists");
349                 }
350             }
351 
352             Store store = _getStore(req);
353 
354             folderName = _getResolvedFolderName(folderName);
355 
356             folder = store.getFolder(folderName);
357 
358             folder.create(Folder.HOLDS_MESSAGES);
359         }
360         catch (MessagingException me) {
361             throw new FolderException(me);
362         }
363         finally {
364             try {
365                 if ((folder != null) && folder.isOpen()) {
366                     folder.close(false);
367                 }
368             }
369             catch (Exception e) {
370             }
371 
372             MailSessionLock.unlock(req);
373         }
374     }
375 
376     public static void deleteMessages(
377             HttpServletRequest req, MultiValueMap msgMap)
378         throws FolderException, MailServerException, StoreException {
379 
380         deleteMessages(req, msgMap, false);
381     }
382 
383     public static void deleteMessages(
384             HttpServletRequest req, MultiValueMap msgMap, boolean permanently)
385         throws FolderException, MailServerException, StoreException {
386 
387         try {
388             MailSessionLock.lock(req);
389 
390             Iterator itr = msgMap.keySet().iterator();
391 
392             while (itr.hasNext()) {
393                 String key = (String)itr.next();
394 
395                 IMAPFolder folder = _getFolder(req);
396 
397                 String folderName = _getResolvedFolderName(folder.getName());
398 
399                 if (permanently || folderName.equals(MAIL_TRASH_NAME)) {
400                     Message[] messages =
401                         folder.getMessagesByUID(_getMessageIds(msgMap, key));
402 
403                     folder.setFlags(
404                         messages, new Flags(Flags.Flag.DELETED), true);
405 
406                     folder.expunge();
407 
408                     msgMap.remove(key);
409                 }
410             }
411 
412             if (!msgMap.isEmpty()) {
413                 moveMessages(req, msgMap, MAIL_TRASH_NAME);
414             }
415         }
416         catch (MessagingException me) {
417             throw new FolderException(me);
418         }
419         finally {
420             MailSessionLock.unlock(req);
421         }
422     }
423 
424     public static void emptyFolder(HttpServletRequest req, String folderName)
425         throws FolderException, MailServerException, StoreException {
426 
427         try {
428             MailSessionLock.lock(req);
429 
430             String lastFolderName = getFolderName(req);
431 
432             IMAPFolder folder = _getFolder(req, folderName);
433 
434             long[] ids = new long[0];
435 
436             try {
437                 Message[] msgs = folder.getMessages();
438 
439                 FetchProfile fetchProfile = new FetchProfile();
440 
441                 fetchProfile.add(FetchProfile.Item.ENVELOPE);
442 
443                 folder.fetch(msgs, fetchProfile);
444 
445                 ids = new long[msgs.length];
446 
447                 for (int i = 0; i < msgs.length; i++) {
448                     ids[i] = folder.getUID(msgs[i]);
449                 }
450 
451                 Message[] messages = folder.getMessagesByUID(ids);
452 
453                 folder.setFlags(messages, new Flags(Flags.Flag.DELETED), true);
454 
455                 folder.expunge();
456             }
457             catch (MessagingException me) {
458                 throw new FolderException(me);
459             }
460             finally {
461                 setFolder(req, lastFolderName);
462             }
463         }
464         finally {
465             MailSessionLock.unlock(req);
466         }
467     }
468 
469     public static Object[] getAttachment(
470             HttpServletRequest req, String contentPath)
471         throws ContentException, ContentPathException, FolderException,
472                MailServerException, StoreException {
473 
474         Object[] parts = null;
475 
476         try {
477             MailSessionLock.lock(req);
478 
479             String[] path = RemoteMailAttachment.parsePath(contentPath);
480 
481             String folderName = path[0];
482             long messageId = GetterUtil.getLong(path[1]);
483             String mimePath = path[2];
484 
485             IMAPFolder folder = _getFolder(req, folderName);
486 
487             Message message = folder.getMessageByUID(messageId);
488 
489             parts = _getAttachmentFromPath(message, mimePath);
490         }
491         catch (ContentPathException cpe) {
492             throw cpe;
493         }
494         catch (IOException ioe) {
495             throw new ContentException(ioe);
496         }
497         catch (MessagingException me) {
498             throw new ContentException(me);
499         }
500         finally {
501             MailSessionLock.unlock(req);
502         }
503 
504         return parts;
505     }
506 
507     public static Set getEnvelopes(
508             HttpServletRequest req, Comparator comparator)
509         throws FolderException {
510 
511         Set envelopes = new TreeSet(comparator);
512 
513         try {
514             MailSessionLock.lock(req);
515 
516             IMAPFolder folder = _getFolder(req);
517 
518             String folderName = _getResolvedFolderName(folder.getName());
519 
520             Message[] messages = folder.getMessages();
521 
522             FetchProfile fetchProfile = new FetchProfile();
523 
524             fetchProfile.add(IMAPFolder.FetchProfileItem.SIZE);
525             fetchProfile.add(FetchProfile.Item.ENVELOPE);
526             fetchProfile.add(FetchProfile.Item.FLAGS);
527             fetchProfile.add(FetchProfileItem.UID);
528 
529             folder.fetch(messages, fetchProfile);
530 
531             _convertEnvelopes(folder, folderName, messages, envelopes);
532 
533             return envelopes;
534         }
535         catch (MessagingException me) {
536             throw new FolderException(me);
537         }
538         finally {
539             MailSessionLock.unlock(req);
540         }
541     }
542 
543     public static MailFolder getFolder(HttpServletRequest req)
544         throws FolderException, MailServerException, MessagingException,
545                StoreException {
546 
547         try {
548 
549             // Make sure a store has been retrieved first
550 
551             _getStore(req);
552 
553             MailSessionLock.lock(req);
554 
555             IMAPFolder folder = _getFolder(req);
556 
557             List list = new ArrayList();
558 
559             _getFolders(list, new IMAPFolder[] {folder});
560 
561             return (MailFolder)list.get(0);
562         }
563         finally {
564             MailSessionLock.unlock(req);
565         }
566     }
567 
568     public static String getFolderName(HttpServletRequest req)
569         throws FolderException, StoreException {
570 
571         try {
572             MailSessionLock.lock(req);
573 
574             IMAPFolder folder = _getFolder(req);
575 
576             return folder.getName();
577         }
578         finally {
579             MailSessionLock.unlock(req);
580         }
581     }
582 
583     public static List getFolders(HttpServletRequest req)
584         throws FolderException, MailServerException, StoreException {
585 
586         List list = new ArrayList();
587 
588         IMAPFolder root = null;
589 
590         try {
591             List tempList = new ArrayList();
592 
593             Store store = _getStore(req);
594 
595             root = (IMAPFolder)store.getDefaultFolder();
596 
597             Folder[] folders = root.list();
598 
599             _getFolders(tempList, folders);
600 
601             for (int i = 0; i < DEFAULT_FOLDERS.length; i++) {
602                 ListIterator itr = tempList.listIterator();
603 
604                 while (itr.hasNext()){
605                     MailFolder mailFolder = (MailFolder)itr.next();
606 
607                     if (DEFAULT_FOLDERS[i].equals(
608                             _getResolvedFolderName(mailFolder.getName()))) {
609 
610                         list.add(mailFolder);
611 
612                         itr.remove();
613 
614                         break;
615                     }
616                 }
617             }
618 
619             list.addAll(tempList);
620         }
621         catch (MessagingException me) {
622             throw new FolderException(me);
623         }
624         finally {
625             try {
626                 if ((root != null) && root.isOpen()) {
627                     root.close(false);
628                 }
629             }
630             catch (Exception ex) {
631             }
632         }
633 
634         return list;
635     }
636 
637     public static MailMessage getMessage(HttpServletRequest req)
638         throws ContentException, FolderException, StoreException {
639 
640         try {
641             MailSessionLock.lock(req);
642 
643             long messageId = getMessageId(req);
644 
645             if (messageId != -1L) {
646                 return getMessage(req, messageId);
647             }
648             else {
649                 return null;
650             }
651         }
652         finally {
653             MailSessionLock.unlock(req);
654         }
655     }
656 
657     public static MailMessage getMessage(HttpServletRequest req, long messageId)
658         throws ContentException, FolderException, StoreException {
659 
660         HttpSession ses = req.getSession();
661 
662         MailMessage mailMessage = new MailMessage();
663 
664         try {
665             MailSessionLock.lock(req);
666 
667             IMAPFolder folder = _getFolder(req);
668 
669             Message message = folder.getMessageByUID(messageId);
670 
671             mailMessage.setMessageId(messageId);
672 
673             if (Validator.isNotNull(message.getFrom())) {
674                 mailMessage.setFrom(message.getFrom()[0]);
675             }
676 
677             mailMessage.setTo(message.getRecipients(RecipientType.TO));
678             mailMessage.setCc(message.getRecipients(RecipientType.CC));
679             mailMessage.setBcc(message.getRecipients(RecipientType.BCC));
680             mailMessage.setReplyTo(message.getReplyTo());
681 
682             String[] messageIdHeader = message.getHeader("Message-ID");
683             String[] referencesHeader = message.getHeader("References");
684 
685             if (Validator.isNotNull(messageIdHeader)) {
686                 mailMessage.setInReplyTo(messageIdHeader[0]);
687 
688                 if (Validator.isNull(referencesHeader)) {
689                     mailMessage.setReferences(messageIdHeader[0]);
690                 }
691                 else {
692                     mailMessage.setReferences(
693                         referencesHeader[0] + StringPool.SPACE +
694                             messageIdHeader[0]);
695                 }
696             }
697             else {
698                 if (Validator.isNotNull(referencesHeader[0])) {
699                     mailMessage.setReferences(referencesHeader[0]);
700                 }
701             }
702 
703             mailMessage.setSubject(message.getSubject());
704             mailMessage.setSentDate(message.getSentDate());
705 
706             String contentPath = RemoteMailAttachment.buildContentPath(
707                 folder.getName(), messageId);
708 
709             MailContent content = new MailContent();
710 
711             mailMessage = _getContent(
712                 message, mailMessage, content, contentPath);
713 
714             mailMessage.setMailContent(content);
715 
716             if (_log.isDebugEnabled()) {
717                 _log.debug("Body before replacing content ids\n" + content);
718             }
719 
720             _replaceContentIds(
721                 content, mailMessage.getRemoteAttachments(),
722                 _getAttachmentURL(req));
723 
724             if (_log.isDebugEnabled()) {
725                 _log.debug("Body after replacing content ids\n" + content);
726             }
727 
728             mailMessage.purgeDirtyRemoteAttachments();
729 
730             ses.setAttribute(WebKeys.MAIL_MESSAGE_ID, new Long(messageId));
731 
732             return mailMessage;
733         }
734         catch (MessagingException me) {
735             throw new FolderException(me);
736         }
737         finally {
738             MailSessionLock.unlock(req);
739         }
740     }
741 
742     public static long getMessageId(HttpServletRequest req)
743         throws ContentException, FolderException, StoreException {
744 
745         HttpSession ses = req.getSession();
746 
747         try {
748             MailSessionLock.lock(req);
749 
750             Long messageId = (Long)ses.getAttribute(WebKeys.MAIL_MESSAGE_ID);
751 
752             if (messageId != null) {
753                 return messageId.longValue();
754             }
755             else {
756                 return -1L;
757             }
758         }
759         finally {
760             MailSessionLock.unlock(req);
761         }
762     }
763 
764     public static void moveMessages(
765             HttpServletRequest req, MultiValueMap msgMap, String toFolderName)
766         throws FolderException, MailServerException, StoreException {
767 
768         IMAPFolder toFolder = null;
769 
770         toFolderName = _getResolvedFolderName(toFolderName);
771 
772         try {
773             MailSessionLock.lock(req);
774 
775             Iterator itr = msgMap.keySet().iterator();
776 
777             while (itr.hasNext()) {
778                 String folderName = (String)itr.next();
779 
780                 long[] messageIds = _getMessageIds(msgMap, folderName);
781 
782                 IMAPFolder folder = _getFolder(req, folderName);
783 
784                 folderName = _getResolvedFolderName(folder.getName());
785 
786                 if (folderName.equals(toFolderName)) {
787                     continue;
788                 }
789 
790                 if ((folderName.equals(MAIL_DRAFTS_NAME) ||
791                         toFolderName.equals(MAIL_DRAFTS_NAME)) &&
792                     (!toFolderName.equals(MAIL_TRASH_NAME))) {
793 
794                     continue;
795                 }
796 
797                 Store store = _getStore(req);
798 
799                 toFolder = (IMAPFolder)store.getFolder(toFolderName);
800 
801                 toFolder.open(IMAPFolder.READ_WRITE);
802 
803                 Message[] messages = folder.getMessagesByUID(messageIds);
804 
805                 folder.copyMessages(messages, toFolder);
806 
807                 folder.setFlags(messages, new Flags(Flags.Flag.DELETED), true);
808 
809                 folder.expunge();
810             }
811         }
812         catch (MessagingException me) {
813             throw new FolderException(me);
814         }
815         finally {
816             try {
817                 if ((toFolder != null) && toFolder.isOpen()) {
818                     toFolder.close(true);
819                 }
820             }
821             catch (Exception e) {
822             }
823 
824             MailSessionLock.unlock(req);
825         }
826     }
827 
828     public static void removeFolder(HttpServletRequest req, String folderName)
829         throws FolderException, MailServerException, StoreException {
830 
831         try {
832             folderName = _getResolvedFolderName(folderName);
833 
834             for (int i = 0; i < DEFAULT_FOLDERS.length; i++) {
835                 if (DEFAULT_FOLDERS[i].equals(folderName)) {
836                     if (_log.isErrorEnabled()) {
837                         _log.error(
838                             "Folder " + folderName +
839                                 " is a system folder and cannot be changed");
840                     }
841 
842                     throw new FolderException();
843                 }
844             }
845 
846             try {
847                 MailSessionLock.lock(req);
848 
849                 setFolder(req, MAIL_INBOX_NAME);
850 
851                 Store store = _getStore(req);
852 
853                 Folder folder = store.getFolder(folderName);
854 
855                 if (!folder.exists()) {
856                     if (_log.isErrorEnabled()) {
857                         _log.error("Folder " + folderName + " does not exist");
858                     }
859 
860                     throw new FolderException();
861                 }
862 
863                 folder.delete(true);
864             }
865             finally {
866                 MailSessionLock.unlock(req);
867             }
868         }
869         catch (MessagingException me) {
870             throw new FolderException(me);
871         }
872     }
873 
874     public static void renameFolder(
875             HttpServletRequest req, String oldFolderName, String newFolderName)
876         throws FolderException, MailServerException, StoreException {
877 
878         try {
879             oldFolderName = _getResolvedFolderName(oldFolderName);
880             newFolderName = _getResolvedFolderName(newFolderName);
881 
882             for (int i = 0; i < DEFAULT_FOLDERS.length; i++) {
883                 if (DEFAULT_FOLDERS[i].equals(oldFolderName)) {
884                     if (_log.isErrorEnabled()) {
885                         _log.error(
886                             "Folder " + oldFolderName +
887                                 " is a system folder and cannot be changed");
888                     }
889 
890                     throw new FolderException();
891                 }
892                 else if (DEFAULT_FOLDERS[i].equals(newFolderName)) {
893                     if (_log.isErrorEnabled()) {
894                         _log.error(
895                             "Folder " + newFolderName +
896                                 " is a system folder and cannot be changed");
897                     }
898 
899                     throw new FolderException();
900                 }
901             }
902 
903             try {
904                 MailSessionLock.lock(req);
905 
906                 setFolder(req, MAIL_INBOX_NAME);
907 
908                 Store store = _getStore(req);
909 
910                 Folder oldFolder = store.getFolder(oldFolderName);
911                 Folder newFolder = store.getFolder(newFolderName);
912 
913                 if (!oldFolder.exists()) {
914                     if (_log.isErrorEnabled()) {
915                         _log.error(
916                             "Folder " + oldFolderName + " does not exist");
917                     }
918 
919                     throw new FolderException();
920                 }
921                 else if (newFolder.exists()) {
922                     if (_log.isErrorEnabled()) {
923                         _log.error(
924                             "Folder " + newFolderName + " already exists");
925                     }
926 
927                     throw new FolderException();
928                 }
929 
930                 oldFolder.renameTo(newFolder);
931             }
932             finally {
933                 MailSessionLock.unlock(req);
934             }
935         }
936         catch (MessagingException me) {
937             throw new FolderException(me);
938         }
939     }
940 
941     public static Set search(
942             HttpServletRequest req, MailDisplayTerms displayTerms,
943             Comparator comparator)
944         throws FolderException, MailServerException, StoreException {
945 
946         Set results = new TreeSet(comparator);
947 
948         if (Validator.isNotNull(displayTerms.getFolderName())) {
949             _search(req, displayTerms, results);
950         }
951         else {
952             List folders = getFolders(req);
953 
954             Iterator itr = folders.iterator();
955 
956             while (itr.hasNext()) {
957                 MailFolder mailFolder = (MailFolder)itr.next();
958 
959                 String resolvedName =
960                     _getResolvedFolderName(mailFolder.getName());
961 
962                 if (resolvedName.equals(MAIL_SPAM_NAME) ||
963                     resolvedName.equals(MAIL_TRASH_NAME)) {
964 
965                     continue;
966                 }
967 
968                 displayTerms.setFolderName(mailFolder.getName());
969 
970                 _search(req, displayTerms, results);
971             }
972         }
973 
974         return results;
975     }
976 
977     public static void setAccount(HttpServletRequest req) {
978         String accountName = ParamUtil.getString(req, Constants.MAIL_ACCOUNT);
979 
980         try {
981             if (Validator.isNotNull(accountName)) {
982                 MailAccounts.setAccount(req, accountName);
983             }
984         }
985         catch (MailAccountsException e) {
986             if (_log.isWarnEnabled()) {
987                 _log.warn("Error setting account " + accountName, e);
988             }
989         }
990     }
991 
992     public static void setFolder(HttpServletRequest req, String folderName)
993         throws FolderException, MailServerException, StoreException {
994 
995         try {
996             MailSessionLock.lock(req);
997 
998             _getFolder(req, folderName);
999         }
1000        finally {
1001            MailSessionLock.unlock(req);
1002        }
1003    }
1004
1005    public static void setMessageId(HttpServletRequest req, long messageId) {
1006        HttpSession ses = req.getSession();
1007
1008        ses.setAttribute(WebKeys.MAIL_MESSAGE_ID, new Long(messageId));
1009    }
1010
1011    protected static void cleanUp(HttpSession ses) throws StoreException {
1012        try {
1013            _closeFolder(ses);
1014
1015            MailCache.clearCache(ses);
1016
1017            ses.removeAttribute(WebKeys.MAIL_MESSAGE_ID);
1018        }
1019        catch (MessagingException me) {
1020            throw new StoreException(me);
1021        }
1022    }
1023
1024    private static SearchTerm _appendSearchTerm(
1025            SearchTerm fullTerm, SearchTerm term, boolean isAndOperator) {
1026
1027        if (fullTerm == null) {
1028            return term;
1029        }
1030
1031        if (isAndOperator) {
1032            return new AndTerm(fullTerm, term);
1033        }
1034        else {
1035            return new OrTerm(fullTerm, term);
1036        }
1037    }
1038
1039    private static void _closeFolder(HttpSession ses) {
1040        IMAPFolder folder = (IMAPFolder)ses.getAttribute(WebKeys.MAIL_FOLDER);
1041
1042        if ((folder != null) && folder.isOpen()) {
1043            try {
1044                folder.close(false);
1045            }
1046            catch (MessagingException me) {
1047                if (_log.isWarnEnabled()) {
1048                    _log.warn(me);
1049                }
1050            }
1051
1052            ses.removeAttribute(WebKeys.MAIL_FOLDER);
1053        }
1054    }
1055
1056    private static void _convertEnvelopes(
1057            IMAPFolder folder, String folderName, Message[] messages,
1058            Set envelopes)
1059        throws MessagingException {
1060
1061        for (int i = 0; i < messages.length; i++) {
1062            Message message = messages[i];
1063
1064            if (message.isExpunged()) {
1065                continue;
1066            }
1067
1068            MailEnvelope mailEnvelope = new MailEnvelope();
1069
1070            mailEnvelope.setMessageId(folder.getUID(message));
1071            mailEnvelope.setFolderName(folder.getName());
1072
1073            if (MAIL_SENT_NAME.equals(folderName) ||
1074                MAIL_DRAFTS_NAME.equals(folderName)) {
1075
1076                Address[] recipients = message.getAllRecipients();
1077
1078                StringMaker sm = new StringMaker();
1079
1080                if (Validator.isNotNull(recipients)) {
1081                    for (int j = 0; j < recipients.length; j++) {
1082                        InternetAddress address =
1083                            (InternetAddress)recipients[j];
1084
1085                        String recipient = GetterUtil.getString(
1086                            address.getPersonal(), address.getAddress());
1087
1088                        sm.append(recipient);
1089
1090                        if (j < (recipients.length - 1)) {
1091                            sm.append(", ");
1092                        }
1093                    }
1094                }
1095
1096                if (sm.length() > 0) {
1097                    mailEnvelope.setRecipient(sm.toString());
1098                }
1099            }
1100            else {
1101                Address[] from = message.getFrom();
1102
1103                if (Validator.isNotNull(from)) {
1104                    InternetAddress address = (InternetAddress)from[0];
1105
1106                    String recipient = GetterUtil.getString(
1107                        address.getPersonal(), address.getAddress());
1108
1109                    mailEnvelope.setRecipient(recipient);
1110                }
1111            }
1112
1113            mailEnvelope.setSubject(message.getSubject());
1114            mailEnvelope.setDate(message.getSentDate());
1115            mailEnvelope.setSize(
1116                (int)(message.getSize() * _ENCODING_FACTOR));
1117            mailEnvelope.setRead(message.isSet(Flag.SEEN));
1118            mailEnvelope.setFlagged(message.isSet(Flag.FLAGGED));
1119            mailEnvelope.setAnswered(message.isSet(Flag.ANSWERED));
1120
1121            envelopes.add(mailEnvelope);
1122        }
1123    }
1124
1125    private static Store _createStore(
1126            HttpServletRequest req, MailAccount account)
1127        throws FolderException, MailServerException, MessagingException,
1128               NamingException, StoreException {
1129
1130        HttpSession ses = req.getSession();
1131
1132        Session session = MailEngine.getSession();
1133
1134        Store store = session.getStore("imap");
1135
1136        String serviceName =
1137            account.getUserId() + StringPool.COLON + WebKeys.MAIL_STORE;
1138
1139        store.addConnectionListener(new ConnectionListener(serviceName));
1140
1141        String imapHost = session.getProperty("mail.imap.host");
1142
1143        store.connect(imapHost, account.getUserId(), account.getPassword());
1144
1145        MailCache.putStore(ses, account.getName(), store);
1146
1147        List list = getFolders(req);
1148
1149        for (int i = 0; i < DEFAULT_FOLDERS.length; i++) {
1150            boolean exists = false;
1151
1152            Iterator itr = list.iterator();
1153
1154            while (itr.hasNext()) {
1155                MailFolder mailFolder = (MailFolder)itr.next();
1156
1157                if (DEFAULT_FOLDERS[i].equals(mailFolder.getName())) {
1158                    exists = true;
1159
1160                    break;
1161                }
1162            }
1163
1164            if (!exists) {
1165                createFolder(req, DEFAULT_FOLDERS[i]);
1166            }
1167        }
1168
1169        if (ses.getAttribute(WebKeys.MAIL_FOLDER) == null) {
1170            setFolder(req, MAIL_INBOX_NAME);
1171        }
1172
1173        return store;
1174    }
1175
1176    private static String _customizeHtml(String html) {
1177        for (int i = 0; i < _HTML_START_TAGS.length; i++) {
1178            Pattern startPattern = Pattern.compile(
1179                _HTML_START_TAGS[i], Pattern.CASE_INSENSITIVE);
1180
1181            Matcher startMatcher = startPattern.matcher(html);
1182
1183            while (startMatcher.find()) {
1184                int start = startMatcher.start();
1185                int end = html.indexOf(">", start);
1186
1187                if (end == -1) {
1188                    html = StringUtil.replace(
1189                        html, html.substring(start), StringPool.BLANK);
1190                }
1191                else {
1192                    html = StringUtil.replace(
1193                        html, html.substring(start, end + 1), StringPool.BLANK);
1194                }
1195
1196                if (i < _HTML_END_TAGS.length) {
1197                    Pattern endPattern = Pattern.compile(
1198                        _HTML_END_TAGS[i], Pattern.CASE_INSENSITIVE);
1199
1200                    Matcher endMatcher = endPattern.matcher(html);
1201
1202                    html = endMatcher.replaceFirst(StringPool.BLANK);
1203                }
1204                else {
1205                    startMatcher.reset(html);
1206                }
1207            }
1208        }
1209
1210        return html.trim();
1211    }
1212
1213    private static Object[] _getAttachmentFromPath(Part part, String mimePath)
1214        throws ContentPathException, IOException, MessagingException {
1215
1216        int index = GetterUtil.getInteger(
1217            StringUtil.split(mimePath.substring(1), StringPool.PERIOD)[0]);
1218
1219        if (part.getContent() instanceof Multipart) {
1220            String prefix = String.valueOf(index) + StringPool.PERIOD;
1221
1222            Multipart multipart = (Multipart)part.getContent();
1223
1224            for (int i = 0; i < multipart.getCount(); i++) {
1225                if (index == i) {
1226                    return _getAttachmentFromPath(
1227                        multipart.getBodyPart(i),
1228                        mimePath.substring(prefix.length()));
1229                }
1230            }
1231
1232            throw new ContentPathException();
1233        }
1234        else if (index != -1) {
1235            throw new ContentPathException();
1236        }
1237
1238        byte[] byteArray = JavaMailUtil.getBytes(part);
1239
1240        return new Object[] {byteArray, part.getContentType()};
1241    }
1242
1243    private static String _getAttachmentURL(HttpServletRequest req) {
1244        ThemeDisplay themeDisplay =
1245            (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
1246
1247        return themeDisplay.getPathMain() + "/mail/get_attachment?";
1248    }
1249
1250    private static MailMessage _getContent(
1251            Part part, MailMessage mailMessage, MailContent content,
1252            String contentPath)
1253        throws ContentException {
1254
1255        try {
1256            String contentType = part.getContentType().toLowerCase();
1257
1258            boolean attachment = true;
1259
1260            if (part.getContent() instanceof Multipart) {
1261                attachment = false;
1262
1263                Multipart multipart = (Multipart)part.getContent();
1264
1265                for (int i = 0; i < multipart.getCount(); i++) {
1266                    Part curPart = multipart.getBodyPart(i);
1267
1268                    mailMessage = _getContent(
1269                        curPart, mailMessage, content,
1270                        contentPath + StringPool.PERIOD + i);
1271                }
1272            }
1273            else if (Validator.isNull(part.getFileName())) {
1274                attachment = false;
1275
1276                if (contentType.startsWith(ContentTypes.TEXT_PLAIN)) {
1277                    content.appendPlainBody((String)part.getContent());
1278                }
1279                else if (contentType.startsWith(ContentTypes.TEXT_HTML)) {
1280                    content.appendHtmlBody(
1281                        _customizeHtml((String)part.getContent()));
1282                }
1283                else if (contentType.startsWith(ContentTypes.MESSAGE_RFC822)) {
1284                    MailContent subContent = new MailContent();
1285
1286                    mailMessage = _getContent(
1287                        (Part)part.getContent(), mailMessage, subContent,
1288                        contentPath + StringPool.PERIOD + 0);
1289
1290                    content.appendSubContent(subContent);
1291                }
1292            }
1293
1294            if (attachment) {
1295                mailMessage.appendRemoteAttachment(
1296                    _getRemoteAttachment(
1297                        part, contentPath + StringPool.PERIOD + -1));
1298            }
1299        }
1300        catch (IOException ioe) {
1301            throw new ContentException(ioe);
1302        }
1303        catch (MessagingException me) {
1304            throw new ContentException(me);
1305        }
1306
1307        return mailMessage;
1308    }
1309
1310    private static IMAPFolder _getFolder(HttpServletRequest req)
1311        throws FolderException {
1312
1313        HttpSession ses = req.getSession();
1314
1315        IMAPFolder folder = (IMAPFolder)ses.getAttribute(WebKeys.MAIL_FOLDER);
1316
1317        if (folder != null) {
1318            return folder;
1319        }
1320        else {
1321            throw new FolderException();
1322        }
1323    }
1324
1325    private static IMAPFolder _getFolder(
1326            HttpServletRequest req, String folderName)
1327        throws FolderException, MailServerException, StoreException {
1328
1329        HttpSession ses = req.getSession();
1330
1331        try {
1332            folderName = _getResolvedFolderName(folderName);
1333
1334            IMAPFolder folder = (IMAPFolder)ses.getAttribute(
1335                WebKeys.MAIL_FOLDER);
1336
1337            if (folder != null) {
1338                String currFolderName =
1339                    _getResolvedFolderName(folder.getName());
1340
1341                if (!currFolderName.equals(folderName)) {
1342                    _closeFolder(ses);
1343
1344                    folder = null;
1345                }
1346                else if (!folder.isOpen()) {
1347                    if (_log.isInfoEnabled()) {
1348                        _log.info(
1349                            "The folder is closed and needs to be reopened");
1350                    }
1351
1352                    _closeFolder(ses);
1353
1354                    folder = null;
1355                }
1356            }
1357
1358            if (folder == null) {
1359                Long userIdObj = (Long)ses.getAttribute(WebKeys.USER_ID);
1360
1361                String serviceName = userIdObj + StringPool.COLON +
1362                    WebKeys.MAIL_FOLDER + StringPool.PERIOD + folderName;
1363
1364                Store store = _getStore(req);
1365
1366                folder = (IMAPFolder)store.getFolder(folderName);
1367
1368                folder.addConnectionListener(
1369                    new ConnectionListener(serviceName));
1370
1371                folder.open(IMAPFolder.READ_WRITE);
1372
1373                ses.setAttribute(WebKeys.MAIL_FOLDER, folder);
1374
1375                ses.removeAttribute(WebKeys.MAIL_MESSAGE_ID);
1376            }
1377
1378            return folder;
1379        }
1380        catch (MessagingException me) {
1381            throw new FolderException(me);
1382        }
1383    }
1384
1385    private static void _getFolders(List list, Folder[] folders) {
1386        for (int i = 0; i < folders.length; i++) {
1387            Folder folder = folders[i];
1388
1389            try {
1390                int folderType = folder.getType();
1391
1392                if ((folderType & IMAPFolder.HOLDS_MESSAGES) != 0) {
1393                    MailFolder mailFolder = new MailFolder(
1394                        folder.getName(), folder.getMessageCount(),
1395                        folder.getUnreadMessageCount());
1396
1397                    list.add(mailFolder);
1398                }
1399
1400                if ((folderType & IMAPFolder.HOLDS_FOLDERS) != 0) {
1401                    _getFolders(list, folder.list());
1402                }
1403            }
1404            catch (MessagingException me) {
1405                _log.error("Skipping IMAP folder because " + me.getMessage());
1406            }
1407        }
1408    }
1409
1410    private static long[] _getMessageIds(
1411            MultiValueMap msgMap, String folderName) {
1412
1413        Collection messages = msgMap.getCollection(folderName);
1414
1415        long[] messageIds = new long[messages.size()];
1416
1417        Iterator msgItr = messages.iterator();
1418
1419        for (int i = 0; msgItr.hasNext(); i++) {
1420            messageIds[i] = GetterUtil.getLong((String)msgItr.next());
1421        }
1422
1423        return messageIds;
1424    }
1425
1426    private static RemoteMailAttachment _getRemoteAttachment(
1427            Part part, String contentPath)
1428        throws ContentException {
1429
1430        RemoteMailAttachment remoteMailAttachment = new RemoteMailAttachment();
1431
1432        try {
1433            remoteMailAttachment.setFilename(part.getFileName());
1434            remoteMailAttachment.setContentPath(contentPath);
1435
1436            String[] contentId = part.getHeader(HttpHeaders.CONTENT_ID);
1437
1438            if ((contentId != null) && (contentId.length == 1)) {
1439                remoteMailAttachment.setContentId(contentId[0]);
1440            }
1441        }
1442        catch (MessagingException me) {
1443            if (_log.isErrorEnabled()) {
1444                _log.error(
1445                    "Unable to properly get file name of MIME attachment");
1446            }
1447
1448            throw new ContentException(me);
1449        }
1450
1451        return remoteMailAttachment;
1452    }
1453
1454    private static String _getResolvedFolderName(String folderName) {
1455        String resolvedName = folderName;
1456
1457        if (Validator.isNull(folderName)) {
1458            resolvedName = MAIL_INBOX_NAME;
1459        }
1460        else if (!folderName.equals(MAIL_INBOX_NAME) &&
1461                 !folderName.startsWith(MAIL_BOX_STYLE)) {
1462
1463            resolvedName = MAIL_BOX_STYLE + folderName;
1464        }
1465
1466        return resolvedName;
1467    }
1468
1469    private static Store _getStore(HttpServletRequest req)
1470        throws FolderException, MailServerException, StoreException {
1471
1472        HttpSession ses = req.getSession();
1473
1474        MailAccount currentAccount = MailAccounts.getCurrentAccount(req);
1475
1476        try {
1477            Store store = MailCache.getStore(ses, currentAccount.getName());
1478
1479            if (store != null && !store.isConnected()) {
1480                if (_log.isInfoEnabled()) {
1481                    _log.info("The store needs to be reconnected");
1482                }
1483
1484                cleanUp(ses);
1485
1486                store = null;
1487            }
1488
1489            if (store == null) {
1490                store = _createStore(req, currentAccount);
1491            }
1492
1493            return store;
1494        }
1495        catch (AuthenticationFailedException afe) {
1496            _log.error(
1497                "Failed to authenticate the userId " +
1498                    currentAccount.getUserId());
1499
1500            throw new StoreException(afe);
1501        }
1502        catch (MessagingException me) {
1503            Exception e = me.getNextException();
1504
1505            if (e instanceof SocketException) {
1506                if (_log.isWarnEnabled()) {
1507                    _log.warn(
1508                        "Failed to connect to a valid mail server. Please " +
1509                            "make sure one is properly configured.");
1510                }
1511
1512                throw new MailServerException(e);
1513            }
1514            else {
1515                throw new StoreException(me);
1516            }
1517        }
1518        catch (NamingException ne) {
1519            throw new StoreException(ne);
1520        }
1521    }
1522
1523    private static void _replaceContentIds(
1524        MailContent content, List rmas, String url) {
1525
1526        String body = content.getHtmlBody();
1527
1528        for (int i = 0; i < rmas.size(); i++) {
1529            RemoteMailAttachment rma = (RemoteMailAttachment)rmas.get(i);
1530
1531            if (Validator.isNotNull(rma.getContentId())) {
1532                String contentId = rma.getContentId();
1533
1534                if (contentId.startsWith(StringPool.LESS_THAN) &&
1535                    contentId.endsWith(StringPool.GREATER_THAN)) {
1536
1537                    contentId =
1538                        "cid:" + contentId.substring(1, contentId.length() - 1);
1539                }
1540
1541                String remotePath =
1542                    url + "fileName=" + rma.getFilename() + "&contentPath=" +
1543                        rma.getContentPath();
1544
1545                body = StringUtil.replace(body, contentId, remotePath);
1546
1547                rma.setDirty(true);
1548            }
1549        }
1550
1551        content.setHtmlBody(body);
1552
1553        for (int i = 0; i < content.getSubContent().size(); i++) {
1554            _replaceContentIds(
1555                (MailContent)content.getSubContent().get(i), rmas, url);
1556        }
1557    }
1558
1559    private static void _replaceEmbeddedImages(
1560            HttpServletRequest req, MailMessage mailMessage, String url)
1561        throws ContentException, ContentPathException, FolderException,
1562               MailServerException, StoreException {
1563
1564        HttpSession ses = req.getSession();
1565
1566        String prefix = ses.getId() + System.currentTimeMillis();
1567
1568        int count = 0;
1569
1570        String body = mailMessage.getBody();
1571
1572        if (_log.isDebugEnabled()) {
1573            _log.debug("Body before replacing embedded images\n" + body);
1574        }
1575
1576        int x = body.indexOf(url);
1577
1578        while (x >= 0) {
1579            int y = body.indexOf("-1", x);
1580
1581            if (y > 0) {
1582                y += 2;
1583
1584                String attachmentPath = body.substring(x, y);
1585
1586                String fileName = Http.getParameter(attachmentPath, "fileName");
1587                String contentPath = Http.getParameter(
1588                    attachmentPath, "contentPath");
1589
1590                String contentId = prefix + count;
1591
1592                Object[] parts = getAttachment(req, contentPath);
1593
1594                MailAttachment mailAttachment = new MailAttachment();
1595
1596                mailAttachment.setFilename(fileName);
1597                mailAttachment.setContent((byte[])parts[0]);
1598                mailAttachment.setContentType((String)parts[1]);
1599                mailAttachment.setContentId(
1600                    StringPool.LESS_THAN + contentId + StringPool.GREATER_THAN);
1601
1602                mailMessage.appendAttachment(mailAttachment);
1603
1604                body = StringUtil.replace(
1605                    body, attachmentPath, "cid:" + contentId);
1606
1607                count++;
1608
1609                x = body.indexOf(url);
1610            }
1611            else {
1612                x = body.indexOf(url, x + 1);
1613            }
1614        }
1615
1616        if (count > 0) {
1617            mailMessage.setBody(body);
1618        }
1619
1620        if (_log.isDebugEnabled()) {
1621            _log.debug("Body after replacing embedded images\n" + body);
1622        }
1623    }
1624
1625    private static Address[] _resolveAddresses(
1626            HttpServletRequest req, Address[] addresses)
1627        throws RecipientException {
1628
1629        Company company = null;
1630
1631        try {
1632            company = PortalUtil.getCompany(req);
1633        }
1634        catch (Exception e) {
1635            return addresses;
1636        }
1637
1638        for (int i = 0; i < addresses.length; i++) {
1639            InternetAddress address = (InternetAddress)addresses[i];
1640
1641            if ((address.getPersonal() == null) &&
1642                !Validator.isEmailAddress(address.getAddress())) {
1643
1644                try {
1645                    User user = UserLocalServiceUtil.getUserByEmailAddress(
1646                        company.getCompanyId(), address.getAddress().trim() +
1647                            StringPool.AT + company.getMx());
1648
1649                    addresses[i] = new InternetAddress(
1650                        user.getEmailAddress(), user.getFullName());
1651                }
1652                catch (Exception e) {
1653                    if (_log.isErrorEnabled()) {
1654                        _log.error(
1655                            "Problems found trying to resolve email address " +
1656                                address);
1657                    }
1658
1659                    throw new RecipientException(e);
1660                }
1661            }
1662        }
1663
1664        return addresses;
1665    }
1666
1667    private static void _search(
1668            HttpServletRequest req, MailDisplayTerms displayTerms, Set results)
1669        throws FolderException, MailServerException, StoreException {
1670
1671        Store store = _getStore(req);
1672
1673        SearchTerm fullTerm = null;
1674
1675        if (Validator.isNotNull(displayTerms.getFrom())) {
1676            fullTerm = new FromStringTerm(displayTerms.getFrom());
1677        }
1678
1679        if (Validator.isNotNull(displayTerms.getTo())) {
1680            SearchTerm to = new RecipientStringTerm(
1681                Message.RecipientType.TO, displayTerms.getTo());
1682            SearchTerm cc = new RecipientStringTerm(
1683                Message.RecipientType.CC, displayTerms.getTo());
1684            SearchTerm bcc = new RecipientStringTerm(
1685                Message.RecipientType.BCC, displayTerms.getTo());
1686
1687            SearchTerm term = to;
1688            term = _appendSearchTerm(term, cc, false);
1689            term = _appendSearchTerm(term, bcc, false);
1690
1691            fullTerm = _appendSearchTerm(
1692                fullTerm, term, displayTerms.isAndOperator());
1693        }
1694
1695        if (Validator.isNotNull(displayTerms.getSubject())) {
1696            SearchTerm term = new SubjectTerm(displayTerms.getSubject());
1697
1698            fullTerm = _appendSearchTerm(
1699                fullTerm, term, displayTerms.isAndOperator());
1700        }
1701
1702        if (Validator.isNotNull(displayTerms.getEntireMessage())) {
1703            String em = displayTerms.getEntireMessage();
1704
1705            SearchTerm from = new FromStringTerm(em);
1706            SearchTerm to = new RecipientStringTerm(
1707                Message.RecipientType.TO, em);
1708            SearchTerm cc = new RecipientStringTerm(
1709                Message.RecipientType.CC, em);
1710            SearchTerm bcc = new RecipientStringTerm(
1711                Message.RecipientType.BCC, em);
1712            SearchTerm subject = new SubjectTerm(em);
1713            SearchTerm body = new BodyTerm(em);
1714
1715            SearchTerm term = from;
1716            term = _appendSearchTerm(term, to, false);
1717            term = _appendSearchTerm(term, cc, false);
1718            term = _appendSearchTerm(term, bcc, false);
1719            term = _appendSearchTerm(term, subject, false);
1720            term = _appendSearchTerm(term, body, false);
1721
1722            fullTerm = _appendSearchTerm(
1723                fullTerm, term, displayTerms.isAndOperator());
1724        }
1725
1726        if (displayTerms.hasDate()) {
1727            SearchTerm startDate =
1728                new SentDateTerm(DateTerm.GE, displayTerms.getStartDate());
1729            SearchTerm endDate =
1730                new SentDateTerm(DateTerm.LE, displayTerms.getEndDate());
1731
1732            SearchTerm term = startDate;
1733            term = _appendSearchTerm(term, endDate, true);
1734
1735            fullTerm = _appendSearchTerm(
1736                fullTerm, term, displayTerms.isAndOperator());
1737        }
1738
1739        if (fullTerm != null) {
1740            try {
1741                IMAPFolder folder = (IMAPFolder)store.getFolder(
1742                    _getResolvedFolderName(displayTerms.getFolderName()));
1743
1744                folder.open(IMAPFolder.READ_ONLY);
1745
1746                Message[] messages = folder.search(fullTerm);
1747
1748                _convertEnvelopes(
1749                    folder, displayTerms.getFolderName(), messages, results);
1750            }
1751            catch (MessagingException me) {
1752                throw new FolderException(me);
1753            }
1754        }
1755    }
1756
1757    private static final String[] _HTML_START_TAGS = new String[] {
1758        "<html", "<head", "<body", "<meta", "<o:SmartTagType"
1759    };
1760
1761    private static final String[] _HTML_END_TAGS = new String[] {
1762        "</html>", "</head>", "</body>"
1763    };
1764
1765    private static final double _ENCODING_FACTOR = 0.65;
1766
1767    private static Log _log = LogFactory.getLog(MailUtil.class);
1768
1769}