LDAP: progress on EWS LDAP implementation and refactoring

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1332 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2010-08-09 20:15:28 +00:00
parent 19865c50b0
commit 905870f7da
6 changed files with 245 additions and 84 deletions

View File

@ -652,7 +652,7 @@ public abstract class ExchangeSession {
/** /**
* Test if the contact matches current condition. * Test if the contact matches current condition.
* *
* @param contact Exchange Contact * @param contact Exchange Contact
* @return true if contact matches condition * @return true if contact matches condition
*/ */
@ -676,6 +676,15 @@ public abstract class ExchangeSession {
public boolean isEmpty() { public boolean isEmpty() {
return false; return false;
} }
public String getAttributeName() {
return attributeName;
}
public String getValue() {
return value;
}
} }
/** /**
@ -736,7 +745,7 @@ public abstract class ExchangeSession {
return false; return false;
} }
} }
} }
/** /**
@ -776,15 +785,9 @@ public abstract class ExchangeSession {
public boolean isMatch(ExchangeSession.Contact contact) { public boolean isMatch(ExchangeSession.Contact contact) {
String actualValue = contact.get(attributeName); String actualValue = contact.get(attributeName);
if (operator == Operator.IsNull) { return (operator == Operator.IsNull && actualValue == null) ||
return actualValue == null; (operator == Operator.IsFalse && "false".equals(actualValue)) ||
} else if (operator == Operator.IsFalse) { (operator == Operator.IsTrue && "true".equals(actualValue));
return "false".equals(actualValue);
} else if (operator == Operator.IsTrue) {
return "true".equals(actualValue);
} else {
return false;
}
} }
} }
@ -1004,7 +1007,7 @@ public abstract class ExchangeSession {
Set<String> visibleRecipients = new HashSet<String>(); Set<String> visibleRecipients = new HashSet<String>();
Address[] recipients = mimeMessage.getAllRecipients(); Address[] recipients = mimeMessage.getAllRecipients();
for (Address address : recipients) { for (Address address : recipients) {
visibleRecipients.add(((InternetAddress)address).getAddress().toLowerCase()); visibleRecipients.add(((InternetAddress) address).getAddress().toLowerCase());
} }
for (String recipient : rcptToRecipients) { for (String recipient : rcptToRecipients) {
if (!visibleRecipients.contains(recipient.toLowerCase())) { if (!visibleRecipients.contains(recipient.toLowerCase())) {
@ -1732,6 +1735,10 @@ public abstract class ExchangeSession {
return name; return name;
} }
public void setName(String name) {
this.itemName = name;
}
/** /**
* Compute vcard uid from name. * Compute vcard uid from name.
* *
@ -2003,7 +2010,7 @@ public abstract class ExchangeSession {
// TODO: get current user attendee status, i18n // TODO: get current user attendee status, i18n
String subject = vCalendar.getFirstVeventPropertyValue("SUMMARY"); String subject = vCalendar.getFirstVeventPropertyValue("SUMMARY");
if (subject == null) { if (subject == null) {
subject = BundleMessage.format("MEETING_REQUEST"); subject = BundleMessage.format("MEETING_REQUEST");
} }
writer.writeHeader("Subject", subject); writer.writeHeader("Subject", subject);
@ -2809,6 +2816,8 @@ public abstract class ExchangeSession {
return results; return results;
} }
public abstract Map<String, Contact> galFind(Condition condition) throws IOException;
/** /**
* Full Contact attribute list * Full Contact attribute list
*/ */

View File

