001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.mail;
018:
019: import java.io.IOException;
020: import java.util.List;
021: import javax.mail.FetchProfile;
022: import javax.mail.Folder;
023: import javax.mail.Message;
024: import javax.mail.MessagingException;
025: import javax.mail.Multipart;
026: import javax.mail.Part;
027: import javax.mail.Store;
028: import javax.mail.UIDFolder;
029: import javax.mail.search.FromStringTerm;
030: import javax.mail.search.OrTerm;
031: import javax.mail.search.SearchTerm;
032: import javax.mail.search.SubjectTerm;
033: import org.apache.avalon.framework.context.Context;
034: import org.apache.avalon.framework.context.ContextException;
035: import org.apache.avalon.framework.context.Contextualizable;
036: import org.apache.avalon.framework.logger.AbstractLogEnabled;
037: import org.apache.cocoon.mail.command.AbstractMailCommand;
038: import org.apache.cocoon.mail.command.MailCommands;
039:
040: /**
041: * Manage invocation of mail commands.
042: *
043: * @author Bernhard Huber
044: * @since 23 October 2002
045: * @version $Id: MailCommandManager.java 468424 2006-10-27 15:44:53Z vgritsenko $
046: */
047: public class MailCommandManager extends AbstractLogEnabled {
048:
049: /**
050: * Description of the Field
051: */
052: public final static String DEFAULT_FOLDER_NAME = "INBOX";
053:
054: /**
055: * Description of the Field
056: */
057: public final static String DEFAULT_FOLDER_PATTERN = "%";
058:
059: /**
060: * Context key specifying the foldername.
061: */
062: public final static String CONTEXT_FOLDER_ENTRY = "folder";
063:
064: /**
065: * Description of the Field
066: */
067: public final static String CONTEXT_UID_ENTRY = "uid";
068:
069: /**
070: * Description of the Field
071: */
072: public final static String CONTEXT_ID_ENTRY = "id";
073:
074: /**
075: * Description of the Field
076: */
077: public final static String CONTEXT_PARTID_ENTRY = "part-id";
078:
079: /**
080: * Description of the Field
081: */
082: public final static String CONTEXT_FOLDER_PATTERN_ENTRY = "folder-pattern";
083:
084: /**
085: * Description of the Field
086: */
087: public final static String CONTEXT_MAX_FOLDER_LEVEL_ENTRY = "max-folder-level";
088:
089: /**
090: * Creates a new instance of MailHeaderList
091: */
092: public MailCommandManager() {
093: }
094:
095: /**
096: * Open a javamail folder
097: *
098: * @param f Description of the Parameter
099: * @param mode folder opening mode, use Folder.READ_WRITE, or Folder.READ_ONLY
100: * @exception MessagingException Description of the Exception
101: */
102: public static void openFolder(Folder f, int mode)
103: throws MessagingException {
104: if (!f.isOpen()) {
105: f.open(mode);
106: }
107: }
108:
109: /**
110: * Close a javamail folder
111: *
112: * @param f Description of the Parameter
113: * @exception MessagingException Description of the Exception
114: */
115: public static void closeFolder(Folder f) throws MessagingException {
116: if (f != null && f.isOpen()) {
117: // fix me : do we need expungeOnExit = true?
118: f.close(false);
119: }
120: }
121:
122: /**
123: * Open a javamail store
124: *
125: * @param s Description of the Parameter
126: * @exception MessagingException Description of the Exception
127: */
128: public static void openStore(Store s) throws MessagingException {
129: if (!s.isConnected()) {
130: s.connect();
131: }
132: }
133:
134: /**
135: * Close a javamail store
136: *
137: * @param s Description of the Parameter
138: * @exception MessagingException Description of the Exception
139: */
140: public static void closeStore(Store s) throws MessagingException {
141: if (s != null && s.isConnected()) {
142: s.close();
143: }
144: }
145:
146: /**
147: * Description of the Method
148: *
149: * @param aList Description of the Parameter
150: * @return Description of the Return Value
151: */
152: public List execute(List aList) {
153: MailCommands folderCommands = new MailCommands(aList);
154: try {
155: folderCommands.execute();
156: } catch (MessagingException me) {
157: // log exception
158: getLogger().error("Cannot execute", me);
159: }
160: return folderCommands.getResults();
161: }
162:
163: /**
164: * Description of the Method
165: *
166: * @param amfa Description of the Parameter
167: * @return Description of the Return Value
168: */
169: public List execute(AbstractMailCommand amfa) {
170: try {
171: amfa.execute();
172: } catch (MessagingException me) {
173: // log exception
174: getLogger().error("Cannot execute", me);
175: }
176: return amfa.getResults();
177: }
178:
179: /**
180: * Retrieve folder, and put it as command result.
181: */
182: public static class MailFolderCatCommand extends
183: AbstractMailCommand implements Contextualizable {
184:
185: private Folder aFolder;
186:
187: /**
188: * Constructor for the MailFolderCommand object
189: */
190: public MailFolderCatCommand() {
191: }
192:
193: /**
194: * Description of the Method
195: *
196: * @param ctx Description of the Parameter
197: * @exception ContextException Description of the Exception
198: */
199: public void contextualize(Context ctx) throws ContextException {
200: MailContext mctx = (MailContext) ctx;
201: this .aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY);
202: }
203:
204: /**
205: * Description of the Method
206: *
207: * @exception MessagingException Description of the Exception
208: */
209: public void execute() throws MessagingException {
210: MailCommandManager.openFolder(aFolder, Folder.READ_ONLY);
211: addResult(aFolder);
212: }
213: }
214:
215: /**
216: * Retrieve folder, and put it as command result.
217: */
218: public static class MailRefreshFolderCommand extends
219: AbstractMailCommand implements Contextualizable {
220:
221: private Folder aFolder;
222:
223: /**
224: * Constructor for the MailFolderCommand object
225: */
226: public MailRefreshFolderCommand() {
227: }
228:
229: /**
230: * Description of the Method
231: *
232: * @param ctx Description of the Parameter
233: * @exception ContextException Description of the Exception
234: */
235: public void contextualize(Context ctx) throws ContextException {
236: MailContext mctx = (MailContext) ctx;
237: this .aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY);
238: }
239:
240: /**
241: * Description of the Method
242: *
243: * @exception MessagingException Description of the Exception
244: */
245: public void execute() throws MessagingException {
246: MailCommandManager.closeFolder(aFolder);
247: MailCommandManager.openFolder(aFolder, Folder.READ_ONLY);
248: addResult(aFolder);
249: }
250: }
251:
252: /**
253: * Retrieved headers of all messages of a folder, put
254: * retrieved messages as command result.
255: */
256: public static class MailListMessagesCommand extends
257: AbstractMailCommand implements Contextualizable {
258:
259: private Folder aFolder;
260:
261: /**
262: * Constructor for the MailAllHeadersCommand object
263: */
264: public MailListMessagesCommand() {
265: }
266:
267: /**
268: * Description of the Method
269: *
270: * @param ctx Description of the Parameter
271: * @exception ContextException Description of the Exception
272: */
273: public void contextualize(Context ctx) throws ContextException {
274: // try to get the folder object
275: MailContext mctx = (MailContext) ctx;
276: this .aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY);
277: }
278:
279: /**
280: * Description of the Method
281: *
282: * @exception MessagingException Description of the Exception
283: */
284: public void execute() throws MessagingException {
285: MailCommandManager.openFolder(aFolder, Folder.READ_ONLY);
286:
287: // add folder, too
288: addResult(aFolder);
289:
290: Message[] messages = aFolder.getMessages();
291:
292: // Use a suitable FetchProfile
293: FetchProfile fp = new FetchProfile();
294: fp.add(FetchProfile.Item.ENVELOPE);
295: fp.add(FetchProfile.Item.FLAGS);
296: fp.add("X-Mailer");
297: aFolder.fetch(messages, fp);
298:
299: // add all messages to the result
300: addResult(messages);
301:
302: }
303: }
304:
305: /**
306: * List all subfolders of a folder, put
307: * all retrieved folders as command result.
308: */
309: public static class MailListFolderCommand extends
310: AbstractMailCommand implements Contextualizable {
311:
312: private Folder aFolder;
313: private String folderPattern = MailCommandManager.DEFAULT_FOLDER_PATTERN;
314:
315: /**
316: * Constructor for the MailFoldersCommand object
317: */
318: public MailListFolderCommand() {
319: }
320:
321: /**
322: * Gets the folderPattern attribute of the ListFolderCommand object
323: *
324: * @return The folderPattern value
325: */
326: public String getFolderPattern() {
327: return this .folderPattern;
328: }
329:
330: /**
331: * Description of the Method
332: *
333: * @param ctx Description of the Parameter
334: * @exception ContextException Description of the Exception
335: */
336: public void contextualize(Context ctx) throws ContextException {
337: MailContext mctx = (MailContext) ctx;
338: this .aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY);
339:
340: try {
341: this .folderPattern = (String) ctx.get("param:"
342: + CONTEXT_FOLDER_PATTERN_ENTRY);
343: } catch (ContextException ce) {
344: // use default folder pattern
345: this .folderPattern = MailCommandManager.DEFAULT_FOLDER_PATTERN;
346: }
347: }
348:
349: /**
350: * Description of the Method
351: *
352: * @exception MessagingException Description of the Exception
353: */
354: public void execute() throws MessagingException {
355: // spec say: folder list can be invoked on closed folder MailCommandManager.openFolder(aFolder,Folder.READ_ONLY);
356: //addResult(aFolder);
357: Folder[] subFolders = aFolder.list(this .folderPattern);
358: getLogger().debug(
359: "Adding " + String.valueOf(subFolders.length)
360: + " subFolders ");
361: for (int i = 0; i < subFolders.length; i++) {
362: getLogger().debug(
363: "subFolder " + String.valueOf(i) + " name "
364: + subFolders[i].getFullName());
365: }
366: addResult(subFolders);
367: }
368: }
369:
370: /**
371: * Retrieved a message (envelope plus content) of a folder by its uid, put
372: * retrieved message as command result.
373: */
374: public static class MailCatMessageByUIDCommand extends
375: AbstractMailCommand implements Contextualizable {
376:
377: private int msgUID = 1;
378: private Folder aFolder;
379:
380: /**
381: * Constructor for the MailMessageByUIDCommand object
382: */
383: public MailCatMessageByUIDCommand() {
384: }
385:
386: /**
387: * Description of the Method
388: *
389: * @param ctx Description of the Parameter
390: * @exception ContextException Description of the Exception
391: */
392: public void contextualize(Context ctx) throws ContextException {
393: MailContext mctx = (MailContext) ctx;
394: this .aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY);
395:
396: Integer i = (Integer) ctx.get("param-integer:"
397: + CONTEXT_UID_ENTRY);
398: if (i == null) {
399: String message = "Missing mandatory context entry "
400: + String.valueOf(CONTEXT_UID_ENTRY);
401: throw new ContextException(message);
402: }
403: this .msgUID = i.intValue();
404: }
405:
406: /**
407: * Description of the Method
408: *
409: * @exception MessagingException Description of the Exception
410: */
411: public void execute() throws MessagingException {
412: UIDFolder uidFolder = (UIDFolder) aFolder;
413: MailCommandManager.openFolder(aFolder, Folder.READ_ONLY);
414:
415: // add folder, too
416: addResult(aFolder);
417:
418: Message msg = uidFolder.getMessageByUID(msgUID);
419: addResult(msg);
420: }
421: }
422:
423: /**
424: * Retrieved a message (envelope plus content) of a folder by its id, put
425: * retrieved message as command result.
426: */
427: public static class MailCatMessageByIdCommand extends
428: AbstractMailCommand implements Contextualizable {
429:
430: private int msgId = 1;
431: private Folder aFolder;
432:
433: /**
434: * Constructor for the MailMessageByIdCommand object
435: */
436: public MailCatMessageByIdCommand() {
437: }
438:
439: /**
440: * Description of the Method
441: *
442: * @param ctx Description of the Parameter
443: * @exception ContextException Description of the Exception
444: */
445: public void contextualize(Context ctx) throws ContextException {
446: MailContext mctx = (MailContext) ctx;
447: this .aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY);
448:
449: try {
450: Integer i = (Integer) ctx.get("param-integer:"
451: + CONTEXT_ID_ENTRY);
452: this .msgId = i.intValue();
453: } catch (ContextException ce) {
454: String message = "Missing mandatory context entry "
455: + String.valueOf(CONTEXT_ID_ENTRY);
456: throw new ContextException(message);
457: }
458: }
459:
460: /**
461: * Description of the Method
462: *
463: * @exception MessagingException Description of the Exception
464: */
465: public void execute() throws MessagingException {
466: MailCommandManager.openFolder(aFolder, Folder.READ_ONLY);
467:
468: // add folder, too
469: addResult(aFolder);
470:
471: Message msg = aFolder.getMessage(msgId);
472: addResult(msg);
473: }
474: }
475:
476: /**
477: * Retrieved a message part by its part id, specifying the message by id, put
478: * retrieved part as command result.
479: */
480: public static class MailCatAttachmentMessageByIdCommand extends
481: AbstractMailCommand implements Contextualizable {
482:
483: private int msgId = -1;
484: private int partId = -1;
485: private Folder aFolder;
486:
487: /**
488: * Constructor for the MailCatAttachmentMessageByIdCommand object
489: */
490: public MailCatAttachmentMessageByIdCommand() {
491: }
492:
493: /**
494: * Description of the Method
495: *
496: * @param ctx Description of the Parameter
497: * @exception ContextException Description of the Exception
498: */
499: public void contextualize(Context ctx) throws ContextException {
500: MailContext mctx = (MailContext) ctx;
501: this .aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY);
502:
503: Integer i = (Integer) ctx.get("param-integer:"
504: + CONTEXT_ID_ENTRY);
505: if (i == null) {
506: String message = "Missing mandatory context entry "
507: + String.valueOf(CONTEXT_ID_ENTRY);
508: throw new ContextException(message);
509: }
510: this .msgId = i.intValue();
511:
512: i = (Integer) ctx.get("param-integer:"
513: + CONTEXT_PARTID_ENTRY);
514: if (i == null) {
515: String message = "Missing mandatory context entry "
516: + String.valueOf(CONTEXT_PARTID_ENTRY);
517: throw new ContextException(message);
518: }
519: this .partId = i.intValue();
520: }
521:
522: /**
523: * Description of the Method
524: *
525: * @exception MessagingException Description of the Exception
526: */
527: public void execute() throws MessagingException {
528: MailCommandManager.openFolder(aFolder, Folder.READ_ONLY);
529:
530: // add folder, too
531: addResult(aFolder);
532:
533: // get the message
534: Message msg = aFolder.getMessage(msgId);
535:
536: if (msg == null) {
537: String message = "Cannot get message for id "
538: + String.valueOf(msgId);
539: getLogger().warn(message);
540: return;
541: }
542: try {
543: Part part = null;
544: Object objRef = msg.getContent();
545: if (!(objRef instanceof Multipart)) {
546: String message = "Message of id "
547: + String.valueOf(msgId)
548: + " is not a multipart message!";
549: getLogger().warn(message);
550: return;
551: }
552: Multipart multipart = (Multipart) objRef;
553: int numParts = multipart.getCount();
554:
555: if (partId < numParts) {
556: part = multipart.getBodyPart(partId);
557: } else {
558: String message = "Invalid part id "
559: + String.valueOf(this .partId)
560: + " of message id "
561: + String.valueOf(this .msgId);
562: getLogger().warn(message);
563: }
564: addResult(part);
565: } catch (IOException ioe) {
566: String message = "Cannot get content of "
567: + "message for id " + String.valueOf(msgId);
568: throw new MessagingException(message, ioe);
569: }
570: }
571: }
572:
573: /**
574: * Description of the Class
575: */
576: public static class MailSearchMessagesCommand extends
577: AbstractMailCommand implements Contextualizable {
578:
579: private Folder aFolder;
580: private SearchTerm searchTerm;
581:
582: /**
583: * Description of the Method
584: *
585: * @param ctx Description of the Parameter
586: * @exception ContextException Description of the Exception
587: */
588: public void contextualize(Context ctx) throws ContextException {
589: MailContext mctx = (MailContext) ctx;
590: this .aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY);
591:
592: String searchString = (String) ctx.get("param:" + "search");
593: if (searchString == null) {
594: searchString = "";
595: }
596: searchTerm = new OrTerm(new SubjectTerm(searchString),
597: new FromStringTerm(searchString));
598:
599: // build searchTerm from searchTermString
600:
601: /* proposed searchTermString syntax
602: {header}:comp-op:{value} & {header}:comp-op:{value} | .....
603: eg. subject:eq:cocoon & date::MM/DD/2002
604: header:com-op:
605: subject:[cont|ncont]:
606: sender:[cont|ncont]:
607: body:[cont|ncont]:
608: date:[is|nis|before|after]
609: status:[is|nis]:[Read|New|Replied|Forwarded]
610: to:[cont|ncont]:
611: cc:
612: age-in-days:[is|nis|gt|lt]:
613: reply-to:[cont|ncont]:
614: */
615: }
616:
617: /**
618: * Description of the Method
619: *
620: * @exception MessagingException Description of the Exception
621: */
622: public void execute() throws MessagingException {
623: MailCommandManager.openFolder(aFolder, Folder.READ_ONLY);
624:
625: // add folder, too
626: addResult(aFolder);
627:
628: Message[] msgs = aFolder.search(searchTerm);
629: addResult(msgs);
630: }
631: }
632: }
|