diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index 82708748..e47d709c 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -118,7 +118,6 @@ public abstract class ExchangeSession { private final String userName; - private boolean disableGalLookup; protected static final String YYYY_MM_DD_HH_MM_SS = "yyyy/MM/dd HH:mm:ss"; private static final String YYYYMMDD_T_HHMMSS_Z = "yyyyMMdd'T'HHmmss'Z'"; protected static final String YYYY_MM_DD_T_HHMMSS_Z = "yyyy-MM-dd'T'HH:mm:ss'Z'"; @@ -2816,7 +2815,7 @@ public abstract class ExchangeSession { return results; } - public abstract Map galFind(Condition condition) throws IOException; + public abstract Map galFind(Condition condition, Set returningAttributes, int sizeLimit) throws IOException; /** * Full Contact attribute list @@ -2890,39 +2889,6 @@ public abstract class ExchangeSession { CONTACT_ATTRIBUTES.add("fburl"); } - /** - * Get extended address book information for person with gallookup. - * Does not work with Exchange 2007 - * - * @param person person attributes map - */ - public void galLookup(Map person) { - if (!disableGalLookup) { - GetMethod getMethod = null; - try { - getMethod = new GetMethod(URIUtil.encodePathQuery(getCmdBasePath() + "?Cmd=gallookup&ADDR=" + person.get("EM"))); - DavGatewayHttpClientFacade.executeGetMethod(httpClient, getMethod, true); - Map> results = XMLStreamUtil.getElementContentsAsMap(getMethod.getResponseBodyAsStream(), "person", "alias"); - // add detailed information - if (!results.isEmpty()) { - Map fullperson = results.get(person.get("AN").toLowerCase()); - if (fullperson != null) { - for (Map.Entry entry : fullperson.entrySet()) { - person.put(entry.getKey(), entry.getValue()); - } - } - } - } catch (IOException e) { - LOGGER.warn("Unable to gallookup person: " + person + ", disable GalLookup"); - disableGalLookup = true; - } finally { - if (getMethod != null) { - getMethod.releaseConnection(); - } - } - } - } - /** * Get freebusy data string from Exchange. * diff --git a/src/java/davmail/exchange/dav/DavExchangeSession.java b/src/java/davmail/exchange/dav/DavExchangeSession.java index cd0806b5..d06856b7 100644 --- a/src/java/davmail/exchange/dav/DavExchangeSession.java +++ b/src/java/davmail/exchange/dav/DavExchangeSession.java @@ -198,6 +198,20 @@ public class DavExchangeSession extends ExchangeSession { GALFIND_CRITERIA_MAP.put("apple-group-realname", "DP"); } + static final HashSet GALLOOKUP_ATTRIBUTES = new HashSet(); + + static { + GALLOOKUP_ATTRIBUTES.add("givenname"); + GALLOOKUP_ATTRIBUTES.add("initials"); + GALLOOKUP_ATTRIBUTES.add("sn"); + GALLOOKUP_ATTRIBUTES.add("street"); + GALLOOKUP_ATTRIBUTES.add("st"); + GALLOOKUP_ATTRIBUTES.add("postalcode"); + GALLOOKUP_ATTRIBUTES.add("c"); + GALLOOKUP_ATTRIBUTES.add("departement"); + GALLOOKUP_ATTRIBUTES.add("mobile"); + } + /** * Exchange to LDAP attribute map */ @@ -225,7 +239,7 @@ public class DavExchangeSession extends ExchangeSession { } @Override - public Map galFind(Condition condition) throws IOException { + public Map galFind(Condition condition, Set returningAttributes, int sizeLimit) throws IOException { Map contacts = new HashMap(); if (condition instanceof MultiCondition) { // TODO @@ -242,9 +256,15 @@ public class DavExchangeSession extends ExchangeSession { getMethod.releaseConnection(); } LOGGER.debug("galfind " + searchAttribute + '=' + searchValue + ": " + results.size() + " result(s)"); - for (Map result:results.values()) { - Contact contact = buildGalfindContact(result); + for (Map result : results.values()) { + Contact contact = new Contact(); + contact.setName(result.get("AN")); + contact.put("uid", result.get("AN")); + buildGalfindContact(contact, result); if (condition.isMatch(contact)) { + if (needGalLookup(returningAttributes)) { + galLookup(contact); + } contacts.put(contact.getName().toLowerCase(), contact); } } @@ -254,17 +274,63 @@ public class DavExchangeSession extends ExchangeSession { return contacts; } - protected Contact buildGalfindContact(Map response) { - Contact contact = new Contact(); - contact.setName(response.get("AN")); - contact.put("uid", response.get("AN")); + protected boolean needGalLookup(Set returningAttributes) { + // iCal search, do not call gallookup + if (returningAttributes.contains("apple-serviceslocator")) { + return false; + // return all attributes => call gallookup + } else if (returningAttributes.isEmpty()) { + return true; + } + + for (String attributeName : GALLOOKUP_ATTRIBUTES) { + if (returningAttributes.contains(attributeName)) { + return true; + } + } + return false; + } + + private boolean disableGalLookup; + + /** + * Get extended address book information for person with gallookup. + * Does not work with Exchange 2007 + * + * @param contact galfind contact + */ + public void galLookup(Contact contact) { + if (!disableGalLookup) { + GetMethod getMethod = null; + try { + getMethod = new GetMethod(URIUtil.encodePathQuery(getCmdBasePath() + "?Cmd=gallookup&ADDR=" + contact.get("smtpemail1"))); + DavGatewayHttpClientFacade.executeGetMethod(httpClient, getMethod, true); + Map> results = XMLStreamUtil.getElementContentsAsMap(getMethod.getResponseBodyAsStream(), "person", "alias"); + // add detailed information + if (!results.isEmpty()) { + Map personGalLookupDetails = results.get(contact.get("uid").toLowerCase()); + if (personGalLookupDetails != null) { + buildGalfindContact(contact, personGalLookupDetails); + } + } + } catch (IOException e) { + LOGGER.warn("Unable to gallookup person: " + contact + ", disable GalLookup"); + disableGalLookup = true; + } finally { + if (getMethod != null) { + getMethod.releaseConnection(); + } + } + } + } + + protected void buildGalfindContact(Contact contact, Map response) { for (Map.Entry entry : GALFIND_ATTRIBUTE_MAP.entrySet()) { String attributeValue = response.get(entry.getValue()); if (attributeValue != null) { contact.put(entry.getKey(), attributeValue); } } - return contact; } @Override @@ -528,6 +594,15 @@ public class DavExchangeSession extends ExchangeSession { } if ("urlcompname".equals(field.alias)) { buffer.append(StringUtil.encodeUrlcompname(value)); + } else if (field.isIntValue()) { + // check value + try { + Integer.parseInt(value); + buffer.append(value); + } catch (NumberFormatException e) { + // invalid value, replace with 0 + buffer.append('0'); + } } else { buffer.append(value); } diff --git a/src/java/davmail/exchange/ews/EwsExchangeSession.java b/src/java/davmail/exchange/ews/EwsExchangeSession.java index 41c4c2d8..efe01f35 100644 --- a/src/java/davmail/exchange/ews/EwsExchangeSession.java +++ b/src/java/davmail/exchange/ews/EwsExchangeSession.java @@ -1280,17 +1280,17 @@ public class EwsExchangeSession extends ExchangeSession { return contact; } - public Map galFind(Condition condition) throws IOException { + public Map galFind(Condition condition, Set returningAttributes, int sizeLimit) throws IOException { Map contacts = new HashMap(); if (condition instanceof MultiCondition) { List conditions = ((MultiCondition) condition).getConditions(); Operator operator = ((MultiCondition) condition).getOperator(); if (operator == Operator.Or) { for (Condition innerCondition : conditions) { - contacts.putAll(galFind(innerCondition)); + contacts.putAll(galFind(innerCondition, returningAttributes, sizeLimit)); } } else if (operator == Operator.And && !conditions.isEmpty()) { - Map innerContacts = galFind(conditions.get(0)); + Map innerContacts = galFind(conditions.get(0), returningAttributes, sizeLimit); for (ExchangeSession.Contact contact : innerContacts.values()) { if (condition.isMatch(contact)) { contacts.put(contact.getName().toLowerCase(), contact); diff --git a/src/java/davmail/ldap/LdapConnection.java b/src/java/davmail/ldap/LdapConnection.java index 01d69492..778fb887 100644 --- a/src/java/davmail/ldap/LdapConnection.java +++ b/src/java/davmail/ldap/LdapConnection.java @@ -186,20 +186,6 @@ public class LdapConnection extends AbstractConnection { STATIC_ATTRIBUTE_MAP.put("apple-serviceslocator", COMPUTER_GUID + ':' + VIRTUALHOST_GUID + ":calendar"); } - static final HashSet EXTENDED_ATTRIBUTES = new HashSet(); - - static { - EXTENDED_ATTRIBUTES.add("givenname"); - EXTENDED_ATTRIBUTES.add("initials"); - EXTENDED_ATTRIBUTES.add("sn"); - EXTENDED_ATTRIBUTES.add("street"); - EXTENDED_ATTRIBUTES.add("st"); - EXTENDED_ATTRIBUTES.add("postalcode"); - EXTENDED_ATTRIBUTES.add("c"); - EXTENDED_ATTRIBUTES.add("departement"); - EXTENDED_ATTRIBUTES.add("mobile"); - } - /** * LDAP to Exchange Criteria Map */ @@ -846,7 +832,7 @@ public class LdapConnection extends AbstractConnection { static interface LdapFilter { ExchangeSession.Condition getContactSearchFilter(); - Map findInGAL(ExchangeSession session) throws IOException; + Map findInGAL(ExchangeSession session, Set returningAttributes, int sizeLimit) throws IOException; void add(LdapFilter filter); @@ -973,11 +959,11 @@ public class LdapConnection extends AbstractConnection { * @return persons map * @throws IOException on error */ - public Map findInGAL(ExchangeSession session) throws IOException { + public Map findInGAL(ExchangeSession session, Set returningAttributes, int sizeLimit) throws IOException { Map persons = null; for (LdapFilter child : criteria) { - Map childFind = child.findInGAL(session); + Map childFind = child.findInGAL(session, returningAttributes, sizeLimit); if (childFind != null) { if (persons == null) { @@ -1091,15 +1077,7 @@ public class LdapConnection extends AbstractConnection { ExchangeSession.Condition condition = null; if (operator == LDAP_FILTER_EQUALITY) { - try { - // check imapUid value - if ("imapUid".equals(contactAttributeName)) { - Integer.parseInt(value); - } - condition = session.isEqualTo(contactAttributeName, value); - } catch (NumberFormatException e) { - // ignore condition - } + condition = session.isEqualTo(contactAttributeName, value); } else if ("*".equals(value)) { condition = session.not(session.isNull(contactAttributeName)); // do not allow substring search on integer field imapUid @@ -1120,7 +1098,7 @@ public class LdapConnection extends AbstractConnection { return true; } - String personAttributeValue = person.get(getGalFindAttributeName()); + String personAttributeValue = person.get(attributeName); if (personAttributeValue == null) { // No value to allow for filter match @@ -1139,7 +1117,7 @@ public class LdapConnection extends AbstractConnection { return false; } - public Map findInGAL(ExchangeSession session) throws IOException { + public Map findInGAL(ExchangeSession session, Set returningAttributes, int sizeLimit) throws IOException { if (canIgnore) { return null; } @@ -1148,7 +1126,7 @@ public class LdapConnection extends AbstractConnection { if (galFindAttributeName != null) { // quick fix for cn=* filter - Map galPersons = session.galFind(session.startsWith(attributeName, "*".equals(value) ? "A" : value)); + Map galPersons = session.galFind(session.startsWith(attributeName, "*".equals(value) ? "A" : value), returningAttributes, sizeLimit); if (operator == LDAP_FILTER_EQUALITY) { // Make sure only exact matches are returned @@ -1278,7 +1256,7 @@ public class LdapConnection extends AbstractConnection { // then in GAL if (persons == null || persons.isEmpty()) { - persons = session.galFind(session.isEqualTo("uid", uid)); + persons = session.galFind(session.isEqualTo("uid", uid), returningAttributes, sizeLimit); ExchangeSession.Contact person = persons.get(uid.toLowerCase()); // filter out non exact results @@ -1315,7 +1293,7 @@ public class LdapConnection extends AbstractConnection { // full search for (char c = 'A'; c < 'Z'; c++) { if (!abandon && persons.size() < sizeLimit) { - for (ExchangeSession.Contact person : session.galFind(session.startsWith("uid", String.valueOf(c))).values()) { + for (ExchangeSession.Contact person : session.galFind(session.startsWith("uid", String.valueOf(c)), returningAttributes, sizeLimit).values()) { persons.put(person.get("uid"), person); if (persons.size() == sizeLimit) { break; @@ -1341,7 +1319,7 @@ public class LdapConnection extends AbstractConnection { } } if (!abandon && persons.size() < sizeLimit) { - for (ExchangeSession.Contact person : ldapFilter.findInGAL(session).values()) { + for (ExchangeSession.Contact person : ldapFilter.findInGAL(session, returningAttributes, sizeLimit).values()) { if (persons.size() == sizeLimit) { break; } @@ -1446,19 +1424,6 @@ public class LdapConnection extends AbstractConnection { boolean needObjectClasses = returningAttributes.contains("objectclass") || returningAttributes.isEmpty(); boolean iCalSearch = returningAttributes.contains("apple-serviceslocator"); boolean returnAllAttributes = returningAttributes.isEmpty(); - boolean needDetails = returnAllAttributes; - if (!needDetails) { - for (String attributeName : EXTENDED_ATTRIBUTES) { - if (returningAttributes.contains(attributeName)) { - needDetails = true; - break; - } - } - } - // iCal search, do not lookup details - if (iCalSearch) { - needDetails = false; - } for (ExchangeSession.Contact person : persons.values()) { if (abandon) { diff --git a/src/test/davmail/exchange/ews/TestEwsExchangeSession.java b/src/test/davmail/exchange/ews/TestEwsExchangeSession.java index 2142a19d..45e35822 100644 --- a/src/test/davmail/exchange/ews/TestEwsExchangeSession.java +++ b/src/test/davmail/exchange/ews/TestEwsExchangeSession.java @@ -48,20 +48,20 @@ public class TestEwsExchangeSession extends AbstractExchangeSessionTestCase { public void testGalFind() throws IOException { // find a set of contacts - Map contacts = ewsSession.galFind(ewsSession.startsWith("cn", "a")); + Map contacts = ewsSession.galFind(ewsSession.startsWith("cn", "a"), null, 100); for (ExchangeSession.Contact contact : contacts.values()) { System.out.println(contact); } if (!contacts.isEmpty()) { ExchangeSession.Contact testContact = contacts.values().iterator().next(); - contacts = ewsSession.galFind(ewsSession.isEqualTo("cn", testContact.get("cn"))); + contacts = ewsSession.galFind(ewsSession.isEqualTo("cn", testContact.get("cn")), null, 100); assertEquals(1, contacts.size()); - contacts = ewsSession.galFind(ewsSession.isEqualTo("email1", testContact.get("email1"))); + contacts = ewsSession.galFind(ewsSession.isEqualTo("email1", testContact.get("email1")), null, 100); assertEquals(1, contacts.size()); - contacts = ewsSession.galFind(ewsSession.startsWith("email1", testContact.get("email1"))); + contacts = ewsSession.galFind(ewsSession.startsWith("email1", testContact.get("email1")), null, 100); assertEquals(1, contacts.size()); contacts = ewsSession.galFind(ewsSession.and(ewsSession.isEqualTo("cn", testContact.get("cn")), - ewsSession.startsWith("email1", testContact.get("email1")))); + ewsSession.startsWith("email1", testContact.get("email1"))), null, 100); assertEquals(1, contacts.size()); } } diff --git a/src/test/davmail/ldap/TestLdap.java b/src/test/davmail/ldap/TestLdap.java index 28ef8638..605af57a 100644 --- a/src/test/davmail/ldap/TestLdap.java +++ b/src/test/davmail/ldap/TestLdap.java @@ -18,13 +18,15 @@ */ package davmail.ldap; -import davmail.AbstractDavMailTestCase; import davmail.DavGateway; import davmail.Settings; +import davmail.exchange.AbstractExchangeSessionTestCase; import davmail.exchange.ExchangeSessionFactory; import javax.naming.NamingEnumeration; import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; @@ -34,7 +36,7 @@ import java.util.Hashtable; /** * Test LDAP. */ -public class TestLdap extends AbstractDavMailTestCase { +public class TestLdap extends AbstractExchangeSessionTestCase { InitialLdapContext ldapContext; @Override @@ -83,4 +85,17 @@ public class TestLdap extends AbstractDavMailTestCase { searchControls.setReturningAttributes(new String[]{"custom1", "mozillausehtmlmail", "postalcode", "custom2", "custom3", "custom4", "street", "surname", "telephonenumber", "mozillahomelocalityname", "orgunit", "mozillaworkstreet2", "xmozillanickname", "mozillahomestreet", "description", "cellphone", "homeurl", "mozillahomepostalcode", "departmentnumber", "postofficebox", "st", "objectclass", "sn", "ou", "fax", "mozillahomeurl", "mozillahomecountryname", "streetaddress", "cn", "company", "mozillaworkurl", "mobile", "region", "birthmonth", "birthday", "labeleduri", "carphone", "department", "xmozillausehtmlmail", "givenname", "nsaimid", "workurl", "facsimiletelephonenumber", "mozillanickname", "title", "nscpaimscreenname", "xmozillasecondemail", "mozillacustom3", "countryname", "mozillacustom4", "mozillacustom1", "mozillacustom2", "homephone", "mozillasecondemail", "pager", "zip", "mail", "c", "mozillahomestate", "o", "l", "birthyear", "modifytimestamp", "locality", "commonname", "notes", "pagerphone", "mozillahomestreet2"}); NamingEnumeration searchResults = ldapContext.search("ou=people", "(objectclass=*)", searchControls); } + + public void testGalfind() throws NamingException { + SearchControls searchControls = new SearchControls(); + searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE); +// searchControls.setReturningAttributes(new String[]{"uid"}); + NamingEnumeration searchResults = ldapContext.search("ou=people", "(uid="+session.getAlias()+ ')', searchControls); + assertTrue(searchResults.hasMore()); + SearchResult searchResult = searchResults.next(); + Attributes attributes = searchResult.getAttributes(); + Attribute attribute = attributes.get("uid"); + assertEquals(session.getAlias(), attribute.get()); + assertNotNull(attributes.get("givenName")); + } }