/* * eXist Mail Module Extension * Copyright (C) 2006-09 Adam Retter <adam.retter@devon.gov.uk> * www.adamretter.co.uk * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id$ */ package org.exist.xquery.modules.mail; import java.util.Map.Entry; import org.exist.xquery.AbstractInternalModule; import org.exist.xquery.FunctionDef; import org.exist.xquery.XQueryContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.mail.Folder; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Store; import org.exist.xquery.modules.ModuleUtils; import org.exist.xquery.modules.ModuleUtils.ContextMapEntryModifier; import org.exist.xquery.modules.ModuleUtils.ContextMapModifier; /** * eXist Mail Module Extension * * An extension module for the eXist Native XML Database that allows email to * be sent from XQuery using either SMTP or Sendmail. * * @author Adam Retter <adam@exist-db.org> * @author Andrzej Taramina <andrzej@chaeron.com> * @author ljo * @author José María Fernández <josemariafg@gmail.com> * @serial 2011-09-06 * @version 1.4.1 * * @see org.exist.xquery.AbstractInternalModule#AbstractInternalModule(org.exist.xquery.FunctionDef[], java.util.Map) */ public class MailModule extends AbstractInternalModule { private final static Logger LOG = LogManager.getLogger( MailModule.class ); public final static String NAMESPACE_URI = "http://exist-db.org/xquery/mail"; public final static String PREFIX = "mail"; // JavaMail-based from 2009-03-14 // makes the need for versioning of the functions obvious too /ljo public final static String INCLUSION_DATE = "2005-05-12, 2009-03-14"; public final static String RELEASED_IN_VERSION = "eXist-1.2 (JavaMail-based in trunk)"; private final static FunctionDef[] functions = { new FunctionDef(MailSessionFunctions.signatures[0], MailSessionFunctions.class), new FunctionDef(MailStoreFunctions.signatures[0], MailStoreFunctions.class), new FunctionDef(MailStoreFunctions.signatures[1], MailStoreFunctions.class), new FunctionDef(MailFolderFunctions.signatures[0], MailFolderFunctions.class), new FunctionDef(MailFolderFunctions.signatures[1], MailFolderFunctions.class), new FunctionDef(MessageListFunctions.signatures[0], MessageListFunctions.class), new FunctionDef(MessageListFunctions.signatures[1], MessageListFunctions.class), new FunctionDef(MessageListFunctions.signatures[2], MessageListFunctions.class), new FunctionDef(MessageListFunctions.signatures[3], MessageListFunctions.class), new FunctionDef(MessageFunctions.signatures[0], MessageFunctions.class), new FunctionDef(SendEmailFunction.signatures[0], SendEmailFunction.class), // deprecated functions: new FunctionDef(SendEmailFunction.deprecated, SendEmailFunction.class) }; public final static String SESSIONS_CONTEXTVAR = "_eXist_mail_sessions"; public final static String STORES_CONTEXTVAR = "_eXist_mail_stores"; public final static String FOLDERS_CONTEXTVAR = "_eXist_mail_folders"; public final static String FOLDERMSGLISTS_CONTEXTVAR = "_eXist_folder_message_lists"; public final static String MSGLISTS_CONTEXTVAR = "_eXist_mail_message_lists"; private static long currentSessionHandle = System.currentTimeMillis(); public MailModule(Map<String, List<? extends Object>> parameters) { super(functions, parameters); } @Override public String getNamespaceURI() { return NAMESPACE_URI; } @Override public String getDefaultPrefix() { return PREFIX; } @Override public String getDescription() { return "A module for performing email related functions"; } @Override public String getReleaseVersion() { return RELEASED_IN_VERSION; } //*************************************************************************** //* //* Session Methods //* //***************************************************************************/ /** * Retrieves a previously stored Session from the Context of an XQuery * * @param context The Context of the XQuery containing the Session * @param sessionHandle The handle of the Session to retrieve from the Context of the XQuery */ static Session retrieveSession(XQueryContext context, long sessionHandle) { return ModuleUtils.retrieveObjectFromContextMap(context, MailModule.SESSIONS_CONTEXTVAR, sessionHandle); } /** * Stores a Session in the Context of an XQuery * * @param context The Context of the XQuery to store the Session in * @param session The Session to store * * @return A unique handle representing the Session */ static long storeSession(XQueryContext context, Session session) { return ModuleUtils.storeObjectInContextMap(context, MailModule.SESSIONS_CONTEXTVAR, session); } //*************************************************************************** //* //* Store Methods //* //***************************************************************************/ /** * Retrieves a previously saved Store from the Context of an XQuery * * @param context The Context of the XQuery containing the Store * @param storeHandle The handle of the Store to retrieve from the Context of the XQuery */ static Store retrieveStore(XQueryContext context, long storeHandle) { return ModuleUtils.retrieveObjectFromContextMap(context, MailModule.STORES_CONTEXTVAR, storeHandle); } /** * Saves a Store in the Context of an XQuery * * @param context The Context of the XQuery to save the Store in * @param store The Store to store * * @return A unique handle representing the Store */ static long storeStore(XQueryContext context, Store store) { return ModuleUtils.storeObjectInContextMap(context, MailModule.STORES_CONTEXTVAR, store); } /** * Remove the store from the specified XQueryContext * * @param context The context to remove the store for */ static void removeStore(XQueryContext context, final long storeHandle) { ModuleUtils.modifyContextMap(context, MailModule.STORES_CONTEXTVAR, new ContextMapModifier<Store>(){ @Override public void modify(Map<Long, Store> map) { map.remove(storeHandle); } }); //update the context //context.setXQueryContextVar(MailModule.STORES_CONTEXTVAR, stores); } /** * Closes all the open stores for the specified XQueryContext * * @param context The context to close stores for */ private static void closeAllStores(XQueryContext context) { ModuleUtils.modifyContextMap(context, MailModule.STORES_CONTEXTVAR, new ContextMapEntryModifier<Store>(){ @Override public void modify(Map<Long, Store> map) { super.modify(map); //remove all stores from map map.clear(); } @Override public void modify(Entry<Long, Store> entry) { final Store store = entry.getValue(); try { // close the store store.close(); } catch(MessagingException me) { LOG.warn("Unable to close Mail Store: " + me.getMessage(), me); } } }); // update the context //context.setXQueryContextVar(MailModule.STORES_CONTEXTVAR, stores); } //*************************************************************************** //* //* Folder Methods //* //***************************************************************************/ /** * Retrieves a previously saved Folder from the Context of an XQuery * * @param context The Context of the XQuery containing the Folder * @param folderHandle The handle of the Folder to retrieve from the Context of the XQuery */ static Folder retrieveFolder(XQueryContext context, long folderHandle) { return ModuleUtils.retrieveObjectFromContextMap(context, MailModule.FOLDERS_CONTEXTVAR, folderHandle); } /** * Saves a Folder in the Context of an XQuery * * @param context The Context of the XQuery to save the Folder in * @param folder The Folder to store * * @return A unique handle representing the Store */ static long storeFolder(XQueryContext context, Folder folder) { return ModuleUtils.storeObjectInContextMap(context, MailModule.FOLDERS_CONTEXTVAR, folder); } /** * Remove the folder from the specified XQueryContext * * @param context The context to remove the store for */ static void removeFolder(final XQueryContext context, final long folderHandle) { ModuleUtils.modifyContextMap(context, MailModule.FOLDERS_CONTEXTVAR, new ContextMapModifier<Folder>(){ @Override public void modify(Map<Long, Folder> map) { //remove the message lists for the folder ModuleUtils.modifyContextMap(context, MailModule.FOLDERMSGLISTS_CONTEXTVAR, new ContextMapModifier<Map<Long, Message[]>>(){ @Override public void modify(Map<Long, Map<Long, Message[]>> map) { final Map<Long, Message[]> folderMsgList = map.get(folderHandle); ModuleUtils.modifyContextMap(context, MailModule.MSGLISTS_CONTEXTVAR, new ContextMapModifier<Message[]>(){ @Override public void modify(Map<Long, Message[]> map) { folderMsgList.keySet().forEach(map::remove); } }); //remove the folder message kist map.remove(folderHandle); } }); //remove the folder map.remove(folderHandle); } }); } /** * Closes all the open folders for the specified XQueryContext * * @param context The context to close folders for */ private static void closeAllFolders(XQueryContext context) { ModuleUtils.modifyContextMap(context, MailModule.FOLDERS_CONTEXTVAR, new ContextMapEntryModifier<Folder>(){ @Override public void modify(Map<Long, Folder> map) { super.modify(map); //remove all from the folders map map.clear(); } @Override public void modify(Entry<Long, Folder> entry) { final Folder folder = entry.getValue(); //close the folder try { folder.close(false); } catch(MessagingException me) { LOG.warn( "Unable to close Mail Folder: " + me.getMessage(), me); } } }); // update the context // context.setXQueryContextVar( MailModule.FOLDERS_CONTEXTVAR, folders ); } //*************************************************************************** //* //* Message List Methods //* //***************************************************************************/ /** * Retrieves a previously saved MessageList from the Context of an XQuery * * @param context The Context of the XQuery containing the Message List * @param msgListHandle The handle of the Message List to retrieve from the Context of the XQuery */ static Message[] retrieveMessageList(XQueryContext context, long msgListHandle) { return ModuleUtils.retrieveObjectFromContextMap(context, MailModule.MSGLISTS_CONTEXTVAR, msgListHandle); } /** * Saves a MessageList in the Context of an XQuery * * @param context The Context of the XQuery to save the MessageList in * @param msgList The MessageList to store * * @return A unique handle representing the Store */ static long storeMessageList(XQueryContext context, final Message[] msgList, final long folderHandle) { final long msgListHandle = ModuleUtils.storeObjectInContextMap(context, MailModule.MSGLISTS_CONTEXTVAR, msgList); ModuleUtils.modifyContextMap(context, MailModule.FOLDERMSGLISTS_CONTEXTVAR, new ContextMapModifier<Map<Long, Message[]>>(){ @Override public void modify(Map<Long, Map<Long, Message[]>> map) { Map<Long, Message[]> folderMsgList = map.get(folderHandle); if(folderMsgList == null) { folderMsgList = new HashMap<>(); map.put(folderHandle, folderMsgList); } folderMsgList.put(msgListHandle, msgList); } }); return msgListHandle; } /** * Remove the MessageList from the specified XQueryContext * * @param context The context to remove the MessageList for */ static void removeMessageList(XQueryContext context, final long msgListHandle) { ModuleUtils.modifyContextMap(context, MailModule.MSGLISTS_CONTEXTVAR, new ContextMapModifier<Message[]>(){ @Override public void modify(Map<Long, Message[]> map) { map.remove(msgListHandle); } }); // update the context //context.setXQueryContextVar( MailModule.MSGLISTS_CONTEXTVAR, msgLists ); } /** * Closes all the open MessageLists for the specified XQueryContext * * @param context The context to close MessageLists for */ private static void closeAllMessageLists(XQueryContext context) { ModuleUtils.modifyContextMap(context, MailModule.MSGLISTS_CONTEXTVAR, new ContextMapModifier<Message[]>(){ @Override public void modify(Map<Long, Message[]> map) { map.clear(); } }); // update the context //context.setXQueryContextVar( MailModule.MSGLISTS_CONTEXTVAR, msgLists ); } /** * Resets the Module Context and closes any open mail stores/folders/message lists for the XQueryContext * * @param context The XQueryContext */ @Override public void reset( XQueryContext context ) { // reset the module context super.reset(context); // close any open MessageLists closeAllMessageLists(context); // close any open folders closeAllFolders(context); // close any open stores closeAllStores(context); } }