/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.mail; import java.io.IOException; import java.util.List; import javax.mail.FetchProfile; import javax.mail.Folder; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Part; import javax.mail.Store; import javax.mail.UIDFolder; import javax.mail.search.FromStringTerm; import javax.mail.search.OrTerm; import javax.mail.search.SearchTerm; import javax.mail.search.SubjectTerm; import org.apache.avalon.framework.context.Context; import org.apache.avalon.framework.context.ContextException; import org.apache.avalon.framework.context.Contextualizable; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.cocoon.mail.command.AbstractMailCommand; import org.apache.cocoon.mail.command.MailCommands; /** * Manage invocation of mail commands. * * @author Bernhard Huber * @since 23 October 2002 * @version $Id$ */ public class MailCommandManager extends AbstractLogEnabled { /** * Description of the Field */ public final static String DEFAULT_FOLDER_NAME = "INBOX"; /** * Description of the Field */ public final static String DEFAULT_FOLDER_PATTERN = "%"; /** * Context key specifying the foldername. */ public final static String CONTEXT_FOLDER_ENTRY = "folder"; /** * Description of the Field */ public final static String CONTEXT_UID_ENTRY = "uid"; /** * Description of the Field */ public final static String CONTEXT_ID_ENTRY = "id"; /** * Description of the Field */ public final static String CONTEXT_PARTID_ENTRY = "part-id"; /** * Description of the Field */ public final static String CONTEXT_FOLDER_PATTERN_ENTRY = "folder-pattern"; /** * Description of the Field */ public final static String CONTEXT_MAX_FOLDER_LEVEL_ENTRY = "max-folder-level"; /** * Creates a new instance of MailHeaderList */ public MailCommandManager() { } /** * Open a javamail folder * * @param f Description of the Parameter * @param mode folder opening mode, use Folder.READ_WRITE, or Folder.READ_ONLY * @exception MessagingException Description of the Exception */ public static void openFolder(Folder f, int mode) throws MessagingException { if (!f.isOpen()) { f.open(mode); } } /** * Close a javamail folder * * @param f Description of the Parameter * @exception MessagingException Description of the Exception */ public static void closeFolder(Folder f) throws MessagingException { if (f != null && f.isOpen()) { // fix me : do we need expungeOnExit = true? f.close(false); } } /** * Open a javamail store * * @param s Description of the Parameter * @exception MessagingException Description of the Exception */ public static void openStore(Store s) throws MessagingException { if (!s.isConnected()) { s.connect(); } } /** * Close a javamail store * * @param s Description of the Parameter * @exception MessagingException Description of the Exception */ public static void closeStore(Store s) throws MessagingException { if (s != null && s.isConnected()) { s.close(); } } /** * Description of the Method * * @param aList Description of the Parameter * @return Description of the Return Value */ public List execute(List aList) { MailCommands folderCommands = new MailCommands(aList); try { folderCommands.execute(); } catch (MessagingException me) { // log exception getLogger().error("Cannot execute", me); } return folderCommands.getResults(); } /** * Description of the Method * * @param amfa Description of the Parameter * @return Description of the Return Value */ public List execute(AbstractMailCommand amfa) { try { amfa.execute(); } catch (MessagingException me) { // log exception getLogger().error("Cannot execute", me); } return amfa.getResults(); } /** * Retrieve folder, and put it as command result. */ public static class MailFolderCatCommand extends AbstractMailCommand implements Contextualizable { private Folder aFolder; /** * Constructor for the MailFolderCommand object */ public MailFolderCatCommand() { } /** * Description of the Method * * @param ctx Description of the Parameter * @exception ContextException Description of the Exception */ public void contextualize(Context ctx) throws ContextException { MailContext mctx = (MailContext) ctx; this.aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY); } /** * Description of the Method * * @exception MessagingException Description of the Exception */ public void execute() throws MessagingException { MailCommandManager.openFolder(aFolder, Folder.READ_ONLY); addResult(aFolder); } } /** * Retrieve folder, and put it as command result. */ public static class MailRefreshFolderCommand extends AbstractMailCommand implements Contextualizable { private Folder aFolder; /** * Constructor for the MailFolderCommand object */ public MailRefreshFolderCommand() { } /** * Description of the Method * * @param ctx Description of the Parameter * @exception ContextException Description of the Exception */ public void contextualize(Context ctx) throws ContextException { MailContext mctx = (MailContext) ctx; this.aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY); } /** * Description of the Method * * @exception MessagingException Description of the Exception */ public void execute() throws MessagingException { MailCommandManager.closeFolder(aFolder); MailCommandManager.openFolder(aFolder, Folder.READ_ONLY); addResult(aFolder); } } /** * Retrieved headers of all messages of a folder, put * retrieved messages as command result. */ public static class MailListMessagesCommand extends AbstractMailCommand implements Contextualizable { private Folder aFolder; /** * Constructor for the MailAllHeadersCommand object */ public MailListMessagesCommand() { } /** * Description of the Method * * @param ctx Description of the Parameter * @exception ContextException Description of the Exception */ public void contextualize(Context ctx) throws ContextException { // try to get the folder object MailContext mctx = (MailContext) ctx; this.aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY); } /** * Description of the Method * * @exception MessagingException Description of the Exception */ public void execute() throws MessagingException { MailCommandManager.openFolder(aFolder, Folder.READ_ONLY); // add folder, too addResult(aFolder); Message[] messages = aFolder.getMessages(); // Use a suitable FetchProfile FetchProfile fp = new FetchProfile(); fp.add(FetchProfile.Item.ENVELOPE); fp.add(FetchProfile.Item.FLAGS); fp.add("X-Mailer"); aFolder.fetch(messages, fp); // add all messages to the result addResult(messages); } } /** * List all subfolders of a folder, put * all retrieved folders as command result. */ public static class MailListFolderCommand extends AbstractMailCommand implements Contextualizable { private Folder aFolder; private String folderPattern = MailCommandManager.DEFAULT_FOLDER_PATTERN; /** * Constructor for the MailFoldersCommand object */ public MailListFolderCommand() { } /** * Gets the folderPattern attribute of the ListFolderCommand object * * @return The folderPattern value */ public String getFolderPattern() { return this.folderPattern; } /** * Description of the Method * * @param ctx Description of the Parameter * @exception ContextException Description of the Exception */ public void contextualize(Context ctx) throws ContextException { MailContext mctx = (MailContext) ctx; this.aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY); try { this.folderPattern = (String) ctx.get("param:" + CONTEXT_FOLDER_PATTERN_ENTRY); } catch (ContextException ce) { // use default folder pattern this.folderPattern = MailCommandManager.DEFAULT_FOLDER_PATTERN; } } /** * Description of the Method * * @exception MessagingException Description of the Exception */ public void execute() throws MessagingException { // spec say: folder list can be invoked on closed folder MailCommandManager.openFolder(aFolder,Folder.READ_ONLY); //addResult(aFolder); Folder[] subFolders = aFolder.list(this.folderPattern); getLogger().debug("Adding " + String.valueOf(subFolders.length) + " subFolders "); for (int i = 0; i < subFolders.length; i++) { getLogger().debug("subFolder " + String.valueOf(i) + " name " + subFolders[i].getFullName()); } addResult(subFolders); } } /** * Retrieved a message (envelope plus content) of a folder by its uid, put * retrieved message as command result. */ public static class MailCatMessageByUIDCommand extends AbstractMailCommand implements Contextualizable { private int msgUID = 1; private Folder aFolder; /** * Constructor for the MailMessageByUIDCommand object */ public MailCatMessageByUIDCommand() { } /** * Description of the Method * * @param ctx Description of the Parameter * @exception ContextException Description of the Exception */ public void contextualize(Context ctx) throws ContextException { MailContext mctx = (MailContext) ctx; this.aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY); Integer i = (Integer) ctx.get("param-integer:" + CONTEXT_UID_ENTRY); if (i == null) { String message = "Missing mandatory context entry " + String.valueOf(CONTEXT_UID_ENTRY); throw new ContextException(message); } this.msgUID = i.intValue(); } /** * Description of the Method * * @exception MessagingException Description of the Exception */ public void execute() throws MessagingException { UIDFolder uidFolder = (UIDFolder) aFolder; MailCommandManager.openFolder(aFolder, Folder.READ_ONLY); // add folder, too addResult(aFolder); Message msg = uidFolder.getMessageByUID(msgUID); addResult(msg); } } /** * Retrieved a message (envelope plus content) of a folder by its id, put * retrieved message as command result. */ public static class MailCatMessageByIdCommand extends AbstractMailCommand implements Contextualizable { private int msgId = 1; private Folder aFolder; /** * Constructor for the MailMessageByIdCommand object */ public MailCatMessageByIdCommand() { } /** * Description of the Method * * @param ctx Description of the Parameter * @exception ContextException Description of the Exception */ public void contextualize(Context ctx) throws ContextException { MailContext mctx = (MailContext) ctx; this.aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY); try { Integer i = (Integer) ctx.get("param-integer:" + CONTEXT_ID_ENTRY); this.msgId = i.intValue(); } catch (ContextException ce) { String message = "Missing mandatory context entry " + String.valueOf(CONTEXT_ID_ENTRY); throw new ContextException(message); } } /** * Description of the Method * * @exception MessagingException Description of the Exception */ public void execute() throws MessagingException { MailCommandManager.openFolder(aFolder, Folder.READ_ONLY); // add folder, too addResult(aFolder); Message msg = aFolder.getMessage(msgId); addResult(msg); } } /** * Retrieved a message part by its part id, specifying the message by id, put * retrieved part as command result. */ public static class MailCatAttachmentMessageByIdCommand extends AbstractMailCommand implements Contextualizable { private int msgId = -1; private int partId = -1; private Folder aFolder; /** * Constructor for the MailCatAttachmentMessageByIdCommand object */ public MailCatAttachmentMessageByIdCommand() { } /** * Description of the Method * * @param ctx Description of the Parameter * @exception ContextException Description of the Exception */ public void contextualize(Context ctx) throws ContextException { MailContext mctx = (MailContext) ctx; this.aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY); Integer i = (Integer) ctx.get("param-integer:" + CONTEXT_ID_ENTRY); if (i == null) { String message = "Missing mandatory context entry " + String.valueOf(CONTEXT_ID_ENTRY); throw new ContextException(message); } this.msgId = i.intValue(); i = (Integer) ctx.get("param-integer:" + CONTEXT_PARTID_ENTRY); if (i == null) { String message = "Missing mandatory context entry " + String.valueOf(CONTEXT_PARTID_ENTRY); throw new ContextException(message); } this.partId = i.intValue(); } /** * Description of the Method * * @exception MessagingException Description of the Exception */ public void execute() throws MessagingException { MailCommandManager.openFolder(aFolder, Folder.READ_ONLY); // add folder, too addResult(aFolder); // get the message Message msg = aFolder.getMessage(msgId); if (msg == null) { String message = "Cannot get message for id " + String.valueOf(msgId); getLogger().warn(message); return; } try { Part part = null; Object objRef = msg.getContent(); if (!(objRef instanceof Multipart)) { String message = "Message of id " + String.valueOf(msgId) + " is not a multipart message!"; getLogger().warn(message); return; } Multipart multipart = (Multipart) objRef; int numParts = multipart.getCount(); if (partId < numParts) { part = multipart.getBodyPart(partId); } else { String message = "Invalid part id " + String.valueOf(this.partId) + " of message id " + String.valueOf(this.msgId); getLogger().warn(message); } addResult(part); } catch (IOException ioe) { String message = "Cannot get content of " + "message for id " + String.valueOf(msgId); throw new MessagingException(message, ioe); } } } /** * Description of the Class */ public static class MailSearchMessagesCommand extends AbstractMailCommand implements Contextualizable { private Folder aFolder; private SearchTerm searchTerm; /** * Description of the Method * * @param ctx Description of the Parameter * @exception ContextException Description of the Exception */ public void contextualize(Context ctx) throws ContextException { MailContext mctx = (MailContext) ctx; this.aFolder = mctx.getTheFolder(CONTEXT_FOLDER_ENTRY); String searchString = (String) ctx.get("param:" + "search"); if (searchString == null) { searchString = ""; } searchTerm = new OrTerm( new SubjectTerm(searchString), new FromStringTerm(searchString)); // build searchTerm from searchTermString /* proposed searchTermString syntax {header}:comp-op:{value} & {header}:comp-op:{value} | ..... eg. subject:eq:cocoon & date::MM/DD/2002 header:com-op: subject:[cont|ncont]: sender:[cont|ncont]: body:[cont|ncont]: date:[is|nis|before|after] status:[is|nis]:[Read|New|Replied|Forwarded] to:[cont|ncont]: cc: age-in-days:[is|nis|gt|lt]: reply-to:[cont|ncont]: */ } /** * Description of the Method * * @exception MessagingException Description of the Exception */ public void execute() throws MessagingException { MailCommandManager.openFolder(aFolder, Folder.READ_ONLY); // add folder, too addResult(aFolder); Message[] msgs = aFolder.search(searchTerm); addResult(msgs); } } }