/*
* eXist Mail Module Extension MessageListFunctions
* 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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import javax.mail.Address;
import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Header;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.search.AndTerm;
import javax.mail.search.BodyTerm;
import javax.mail.search.ComparisonTerm;
import javax.mail.search.FlagTerm;
import javax.mail.search.FromStringTerm;
import javax.mail.search.HeaderTerm;
import javax.mail.search.NotTerm;
import javax.mail.search.OrTerm;
import javax.mail.search.ReceivedDateTerm;
import javax.mail.search.RecipientStringTerm;
import javax.mail.search.SearchTerm;
import javax.mail.search.SentDateTerm;
import javax.mail.search.SubjectTerm;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.exist.dom.QName;
import org.exist.memtree.MemTreeBuilder;
import org.exist.xquery.BasicFunction;
import org.exist.xquery.Cardinality;
import org.exist.xquery.FunctionSignature;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.value.FunctionParameterSequenceType;
import org.exist.xquery.value.FunctionReturnSequenceType;
import org.exist.xquery.value.IntegerValue;
import org.exist.xquery.value.NodeValue;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceType;
import org.exist.xquery.value.Type;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* eXist Mail Module Extension GetMessageList
*
* Get a mail store
*
* @author Andrzej Taramina <andrzej@chaeron.com>
* @serial 2009-03-12
* @version 1.3
*
* @see org.exist.xquery.BasicFunction#BasicFunction(org.exist.xquery.XQueryContext, org.exist.xquery.FunctionSignature)
*/
public class MessageListFunctions extends BasicFunction
{
protected static final Logger logger = Logger.getLogger(MessageListFunctions.class);
public final static FunctionSignature signatures[] = {
new FunctionSignature(
new QName( "get-message-list", MailModule.NAMESPACE_URI, MailModule.PREFIX ),
"Returns a message list of all messages in a folder.",
new SequenceType[]
{
new FunctionParameterSequenceType( "mail-folder-handle", Type.INTEGER, Cardinality.EXACTLY_ONE, "The mail folder handle retrieved from mail:get-mail-folder()" )
},
new FunctionReturnSequenceType( Type.LONG, Cardinality.ZERO_OR_ONE, "an xs:long representing the message list handle." )
),
new FunctionSignature(
new QName( "search-message-list", MailModule.NAMESPACE_URI, MailModule.PREFIX ),
"Searches messages in a folder. " +
"Search terms are of the form <searchTerm type=\"xxx\">...</searchTerm>. Valid types include: not, and, or, from, subject, body, recipient, header, flag, sent, received. " +
"<searchTerm type=\"not\"> requires a single nested child search term. <searchTerm type=\"and\"> and <searchTerm type=\"or\"> must have one or more nested child search terms. " +
"<searchTerm type=\"from\" pattern=\"pat\">, <searchTerm type=\"subject\" pattern=\"pat\"> and <searchTerm type=\"body\" pattern=\"pat\"> require a pattern attribute and will search for a substring that matches the pattern. " +
"<searchTerm type=\"recipient\" pattern=\"pat\" recipientType=\"to|cc|bcc\"> requires pattern and recipientType attributes. " +
"<searchTerm type=\"header\" pattern=\"pat\" name=\"Content-Type\"> requires pattern and name attributes. " +
"<searchTerm type=\"flag\" flag=\"answered|deleted|draft|recent|seen\" value=\"true|false\"> requires flag and value attributes. " +
"<searchTerm type=\"sent\" comparison=\"eq|gt|ge|lt|le|ne\" format=\"format\" date=\"date\"> and <searchTerm type=\"received\" comparison=\"eq|gt|ge|lt|le|ne\" format=\"format\" date=\"date\"> require comparison, format and date attributes. " +
"The format string should conform to Java SimpleDateFormat specifications and the date string must conform to the specified format string.",
new SequenceType[]
{
new FunctionParameterSequenceType( "mail-folder-handle", Type.INTEGER, Cardinality.EXACTLY_ONE, "The mail folder handle retrieved from mail:get-mail-folder()" ),
new FunctionParameterSequenceType( "search-parameters", Type.ELEMENT, Cardinality.EXACTLY_ONE, "The xml fragment defining the search terms" )
},
new FunctionReturnSequenceType( Type.LONG, Cardinality.ZERO_OR_ONE, "an xs:long representing the message list handle." )
),
new FunctionSignature(
new QName( "get-message-list-as-xml", MailModule.NAMESPACE_URI, MailModule.PREFIX ),
"Returns a message list of all messages in a folder as XML. If there are no messages in the list, an empty sequence will be returned",
new SequenceType[]
{
new FunctionParameterSequenceType( "message-list-handle", Type.INTEGER, Cardinality.EXACTLY_ONE, "The message list handle retrieved from mail:get-message-list() or mail:search-message-list()" ),
new FunctionParameterSequenceType( "include-headers", Type.BOOLEAN, Cardinality.EXACTLY_ONE, "A boolean specifying whether to include message headers" )
},
new FunctionReturnSequenceType( Type.ELEMENT, Cardinality.ZERO_OR_ONE, "the list of all messages in a folder as XML" )
),
new FunctionSignature(
new QName( "close-message-list", MailModule.NAMESPACE_URI, MailModule.PREFIX ),
"Closes a message list.",
new SequenceType[]
{
new FunctionParameterSequenceType( "message-list-handle", Type.INTEGER, Cardinality.EXACTLY_ONE, "The message list handle retrieved from mail:get-message-list() or mail:search-message-list()" )
},
new SequenceType( Type.ITEM, Cardinality.EMPTY )
)
};
private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
private static final String PREFETCH_HEADERS[] = {
"Return-Path",
"Delivered-To",
"Received",
"Date",
"From",
"To",
"Message-ID",
"Subject",
"MIME-Version",
"Content-Type",
"Content-Transfer-Encoding",
"X-Mailer",
"X-Priority"
};
/**
* MessageListFunctions Constructor
*
* @param context The Context of the calling XQuery
*/
public MessageListFunctions( XQueryContext context, FunctionSignature signature )
{
super( context, signature );
}
/**
* evaluate the call to the xquery get-message-list function,
* it is really the main entry point of this class
*
* @param args arguments from the get-message-list() function call
* @param contextSequence the Context Sequence to operate on (not used here internally!)
* @return A sequence representing the result of the get-message-list() function call
*
* @see org.exist.xquery.BasicFunction#eval(org.exist.xquery.value.Sequence[], org.exist.xquery.value.Sequence)
*/
public Sequence eval( Sequence[] args, Sequence contextSequence ) throws XPathException
{
if( isCalledAs( "get-message-list" ) ) {
Sequence messageList = getMessageList( args, contextSequence );
return messageList;
} else if( isCalledAs( "search-message-list" ) ) {
Sequence searchMessageList = searchMessageList( args, contextSequence );
return searchMessageList;
} else if( isCalledAs( "get-message-list-as-xml" ) ) {
Sequence messageListAsXML = getMessageListAsXML( args, contextSequence );
return messageListAsXML;
} else if( isCalledAs( "close-message-list" ) ) {
Sequence closeMessageList = closeMessageList( args, contextSequence );
return closeMessageList;
}
throw( new XPathException(this, "Invalid function name" ) );
}
//***************************************************************************
//*
//* Function Implementation Methods
//*
//***************************************************************************/
private Sequence getMessageList( Sequence[] args, Sequence contextSequence ) throws XPathException
{
Message[] msgList;
// was a folder handle specified?
if( args[0].isEmpty() ) {
throw( new XPathException(this, "Folder handle not specified" ) );
}
// get the Folder
long folderHandle = ((IntegerValue)args[0].itemAt(0)).getLong();
Folder folder= MailModule.retrieveFolder( context, folderHandle );
if( folder == null ) {
throw( new XPathException(this, "Invalid Folder handle specified" ) );
}
try {
msgList = folder.getMessages();
prefetchMessages( folder, msgList );
}
catch( MessagingException me ) {
throw( new XPathException(this, "Failed to get mail list", me ) );
}
// save the message list and return the handle of the message list
return( new IntegerValue( MailModule.storeMessageList( context, msgList, folderHandle ) ) );
}
private Sequence searchMessageList( Sequence[] args, Sequence contextSequence ) throws XPathException
{
Message[] msgList;
// was a folder handle specified?
if( args[0].isEmpty() || args[1].isEmpty() ) {
throw( new XPathException(this, "Folder handle or Search Terms not specified" ) );
}
// get the Folder
long folderHandle = ((IntegerValue)args[0].itemAt(0)).getLong();
Folder folder= MailModule.retrieveFolder( context, folderHandle );
if( folder == null ) {
throw( new XPathException(this, "Invalid Folder handle specified" ) );
}
Node searchTermsXML = ( (NodeValue)args[1].itemAt( 0 ) ).getNode();
try {
msgList = folder.search( parseSearchTerms( searchTermsXML ) );
prefetchMessages( folder, msgList );
}
catch( MessagingException me ) {
throw( new XPathException(this, "Failed to get mail list", me ) );
}
// save the message list and return the handle of the message list
return( new IntegerValue( MailModule.storeMessageList( context, msgList, folderHandle ) ) );
}
private void prefetchMessages( Folder folder, Message[] msgList ) throws MessagingException
{
// Prefetch all the key information and headers
FetchProfile fp = new FetchProfile();
fp.add( FetchProfile.Item.ENVELOPE );
for (String PREFETCH_HEADER : PREFETCH_HEADERS) {
fp.add(PREFETCH_HEADER);
}
folder.fetch( msgList, fp );
}
private Sequence getMessageListAsXML( Sequence[] args, Sequence contextSequence ) throws XPathException
{
Message[] msgList;
Sequence ret = Sequence.EMPTY_SEQUENCE;
// was a msgList handle specified?
if( args[0].isEmpty() ) {
throw( new XPathException(this, "Message List handle not specified" ) );
}
// get the MessageList
long msgListHandle = ((IntegerValue)args[0].itemAt(0)).getLong();
msgList = MailModule.retrieveMessageList( context, msgListHandle );
if( msgList == null ) {
throw( new XPathException(this, "Invalid Message List handle specified" ) );
}
if( msgList.length > 0 ) {
boolean includeHeaders = args[1].effectiveBooleanValue();
MemTreeBuilder builder = context.getDocumentBuilder();
builder.startDocument();
builder.startElement( new QName( "messages", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "count", null, null ), String.valueOf( msgList.length ) );
try {
for( int i = 0; i < msgList.length; i++ ) {
Message message = msgList[ i ];
builder.startElement( new QName( "message", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "number", null, null ), String.valueOf(message.getMessageNumber()) );
// Sent Date
if( message.getSentDate() != null ) {
builder.startElement( new QName( "sent", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.characters( formatDate( message.getSentDate() ) );
builder.endElement();
}
// Received Date
if( message.getReceivedDate() != null ) {
builder.startElement( new QName( "received", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.characters( formatDate( message.getReceivedDate() ) );
builder.endElement();
}
// From
if( message.getFrom() != null ) {
builder.startElement( new QName( "from", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.characters( message.getFrom()[0].toString() );
builder.endElement();
}
// Recipients
builder.startElement( new QName( "recipients", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
// To Recipients
Address[] toAddresses = message.getRecipients( Message.RecipientType.TO );
if( toAddresses != null ) {
for (Address to : toAddresses) {
builder.startElement( new QName( "recipient", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "type", null, null ), "to" );
builder.characters(to.toString());
builder.endElement();
}
}
// cc Recipients
Address[] ccAddresses = message.getRecipients( Message.RecipientType.CC );
if( ccAddresses != null ) {
for (Address ccAddress : ccAddresses) {
builder.startElement( new QName( "recipient", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "type", null, null ), "cc" );
builder.characters(ccAddress.toString());
builder.endElement();
}
}
// bcc Recipients
Address[] bccAddresses = message.getRecipients( Message.RecipientType.BCC );
if( bccAddresses != null ) {
for (Address bccAddress : bccAddresses) {
builder.startElement( new QName( "recipient", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "type", null, null ), "bcc" );
builder.characters(bccAddress.toString());
builder.endElement();
}
}
builder.endElement();
// Flags
Flags flags = message.getFlags();
Flags.Flag[] systemFlags = flags.getSystemFlags();
String[] userFlags = flags.getUserFlags();
if( systemFlags.length > 0 || userFlags.length > 0 ) {
builder.startElement( new QName( "flags", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
for (Flags.Flag systemFlag : systemFlags) {
if (systemFlag == Flags.Flag.ANSWERED) {
builder.startElement( new QName( "flag", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "type", null, null ), "answered" );
builder.endElement();
} else if (systemFlag == Flags.Flag.DELETED) {
builder.startElement( new QName( "flag", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "type", null, null ), "deleted" );
builder.endElement();
} else if (systemFlag == Flags.Flag.DRAFT) {
builder.startElement( new QName( "flag", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "type", null, null ), "draft" );
builder.endElement();
} else if (systemFlag == Flags.Flag.FLAGGED) {
builder.startElement( new QName( "flag", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "type", null, null ), "flagged" );
builder.endElement();
} else if (systemFlag == Flags.Flag.RECENT) {
builder.startElement( new QName( "flag", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "type", null, null ), "recent" );
builder.endElement();
} else if (systemFlag == Flags.Flag.SEEN) {
builder.startElement( new QName( "flag", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "type", null, null ), "seen" );
builder.endElement();
}
}
for (String userFlag : userFlags) {
builder.startElement( new QName( "flag", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "type", null, null ), "user" );
builder.addAttribute(new QName( "value", null, null ), userFlag);
builder.endElement();
}
builder.endElement();
}
// Headers
if( includeHeaders ) {
Enumeration headers = message.getAllHeaders();
if( headers.hasMoreElements() ) {
builder.startElement( new QName( "headers", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
while( headers.hasMoreElements() ) {
Header header = (Header)headers.nextElement();
builder.startElement( new QName( "header", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.addAttribute( new QName( "name", null, null ), header.getName() );
builder.addAttribute( new QName( "value", null, null ), header.getValue() );
builder.endElement();
}
builder.endElement();
}
}
// Subject
builder.startElement( new QName( "subject", MailModule.NAMESPACE_URI, MailModule.PREFIX ), null );
builder.characters( message.getSubject() );
builder.endElement();
builder.endElement();
}
}
catch( MessagingException me ) {
throw( new XPathException(this, "Failed to retrieve messages from list", me ) );
}
builder.endElement();
ret = (NodeValue)builder.getDocument().getDocumentElement();
}
return( ret );
}
private String formatDate( Date date )
{
String formatted = "";
SimpleDateFormat sdf = new SimpleDateFormat( DATE_FORMAT );
String temp = sdf.format( date );
formatted = temp.substring( 0, temp.length() - 2 ) + ":" + temp.substring( temp.length() - 2 );
return( formatted );
}
private Sequence closeMessageList( Sequence[] args, Sequence contextSequence ) throws XPathException
{
// was a msgList handle specified?
if( args[0].isEmpty() ) {
throw( new XPathException(this, "Message List handle not specified" ) );
}
// get the msgList
long msgListHandle = ((IntegerValue)args[0].itemAt(0)).getLong();
MailModule.removeMessageList( context, msgListHandle );
return( Sequence.EMPTY_SEQUENCE );
}
//***************************************************************************
//*
//* Search Term Methods
//*
//***************************************************************************/
private SearchTerm parseSearchTerms( Node terms ) throws XPathException
{
SearchTerm st = null;
if( terms.getNodeType() == Node.ELEMENT_NODE && terms.getLocalName().equalsIgnoreCase( "searchTerm" ) ) {
String type = ((Element)terms).getAttribute( "type" );
if( type != null ) {
if( type.equalsIgnoreCase( "not" ) ) {
st = new NotTerm( parseChildSearchTerm( terms ) );
} else if( type.equalsIgnoreCase( "and" ) ) {
st = new AndTerm( parseChildSearchTerms( terms ) );
} else if( type.equalsIgnoreCase( "or" ) ) {
st = new OrTerm( parseChildSearchTerms( terms ) );
} else if( type.equalsIgnoreCase( "from" ) ) {
st = parseFromTerm( terms );
} else if( type.equalsIgnoreCase( "subject" ) ) {
st = parseSubjectTerm( terms );
} else if( type.equalsIgnoreCase( "body" ) ) {
st = parseBodyTerm( terms );
} else if( type.equalsIgnoreCase( "to" ) || type.equalsIgnoreCase( "recipient" ) ) {
st = parseRecipientTerm( terms );
} else if( type.equalsIgnoreCase( "header" ) ) {
st = parseHeaderTerm( terms );
} else if( type.equalsIgnoreCase( "flag" ) ) {
st = parseFlagTerm( terms );
} else if( type.equalsIgnoreCase( "sent" ) ) {
st = parseSentDateTerm( terms );
} else if( type.equalsIgnoreCase( "received" ) ) {
st = parseReceivedDateTerm( terms );
} else {
throw( new XPathException(this, "Invalid Search Term type specified: " + type ) );
}
} else {
throw( new XPathException(this, "Invalid Search Term type specified: null" ) );
}
}
if( st == null ) {
throw( new XPathException(this, "Invalid Search Terms specified" ) );
}
return( st );
}
private SearchTerm parseChildSearchTerm( Node terms ) throws XPathException
{
// Parent only allows a single child search term
SearchTerm st = null;
NodeList children = terms.getChildNodes();
if( children.getLength() == 1 ) {
Node child = children.item( 0 );
st = parseSearchTerms( child );
} else {
throw( new XPathException(this, "Only one child term is allowed for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( st );
}
private SearchTerm[] parseChildSearchTerms( Node terms ) throws XPathException
{
// Parent allows multiple child search terms
ArrayList<SearchTerm> st = new ArrayList<SearchTerm>();
NodeList children = terms.getChildNodes();
if( children.getLength() > 0 ) {
for( int i = 0; i < children.getLength(); i++ ) {
Node child = children.item( i );
st.add( parseSearchTerms( child ) );
}
} else {
throw( new XPathException(this, "At least one child term is required for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( (SearchTerm[])st.toArray( new SearchTerm[] {} ) );
}
private SearchTerm parseFromTerm( Node terms ) throws XPathException
{
SearchTerm st = null;
String pattern = ((Element)terms).getAttribute( "pattern" );
if( pattern != null && pattern.length() > 0 ) {
st = new FromStringTerm( pattern );
} else {
throw( new XPathException(this, "Pattern attribute must be specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( st );
}
private SearchTerm parseSubjectTerm( Node terms ) throws XPathException
{
SearchTerm st = null;
String pattern = ((Element)terms).getAttribute( "pattern" );
if( pattern != null && pattern.length() > 0 ) {
st = new SubjectTerm( pattern );
} else {
throw( new XPathException(this, "Pattern attribute must be specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( st );
}
private SearchTerm parseBodyTerm( Node terms ) throws XPathException
{
SearchTerm st = null;
String pattern = ((Element)terms).getAttribute( "pattern" );
if( pattern != null && pattern.length() > 0 ) {
st = new BodyTerm( pattern );
} else {
throw( new XPathException(this, "Pattern attribute must be specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( st );
}
private SearchTerm parseRecipientTerm( Node terms ) throws XPathException
{
SearchTerm st = null;
String pattern = ((Element)terms).getAttribute( "pattern" );
String type = ((Element)terms).getAttribute( "recipientType" );
if( StringUtils.isEmpty(type) ) {
throw( new XPathException(this, "recipientType not specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
if( pattern != null && pattern.length() > 0 ) {
Message.RecipientType rtype = null;
if( type.equalsIgnoreCase( "to" ) ) {
rtype = Message.RecipientType.TO;
} else if( type.equalsIgnoreCase( "cc" ) ) {
rtype = Message.RecipientType.CC;
} else if( type.equalsIgnoreCase( "bcc" ) ) {
rtype = Message.RecipientType.BCC;
} else {
throw( new XPathException(this, "Invalid recipientType: " + type + ", for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
st = new RecipientStringTerm( rtype, pattern );
} else {
throw( new XPathException(this, "Pattern attribute must be specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( st );
}
private SearchTerm parseHeaderTerm( Node terms ) throws XPathException
{
SearchTerm st = null;
String pattern = ((Element)terms).getAttribute( "pattern" );
String name = ((Element)terms).getAttribute( "name" );
if( StringUtils.isEmpty(name) ) {
throw( new XPathException(this, "name not specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
if( pattern != null && pattern.length() > 0 ) {
st = new HeaderTerm( name, pattern );
} else {
throw( new XPathException(this, "pattern attribute must be specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( st );
}
private SearchTerm parseFlagTerm( Node terms ) throws XPathException
{
SearchTerm st = null;
String flag = ((Element)terms).getAttribute( "flag" );
String value = ((Element)terms).getAttribute( "value" );
if( StringUtils.isEmpty(value) ) {
throw( new XPathException(this, "value not specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
if( flag != null && flag.length() > 0 ) {
Flags flags = null;
if( flag.equalsIgnoreCase( "answered" ) ) {
flags = new Flags( Flags.Flag.ANSWERED );
} else if( flag.equalsIgnoreCase( "deleted" ) ) {
flags = new Flags( Flags.Flag.DELETED );
} else if( flag.equalsIgnoreCase( "draft" ) ) {
flags = new Flags( Flags.Flag.DRAFT );
} else if( flag.equalsIgnoreCase( "recent" ) ) {
flags = new Flags( Flags.Flag.RECENT );
} else if( flag.equalsIgnoreCase( "seen" ) ) {
flags = new Flags( Flags.Flag.SEEN );
} else {
throw( new XPathException(this, "Invalid flag: " + flag + ", for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
st = new FlagTerm( flags, value.equalsIgnoreCase( "true" ) );
} else {
throw( new XPathException(this, "flag attribute must be specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( st );
}
private SearchTerm parseSentDateTerm( Node terms ) throws XPathException
{
SearchTerm st = null;
String value = ((Element)terms).getAttribute( "date" );
String format = ((Element)terms).getAttribute( "format" );
if( StringUtils.isEmpty(value) ) {
throw( new XPathException(this, "value not specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
if( StringUtils.isEmpty(format) ) {
throw( new XPathException(this, "format not specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
int cp = parseComparisonAttribute( terms );
try {
SimpleDateFormat sdf = new SimpleDateFormat( format );
Date date = sdf.parse( value );
st = new SentDateTerm( cp, date );
}
catch( ParseException pe ) {
throw( new XPathException(this, "Cannot parse date value: " + value + ", using format: " + format + ", for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( st );
}
private SearchTerm parseReceivedDateTerm( Node terms ) throws XPathException
{
SearchTerm st = null;
String value = ((Element)terms).getAttribute( "date" );
String format = ((Element)terms).getAttribute( "format" );
if( StringUtils.isEmpty(value) ) {
throw( new XPathException(this, "value not specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
if( StringUtils.isEmpty(format) ) {
throw( new XPathException(this, "format not specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
int cp = parseComparisonAttribute( terms );
try {
SimpleDateFormat sdf = new SimpleDateFormat( format );
Date date = sdf.parse( value );
st = new ReceivedDateTerm( cp, date );
}
catch( ParseException pe ) {
throw( new XPathException(this, "Cannot parse date value: " + value + ", using format: " + format + ", for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( st );
}
private int parseComparisonAttribute( Node terms ) throws XPathException
{
int cp = ComparisonTerm.EQ;
String comp = ((Element)terms).getAttribute( "comparison" );
if( comp != null && comp.length() > 0 ) {
if( comp.equalsIgnoreCase( "eq" ) ) {
cp = ComparisonTerm.EQ;
} else if( comp.equalsIgnoreCase( "ge" ) ) {
cp = ComparisonTerm.GE;
} else if( comp.equalsIgnoreCase( "gt" ) ) {
cp = ComparisonTerm.GT;
} else if( comp.equalsIgnoreCase( "le" ) ) {
cp = ComparisonTerm.LE;
} else if( comp.equalsIgnoreCase( "lt" ) ) {
cp = ComparisonTerm.LT;
} else if( comp.equalsIgnoreCase( "ne" ) ) {
cp = ComparisonTerm.NE;
} else {
throw( new XPathException(this, "Invalid comparison: " + comp + ", for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
} else {
throw( new XPathException(this, "comparison attribute must be specified for term with type: " + ((Element)terms).getAttribute( "type" ) ) );
}
return( cp );
}
}