mirror of
https://github.com/moparisthebest/davmail
synced 2024-12-13 19:22:22 -05:00
LDAP: use PR_SEARCH_KEY instead of DAV:uid as uid string
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1115 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
6d2fecdd9a
commit
3320d19494
@ -89,7 +89,7 @@ public abstract class ExchangeSession {
|
||||
|
||||
protected static final String PUBLIC_ROOT = "/public";
|
||||
protected static final String CALENDAR = "calendar";
|
||||
protected static final String CONTACTS = "contacts";
|
||||
public static final String CONTACTS = "contacts";
|
||||
protected static final String ADDRESSBOOK = "addressbook";
|
||||
protected static final String INBOX = "INBOX";
|
||||
protected static final String LOWER_CASE_INBOX = "inbox";
|
||||
@ -513,7 +513,7 @@ public abstract class ExchangeSession {
|
||||
*/
|
||||
protected abstract BufferedReader getContentReader(Message message) throws IOException;
|
||||
|
||||
protected static final List<String> POP_MESSAGE_ATTRIBUTES = new ArrayList<String>();
|
||||
protected static final Set<String> POP_MESSAGE_ATTRIBUTES = new HashSet<String>();
|
||||
|
||||
static {
|
||||
POP_MESSAGE_ATTRIBUTES.add("uid");
|
||||
@ -531,7 +531,7 @@ public abstract class ExchangeSession {
|
||||
return searchMessages(folderName, POP_MESSAGE_ATTRIBUTES, null);
|
||||
}
|
||||
|
||||
protected static final List<String> IMAP_MESSAGE_ATTRIBUTES = new ArrayList<String>();
|
||||
protected static final Set<String> IMAP_MESSAGE_ATTRIBUTES = new HashSet<String>();
|
||||
|
||||
static {
|
||||
IMAP_MESSAGE_ATTRIBUTES.add("uid");
|
||||
@ -546,7 +546,7 @@ public abstract class ExchangeSession {
|
||||
IMAP_MESSAGE_ATTRIBUTES.add("date");
|
||||
}
|
||||
|
||||
protected static final List<String> UID_MESSAGE_ATTRIBUTES = new ArrayList<String>();
|
||||
protected static final Set<String> UID_MESSAGE_ATTRIBUTES = new HashSet<String>();
|
||||
|
||||
static {
|
||||
UID_MESSAGE_ATTRIBUTES.add("uid");
|
||||
@ -584,7 +584,7 @@ public abstract class ExchangeSession {
|
||||
* @return message list
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public abstract MessageList searchMessages(String folderName, List<String> attributes, Condition condition) throws IOException;
|
||||
public abstract MessageList searchMessages(String folderName, Set<String> attributes, Condition condition) throws IOException;
|
||||
|
||||
protected enum Operator {
|
||||
Or, And, Not, IsEqualTo, IsGreaterThan, IsGreaterThanOrEqualTo, IsLessThan, IsNull, IsTrue, IsFalse,
|
||||
@ -1701,7 +1701,7 @@ public abstract class ExchangeSession {
|
||||
writer.appendProperty("FN", get("cn"));
|
||||
// RFC 2426: Family Name, Given Name, Additional Names, Honorific Prefixes, and Honorific Suffixes
|
||||
writer.appendProperty("N", get("sn"), get("givenName"), get("middlename"), get("personaltitle"), get("namesuffix"));
|
||||
|
||||
|
||||
writer.appendProperty("TEL;TYPE=cell", get("mobile"));
|
||||
writer.appendProperty("TEL;TYPE=work", get("telephoneNumber"));
|
||||
writer.appendProperty("TEL;TYPE=home", get("homePhone"));
|
||||
@ -1741,13 +1741,12 @@ public abstract class ExchangeSession {
|
||||
writer.appendProperty("X-EVOLUTION-SPOUSE", get("spousecn"));
|
||||
|
||||
|
||||
|
||||
String lastModified = get("lastmodified");
|
||||
if (lastModified != null) {
|
||||
try {
|
||||
writer.appendProperty("REV", getZuluDateFormat().format(getExchangeZuluDateFormatMillisecond().parse(lastModified)));
|
||||
} catch (ParseException e) {
|
||||
LOGGER.warn("Invalid date: "+lastModified);
|
||||
LOGGER.warn("Invalid date: " + lastModified);
|
||||
}
|
||||
}
|
||||
writer.endCard();
|
||||
@ -2392,7 +2391,7 @@ public abstract class ExchangeSession {
|
||||
|
||||
}
|
||||
|
||||
public static final List<String> ITEM_PROPERTIES = new ArrayList<String>();
|
||||
public static final Set<String> ITEM_PROPERTIES = new HashSet<String>();
|
||||
|
||||
static {
|
||||
ITEM_PROPERTIES.add("etag");
|
||||
@ -2422,7 +2421,7 @@ public abstract class ExchangeSession {
|
||||
* @return list of contacts
|
||||
* @throws IOException on error
|
||||
*/
|
||||
protected abstract List<Contact> searchContacts(String folderPath, List<String> attributes, Condition condition) throws IOException;
|
||||
public abstract List<Contact> searchContacts(String folderPath, Set<String> attributes, Condition condition) throws IOException;
|
||||
|
||||
/**
|
||||
* Search calendar messages in provided folder.
|
||||
@ -2478,7 +2477,7 @@ public abstract class ExchangeSession {
|
||||
* @return list of calendar messages as Event objects
|
||||
* @throws IOException on error
|
||||
*/
|
||||
protected abstract List<Event> searchEvents(String folderPath, List<String> attributes, Condition condition) throws IOException;
|
||||
protected abstract List<Event> searchEvents(String folderPath, Set<String> attributes, Condition condition) throws IOException;
|
||||
|
||||
/**
|
||||
* convert vcf extension to EML.
|
||||
@ -2858,18 +2857,7 @@ public abstract class ExchangeSession {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search users in contacts folder by uid.
|
||||
*
|
||||
* @param uid unique id
|
||||
* @return List of users
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public Map<String, Map<String, String>> contactFindByUid(String uid) throws IOException {
|
||||
return contactFind(equals("uid", uid));
|
||||
}
|
||||
|
||||
protected static final List<String> CONTACT_ATTRIBUTES = new ArrayList<String>();
|
||||
public static final Set<String> CONTACT_ATTRIBUTES = new HashSet<String>();
|
||||
|
||||
static {
|
||||
CONTACT_ATTRIBUTES.add("uid");
|
||||
@ -2919,87 +2907,6 @@ public abstract class ExchangeSession {
|
||||
CONTACT_ATTRIBUTES.add("lastmodified");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search users in contacts folder
|
||||
*
|
||||
* @param condition search filter
|
||||
* @return List of users
|
||||
* @throws IOException on error
|
||||
*/
|
||||
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) {
|
||||
int uidEnd = searchFilter.indexOf('\'', uidStart + DAV_UID_FILTER.length());
|
||||
if (uidEnd >= 0) {
|
||||
try {
|
||||
filterUid = searchFilter.substring(uidStart + DAV_UID_FILTER.length(), uidEnd);
|
||||
actualFilterUid = new String(Base64.encodeBase64(Hex.decodeHex(filterUid.toCharArray())));
|
||||
searchFilter = searchFilter.substring(0, uidStart + DAV_UID_FILTER.length()) + actualFilterUid + searchFilter.substring(uidEnd);
|
||||
} catch (DecoderException e) {
|
||||
// ignore, this is not an hex uid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Map<String, Map<String, String>> results = new HashMap<String, Map<String, String>>();
|
||||
|
||||
List<Contact> contacts = searchContacts(CONTACTS, CONTACT_ATTRIBUTES, and(equals("outlookmessageclass", "IPM.Contact"), condition));
|
||||
|
||||
Map<String, String> item;
|
||||
for (Contact contact : contacts) {
|
||||
item = new HashMap<String, String>();
|
||||
|
||||
for (Map.Entry<String, String> contactEntry : contact.entrySet()) {
|
||||
String propertyName = contactEntry.getKey();
|
||||
String propertyValue = contactEntry.getValue();
|
||||
if ("uid".equals(propertyName)) {
|
||||
// TODO: move to LDAP ?
|
||||
// uid is base64, reencode to hex
|
||||
propertyValue = new String(Hex.encodeHex(Base64.decodeBase64(propertyValue.getBytes())));
|
||||
// if actualFilterUid is not null, exclude non exact match
|
||||
if (actualFilterUid != null && !filterUid.equals(propertyValue)) {
|
||||
propertyValue = null;
|
||||
}
|
||||
} else if ("bday".equals(propertyName)) {
|
||||
SimpleDateFormat parser = getExchangeZuluDateFormatMillisecond();
|
||||
try {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(parser.parse(propertyValue));
|
||||
item.put("birthday", String.valueOf(calendar.get(Calendar.DAY_OF_MONTH)));
|
||||
item.put("birthmonth", String.valueOf(calendar.get(Calendar.MONTH) + 1));
|
||||
item.put("birthyear", String.valueOf(calendar.get(Calendar.YEAR)));
|
||||
propertyValue = null;
|
||||
} catch (ParseException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
} else if ("textdescription".equals(propertyName) && " \n".equals(propertyValue)) {
|
||||
propertyValue = null;
|
||||
}
|
||||
if (propertyValue != null && propertyValue.length() > 0) {
|
||||
item.put(propertyName, propertyValue);
|
||||
}
|
||||
}
|
||||
if (item.get("uid") != null) {
|
||||
results.put(item.get("uid"), item);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.debug("contactFind: " + results.size() + " result(s)");
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extended address book information for person with gallookup.
|
||||
* Does not work with Exchange 2007
|
||||
|
@ -117,6 +117,10 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
exchangeFolderPath = mailPath + draftsName + folderPath.substring(DRAFTS.length());
|
||||
} else if (folderPath.startsWith(SENT)) {
|
||||
exchangeFolderPath = mailPath + sentitemsName + folderPath.substring(SENT.length());
|
||||
} else if (folderPath.startsWith(CONTACTS)) {
|
||||
exchangeFolderPath = mailPath + contactsName + folderPath.substring(CONTACTS.length());
|
||||
} else if (folderPath.startsWith(CALENDAR)) {
|
||||
exchangeFolderPath = mailPath + calendarName + folderPath.substring(CALENDAR.length());
|
||||
} else if (folderPath.startsWith("public")) {
|
||||
exchangeFolderPath = publicFolderUrl + folderPath.substring("public".length());
|
||||
|
||||
@ -415,9 +419,13 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
}
|
||||
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
buffer.append('"').append(Field.get(attributeName).getUri()).append('"');
|
||||
Field field = Field.get(attributeName);
|
||||
buffer.append('"').append(field.getUri()).append('"');
|
||||
buffer.append(operatorMap.get(operator));
|
||||
if (!isIntValue) {
|
||||
//noinspection VariableNotUsedInsideIf
|
||||
if (field.cast != null) {
|
||||
buffer.append("CAST (\"");
|
||||
} else if (!isIntValue) {
|
||||
buffer.append('\'');
|
||||
}
|
||||
if (Operator.Like == operator) {
|
||||
@ -427,7 +435,9 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
if (Operator.Like == operator || Operator.StartsWith == operator) {
|
||||
buffer.append('%');
|
||||
}
|
||||
if (!isIntValue) {
|
||||
if (field.cast != null) {
|
||||
buffer.append("\" as '").append(field.cast).append("')");
|
||||
} else if (!isIntValue) {
|
||||
buffer.append('\'');
|
||||
}
|
||||
}
|
||||
@ -901,7 +911,7 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
return folder;
|
||||
}
|
||||
|
||||
protected static final List<String> FOLDER_PROPERTIES = new ArrayList<String>();
|
||||
protected static final Set<String> FOLDER_PROPERTIES = new HashSet<String>();
|
||||
|
||||
static {
|
||||
FOLDER_PROPERTIES.add("displayname");
|
||||
@ -1082,7 +1092,7 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageList searchMessages(String folderPath, List<String> attributes, Condition condition) throws IOException {
|
||||
public MessageList searchMessages(String folderPath, Set<String> attributes, Condition condition) throws IOException {
|
||||
MessageList messages = new MessageList();
|
||||
MultiStatusResponse[] responses = searchItems(folderPath, attributes, and(isFalse("isfolder"), isFalse("ishidden"), condition), FolderQueryTraversal.Shallow);
|
||||
|
||||
@ -1099,9 +1109,11 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
protected List<ExchangeSession.Contact> searchContacts(String folderPath, List<String> attributes, Condition condition) throws IOException {
|
||||
public List<ExchangeSession.Contact> searchContacts(String folderPath, Set<String> attributes, Condition condition) throws IOException {
|
||||
List<ExchangeSession.Contact> contacts = new ArrayList<ExchangeSession.Contact>();
|
||||
MultiStatusResponse[] responses = searchItems(folderPath, attributes, and(isFalse("isfolder"), isFalse("ishidden"), condition), FolderQueryTraversal.Shallow);
|
||||
MultiStatusResponse[] responses = searchItems(folderPath, attributes,
|
||||
and(equals("outlookmessageclass", "IPM.Contact"), isFalse("isfolder"), isFalse("ishidden"), condition),
|
||||
FolderQueryTraversal.Shallow);
|
||||
for (MultiStatusResponse response : responses) {
|
||||
contacts.add(new Contact(response));
|
||||
}
|
||||
@ -1109,7 +1121,7 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ExchangeSession.Event> searchEvents(String folderPath, List<String> attributes, Condition condition) throws IOException {
|
||||
protected List<ExchangeSession.Event> searchEvents(String folderPath, Set<String> attributes, Condition condition) throws IOException {
|
||||
List<ExchangeSession.Event> events = new ArrayList<ExchangeSession.Event>();
|
||||
MultiStatusResponse[] responses = searchItems(folderPath, attributes, and(isFalse("isfolder"), isFalse("ishidden"), condition), FolderQueryTraversal.Shallow);
|
||||
for (MultiStatusResponse response : responses) {
|
||||
@ -1133,7 +1145,7 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
return events;
|
||||
}
|
||||
|
||||
protected MultiStatusResponse[] searchItems(String folderPath, List<String> attributes, Condition condition, FolderQueryTraversal folderQueryTraversal) throws IOException {
|
||||
protected MultiStatusResponse[] searchItems(String folderPath, Set<String> attributes, Condition condition, FolderQueryTraversal folderQueryTraversal) throws IOException {
|
||||
String folderUrl = getFolderPath(folderPath);
|
||||
StringBuilder searchRequest = new StringBuilder();
|
||||
searchRequest.append("SELECT ")
|
||||
@ -1237,7 +1249,7 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
if ("urn:content-classes:person".equals(contentClass)) {
|
||||
// retrieve Contact properties
|
||||
// TODO: need to check list size
|
||||
return searchContacts(itemPath.substring(0, itemPath.lastIndexOf('/')), CONTACT_ATTRIBUTES, equals("urlcompname", itemPath.substring(itemPath.lastIndexOf('/')+1))).get(0);
|
||||
return searchContacts(itemPath.substring(0, itemPath.lastIndexOf('/')), CONTACT_ATTRIBUTES, equals("urlcompname", itemPath.substring(itemPath.lastIndexOf('/') + 1))).get(0);
|
||||
} else if ("urn:content-classes:appointment".equals(contentClass)
|
||||
|| "urn:content-classes:calendarmessage".equals(contentClass)) {
|
||||
return new Event(responses[0]);
|
||||
@ -1330,7 +1342,7 @@ public class DavExchangeSession extends ExchangeSession {
|
||||
String timezoneId = null;
|
||||
|
||||
try {
|
||||
ArrayList<String> attributes = new ArrayList<String>();
|
||||
Set<String> attributes = new HashSet<String>();
|
||||
attributes.add("roamingdictionary");
|
||||
|
||||
MultiStatusResponse[] responses = searchItems("/users/" + getEmail() + "/NON_IPM_SUBTREE", attributes, equals("messageclass", "IPM.Configuration.OWA.UserOptions"), DavExchangeSession.FolderQueryTraversal.Deep);
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package davmail.exchange.dav;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.jackrabbit.webdav.DavConstants;
|
||||
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
||||
import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
|
||||
@ -111,8 +112,10 @@ public class Field {
|
||||
|
||||
createField(DAV, "isfolder");
|
||||
|
||||
// item id, do not use DAV:uid, see http://support.microsoft.com/kb/320749
|
||||
createField("uid", 0x300b, PropertyType.Binary); // PR_SEARCH_KEY
|
||||
|
||||
// POP and IMAP message
|
||||
createField(DAV, "uid");
|
||||
createField("messageSize", 0x0e08, PropertyType.Long);//PR_MESSAGE_SIZE
|
||||
createField("imapUid", 0x0e23, PropertyType.Long);//PR_INTERNET_ARTICLE_NUMBER
|
||||
createField("junk", 0x1083, PropertyType.Long);
|
||||
@ -238,9 +241,22 @@ public class Field {
|
||||
createField(DAV, "ishidden");
|
||||
}
|
||||
|
||||
protected static String toHexString(int propertyTag) {
|
||||
String hexValue = Integer.toHexString(propertyTag);
|
||||
while (hexValue.length() < 4) {
|
||||
hexValue = '0' + hexValue;
|
||||
}
|
||||
return hexValue;
|
||||
}
|
||||
|
||||
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);
|
||||
String name = 'x' + toHexString(propertyTag) + propertyTypeMap.get(propertyType);
|
||||
Field field;
|
||||
if (propertyType == PropertyType.Binary) {
|
||||
field = new Field(alias, SCHEMAS_MAPI_PROPTAG, name, null, "bin.base64");
|
||||
} else {
|
||||
field = new Field(alias, SCHEMAS_MAPI_PROPTAG, name);
|
||||
}
|
||||
fieldMap.put(field.alias, field);
|
||||
}
|
||||
|
||||
@ -251,15 +267,15 @@ public class Field {
|
||||
name = String.valueOf(propertyTag);
|
||||
} else {
|
||||
// Common namespace expects hex names
|
||||
name = "0x" + Integer.toHexString(propertyTag);
|
||||
name = "0x" + toHexString(propertyTag);
|
||||
}
|
||||
Field field = new Field(alias, Namespace.getNamespace(SCHEMAS_MAPI_ID.getURI() +
|
||||
'{' + distinguishedPropertySetMap.get(propertySetType) + "}/"), name, responseAlias);
|
||||
'{' + distinguishedPropertySetMap.get(propertySetType) + "}/"), name, responseAlias, null);
|
||||
fieldMap.put(field.alias, field);
|
||||
}
|
||||
|
||||
protected static void createField(String alias, DistinguishedPropertySetType propertySetType, int propertyTag, PropertyType propertyType) {
|
||||
String name = "_x" + propertyTypeMap.get(propertyType) + "_x" + Integer.toHexString(propertyTag);
|
||||
String name = "_x" + propertyTypeMap.get(propertyType) + "_x" + toHexString(propertyTag);
|
||||
|
||||
Field field = new Field(alias, Namespace.getNamespace(SCHEMAS_MAPI_ID.getURI() +
|
||||
'{' + distinguishedPropertySetMap.get(propertySetType) + "}/"), name);
|
||||
@ -281,6 +297,7 @@ public class Field {
|
||||
protected final String uri;
|
||||
protected final String requestPropertyString;
|
||||
protected final DavPropertyName responsePropertyName;
|
||||
protected final String cast;
|
||||
|
||||
|
||||
public Field(Namespace namespace, String name) {
|
||||
@ -288,10 +305,10 @@ public class Field {
|
||||
}
|
||||
|
||||
public Field(String alias, Namespace namespace, String name) {
|
||||
this(alias, namespace, name, null);
|
||||
this(alias, namespace, name, null, null);
|
||||
}
|
||||
|
||||
public Field(String alias, Namespace namespace, String name, String responseAlias) {
|
||||
public Field(String alias, Namespace namespace, String name, String responseAlias, String cast) {
|
||||
davPropertyName = DavPropertyName.create(name, namespace);
|
||||
this.alias = alias;
|
||||
this.uri = namespace.getURI() + name;
|
||||
@ -302,6 +319,7 @@ public class Field {
|
||||
this.requestPropertyString = '"' + uri + "\" as " + responseAlias;
|
||||
this.responsePropertyName = DavPropertyName.create(responseAlias, EMPTY);
|
||||
}
|
||||
this.cast = cast;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
|
@ -138,7 +138,7 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageList searchMessages(String folderName, List<String> attributes, Condition condition) throws IOException {
|
||||
public MessageList searchMessages(String folderName, Set<String> attributes, Condition condition) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@ -468,12 +468,12 @@ public class EwsExchangeSession extends ExchangeSession {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Contact> searchContacts(String folderName, List<String> attributes, Condition condition) throws IOException {
|
||||
public List<Contact> searchContacts(String folderName, Set<String> attributes, Condition condition) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Event> searchEvents(String folderPath, List<String> attributes, Condition condition) throws IOException {
|
||||
protected List<Event> searchEvents(String folderPath, Set<String> attributes, Condition condition) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,10 @@ import davmail.exception.DavMailException;
|
||||
import davmail.exchange.ExchangeSession;
|
||||
import davmail.exchange.ExchangeSessionFactory;
|
||||
import davmail.ui.tray.DavGatewayTray;
|
||||
import davmail.util.StringUtil;
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
@ -35,6 +39,8 @@ import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.*;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@ -1021,16 +1027,26 @@ public class LdapConnection extends AbstractConnection {
|
||||
|
||||
ExchangeSession.Condition condition;
|
||||
|
||||
// convert hex uid to base64
|
||||
String actualValue = value;
|
||||
if ("uid".equals(contactAttributeName)) {
|
||||
try {
|
||||
actualValue = StringUtil.hexToBase64(value);
|
||||
} catch (DecoderException e) {
|
||||
// ignore, this is not an hex uid
|
||||
}
|
||||
}
|
||||
|
||||
if (operator == LDAP_FILTER_EQUALITY) {
|
||||
condition = session.equals(contactAttributeName, value);
|
||||
} else if ("*".equals(value)) {
|
||||
condition = session.equals(contactAttributeName, actualValue);
|
||||
} else if ("*".equals(actualValue)) {
|
||||
condition = session.not(session.isNull(contactAttributeName));
|
||||
} else {
|
||||
// endsWith not supported by exchange, convert to contains
|
||||
if (mode == LDAP_SUBSTRING_FINAL || mode == LDAP_SUBSTRING_ANY) {
|
||||
condition = session.contains(contactAttributeName, value);
|
||||
condition = session.contains(contactAttributeName, actualValue);
|
||||
} else {
|
||||
condition = session.startsWith(contactAttributeName, value);
|
||||
condition = session.startsWith(contactAttributeName, actualValue);
|
||||
}
|
||||
}
|
||||
return condition;
|
||||
@ -1157,11 +1173,17 @@ public class LdapConnection extends AbstractConnection {
|
||||
if (session != null) {
|
||||
// single user request
|
||||
String uid = dn.substring("uid=".length(), dn.indexOf(','));
|
||||
Map<String, Map<String, String>> persons = null;
|
||||
|
||||
// first search in contact
|
||||
Map<String, Map<String, String>> persons = session.contactFindByUid(uid);
|
||||
try {
|
||||
persons = contactFind(session.equals("uid", StringUtil.hexToBase64(uid)), returningAttributes);
|
||||
} catch (DecoderException e) {
|
||||
// ignore, this is not an hex uid
|
||||
}
|
||||
|
||||
// then in GAL
|
||||
if (persons.isEmpty()) {
|
||||
if (persons == null || persons.isEmpty()) {
|
||||
persons = session.galFind("AN", uid);
|
||||
|
||||
Map<String, String> person = persons.get(uid.toLowerCase());
|
||||
@ -1190,7 +1212,7 @@ public class LdapConnection extends AbstractConnection {
|
||||
Map<String, Map<String, String>> persons = new HashMap<String, Map<String, String>>();
|
||||
if (ldapFilter.isFullSearch()) {
|
||||
// append personal contacts first
|
||||
for (Map<String, String> person : session.contactFind(null).values()) {
|
||||
for (Map<String, String> person : contactFind(null, returningAttributes).values()) {
|
||||
persons.put(person.get("uid"), person);
|
||||
if (persons.size() == sizeLimit) {
|
||||
break;
|
||||
@ -1217,7 +1239,7 @@ public class LdapConnection extends AbstractConnection {
|
||||
// if ldapfilter is not a full search and filter is null,
|
||||
// ignored all attribute filters => return empty results
|
||||
if (ldapFilter.isFullSearch() || filter != null) {
|
||||
for (Map<String, String> person : session.contactFind(filter).values()) {
|
||||
for (Map<String, String> person : contactFind(filter, returningAttributes).values()) {
|
||||
persons.put(person.get("uid"), person);
|
||||
|
||||
if (persons.size() == sizeLimit) {
|
||||
@ -1273,6 +1295,63 @@ public class LdapConnection extends AbstractConnection {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Search users in contacts folder
|
||||
*
|
||||
* @param condition search filter
|
||||
* @return List of users
|
||||
* @throws IOException on error
|
||||
*/
|
||||
public Map<String, Map<String, String>> contactFind(ExchangeSession.Condition condition, Set<String> returningAttributes) throws IOException {
|
||||
Set<String> ldapReturningAttributes;
|
||||
if (returningAttributes != null && !returningAttributes.isEmpty()) {
|
||||
ldapReturningAttributes = new HashSet<String>();
|
||||
// always return uid
|
||||
ldapReturningAttributes.add("uid");
|
||||
for (String attribute : returningAttributes) {
|
||||
if (!"objectclass".equals(attribute)) {
|
||||
ldapReturningAttributes.add(attribute);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ldapReturningAttributes = ExchangeSession.CONTACT_ATTRIBUTES;
|
||||
}
|
||||
|
||||
Map<String, Map<String, String>> results = new HashMap<String, Map<String, String>>();
|
||||
|
||||
List<ExchangeSession.Contact> contacts = session.searchContacts(ExchangeSession.CONTACTS, ldapReturningAttributes, condition);
|
||||
|
||||
for (ExchangeSession.Contact contact : contacts) {
|
||||
// TODO convert values
|
||||
/*
|
||||
if ("bday".equals(propertyName)) {
|
||||
SimpleDateFormat parser = getExchangeZuluDateFormatMillisecond();
|
||||
try {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(parser.parse(propertyValue));
|
||||
item.put("birthday", String.valueOf(calendar.get(Calendar.DAY_OF_MONTH)));
|
||||
item.put("birthmonth", String.valueOf(calendar.get(Calendar.MONTH) + 1));
|
||||
item.put("birthyear", String.valueOf(calendar.get(Calendar.YEAR)));
|
||||
propertyValue = null;
|
||||
} catch (ParseException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
} else if ("textdescription".equals(propertyName) && " \n".equals(propertyValue)) {
|
||||
propertyValue = null;
|
||||
}
|
||||
*/
|
||||
if (contact.get("uid") != null) {
|
||||
// convert uid to hex
|
||||
String hexUid = StringUtil.base64ToHex(contact.get("uid"));
|
||||
contact.put("uid", hexUid);
|
||||
results.put(hexUid, contact);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert to LDAP attributes and send entry
|
||||
*
|
||||
|
@ -18,6 +18,10 @@
|
||||
*/
|
||||
package davmail.util;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -169,4 +173,33 @@ public final class StringUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert base64 value to hex.
|
||||
*
|
||||
* @param value base64 value
|
||||
* @return hex value
|
||||
*/
|
||||
public static String base64ToHex(String value) {
|
||||
String hexValue = null;
|
||||
if (value != null) {
|
||||
hexValue = new String(Hex.encodeHex(Base64.decodeBase64(value.getBytes())));
|
||||
}
|
||||
return hexValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex value to base64.
|
||||
*
|
||||
* @param value hex value
|
||||
* @return base64 value
|
||||
* @throws DecoderException on error
|
||||
*/
|
||||
public static String hexToBase64(String value) throws DecoderException {
|
||||
String base64Value = null;
|
||||
if (value != null) {
|
||||
base64Value = new String(Base64.encodeBase64(Hex.decodeHex(value.toCharArray())));
|
||||
}
|
||||
return base64Value;
|
||||
}
|
||||
|
||||
}
|
||||
|
59
src/test/davmail/exchange/TestExchangeSessionContact.java
Normal file
59
src/test/davmail/exchange/TestExchangeSessionContact.java
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import davmail.exchange.dav.DavExchangeSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Test ExchangeSession contact features.
|
||||
*/
|
||||
@SuppressWarnings({"UseOfSystemOutOrSystemErr"})
|
||||
public class TestExchangeSessionContact extends AbstractExchangeSessionTestCase {
|
||||
|
||||
public void testSearchContacts() throws IOException {
|
||||
List<ExchangeSession.Contact> contacts = session.searchContacts(ExchangeSession.CONTACTS, ExchangeSession.CONTACT_ATTRIBUTES, null);
|
||||
for (ExchangeSession.Contact contact : contacts) {
|
||||
System.out.println(session.getItem(ExchangeSession.CONTACTS, contact.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
public void testSearchContactsUidOnly() throws IOException {
|
||||
Set<String> attributes = new HashSet<String>();
|
||||
attributes.add("uid");
|
||||
List<ExchangeSession.Contact> contacts = session.searchContacts(ExchangeSession.CONTACTS, attributes, null);
|
||||
for (ExchangeSession.Contact contact : contacts) {
|
||||
System.out.println(contact);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSearchContactsByUid() throws IOException {
|
||||
Set<String> attributes = new HashSet<String>();
|
||||
attributes.add("uid");
|
||||
List<ExchangeSession.Contact> contacts = session.searchContacts(ExchangeSession.CONTACTS, attributes, null);
|
||||
for (ExchangeSession.Contact contact : contacts) {
|
||||
System.out.println(session.searchContacts(ExchangeSession.CONTACTS, attributes, session.equals("uid", contact.get("uid"))));
|
||||
}
|
||||
}
|
||||
}
|
@ -54,6 +54,9 @@ public class TestDavExchangeSession extends AbstractExchangeSessionTestCase {
|
||||
assertEquals(mailPath + davSession.sentitemsName, davSession.getFolderPath("Sent"));
|
||||
assertEquals(mailPath + davSession.draftsName, davSession.getFolderPath("Drafts"));
|
||||
|
||||
assertEquals(mailPath + davSession.contactsName, davSession.getFolderPath("contacts"));
|
||||
assertEquals(mailPath + davSession.calendarName, davSession.getFolderPath("calendar"));
|
||||
|
||||
assertEquals(mailPath + davSession.inboxName + "/test", davSession.getFolderPath("INBOX/test"));
|
||||
assertEquals(mailPath + davSession.deleteditemsName + "/test", davSession.getFolderPath("Trash/test"));
|
||||
assertEquals(mailPath + davSession.sentitemsName + "/test", davSession.getFolderPath("Sent/test"));
|
||||
@ -99,7 +102,7 @@ public class TestDavExchangeSession extends AbstractExchangeSessionTestCase {
|
||||
}
|
||||
|
||||
public void testGetCategoryList() throws IOException {
|
||||
ArrayList<String> attributes = new ArrayList<String>();
|
||||
Set<String> attributes = new HashSet<String>();
|
||||
attributes.add("permanenturl");
|
||||
attributes.add("roamingxmlstream");
|
||||
MultiStatusResponse[] responses = davSession.searchItems("/users/" + davSession.getEmail() + "/calendar", attributes, davSession.and(davSession.isFalse("isfolder"), davSession.equals("messageclass", "IPM.Configuration.CategoryList")), DavExchangeSession.FolderQueryTraversal.Shallow);
|
||||
@ -109,7 +112,7 @@ public class TestDavExchangeSession extends AbstractExchangeSessionTestCase {
|
||||
}
|
||||
|
||||
public void testGetCalendarOptions() throws IOException {
|
||||
ArrayList<String> attributes = new ArrayList<String>();
|
||||
Set<String> attributes = new HashSet<String>();
|
||||
attributes.add("permanenturl");
|
||||
attributes.add("roamingxmlstream");
|
||||
MultiStatusResponse[] responses = davSession.searchItems("/users/" + davSession.getEmail() + "/calendar", attributes, davSession.and(davSession.isFalse("isfolder"), davSession.equals("messageclass", "IPM.Configuration.Calendar")), DavExchangeSession.FolderQueryTraversal.Shallow);
|
||||
@ -119,7 +122,7 @@ public class TestDavExchangeSession extends AbstractExchangeSessionTestCase {
|
||||
}
|
||||
|
||||
public void testAllHidden() throws IOException {
|
||||
ArrayList<String> attributes = new ArrayList<String>();
|
||||
Set<String> attributes = new HashSet<String>();
|
||||
attributes.add("messageclass");
|
||||
attributes.add("permanenturl");
|
||||
attributes.add("roamingxmlstream");
|
||||
@ -139,7 +142,7 @@ public class TestDavExchangeSession extends AbstractExchangeSessionTestCase {
|
||||
}
|
||||
|
||||
public void testNonIpmSubtree() throws IOException {
|
||||
ArrayList<String> attributes = new ArrayList<String>();
|
||||
Set<String> attributes = new HashSet<String>();
|
||||
attributes.add("messageclass");
|
||||
attributes.add("permanenturl");
|
||||
attributes.add("roamingxmlstream");
|
||||
|
Loading…
Reference in New Issue
Block a user