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

EWS: refactor contactFind, use new Condition API

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1095 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2010-06-17 22:37:33 +00:00
parent df99136e61
commit 9a2149ef93
8 changed files with 207 additions and 97 deletions

View File

@ -22,6 +22,7 @@ import davmail.BundleMessage;
import davmail.Settings;
import davmail.exception.DavMailAuthenticationException;
import davmail.exception.DavMailException;
import davmail.exchange.dav.Field;
import davmail.http.DavGatewayHttpClientFacade;
import davmail.http.DavGatewayOTPPrompt;
import davmail.util.StringUtil;
@ -600,7 +601,8 @@ public abstract class ExchangeSession {
public abstract MessageList searchMessages(String folderName, List<String> attributes, Condition condition) throws IOException;
protected enum Operator {
Or, And, Not, IsEqualTo, Like, IsGreaterThan, IsGreaterThanOrEqualTo, IsLessThan, IsNull, IsTrue, IsFalse
Or, And, Not, IsEqualTo, IsGreaterThan, IsGreaterThanOrEqualTo, IsLessThan, IsNull, IsTrue, IsFalse,
Like, StartsWith, Contains
}
public abstract static class Condition {
@ -628,7 +630,7 @@ public abstract class ExchangeSession {
this.conditions = Arrays.asList(conditions);
}
public void append(Condition condition) {
public void add(Condition condition) {
if (condition != null) {
conditions.add(condition);
}
@ -673,6 +675,8 @@ public abstract class ExchangeSession {
public abstract Condition like(String attributeName, String value);
public abstract Condition startsWith(String attributeName, String value);
public abstract Condition isNull(String attributeName);
public abstract Condition isTrue(String attributeName);
@ -2755,7 +2759,7 @@ public abstract class ExchangeSession {
* @throws IOException on error
*/
public Map<String, Map<String, String>> contactFindByUid(String uid) throws IOException {
return contactFind(DAV_UID_FILTER + uid + '\'');
return contactFind(equals("uid", uid));
}
static final String DAV_UID_FILTER = "\"DAV:uid\"='";
@ -2767,13 +2771,15 @@ public abstract class ExchangeSession {
* @return List of users
* @throws IOException on error
*/
public Map<String, Map<String, String>> contactFind(String searchFilter) throws IOException {
public Map<String, Map<String, String>> contactFind(Condition condition) throws IOException {
// uid value in search filter (hex value)
String filterUid = null;
// base64 encoded uid value
String actualFilterUid = null;
// TODO: move to LDAP code
// replace hex encoded uid with base64 uid
/*
if (searchFilter != null) {
int uidStart = searchFilter.indexOf(DAV_UID_FILTER);
if (uidStart >= 0) {
@ -2789,52 +2795,63 @@ public abstract class ExchangeSession {
}
}
}
*/
List<String> attributes = new ArrayList<String>();
attributes.add("extensionattribute1");
attributes.add("extensionattribute2");
attributes.add("extensionattribute3");
attributes.add("extensionattribute4");
attributes.add("bday");
attributes.add("businesshomepage");
attributes.add("c");
attributes.add("cn");
attributes.add("co");
attributes.add("department");
attributes.add("email1");
attributes.add("email2");
attributes.add("facsimiletelephonenumber");
attributes.add("givenName");
attributes.add("homeCity");
attributes.add("homeCountry");
attributes.add("homePhone");
attributes.add("homePostalCode");
attributes.add("homeState");
attributes.add("homeStreet");
attributes.add("l");
attributes.add("manager");
attributes.add("mobile");
attributes.add("namesuffix");
attributes.add("nickname");
attributes.add("o");
attributes.add("pager");
attributes.add("personaltitle");
attributes.add("postalcode");
attributes.add("postofficebox");
attributes.add("profession");
attributes.add("roomnumber");
attributes.add("secretarycn");
attributes.add("sn");
attributes.add("spousecn");
attributes.add("st");
attributes.add("street");
attributes.add("telephoneNumber");
attributes.add("title");
attributes.add("textdescription");
StringBuilder searchRequest = new StringBuilder();
searchRequest.append("Select \"DAV:uid\", " +
"\"http://schemas.microsoft.com/exchange/extensionattribute1\"," +
"\"http://schemas.microsoft.com/exchange/extensionattribute2\"," +
"\"http://schemas.microsoft.com/exchange/extensionattribute3\"," +
"\"http://schemas.microsoft.com/exchange/extensionattribute4\"," +
"\"urn:schemas:contacts:bday\"," +
"\"urn:schemas:contacts:businesshomepage\"," +
"\"urn:schemas:contacts:c\"," +
"\"urn:schemas:contacts:cn\"," +
"\"urn:schemas:contacts:co\"," +
"\"urn:schemas:contacts:department\"," +
"\"urn:schemas:contacts:email1\"," +
"\"urn:schemas:contacts:email2\"," +
"\"urn:schemas:contacts:facsimiletelephonenumber\"," +
"\"urn:schemas:contacts:givenName\"," +
"\"urn:schemas:contacts:homeCity\"," +
"\"urn:schemas:contacts:homeCountry\"," +
"\"urn:schemas:contacts:homePhone\"," +
"\"urn:schemas:contacts:homePostalCode\"," +
"\"urn:schemas:contacts:homeState\"," +
"\"urn:schemas:contacts:homeStreet\"," +
"\"urn:schemas:contacts:l\"," +
"\"urn:schemas:contacts:manager\"," +
"\"urn:schemas:contacts:mobile\"," +
"\"urn:schemas:contacts:namesuffix\"," +
"\"urn:schemas:contacts:nickname\"," +
"\"urn:schemas:contacts:o\"," +
"\"urn:schemas:contacts:pager\"," +
"\"urn:schemas:contacts:personaltitle\"," +
"\"urn:schemas:contacts:postalcode\"," +
"\"urn:schemas:contacts:postofficebox\"," +
"\"urn:schemas:contacts:profession\"," +
"\"urn:schemas:contacts:roomnumber\"," +
"\"urn:schemas:contacts:secretarycn\"," +
"\"urn:schemas:contacts:sn\"," +
"\"urn:schemas:contacts:spousecn\"," +
"\"urn:schemas:contacts:st\"," +
"\"urn:schemas:contacts:street\"," +
"\"urn:schemas:contacts:telephoneNumber\"," +
"\"urn:schemas:contacts:title\"," +
"\"urn:schemas:httpmail:textdescription\"")
.append(" FROM Scope('SHALLOW TRAVERSAL OF \"").append(contactsUrl).append("\"')\n")
.append(" WHERE \"DAV:contentclass\" = 'urn:content-classes:person' \n");
if (searchFilter != null && searchFilter.length() > 0) {
searchRequest.append(" AND ").append(searchFilter);
searchRequest.append("SELECT ");
if (attributes != null) {
for (String attribute : attributes) {
Field field = Field.get(attribute);
searchRequest.append(',').append(Field.getRequestPropertyString(field.getAlias()));
}
}
searchRequest.append(" FROM SCOPE('SHALLOW TRAVERSAL OF \"").append(contactsUrl).append("\"')")
.append(" WHERE \"DAV:contentclass\" = 'urn:content-classes:person'");
if (condition != null) {
searchRequest.append(" AND ");
condition.appendTo(searchRequest);
}
LOGGER.debug("contactFind: " + searchRequest);
MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeSearchMethod(
@ -2889,7 +2906,7 @@ public abstract class ExchangeSession {
}
}
LOGGER.debug("contactFind " + ((searchFilter == null) ? "" : searchFilter) + ": " + results.size() + " result(s)");
LOGGER.debug("contactFind " + searchRequest + ": " + results.size() + " result(s)");
return results;
}

View File

@ -307,7 +307,7 @@ public class DavExchangeSession extends ExchangeSession {
buffer.append('%');
}
buffer.append(value);
if (Operator.Like == operator) {
if (Operator.Like == operator || Operator.StartsWith == operator) {
buffer.append('%');
}
if (!isIntValue) {
@ -404,6 +404,11 @@ public class DavExchangeSession extends ExchangeSession {
return new AttributeCondition(attributeName, Operator.Like, value);
}
@Override
public Condition startsWith(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.StartsWith, value);
}
@Override
public Condition isNull(String attributeName) {
return new MonoCondition(attributeName, Operator.IsNull);

View File

@ -30,6 +30,11 @@ public abstract class AttributeOption extends Option {
super(name, value);
}
public void appendTo(StringBuilder buffer) {
buffer.append(' ').append(name).append("=\"").append(value).append('"');
}
/**
* @inheritDoc
*/

View File

@ -0,0 +1,38 @@
/*
* 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.ews;
/**
* Contains comparison mode.
*/
public class ContainmentComparison extends AttributeOption {
private ContainmentComparison(String value) {
super("ContainmentComparison", value);
}
public static final ContainmentComparison Exact = new ContainmentComparison("Exact");
public static final ContainmentComparison IgnoreCase = new ContainmentComparison("IgnoreCase");
public static final ContainmentComparison IgnoreNonSpacingCharacters = new ContainmentComparison("IgnoreNonSpacingCharacters");
public static final ContainmentComparison Loose = new ContainmentComparison("Loose");
public static final ContainmentComparison IgnoreCaseAndNonSpacingCharacters = new ContainmentComparison("IgnoreCaseAndNonSpacingCharacters");
public static final ContainmentComparison LooseAndIgnoreCase = new ContainmentComparison("LooseAndIgnoreCase");
public static final ContainmentComparison LooseAndIgnoreNonSpace = new ContainmentComparison("LooseAndIgnoreNonSpace");
public static final ContainmentComparison LooseAndIgnoreCaseAndIgnoreNonSpace = new ContainmentComparison("LooseAndIgnoreCaseAndIgnoreNonSpace");
}

View File

@ -0,0 +1,41 @@
/*
* 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.ews;
/**
* Contains search mode.
*/
public class ContainmentMode extends AttributeOption {
private ContainmentMode(String value) {
super("ContainmentMode", value);
}
/**
* Full String.
*/
public static final ContainmentMode FullString = new ContainmentMode("FullString");
/**
* Starts with.
*/
public static final ContainmentMode Prefixed = new ContainmentMode("Prefixed");
public static final ContainmentMode Substring = new ContainmentMode("Substring");
public static final ContainmentMode PrefixOnWords = new ContainmentMode("PrefixOnWords");
public static final ContainmentMode ExactPhrase = new ContainmentMode("ExactPhrase");
}

View File

@ -164,10 +164,20 @@ public class EwsExchangeSession extends ExchangeSession {
}
protected static class AttributeCondition extends ExchangeSession.AttributeCondition implements SearchExpression {
protected ContainmentMode containmentMode;
protected ContainmentComparison containmentComparison;
protected AttributeCondition(String attributeName, Operator operator, String value) {
super(attributeName, operator, value);
}
protected AttributeCondition(String attributeName, Operator operator, String value,
ContainmentMode containmentMode, ContainmentComparison containmentComparison) {
super(attributeName, operator, value);
this.containmentMode = containmentMode;
this.containmentComparison = containmentComparison;
}
protected FieldURI getFieldURI(String attributeName) {
FieldURI fieldURI = attributeMap.get(attributeName);
if (fieldURI == null) {
@ -178,7 +188,14 @@ public class EwsExchangeSession extends ExchangeSession {
@Override
public void appendTo(StringBuilder buffer) {
buffer.append("<t:").append(operator.toString()).append('>');
buffer.append("<t:").append(operator.toString());
if (containmentMode != null) {
containmentMode.appendTo(buffer);
}
if (containmentComparison != null) {
containmentComparison.appendTo(buffer);
}
buffer.append('>');
getFieldURI(attributeName).appendTo(buffer);
buffer.append("<t:FieldURIOrConstant><t:Constant Value=\"");
@ -264,7 +281,12 @@ public class EwsExchangeSession extends ExchangeSession {
@Override
public Condition like(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.Like, value);
return new AttributeCondition(attributeName, Operator.Contains, value, ContainmentMode.Substring, ContainmentComparison.IgnoreCase);
}
@Override
public Condition startsWith(String attributeName, String value) {
return new AttributeCondition(attributeName, Operator.Contains, value, ContainmentMode.Prefixed, ContainmentComparison.IgnoreCase);
}
@Override

View File

@ -739,7 +739,7 @@ public class ImapConnection extends AbstractConnection {
if (condition == null) {
condition = session.and();
}
condition.append(buildConditions(conditions, new IMAPTokenizer(token.substring(1, token.length() - 1))));
condition.add(buildConditions(conditions, new IMAPTokenizer(token.substring(1, token.length() - 1))));
} else if ("OR".equals(token)) {
condition = session.or();
} else if (token.startsWith("OR ")) {
@ -748,7 +748,7 @@ public class ImapConnection extends AbstractConnection {
if (condition == null) {
condition = session.and();
}
condition.append(appendSearchParam(tokens, token, conditions));
condition.add(appendSearchParam(tokens, token, conditions));
}
}
return condition;
@ -996,7 +996,7 @@ public class ImapConnection extends AbstractConnection {
innerTokens.nextToken();
while (innerTokens.hasMoreTokens()) {
String innerToken = innerTokens.nextToken();
orCondition.append(appendSearchParam(innerTokens, innerToken, conditions));
orCondition.add(appendSearchParam(innerTokens, innerToken, conditions));
}
return orCondition;
}

View File

@ -573,10 +573,10 @@ public class LdapConnection extends AbstractConnection {
String attributeName = reqBer.parseStringWithTag(LDAP_FILTER_PRESENT, isLdapV3(), null).toLowerCase();
nestedFilter.add(new SimpleFilter(attributeName));
} else {
int[] seqSize = new int[1];
int ldapFilterOperator = reqBer.parseSeq(seqSize);
int subEnd = reqBer.getParsePosition() + seqSize[0];
nestedFilter.add(parseNestedFilter(reqBer, ldapFilterOperator, subEnd));
int[] seqSize = new int[1];
int ldapFilterOperator = reqBer.parseSeq(seqSize);
int subEnd = reqBer.getParsePosition() + seqSize[0];
nestedFilter.add(parseNestedFilter(reqBer, ldapFilterOperator, subEnd));
}
}
} else {
@ -774,7 +774,7 @@ public class LdapConnection extends AbstractConnection {
}
static interface LdapFilter {
String getContactSearchFilter();
ExchangeSession.Condition getContactSearchFilter();
Map<String, Map<String, String>> findInGAL(ExchangeSession session) throws IOException;
@ -785,7 +785,7 @@ public class LdapConnection extends AbstractConnection {
boolean isMatch(Map<String, String> person);
}
static class CompoundFilter implements LdapFilter {
class CompoundFilter implements LdapFilter {
final Set<LdapFilter> criteria = new HashSet<LdapFilter>();
final int type;
@ -843,35 +843,21 @@ public class LdapConnection extends AbstractConnection {
*
* @return contact search filter
*/
public String getContactSearchFilter() {
StringBuilder buffer = new StringBuilder();
public ExchangeSession.Condition getContactSearchFilter() {
ExchangeSession.MultiCondition condition;
String op;
if (type == LDAP_FILTER_OR) {
op = " OR ";
condition = session.or();
} else {
op = " AND ";
condition = session.and();
}
buffer.append('(');
for (LdapFilter child : criteria) {
String childFilter = child.getContactSearchFilter();
if (childFilter != null) {
if (buffer.length() > 1) {
buffer.append(op);
}
buffer.append(childFilter);
}
condition.add(child.getContactSearchFilter());
}
// empty filter
if (buffer.length() == 1) {
return null;
}
buffer.append(')');
return buffer.toString();
return condition;
}
/**
@ -956,7 +942,7 @@ public class LdapConnection extends AbstractConnection {
}
}
static class SimpleFilter implements LdapFilter {
class SimpleFilter implements LdapFilter {
static final String STAR = "*";
final String attributeName;
final String value;
@ -1026,32 +1012,28 @@ public class LdapConnection extends AbstractConnection {
return buffer.toString();
}
public String getContactSearchFilter() {
StringBuilder buffer;
public ExchangeSession.Condition getContactSearchFilter() {
String contactAttributeName = getContactAttributeName();
if (canIgnore || (contactAttributeName == null)) {
return null;
}
buffer = new StringBuilder();
buffer.append('"').append(contactAttributeName).append('"');
ExchangeSession.Condition condition;
if (operator == LDAP_FILTER_EQUALITY) {
buffer.append("='").append(value).append('\'');
condition = session.equals(contactAttributeName, value);
} else if ("*".equals(value)) {
buffer.append(" is not null");
condition = session.not(session.isNull(contactAttributeName));
} else {
buffer.append(" LIKE '");
// endsWith not supported by exchange, convert to contains
if (mode == LDAP_SUBSTRING_FINAL || mode == LDAP_SUBSTRING_ANY) {
buffer.append('%');
condition = session.like(contactAttributeName, value);
} else {
condition = session.startsWith(contactAttributeName, value);
}
buffer.append(value.replaceAll("'", "''"));
// endsWith not supported by exchange, always append %
buffer.append('%');
buffer.append('\'');
}
return buffer.toString();
return condition;
}
public boolean isMatch(Map<String, String> person) {
@ -1230,7 +1212,7 @@ public class LdapConnection extends AbstractConnection {
}
} else {
// append personal contacts first
String filter = ldapFilter.getContactSearchFilter();
ExchangeSession.Condition filter = ldapFilter.getContactSearchFilter();
// if ldapfilter is not a full search and filter is null,
// ignored all attribute filters => return empty results