@ -25,6 +25,7 @@ import davmail.exception.DavMailException;
import davmail.exception.HttpNotFoundException; import davmail.exception.HttpNotFoundException;
import davmail.exchange.ExchangeSession; import davmail.exchange.ExchangeSession;
import davmail.exchange.VObject; import davmail.exchange.VObject;
import davmail.exchange.XMLStreamUtil;
import davmail.http.DavGatewayHttpClientFacade; import davmail.http.DavGatewayHttpClientFacade;
import davmail.ui.tray.DavGatewayTray; import davmail.ui.tray.DavGatewayTray;
import davmail.util.IOUtil; import davmail.util.IOUtil;
@ -176,6 +177,96 @@ public class DavExchangeSession extends ExchangeSession {
return !getFolderPath(folderPath).toLowerCase().startsWith(mailPath.toLowerCase()); return !getFolderPath(folderPath).toLowerCase().startsWith(mailPath.toLowerCase());
} }
/**
* LDAP to Exchange Criteria Map
*/
static final HashMap<String, String> GALFIND_CRITERIA_MAP = new HashMap<String, String>();
static {
GALFIND_CRITERIA_MAP.put("uid", "AN");
// assume mail starts with firstname
GALFIND_CRITERIA_MAP.put("smtpemail1", "FN");
GALFIND_CRITERIA_MAP.put("displayname", "DN");
GALFIND_CRITERIA_MAP.put("cn", "DN");
GALFIND_CRITERIA_MAP.put("givenname", "FN");
GALFIND_CRITERIA_MAP.put("sn", "LN");
GALFIND_CRITERIA_MAP.put("title", "TL");
GALFIND_CRITERIA_MAP.put("company", "CP");
GALFIND_CRITERIA_MAP.put("o", "CP");
GALFIND_CRITERIA_MAP.put("l", "OF");
GALFIND_CRITERIA_MAP.put("department", "DP");
GALFIND_CRITERIA_MAP.put("apple-group-realname", "DP");
}
/**
* Exchange to LDAP attribute map
*/
static final HashMap<String, String> GALFIND_ATTRIBUTE_MAP = new HashMap<String, String>();
static {
GALFIND_ATTRIBUTE_MAP.put("uid", "AN");
GALFIND_ATTRIBUTE_MAP.put("smtpemail1", "EM");
GALFIND_ATTRIBUTE_MAP.put("cn", "DN");
GALFIND_ATTRIBUTE_MAP.put("displayName", "DN");
GALFIND_ATTRIBUTE_MAP.put("telephoneNumber", "PH");
GALFIND_ATTRIBUTE_MAP.put("l", "OFFICE");
GALFIND_ATTRIBUTE_MAP.put("company", "CP");
GALFIND_ATTRIBUTE_MAP.put("title", "TL");
GALFIND_ATTRIBUTE_MAP.put("givenName", "first");
GALFIND_ATTRIBUTE_MAP.put("initials", "initials");
GALFIND_ATTRIBUTE_MAP.put("sn", "last");
GALFIND_ATTRIBUTE_MAP.put("street", "street");
GALFIND_ATTRIBUTE_MAP.put("st", "state");
GALFIND_ATTRIBUTE_MAP.put("postalCode", "zip");
GALFIND_ATTRIBUTE_MAP.put("c", "country");
GALFIND_ATTRIBUTE_MAP.put("departement", "department");
GALFIND_ATTRIBUTE_MAP.put("mobile", "mobile");
}
@Override
public Map<String, ExchangeSession.Contact> galFind(Condition condition) throws IOException {
Map<String, ExchangeSession.Contact> contacts = new HashMap<String, ExchangeSession.Contact>();
if (condition instanceof MultiCondition) {
// TODO
} else if (condition instanceof AttributeCondition) {
String searchAttribute = GALFIND_CRITERIA_MAP.get(((ExchangeSession.AttributeCondition) condition).getAttributeName());
if (searchAttribute != null) {
String searchValue = ((ExchangeSession.AttributeCondition) condition).getValue();
Map<String, Map<String, String>> results;
GetMethod getMethod = new GetMethod(URIUtil.encodePathQuery(getCmdBasePath() + "?Cmd=galfind&" + searchAttribute + '=' + searchValue));
try {
DavGatewayHttpClientFacade.executeGetMethod(httpClient, getMethod, true);
results = XMLStreamUtil.getElementContentsAsMap(getMethod.getResponseBodyAsStream(), "item", "AN");
} finally {
getMethod.releaseConnection();
}
LOGGER.debug("galfind " + searchAttribute + '=' + searchValue + ": " + results.size() + " result(s)");
for (Map<String, String> result:results.values()) {
Contact contact = buildGalfindContact(result);
if (condition.isMatch(contact)) {
contacts.put(contact.getName().toLowerCase(), contact);
}
}
}
}
return contacts;
}
protected Contact buildGalfindContact(Map<String, String> response) {
Contact contact = new Contact();
contact.setName(response.get("AN"));
contact.put("uid", response.get("AN"));
for (Map.Entry<String, String> entry : GALFIND_ATTRIBUTE_MAP.entrySet()) {
String attributeValue = response.get(entry.getValue());
if (attributeValue != null) {
contact.put(entry.getKey(), attributeValue);
}
}
return contact;
}
@Override @Override
protected String getFreeBusyData(String attendee, String start, String end, int interval) throws IOException { protected String getFreeBusyData(String attendee, String start, String end, int interval) throws IOException {
String freebusyUrl = publicFolderUrl + "/?cmd=freebusy" + String freebusyUrl = publicFolderUrl + "/?cmd=freebusy" +
@ -460,7 +551,7 @@ public class DavExchangeSession extends ExchangeSession {
if (operator == Operator.IsEqualTo) { if (operator == Operator.IsEqualTo) {
return actualValue.equals(lowerCaseValue); return actualValue.equals(lowerCaseValue);
} else if (operator == Operator.Like) { } else if (operator == Operator.Like) {
return actualValue.contains(lowerCaseValue); return actualValue.contains(lowerCaseValue);
} else if (operator == Operator.StartsWith) { } else if (operator == Operator.StartsWith) {
return actualValue.startsWith(lowerCaseValue); return actualValue.startsWith(lowerCaseValue);
} else { } else {
@ -619,6 +710,9 @@ public class DavExchangeSession extends ExchangeSession {
super(folderPath, itemName, properties, etag, noneMatch); super(folderPath, itemName, properties, etag, noneMatch);
} }
public Contact() {
}
protected Set<PropertyValue> buildProperties() { protected Set<PropertyValue> buildProperties() {
Set<PropertyValue> propertyValues = new HashSet<PropertyValue>(); Set<PropertyValue> propertyValues = new HashSet<PropertyValue>();
for (Map.Entry<String, String> entry : entrySet()) { for (Map.Entry<String, String> entry : entrySet()) {

View File

@ -553,8 +553,6 @@ public abstract class EWSMethod extends PostMethod {
public void checkSuccess() throws EWSException { public void checkSuccess() throws EWSException {
if (errorDetail != null) { if (errorDetail != null) {
if (!"ErrorAccessDenied".equals(errorDetail) if (!"ErrorAccessDenied".equals(errorDetail)
&& !"ErrorNameResolutionMultipleResults".equals(errorDetail)
&& !"ErrorNameResolutionNoResults".equals(errorDetail)
&& !"ErrorMailRecipientNotFound".equals(errorDetail)) { && !"ErrorMailRecipientNotFound".equals(errorDetail)) {
try { try {
throw new EWSException(errorDetail + "\n request: " + new String(generateSoapEnvelope(), "UTF-8")); throw new EWSException(errorDetail + "\n request: " + new String(generateSoapEnvelope(), "UTF-8"));
@ -633,7 +631,11 @@ public abstract class EWSMethod extends PostMethod {
protected void handleErrors(XMLStreamReader reader) throws XMLStreamException { protected void handleErrors(XMLStreamReader reader) throws XMLStreamException {
String result = handleTag(reader, "ResponseCode"); String result = handleTag(reader, "ResponseCode");
if (errorDetail == null && result != null && !"NoError".equals(result)) { if (errorDetail == null && result != null
&& !"NoError".equals(result)
&& !"ErrorNameResolutionMultipleResults".equals(result)
&& !"ErrorNameResolutionNoResults".equals(result)
) {
errorDetail = result; errorDetail = result;
} }
if (isStartTag(reader, "faultstring")) { if (isStartTag(reader, "faultstring")) {

View File

@ -361,10 +361,6 @@ public class EwsExchangeSession extends ExchangeSession {
return fieldURI; return fieldURI;
} }
protected String getValue() {
return value;
}
protected Operator getOperator() { protected Operator getOperator() {
return operator; return operator;
} }
@ -381,22 +377,24 @@ public class EwsExchangeSession extends ExchangeSession {
FieldURI fieldURI = getFieldURI(); FieldURI fieldURI = getFieldURI();
fieldURI.appendTo(buffer); fieldURI.appendTo(buffer);
buffer.append("<t:FieldURIOrConstant><t:Constant Value=\""); if (operator == Operator.IsEqualTo) {
buffer.append("<t:FieldURIOrConstant>");
}
buffer.append("<t:Constant Value=\"");
// encode urlcompname // encode urlcompname
if (fieldURI instanceof ExtendedFieldURI && "0x10f3".equals(((ExtendedFieldURI) fieldURI).propertyTag)) { if (fieldURI instanceof ExtendedFieldURI && "0x10f3".equals(((ExtendedFieldURI) fieldURI).propertyTag)) {
buffer.append(StringUtil.xmlEncode(StringUtil.encodeUrlcompname(value))); buffer.append(StringUtil.xmlEncode(StringUtil.encodeUrlcompname(value)));
} else { } else {
buffer.append(StringUtil.xmlEncode(value)); buffer.append(StringUtil.xmlEncode(value));
} }
buffer.append("\"/></t:FieldURIOrConstant>"); buffer.append("\"/>");
if (operator == Operator.IsEqualTo) {
buffer.append("</t:FieldURIOrConstant>");
}
buffer.append("</t:").append(operator.toString()).append('>'); buffer.append("</t:").append(operator.toString()).append('>');
} }
public String getAttributeName() {
return attributeName;
}
public boolean isMatch(ExchangeSession.Contact contact) { public boolean isMatch(ExchangeSession.Contact contact) {
String lowerCaseValue = value.toLowerCase(); String lowerCaseValue = value.toLowerCase();
@ -406,7 +404,7 @@ public class EwsExchangeSession extends ExchangeSession {
} }
actualValue = actualValue.toLowerCase(); actualValue = actualValue.toLowerCase();
if (operator == Operator.IsEqualTo) { if (operator == Operator.IsEqualTo) {
return value.equals(actualValue); return lowerCaseValue.equals(actualValue);
} else { } else {
return operator == Operator.Contains && ((containmentMode.equals(ContainmentMode.Substring) && actualValue.contains(lowerCaseValue)) || return operator == Operator.Contains && ((containmentMode.equals(ContainmentMode.Substring) && actualValue.contains(lowerCaseValue)) ||
(containmentMode.equals(ContainmentMode.Prefixed) && actualValue.startsWith(lowerCaseValue))); (containmentMode.equals(ContainmentMode.Prefixed) && actualValue.startsWith(lowerCaseValue)));
@ -711,7 +709,7 @@ public class EwsExchangeSession extends ExchangeSession {
} }
for (String attributeName : CONTACT_ATTRIBUTES) { for (String attributeName : CONTACT_ATTRIBUTES) {
String value = response.get(Field.get(attributeName).getResponseName()); String value = response.get(Field.get(attributeName).getResponseName());
if (value != null) { if (value != null && value.length() > 0) {
if ("bday".equals(attributeName) || "anniversary".equals(attributeName) || "lastmodified".equals(attributeName) || "datereceived".equals(attributeName)) { if ("bday".equals(attributeName) || "anniversary".equals(attributeName) || "lastmodified".equals(attributeName) || "datereceived".equals(attributeName)) {
value = convertDateFromExchange(value); value = convertDateFromExchange(value);
} }
@ -852,10 +850,6 @@ public class EwsExchangeSession extends ExchangeSession {
return itemResult; return itemResult;
} }
public void setName(String name) {
this.itemName = name;
}
} }
protected class Event extends ExchangeSession.Event { protected class Event extends ExchangeSession.Event {
@ -1264,17 +1258,19 @@ public class EwsExchangeSession extends ExchangeSession {
protected static final HashMap<String, String> GALFIND_ATTRIBUTE_MAP = new HashMap<String, String>(); protected static final HashMap<String, String> GALFIND_ATTRIBUTE_MAP = new HashMap<String, String>();
static { static {
GALFIND_ATTRIBUTE_MAP.put("uid", "Name");
GALFIND_ATTRIBUTE_MAP.put("cn", "DisplayName"); GALFIND_ATTRIBUTE_MAP.put("cn", "DisplayName");
GALFIND_ATTRIBUTE_MAP.put("givenName", "GivenName"); GALFIND_ATTRIBUTE_MAP.put("givenName", "GivenName");
GALFIND_ATTRIBUTE_MAP.put("sn", "Surname"); GALFIND_ATTRIBUTE_MAP.put("sn", "Surname");
GALFIND_ATTRIBUTE_MAP.put("email1", "EmailAddress1"); GALFIND_ATTRIBUTE_MAP.put("email1", "EmailAddress1");
GALFIND_ATTRIBUTE_MAP.put("email2", "EmailAddress1"); GALFIND_ATTRIBUTE_MAP.put("email2", "EmailAddress2");
GALFIND_ATTRIBUTE_MAP.put("email3", "EmailAddress1"); GALFIND_ATTRIBUTE_MAP.put("email3", "EmailAddress3");
} }
protected Contact buildGalfindContact(EWSMethod.Item response) { protected Contact buildGalfindContact(EWSMethod.Item response) {
Contact contact = new Contact(); Contact contact = new Contact();
contact.setName(response.get("DisplayName")); contact.setName(response.get("Name"));
contact.put("uid", response.get("Name"));
for (Map.Entry<String, String> entry : GALFIND_ATTRIBUTE_MAP.entrySet()) { for (Map.Entry<String, String> entry : GALFIND_ATTRIBUTE_MAP.entrySet()) {
String attributeValue = response.get(entry.getValue()); String attributeValue = response.get(entry.getValue());
if (attributeValue != null) { if (attributeValue != null) {
@ -1284,7 +1280,7 @@ public class EwsExchangeSession extends ExchangeSession {
return contact; return contact;
} }
protected Map<String, ExchangeSession.Contact> galFind(Condition condition) throws IOException { public Map<String, ExchangeSession.Contact> galFind(Condition condition) throws IOException {
Map<String, ExchangeSession.Contact> contacts = new HashMap<String, ExchangeSession.Contact>(); Map<String, ExchangeSession.Contact> contacts = new HashMap<String, ExchangeSession.Contact>();
if (condition instanceof MultiCondition) { if (condition instanceof MultiCondition) {
List<Condition> conditions = ((MultiCondition) condition).getConditions(); List<Condition> conditions = ((MultiCondition) condition).getConditions();
@ -1297,7 +1293,7 @@ public class EwsExchangeSession extends ExchangeSession {
Map<String, ExchangeSession.Contact> innerContacts = galFind(conditions.get(0)); Map<String, ExchangeSession.Contact> innerContacts = galFind(conditions.get(0));
for (ExchangeSession.Contact contact : innerContacts.values()) { for (ExchangeSession.Contact contact : innerContacts.values()) {
if (condition.isMatch(contact)) { if (condition.isMatch(contact)) {
contacts.put(contact.getName(), contact); contacts.put(contact.getName().toLowerCase(), contact);
} }
} }
} }
@ -1313,13 +1309,16 @@ public class EwsExchangeSession extends ExchangeSession {
if (operator == Operator.IsEqualTo) { if (operator == Operator.IsEqualTo) {
searchValue = '=' + searchValue; searchValue = '=' + searchValue;
} }
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("ResolveNames(" + searchValue + ')');
}
ResolveNamesMethod resolveNamesMethod = new ResolveNamesMethod(searchValue); ResolveNamesMethod resolveNamesMethod = new ResolveNamesMethod(searchValue);
executeMethod(resolveNamesMethod); executeMethod(resolveNamesMethod);
List<EWSMethod.Item> responses = resolveNamesMethod.getResponseItems(); List<EWSMethod.Item> responses = resolveNamesMethod.getResponseItems();
for (EWSMethod.Item response : responses) { for (EWSMethod.Item response : responses) {
Contact contact = buildGalfindContact(response); Contact contact = buildGalfindContact(response);
if (condition.isMatch(contact)) { if (condition.isMatch(contact)) {
contacts.put(contact.getName(), contact); contacts.put(contact.getName().toLowerCase(), contact);
} }
} }
} }

View File

@ -45,24 +45,74 @@ public class ResolveNamesMethod extends EWSMethod {
Item responseItem = new Item(); Item responseItem = new Item();
responseItem.type = "Contact"; responseItem.type = "Contact";
// skip to Contact // skip to Contact
while (reader.hasNext() && !isStartTag(reader, "Contact")) { while (reader.hasNext() && !isStartTag(reader, "Resolution")) {
reader.next(); reader.next();
} }
while (reader.hasNext() && !isEndTag(reader, "Contact")) { while (reader.hasNext() && !isEndTag(reader, "Resolution")) {
int event = reader.next(); int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT) { if (event == XMLStreamConstants.START_ELEMENT) {
String tagLocalName = reader.getLocalName(); String tagLocalName = reader.getLocalName();
if ("EmailAddresses".equals(tagLocalName)) { if ("Mailbox".equals(tagLocalName)) {
handleAddresses(reader, responseItem); handleMailbox(reader, responseItem);
} else { } else if ("Contact".equals(tagLocalName)) {
responseItem.put(tagLocalName, reader.getElementText()); handleContact(reader, responseItem);
} }
} }
} }
return responseItem; return responseItem;
} }
protected void handleAddresses(XMLStreamReader reader, Item responseItem) throws XMLStreamException { protected void handleMailbox(XMLStreamReader reader, Item responseItem) throws XMLStreamException {
while (reader.hasNext() && !isEndTag(reader, "Mailbox")) {
int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT) {
String tagLocalName = reader.getLocalName();
if ("Name".equals(tagLocalName)) {
responseItem.put(tagLocalName, reader.getElementText());
}
}
}
}
protected void handleContact(XMLStreamReader reader, Item responseItem) throws XMLStreamException {
while (reader.hasNext() && !isEndTag(reader, "Contact")) {
int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT) {
String tagLocalName = reader.getLocalName();
if ("EmailAddresses".equals(tagLocalName)) {
handleEmailAddresses(reader, responseItem);
} else if ("PhysicalAddresses".equals(tagLocalName)) {
handlePhysicalAddresses(reader, responseItem);
} else if ("PhoneNumbers".equals(tagLocalName)) {
handlePhoneNumbers(reader, responseItem);
} else {
responseItem.put(tagLocalName, reader.getElementText());
}
}
}
}
protected void handlePhysicalAddresses(XMLStreamReader reader, Item responseItem) throws XMLStreamException {
while (reader.hasNext() && !isEndTag(reader, "PhysicalAddresses")) {
int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT) {
String tagLocalName = reader.getLocalName();
// TODO
}
}
}
protected void handlePhoneNumbers(XMLStreamReader reader, Item responseItem) throws XMLStreamException {
while (reader.hasNext() && !isEndTag(reader, "PhoneNumbers")) {
int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT) {
String tagLocalName = reader.getLocalName();
// TODO
}
}
}
protected void handleEmailAddresses(XMLStreamReader reader, Item responseItem) throws XMLStreamException {
while (reader.hasNext() && !isEndTag(reader, "EmailAddresses")) { while (reader.hasNext() && !isEndTag(reader, "EmailAddresses")) {
int event = reader.next(); int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT) { if (event == XMLStreamConstants.START_ELEMENT) {

View File

@ -105,8 +105,8 @@ public class LdapConnection extends AbstractConnection {
CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("extensionattribute2", "custom2"); CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("extensionattribute2", "custom2");
CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("extensionattribute3", "custom3"); CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("extensionattribute3", "custom3");
CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("extensionattribute4", "custom4"); CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("extensionattribute4", "custom4");
CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("email1", "mail"); CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("smtpemail1", "mail");
CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("email2", "xmozillasecondemail"); CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("smtpemail2", "xmozillasecondemail");
CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("homeCountry", "mozillahomecountryname"); CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("homeCountry", "mozillahomecountryname");
CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("homeCity", "mozillahomelocalityname"); CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("homeCity", "mozillahomelocalityname");
CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("homePostalCode", "mozillahomepostalcode"); CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("homePostalCode", "mozillahomepostalcode");
@ -225,7 +225,7 @@ public class LdapConnection extends AbstractConnection {
static { static {
LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("uid", "imapUid"); LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("uid", "imapUid");
LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("mail", "email1"); LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("mail", "smtpemail1");
LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("displayname", "cn"); LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("displayname", "cn");
LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("commonname", "cn"); LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("commonname", "cn");
@ -846,7 +846,7 @@ public class LdapConnection extends AbstractConnection {
static interface LdapFilter { static interface LdapFilter {
ExchangeSession.Condition getContactSearchFilter(); ExchangeSession.Condition getContactSearchFilter();
Map<String, Map<String, String>> findInGAL(ExchangeSession session) throws IOException; Map<String, ExchangeSession.Contact> findInGAL(ExchangeSession session) throws IOException;
void add(LdapFilter filter); void add(LdapFilter filter);
@ -973,11 +973,11 @@ public class LdapConnection extends AbstractConnection {
* @return persons map * @return persons map
* @throws IOException on error * @throws IOException on error
*/ */
public Map<String, Map<String, String>> findInGAL(ExchangeSession session) throws IOException { public Map<String, ExchangeSession.Contact> findInGAL(ExchangeSession session) throws IOException {
Map<String, Map<String, String>> persons = null; Map<String, ExchangeSession.Contact> persons = null;
for (LdapFilter child : criteria) { for (LdapFilter child : criteria) {
Map<String, Map<String, String>> childFind = child.findInGAL(session); Map<String, ExchangeSession.Contact> childFind = child.findInGAL(session);
if (childFind != null) { if (childFind != null) {
if (persons == null) { if (persons == null) {
@ -992,10 +992,10 @@ public class LdapConnection extends AbstractConnection {
// Thus, instead of building the intersection, we check each result against // Thus, instead of building the intersection, we check each result against
// all filters. // all filters.
for (Map<String, String> result : childFind.values()) { for (ExchangeSession.Contact result : childFind.values()) {
if (isMatch(result)) { if (isMatch(result)) {
// This item from the child result set matches all sub-criteria, add it // This item from the child result set matches all sub-criteria, add it
persons.put(result.get("AN"), result); persons.put(result.get("uid"), result);
} }
} }
} }
@ -1004,7 +1004,7 @@ public class LdapConnection extends AbstractConnection {
if ((persons == null) && !isFullSearch()) { if ((persons == null) && !isFullSearch()) {
// return an empty map (indicating no results were found) // return an empty map (indicating no results were found)
return new HashMap<String, Map<String, String>>(); return new HashMap<String, ExchangeSession.Contact>();
} }
return persons; return persons;
@ -1139,7 +1139,7 @@ public class LdapConnection extends AbstractConnection {
return false; return false;
} }
public Map<String, Map<String, String>> findInGAL(ExchangeSession session) throws IOException { public Map<String, ExchangeSession.Contact> findInGAL(ExchangeSession session) throws IOException {
if (canIgnore) { if (canIgnore) {
return null; return null;
} }
@ -1148,17 +1148,17 @@ public class LdapConnection extends AbstractConnection {
if (galFindAttributeName != null) { if (galFindAttributeName != null) {
// quick fix for cn=* filter // quick fix for cn=* filter
Map<String, Map<String, String>> galPersons = session.galFind(galFindAttributeName, "*".equals(value) ? "A" : value); Map<String, ExchangeSession.Contact> galPersons = session.galFind(session.startsWith(attributeName, "*".equals(value) ? "A" : value));
if (operator == LDAP_FILTER_EQUALITY) { if (operator == LDAP_FILTER_EQUALITY) {
// Make sure only exact matches are returned // Make sure only exact matches are returned
Map<String, Map<String, String>> results = new HashMap<String, Map<String, String>>(); Map<String, ExchangeSession.Contact> results = new HashMap<String, ExchangeSession.Contact>();
for (Map<String, String> person : galPersons.values()) { for (ExchangeSession.Contact person : galPersons.values()) {
if (isMatch(person)) { if (isMatch(person)) {
// Found an exact match // Found an exact match
results.put(person.get("AN"), person); results.put(person.get("uid"), person);
} }
} }
@ -1213,9 +1213,9 @@ public class LdapConnection extends AbstractConnection {
protected static String getLdapAttributeName(String contactAttributeName) { protected static String getLdapAttributeName(String contactAttributeName) {
String mappedAttributeName = CONTACT_TO_LDAP_ATTRIBUTE_MAP.get(contactAttributeName); String mappedAttributeName = CONTACT_TO_LDAP_ATTRIBUTE_MAP.get(contactAttributeName);
if (mappedAttributeName != null) { if (mappedAttributeName != null) {
return contactAttributeName;
} else {
return mappedAttributeName; return mappedAttributeName;
} else {
return contactAttributeName;
} }
} }
@ -1265,7 +1265,7 @@ public class LdapConnection extends AbstractConnection {
if (session != null) { if (session != null) {
// single user request // single user request
String uid = dn.substring("uid=".length(), dn.indexOf(',')); String uid = dn.substring("uid=".length(), dn.indexOf(','));
Map<String, Map<String, String>> persons = null; Map<String, ExchangeSession.Contact> persons = null;
// first search in contact // first search in contact
try { try {
@ -1278,12 +1278,12 @@ public class LdapConnection extends AbstractConnection {
// then in GAL // then in GAL
if (persons == null || persons.isEmpty()) { if (persons == null || persons.isEmpty()) {
persons = session.galFind("AN", uid); persons = session.galFind(session.isEqualTo("uid", uid));
Map<String, String> person = persons.get(uid.toLowerCase()); ExchangeSession.Contact person = persons.get(uid.toLowerCase());
// filter out non exact results // filter out non exact results
if (persons.size() > 1 || person == null) { if (persons.size() > 1 || person == null) {
persons = new HashMap<String, Map<String, String>>(); persons = new HashMap<String, ExchangeSession.Contact>();
if (person != null) { if (person != null) {
persons.put(uid.toLowerCase(), person); persons.put(uid.toLowerCase(), person);
} }
@ -1303,10 +1303,10 @@ public class LdapConnection extends AbstractConnection {
sendComputerContext(currentMessageId, returningAttributes); sendComputerContext(currentMessageId, returningAttributes);
} else if ((BASE_CONTEXT.equalsIgnoreCase(dn) || OD_USER_CONTEXT.equalsIgnoreCase(dn))) { } else if ((BASE_CONTEXT.equalsIgnoreCase(dn) || OD_USER_CONTEXT.equalsIgnoreCase(dn))) {
if (session != null) { if (session != null) {
Map<String, Map<String, String>> persons = new HashMap<String, Map<String, String>>(); Map<String, ExchangeSession.Contact> persons = new HashMap<String, ExchangeSession.Contact>();
if (ldapFilter.isFullSearch()) { if (ldapFilter.isFullSearch()) {
// append personal contacts first // append personal contacts first
for (Map<String, String> person : contactFind(null, returningAttributes, sizeLimit).values()) { for (ExchangeSession.Contact person : contactFind(null, returningAttributes, sizeLimit).values()) {
persons.put(person.get("imapUid"), person); persons.put(person.get("imapUid"), person);
if (persons.size() == sizeLimit) { if (persons.size() == sizeLimit) {
break; break;
@ -1315,8 +1315,8 @@ public class LdapConnection extends AbstractConnection {
// full search // full search
for (char c = 'A'; c < 'Z'; c++) { for (char c = 'A'; c < 'Z'; c++) {
if (!abandon && persons.size() < sizeLimit) { if (!abandon && persons.size() < sizeLimit) {
for (Map<String, String> person : session.galFind("AN", String.valueOf(c)).values()) { for (ExchangeSession.Contact person : session.galFind(session.startsWith("uid", String.valueOf(c))).values()) {
persons.put(person.get("AN"), person); persons.put(person.get("uid"), person);
if (persons.size() == sizeLimit) { if (persons.size() == sizeLimit) {
break; break;
} }
@ -1333,7 +1333,7 @@ public class LdapConnection extends AbstractConnection {
// if ldapfilter is not a full search and filter is null, // if ldapfilter is not a full search and filter is null,
// ignored all attribute filters => return empty results // ignored all attribute filters => return empty results
if (ldapFilter.isFullSearch() || filter != null) { if (ldapFilter.isFullSearch() || filter != null) {
for (Map<String, String> person : contactFind(filter, returningAttributes, sizeLimit).values()) { for (ExchangeSession.Contact person : contactFind(filter, returningAttributes, sizeLimit).values()) {
persons.put(person.get("imapUid"), person); persons.put(person.get("imapUid"), person);
if (persons.size() == sizeLimit) { if (persons.size() == sizeLimit) {
@ -1341,12 +1341,12 @@ public class LdapConnection extends AbstractConnection {
} }
} }
if (!abandon && persons.size() < sizeLimit) { if (!abandon && persons.size() < sizeLimit) {
for (Map<String, String> person : ldapFilter.findInGAL(session).values()) { for (ExchangeSession.Contact person : ldapFilter.findInGAL(session).values()) {
if (persons.size() == sizeLimit) { if (persons.size() == sizeLimit) {
break; break;
} }
persons.put(person.get("AN"), person); persons.put(person.get("uid"), person);
} }
} }
} }
@ -1399,7 +1399,7 @@ public class LdapConnection extends AbstractConnection {
* @return List of users * @return List of users
* @throws IOException on error * @throws IOException on error
*/ */
public Map<String, Map<String, String>> contactFind(ExchangeSession.Condition condition, Set<String> returningAttributes, int maxCount) throws IOException { public Map<String, ExchangeSession.Contact> contactFind(ExchangeSession.Condition condition, Set<String> returningAttributes, int maxCount) throws IOException {
Set<String> contactReturningAttributes; Set<String> contactReturningAttributes;
if (returningAttributes != null && !returningAttributes.isEmpty()) { if (returningAttributes != null && !returningAttributes.isEmpty()) {
contactReturningAttributes = new HashSet<String>(); contactReturningAttributes = new HashSet<String>();
@ -1415,13 +1415,17 @@ public class LdapConnection extends AbstractConnection {
contactReturningAttributes = ExchangeSession.CONTACT_ATTRIBUTES; contactReturningAttributes = ExchangeSession.CONTACT_ATTRIBUTES;
} }
Map<String, Map<String, String>> results = new HashMap<String, Map<String, String>>(); Map<String, ExchangeSession.Contact> results = new HashMap<String, ExchangeSession.Contact>();
List<ExchangeSession.Contact> contacts = session.searchContacts(ExchangeSession.CONTACTS, contactReturningAttributes, condition, maxCount); List<ExchangeSession.Contact> contacts = session.searchContacts(ExchangeSession.CONTACTS, contactReturningAttributes, condition, maxCount);
for (ExchangeSession.Contact contact : contacts) { for (ExchangeSession.Contact contact : contacts) {
if (contact.get("imapUid") != null) { // use imapUid as uid
results.put(contact.get("imapUid"), contact); String imapUid = contact.get("imapUid");
if (imapUid != null) {
contact.put("uid", imapUid);
contact.remove("imapUid");
results.put(imapUid, contact);
} }
} }
@ -1438,7 +1442,7 @@ public class LdapConnection extends AbstractConnection {
* @param returningAttributes returning attributes * @param returningAttributes returning attributes
* @throws IOException on error * @throws IOException on error
*/ */
protected void sendPersons(int currentMessageId, String baseContext, Map<String, Map<String, String>> persons, Set<String> returningAttributes) throws IOException { protected void sendPersons(int currentMessageId, String baseContext, Map<String, ExchangeSession.Contact> persons, Set<String> returningAttributes) throws IOException {
boolean needObjectClasses = returningAttributes.contains("objectclass") || returningAttributes.isEmpty(); boolean needObjectClasses = returningAttributes.contains("objectclass") || returningAttributes.isEmpty();
boolean iCalSearch = returningAttributes.contains("apple-serviceslocator"); boolean iCalSearch = returningAttributes.contains("apple-serviceslocator");
boolean returnAllAttributes = returningAttributes.isEmpty(); boolean returnAllAttributes = returningAttributes.isEmpty();
@ -1456,16 +1460,16 @@ public class LdapConnection extends AbstractConnection {
needDetails = false; needDetails = false;
} }
for (Map<String, String> person : persons.values()) { for (ExchangeSession.Contact person : persons.values()) {
if (abandon) { if (abandon) {
break; break;
} }
returningAttributes.add("uid");
Map<String, Object> ldapPerson = new HashMap<String, Object>(); Map<String, Object> ldapPerson = new HashMap<String, Object>();
// convert GAL entries // convert GAL entries
if (person.get("AN") != null) { /*if (person.get("uid") != null) {
// TODO: move to galFind
// add detailed information, only for GAL entries // add detailed information, only for GAL entries
if (needDetails) { if (needDetails) {
session.galLookup(person); session.galLookup(person);
@ -1484,13 +1488,14 @@ public class LdapConnection extends AbstractConnection {
ldapPerson.put(ldapAttribute, value); ldapPerson.put(ldapAttribute, value);
} }
} }
// TODO
// iCal fix to suit both iCal 3 and 4: move cn to sn, remove cn // iCal fix to suit both iCal 3 and 4: move cn to sn, remove cn
if (iCalSearch && ldapPerson.get("cn") != null && returningAttributes.contains("sn")) { if (iCalSearch && ldapPerson.get("cn") != null && returningAttributes.contains("sn")) {
ldapPerson.put("sn", ldapPerson.get("cn")); ldapPerson.put("sn", ldapPerson.get("cn"));
ldapPerson.remove("cn"); ldapPerson.remove("cn");
} }
} else { } else {*/
// convert Contact entries // convert Contact entries
if (returnAllAttributes) { if (returnAllAttributes) {
// just convert contact attributes to default ldap names // just convert contact attributes to default ldap names
@ -1502,6 +1507,8 @@ public class LdapConnection extends AbstractConnection {
} }
} }
} else { } else {
// always map uid
ldapPerson.put("uid", person.get("uid"));
// iterate over requested attributes // iterate over requested attributes
for (String ldapAttribute : returningAttributes) { for (String ldapAttribute : returningAttributes) {
String contactAttribute = getContactAttributeName(ldapAttribute); String contactAttribute = getContactAttributeName(ldapAttribute);
@ -1528,7 +1535,7 @@ public class LdapConnection extends AbstractConnection {
} }
} }
} //}
// Process all attributes which have static mappings // Process all attributes which have static mappings
for (Map.Entry<String, String> entry : STATIC_ATTRIBUTE_MAP.entrySet()) { for (Map.Entry<String, String> entry : STATIC_ATTRIBUTE_MAP.entrySet()) {