diff --git a/lib/native/windows-64/jmsoutlookaddrbook.dll b/lib/native/windows-64/jmsoutlookaddrbook.dll index 19507f9d8..b4c421862 100644 Binary files a/lib/native/windows-64/jmsoutlookaddrbook.dll and b/lib/native/windows-64/jmsoutlookaddrbook.dll differ diff --git a/lib/native/windows/jmsoutlookaddrbook.dll b/lib/native/windows/jmsoutlookaddrbook.dll index d84d372cf..ced518868 100644 Binary files a/lib/native/windows/jmsoutlookaddrbook.dll and b/lib/native/windows/jmsoutlookaddrbook.dll differ diff --git a/src/native/addrbook/msoutlook/Makefile b/src/native/addrbook/msoutlook/Makefile index 6b85fc253..a594e5a13 100644 --- a/src/native/addrbook/msoutlook/Makefile +++ b/src/native/addrbook/msoutlook/Makefile @@ -1,8 +1,8 @@ CC = gcc -O2 -OUTLOOK_MAPI_HEADERS ?= C:/Users/lyubomir/Downloads/Outlook2010MAPIHeaders +OUTLOOK_MAPI_HEADERS ?= C:/Users/lyub0m1r/Downloads/Outlook2010MAPIHeaders TARGET_BASENAME = jmsoutlookaddrbook -ARCH = $(shell $(CC) -dumpmachine | sed -e s/x86_64-.*/-64/ -e s/i.86-.*// -e s/mingw32//) +ARCH ?= $(shell $(CC) -dumpmachine | sed -e s/x86_64-.*/-64/ -e s/i.86-.*// -e s/mingw32//) ifeq "$(ARCH)" "-64" JAVA_HOME ?= C:/PROGRA~1/jdk else diff --git a/src/native/addrbook/msoutlook/MsOutlookMAPIHResultException.cxx b/src/native/addrbook/msoutlook/MsOutlookMAPIHResultException.cxx index 4c090a3f2..8123b2a9b 100644 --- a/src/native/addrbook/msoutlook/MsOutlookMAPIHResultException.cxx +++ b/src/native/addrbook/msoutlook/MsOutlookMAPIHResultException.cxx @@ -1,5 +1,5 @@ /* - * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Distributable under LGPL license. * See terms of license at gnu.org. diff --git a/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactQuery.cxx b/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactQuery.cxx index d6bc0f0ee..861d485db 100644 --- a/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactQuery.cxx +++ b/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactQuery.cxx @@ -1,5 +1,5 @@ /* - * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Distributable under LGPL license. * See terms of license at gnu.org. @@ -11,24 +11,69 @@ #include "MsOutlookMAPI.h" #include "MsOutlookMAPIHResultException.h" +#include #include -#define WIN32_MEAN_AND_LEAN -#include +#define PR_ATTACHMENT_CONTACTPHOTO PROP_TAG(PT_BOOLEAN, 0x7FFF) +typedef + jboolean (*MsOutlookAddrBookContactQuery_ForeachRowInTableCallback) + (LPUNKNOWN iUnknown, + ULONG entryIDByteCount, LPENTRYID entryID, ULONG objType, + JNIEnv *jniEnv, + jstring query, + jobject callback, jmethodID callbackMethodID); + +static HRESULT HrGetOneProp + (LPMAPIPROP mapiProp, ULONG propTag, LPSPropValue *prop); + +static jboolean MsOutlookAddrBookContactQuery_foreachContactInMsgStoresTable + (LPMAPISESSION mapiSession, + JNIEnv *jniEnv, + jstring query, + jobject callback, jmethodID callbackMethodID); static jboolean MsOutlookAddrBookContactQuery_foreachMailUser (ULONG objType, LPUNKNOWN iUnknown, JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID); +static jboolean MsOutlookAddrBookContactQuery_foreachMailUserInAddressBook + (LPMAPISESSION mapiSession, + JNIEnv *jniEnv, + jstring query, + jobject callback, jmethodID callbackMethodID); static jboolean MsOutlookAddrBookContactQuery_foreachMailUserInContainerTable (LPMAPICONTAINER mapiContainer, LPMAPITABLE mapiTable, JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID); +static jboolean MsOutlookAddrBookContactQuery_foreachRowInTable + (LPMAPITABLE mapiTable, + MsOutlookAddrBookContactQuery_ForeachRowInTableCallback rowCallback, + LPUNKNOWN iUnknown, + JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID); static void MsOutlookAddrBookContactQuery_freeSRowSet(LPSRowSet rows); +static jbyteArray MsOutlookAddrBookContactQuery_getAttachmentContactPhoto + (LPMESSAGE message, + JNIEnv *jniEnv); +static HRESULT MsOutlookAddrBookContactQuery_getContactsFolderEntryID + (LPMDB msgStore, + ULONG folderEntryIDByteCount, LPENTRYID folderEntryID, + ULONG *contactsFolderEntryIDByteCount, LPENTRYID *contactsFolderEntryID); +static ULONG MsOutlookAddrBookContactQuery_getPropTagFromLid + (LPMAPIPROP mapiProp, LONG lid); static jboolean MsOutlookAddrBookContactQuery_mailUserMatches (LPMAPIPROP mailUser, JNIEnv *jniEnv, jstring query); +static jboolean MsOutlookAddrBookContactQuery_onForeachContactInMsgStoresTableRow + (LPUNKNOWN mapiSession, + ULONG entryIDByteCount, LPENTRYID entryID, ULONG objType, + JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID); +static jboolean MsOutlookAddrBookContactQuery_onForeachMailUserInContainerTableRow + (LPUNKNOWN mapiContainer, + ULONG entryIDByteCount, LPENTRYID entryID, ULONG objType, + JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID); +static jbyteArray MsOutlookAddrBookContactQuery_readAttachment + (LPMESSAGE message, LONG method, ULONG num, JNIEnv *jniEnv, ULONG cond); JNIEXPORT void JNICALL Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactQuery_foreachMailUser @@ -37,11 +82,11 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac jmethodID callbackMethodID; HRESULT hResult; - LPMAPISESSION mapiSession; + LPMAPISESSION mapiSession = NULL; callbackMethodID = AddrBookContactQuery_getPtrCallbackMethodID(jniEnv, callback); - if (!callbackMethodID || (JNI_TRUE == jniEnv->ExceptionCheck())) + if (!callbackMethodID || jniEnv->ExceptionCheck()) return; hResult @@ -50,45 +95,32 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac NULL, NULL, MAPI_EXTENDED | MAPI_NO_MAIL | MAPI_USE_DEFAULT, &mapiSession); - if (HR_SUCCEEDED(hResult)) + if (HR_SUCCEEDED(hResult) && mapiSession) { - LPADRBOOK adrBook; - - hResult = mapiSession->OpenAddressBook(0, NULL, AB_NO_DIALOG, &adrBook); - if (HR_SUCCEEDED(hResult)) - { - ULONG objType; - LPUNKNOWN iUnknown; - - hResult = adrBook->OpenEntry(0, NULL, NULL, 0, &objType, &iUnknown); - if (HR_SUCCEEDED(hResult)) - { - MsOutlookAddrBookContactQuery_foreachMailUser( - objType, iUnknown, - jniEnv, query, callback, callbackMethodID); - - iUnknown->Release(); - } - else - { - MsOutlookMAPIHResultException_throwNew( - jniEnv, - hResult, - __FILE__, __LINE__); - } + jboolean proceed + = MsOutlookAddrBookContactQuery_foreachContactInMsgStoresTable( + mapiSession, + jniEnv, + query, + callback, callbackMethodID); - adrBook->Release(); - } - else + if (proceed && !(jniEnv->ExceptionCheck())) { - MsOutlookMAPIHResultException_throwNew( + MsOutlookAddrBookContactQuery_foreachMailUserInAddressBook( + mapiSession, jniEnv, - hResult, - __FILE__, __LINE__); + query, + callback, callbackMethodID); } - mapiSession->Logoff(0, 0, 0); - mapiSession->Release(); + /* + * XXX MAPILogonEx has been redefined to return a shared mapiSession + * which is logged off and released upon uninitializing MAPI. The reason + * for the redefinition is that logging on, off and releasing multiple + * times leads to a crash eventually. + */ +// mapiSession->Logoff(0, 0, 0); +// mapiSession->Release(); } else { @@ -122,7 +154,7 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac jlong propId; jniEnv->GetLongArrayRegion(propIds, i, 1, &propId); - if (JNI_TRUE == jniEnv->ExceptionCheck()) + if (jniEnv->ExceptionCheck()) { MAPIFreeBuffer(propTagArray); propTagArray = NULL; @@ -130,8 +162,23 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac } else { - *(propTagArray->aulPropTag + i) - = PROP_TAG(PT_UNSPECIFIED, propId); + ULONG propTag; + + if (propId < 0x8000) + { + if (propId == PROP_ID(PR_ATTACHMENT_CONTACTPHOTO)) + propTag = PR_HASATTACH; + else + propTag = PROP_TAG(PT_UNSPECIFIED, propId); + } + else + { + propTag + = MsOutlookAddrBookContactQuery_getPropTagFromLid( + (LPMAPIPROP) mapiProp, + propId); + } + *(propTagArray->aulPropTag + i) = propTag; } } if (propTagArray) @@ -167,6 +214,61 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac { switch (PROP_TYPE(prop->ulPropTag)) { + case PT_BOOLEAN: + { + if ((PR_HASATTACH == prop->ulPropTag) + && prop->Value.b) + { + jbyteArray value + = MsOutlookAddrBookContactQuery_getAttachmentContactPhoto( + (LPMESSAGE) mapiProp, + jniEnv); + + if (value) + { + jniEnv->SetObjectArrayElement( + props, j, + value); + if (jniEnv->ExceptionCheck()) + props = NULL; + } + } + break; + } + + case PT_LONG: + { + jclass longClass + = jniEnv->FindClass("java/lang/Long"); + + if (longClass) + { + jmethodID longMethodID + = jniEnv->GetMethodID( + longClass, + "", "(J)V"); + + if (longMethodID) + { + jlong l = prop->Value.l; + jobject value + = jniEnv->NewObject( + longClass, longMethodID, + l); + + if (value) + { + jniEnv->SetObjectArrayElement( + props, j, + value); + if (jniEnv->ExceptionCheck()) + props = NULL; + } + } + } + break; + } + case PT_STRING8: { if (prop->Value.lpszA) @@ -209,8 +311,8 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac } } } - MAPIFreeBuffer(prop); propArray++; + MAPIFreeBuffer(prop); } } else @@ -233,26 +335,90 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac return props; } +static HRESULT +HrGetOneProp(LPMAPIPROP mapiProp, ULONG propTag, LPSPropValue *prop) +{ + SPropTagArray propTagArray; + HRESULT hResult; + ULONG valueCount; + LPSPropValue values; + + propTagArray.cValues = 1; + propTagArray.aulPropTag[0] = propTag; + + hResult = mapiProp->GetProps(&propTagArray, 0, &valueCount, &values); + if (HR_SUCCEEDED(hResult)) + { + ULONG i; + jboolean propHasBeenAssignedTo = JNI_FALSE; + + for (i = 0; i < valueCount; i++) + { + LPSPropValue value = values; + + values++; + if (value->ulPropTag == propTag) + { + *prop = value; + propHasBeenAssignedTo = JNI_TRUE; + } + else + MAPIFreeBuffer(value); + } + if (!propHasBeenAssignedTo) + hResult = MAPI_E_NOT_FOUND; + } + return hResult; +} + +static jboolean +MsOutlookAddrBookContactQuery_foreachContactInMsgStoresTable + (LPMAPISESSION mapiSession, + JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID) +{ + HRESULT hResult; + LPMAPITABLE msgStoresTable = NULL; + jboolean proceed; + + hResult = mapiSession->GetMsgStoresTable(0, &msgStoresTable); + if (HR_SUCCEEDED(hResult) && msgStoresTable) + { + proceed + = MsOutlookAddrBookContactQuery_foreachRowInTable( + msgStoresTable, + MsOutlookAddrBookContactQuery_onForeachContactInMsgStoresTableRow, + (LPUNKNOWN) mapiSession, + jniEnv, query, callback, callbackMethodID); + msgStoresTable->Release(); + } + else + { + MsOutlookMAPIHResultException_throwNew( + jniEnv, + hResult, + __FILE__, __LINE__); + proceed = JNI_TRUE; + } + return proceed; +} + static jboolean MsOutlookAddrBookContactQuery_foreachMailUser (ULONG objType, LPUNKNOWN iUnknown, - JNIEnv *jniEnv, - jstring query, - jobject callback, jmethodID callbackMethodID) + JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID) { - jboolean proceed; + jboolean proceed = JNI_TRUE; switch (objType) { case MAPI_ABCONT: + case MAPI_FOLDER: { LPMAPICONTAINER mapiContainer = (LPMAPICONTAINER) iUnknown; HRESULT hResult; LPMAPITABLE mapiTable; - proceed = JNI_TRUE; - /* Look for MAPI_MAILUSER through the contents. */ mapiTable = NULL; hResult = mapiContainer->GetContentsTable(0, &mapiTable); @@ -266,7 +432,7 @@ MsOutlookAddrBookContactQuery_foreachMailUser } /* Drill down the hierarchy. */ - if (JNI_TRUE == proceed) + if (proceed) { mapiTable = NULL; hResult = mapiContainer->GetHierarchyTable(0, &mapiTable); @@ -284,28 +450,74 @@ MsOutlookAddrBookContactQuery_foreachMailUser } case MAPI_MAILUSER: + case MAPI_MESSAGE: { - if (JNI_TRUE - == MsOutlookAddrBookContactQuery_mailUserMatches( - (LPMAPIPROP) iUnknown, - jniEnv, query)) + if (MsOutlookAddrBookContactQuery_mailUserMatches( + (LPMAPIPROP) iUnknown, + jniEnv, query)) { /* Report the MAPI_MAILUSER to the callback. */ proceed = jniEnv->CallBooleanMethod( callback, callbackMethodID, iUnknown); + /* * XXX When an exception is thrown in the callback, does proceed get * assigned JNI_FALSE? */ - if ((JNI_TRUE == proceed) && (JNI_TRUE == jniEnv->ExceptionCheck())) + if (proceed && jniEnv->ExceptionCheck()) proceed = JNI_FALSE; } + break; + } + } + return proceed; +} + +static jboolean +MsOutlookAddrBookContactQuery_foreachMailUserInAddressBook + (LPMAPISESSION mapiSession, + JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID) +{ + HRESULT hResult; + LPADRBOOK adrBook; + jboolean proceed; + + hResult = mapiSession->OpenAddressBook(0, NULL, AB_NO_DIALOG, &adrBook); + if (HR_SUCCEEDED(hResult)) + { + ULONG objType; + LPUNKNOWN iUnknown; + + hResult = adrBook->OpenEntry(0, NULL, NULL, 0, &objType, &iUnknown); + if (HR_SUCCEEDED(hResult)) + { + proceed + = MsOutlookAddrBookContactQuery_foreachMailUser( + objType, iUnknown, + jniEnv, query, callback, callbackMethodID); + + iUnknown->Release(); + } else + { + MsOutlookMAPIHResultException_throwNew( + jniEnv, + hResult, + __FILE__, __LINE__); proceed = JNI_TRUE; - break; + } + + adrBook->Release(); } + else + { + MsOutlookMAPIHResultException_throwNew( + jniEnv, + hResult, + __FILE__, __LINE__); + proceed = JNI_TRUE; } return proceed; } @@ -313,9 +525,22 @@ MsOutlookAddrBookContactQuery_foreachMailUser static jboolean MsOutlookAddrBookContactQuery_foreachMailUserInContainerTable (LPMAPICONTAINER mapiContainer, LPMAPITABLE mapiTable, - JNIEnv *jniEnv, - jstring query, - jobject callback, jmethodID callbackMethodID) + JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID) +{ + return + MsOutlookAddrBookContactQuery_foreachRowInTable( + mapiTable, + MsOutlookAddrBookContactQuery_onForeachMailUserInContainerTableRow, + (LPUNKNOWN) mapiContainer, + jniEnv, query, callback, callbackMethodID); +} + +static jboolean +MsOutlookAddrBookContactQuery_foreachRowInTable + (LPMAPITABLE mapiTable, + MsOutlookAddrBookContactQuery_ForeachRowInTableCallback rowCallback, + LPUNKNOWN iUnknown, + JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID) { HRESULT hResult; jboolean proceed; @@ -323,18 +548,21 @@ MsOutlookAddrBookContactQuery_foreachMailUserInContainerTable hResult = mapiTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL); if (HR_SUCCEEDED(hResult)) { - LPSRowSet rows; - proceed = JNI_TRUE; - while ((JNI_TRUE == proceed) - && HR_SUCCEEDED(hResult = mapiTable->QueryRows(1, 0, &rows))) + while (proceed) { + LPSRowSet rows; + + hResult = mapiTable->QueryRows(1, 0, &rows); + if (HR_FAILED(hResult)) + break; + if (rows->cRows == 1) { ULONG i; LPSRow row = rows->aRow; ULONG objType = 0; - SBinary entryIDBinary = {0, NULL}; + SBinary entryIDBinary = { 0, NULL }; for (i = 0; i < row->cValues; i++) { @@ -360,8 +588,6 @@ MsOutlookAddrBookContactQuery_foreachMailUserInContainerTable entryIDBinary.cb, (void **) &entryID)) { - LPUNKNOWN iUnknown; - CopyMemory( entryID, entryIDBinary.lpb, @@ -373,22 +599,16 @@ MsOutlookAddrBookContactQuery_foreachMailUserInContainerTable */ MsOutlookAddrBookContactQuery_freeSRowSet(rows); - hResult - = mapiContainer->OpenEntry( - entryIDBinary.cb, entryID, - NULL, - 0, - &objType, &iUnknown); - if (HR_SUCCEEDED(hResult)) - { - proceed - = MsOutlookAddrBookContactQuery_foreachMailUser( - objType, iUnknown, - jniEnv, query, callback, callbackMethodID); - iUnknown->Release(); - } + proceed + = rowCallback( + iUnknown, + entryIDBinary.cb, entryID, objType, + jniEnv, query, callback, callbackMethodID); MAPIFreeBuffer(entryID); + + if (proceed && jniEnv->ExceptionCheck()) + proceed = JNI_FALSE; } else MsOutlookAddrBookContactQuery_freeSRowSet(rows); @@ -431,6 +651,177 @@ MsOutlookAddrBookContactQuery_freeSRowSet(LPSRowSet rows) MAPIFreeBuffer(rows); } +static jbyteArray +MsOutlookAddrBookContactQuery_getAttachmentContactPhoto + (LPMESSAGE message, JNIEnv *jniEnv) +{ + HRESULT hResult; + LPMAPITABLE attachmentTable; + jbyteArray attachmentContactPhoto = NULL; + + hResult = message->GetAttachmentTable(0, &attachmentTable); + if (HR_SUCCEEDED(hResult)) + { + hResult = attachmentTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL); + if (HR_SUCCEEDED(hResult)) + { + while (1) + { + LPSRowSet rows; + + hResult = attachmentTable->QueryRows(1, 0, &rows); + if (HR_FAILED(hResult)) + break; + + if (rows->cRows == 1) + { + ULONG i; + LPSRow row = rows->aRow; + jboolean isAttachmentContactPhotoRow = JNI_FALSE; + jboolean hasAttachmentContactPhoto = JNI_FALSE; + ULONG attachNum = 0; + LONG attachMethod = NO_ATTACHMENT; + + for (i = 0; i < row->cValues; i++) + { + LPSPropValue prop = (row->lpProps) + i; + + switch (prop->ulPropTag) + { + case PR_ATTACHMENT_CONTACTPHOTO: + isAttachmentContactPhotoRow = JNI_TRUE; + hasAttachmentContactPhoto + = prop->Value.b ? JNI_TRUE : JNI_FALSE; + break; + case PR_ATTACH_METHOD: + attachMethod = prop->Value.l; + break; + case PR_ATTACH_NUM: + attachNum = prop->Value.l; + break; + } + } + + MsOutlookAddrBookContactQuery_freeSRowSet(rows); + + /* + * As the reference says and as discovered in practice, + * PR_ATTACHMENT_CONTACTPHOTO is sometimes in IAttach. + */ + if ((isAttachmentContactPhotoRow + && hasAttachmentContactPhoto) + || !isAttachmentContactPhotoRow) + { + attachmentContactPhoto + = MsOutlookAddrBookContactQuery_readAttachment( + message, + attachMethod, attachNum, + jniEnv, + (!isAttachmentContactPhotoRow) + ? PR_ATTACHMENT_CONTACTPHOTO + : PROP_TAG(PT_UNSPECIFIED, 0)); + } + if (isAttachmentContactPhotoRow + || attachmentContactPhoto) + { + /* + * The reference says there can be only 1 + * PR_ATTACHMENT_CONTACTPHOTO. + */ + break; + } + } + else + { + MAPIFreeBuffer(rows); + break; + } + } + } + + attachmentTable->Release(); + } + return attachmentContactPhoto; +} + +static HRESULT +MsOutlookAddrBookContactQuery_getContactsFolderEntryID + (LPMDB msgStore, + ULONG folderEntryIDByteCount, LPENTRYID folderEntryID, + ULONG *contactsFolderEntryIDByteCount, LPENTRYID *contactsFolderEntryID) +{ + HRESULT hResult; + ULONG objType; + LPUNKNOWN folder; + + hResult + = msgStore->OpenEntry( + folderEntryIDByteCount, folderEntryID, + NULL, + 0, + &objType, &folder); + if (HR_SUCCEEDED(hResult)) + { + LPSPropValue prop; + + hResult + = HrGetOneProp( + (LPMAPIPROP) folder, + 0x36D10102 /* PR_IPM_CONTACT_ENTRYID */, + &prop); + if (HR_SUCCEEDED(hResult)) + { + LPSBinary bin = &(prop->Value.bin); + if (S_OK + == MAPIAllocateBuffer( + bin->cb, + (void **) contactsFolderEntryID)) + { + hResult = S_OK; + *contactsFolderEntryIDByteCount = bin->cb; + CopyMemory(*contactsFolderEntryID, bin->lpb, bin->cb); + } + else + hResult = MAPI_E_NOT_ENOUGH_MEMORY; + MAPIFreeBuffer(prop); + } + folder->Release(); + } + return hResult; +} + +static ULONG +MsOutlookAddrBookContactQuery_getPropTagFromLid(LPMAPIPROP mapiProp, LONG lid) +{ + GUID PSETID_Address + = {0x00062004, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; + MAPINAMEID propName; + LPMAPINAMEID propNamePtr; + HRESULT hResult; + LPSPropTagArray propTagArray; + + propName.lpguid = (LPGUID) &PSETID_Address; + propName.ulKind = MNID_ID; + propName.Kind.lID = lid; + propNamePtr = &propName; + hResult + = mapiProp->GetIDsFromNames( + 1, &propNamePtr, + 0, + &propTagArray); + if (HR_SUCCEEDED(hResult) && (1 == propTagArray->cValues)) + { + ULONG propTag = propTagArray->aulPropTag[0]; + + if (PT_ERROR == PROP_TYPE(propTag)) + propTag = PROP_TAG(PT_UNSPECIFIED, lid); + MAPIFreeBuffer(propTagArray); + return propTag; + } + else + return PROP_TAG(PT_UNSPECIFIED, lid); +} + static jboolean MsOutlookAddrBookContactQuery_mailUserMatches (LPMAPIPROP mailUser, JNIEnv *jniEnv, jstring query) @@ -438,3 +829,209 @@ MsOutlookAddrBookContactQuery_mailUserMatches // TODO Auto-generated method stub return JNI_TRUE; } + +static jboolean +MsOutlookAddrBookContactQuery_onForeachContactInMsgStoresTableRow + (LPUNKNOWN mapiSession, + ULONG entryIDByteCount, LPENTRYID entryID, ULONG objType, + JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID) +{ + HRESULT hResult; + LPMDB msgStore; + jboolean proceed; + + hResult + = ((LPMAPISESSION) mapiSession)->OpenMsgStore( + 0, + entryIDByteCount, entryID, + NULL, + MDB_NO_MAIL, + &msgStore); + if (HR_SUCCEEDED(hResult)) + { + LPENTRYID receiveFolderEntryID; + ULONG contactsFolderEntryIDByteCount; + LPENTRYID contactsFolderEntryID; + + hResult + = msgStore->GetReceiveFolder( + NULL, + 0, + &entryIDByteCount, &receiveFolderEntryID, + NULL); + if (HR_SUCCEEDED(hResult)) + { + hResult + = MsOutlookAddrBookContactQuery_getContactsFolderEntryID( + msgStore, + entryIDByteCount, receiveFolderEntryID, + &contactsFolderEntryIDByteCount, &contactsFolderEntryID); + MAPIFreeBuffer(receiveFolderEntryID); + } + if (HR_FAILED(hResult)) + { + hResult + = MsOutlookAddrBookContactQuery_getContactsFolderEntryID( + msgStore, + 0, NULL, + &contactsFolderEntryIDByteCount, &contactsFolderEntryID); + } + if (HR_SUCCEEDED(hResult)) + { + ULONG contactsFolderObjType; + LPUNKNOWN contactsFolder; + + hResult + = msgStore->OpenEntry( + contactsFolderEntryIDByteCount, contactsFolderEntryID, + NULL, + 0, + &contactsFolderObjType, &contactsFolder); + if (HR_SUCCEEDED(hResult)) + { + proceed + = MsOutlookAddrBookContactQuery_foreachMailUser( + contactsFolderObjType, contactsFolder, + jniEnv, query, callback, callbackMethodID); + contactsFolder->Release(); + } + else + { + /* + * We've failed but other parts of the hierarchy may still + * succeed. + */ + proceed = JNI_TRUE; + } + MAPIFreeBuffer(contactsFolderEntryID); + } + else + { + /* + * We've failed but other parts of the hierarchy may still succeed. + */ + proceed = JNI_TRUE; + } + msgStore->Release(); + } + else + { + /* We've failed but other parts of the hierarchy may still succeed. */ + proceed = JNI_TRUE; + } + return proceed; +} + +static jboolean +MsOutlookAddrBookContactQuery_onForeachMailUserInContainerTableRow + (LPUNKNOWN mapiContainer, + ULONG entryIDByteCount, LPENTRYID entryID, ULONG objType, + JNIEnv *jniEnv, jstring query, jobject callback, jmethodID callbackMethodID) +{ + HRESULT hResult; + LPUNKNOWN iUnknown; + jboolean proceed; + + hResult + = ((LPMAPICONTAINER) mapiContainer)->OpenEntry( + entryIDByteCount, entryID, + NULL, + 0, + &objType, &iUnknown); + if (HR_SUCCEEDED(hResult)) + { + proceed + = MsOutlookAddrBookContactQuery_foreachMailUser( + objType, iUnknown, + jniEnv, query, callback, callbackMethodID); + iUnknown->Release(); + } + else + { + /* We've failed but other parts of the hierarchy may still succeed. */ + proceed = JNI_TRUE; + } + return proceed; +} + +static jbyteArray +MsOutlookAddrBookContactQuery_readAttachment + (LPMESSAGE message, LONG method, ULONG num, JNIEnv *jniEnv, ULONG cond) +{ + jbyteArray attachment = NULL; + + if (ATTACH_BY_VALUE == method) + { + HRESULT hResult; + LPATTACH attach; + + hResult = message->OpenAttach(num, NULL, 0, &attach); + if (HR_SUCCEEDED(hResult)) + { + IStream *stream; + + if (PT_BOOLEAN == PROP_TYPE(cond)) + { + LPSPropValue condValue; + + hResult = HrGetOneProp((LPMAPIPROP) attach, cond, &condValue); + if (HR_SUCCEEDED(hResult)) + { + if ((PT_BOOLEAN != PROP_TYPE(condValue->ulPropTag)) + || !(condValue->Value.b)) + hResult = MAPI_E_NOT_FOUND; + MAPIFreeBuffer(condValue); + } + } + + if (HR_SUCCEEDED(hResult)) + { + hResult + = ((LPMAPIPROP) attach)->OpenProperty( + PR_ATTACH_DATA_BIN, + &IID_IStream, 0, + 0, + (LPUNKNOWN *) &stream); + } + if (HR_SUCCEEDED(hResult)) + { + STATSTG statstg; + ULONGLONG length; + + hResult = stream->Stat(&statstg, STATFLAG_NONAME); + if ((S_OK == hResult) && ((length = statstg.cbSize.QuadPart))) + { + attachment = jniEnv->NewByteArray((jsize) length); + if (attachment) + { + jbyte *bytes + = jniEnv->GetByteArrayElements(attachment, NULL); + + if (bytes) + { + ULONG read; + jint mode; + + hResult + = stream->Read(bytes, (ULONG) length, &read); + mode + = ((S_OK == hResult) || (S_FALSE == hResult)) + ? 0 + : JNI_ABORT; + jniEnv->ReleaseByteArrayElements( + attachment, bytes, + mode); + if (0 != mode) + attachment = NULL; + } + } + } + + stream->Release(); + } + + attach->Release(); + } + } + return attachment; +} diff --git a/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactSourceService.cxx b/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactSourceService.cxx index 20f9a3c6c..3e7aa2c38 100644 --- a/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactSourceService.cxx +++ b/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactSourceService.cxx @@ -1,5 +1,5 @@ /* - * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Distributable under LGPL license. * See terms of license at gnu.org. @@ -22,6 +22,13 @@ static LPMAPILOGONEX MsOutlookAddrBookContactSourceService_mapiLogonEx; static LPMAPIUNINITIALIZE MsOutlookAddrBookContactSourceService_mapiUninitialize; +static LPMAPISESSION MsOutlookAddrBookContactSourceService_mapiSession = NULL; +static CRITICAL_SECTION MsOutlookAddrBookContactSourceService_mapiSessionCriticalSection; + +static jboolean +MsOutlookAddrBookContactSourceService_isValidDefaultMailClient + (LPCTSTR name, DWORD nameLength); + JNIEXPORT void JNICALL Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactSourceService_MAPIInitialize (JNIEnv *jniEnv, jclass clazz, jlong version, jlong flags) @@ -193,9 +200,10 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac DWORD defaultValueLength = defaultValueSize / sizeof(TCHAR); - if ((0 == defaultValueLength) || (0 == defaultValue[0])) - checkHKeyLocalMachine = JNI_TRUE; - else + if (JNI_TRUE + == MsOutlookAddrBookContactSourceService_isValidDefaultMailClient( + defaultValue, + defaultValueLength)) { checkHKeyLocalMachine = JNI_FALSE; if (_tcsnicmp( @@ -204,6 +212,8 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac == 0) hResult = S_OK; } + else + checkHKeyLocalMachine = JNI_TRUE; } else checkHKeyLocalMachine = JNI_FALSE; @@ -246,10 +256,12 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac { DWORD defaultValueLength = defaultValueSize / sizeof(TCHAR); - if (_tcsnicmp( - _T("Microsoft Outlook"), defaultValue, - defaultValueLength) - == 0) + if ((_tcsnicmp( + _T("Microsoft Outlook"), defaultValue, + defaultValueLength) + == 0) + && (JNI_TRUE + == MsOutlookAddrBookContactSourceService_isValidDefaultMailClient(_T("Microsoft Outlook"), 17))) hResult = S_OK; } RegCloseKey(regKey); @@ -288,6 +300,10 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac GetProcAddress(lib, "MAPIFreeBuffer"); MsOutlookAddrBookContactSourceService_mapiLogonEx = (LPMAPILOGONEX) GetProcAddress(lib, "MAPILogonEx"); + + InitializeCriticalSection( + &MsOutlookAddrBookContactSourceService_mapiSessionCriticalSection); + if (MsOutlookAddrBookContactSourceService_mapiAllocateBuffer && MsOutlookAddrBookContactSourceService_mapiFreeBuffer && MsOutlookAddrBookContactSourceService_mapiLogonEx) @@ -315,7 +331,21 @@ JNIEXPORT void JNICALL Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactSourceService_MAPIUninitialize (JNIEnv *jniEnv, jclass clazz) { + EnterCriticalSection( + &MsOutlookAddrBookContactSourceService_mapiSessionCriticalSection); + if (MsOutlookAddrBookContactSourceService_mapiSession) + { + MsOutlookAddrBookContactSourceService_mapiSession->Logoff(0, 0, 0); + MsOutlookAddrBookContactSourceService_mapiSession->Release(); + MsOutlookAddrBookContactSourceService_mapiSession = NULL; + } + LeaveCriticalSection( + &MsOutlookAddrBookContactSourceService_mapiSessionCriticalSection); + MsOutlookAddrBookContactSourceService_mapiUninitialize(); + + DeleteCriticalSection( + &MsOutlookAddrBookContactSourceService_mapiSessionCriticalSection); } SCODE @@ -338,10 +368,63 @@ MsOutlookAddrBook_mapiLogonEx FLAGS flags, LPMAPISESSION FAR *mapiSession) { - return - MsOutlookAddrBookContactSourceService_mapiLogonEx( - uiParam, - profileName, password, - flags, - mapiSession); + HRESULT hResult; + + EnterCriticalSection( + &MsOutlookAddrBookContactSourceService_mapiSessionCriticalSection); + if (MsOutlookAddrBookContactSourceService_mapiSession) + hResult = S_OK; + else + { + hResult + = MsOutlookAddrBookContactSourceService_mapiLogonEx( + uiParam, + profileName, password, + flags, + &MsOutlookAddrBookContactSourceService_mapiSession); + } + if (HR_SUCCEEDED(hResult)) + *mapiSession = MsOutlookAddrBookContactSourceService_mapiSession; + LeaveCriticalSection( + &MsOutlookAddrBookContactSourceService_mapiSessionCriticalSection); + + return hResult; +} + +static jboolean +MsOutlookAddrBookContactSourceService_isValidDefaultMailClient + (LPCTSTR name, DWORD nameLength) +{ + jboolean validDefaultMailClient = JNI_FALSE; + + if ((0 != nameLength) && (0 != name[0])) + { + LPTSTR str; + TCHAR keyName[ + 22 /* Software\Clients\Mail\ */ + + 255 + + 1 /* The terminating null character */]; + HKEY key; + + str = keyName; + _tcsncpy(str, _T("Software\\Clients\\Mail\\"), 22); + str += 22; + if (nameLength > 255) + nameLength = 255; + _tcsncpy(str, name, nameLength); + *(str + nameLength) = 0; + + if (ERROR_SUCCESS + == RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + keyName, + 0, + KEY_QUERY_VALUE, + &key)) + { + validDefaultMailClient = JNI_TRUE; + RegCloseKey(key); + } + } + return validDefaultMailClient; } diff --git a/src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf b/src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf index fbafa493c..b42344a33 100644 --- a/src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf +++ b/src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf @@ -3,13 +3,13 @@ Bundle-Description: OS-specific Address Book support Bundle-Name: OS-specific Address Book support Bundle-Vendor: sip-communicator.org Bundle-Version: 0.0.1 -Import-Package: net.java.sip.communicator.service.contactsource, +Import-Package: javax.swing, + net.java.sip.communicator.service.configuration, + net.java.sip.communicator.service.contactsource, + net.java.sip.communicator.service.gui, net.java.sip.communicator.service.protocol, + net.java.sip.communicator.service.resources, net.java.sip.communicator.util, - net.java.sip.communicator.service.gui, - net.java.sip.communicator.util.swing, - net.java.sip.communicator.service.resources, - net.java.sip.communicator.service.configuration, - org.osgi.framework, - javax.swing + net.java.sip.communicator.util.swing, + org.osgi.framework System-Bundle: yes diff --git a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java index 063c78ee3..229137822 100644 --- a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java +++ b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java @@ -12,6 +12,7 @@ import net.java.sip.communicator.plugin.addrbook.*; import net.java.sip.communicator.service.contactsource.*; import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; /** * Implements ContactQuery for the Address Book of Microsoft Outlook. @@ -21,6 +22,13 @@ public class MsOutlookAddrBookContactQuery extends AsyncContactQuery { + /** + * The Logger used by the MsOutlookAddrBookContactQuery + * class and its instances for logging output. + */ + private static final Logger logger + = Logger.getLogger(MsOutlookAddrBookContactQuery.class); + private static final int dispidEmail1EmailAddress = 11; private static final int dispidEmail2EmailAddress = 12; @@ -53,7 +61,8 @@ public class MsOutlookAddrBookContactQuery 0x0FFE /* PR_OBJECT_TYPE */, 0x00008083 /* dispidEmail1EmailAddress */, 0x00008093 /* dispidEmail2EmailAddress */, - 0x000080A3 /* dispidEmail3EmailAddress */ + 0x000080A3 /* dispidEmail3EmailAddress */, + 0x3A16 /* PR_COMPANY_NAME */ }; /** @@ -85,6 +94,8 @@ public class MsOutlookAddrBookContactQuery */ private static final int PR_BUSINESS2_TELEPHONE_NUMBER = 6; + private static final int PR_COMPANY_NAME = 14; + /** * The index of the id of the PR_DISPLAY_NAME property in * {@link #MAPI_MAILUSER_PROP_IDS}. @@ -376,35 +387,49 @@ private boolean onMailUser(long iUnknown) } } - GenericSourceContact sourceContact - = new GenericSourceContact( - getContactSource(), - (String) props[PR_DISPLAY_NAME], - contactDetails); - - if (MAPI_MESSAGE == objType) + /* + * What's the point of showing a contact who has no contact details? + */ + if (!contactDetails.isEmpty()) { - ++mapiMessageCount; + String displayName = (String) props[PR_DISPLAY_NAME]; - try - { - Object[] images - = IMAPIProp_GetProps( - iUnknown, - new long[] { PR_ATTACHMENT_CONTACTPHOTO }, - 0); - Object image = images[0]; - - if (image instanceof byte[]) - sourceContact.setImage((byte[]) image); - } - catch (MsOutlookMAPIHResultException ex) + if ((displayName == null) || (displayName.length() == 0)) + displayName = (String) props[PR_COMPANY_NAME]; + + GenericSourceContact sourceContact + = new GenericSourceContact( + getContactSource(), + displayName, + contactDetails); + + if (MAPI_MESSAGE == objType) { - // Ignore it, the image isn't as vital as the SourceContact. + ++mapiMessageCount; + + try + { + Object[] images + = IMAPIProp_GetProps( + iUnknown, + new long[] { PR_ATTACHMENT_CONTACTPHOTO }, + 0); + Object image = images[0]; + + if (image instanceof byte[]) + sourceContact.setImage((byte[]) image); + } + catch (MsOutlookMAPIHResultException ex) + { + /* + * Ignore it, the image isn't as vital as the + * SourceContact. + */ + } } - } - addQueryResult(sourceContact); + addQueryResult(sourceContact); + } } return (getStatus() == QUERY_IN_PROGRESS); } @@ -416,23 +441,33 @@ private boolean onMailUser(long iUnknown) */ protected void run() { - foreachMailUser( - query.toString(), - new PtrCallback() - { - public boolean callback(long iUnknown) + synchronized (MsOutlookAddrBookContactQuery.class) + { + foreachMailUser( + query.toString(), + new PtrCallback() { - try + public boolean callback(long iUnknown) { - return onMailUser(iUnknown); - } - catch (MsOutlookMAPIHResultException ex) - { - ex.printStackTrace(System.err); - return false; + try + { + return onMailUser(iUnknown); + } + catch (MsOutlookMAPIHResultException e) + { + if (logger.isDebugEnabled()) + { + logger.debug( + MsOutlookAddrBookContactQuery.class + .getSimpleName() + + "#onMailUser(long)", + e); + } + return false; + } } - } - }); + }); + } } /**