1
0
mirror of https://github.com/moparisthebest/davmail synced 2024-12-13 11:12:22 -05:00

EWS: refactor IMAP search, use Conditions classes instead of string search filder

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1083 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2010-06-08 22:21:53 +00:00
parent aab4709956
commit 51936619e3
6 changed files with 644 additions and 237 deletions

View File

@ -109,6 +109,7 @@ public abstract class ExchangeSession {
protected static final String UNSENT = "Unsent Messages";
protected static final Namespace EMPTY = Namespace.getNamespace("");
protected static final Namespace DAV = Namespace.getNamespace("DAV:");
protected static final Namespace URN_SCHEMAS_HTTPMAIL = Namespace.getNamespace("urn:schemas:httpmail:");
protected static final Namespace SCHEMAS_EXCHANGE = Namespace.getNamespace("http://schemas.microsoft.com/exchange/");
@ -124,18 +125,6 @@ public abstract class ExchangeSession {
EVENT_REQUEST_PROPERTIES.add(DavPropertyName.create("contentclass", DAV));
}
protected static final DavPropertyNameSet WELL_KNOWN_FOLDERS = new DavPropertyNameSet();
static {
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("inbox", URN_SCHEMAS_HTTPMAIL));
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("deleteditems", URN_SCHEMAS_HTTPMAIL));
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("sentitems", URN_SCHEMAS_HTTPMAIL));
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("sendmsg", URN_SCHEMAS_HTTPMAIL));
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("drafts", URN_SCHEMAS_HTTPMAIL));
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("calendar", URN_SCHEMAS_HTTPMAIL));
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("contacts", URN_SCHEMAS_HTTPMAIL));
WELL_KNOWN_FOLDERS.add(DavPropertyName.create("outbox", URN_SCHEMAS_HTTPMAIL));
}
protected static final DavPropertyNameSet DISPLAY_NAME = new DavPropertyNameSet();
@ -605,15 +594,6 @@ public abstract class ExchangeSession {
}
}
protected String getURIPropertyIfExists(DavPropertySet properties, String name, Namespace namespace) throws URIException {
DavProperty property = properties.get(name, namespace);
if (property == null) {
return null;
} else {
return URIUtil.decode((String) property.getValue());
}
}
/**
* Create message in specified folder.
* Will overwrite an existing message with same subject in the same folder
@ -672,40 +652,6 @@ public abstract class ExchangeSession {
}
}
protected Message buildMessage(MultiStatusResponse responseEntity) throws URIException {
Message message = new Message();
message.messageUrl = URIUtil.decode(responseEntity.getHref());
DavPropertySet properties = responseEntity.getProperties(HttpStatus.SC_OK);
message.permanentUrl = getPropertyIfExists(properties, "permanenturl", SCHEMAS_EXCHANGE);
message.size = getIntPropertyIfExists(properties, "x0e080003", SCHEMAS_MAPI_PROPTAG);
message.uid = getPropertyIfExists(properties, "uid", DAV);
message.imapUid = getLongPropertyIfExists(properties, "x0e230003", SCHEMAS_MAPI_PROPTAG);
message.read = "1".equals(getPropertyIfExists(properties, "read", URN_SCHEMAS_HTTPMAIL));
message.junk = "1".equals(getPropertyIfExists(properties, "x10830003", SCHEMAS_MAPI_PROPTAG));
message.flagged = "2".equals(getPropertyIfExists(properties, "x10900003", SCHEMAS_MAPI_PROPTAG));
message.draft = "9".equals(getPropertyIfExists(properties, "x0E070003", SCHEMAS_MAPI_PROPTAG));
String x10810003 = getPropertyIfExists(properties, "x10810003", SCHEMAS_MAPI_PROPTAG);
message.answered = "102".equals(x10810003) || "103".equals(x10810003);
message.forwarded = "104".equals(x10810003);
message.date = getPropertyIfExists(properties, "date", Namespace.getNamespace("urn:schemas:mailheader:"));
message.deleted = "1".equals(getPropertyIfExists(properties, "deleted", Namespace.getNamespace("")));
if (LOGGER.isDebugEnabled()) {
StringBuilder buffer = new StringBuilder();
buffer.append("Message");
if (message.imapUid != 0) {
buffer.append(" IMAP uid: ").append(message.imapUid);
}
if (message.uid != null) {
buffer.append(" uid: ").append(message.uid);
}
buffer.append(" href: ").append(responseEntity.getHref()).append(" permanenturl:").append(message.permanentUrl);
LOGGER.debug(buffer.toString());
}
return message;
}
protected List<DavProperty> buildProperties(Map<String, String> properties) {
ArrayList<DavProperty> list = new ArrayList<DavProperty>();
for (Map.Entry<String, String> entry : properties.entrySet()) {
@ -763,6 +709,13 @@ public abstract class ExchangeSession {
}
}
protected static final List<String> POP_MESSAGE_ATTRIBUTES = new ArrayList<String>();
static {
POP_MESSAGE_ATTRIBUTES.add("uid");
POP_MESSAGE_ATTRIBUTES.add("messageSize");
}
/**
* Return folder message list with id and size only (for POP3 listener).
*
@ -771,24 +724,46 @@ public abstract class ExchangeSession {
* @throws IOException on error
*/
public MessageList getAllMessageUidAndSize(String folderName) throws IOException {
return searchMessages(folderName, "\"DAV:uid\", \"http://schemas.microsoft.com/mapi/proptag/x0e080003\"", "");
return searchMessages(folderName, POP_MESSAGE_ATTRIBUTES, null);
}
protected static final List<String> IMAP_MESSAGE_ATTRIBUTES = new ArrayList<String>();
static {
IMAP_MESSAGE_ATTRIBUTES.add("uid");
IMAP_MESSAGE_ATTRIBUTES.add("messageSize");
IMAP_MESSAGE_ATTRIBUTES.add("imapUid");
IMAP_MESSAGE_ATTRIBUTES.add("junk");
IMAP_MESSAGE_ATTRIBUTES.add("flagStatus");
IMAP_MESSAGE_ATTRIBUTES.add("messageFlags");
IMAP_MESSAGE_ATTRIBUTES.add("lastVerbExecuted");
IMAP_MESSAGE_ATTRIBUTES.add("read");
IMAP_MESSAGE_ATTRIBUTES.add("deleted");
IMAP_MESSAGE_ATTRIBUTES.add("date");
}
/**
* Get all folder messages.
*
* @param folderName Exchange folder name
* @param condition search filter
* @return message list
* @throws IOException on error
*/
public MessageList searchMessages(String folderName) throws IOException {
return searchMessages(folderName, IMAP_MESSAGE_ATTRIBUTES, null);
}
/**
* Search folder for messages matching conditions, with attributes needed by IMAP listener.
*
* @param folderName Exchange folder name
* @param conditions conditions string in Exchange SQL syntax
* @param condition search filter
* @return message list
* @throws IOException on error
*/
public MessageList searchMessages(String folderName, String conditions) throws IOException {
return searchMessages(folderName, "\"DAV:uid\", \"http://schemas.microsoft.com/mapi/proptag/x0e080003\"" +
" ,\"http://schemas.microsoft.com/mapi/proptag/x0e230003\"" +
" ,\"http://schemas.microsoft.com/mapi/proptag/x10830003\", \"http://schemas.microsoft.com/mapi/proptag/x10900003\"" +
" ,\"http://schemas.microsoft.com/mapi/proptag/x0E070003\", \"http://schemas.microsoft.com/mapi/proptag/x10810003\"" +
" , \"urn:schemas:httpmail:read\" " +
" ,\"http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/0x8570\" as deleted, \"urn:schemas:mailheader:date\"", conditions);
public MessageList searchMessages(String folderName, Condition condition) throws IOException {
return searchMessages(folderName, IMAP_MESSAGE_ATTRIBUTES, condition);
}
/**
@ -800,41 +775,17 @@ public abstract class ExchangeSession {
* @return message list
* @throws IOException on error
*/
public MessageList searchMessages(String folderName, String attributes, String conditions) throws IOException {
String folderUrl = getFolderPath(folderName);
MessageList messages = new MessageList();
StringBuilder searchRequest = new StringBuilder();
searchRequest.append("Select \"http://schemas.microsoft.com/exchange/permanenturl\"");
if (attributes != null && attributes.length() > 0) {
searchRequest.append(',').append(attributes);
}
searchRequest.append(" FROM Scope('SHALLOW TRAVERSAL OF \"").append(folderUrl).append("\"')\n")
.append(" WHERE \"DAV:ishidden\" = False AND \"DAV:isfolder\" = False\n");
if (conditions != null) {
searchRequest.append(conditions);
}
searchRequest.append(" ORDER BY \"urn:schemas:httpmail:date\" ASC");
MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeSearchMethod(
httpClient, URIUtil.encodePath(folderUrl), searchRequest.toString());
for (MultiStatusResponse response : responses) {
Message message = buildMessage(response);
message.messageList = messages;
messages.add(message);
}
Collections.sort(messages);
return messages;
}
public abstract MessageList searchMessages(String folderName, List<String> attributes, Condition condition) throws IOException;
protected enum Operator {
Or, And, Not, IsEqualTo
Or, And, Not, IsEqualTo, Like, IsGreaterThan, IsGreaterThanOrEqualTo, IsLessThan, IsNull, IsTrue, IsFalse
}
protected abstract static class Condition {
public abstract static class Condition {
public abstract void appendTo(StringBuilder buffer);
}
protected abstract static class AttributeCondition extends Condition {
public abstract static class AttributeCondition extends Condition {
protected String attributeName;
protected Operator operator;
protected String value;
@ -846,17 +797,23 @@ public abstract class ExchangeSession {
}
}
protected abstract static class MultiCondition extends Condition {
public abstract static class MultiCondition extends Condition {
protected Operator operator;
protected Condition[] conditions;
protected List<Condition> conditions;
protected MultiCondition(Operator operator, Condition... conditions) {
this.operator = operator;
this.conditions = conditions;
this.conditions = Arrays.asList(conditions);
}
public void append(Condition condition) {
if (condition != null) {
conditions.add(condition);
}
}
}
protected abstract static class NotCondition extends Condition {
public abstract static class NotCondition extends Condition {
protected Condition condition;
protected NotCondition(Condition condition) {
@ -864,24 +821,40 @@ public abstract class ExchangeSession {
}
}
protected abstract static class IsNullCondition extends Condition {
protected String attributeName;
public abstract static class MonoCondition extends Condition {
protected String attributeName;
protected Operator operator;
protected IsNullCondition(String attributeName) {
protected MonoCondition(String attributeName, Operator operator) {
this.attributeName = attributeName;
this.operator = operator;
}
}
public abstract Condition and(Condition... condition);
public abstract MultiCondition and(Condition... condition);
public abstract Condition or(Condition... condition);
public abstract MultiCondition or(Condition... condition);
public abstract Condition not(Condition condition);
public abstract Condition equals(String attributeName, String value);
public abstract Condition headerEquals(String headerName, String value);
public abstract Condition gte(String attributeName, String value);
public abstract Condition gt(String attributeName, String value);
public abstract Condition lt(String attributeName, String value);
public abstract Condition like(String attributeName, String value);
public abstract Condition isNull(String attributeName);
public abstract Condition isTrue(String attributeName);
public abstract Condition isFalse(String attributeName);
/**
* Search mail and generic folders under given folder.
* Exclude calendar and contacts folders
@ -1288,19 +1261,19 @@ public abstract class ExchangeSession {
* @throws IOException on error
*/
public void loadMessages() throws IOException {
messages = ExchangeSession.this.searchMessages(folderPath, "");
messages = ExchangeSession.this.searchMessages(folderPath, null);
fixUids(messages);
}
/**
* Search messages in folder matching query.
*
* @param query search query
* @param condition search query
* @return message list
* @throws IOException on error
*/
public MessageList searchMessages(String query) throws IOException {
MessageList localMessages = ExchangeSession.this.searchMessages(folderName, query);
public MessageList searchMessages(Condition condition) throws IOException {
MessageList localMessages = ExchangeSession.this.searchMessages(folderName, condition);
fixUids(localMessages);
return localMessages;
}
@ -1406,23 +1379,23 @@ public abstract class ExchangeSession {
/**
* enclosing message list
*/
protected MessageList messageList;
public MessageList messageList;
/**
* Message url.
*/
protected String messageUrl;
public String messageUrl;
/**
* Message permanent url (does not change on message move).
*/
protected String permanentUrl;
public String permanentUrl;
/**
* Message uid.
*/
protected String uid;
public String uid;
/**
* Message IMAP uid, unique in folder (x0e230003).
*/
protected long imapUid;
public long imapUid;
/**
* MAPI message size.
*/
@ -3011,7 +2984,7 @@ public abstract class ExchangeSession {
// failover for Exchange 2007 plus encoding issue
String decodedEventName = convertItemNameToEML(itemName).replaceAll("_xF8FF_", "/").replaceAll("_x003F_", "?").replaceAll("'", "''");
LOGGER.debug("Item not found at " + itemPath + ", search by displayname: '" + decodedEventName + '\'');
ExchangeSession.MessageList messages = searchMessages(folderPath, " AND \"DAV:displayname\"='" + decodedEventName + '\'');
ExchangeSession.MessageList messages = searchMessages(folderPath, equals("displayname", decodedEventName));
if (!messages.isEmpty()) {
item = getItem(messages.get(0).getPermanentUrl());
} else {

View File

@ -18,10 +18,12 @@
*/
package davmail.exchange.dav;
import davmail.BundleMessage;
import davmail.exception.DavMailAuthenticationException;
import davmail.exception.DavMailException;
import davmail.exchange.ExchangeSession;
import davmail.http.DavGatewayHttpClientFacade;
import davmail.ui.tray.DavGatewayTray;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.URI;
@ -29,6 +31,9 @@ import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
import org.apache.jackrabbit.webdav.property.DavProperty;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
import org.apache.jackrabbit.webdav.property.DavPropertySet;
import org.apache.jackrabbit.webdav.xml.Namespace;
@ -36,16 +41,25 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* Webdav Exchange adapter.
* Compatible with Exchange 2003 and 2007 with webdav available.
*/
public class DavExchangeSession extends ExchangeSession {
protected static final DavPropertyNameSet WELL_KNOWN_FOLDERS = new DavPropertyNameSet();
static {
WELL_KNOWN_FOLDERS.add(Field.get("inbox").davPropertyName);
WELL_KNOWN_FOLDERS.add(Field.get("deleteditems").davPropertyName);
WELL_KNOWN_FOLDERS.add(Field.get("sentitems").davPropertyName);
WELL_KNOWN_FOLDERS.add(Field.get("sendmsg").davPropertyName);
WELL_KNOWN_FOLDERS.add(Field.get("drafts").davPropertyName);
WELL_KNOWN_FOLDERS.add(Field.get("calendar").davPropertyName);
WELL_KNOWN_FOLDERS.add(Field.get("contacts").davPropertyName);
WELL_KNOWN_FOLDERS.add(Field.get("outbox").davPropertyName);
}
/**
* @inheritDoc
@ -109,6 +123,15 @@ public class DavExchangeSession extends ExchangeSession {
}
}
protected String getURIPropertyIfExists(DavPropertySet properties, String alias) throws URIException {
DavProperty property = properties.get(Field.get(alias).davPropertyName);
if (property == null) {
return null;
} else {
return URIUtil.decode((String) property.getValue());
}
}
protected void getWellKnownFolders() throws DavMailException {
// Retrieve well known URLs
MultiStatusResponse[] responses;
@ -119,14 +142,14 @@ public class DavExchangeSession extends ExchangeSession {
throw new DavMailException("EXCEPTION_UNABLE_TO_GET_MAIL_FOLDER", mailPath);
}
DavPropertySet properties = responses[0].getProperties(HttpStatus.SC_OK);
inboxUrl = getURIPropertyIfExists(properties, "inbox", URN_SCHEMAS_HTTPMAIL);
deleteditemsUrl = getURIPropertyIfExists(properties, "deleteditems", URN_SCHEMAS_HTTPMAIL);
sentitemsUrl = getURIPropertyIfExists(properties, "sentitems", URN_SCHEMAS_HTTPMAIL);
sendmsgUrl = getURIPropertyIfExists(properties, "sendmsg", URN_SCHEMAS_HTTPMAIL);
draftsUrl = getURIPropertyIfExists(properties, "drafts", URN_SCHEMAS_HTTPMAIL);
calendarUrl = getURIPropertyIfExists(properties, "calendar", URN_SCHEMAS_HTTPMAIL);
contactsUrl = getURIPropertyIfExists(properties, "contacts", URN_SCHEMAS_HTTPMAIL);
outboxUrl = getURIPropertyIfExists(properties, "outbox", URN_SCHEMAS_HTTPMAIL);
inboxUrl = getURIPropertyIfExists(properties, "inbox");
deleteditemsUrl = getURIPropertyIfExists(properties, "deleteditems");
sentitemsUrl = getURIPropertyIfExists(properties, "sentitems");
sendmsgUrl = getURIPropertyIfExists(properties, "sendmsg");
draftsUrl = getURIPropertyIfExists(properties, "drafts");
calendarUrl = getURIPropertyIfExists(properties, "calendar");
contactsUrl = getURIPropertyIfExists(properties, "contacts");
outboxUrl = getURIPropertyIfExists(properties, "outbox");
// junk folder not available over webdav
// default public folder path
@ -208,17 +231,16 @@ public class DavExchangeSession extends ExchangeSession {
}
}
static final Map<String, String> attributeMap = new HashMap<String, String>();
static {
attributeMap.put("folderclass", "http://schemas.microsoft.com/exchange/outlookfolderclass");
attributeMap.put("contentclass", "DAV:contentclass");
}
static final Map<Operator, String> operatorMap = new HashMap<Operator, String>();
static {
operatorMap.put(Operator.IsEqualTo, "=");
operatorMap.put(Operator.IsEqualTo, " = ");
operatorMap.put(Operator.IsGreaterThanOrEqualTo, " >= ");
operatorMap.put(Operator.IsGreaterThan, " > ");
operatorMap.put(Operator.IsLessThan, " < ");
operatorMap.put(Operator.Like, " like ");
operatorMap.put(Operator.IsNull, " is null");
}
protected static class AttributeCondition extends ExchangeSession.AttributeCondition {
@ -228,37 +250,71 @@ public class DavExchangeSession extends ExchangeSession {
@Override
public void appendTo(StringBuilder buffer) {
buffer.append('"').append(attributeMap.get(attributeName)).append('"');
buffer.append('"').append(Field.get(attributeName).getUri()).append('"');
buffer.append(operatorMap.get(operator));
buffer.append('\'').append(value).append('\'');
buffer.append('\'');
if (Operator.Like == operator) {
buffer.append('%');
}
buffer.append(value);
if (Operator.Like == operator) {
buffer.append('%');
}
buffer.append('\'');
}
}
protected static class IsNullCondition extends ExchangeSession.IsNullCondition {
protected IsNullCondition(String attributeName) {
super(attributeName);
protected static class HeaderCondition extends AttributeCondition {
protected HeaderCondition(String attributeName, Operator operator, String value) {
super(attributeName, operator, value);
}
@Override
public void appendTo(StringBuilder buffer) {
buffer.append('"').append(attributeMap.get(attributeName)).append('"');
buffer.append(" is null");
buffer.append('"').append(Field.getHeader(attributeName)).append('"');
buffer.append(operatorMap.get(operator));
buffer.append('\'');
if (Operator.Like == operator) {
buffer.append('%');
}
buffer.append(value);
if (Operator.Like == operator) {
buffer.append('%');
}
buffer.append('\'');
}
}
protected static class MonoCondition extends ExchangeSession.MonoCondition {
protected MonoCondition(String attributeName, Operator operator) {
super(attributeName, operator);
}
@Override
public void appendTo(StringBuilder buffer) {
buffer.append('"').append(Field.get(attributeName).getUri()).append('"');
buffer.append(operatorMap.get(operator));
}
}
@Override
public Condition and(Condition... condition) {
public MultiCondition and(Condition... condition) {
return new MultiCondition(Operator.And, condition);
}
@Override
public Condition or(Condition... condition) {
public MultiCondition or(Condition... condition) {
return new MultiCondition(Operator.Or, condition);
}
@Override
public Condition not(Condition condition) {
return new NotCondition(condition);
if (condition == null) {
return null;
} else {
return new NotCondition(condition);
}
}
@Override
@ -266,9 +322,44 @@ public class DavExchangeSession extends ExchangeSession {
return new AttributeCondition(attributeName, Operator.IsEqualTo, value);
}
@Override
public Condition headerEquals(String headerName, String value) {
return new HeaderCondition(headerName, Operator.IsEqualTo, value);
}
@Override
public Condition gte(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.IsGreaterThanOrEqualTo, value);
}
@Override
public Condition lt(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.IsLessThan, value);
}
@Override
public Condition gt(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.IsGreaterThan, value);
}
@Override
public Condition like(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.Like, value);
}
@Override
public Condition isNull(String attributeName) {
return new IsNullCondition(attributeName);
return new MonoCondition(attributeName, Operator.IsNull);
}
@Override
public Condition isTrue(String attributeName) {
return new MonoCondition(attributeName, Operator.IsTrue);
}
@Override
public Condition isFalse(String attributeName) {
return new MonoCondition(attributeName, Operator.IsFalse);
}
@ -348,7 +439,7 @@ public class DavExchangeSession extends ExchangeSession {
"\"urn:schemas:httpmail:unreadcount\" FROM Scope('").append(mode).append(" TRAVERSAL OF \"").append(getFolderPath(folderName)).append("\"')\n" +
" WHERE \"DAV:ishidden\" = False AND \"DAV:isfolder\" = True \n");
if (condition != null) {
searchRequest.append(" AND ");
searchRequest.append(" AND ");
condition.appendTo(searchRequest);
}
MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeSearchMethod(
@ -364,4 +455,98 @@ public class DavExchangeSession extends ExchangeSession {
return folders;
}
protected String getPropertyIfExists(DavPropertySet properties, String name) {
DavProperty property = properties.get(name, EMPTY);
if (property == null) {
return null;
} else {
return (String) property.getValue();
}
}
protected int getIntPropertyIfExists(DavPropertySet properties, String name) {
DavProperty property = properties.get(name, EMPTY);
if (property == null) {
return 0;
} else {
return Integer.parseInt((String) property.getValue());
}
}
protected long getLongPropertyIfExists(DavPropertySet properties, String name) {
DavProperty property = properties.get(name, EMPTY);
if (property == null) {
return 0;
} else {
return Long.parseLong((String) property.getValue());
}
}
protected Message buildMessage(MultiStatusResponse responseEntity) throws URIException {
Message message = new Message();
message.messageUrl = URIUtil.decode(responseEntity.getHref());
DavPropertySet properties = responseEntity.getProperties(HttpStatus.SC_OK);
message.permanentUrl = getPropertyIfExists(properties, "permanenturl");
message.size = getIntPropertyIfExists(properties, "messageSize");
message.uid = getPropertyIfExists(properties, "uid");
message.imapUid = getLongPropertyIfExists(properties, "imapUid");
message.read = "1".equals(getPropertyIfExists(properties, "read"));
message.junk = "1".equals(getPropertyIfExists(properties, "junk"));
message.flagged = "2".equals(getPropertyIfExists(properties, "flagStatus"));
message.draft = "9".equals(getPropertyIfExists(properties, "messageFlags"));
String lastVerbExecuted = getPropertyIfExists(properties, "lastVerbExecuted");
message.answered = "102".equals(lastVerbExecuted) || "103".equals(lastVerbExecuted);
message.forwarded = "104".equals(lastVerbExecuted);
message.date = getPropertyIfExists(properties, "date");
message.deleted = "1".equals(getPropertyIfExists(properties, "deleted"));
if (LOGGER.isDebugEnabled()) {
StringBuilder buffer = new StringBuilder();
buffer.append("Message");
if (message.imapUid != 0) {
buffer.append(" IMAP uid: ").append(message.imapUid);
}
if (message.uid != null) {
buffer.append(" uid: ").append(message.uid);
}
buffer.append(" href: ").append(responseEntity.getHref()).append(" permanenturl:").append(message.permanentUrl);
LOGGER.debug(buffer.toString());
}
return message;
}
@Override
public MessageList searchMessages(String folderName, List<String> attributes, Condition condition) throws IOException {
String folderUrl = getFolderPath(folderName);
MessageList messages = new MessageList();
StringBuilder searchRequest = new StringBuilder();
searchRequest.append("Select \"http://schemas.microsoft.com/exchange/permanenturl\" as permanenturl");
if (attributes != null) {
for (String attribute : attributes) {
Field field = Field.get(attribute);
searchRequest.append(",\"").append(field.getUri()).append("\" as ").append(field.getAlias());
}
}
searchRequest.append(" FROM Scope('SHALLOW TRAVERSAL OF \"").append(folderUrl).append("\"')\n")
.append(" WHERE \"DAV:ishidden\" = False AND \"DAV:isfolder\" = False\n");
if (condition != null) {
searchRequest.append(" AND ");
condition.appendTo(searchRequest);
}
// TODO order by ImapUid
//searchRequest.append(" ORDER BY \"urn:schemas:httpmail:date\" ASC");
DavGatewayTray.debug(new BundleMessage("LOG_SEARCH_QUERY", searchRequest));
MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeSearchMethod(
httpClient, URIUtil.encodePath(folderUrl), searchRequest.toString());
for (MultiStatusResponse response : responses) {
Message message = buildMessage(response);
message.messageList = messages;
messages.add(message);
}
Collections.sort(messages);
return messages;
}
}

View File

@ -0,0 +1,188 @@
/*
* DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
* Copyright (C) 2010 Mickael Guessant
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU 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.
*/
package davmail.exchange.dav;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.xml.Namespace;
import java.util.HashMap;
import java.util.Map;
/**
* WebDav Field
*/
public class Field {
protected static final Namespace DAV = Namespace.getNamespace("DAV:");
protected static final Namespace URN_SCHEMAS_HTTPMAIL = Namespace.getNamespace("urn:schemas:httpmail:");
protected static final Namespace URN_SCHEMAS_MAILHEADER = Namespace.getNamespace("urn:schemas:mailheader:");
protected static final Namespace SCHEMAS_EXCHANGE = Namespace.getNamespace("http://schemas.microsoft.com/exchange/");
protected static final Namespace SCHEMAS_MAPI_PROPTAG = Namespace.getNamespace("http://schemas.microsoft.com/mapi/proptag/");
protected static final Namespace SCHEMAS_MAPI_ID = Namespace.getNamespace("http://schemas.microsoft.com/mapi/id/");
protected static final Namespace SCHEMAS_MAPI_STRING = Namespace.getNamespace("http://schemas.microsoft.com/mapi/string/");
protected static final Namespace URN_SCHEMAS_CONTACTS = Namespace.getNamespace("urn:schemas:contacts:");
protected static enum PropertyType {
ApplicationTime, ApplicationTimeArray, Binary, BinaryArray, Boolean, CLSID, CLSIDArray, Currency, CurrencyArray,
Double, DoubleArray, Error, Float, FloatArray, Integer, IntegerArray, Long, LongArray, Null, Object,
ObjectArray, Short, ShortArray, SystemTime, SystemTimeArray, String, StringArray
}
protected static final Map<PropertyType, String> propertyTypeMap = new HashMap<PropertyType, String>();
static {
propertyTypeMap.put(PropertyType.Integer, "0003");
propertyTypeMap.put(PropertyType.Boolean, "000b");
propertyTypeMap.put(PropertyType.SystemTime, "0040");
propertyTypeMap.put(PropertyType.String, "001f");
}
protected static enum DistinguishedPropertySetType {
Meeting, Appointment, Common, PublicStrings, Address, InternetHeaders, CalendarAssistant, UnifiedMessaging, Task
}
protected static final Map<DistinguishedPropertySetType, String> distinguishedPropertySetMap = new HashMap<DistinguishedPropertySetType, String>();
static {
distinguishedPropertySetMap.put(DistinguishedPropertySetType.Meeting, "6ed8da90-450b-101b-98da-00aa003f1305");
distinguishedPropertySetMap.put(DistinguishedPropertySetType.Appointment, "00062002-0000-0000-c000-000000000046");
distinguishedPropertySetMap.put(DistinguishedPropertySetType.Common, "00062008-0000-0000-c000-000000000046");
distinguishedPropertySetMap.put(DistinguishedPropertySetType.PublicStrings, "00020329-0000-0000-c000-000000000046");
distinguishedPropertySetMap.put(DistinguishedPropertySetType.Address, "00062004-0000-0000-c000-000000000046");
distinguishedPropertySetMap.put(DistinguishedPropertySetType.InternetHeaders, "00020386-0000-0000-c000-000000000046");
distinguishedPropertySetMap.put(DistinguishedPropertySetType.UnifiedMessaging, "4442858e-a9e3-4e80-b900-317a210cc15b");
distinguishedPropertySetMap.put(DistinguishedPropertySetType.Task, "00062003-0000-0000-c000-000000000046");
}
protected static final Map<String, Field> fieldMap = new HashMap<String, Field>();
static {
// well known folders
createField(URN_SCHEMAS_HTTPMAIL, "inbox");
createField(URN_SCHEMAS_HTTPMAIL, "deleteditems");
createField(URN_SCHEMAS_HTTPMAIL, "sentitems");
createField(URN_SCHEMAS_HTTPMAIL, "sendmsg");
createField(URN_SCHEMAS_HTTPMAIL, "drafts");
createField(URN_SCHEMAS_HTTPMAIL, "calendar");
createField(URN_SCHEMAS_HTTPMAIL, "contacts");
createField(URN_SCHEMAS_HTTPMAIL, "outbox");
// folder
createField("folderclass", SCHEMAS_EXCHANGE, "outlookfolderclass");
// POP and IMAP message
createField(DAV, "uid");
createField("messageSize", 0x0e08, PropertyType.Integer);//PR_MESSAGE_SIZE
createField("imapUid", 0x0e23, PropertyType.Integer);//PR_INTERNET_ARTICLE_NUMBER
createField("junk", 0x1083, PropertyType.Integer);
createField("flagStatus", 0x1090, PropertyType.Integer);//PR_FLAG_STATUS
createField("messageFlags", 0x0e07, PropertyType.Integer);//PR_MESSAGE_FLAGS
createField("lastVerbExecuted", 0x1081, PropertyType.Integer);//PR_LAST_VERB_EXECUTED
createField(URN_SCHEMAS_HTTPMAIL, "read");
//createField("read", 0x0e69, PropertyType.Boolean);//PR_READ
createField("deleted", DistinguishedPropertySetType.Common, 0x8570);
createField(URN_SCHEMAS_HTTPMAIL, "date"); //PR_CLIENT_SUBMIT_TIME, 0x0039
//createField("date", 0x0e06, PropertyType.SystemTime);//PR_MESSAGE_DELIVERY_TIME
// IMAP search
createField(URN_SCHEMAS_HTTPMAIL, "subject");
//createField("subject", 0x0037, PropertyType.String);//PR_SUBJECT
createField("body", 0x1000, PropertyType.String);//PR_BODY
createField(URN_SCHEMAS_HTTPMAIL, "from");
//createField("from", DistinguishedPropertySetType.PublicStrings, 0x001f);//urn:schemas:httpmail:from
createField(URN_SCHEMAS_MAILHEADER, "to");
createField(URN_SCHEMAS_MAILHEADER, "cc");
createField("lastmodified", 0x3008, PropertyType.SystemTime);//PR_LAST_MODIFICATION_TIME DAV:getlastmodified
// failover search
createField(DAV, "displayname");
}
protected static void createField(String alias, int propertyTag, PropertyType propertyType) {
String name = 'x' + Integer.toHexString(propertyTag) + propertyTypeMap.get(propertyType);
Field field = new Field(alias, SCHEMAS_MAPI_PROPTAG, name);
fieldMap.put(field.alias, field);
}
protected static void createField(String alias, DistinguishedPropertySetType propertySetType, int propertyTag) {
String name = '{' + distinguishedPropertySetMap.get(propertySetType) + "}/0x" + Integer.toHexString(propertyTag);
Field field = new Field(alias, SCHEMAS_MAPI_ID, name);
fieldMap.put(field.alias, field);
}
protected static void createField(Namespace namespace, String name) {
Field field = new Field(namespace, name);
fieldMap.put(field.alias, field);
}
protected static void createField(String alias, Namespace namespace, String name) {
Field field = new Field(alias, namespace, name);
fieldMap.put(field.alias, field);
}
protected final DavPropertyName davPropertyName;
protected final String alias;
protected final String uri;
public Field(Namespace namespace, String name) {
this(name, namespace, name);
}
public Field(String alias, Namespace namespace, String name) {
davPropertyName = DavPropertyName.create(name, namespace);
this.alias = alias;
this.uri = namespace.getURI()+name;
}
public String getUri() {
return uri;
}
public String getAlias() {
return alias;
}
/**
* Get Field by alias.
*
* @param alias field alias
* @return field
*/
public static Field get(String alias) {
Field field = fieldMap.get(alias);
if (field == null) {
throw new IllegalArgumentException("Unknown field: " + alias);
}
return field;
}
/**
* Get Mime header fieks.
*
* @param alias field alias
* @return field
*/
public static Field getHeader(String headerName) {
String name = '{' + distinguishedPropertySetMap.get(DistinguishedPropertySetType.InternetHeaders) + "}/" + headerName;
return new Field(SCHEMAS_MAPI_STRING, name);
}
}

View File

@ -86,6 +86,12 @@ public class EwsExchangeSession extends ExchangeSession {
}
}
@Override
public MessageList searchMessages(String folderName, List<String> attributes, Condition condition) throws IOException {
// TODO
throw new UnsupportedOperationException();
}
protected static class MultiCondition extends ExchangeSession.MultiCondition implements SearchExpression {
protected MultiCondition(Operator operator, Condition... condition) {
super(operator, condition);
@ -111,9 +117,7 @@ public class EwsExchangeSession extends ExchangeSession {
@Override
public void appendTo(StringBuilder buffer) {
buffer.append("<t:Not>");
condition.appendTo(buffer);
buffer.append("</t:Not>");
}
}
@ -122,6 +126,7 @@ public class EwsExchangeSession extends ExchangeSession {
static {
attributeMap.put("folderclass", ExtendedFieldURI.PR_CONTAINER_CLASS);
attributeMap.put("read", ExtendedFieldURI.PR_READ);
}
protected static class AttributeCondition extends ExchangeSession.AttributeCondition implements SearchExpression {
@ -129,10 +134,18 @@ public class EwsExchangeSession extends ExchangeSession {
super(attributeName, operator, value);
}
protected FieldURI getFieldURI(String attributeName) {
FieldURI fieldURI = attributeMap.get(attributeName);
if (fieldURI == null) {
throw new IllegalArgumentException("Unknown field: " + attributeName);
}
return fieldURI;
}
@Override
public void appendTo(StringBuilder buffer) {
buffer.append("<t:").append(operator.toString()).append('>');
attributeMap.get(attributeName).appendTo(buffer);
getFieldURI(attributeName).appendTo(buffer);
buffer.append("<t:FieldURIOrConstant><t:Constant Value=\"");
buffer.append(StringUtil.xmlEncode(value));
@ -142,9 +155,24 @@ public class EwsExchangeSession extends ExchangeSession {
}
}
protected static class IsNullCondition extends ExchangeSession.IsNullCondition implements SearchExpression {
protected static class HeaderCondition extends AttributeCondition {
protected HeaderCondition(String attributeName, Operator operator, String value) {
super(attributeName, operator, value);
}
@Override
protected FieldURI getFieldURI(String attributeName) {
return new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, attributeName);
}
}
protected static class IsNullCondition extends ExchangeSession.Condition implements SearchExpression {
protected String attributeName;
protected IsNullCondition(String attributeName) {
super(attributeName);
this.attributeName = attributeName;
}
@Override
@ -156,12 +184,12 @@ public class EwsExchangeSession extends ExchangeSession {
}
@Override
public Condition and(Condition... condition) {
public MultiCondition and(Condition... condition) {
return new MultiCondition(Operator.And, condition);
}
@Override
public Condition or(Condition... condition) {
public MultiCondition or(Condition... condition) {
return new MultiCondition(Operator.Or, condition);
}
@ -175,11 +203,46 @@ public class EwsExchangeSession extends ExchangeSession {
return new AttributeCondition(attributeName, Operator.IsEqualTo, value);
}
@Override
public Condition headerEquals(String headerName, String value) {
return new HeaderCondition(headerName, Operator.IsEqualTo, value);
}
@Override
public Condition gte(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.IsGreaterThanOrEqualTo, value);
}
@Override
public Condition lt(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.IsLessThan, value);
}
@Override
public Condition gt(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.IsGreaterThan, value);
}
@Override
public Condition like(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.Like, value);
}
@Override
public Condition isNull(String attributeName) {
return new IsNullCondition(attributeName);
}
@Override
public Condition isTrue(String attributeName) {
return new AttributeCondition(attributeName, Operator.IsEqualTo, "True");
}
@Override
public Condition isFalse(String attributeName) {
return new AttributeCondition(attributeName, Operator.IsEqualTo, "False");
}
protected Folder buildFolder(EWSMethod.Item item) {
Folder folder = new Folder();
folder.folderId = new FolderId(item.get("FolderId"));

View File

@ -31,22 +31,34 @@ public class ExtendedFieldURI implements FieldURI {
ObjectArray, Short, ShortArray, SystemTime, SystemTimeArray, String, StringArray
}
protected static enum DistinguishedPropertySetType {
Meeting, Appointment, Common, PublicStrings, Address, InternetHeaders, CalendarAssistant, UnifiedMessaging, Task
}
protected String propertyTag;
protected DistinguishedPropertySetType distinguishedPropertySetId;
protected String propertySetId;
protected String propertyName;
protected int propertyId;
protected final PropertyType propertyType;
protected PropertyType propertyType;
public ExtendedFieldURI(int intPropertyTag, PropertyType propertyType) {
this.propertyTag = "0x"+Integer.toHexString(intPropertyTag);
this.propertyTag = "0x" + Integer.toHexString(intPropertyTag);
this.propertyType = propertyType;
}
public ExtendedFieldURI(String propertySetId, int propertyId, PropertyType propertyType) {
this.propertySetId = propertySetId;
public ExtendedFieldURI(DistinguishedPropertySetType distinguishedPropertySetId, int propertyId, PropertyType propertyType) {
this.distinguishedPropertySetId = distinguishedPropertySetId;
this.propertyId = propertyId;
this.propertyType = propertyType;
}
public ExtendedFieldURI(DistinguishedPropertySetType distinguishedPropertySetId, String propertyName) {
this.distinguishedPropertySetId = distinguishedPropertySetId;
this.propertyName = propertyName;
}
public String getPropertyTag() {
return propertyTag;
}
@ -56,13 +68,21 @@ public class ExtendedFieldURI implements FieldURI {
if (propertyTag != null) {
buffer.append("PropertyTag=\"").append(propertyTag).append("\" ");
}
if (distinguishedPropertySetId != null) {
buffer.append("DistinguishedPropertySetId=\"").append(distinguishedPropertySetId).append("\" ");
}
if (propertySetId != null) {
buffer.append("PropertySetId=\"").append(propertySetId).append("\" ");
}
if (propertyName != null) {
buffer.append("propertyName=\"").append(propertyName).append("\" ");
}
if (propertyId != 0) {
buffer.append("PropertyId=\"").append(String.valueOf(propertyId)).append("\" ");
}
buffer.append("PropertyType=\"").append(propertyType.toString()).append("\"/>");
if (propertyType != null) {
buffer.append("PropertyType=\"").append(propertyType.toString()).append("\"/>");
}
}
public static final ExtendedFieldURI PR_INSTANCE_KEY = new ExtendedFieldURI(0xff6, PropertyType.Binary);
@ -77,6 +97,8 @@ public class ExtendedFieldURI implements FieldURI {
public static final ExtendedFieldURI PR_LAST_MODIFICATION_TIME = new ExtendedFieldURI(0x3008, PropertyType.SystemTime);
// message properties
public static final ExtendedFieldURI PR_READ = new ExtendedFieldURI(0xe69, PropertyType.Boolean);
}

View File

@ -730,45 +730,36 @@ public class ImapConnection extends AbstractConnection {
sendClient(commandId + " OK STORE completed");
}
protected void buildConditions(SearchConditions conditions, IMAPTokenizer tokens) throws IOException {
boolean or = false;
protected ExchangeSession.Condition buildConditions(SearchConditions conditions, IMAPTokenizer tokens) throws IOException {
ExchangeSession.MultiCondition condition = null;
while (tokens.hasMoreTokens()) {
String token = tokens.nextQuotedToken().toUpperCase();
if (token.startsWith("(") && token.endsWith(")")) {
// quoted search param
buildConditions(conditions, new IMAPTokenizer(token.substring(1, token.length() - 1)));
} else if ("OR".equals(token)) {
or = true;
} else if (token.startsWith("OR ")) {
or = true;
appendOrSearchParams(token, conditions);
} else {
String operator;
if (conditions.query.length() == 5) {
operator = "";
} else if (or) {
operator = " OR ";
} else {
operator = " AND ";
if (condition == null) {
condition = session.and();
}
appendSearchParam(operator, tokens, token, conditions);
condition.append(buildConditions(conditions, new IMAPTokenizer(token.substring(1, token.length() - 1))));
} else if ("OR".equals(token)) {
condition = session.or();
} else if (token.startsWith("OR ")) {
condition = appendOrSearchParams(token, conditions);
} else {
if (condition == null) {
condition = session.and();
}
condition.append(appendSearchParam(tokens, token, conditions));
}
}
return condition;
}
protected List<Long> handleSearch(IMAPTokenizer tokens) throws IOException {
List<Long> uidList = new ArrayList<Long>();
SearchConditions conditions = new SearchConditions();
conditions.append("AND (");
buildConditions(conditions, tokens);
conditions.append(")");
String query = conditions.query.toString();
DavGatewayTray.debug(new BundleMessage("LOG_SEARCH_QUERY", conditions.query));
if ("AND ()".equals(query)) {
query = null;
}
ExchangeSession.MessageList localMessages = currentFolder.searchMessages(query);
ExchangeSession.Condition condition = buildConditions(conditions, tokens);
ExchangeSession.MessageList localMessages = currentFolder.searchMessages(condition);
Iterator<ExchangeSession.Message> iterator;
if (conditions.uidRange != null) {
iterator = new UIDRangeIterator(localMessages, conditions.uidRange);
@ -988,63 +979,60 @@ public class ImapConnection extends AbstractConnection {
}
}
/**
* client side search conditions
*/
static final class SearchConditions {
Boolean flagged;
Boolean answered;
Boolean deleted;
String indexRange;
String uidRange;
final StringBuilder query = new StringBuilder();
public StringBuilder append(String value) {
return query.append(value);
}
}
protected void appendOrSearchParams(String token, SearchConditions conditions) throws IOException {
protected ExchangeSession.MultiCondition appendOrSearchParams(String token, SearchConditions conditions) throws IOException {
ExchangeSession.MultiCondition orCondition = session.or();
IMAPTokenizer innerTokens = new IMAPTokenizer(token);
innerTokens.nextToken();
boolean first = true;
while (innerTokens.hasMoreTokens()) {
String innerToken = innerTokens.nextToken();
String operator = "";
if (!first) {
operator = " OR ";
}
first = false;
appendSearchParam(operator, innerTokens, innerToken, conditions);
orCondition.append(appendSearchParam(innerTokens, innerToken, conditions));
}
return orCondition;
}
protected void appendSearchParam(String operator, StringTokenizer tokens, String token, SearchConditions conditions) throws IOException {
protected ExchangeSession.Condition appendSearchParam(StringTokenizer tokens, String token, SearchConditions conditions) throws IOException {
if ("NOT".equals(token)) {
appendSearchParam(operator + " NOT ", tokens, tokens.nextToken(), conditions);
String nextToken = tokens.nextToken();
if ("DELETED".equals(token)) {
conditions.deleted = Boolean.FALSE;
} else {
return session.not(appendSearchParam(tokens, nextToken, conditions));
}
} else if (token.startsWith("OR ")) {
appendOrSearchParams(token, conditions);
return appendOrSearchParams(token, conditions);
} else if ("SUBJECT".equals(token)) {
conditions.append(operator).append("\"urn:schemas:httpmail:subject\" LIKE '%").append(tokens.nextToken()).append("%'");
return session.like("subject", tokens.nextToken());
} else if ("BODY".equals(token)) {
conditions.append(operator).append("\"http://schemas.microsoft.com/mapi/proptag/x01000001E\" LIKE '%").append(tokens.nextToken()).append("%'");
return session.like("body", tokens.nextToken());
} else if ("FROM".equals(token)) {
conditions.append(operator).append("\"urn:schemas:mailheader:from\" LIKE '%").append(tokens.nextToken()).append("%'");
return session.like("from", tokens.nextToken());
} else if ("TO".equals(token)) {
conditions.append(operator).append("\"urn:schemas:mailheader:to\" LIKE '%").append(tokens.nextToken()).append("%'");
return session.like("to", tokens.nextToken());
} else if ("CC".equals(token)) {
conditions.append(operator).append("\"urn:schemas:mailheader:cc\" LIKE '%").append(tokens.nextToken()).append("%'");
return session.like("cc", tokens.nextToken());
} else if ("LARGER".equals(token)) {
conditions.append(operator).append("\"http://schemas.microsoft.com/mapi/proptag/x0e080003\" &gt;= ").append(Long.parseLong(tokens.nextToken())).append("");
return session.gte("messageSize", tokens.nextToken());
} else if ("SMALLER".equals(token)) {
conditions.append(operator).append("\"http://schemas.microsoft.com/mapi/proptag/x0e080003\" < ").append(Long.parseLong(tokens.nextToken())).append("");
return session.lt("messageSize", tokens.nextToken());
} else if (token.startsWith("SENT") || "SINCE".equals(token) || "BEFORE".equals(token)) {
conditions.append(operator);
appendDateSearchParam(tokens, token, conditions);
return appendDateSearchParam(tokens, token);
} else if ("SEEN".equals(token)) {
conditions.append(operator).append("\"urn:schemas:httpmail:read\" = True");
return session.isTrue("read");
} else if ("UNSEEN".equals(token) || "NEW".equals(token)) {
conditions.append(operator).append("\"urn:schemas:httpmail:read\" = False");
return session.isFalse("read");
} else if ("DELETED".equals(token)) {
conditions.deleted = !operator.endsWith(" NOT ");
conditions.deleted = Boolean.TRUE;
} else if ("UNDELETED".equals(token) || "NOT DELETED".equals(token)) {
conditions.deleted = Boolean.FALSE;
} else if ("FLAGGED".equals(token)) {
@ -1061,15 +1049,7 @@ public class ImapConnection extends AbstractConnection {
if ("message-id".equals(headerName) && !value.startsWith("<")) {
value = '<' + value + '>';
}
String namespace;
if (headerName.startsWith("x-")) {
// look for extended headers in MAPI namespace
namespace = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/";
} else {
// look for standard properties in mailheader namespace
namespace = "urn:schemas:mailheader:";
}
conditions.append(operator).append('"').append(namespace).append(headerName).append("\"='").append(value).append('\'');
return session.headerEquals(headerName, value);
} else if ("UID".equals(token)) {
String range = tokens.nextToken();
if ("1:*".equals(range)) {
@ -1085,9 +1065,11 @@ public class ImapConnection extends AbstractConnection {
} else {
throw new DavMailException("EXCEPTION_INVALID_SEARCH_PARAMETERS", token);
}
// client side search token
return null;
}
protected void appendDateSearchParam(StringTokenizer tokens, String token, SearchConditions conditions) throws IOException {
protected ExchangeSession.Condition appendDateSearchParam(StringTokenizer tokens, String token) throws IOException {
Date startDate;
Date endDate;
SimpleDateFormat parser = new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH);
@ -1106,27 +1088,21 @@ public class ImapConnection extends AbstractConnection {
}
String searchAttribute;
if (token.startsWith("SENT")) {
searchAttribute = "urn:schemas:httpmail:date";
searchAttribute = "date";
} else {
searchAttribute = "DAV:getlastmodified";
searchAttribute = "lastmodified";
}
if (token.endsWith("ON")) {
conditions.append("(\"").append(searchAttribute).append("\" > '")
.append(dateFormatter.format(startDate))
.append("' AND \"").append(searchAttribute).append("\" < '")
.append(dateFormatter.format(endDate))
.append("')");
return session.and(session.gt(searchAttribute, dateFormatter.format(startDate)),
session.lt(searchAttribute, dateFormatter.format(endDate)));
} else if (token.endsWith("BEFORE")) {
conditions.append("\"").append(searchAttribute).append("\" < '")
.append(dateFormatter.format(startDate))
.append('\'');
return session.lt(searchAttribute, dateFormatter.format(startDate));
} else if (token.endsWith("SINCE")) {
conditions.append("\"").append(searchAttribute).append("\" >= '")
.append(dateFormatter.format(startDate))
.append('\'');
return session.gte(searchAttribute, dateFormatter.format(startDate));
} else {
throw new DavMailException("EXCEPTION_INVALID_SEARCH_PARAMETERS", dateToken);
}
}
protected boolean expunge(boolean silent) throws IOException {
@ -1436,8 +1412,8 @@ public class ImapConnection extends AbstractConnection {
endUid = startUid;
startUid = swap;
}
} else if ("*".equals(currentRange)){
startUid = endUid = messages.get(messages.size()-1).getImapUid();
} else if ("*".equals(currentRange)) {
startUid = endUid = messages.get(messages.size() - 1).getImapUid();
} else {
startUid = endUid = convertToLong(currentRange);
}
@ -1519,7 +1495,7 @@ public class ImapConnection extends AbstractConnection {
endUid = startUid;
startUid = swap;
}
} else if ("*".equals(currentRange)){
} else if ("*".equals(currentRange)) {
startUid = endUid = messages.size();
} else {
startUid = endUid = convertToLong(currentRange);