mirror of
https://github.com/moparisthebest/davmail
synced 2024-12-14 19:52:21 -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 PUBLIC_ROOT = "/public";
|
||||||
protected static final String CALENDAR = "calendar";
|
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 ADDRESSBOOK = "addressbook";
|
||||||
protected static final String INBOX = "INBOX";
|
protected static final String INBOX = "INBOX";
|
||||||
protected static final String LOWER_CASE_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 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 {
|
static {
|
||||||
POP_MESSAGE_ATTRIBUTES.add("uid");
|
POP_MESSAGE_ATTRIBUTES.add("uid");
|
||||||
@ -531,7 +531,7 @@ public abstract class ExchangeSession {
|
|||||||
return searchMessages(folderName, POP_MESSAGE_ATTRIBUTES, null);
|
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 {
|
static {
|
||||||
IMAP_MESSAGE_ATTRIBUTES.add("uid");
|
IMAP_MESSAGE_ATTRIBUTES.add("uid");
|
||||||
@ -546,7 +546,7 @@ public abstract class ExchangeSession {
|
|||||||
IMAP_MESSAGE_ATTRIBUTES.add("date");
|
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 {
|
static {
|
||||||
UID_MESSAGE_ATTRIBUTES.add("uid");
|
UID_MESSAGE_ATTRIBUTES.add("uid");
|
||||||
@ -584,7 +584,7 @@ public abstract class ExchangeSession {
|
|||||||
* @return message list
|
* @return message list
|
||||||
* @throws IOException on error
|
* @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 {
|
protected enum Operator {
|
||||||
Or, And, Not, IsEqualTo, IsGreaterThan, IsGreaterThanOrEqualTo, IsLessThan, IsNull, IsTrue, IsFalse,
|
Or, And, Not, IsEqualTo, IsGreaterThan, IsGreaterThanOrEqualTo, IsLessThan, IsNull, IsTrue, IsFalse,
|
||||||
@ -1741,7 +1741,6 @@ public abstract class ExchangeSession {
|
|||||||
writer.appendProperty("X-EVOLUTION-SPOUSE", get("spousecn"));
|
writer.appendProperty("X-EVOLUTION-SPOUSE", get("spousecn"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String lastModified = get("lastmodified");
|
String lastModified = get("lastmodified");
|
||||||
if (lastModified != null) {
|
if (lastModified != null) {
|
||||||
try {
|
try {
|
||||||
@ -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 {
|
static {
|
||||||
ITEM_PROPERTIES.add("etag");
|
ITEM_PROPERTIES.add("etag");
|
||||||
@ -2422,7 +2421,7 @@ public abstract class ExchangeSession {
|
|||||||
* @return list of contacts
|
* @return list of contacts
|
||||||
* @throws IOException on error
|
* @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.
|
* Search calendar messages in provided folder.
|
||||||
@ -2478,7 +2477,7 @@ public abstract class ExchangeSession {
|
|||||||
* @return list of calendar messages as Event objects
|
* @return list of calendar messages as Event objects
|
||||||
* @throws IOException on error
|
* @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.
|
* convert vcf extension to EML.
|
||||||
@ -2858,18 +2857,7 @@ public abstract class ExchangeSession {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static final Set<String> CONTACT_ATTRIBUTES = new HashSet<String>();
|
||||||
* 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>();
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
CONTACT_ATTRIBUTES.add("uid");
|
CONTACT_ATTRIBUTES.add("uid");
|
||||||
@ -2919,87 +2907,6 @@ public abstract class ExchangeSession {
|
|||||||
CONTACT_ATTRIBUTES.add("lastmodified");
|
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.
|
* Get extended address book information for person with gallookup.
|
||||||
* Does not work with Exchange 2007
|
* Does not work with Exchange 2007
|
||||||
|
@ -117,6 +117,10 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
exchangeFolderPath = mailPath + draftsName + folderPath.substring(DRAFTS.length());
|
exchangeFolderPath = mailPath + draftsName + folderPath.substring(DRAFTS.length());
|
||||||
} else if (folderPath.startsWith(SENT)) {
|
} else if (folderPath.startsWith(SENT)) {
|
||||||
exchangeFolderPath = mailPath + sentitemsName + folderPath.substring(SENT.length());
|
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")) {
|
} else if (folderPath.startsWith("public")) {
|
||||||
exchangeFolderPath = publicFolderUrl + folderPath.substring("public".length());
|
exchangeFolderPath = publicFolderUrl + folderPath.substring("public".length());
|
||||||
|
|
||||||
@ -415,9 +419,13 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void appendTo(StringBuilder buffer) {
|
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));
|
buffer.append(operatorMap.get(operator));
|
||||||
if (!isIntValue) {
|
//noinspection VariableNotUsedInsideIf
|
||||||
|
if (field.cast != null) {
|
||||||
|
buffer.append("CAST (\"");
|
||||||
|
} else if (!isIntValue) {
|
||||||
buffer.append('\'');
|
buffer.append('\'');
|
||||||
}
|
}
|
||||||
if (Operator.Like == operator) {
|
if (Operator.Like == operator) {
|
||||||
@ -427,7 +435,9 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
if (Operator.Like == operator || Operator.StartsWith == operator) {
|
if (Operator.Like == operator || Operator.StartsWith == operator) {
|
||||||
buffer.append('%');
|
buffer.append('%');
|
||||||
}
|
}
|
||||||
if (!isIntValue) {
|
if (field.cast != null) {
|
||||||
|
buffer.append("\" as '").append(field.cast).append("')");
|
||||||
|
} else if (!isIntValue) {
|
||||||
buffer.append('\'');
|
buffer.append('\'');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -901,7 +911,7 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final List<String> FOLDER_PROPERTIES = new ArrayList<String>();
|
protected static final Set<String> FOLDER_PROPERTIES = new HashSet<String>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
FOLDER_PROPERTIES.add("displayname");
|
FOLDER_PROPERTIES.add("displayname");
|
||||||
@ -1082,7 +1092,7 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
MessageList messages = new MessageList();
|
||||||
MultiStatusResponse[] responses = searchItems(folderPath, attributes, and(isFalse("isfolder"), isFalse("ishidden"), condition), FolderQueryTraversal.Shallow);
|
MultiStatusResponse[] responses = searchItems(folderPath, attributes, and(isFalse("isfolder"), isFalse("ishidden"), condition), FolderQueryTraversal.Shallow);
|
||||||
|
|
||||||
@ -1099,9 +1109,11 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
@Override
|
@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>();
|
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) {
|
for (MultiStatusResponse response : responses) {
|
||||||
contacts.add(new Contact(response));
|
contacts.add(new Contact(response));
|
||||||
}
|
}
|
||||||
@ -1109,7 +1121,7 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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>();
|
List<ExchangeSession.Event> events = new ArrayList<ExchangeSession.Event>();
|
||||||
MultiStatusResponse[] responses = searchItems(folderPath, attributes, and(isFalse("isfolder"), isFalse("ishidden"), condition), FolderQueryTraversal.Shallow);
|
MultiStatusResponse[] responses = searchItems(folderPath, attributes, and(isFalse("isfolder"), isFalse("ishidden"), condition), FolderQueryTraversal.Shallow);
|
||||||
for (MultiStatusResponse response : responses) {
|
for (MultiStatusResponse response : responses) {
|
||||||
@ -1133,7 +1145,7 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
return events;
|
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);
|
String folderUrl = getFolderPath(folderPath);
|
||||||
StringBuilder searchRequest = new StringBuilder();
|
StringBuilder searchRequest = new StringBuilder();
|
||||||
searchRequest.append("SELECT ")
|
searchRequest.append("SELECT ")
|
||||||
@ -1330,7 +1342,7 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
String timezoneId = null;
|
String timezoneId = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ArrayList<String> attributes = new ArrayList<String>();
|
Set<String> attributes = new HashSet<String>();
|
||||||
attributes.add("roamingdictionary");
|
attributes.add("roamingdictionary");
|
||||||
|
|
||||||
MultiStatusResponse[] responses = searchItems("/users/" + getEmail() + "/NON_IPM_SUBTREE", attributes, equals("messageclass", "IPM.Configuration.OWA.UserOptions"), DavExchangeSession.FolderQueryTraversal.Deep);
|
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;
|
package davmail.exchange.dav;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Hex;
|
||||||
import org.apache.jackrabbit.webdav.DavConstants;
|
import org.apache.jackrabbit.webdav.DavConstants;
|
||||||
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
import org.apache.jackrabbit.webdav.property.DavPropertyName;
|
||||||
import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
|
import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
|
||||||
@ -111,8 +112,10 @@ public class Field {
|
|||||||
|
|
||||||
createField(DAV, "isfolder");
|
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
|
// POP and IMAP message
|
||||||
createField(DAV, "uid");
|
|
||||||
createField("messageSize", 0x0e08, PropertyType.Long);//PR_MESSAGE_SIZE
|
createField("messageSize", 0x0e08, PropertyType.Long);//PR_MESSAGE_SIZE
|
||||||
createField("imapUid", 0x0e23, PropertyType.Long);//PR_INTERNET_ARTICLE_NUMBER
|
createField("imapUid", 0x0e23, PropertyType.Long);//PR_INTERNET_ARTICLE_NUMBER
|
||||||
createField("junk", 0x1083, PropertyType.Long);
|
createField("junk", 0x1083, PropertyType.Long);
|
||||||
@ -238,9 +241,22 @@ public class Field {
|
|||||||
createField(DAV, "ishidden");
|
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) {
|
protected static void createField(String alias, int propertyTag, PropertyType propertyType) {
|
||||||
String name = 'x' + Integer.toHexString(propertyTag) + propertyTypeMap.get(propertyType);
|
String name = 'x' + toHexString(propertyTag) + propertyTypeMap.get(propertyType);
|
||||||
Field field = new Field(alias, SCHEMAS_MAPI_PROPTAG, name);
|
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);
|
fieldMap.put(field.alias, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,15 +267,15 @@ public class Field {
|
|||||||
name = String.valueOf(propertyTag);
|
name = String.valueOf(propertyTag);
|
||||||
} else {
|
} else {
|
||||||
// Common namespace expects hex names
|
// 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() +
|
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);
|
fieldMap.put(field.alias, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void createField(String alias, DistinguishedPropertySetType propertySetType, int propertyTag, PropertyType propertyType) {
|
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() +
|
Field field = new Field(alias, Namespace.getNamespace(SCHEMAS_MAPI_ID.getURI() +
|
||||||
'{' + distinguishedPropertySetMap.get(propertySetType) + "}/"), name);
|
'{' + distinguishedPropertySetMap.get(propertySetType) + "}/"), name);
|
||||||
@ -281,6 +297,7 @@ public class Field {
|
|||||||
protected final String uri;
|
protected final String uri;
|
||||||
protected final String requestPropertyString;
|
protected final String requestPropertyString;
|
||||||
protected final DavPropertyName responsePropertyName;
|
protected final DavPropertyName responsePropertyName;
|
||||||
|
protected final String cast;
|
||||||
|
|
||||||
|
|
||||||
public Field(Namespace namespace, String name) {
|
public Field(Namespace namespace, String name) {
|
||||||
@ -288,10 +305,10 @@ public class Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Field(String alias, Namespace namespace, String name) {
|
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);
|
davPropertyName = DavPropertyName.create(name, namespace);
|
||||||
this.alias = alias;
|
this.alias = alias;
|
||||||
this.uri = namespace.getURI() + name;
|
this.uri = namespace.getURI() + name;
|
||||||
@ -302,6 +319,7 @@ public class Field {
|
|||||||
this.requestPropertyString = '"' + uri + "\" as " + responseAlias;
|
this.requestPropertyString = '"' + uri + "\" as " + responseAlias;
|
||||||
this.responsePropertyName = DavPropertyName.create(responseAlias, EMPTY);
|
this.responsePropertyName = DavPropertyName.create(responseAlias, EMPTY);
|
||||||
}
|
}
|
||||||
|
this.cast = cast;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUri() {
|
public String getUri() {
|
||||||
|
@ -138,7 +138,7 @@ public class EwsExchangeSession extends ExchangeSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,12 +468,12 @@ public class EwsExchangeSession extends ExchangeSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,10 @@ import davmail.exception.DavMailException;
|
|||||||
import davmail.exchange.ExchangeSession;
|
import davmail.exchange.ExchangeSession;
|
||||||
import davmail.exchange.ExchangeSessionFactory;
|
import davmail.exchange.ExchangeSessionFactory;
|
||||||
import davmail.ui.tray.DavGatewayTray;
|
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.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
@ -35,6 +39,8 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1021,16 +1027,26 @@ public class LdapConnection extends AbstractConnection {
|
|||||||
|
|
||||||
ExchangeSession.Condition condition;
|
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) {
|
if (operator == LDAP_FILTER_EQUALITY) {
|
||||||
condition = session.equals(contactAttributeName, value);
|
condition = session.equals(contactAttributeName, actualValue);
|
||||||
} else if ("*".equals(value)) {
|
} else if ("*".equals(actualValue)) {
|
||||||
condition = session.not(session.isNull(contactAttributeName));
|
condition = session.not(session.isNull(contactAttributeName));
|
||||||
} else {
|
} else {
|
||||||
// endsWith not supported by exchange, convert to contains
|
// endsWith not supported by exchange, convert to contains
|
||||||
if (mode == LDAP_SUBSTRING_FINAL || mode == LDAP_SUBSTRING_ANY) {
|
if (mode == LDAP_SUBSTRING_FINAL || mode == LDAP_SUBSTRING_ANY) {
|
||||||
condition = session.contains(contactAttributeName, value);
|
condition = session.contains(contactAttributeName, actualValue);
|
||||||
} else {
|
} else {
|
||||||
condition = session.startsWith(contactAttributeName, value);
|
condition = session.startsWith(contactAttributeName, actualValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return condition;
|
return condition;
|
||||||
@ -1157,11 +1173,17 @@ 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;
|
||||||
|
|
||||||
// first search in contact
|
// 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
|
// then in GAL
|
||||||
if (persons.isEmpty()) {
|
if (persons == null || persons.isEmpty()) {
|
||||||
persons = session.galFind("AN", uid);
|
persons = session.galFind("AN", uid);
|
||||||
|
|
||||||
Map<String, String> person = persons.get(uid.toLowerCase());
|
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>>();
|
Map<String, Map<String, String>> persons = new HashMap<String, Map<String, String>>();
|
||||||
if (ldapFilter.isFullSearch()) {
|
if (ldapFilter.isFullSearch()) {
|
||||||
// append personal contacts first
|
// 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);
|
persons.put(person.get("uid"), person);
|
||||||
if (persons.size() == sizeLimit) {
|
if (persons.size() == sizeLimit) {
|
||||||
break;
|
break;
|
||||||
@ -1217,7 +1239,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 : session.contactFind(filter).values()) {
|
for (Map<String, String> person : contactFind(filter, returningAttributes).values()) {
|
||||||
persons.put(person.get("uid"), person);
|
persons.put(person.get("uid"), person);
|
||||||
|
|
||||||
if (persons.size() == sizeLimit) {
|
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
|
* Convert to LDAP attributes and send entry
|
||||||
*
|
*
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package davmail.util;
|
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.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -169,4 +173,33 @@ public final class StringUtil {
|
|||||||
return result;
|
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.sentitemsName, davSession.getFolderPath("Sent"));
|
||||||
assertEquals(mailPath + davSession.draftsName, davSession.getFolderPath("Drafts"));
|
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.inboxName + "/test", davSession.getFolderPath("INBOX/test"));
|
||||||
assertEquals(mailPath + davSession.deleteditemsName + "/test", davSession.getFolderPath("Trash/test"));
|
assertEquals(mailPath + davSession.deleteditemsName + "/test", davSession.getFolderPath("Trash/test"));
|
||||||
assertEquals(mailPath + davSession.sentitemsName + "/test", davSession.getFolderPath("Sent/test"));
|
assertEquals(mailPath + davSession.sentitemsName + "/test", davSession.getFolderPath("Sent/test"));
|
||||||
@ -99,7 +102,7 @@ public class TestDavExchangeSession extends AbstractExchangeSessionTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testGetCategoryList() throws IOException {
|
public void testGetCategoryList() throws IOException {
|
||||||
ArrayList<String> attributes = new ArrayList<String>();
|
Set<String> attributes = new HashSet<String>();
|
||||||
attributes.add("permanenturl");
|
attributes.add("permanenturl");
|
||||||
attributes.add("roamingxmlstream");
|
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);
|
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 {
|
public void testGetCalendarOptions() throws IOException {
|
||||||
ArrayList<String> attributes = new ArrayList<String>();
|
Set<String> attributes = new HashSet<String>();
|
||||||
attributes.add("permanenturl");
|
attributes.add("permanenturl");
|
||||||
attributes.add("roamingxmlstream");
|
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);
|
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 {
|
public void testAllHidden() throws IOException {
|
||||||
ArrayList<String> attributes = new ArrayList<String>();
|
Set<String> attributes = new HashSet<String>();
|
||||||
attributes.add("messageclass");
|
attributes.add("messageclass");
|
||||||
attributes.add("permanenturl");
|
attributes.add("permanenturl");
|
||||||
attributes.add("roamingxmlstream");
|
attributes.add("roamingxmlstream");
|
||||||
@ -139,7 +142,7 @@ public class TestDavExchangeSession extends AbstractExchangeSessionTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testNonIpmSubtree() throws IOException {
|
public void testNonIpmSubtree() throws IOException {
|
||||||
ArrayList<String> attributes = new ArrayList<String>();
|
Set<String> attributes = new HashSet<String>();
|
||||||
attributes.add("messageclass");
|
attributes.add("messageclass");
|
||||||
attributes.add("permanenturl");
|
attributes.add("permanenturl");
|
||||||
attributes.add("roamingxmlstream");
|
attributes.add("roamingxmlstream");
|
||||||
|
Loading…
Reference in New Issue
Block a user