diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index fbead6a2..1c9c46e9 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -2020,6 +2020,9 @@ public String getBody() { writer.writeLine("PHOTO;TYPE=" + contactPhoto.contentType + ";ENCODING=BASE64:"); writer.writeLine(contactPhoto.content, true); } + + writer.appendProperty("KEY1;X509;ENCODING=BASE64", get("msexchangecertificate")); + writer.appendProperty("KEY2;X509;ENCODING=BASE64", get("usersmimecertificate")); writer.endCard(); return writer.toString(); @@ -2798,6 +2801,10 @@ protected ItemResult createOrUpdateContact(String folderPath, String itemName, S } else if ("PHOTO".equals(property.getKey())) { properties.put("photo", property.getValue()); properties.put("haspicture", "true"); + } else if ("KEY1".equals(property.getKey())) { + properties.put("msexchangecertificate", property.getValue()); + } else if ("KEY2".equals(property.getKey())) { + properties.put("usersmimecertificate", property.getValue()); } } LOGGER.debug("Create or update contact " + itemName + ": " + properties); @@ -3012,6 +3019,8 @@ public String getAlias() { CONTACT_ATTRIBUTES.add("private"); CONTACT_ATTRIBUTES.add("sensitivity"); CONTACT_ATTRIBUTES.add("fburl"); + CONTACT_ATTRIBUTES.add("msexchangecertificate"); + CONTACT_ATTRIBUTES.add("usersmimecertificate"); } protected static final Set DISTRIBUTION_LIST_ATTRIBUTES = new HashSet<>(); diff --git a/src/java/davmail/exchange/ews/ContactDataShape.java b/src/java/davmail/exchange/ews/ContactDataShape.java new file mode 100644 index 00000000..e649a41b --- /dev/null +++ b/src/java/davmail/exchange/ews/ContactDataShape.java @@ -0,0 +1,34 @@ +/* + * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway + * Copyright (C) 2010 Mickael Guessant + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package davmail.exchange.ews; + +/** + * ResolveNames contact data shape. + */ +@SuppressWarnings({"UnusedDeclaration"}) +public class ContactDataShape extends AttributeOption { + private ContactDataShape(String value) { + super("ContactDataShape", value); + } + + public static final ContactDataShape IdOnly = new ContactDataShape("IdOnly"); + public static final ContactDataShape Default = new ContactDataShape("Default"); + public static final ContactDataShape AllProperties = new ContactDataShape("AllProperties"); + +} diff --git a/src/java/davmail/exchange/ews/EwsExchangeSession.java b/src/java/davmail/exchange/ews/EwsExchangeSession.java index 9925eff2..864918ea 100644 --- a/src/java/davmail/exchange/ews/EwsExchangeSession.java +++ b/src/java/davmail/exchange/ews/EwsExchangeSession.java @@ -2975,6 +2975,8 @@ protected void internalExecuteMethod(EWSMethod ewsMethod) throws IOException { GALFIND_ATTRIBUTE_MAP.put("homePhone", "HomePhone"); GALFIND_ATTRIBUTE_MAP.put("pager", "Pager"); + GALFIND_ATTRIBUTE_MAP.put("msexchangecertificate", "MSExchangeCertificate"); + GALFIND_ATTRIBUTE_MAP.put("usersmimecertificate", "UserSMIMECertificate"); } protected static final HashSet IGNORE_ATTRIBUTE_SET = new HashSet<>(); diff --git a/src/java/davmail/exchange/ews/Field.java b/src/java/davmail/exchange/ews/Field.java index 1fab30a9..3b7eeffd 100644 --- a/src/java/davmail/exchange/ews/Field.java +++ b/src/java/davmail/exchange/ews/Field.java @@ -272,6 +272,9 @@ private Field() { // attachments FIELD_MAP.put("attachments", new UnindexedFieldURI("item:Attachments")); + // user certificate + FIELD_MAP.put("msexchangecertificate", new UnindexedFieldURI("contacts:MSExchangeCertificate")); + FIELD_MAP.put("usersmimecertificate", new UnindexedFieldURI("contacts:UserSMIMECertificate")); } /** diff --git a/src/java/davmail/exchange/ews/ResolveNamesMethod.java b/src/java/davmail/exchange/ews/ResolveNamesMethod.java index 58f65340..d95b9b4f 100644 --- a/src/java/davmail/exchange/ews/ResolveNamesMethod.java +++ b/src/java/davmail/exchange/ews/ResolveNamesMethod.java @@ -38,6 +38,7 @@ public ResolveNamesMethod(String value) { super("Contact", "ResolveNames", "ResolutionSet"); addMethodOption(SearchScope.ActiveDirectory); addMethodOption(RETURN_FULL_CONTACT_DATA); + addMethodOption(ContactDataShape.AllProperties); unresolvedEntry = new ElementOption("m:UnresolvedEntry", value); } @@ -88,6 +89,27 @@ protected void handleContact(XMLStreamReader reader, Item responseItem) throws X handlePhysicalAddresses(reader, responseItem); } else if ("PhoneNumbers".equals(tagLocalName)) { handlePhoneNumbers(reader, responseItem); + } else if ("MSExchangeCertificate".equals(tagLocalName) + || "UserSMIMECertificate".equals(tagLocalName)) { + handleUserCertificate(reader, responseItem, tagLocalName); + } else if ("ManagerMailbox".equals(tagLocalName) + || "Attachments".equals(tagLocalName) + || "Photo".equals(tagLocalName) + || "Notes".equals(tagLocalName) + || "HasPicture".equals(tagLocalName) + || "DirectoryId".equals(tagLocalName) + || "Alias".equals(tagLocalName) + || "Categories".equals(tagLocalName) + || "InternetMessageHeaders".equals(tagLocalName) + || "ResponseObjects".equals(tagLocalName) + || "ExtendedProperty".equals(tagLocalName) + || "EffectiveRights".equals(tagLocalName) + || "CompleteName".equals(tagLocalName) + || "Children".equals(tagLocalName) + || "Companies".equals(tagLocalName) + || "ImAddresses".equals(tagLocalName) + || "DirectReports".equals(tagLocalName)) { + skipTag(reader, tagLocalName); } else { responseItem.put(tagLocalName, XMLStreamUtil.getElementText(reader)); } @@ -133,6 +155,38 @@ protected void handlePhoneNumbers(XMLStreamReader reader, Item responseItem) thr } } + protected void handleUserCertificate(XMLStreamReader reader, Item responseItem, String contextTagLocalName) throws XMLStreamException { + boolean firstValueRead = false; + String certificate = ""; + while (reader.hasNext() && !XMLStreamUtil.isEndTag(reader, contextTagLocalName)) { + reader.next(); + if (XMLStreamUtil.isStartTag(reader)) { + String tagLocalName = reader.getLocalName(); + if ("Base64Binary".equals(tagLocalName)) { + String value = reader.getElementText(); + if ((value != null) && !value.isEmpty()) { + if (!firstValueRead) { + // Only first certificate value will be read + certificate = value; + firstValueRead = true; + } else { + LOGGER.debug("ResolveNames multiple certificates found, tagLocaleName=" + + contextTagLocalName + " Certificate [" + value + "] ignored"); + } + } + } + } + } + responseItem.put(contextTagLocalName, certificate); + } + + protected void skipTag(XMLStreamReader reader, String tagLocalName) throws XMLStreamException { + LOGGER.debug("ResolveNames tag parsing skipped. tagLocalName=" + tagLocalName); + while (reader.hasNext() && !XMLStreamUtil.isEndTag(reader, tagLocalName)) { + reader.next(); + } + } + @Override protected void handleEmailAddresses(XMLStreamReader reader, Item responseItem) throws XMLStreamException { while (reader.hasNext() && !XMLStreamUtil.isEndTag(reader, "EmailAddresses")) { diff --git a/src/java/davmail/ldap/LdapConnection.java b/src/java/davmail/ldap/LdapConnection.java index aab33e0b..ad1f05d4 100644 --- a/src/java/davmail/ldap/LdapConnection.java +++ b/src/java/davmail/ldap/LdapConnection.java @@ -26,6 +26,7 @@ import davmail.exchange.ExchangeSessionFactory; import davmail.exchange.dav.DavExchangeSession; import davmail.ui.tray.DavGatewayTray; +import davmail.util.IOUtil; import org.apache.log4j.Logger; import javax.naming.InvalidNameException; @@ -122,6 +123,8 @@ public class LdapConnection extends AbstractConnection { CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("homeStreet", "mozillahomestreet"); CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("businesshomepage", "mozillaworkurl"); CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("nickname", "mozillanickname"); + CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("msexchangecertificate", "msexchangecertificate;binary"); + CONTACT_TO_LDAP_ATTRIBUTE_MAP.put("usersmimecertificate", "usersmimecertificate;binary"); } /** @@ -287,6 +290,10 @@ public class LdapConnection extends AbstractConnection { // iCal search attribute LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("apple-serviceslocator", "apple-serviceslocator"); + + LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("msexchangecertificate;binary", "msexchangecertificate"); + LDAP_TO_CONTACT_ATTRIBUTE_MAP.put("usersmimecertificate;binary", "usersmimecertificate"); + } /** @@ -967,6 +974,8 @@ protected void sendEntry(int currentMessageId, String dn, Map at for (Object value : (Iterable) values) { responseBer.encodeString((String) value, isLdapV3()); } + } else if (values instanceof byte[]) { + responseBer.encodeOctetString((byte[])values, BerEncoder.ASN_OCTET_STR); } else { throw new DavMailException("EXCEPTION_UNSUPPORTED_VALUE", values); } @@ -1688,6 +1697,14 @@ protected void sendPersons(int currentMessageId, String baseContext, Map