diff options
author | hristoterezov <hristo@jitsi.org> | 2014-04-02 17:04:44 +0300 |
---|---|---|
committer | hristoterezov <hristo@jitsi.org> | 2014-04-02 17:04:44 +0300 |
commit | 96ef724f2db9365250a7a9d76dbe8b19c3987f55 (patch) | |
tree | ef97430715621ab5579739acd4fa75903c048026 | |
parent | a325c6bc19214271cf7e98768179b5a71257eb91 (diff) | |
download | jitsi-96ef724f2db9365250a7a9d76dbe8b19c3987f55.zip jitsi-96ef724f2db9365250a7a9d76dbe8b19c3987f55.tar.gz jitsi-96ef724f2db9365250a7a9d76dbe8b19c3987f55.tar.bz2 |
Adds CalendarService implementation. The Calendar service calculates the free busy status based on outlook meetings.
45 files changed, 3507 insertions, 410 deletions
@@ -2762,6 +2762,8 @@ javax.swing.event, javax.swing.border"/> manifest="${src}/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf"> <zipfileset dir="${dest}/net/java/sip/communicator/plugin/addrbook" prefix="net/java/sip/communicator/plugin/addrbook" /> + <zipfileset dir="${dest}/net/java/sip/communicator/service/calendar" + prefix="net/java/sip/communicator/service/calendar" /> </jar> </target> diff --git a/lib/native/windows-64/IMsOutlookAddrBookClient.tlb b/lib/native/windows-64/IMsOutlookAddrBookClient.tlb Binary files differindex 168d9ad..6873acd 100644 --- a/lib/native/windows-64/IMsOutlookAddrBookClient.tlb +++ b/lib/native/windows-64/IMsOutlookAddrBookClient.tlb diff --git a/lib/native/windows-64/IMsOutlookAddrBookServer.tlb b/lib/native/windows-64/IMsOutlookAddrBookServer.tlb Binary files differindex 9492af3..267171f 100644 --- a/lib/native/windows-64/IMsOutlookAddrBookServer.tlb +++ b/lib/native/windows-64/IMsOutlookAddrBookServer.tlb diff --git a/lib/native/windows-64/jmsoutlookaddrbook.dll b/lib/native/windows-64/jmsoutlookaddrbook.dll Binary files differindex f58c4c9..7072f4a 100755 --- a/lib/native/windows-64/jmsoutlookaddrbook.dll +++ b/lib/native/windows-64/jmsoutlookaddrbook.dll diff --git a/lib/native/windows-64/jmsoutlookaddrbookcomserver32.exe b/lib/native/windows-64/jmsoutlookaddrbookcomserver32.exe Binary files differindex 087e118..b249bfd 100755 --- a/lib/native/windows-64/jmsoutlookaddrbookcomserver32.exe +++ b/lib/native/windows-64/jmsoutlookaddrbookcomserver32.exe diff --git a/lib/native/windows-64/jmsoutlookaddrbookcomserver64.exe b/lib/native/windows-64/jmsoutlookaddrbookcomserver64.exe Binary files differindex 6cedd98..e78d5fa 100755 --- a/lib/native/windows-64/jmsoutlookaddrbookcomserver64.exe +++ b/lib/native/windows-64/jmsoutlookaddrbookcomserver64.exe diff --git a/resources/images/protocol/jabber/status16x16-meeting.png b/resources/images/protocol/jabber/status16x16-meeting.png Binary files differnew file mode 100644 index 0000000..9e24e1b --- /dev/null +++ b/resources/images/protocol/jabber/status16x16-meeting.png diff --git a/resources/images/protocol/msn/msn16x16-meeting.png b/resources/images/protocol/msn/msn16x16-meeting.png Binary files differnew file mode 100644 index 0000000..c2fd663 --- /dev/null +++ b/resources/images/protocol/msn/msn16x16-meeting.png diff --git a/resources/images/protocol/sip/sip16x16-meeting.png b/resources/images/protocol/sip/sip16x16-meeting.png Binary files differnew file mode 100644 index 0000000..d196310 --- /dev/null +++ b/resources/images/protocol/sip/sip16x16-meeting.png diff --git a/src/native/addrbook/msoutlook/MAPINotification.cxx b/src/native/addrbook/msoutlook/MAPINotification.cxx index d2f2422..5a3a500 100644 --- a/src/native/addrbook/msoutlook/MAPINotification.cxx +++ b/src/native/addrbook/msoutlook/MAPINotification.cxx @@ -43,13 +43,23 @@ static ULONG MAPINotification_nbMsgStores = 0; static jmethodID MAPINotification_notificationsDelegateMethodIdDeleted = NULL; static jmethodID MAPINotification_notificationsDelegateMethodIdInserted = NULL; static jmethodID MAPINotification_notificationsDelegateMethodIdUpdated = NULL; +static jmethodID MAPINotification_notificationsDelegateCalendarMethodIdDeleted + = NULL; +static jmethodID MAPINotification_notificationsDelegateCalendarMethodIdInserted + = NULL; +static jmethodID MAPINotification_notificationsDelegateCalendarMethodIdUpdated + = NULL; static jobject MAPINotification_notificationsDelegateObject = NULL; +static jobject MAPINotification_notificationsDelegateCalendarObject = NULL; static ULONG MAPINotification_openEntryUlFlags = MAPI_BEST_ACCESS; static JavaVM * MAPINotification_VM = NULL; void (*MAPINotification_callDeletedMethod)(LPSTR iUnknown) = NULL; void (*MAPINotification_callInsertedMethod)(LPSTR iUnknown) = NULL; void (*MAPINotification_callUpdatedMethod)(LPSTR iUnknown) = NULL; +void (*MAPINotification_callCalendarDeletedMethod)(LPSTR iUnknown) = NULL; +void (*MAPINotification_callCalendarInsertedMethod)(LPSTR iUnknown) = NULL; +void (*MAPINotification_callCalendarUpdatedMethod)(LPSTR iUnknown) = NULL; ULONG MAPINotification_registerNotifyMessageDataBase (LPMDB iUnknown, LPMAPIADVISESINK * adviseSink); @@ -129,10 +139,17 @@ void MAPINotification_jniCallDeletedMethod(LPSTR iUnknown) { jstring value = tmpJniEnv->NewStringUTF(iUnknown); - tmpJniEnv->CallVoidMethod( - MAPINotification_notificationsDelegateObject, - MAPINotification_notificationsDelegateMethodIdDeleted, - value); + if(MAPINotification_notificationsDelegateObject != NULL) + tmpJniEnv->CallVoidMethod( + MAPINotification_notificationsDelegateObject, + MAPINotification_notificationsDelegateMethodIdDeleted, + value); + + if(MAPINotification_notificationsDelegateCalendarObject != NULL) + tmpJniEnv->CallVoidMethod( + MAPINotification_notificationsDelegateCalendarObject, + MAPINotification_notificationsDelegateCalendarMethodIdDeleted, + value); tmpJniEnv->DeleteLocalRef(value); @@ -154,10 +171,17 @@ void MAPINotification_jniCallInsertedMethod(LPSTR iUnknown) { jstring value = tmpJniEnv->NewStringUTF(iUnknown); - tmpJniEnv->CallVoidMethod( - MAPINotification_notificationsDelegateObject, - MAPINotification_notificationsDelegateMethodIdInserted, - value); + if(MAPINotification_notificationsDelegateObject != NULL) + tmpJniEnv->CallVoidMethod( + MAPINotification_notificationsDelegateObject, + MAPINotification_notificationsDelegateMethodIdInserted, + value); + + if(MAPINotification_notificationsDelegateCalendarObject != NULL) + tmpJniEnv->CallVoidMethod( + MAPINotification_notificationsDelegateCalendarObject, + MAPINotification_notificationsDelegateCalendarMethodIdInserted, + value); tmpJniEnv->DeleteLocalRef(value); @@ -173,16 +197,23 @@ void MAPINotification_jniCallInsertedMethod(LPSTR iUnknown) void MAPINotification_jniCallUpdatedMethod(LPSTR iUnknown) { JNIEnv *tmpJniEnv = NULL; - if(MAPINotification_VM ->AttachCurrentThreadAsDaemon((void**) &tmpJniEnv, NULL) == 0) { jstring value = tmpJniEnv->NewStringUTF(iUnknown); - tmpJniEnv->CallVoidMethod( - MAPINotification_notificationsDelegateObject, - MAPINotification_notificationsDelegateMethodIdUpdated, - value); + if(MAPINotification_notificationsDelegateObject != NULL) + tmpJniEnv->CallVoidMethod( + MAPINotification_notificationsDelegateObject, + MAPINotification_notificationsDelegateMethodIdUpdated, + value); + + if(MAPINotification_notificationsDelegateCalendarObject != NULL) + tmpJniEnv->CallVoidMethod( + MAPINotification_notificationsDelegateCalendarObject, + MAPINotification_notificationsDelegateCalendarMethodIdUpdated, + value); + tmpJniEnv->DeleteLocalRef(value); @@ -425,6 +456,60 @@ MAPINotification_registerJniNotificationsDelegate } } + +/** + * Registers java callback functions when a calendar item is deleted, inserted or + * updated. + * + * @param jniEnv The Java native interface environment. + * @param notificationsDelegate The object called when a notification is fired + * (contact updated, inserted or deleted). + */ +void +MAPINotification_registerCalendarJniNotificationsDelegate + (JNIEnv *jniEnv, jobject notificationsDelegate) +{ + if(jniEnv->GetJavaVM(&MAPINotification_VM) < 0) + { + fprintf(stderr, "Failed to get the Java VM\n"); + fflush(stderr); + } + + if(notificationsDelegate != NULL) + { + MAPINotification_notificationsDelegateCalendarObject + = jniEnv->NewGlobalRef(notificationsDelegate); + if(MAPINotification_notificationsDelegateCalendarObject != NULL) + { + jclass callbackClass + = jniEnv->GetObjectClass(notificationsDelegate); + MAPINotification_notificationsDelegateCalendarMethodIdInserted + = jniEnv->GetMethodID( + callbackClass, + "inserted", + "(Ljava/lang/String;)V"); + MAPINotification_notificationsDelegateCalendarMethodIdUpdated + = jniEnv->GetMethodID( + callbackClass, + "updated", + "(Ljava/lang/String;)V"); + MAPINotification_notificationsDelegateCalendarMethodIdDeleted + = jniEnv->GetMethodID( + callbackClass, + "deleted", + "(Ljava/lang/String;)V"); + + MAPINotification_callDeletedMethod + = MAPINotification_jniCallDeletedMethod; + MAPINotification_callInsertedMethod + = MAPINotification_jniCallInsertedMethod; + MAPINotification_callUpdatedMethod + = MAPINotification_jniCallUpdatedMethod; + + jniEnv->DeleteLocalRef(callbackClass); + } + } +} /** * Registers C callback functions when a contact is deleted, inserted or * updated. diff --git a/src/native/addrbook/msoutlook/MAPINotification.h b/src/native/addrbook/msoutlook/MAPINotification.h index f1517d7..f7b9f05 100644 --- a/src/native/addrbook/msoutlook/MAPINotification.h +++ b/src/native/addrbook/msoutlook/MAPINotification.h @@ -36,6 +36,10 @@ STDAPICALLTYPE MAPINotification_onNotify void MAPINotification_registerJniNotificationsDelegate (JNIEnv *jniEnv, jobject notificationsDelegate); + +void +MAPINotification_registerCalendarJniNotificationsDelegate + (JNIEnv *jniEnv, jobject notificationsDelegate); void MAPINotification_registerNativeNotificationsDelegate (void * deletedMethod, void * insertedMethod, void *updatedMethod); diff --git a/src/native/addrbook/msoutlook/MAPISession.cxx b/src/native/addrbook/msoutlook/MAPISession.cxx index fb672b4..2b6988d 100644 --- a/src/native/addrbook/msoutlook/MAPISession.cxx +++ b/src/native/addrbook/msoutlook/MAPISession.cxx @@ -5,6 +5,7 @@ * See terms of license at gnu.org.
*/
#include "MAPISession.h"
+#include <stdio.h>
static LPMAPISESSION MAPISession_mapiSession = NULL;
static CRITICAL_SECTION MAPISession_mapiSessionCriticalSection;
diff --git a/src/native/addrbook/msoutlook/MsOutlookAddrBookContactQuery.cxx b/src/native/addrbook/msoutlook/MsOutlookAddrBookContactQuery.cxx index d24b305..f3d9d2f 100644 --- a/src/native/addrbook/msoutlook/MsOutlookAddrBookContactQuery.cxx +++ b/src/native/addrbook/msoutlook/MsOutlookAddrBookContactQuery.cxx @@ -5,6 +5,7 @@ * See terms of license at gnu.org. */ +#include "MsOutlookUtils.h" #include "MsOutlookAddrBookContactQuery.h" #include "MsOutlookAddrBookContactSourceService.h" @@ -43,22 +44,10 @@ typedef struct MsOutlookAddrBookContactQuery_OneOffEntryID typedef UNALIGNED ONEOFFENTRYID *MsOutlookAddrBookContactQuery_LPONEOFFENTRYID; -typedef - jboolean (*MsOutlookAddrBookContactQuery_ForeachRowInTableCallback) - (LPUNKNOWN iUnknown, - ULONG entryIDByteCount, LPENTRYID entryID, ULONG objType, - const char * query, - void * callbackMethod, - void * callbackClient, - long callbackAddress); - static ULONG MsOutlookAddrBookContactQuery_rdOpenEntryUlFlags = 0x0; static ULONG MsOutlookAddrBookContactQuery_rwOpenEntryUlFlags = MAPI_BEST_ACCESS; -static HRESULT MsOutlookAddrBookContactQuery_HrGetOneProp - (LPMAPIPROP mapiProp, ULONG propTag, LPSPropValue *prop); - HRESULT MsOutlookAddrBookContactQuery_buildOneOff (LPWSTR displayName, LPWSTR addressType, LPWSTR emailAddress, ULONG* oneOffEntryIdLength, LPBYTE* oneOffEntryId); @@ -69,26 +58,12 @@ HRESULT MsOutlookAddrBookContactQuery_createEmailAddress static jboolean MsOutlookAddrBookContactQuery_foreachContactInMsgStoresTable (LPMAPISESSION mapiSession, const char * query, void * callbackMethod, void * callbackClient, long callbackAddress); -static jboolean MsOutlookAddrBookContactQuery_foreachMailUser - (ULONG objType, LPUNKNOWN iUnknown, - const char * query, - void * callbackMethod, - void * callbackClient, - long callbackAddress); static jboolean MsOutlookAddrBookContactQuery_foreachMailUserInContainerTable (LPMAPICONTAINER mapiContainer, LPMAPITABLE mapiTable, const char * query, void * callbackMethod, void * callbackClient, long callbackAddress); -static jboolean MsOutlookAddrBookContactQuery_foreachRowInTable - (LPMAPITABLE mapiTable, - MsOutlookAddrBookContactQuery_ForeachRowInTableCallback rowCallback, - LPUNKNOWN iUnknown, - const char * query, - void * callbackMethod, - void * callbackClient, - long callbackAddress); static void MsOutlookAddrBookContactQuery_freeSRowSet(LPSRowSet rows); static void* MsOutlookAddrBookContactQuery_getAttachmentContactPhoto (LPMESSAGE message, ULONGLONG * length); @@ -104,9 +79,9 @@ LPMAPIFOLDER MsOutlookAddrBookContactQuery_getDefaultContactFolderId (ULONG flags); LPMDB MsOutlookAddrBookContactQuery_getDefaultMsgStores(ULONG flags); ULONG MsOutlookAddrBookContactQuery_getPropTag - (LPMAPIPROP mapiProp, long propId, long propType); + (LPMAPIPROP mapiProp, long propId, long propType, UUID UUID_Address); static ULONG MsOutlookAddrBookContactQuery_getPropTagFromLid - (LPMAPIPROP mapiProp, LONG lid); + (LPMAPIPROP mapiProp, LONG lid, UUID UUID_Address); static jboolean MsOutlookAddrBookContactQuery_mailUserMatches (LPMAPIPROP mailUser, const char * query); static jboolean MsOutlookAddrBookContactQuery_onForeachContactInMsgStoresTableRow @@ -470,7 +445,7 @@ MsOutlookAddrBookContactQuery_foreachContactInMsgStoresTable return proceed; } -static jboolean +jboolean MsOutlookAddrBookContactQuery_foreachMailUser (ULONG objType, LPUNKNOWN iUnknown, const char * query, @@ -567,7 +542,7 @@ MsOutlookAddrBookContactQuery_foreachMailUserInContainerTable callbackAddress); } -static jboolean +jboolean MsOutlookAddrBookContactQuery_foreachRowInTable (LPMAPITABLE mapiTable, MsOutlookAddrBookContactQuery_ForeachRowInTableCallback rowCallback, @@ -823,46 +798,14 @@ MsOutlookAddrBookContactQuery_getContactsFolderEntryID ULONG *contactsFolderEntryIDByteCount, LPENTRYID *contactsFolderEntryID, ULONG flags) { - HRESULT hResult; - ULONG objType; - LPUNKNOWN folder; - - hResult = msgStore->OpenEntry( - folderEntryIDByteCount, - folderEntryID, - NULL, - flags, - &objType, - &folder); - - if (HR_SUCCEEDED(hResult)) - { - LPSPropValue prop; - - hResult - = MsOutlookAddrBookContactQuery_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; + return MsOutlookUtils_getFolderEntryIDByType( + msgStore, + folderEntryIDByteCount, + folderEntryID, + contactsFolderEntryIDByteCount, + contactsFolderEntryID, + flags, + 0x36D10102 /* PR_IPM_CONTACT_ENTRYID */); } /** @@ -1038,7 +981,8 @@ LPMDB MsOutlookAddrBookContactQuery_getDefaultMsgStores(ULONG flags) * @return The property tag associated for the given identifier and type. */ ULONG MsOutlookAddrBookContactQuery_getPropTag - (LPMAPIPROP mapiProp, long propId, long propType) + (LPMAPIPROP mapiProp, long propId, long propType, + UUID UUID_Address) { ULONG propTag; @@ -1053,7 +997,7 @@ ULONG MsOutlookAddrBookContactQuery_getPropTag { propTag = MsOutlookAddrBookContactQuery_getPropTagFromLid( (LPMAPIPROP) mapiProp, - (LONG)propId); + (LONG)propId, UUID_Address); propTag = CHANGE_PROP_TYPE(propTag, propType); } @@ -1061,17 +1005,15 @@ ULONG MsOutlookAddrBookContactQuery_getPropTag } static ULONG -MsOutlookAddrBookContactQuery_getPropTagFromLid(LPMAPIPROP mapiProp, LONG lid) +MsOutlookAddrBookContactQuery_getPropTagFromLid(LPMAPIPROP mapiProp, LONG lid, + UUID UUID_Address) { - 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.lpguid = (LPGUID) &UUID_Address; propName.ulKind = MNID_ID; propName.Kind.lID = lid; propNamePtr = &propName; @@ -1094,55 +1036,6 @@ MsOutlookAddrBookContactQuery_getPropTagFromLid(LPMAPIPROP mapiProp, LONG lid) } /** - * Get one property for a given contact. - * - * @param mapiProp A pointer to the contact. - * @param propTag The tag of the property to get. - * @param prop The memory location to store the property value. - * - * @return S_OK if everything work fine. Any other value is a failure. - */ -static HRESULT -MsOutlookAddrBookContactQuery_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; - MAPIFreeBuffer(values); - } - return hResult; -} - -/** * Deletes one property from a contact. * * @param propId The outlook property identifier. @@ -1199,7 +1092,8 @@ int MsOutlookAddrBookContactQuery_IMAPIProp_1DeleteProp propTag = MsOutlookAddrBookContactQuery_getPropTag( (LPMAPIPROP) mapiProp, propIds[i], - PT_UNICODE); + PT_UNICODE, + MsOutlookAddrBookContactQuery_UUID_Address); *(propTagArray->aulPropTag + i) = propTag; } @@ -1233,7 +1127,8 @@ int MsOutlookAddrBookContactQuery_IMAPIProp_1DeleteProp propToDelete.aulPropTag[0] = MsOutlookAddrBookContactQuery_getPropTag( (LPMAPIPROP) mapiProp, propId, - PT_UNICODE); + PT_UNICODE, + MsOutlookAddrBookContactQuery_UUID_Address); HRESULT hResult = ((LPMAPIPROP) mapiProp)->DeleteProps( @@ -1265,7 +1160,8 @@ HRESULT MsOutlookAddrBookContactQuery_IMAPIProp_1GetProps( long flags, void ** props, unsigned long* propsLength, - char * propsType) + char * propsType, + UUID UUID_Address) { HRESULT hr = E_FAIL; LPSPropTagArray propTagArray; @@ -1296,7 +1192,8 @@ HRESULT MsOutlookAddrBookContactQuery_IMAPIProp_1GetProps( ULONG propTag = MsOutlookAddrBookContactQuery_getPropTag( (LPMAPIPROP) mapiProp, propId, - PT_UNSPECIFIED); + PT_UNSPECIFIED, + UUID_Address); *(propTagArray->aulPropTag + i) = propTag; } @@ -1334,6 +1231,19 @@ HRESULT MsOutlookAddrBookContactQuery_IMAPIProp_1GetProps( (ULONGLONG*) &propsLength[j]); propsType[j] = 'b'; // byte array } + else if(prop->Value.b) + { + propsLength[j] = sizeof(prop->Value.b); + if( (props[j] = malloc(propsLength[j])) + != NULL) + { + memcpy( + props[j], + &prop->Value.b, + propsLength[j]); + propsType[j] = 'B'; + } + } break; } @@ -1391,18 +1301,55 @@ HRESULT MsOutlookAddrBookContactQuery_IMAPIProp_1GetProps( case PT_BINARY: { - propsLength[j] = prop->Value.bin.cb * 2 + 1; - if((props[j] = malloc(propsLength[j])) - != NULL) - { - HexFromBin( - prop->Value.bin.lpb, - prop->Value.bin.cb, - (LPSTR) props[j]); + if(IsEqualGUID(UUID_Address, MsOutlookAddrBookContactQuery_UUID_Address)) + { + propsLength[j] = prop->Value.bin.cb * 2 + 1; + if((props[j] = malloc(propsLength[j])) + != NULL) + { + HexFromBin( + prop->Value.bin.lpb, + prop->Value.bin.cb, + (LPSTR) props[j]); + + propsType[j] = 's'; // 16 bits string + } + + } + else + { + propsLength[j] = prop->Value.bin.cb; + if((props[j] = malloc(propsLength[j])) + != NULL) + { + memcpy(props[j], + prop->Value.bin.lpb, + prop->Value.bin.cb); + + propsType[j] = 'b'; + } + } + break; + } - propsType[j] = 's'; // 16 bits string - } - break; + case PT_SYSTIME: + { + propsLength[j] = sizeof(SYSTEMTIME); + if((props[j] = malloc(propsLength[j])) + != NULL) + { + FILETIME lpLocalFileTime; + SYSTEMTIME systime; + FileTimeToLocalFileTime( + &prop->Value.ft, + &lpLocalFileTime); + FileTimeToSystemTime( + &prop->Value.ft, + &systime); + memcpy(props[j],&systime, propsLength[j]); + propsType[j] = 't'; + } + break; } } } @@ -1486,7 +1433,8 @@ int MsOutlookAddrBookContactQuery_IMAPIProp_1SetPropString propTag = MsOutlookAddrBookContactQuery_getPropTag( (LPMAPIPROP) mapiProp, propIds[i], - PT_UNSPECIFIED); + PT_UNSPECIFIED, + MsOutlookAddrBookContactQuery_UUID_Address); *(propTagArray->aulPropTag + i) = propTag; } hResult = ((LPMAPIPROP) mapiProp)->GetProps( @@ -1569,7 +1517,8 @@ int MsOutlookAddrBookContactQuery_IMAPIProp_1SetPropString updateValue.ulPropTag = MsOutlookAddrBookContactQuery_getPropTag( (LPMAPIPROP) mapiProp, propId, - PT_UNICODE); + PT_UNICODE, + MsOutlookAddrBookContactQuery_UUID_Address); updateValue.Value.lpszW = wCharValue; hResult = ((LPMAPIPROP) mapiProp)->SetProps( @@ -1809,7 +1758,7 @@ MsOutlookAddrBookContactQuery_readAttachment { LPSPropValue condValue; - hResult = MsOutlookAddrBookContactQuery_HrGetOneProp( + hResult = MsOutlookUtils_HrGetOneProp( (LPMAPIPROP) attach, cond, &condValue); diff --git a/src/native/addrbook/msoutlook/MsOutlookAddrBookContactQuery.h b/src/native/addrbook/msoutlook/MsOutlookAddrBookContactQuery.h index 99fd749..a535543 100644 --- a/src/native/addrbook/msoutlook/MsOutlookAddrBookContactQuery.h +++ b/src/native/addrbook/msoutlook/MsOutlookAddrBookContactQuery.h @@ -8,6 +8,32 @@ #define _NET_JAVA_SIP_COMMUNICATOR_PLUGIN_ADDRBOOK_MSOUTLOOK_MSOUTLOOKADDRBOOKCONTACTQUERY_H_ #include <mapidefs.h> +#include <jni.h> + +typedef + jboolean (*MsOutlookAddrBookContactQuery_ForeachRowInTableCallback) + (LPUNKNOWN iUnknown, + ULONG entryIDByteCount, LPENTRYID entryID, ULONG objType, + const char * query, + void * callbackMethod, + void * callbackClient, + long callbackAddress); + +jboolean MsOutlookAddrBookContactQuery_foreachRowInTable + (LPMAPITABLE mapiTable, + MsOutlookAddrBookContactQuery_ForeachRowInTableCallback rowCallback, + LPUNKNOWN iUnknown, + const char * query, + void * callbackMethod, + void * callbackClient, + long callbackAddress); + +jboolean MsOutlookAddrBookContactQuery_foreachMailUser + (ULONG objType, LPUNKNOWN iUnknown, + const char * query, + void * callbackMethod, + void * callbackClient, + long callbackAddress); int MsOutlookAddrBookContactQuery_IMAPIProp_1DeleteProp (long propId, const char * nativeEntryId); @@ -19,7 +45,8 @@ long MsOutlookAddrBookContactQuery_IMAPIProp_1GetProps( long flags, void ** props, unsigned long* propsLength, - char * propsType); + char * propsType, + UUID UUID_Address); int MsOutlookAddrBookContactQuery_IMAPIProp_1SetPropString (long propId, const wchar_t* nativeValue, const char* nativeEntryId); @@ -40,4 +67,6 @@ char* MsOutlookAddrBookContactQuery_getStringUnicodeProp int MsOutlookAddrBookContactQuery_compareEntryIds (LPSTR id1, LPSTR id2); +#define MsOutlookAddrBookContactQuery_UUID_Address (UUID){0x00062004, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} + #endif diff --git a/src/native/addrbook/msoutlook/MsOutlookCalendar.cxx b/src/native/addrbook/msoutlook/MsOutlookCalendar.cxx new file mode 100644 index 0000000..5667488 --- /dev/null +++ b/src/native/addrbook/msoutlook/MsOutlookCalendar.cxx @@ -0,0 +1,194 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +#include "MsOutlookUtils.h" +#include "MsOutlookAddrBookContactQuery.h" +#include "MsOutlookCalendar.h" +#include "MAPINotification.h" +#include "MsOutlookAddrBookContactSourceService.h" + +#include "MAPISession.h" +#include "StringUtils.h" +#include <Mapidefs.h> +#include <jni.h> + +static ULONG MsOutlookCalendar_rdOpenEntryUlFlags = 0x0; + +static void* callbackObject = NULL; + +jboolean MsOutlookCalendar_foreachCalendarItemCallback( + LPSTR iUnknown, + void * object); + +static jboolean +MsOutlookCalendar_onForeachCalendarInMsgStoresTableRow + (LPUNKNOWN mapiSession, + ULONG entryIDByteCount, LPENTRYID entryID, ULONG objType, + const char * query, void * callbackMethod, void * callbackClient, + long callbackAddress); + +static HRESULT +MsOutlookCalendar_getCalendarFolderEntryID + (LPMDB msgStore, + ULONG folderEntryIDByteCount, LPENTRYID folderEntryID, + ULONG *calendarFolderEntryIDByteCount, LPENTRYID *calendarFolderEntryID, + ULONG flags); + +void MsOutlookCalendar_setCallbackObject(void *callback) +{ + callbackObject = callback; +} + +void MsOutlookCalendar_getAllCalendarItems( + void * callbackMethod, + void * callbackClient, + long callbackAddress) +{ + MAPISession_lock(); + LPMAPISESSION mapiSession = MAPISession_getMapiSession(); + if (mapiSession == NULL) + { + MAPISession_unlock(); + return; + } + HRESULT hResult; + LPMAPITABLE msgStoresTable = NULL; + hResult = mapiSession->GetMsgStoresTable(0, &msgStoresTable); + if (HR_SUCCEEDED(hResult) && msgStoresTable) + { + MsOutlookAddrBookContactQuery_foreachRowInTable( + msgStoresTable, + MsOutlookCalendar_onForeachCalendarInMsgStoresTableRow, + (LPUNKNOWN) mapiSession, + NULL,callbackMethod, + callbackClient, + callbackAddress); + msgStoresTable->Release(); + } + + MAPISession_unlock(); +} + +jboolean MsOutlookCalendar_foreachCalendarItemCallback( + LPSTR iUnknown, + long callbackObject) +{ + + LPWSTR iUnknownW = StringUtils::MultiByteToWideChar(iUnknown); + BSTR res = SysAllocString(iUnknownW); + + char * charId = StringUtils::WideCharToMultiByte(res); + MAPINotification_callCallbackMethod(charId, callbackObject); + free(charId); + + SysFreeString(res); + free(iUnknownW); + + return true; +} + + +static jboolean +MsOutlookCalendar_onForeachCalendarInMsgStoresTableRow + (LPUNKNOWN mapiSession, + ULONG entryIDByteCount, LPENTRYID entryID, ULONG objType, + const char * query, + void * callbackMethod, + void * callbackClient, + long callbackAddress) +{ + HRESULT hResult; + LPMDB msgStore; + // In case, that we've failed but other parts of the hierarchy may still + // succeed. + jboolean proceed = JNI_TRUE; + + hResult = ((LPMAPISESSION) mapiSession)->OpenMsgStore( + 0, + entryIDByteCount, entryID, + NULL, + MDB_NO_MAIL | MsOutlookCalendar_rdOpenEntryUlFlags, + &msgStore); + if (HR_SUCCEEDED(hResult)) + { + LPENTRYID receiveFolderEntryID = NULL; + ULONG calendarFolderEntryIDByteCount = 0; + LPENTRYID calendarFolderEntryID = NULL; + + hResult = msgStore->GetReceiveFolder( + NULL, + 0, + &entryIDByteCount, + &receiveFolderEntryID, + NULL); + if (HR_SUCCEEDED(hResult)) + { + hResult = MsOutlookCalendar_getCalendarFolderEntryID( + msgStore, + entryIDByteCount, + receiveFolderEntryID, + &calendarFolderEntryIDByteCount, + &calendarFolderEntryID, + MsOutlookCalendar_rdOpenEntryUlFlags); + MAPIFreeBuffer(receiveFolderEntryID); + } + if (HR_FAILED(hResult)) + { + hResult = MsOutlookCalendar_getCalendarFolderEntryID( + msgStore, + 0, + NULL, + &calendarFolderEntryIDByteCount, + &calendarFolderEntryID, + MsOutlookCalendar_rdOpenEntryUlFlags); + } + if (HR_SUCCEEDED(hResult)) + { + ULONG calendarFolderObjType; + LPUNKNOWN calendarFolder; + + hResult = msgStore->OpenEntry( + calendarFolderEntryIDByteCount, + calendarFolderEntryID, + NULL, + MsOutlookCalendar_rdOpenEntryUlFlags, + &calendarFolderObjType, + &calendarFolder); + if (HR_SUCCEEDED(hResult)) + { + proceed = MsOutlookAddrBookContactQuery_foreachMailUser( + calendarFolderObjType, + calendarFolder, + query, + callbackMethod, + callbackClient, + callbackAddress); + calendarFolder->Release(); + } + MAPIFreeBuffer(calendarFolderEntryID); + } + msgStore->Release(); + } + + return proceed; +} + +static HRESULT +MsOutlookCalendar_getCalendarFolderEntryID + (LPMDB msgStore, + ULONG folderEntryIDByteCount, LPENTRYID folderEntryID, + ULONG *calendarFolderEntryIDByteCount, LPENTRYID *calendarFolderEntryID, + ULONG flags) +{ + return MsOutlookUtils_getFolderEntryIDByType( + msgStore, + folderEntryIDByteCount, + folderEntryID, + calendarFolderEntryIDByteCount, + calendarFolderEntryID, + flags, + 0x36D00102); +} diff --git a/src/native/addrbook/msoutlook/MsOutlookCalendar.h b/src/native/addrbook/msoutlook/MsOutlookCalendar.h new file mode 100644 index 0000000..e0e5322 --- /dev/null +++ b/src/native/addrbook/msoutlook/MsOutlookCalendar.h @@ -0,0 +1,21 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +#ifndef _NET_JAVA_SIP_COMMUNICATOR_PLUGIN_ADDRBOOK_MSOUTLOOK_MSOUTLOOKCALENDAR_H_ +#define _NET_JAVA_SIP_COMMUNICATOR_PLUGIN_ADDRBOOK_MSOUTLOOK_MSOUTLOOKCALENDAR_H_ + +void MsOutlookCalendar_getAllCalendarItems( + void * callbackMethod, + void * callbackClient, + long callbackAddress); +jboolean MsOutlookCalendar_foreachCalendarItemCallback( + LPSTR iUnknown, + long callbackAddress); + +void MsOutlookCalendar_setCallbackObject(void *callback); + +#define MsOutlookCalendar_UUID_Address (UUID){0x00062002, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} +#endif diff --git a/src/native/addrbook/msoutlook/MsOutlookUtils.cxx b/src/native/addrbook/msoutlook/MsOutlookUtils.cxx new file mode 100644 index 0000000..86e501a --- /dev/null +++ b/src/native/addrbook/msoutlook/MsOutlookUtils.cxx @@ -0,0 +1,404 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +#include "MsOutlookUtils.h" +#include "MsOutlookAddrBookContactSourceService.h" + +#include "MAPIBitness.h" +#include "MAPISession.h" + +#include "com/ComClient.h" +#include "com/MsOutlookAddrBookServer.h" +#include "MsOutlookMAPIHResultException.h" +#include "StringUtils.h" + +#include <initguid.h> +#include <jni.h> +#include <Mapidefs.h> +#include <Mapix.h> +#include <windows.h> + + + +HRESULT +MsOutlookUtils_getFolderEntryIDByType + (LPMDB msgStore, + ULONG folderEntryIDByteCount, LPENTRYID folderEntryID, + ULONG *contactsFolderEntryIDByteCount, LPENTRYID *contactsFolderEntryID, + ULONG flags, ULONG type) +{ + HRESULT hResult; + ULONG objType; + LPUNKNOWN folder; + + hResult = msgStore->OpenEntry( + folderEntryIDByteCount, + folderEntryID, + NULL, + flags, + &objType, + &folder); + + if (HR_SUCCEEDED(hResult)) + { + LPSPropValue prop; + + hResult + = MsOutlookUtils_HrGetOneProp( + (LPMAPIPROP) folder, + type, + &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; +} + + + +/** + * Get one property for a given contact. + * + * @param mapiProp A pointer to the contact. + * @param propTag The tag of the property to get. + * @param prop The memory location to store the property value. + * + * @return S_OK if everything work fine. Any other value is a failure. + */ +HRESULT +MsOutlookUtils_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; + MAPIFreeBuffer(values); + } + return hResult; +} + + +jobjectArray +MsOutlookUtils_IMAPIProp_GetProps( + JNIEnv *jniEnv, + jclass clazz, + jstring entryId, + jlongArray propIds, + jlong flags, + UUID UUID_Address) +{ + HRESULT hr = E_FAIL; + jobjectArray javaProps = NULL; + const char *nativeEntryId = jniEnv->GetStringUTFChars(entryId, NULL); + jsize propIdCount = jniEnv->GetArrayLength(propIds); + long nativePropIds[propIdCount]; + + for(int i = 0; i < propIdCount; ++i) + { + jlong propId; + + jniEnv->GetLongArrayRegion(propIds, i, 1, &propId); + nativePropIds[i] = propId; + } + + if(jniEnv->ExceptionCheck()) + { + jniEnv->ReleaseStringUTFChars(entryId, nativeEntryId); + return NULL; + } + + void ** props = NULL; + unsigned long* propsLength = NULL; + // b = byteArray, l = long, s = 8 bits string, u = 16 bits string. + char * propsType = NULL; + + if((props = (void**) malloc(propIdCount * sizeof(void*))) != NULL) + { + memset(props, 0, propIdCount * sizeof(void*)); + if((propsLength = (unsigned long*) malloc( + propIdCount * sizeof(unsigned long))) != NULL) + { + if((propsType = (char*) malloc(propIdCount * sizeof(char))) + != NULL) + { + IMsOutlookAddrBookServer * iServer = ComClient_getIServer(); + if(iServer) + { + LPWSTR unicodeEntryId + = StringUtils::MultiByteToWideChar(nativeEntryId); + BSTR comEntryId = SysAllocString(unicodeEntryId); + + LPSAFEARRAY comPropIds + = SafeArrayCreateVector(VT_I4, 0, propIdCount); + SafeArrayLock(comPropIds); + comPropIds->pvData = nativePropIds; + SafeArrayUnlock(comPropIds); + + LPSAFEARRAY comProps; + LPSAFEARRAY comPropsLength; + LPSAFEARRAY comPropsType; + + hr = iServer->IMAPIProp_GetProps( + comEntryId, + propIdCount, + comPropIds, + flags, + UUID_Address, + &comProps, + &comPropsLength, + &comPropsType); + + if(HR_SUCCEEDED(hr)) + { + SafeArrayLock(comPropsType); + memcpy( + propsType, + comPropsType->pvData, + propIdCount * sizeof(char)); + SafeArrayUnlock(comPropsType); + + SafeArrayLock(comPropsLength); + memcpy( + propsLength, + comPropsLength->pvData, + propIdCount * sizeof(unsigned long)); + SafeArrayUnlock(comPropsLength); + + SafeArrayLock(comProps); + byte * data = (byte*) comProps->pvData; + for(int j = 0; j < propIdCount; ++j) + { + if((props[j] = malloc(propsLength[j])) != NULL) + { + memcpy(props[j], data, propsLength[j]); + data += propsLength[j]; + } + } + SafeArrayUnlock(comProps); + + // Decode properties to java + jclass objectClass + = jniEnv->FindClass("java/lang/Object"); + if (objectClass) + { + javaProps = jniEnv->NewObjectArray( + propIdCount, + objectClass, + NULL); + for(int j = 0; j < propIdCount; ++j) + { + // byte array + if(propsType[j] == 'b' && props[j] != NULL) + { + jbyteArray value = jniEnv->NewByteArray( + (jsize) propsLength[j]); + if(value) + { + jbyte *bytes + = jniEnv->GetByteArrayElements( + value, NULL); + + if (bytes) + { + memcpy( + bytes, + props[j], + propsLength[j]); + jniEnv->ReleaseByteArrayElements( + value, + bytes, + 0); + jniEnv->SetObjectArrayElement( + javaProps, + j, + value); + } + } + } + // long + else if(propsType[j] == 'l' && props[j] != NULL) + { + jclass longClass + = jniEnv->FindClass("java/lang/Long"); + if (longClass) + { + jmethodID longMethodID + = jniEnv->GetMethodID( + longClass, + "<init>", + "(J)V"); + + if (longMethodID) + { + jlong l = (jlong)(*((long*)props[j])); + memcpy(&l, props[j], propsLength[j]); + jobject value = jniEnv->NewObject( + longClass, + longMethodID, + l); + + if (value) + { + jniEnv->SetObjectArrayElement( + javaProps, + j, + value); + } + } + } + } + // 8 bits string + else if(propsType[j] == 's' && props[j] != NULL) + { + jstring value = jniEnv->NewStringUTF( + (const char*) props[j]); + if (value) + { + jniEnv->SetObjectArrayElement( + javaProps, + j, + value); + } + } + // 16 bits string + else if(propsType[j] == 'u' && props[j] != NULL) + { + jstring value + = jniEnv->NewString( + (const jchar *) props[j], + wcslen((const wchar_t *) props[j])); + if (value) + { + jniEnv->SetObjectArrayElement( + javaProps, + j, + value); + } + } + else if(propsType[j] == 'B' && props[j] != NULL) + { + jclass booleanClass + = jniEnv->FindClass("java/lang/Boolean"); + jmethodID boolMethodID + = jniEnv->GetStaticMethodID( + booleanClass, + "valueOf", + "(Z)Ljava/lang/Boolean;"); + bool value = false; + if((bool)props[j]) + value = true; + jobject jValue + = jniEnv->CallStaticObjectMethod( + booleanClass, + boolMethodID, + value); + jniEnv->SetObjectArrayElement( + javaProps, + j, + jValue); + } + else if(propsType[j] == 't' && props[j] != NULL) + { char dateTime[20]; + LPSYSTEMTIME sysTime + = (LPSYSTEMTIME) props[j]; + sprintf(dateTime, + "%u-%02u-%02u %02u:%02u:%02u", + sysTime->wYear, sysTime->wMonth, + sysTime->wDay, sysTime->wHour, + sysTime->wMinute, sysTime->wSecond); + jstring value = jniEnv->NewStringUTF( + (const char*) dateTime); + if (value) + { + jniEnv->SetObjectArrayElement( + javaProps, + j, + value); + } + } + + if(jniEnv->ExceptionCheck()) + javaProps = NULL; + } + } + } + else + { + MsOutlookMAPIHResultException_throwNew( + jniEnv, + hr, + __FILE__, __LINE__); + } + + SafeArrayDestroy(comPropsType); + SafeArrayDestroy(comPropsLength); + SafeArrayDestroy(comProps); + SafeArrayDestroy(comPropIds); + SysFreeString(comEntryId); + free(unicodeEntryId); + } + + + for(int j = 0; j < propIdCount; ++j) + { + if(props[j] != NULL) + free(props[j]); + } + free(propsType); + } + free(propsLength); + } + free(props); + } + + jniEnv->ReleaseStringUTFChars(entryId, nativeEntryId); + + return javaProps; +} diff --git a/src/native/addrbook/msoutlook/MsOutlookUtils.h b/src/native/addrbook/msoutlook/MsOutlookUtils.h new file mode 100644 index 0000000..023d4d1 --- /dev/null +++ b/src/native/addrbook/msoutlook/MsOutlookUtils.h @@ -0,0 +1,34 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +#ifndef _NET_JAVA_SIP_COMMUNICATOR_PLUGIN_ADDRBOOK_MSOUTLOOK_MSOUTLOOKUTILS_H_ +#define _NET_JAVA_SIP_COMMUNICATOR_PLUGIN_ADDRBOOK_MSOUTLOOK_MSOUTLOOKUTILS_H_ + +#include <mapidefs.h> +#include <jni.h> + +HRESULT +MsOutlookUtils_getFolderEntryIDByType + (LPMDB msgStore, + ULONG folderEntryIDByteCount, LPENTRYID folderEntryID, + ULONG *contactsFolderEntryIDByteCount, LPENTRYID *contactsFolderEntryID, + ULONG flags, ULONG type); + +HRESULT +MsOutlookUtils_HrGetOneProp( + LPMAPIPROP mapiProp, + ULONG propTag, + LPSPropValue *prop); + +jobjectArray +MsOutlookUtils_IMAPIProp_GetProps( + JNIEnv *jniEnv, + jclass clazz, + jstring entryId, + jlongArray propIds, + jlong flags, + UUID UUID_Address); +#endif diff --git a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.h b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.h index 4337015..9aeedce 100644 --- a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.h +++ b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.h @@ -3,11 +3,11 @@ /* this ALWAYS GENERATED file contains the definitions for the interfaces */ - /* File created by MIDL compiler version 8.00.0603 */ -/* at Mon Mar 24 09:03:06 2014 + /* File created by MIDL compiler version 7.00.0555 */ +/* at Tue Apr 01 12:24:18 2014 */ /* Compiler settings for IMsOutlookAddrBookClient.idl: - Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0603 + Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: @@ -48,14 +48,12 @@ #ifndef __IMsOutlookAddrBookClient_FWD_DEFINED__ #define __IMsOutlookAddrBookClient_FWD_DEFINED__ typedef interface IMsOutlookAddrBookClient IMsOutlookAddrBookClient; - #endif /* __IMsOutlookAddrBookClient_FWD_DEFINED__ */ #ifndef __IMsOutlookAddrBookClient_FWD_DEFINED__ #define __IMsOutlookAddrBookClient_FWD_DEFINED__ typedef interface IMsOutlookAddrBookClient IMsOutlookAddrBookClient; - #endif /* __IMsOutlookAddrBookClient_FWD_DEFINED__ */ @@ -87,6 +85,10 @@ EXTERN_C const IID IID_IMsOutlookAddrBookClient; /* [in] */ BSTR id, /* [in] */ long callback) = 0; + virtual HRESULT STDMETHODCALLTYPE foreachCalendarItemCallback( + /* [in] */ BSTR id, + /* [in] */ long callback) = 0; + virtual HRESULT STDMETHODCALLTYPE deleted( /* [in] */ BSTR id) = 0; @@ -98,7 +100,6 @@ EXTERN_C const IID IID_IMsOutlookAddrBookClient; }; - #else /* C style interface */ typedef struct IMsOutlookAddrBookClientVtbl @@ -109,7 +110,7 @@ EXTERN_C const IID IID_IMsOutlookAddrBookClient; IMsOutlookAddrBookClient * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ - _COM_Outptr_ void **ppvObject); + __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IMsOutlookAddrBookClient * This); @@ -122,6 +123,11 @@ EXTERN_C const IID IID_IMsOutlookAddrBookClient; /* [in] */ BSTR id, /* [in] */ long callback); + HRESULT ( STDMETHODCALLTYPE *foreachCalendarItemCallback )( + IMsOutlookAddrBookClient * This, + /* [in] */ BSTR id, + /* [in] */ long callback); + HRESULT ( STDMETHODCALLTYPE *deleted )( IMsOutlookAddrBookClient * This, /* [in] */ BSTR id); @@ -160,6 +166,9 @@ EXTERN_C const IID IID_IMsOutlookAddrBookClient; #define IMsOutlookAddrBookClient_foreachMailUserCallback(This,id,callback) \ ( (This)->lpVtbl -> foreachMailUserCallback(This,id,callback) ) +#define IMsOutlookAddrBookClient_foreachCalendarItemCallback(This,id,callback) \ + ( (This)->lpVtbl -> foreachCalendarItemCallback(This,id,callback) ) + #define IMsOutlookAddrBookClient_deleted(This,id) \ ( (This)->lpVtbl -> deleted(This,id) ) diff --git a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.idl b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.idl index 6e1fad5..30f457a 100644 --- a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.idl +++ b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.idl @@ -12,6 +12,9 @@ interface IMsOutlookAddrBookClient : IUnknown HRESULT foreachMailUserCallback( [in] BSTR id, [in] long callback); + HRESULT foreachCalendarItemCallback( + [in] BSTR id, + [in] long callback); HRESULT deleted( [in] BSTR id); diff --git a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.tlb b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.tlb Binary files differindex 168d9ad..6873acd 100644 --- a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.tlb +++ b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.tlb diff --git a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.h b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.h index aee8983..a263d2a 100644 --- a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.h +++ b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.h @@ -3,11 +3,11 @@ /* this ALWAYS GENERATED file contains the definitions for the interfaces */ - /* File created by MIDL compiler version 8.00.0603 */ -/* at Mon Mar 24 09:03:14 2014 + /* File created by MIDL compiler version 7.00.0555 */ +/* at Tue Apr 01 12:24:24 2014 */ /* Compiler settings for IMsOutlookAddrBookServer.idl: - Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0603 + Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 protocol : dce , ms_ext, c_ext, robust error checks: allocation ref bounds_check enum stub_data VC __declspec() decoration level: @@ -48,14 +48,12 @@ #ifndef __IMsOutlookAddrBookServer_FWD_DEFINED__ #define __IMsOutlookAddrBookServer_FWD_DEFINED__ typedef interface IMsOutlookAddrBookServer IMsOutlookAddrBookServer; - #endif /* __IMsOutlookAddrBookServer_FWD_DEFINED__ */ #ifndef __IMsOutlookAddrBookServer_FWD_DEFINED__ #define __IMsOutlookAddrBookServer_FWD_DEFINED__ typedef interface IMsOutlookAddrBookServer IMsOutlookAddrBookServer; - #endif /* __IMsOutlookAddrBookServer_FWD_DEFINED__ */ @@ -87,11 +85,15 @@ EXTERN_C const IID IID_IMsOutlookAddrBookServer; /* [in] */ BSTR query, /* [in] */ long callback) = 0; + virtual HRESULT STDMETHODCALLTYPE getAllCalendarItems( + /* [in] */ long callback) = 0; + virtual HRESULT STDMETHODCALLTYPE IMAPIProp_GetProps( /* [in] */ BSTR entryId, /* [in] */ int nbPropIds, /* [in] */ SAFEARRAY * propIds, /* [in] */ long flags, + /* [in] */ GUID UUID_Address, /* [out] */ SAFEARRAY * *props, /* [out] */ SAFEARRAY * *propsLength, /* [out] */ SAFEARRAY * *propsType) = 0; @@ -118,7 +120,6 @@ EXTERN_C const IID IID_IMsOutlookAddrBookServer; }; - #else /* C style interface */ typedef struct IMsOutlookAddrBookServerVtbl @@ -129,7 +130,7 @@ EXTERN_C const IID IID_IMsOutlookAddrBookServer; IMsOutlookAddrBookServer * This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ - _COM_Outptr_ void **ppvObject); + __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( IMsOutlookAddrBookServer * This); @@ -142,12 +143,17 @@ EXTERN_C const IID IID_IMsOutlookAddrBookServer; /* [in] */ BSTR query, /* [in] */ long callback); + HRESULT ( STDMETHODCALLTYPE *getAllCalendarItems )( + IMsOutlookAddrBookServer * This, + /* [in] */ long callback); + HRESULT ( STDMETHODCALLTYPE *IMAPIProp_GetProps )( IMsOutlookAddrBookServer * This, /* [in] */ BSTR entryId, /* [in] */ int nbPropIds, /* [in] */ SAFEARRAY * propIds, /* [in] */ long flags, + /* [in] */ GUID UUID_Address, /* [out] */ SAFEARRAY * *props, /* [out] */ SAFEARRAY * *propsLength, /* [out] */ SAFEARRAY * *propsType); @@ -203,8 +209,11 @@ EXTERN_C const IID IID_IMsOutlookAddrBookServer; #define IMsOutlookAddrBookServer_foreachMailUser(This,query,callback) \ ( (This)->lpVtbl -> foreachMailUser(This,query,callback) ) -#define IMsOutlookAddrBookServer_IMAPIProp_GetProps(This,entryId,nbPropIds,propIds,flags,props,propsLength,propsType) \ - ( (This)->lpVtbl -> IMAPIProp_GetProps(This,entryId,nbPropIds,propIds,flags,props,propsLength,propsType) ) +#define IMsOutlookAddrBookServer_getAllCalendarItems(This,callback) \ + ( (This)->lpVtbl -> getAllCalendarItems(This,callback) ) + +#define IMsOutlookAddrBookServer_IMAPIProp_GetProps(This,entryId,nbPropIds,propIds,flags,UUID_Address,props,propsLength,propsType) \ + ( (This)->lpVtbl -> IMAPIProp_GetProps(This,entryId,nbPropIds,propIds,flags,UUID_Address,props,propsLength,propsType) ) #define IMsOutlookAddrBookServer_createContact(This,id) \ ( (This)->lpVtbl -> createContact(This,id) ) diff --git a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.idl b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.idl index 5fbaffa..638435e 100644 --- a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.idl +++ b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.idl @@ -12,12 +12,16 @@ interface IMsOutlookAddrBookServer : IUnknown HRESULT foreachMailUser( [in] BSTR query, [in] long callback); + + HRESULT getAllCalendarItems( + [in] long callback); HRESULT IMAPIProp_GetProps( [in] BSTR entryId, [in] int nbPropIds, [in] SAFEARRAY(long) propIds, [in] long flags, + [in] GUID UUID_Address, [out] SAFEARRAY(byte) * props, [out] SAFEARRAY(unsigned long) * propsLength, [out] SAFEARRAY(byte) * propsType); diff --git a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.tlb b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.tlb Binary files differindex 9492af3..267171f 100644 --- a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.tlb +++ b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.tlb diff --git a/src/native/addrbook/msoutlook/com/MsOutlookAddrBookClient.cxx b/src/native/addrbook/msoutlook/com/MsOutlookAddrBookClient.cxx index b21a636..c0564e2 100644 --- a/src/native/addrbook/msoutlook/com/MsOutlookAddrBookClient.cxx +++ b/src/native/addrbook/msoutlook/com/MsOutlookAddrBookClient.cxx @@ -10,6 +10,7 @@ #include <wchar.h> #include "../MAPINotification.h" +#include "../MsOutlookCalendar.h" #include "../net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactQuery.h" #include "../StringUtils.h" @@ -117,6 +118,15 @@ HRESULT STDMETHODCALLTYPE MsOutlookAddrBookClient::foreachMailUserCallback( return E_ABORT; } +HRESULT STDMETHODCALLTYPE MsOutlookAddrBookClient::foreachCalendarItemCallback( + BSTR id, long callback) +{ + char * charId = StringUtils::WideCharToMultiByte(id); + MsOutlookCalendar_foreachCalendarItemCallback(charId, callback); + + return S_OK; +} + /** * Callback called each time the COM server forward a contact deleted notify * event from MAPI. diff --git a/src/native/addrbook/msoutlook/com/MsOutlookAddrBookClient.h b/src/native/addrbook/msoutlook/com/MsOutlookAddrBookClient.h index 159e0f8..06e1847 100644 --- a/src/native/addrbook/msoutlook/com/MsOutlookAddrBookClient.h +++ b/src/native/addrbook/msoutlook/com/MsOutlookAddrBookClient.h @@ -37,6 +37,8 @@ class MsOutlookAddrBookClient: // IMsOutlookAddrBookClient HRESULT STDMETHODCALLTYPE foreachMailUserCallback( BSTR id, long callback); + HRESULT STDMETHODCALLTYPE foreachCalendarItemCallback( + BSTR id, long callback); HRESULT STDMETHODCALLTYPE deleted(BSTR id); HRESULT STDMETHODCALLTYPE inserted(BSTR id); diff --git a/src/native/addrbook/msoutlook/com/MsOutlookAddrBookServer.cxx b/src/native/addrbook/msoutlook/com/MsOutlookAddrBookServer.cxx index f80b60b..6a7300e 100644 --- a/src/native/addrbook/msoutlook/com/MsOutlookAddrBookServer.cxx +++ b/src/native/addrbook/msoutlook/com/MsOutlookAddrBookServer.cxx @@ -14,6 +14,7 @@ #include "../StringUtils.h" #include "../MsOutlookAddrBookContactQuery.h" +#include "../MsOutlookCalendar.h" /** * Instanciates a new MsOutlookAddrBookServer. @@ -135,6 +136,68 @@ HRESULT STDMETHODCALLTYPE MsOutlookAddrBookServer::foreachMailUser( } /** + * Starts a search for calendar items using MAPI.A + * + * @param callbackAddress the address for the callback method + * @return S_OK. + */ +HRESULT STDMETHODCALLTYPE MsOutlookAddrBookServer::getAllCalendarItems( + long callbackAddress) +{ + HRESULT hr = E_FAIL; + IMsOutlookAddrBookClient * msOutlookAddrBookClient = NULL; + if((hr = CoCreateInstance( + CLSID_MsOutlookAddrBookClient, + NULL, + CLSCTX_LOCAL_SERVER, + IID_IMsOutlookAddrBookClient, + (void**) &msOutlookAddrBookClient)) == S_OK) + { + MsOutlookCalendar_getAllCalendarItems( + (void *) MsOutlookAddrBookServer::foreachCalendarItemCallback, + (void *) msOutlookAddrBookClient, + callbackAddress); + msOutlookAddrBookClient->Release(); + } + + return S_OK; +} + +/** + * Calls back the java side to add a calendar item. + * + * @param iUnknown The string representation of the entry id of the calendar + * item. + * + * @return True everything works fine and that we must continue to list the + * other contacts. False otherwise. + */ +boolean MsOutlookAddrBookServer::foreachCalendarItemCallback( + LPSTR iUnknown, + void * callbackClient, + long callbackAddress) +{ + HRESULT hr = E_FAIL; + + if(callbackClient) + { + LPWSTR iUnknownW = StringUtils::MultiByteToWideChar(iUnknown); + BSTR res = SysAllocString(iUnknownW); + + hr = ((IMsOutlookAddrBookClient *)callbackClient) + ->foreachCalendarItemCallback(res, callbackAddress); + + SysFreeString(res); + free(iUnknownW); + } + + + return (hr == S_OK); +} + + + +/** * Calls back the java side to list a contact. * * @param iUnknown The string representation of the entry id of the contact. @@ -186,6 +249,7 @@ HRESULT STDMETHODCALLTYPE MsOutlookAddrBookServer::IMAPIProp_GetProps( int nbPropIds, SAFEARRAY * propIds, long flags, + UUID UUID_Address, SAFEARRAY ** props, SAFEARRAY ** propsLength, SAFEARRAY ** propsType) @@ -218,7 +282,8 @@ HRESULT STDMETHODCALLTYPE MsOutlookAddrBookServer::IMAPIProp_GetProps( flags, localProps, localPropsLength, - localPropsType); + localPropsType, + UUID_Address); free(id); diff --git a/src/native/addrbook/msoutlook/com/MsOutlookAddrBookServer.h b/src/native/addrbook/msoutlook/com/MsOutlookAddrBookServer.h index 190217a..261c46f 100644 --- a/src/native/addrbook/msoutlook/com/MsOutlookAddrBookServer.h +++ b/src/native/addrbook/msoutlook/com/MsOutlookAddrBookServer.h @@ -37,11 +37,14 @@ class MsOutlookAddrBookServer: // IMsOutlookAddrBookServer HRESULT STDMETHODCALLTYPE foreachMailUser(BSTR query, long callback); + HRESULT STDMETHODCALLTYPE getAllCalendarItems(long callback); + HRESULT STDMETHODCALLTYPE IMAPIProp_GetProps( BSTR entryId, int nbPropIds, SAFEARRAY * propIds, long flags, + UUID UUID_Address, SAFEARRAY ** props, SAFEARRAY ** propsLength, SAFEARRAY ** propsType); @@ -76,6 +79,10 @@ class MsOutlookAddrBookServer: LPSTR iUnknown, void * callbackClient, long callbackAddress); + static boolean foreachCalendarItemCallback( + LPSTR iUnknown, + void * callbackClient, + long callbackAddress); }; #endif 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 9e34c65..0987a62 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 @@ -8,6 +8,7 @@ #include "net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactQuery.h" #include "MsOutlookAddrBookContactQuery.h" +#include "MsOutlookUtils.h" #include "com/ComClient.h" #include "com/MsOutlookAddrBookServer.h" #include "MAPIBitness.h" @@ -193,231 +194,8 @@ Java_net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContac jlongArray propIds, jlong flags) { - HRESULT hr = E_FAIL; - jobjectArray javaProps = NULL; - const char *nativeEntryId = jniEnv->GetStringUTFChars(entryId, NULL); - jsize propIdCount = jniEnv->GetArrayLength(propIds); - long nativePropIds[propIdCount]; - - for(int i = 0; i < propIdCount; ++i) - { - jlong propId; - - jniEnv->GetLongArrayRegion(propIds, i, 1, &propId); - nativePropIds[i] = propId; - } - - if(jniEnv->ExceptionCheck()) - { - jniEnv->ReleaseStringUTFChars(entryId, nativeEntryId); - return NULL; - } - - void ** props = NULL; - unsigned long* propsLength = NULL; - // b = byteArray, l = long, s = 8 bits string, u = 16 bits string. - char * propsType = NULL; - - if((props = (void**) malloc(propIdCount * sizeof(void*))) != NULL) - { - memset(props, 0, propIdCount * sizeof(void*)); - if((propsLength = (unsigned long*) malloc( - propIdCount * sizeof(unsigned long))) != NULL) - { - if((propsType = (char*) malloc(propIdCount * sizeof(char))) - != NULL) - { - IMsOutlookAddrBookServer * iServer = ComClient_getIServer(); - if(iServer) - { - LPWSTR unicodeEntryId - = StringUtils::MultiByteToWideChar(nativeEntryId); - BSTR comEntryId = SysAllocString(unicodeEntryId); - - LPSAFEARRAY comPropIds - = SafeArrayCreateVector(VT_I4, 0, propIdCount); - SafeArrayLock(comPropIds); - comPropIds->pvData = nativePropIds; - SafeArrayUnlock(comPropIds); - - LPSAFEARRAY comProps; - LPSAFEARRAY comPropsLength; - LPSAFEARRAY comPropsType; - - hr = iServer->IMAPIProp_GetProps( - comEntryId, - propIdCount, - comPropIds, - flags, - &comProps, - &comPropsLength, - &comPropsType); - - if(HR_SUCCEEDED(hr)) - { - SafeArrayLock(comPropsType); - memcpy( - propsType, - comPropsType->pvData, - propIdCount * sizeof(char)); - SafeArrayUnlock(comPropsType); - - SafeArrayLock(comPropsLength); - memcpy( - propsLength, - comPropsLength->pvData, - propIdCount * sizeof(unsigned long)); - SafeArrayUnlock(comPropsLength); - - SafeArrayLock(comProps); - byte * data = (byte*) comProps->pvData; - for(int j = 0; j < propIdCount; ++j) - { - if((props[j] = malloc(propsLength[j])) != NULL) - { - memcpy(props[j], data, propsLength[j]); - data += propsLength[j]; - } - } - SafeArrayUnlock(comProps); - - // Decode properties to java - jclass objectClass - = jniEnv->FindClass("java/lang/Object"); - if (objectClass) - { - javaProps = jniEnv->NewObjectArray( - propIdCount, - objectClass, - NULL); - for(int j = 0; j < propIdCount; ++j) - { - // byte array - if(propsType[j] == 'b' && props[j] != NULL) - { - jbyteArray value = jniEnv->NewByteArray( - (jsize) propsLength[j]); - if(value) - { - jbyte *bytes - = jniEnv->GetByteArrayElements( - value, NULL); - - if (bytes) - { - memcpy( - bytes, - props[j], - propsLength[j]); - jniEnv->ReleaseByteArrayElements( - value, - bytes, - 0); - jniEnv->SetObjectArrayElement( - javaProps, - j, - value); - } - } - } - // long - else if(propsType[j] == 'l' && props[j] != NULL) - { - jclass longClass - = jniEnv->FindClass("java/lang/Long"); - if (longClass) - { - jmethodID longMethodID - = jniEnv->GetMethodID( - longClass, - "<init>", - "(J)V"); - - if (longMethodID) - { - jlong l; - memcpy(&l, props[j], propsLength[j]); - jobject value = jniEnv->NewObject( - longClass, - longMethodID, - l); - - if (value) - { - jniEnv->SetObjectArrayElement( - javaProps, - j, - value); - } - } - } - } - // 8 bits string - else if(propsType[j] == 's' && props[j] != NULL) - { - jstring value = jniEnv->NewStringUTF( - (const char*) props[j]); - if (value) - { - jniEnv->SetObjectArrayElement( - javaProps, - j, - value); - } - } - // 16 bits string - else if(propsType[j] == 'u' && props[j] != NULL) - { - jstring value - = jniEnv->NewString( - (const jchar *) props[j], - wcslen((const wchar_t *) props[j])); - if (value) - { - jniEnv->SetObjectArrayElement( - javaProps, - j, - value); - } - } - - if(jniEnv->ExceptionCheck()) - javaProps = NULL; - } - } - } - else - { - MsOutlookMAPIHResultException_throwNew( - jniEnv, - hr, - __FILE__, __LINE__); - } - - SafeArrayDestroy(comPropsType); - SafeArrayDestroy(comPropsLength); - SafeArrayDestroy(comProps); - SafeArrayDestroy(comPropIds); - SysFreeString(comEntryId); - free(unicodeEntryId); - } - - - for(int j = 0; j < propIdCount; ++j) - { - if(props[j] != NULL) - free(props[j]); - } - free(propsType); - } - free(propsLength); - } - free(props); - } - - jniEnv->ReleaseStringUTFChars(entryId, nativeEntryId); - - return javaProps; + return MsOutlookUtils_IMAPIProp_GetProps(jniEnv, clazz, entryId, propIds, + flags, MsOutlookAddrBookContactQuery_UUID_Address); } diff --git a/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl.cxx b/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl.cxx new file mode 100644 index 0000000..449775c --- /dev/null +++ b/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl.cxx @@ -0,0 +1,44 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +#include "net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl.h" +#include "MsOutlookUtils.h" +#include "MsOutlookCalendar.h" +#include "MAPINotification.h" +#include "com/ComClient.h" +#include "com/MsOutlookAddrBookServer.h" + +JNIEXPORT void JNICALL Java_net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl_getAllCalendarItems( + JNIEnv *jniEnv, + jclass clazz, + jobject callback) +{ + MAPINotification_registerCalendarJniNotificationsDelegate( + jniEnv, + callback); + MsOutlookCalendar_setCallbackObject(callback); + IMsOutlookAddrBookServer * iServer = ComClient_getIServer(); + if(iServer) + { + iServer->getAllCalendarItems((long)(intptr_t)callback); + } + +} + + + +JNIEXPORT jobjectArray JNICALL +Java_net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl_IMAPIProp_1GetProps( + JNIEnv *jniEnv, + jclass clazz, + jstring entryId, + jlongArray propIds, + jlong flags) +{ + return MsOutlookUtils_IMAPIProp_GetProps(jniEnv, clazz, entryId, propIds, flags, MsOutlookCalendar_UUID_Address); +} + diff --git a/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl.h b/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl.h new file mode 100644 index 0000000..499dc97 --- /dev/null +++ b/src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl.h @@ -0,0 +1,30 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl */ + +#ifndef _Included_net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl +#define _Included_net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Class: net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl + * Method: getAllCalendarItems + * Signature: (Lnet/java/sip/communicator/plugin/addrbook/msoutlook/calendar/CalendarServiceImpl/PtrOutlookCalendarCallback;)V + */ +JNIEXPORT void JNICALL Java_net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl_getAllCalendarItems + (JNIEnv *, jclass, jobject); + +/* + * Class: net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl + * Method: IMAPIProp_GetProps + * Signature: (Ljava/lang/String;[JJ)[Ljava/lang/Object; + */ +JNIEXPORT jobjectArray JNICALL Java_net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl_IMAPIProp_1GetProps + (JNIEnv *, jclass, jstring, jlongArray, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java index e6d0211..00a93a7 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java @@ -64,6 +64,8 @@ public class OperationSetPersistentPresenceJabberImpl Presence.Mode.away); scToJabberModesMappings.put(JabberStatusEnum.ON_THE_PHONE, Presence.Mode.away); + scToJabberModesMappings.put(JabberStatusEnum.IN_A_MEETING, + Presence.Mode.away); scToJabberModesMappings.put(JabberStatusEnum.EXTENDED_AWAY, Presence.Mode.xa); scToJabberModesMappings.put(JabberStatusEnum.DO_NOT_DISTURB, @@ -463,6 +465,11 @@ public class OperationSetPersistentPresenceJabberImpl { presence.setStatus(JabberStatusEnum.ON_THE_PHONE); } + else if(status.equals(jabberStatusEnum.getStatus( + JabberStatusEnum.IN_A_MEETING))) + { + presence.setStatus(JabberStatusEnum.IN_A_MEETING); + } else presence.setStatus(statusMessage); //presence.addExtension(new Version()); @@ -707,6 +714,9 @@ public class OperationSetPersistentPresenceJabberImpl if(presence.getStatus() != null && presence.getStatus().contains(JabberStatusEnum.ON_THE_PHONE)) return jabberStatusEnum.getStatus(JabberStatusEnum.ON_THE_PHONE); + else if(presence.getStatus() != null + && presence.getStatus().contains(JabberStatusEnum.IN_A_MEETING)) + return jabberStatusEnum.getStatus(JabberStatusEnum.IN_A_MEETING); else return jabberStatusEnum.getStatus(JabberStatusEnum.AWAY); } @@ -1803,6 +1813,7 @@ public class OperationSetPersistentPresenceJabberImpl addDefaultValue(JabberStatusEnum.AWAY, -5); addDefaultValue(JabberStatusEnum.EXTENDED_AWAY, -10); addDefaultValue(JabberStatusEnum.ON_THE_PHONE, -15); + addDefaultValue(JabberStatusEnum.IN_A_MEETING, -16); addDefaultValue(JabberStatusEnum.DO_NOT_DISTURB, -20); addDefaultValue(JabberStatusEnum.FREE_FOR_CHAT, +5); } diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetPersistentPresenceMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetPersistentPresenceMsnImpl.java index 12280ad..e872eed 100644 --- a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetPersistentPresenceMsnImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetPersistentPresenceMsnImpl.java @@ -66,6 +66,7 @@ public class OperationSetPersistentPresenceMsnImpl supportedPresenceStatusSet.add(MsnStatusEnum.OFFLINE); supportedPresenceStatusSet.add(MsnStatusEnum.ONLINE); supportedPresenceStatusSet.add(MsnStatusEnum.ON_THE_PHONE); + supportedPresenceStatusSet.add(MsnStatusEnum.IN_A_MEETING); supportedPresenceStatusSet.add(MsnStatusEnum.OUT_TO_LUNCH); } diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipStatusEnum.java b/src/net/java/sip/communicator/impl/protocol/sip/SipStatusEnum.java index f1375e4..aa93497 100644 --- a/src/net/java/sip/communicator/impl/protocol/sip/SipStatusEnum.java +++ b/src/net/java/sip/communicator/impl/protocol/sip/SipStatusEnum.java @@ -41,6 +41,11 @@ public class SipStatusEnum * The On the phone status. Indicates that the user is talking to the phone. */ public static final String ON_THE_PHONE = "On the phone"; + + /** + * The In meeting status. Indicates that the user is in meeting. + */ + public static final String IN_A_MEETING = "In a meeting"; /** * The Away status. Indicates that the user has connectivity but might @@ -75,6 +80,11 @@ public class SipStatusEnum * The On the phone status. Indicates that the user is talking to the phone. */ private final SipPresenceStatus onThePhoneStatus; + + /** + * The On the phone status. Indicates that the user is talking to the phone. + */ + private final SipPresenceStatus inMeetingStatus; /** * The Away status. Indicates that the user has connectivity but might @@ -116,6 +126,11 @@ public class SipStatusEnum 31, ON_THE_PHONE, loadIcon(iconPath + "/sip16x16-phone.png")); + + this.inMeetingStatus = new SipPresenceStatus( + 32, + IN_A_MEETING, + loadIcon(iconPath + "/sip16x16-meeting.png")); this.awayStatus = new SipPresenceStatus( 40, @@ -136,6 +151,7 @@ public class SipStatusEnum supportedStatusSet.add(onlineStatus); supportedStatusSet.add(awayStatus); supportedStatusSet.add(onThePhoneStatus); + supportedStatusSet.add(inMeetingStatus); supportedStatusSet.add(busyStatus); supportedStatusSet.add(offlineStatus); } @@ -156,6 +172,8 @@ public class SipStatusEnum return busyStatus; else if (statusName.equals(ON_THE_PHONE)) return onThePhoneStatus; + else if (statusName.equals(IN_A_MEETING)) + return inMeetingStatus; else if (statusName.equals(AWAY)) return awayStatus; else diff --git a/src/net/java/sip/communicator/plugin/addrbook/AddrBookActivator.java b/src/net/java/sip/communicator/plugin/addrbook/AddrBookActivator.java index 5885007..c99bbd4 100644 --- a/src/net/java/sip/communicator/plugin/addrbook/AddrBookActivator.java +++ b/src/net/java/sip/communicator/plugin/addrbook/AddrBookActivator.java @@ -8,9 +8,13 @@ package net.java.sip.communicator.plugin.addrbook; import java.util.*; -import net.java.sip.communicator.plugin.addrbook.msoutlook.DefaultIMApp; +import net.java.sip.communicator.plugin.addrbook.msoutlook.*; +import net.java.sip.communicator.plugin.addrbook.msoutlook.calendar.*; +import net.java.sip.communicator.service.calendar.*; import net.java.sip.communicator.service.contactsource.*; import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.Logger; @@ -91,6 +95,77 @@ public class AddrBookActivator * properties. */ private static ConfigurationService configService; + + /** + * The calendar service + */ + private static CalendarServiceImpl calendarService + = new CalendarServiceImpl(); + + /** + * List of the providers with registration listener. + */ + private static List<ProtocolProviderService> providers + = new ArrayList<ProtocolProviderService>(); + + /** + * The registration change listener. + */ + private static RegistrationStateChangeListener providerListener + = new RegistrationStateChangeListener() + { + + @Override + public void registrationStateChanged( + RegistrationStateChangeEvent evt) + { + if(evt.getNewState().equals(RegistrationState.REGISTERED)) + { + calendarService.handleProviderAdded( + evt.getProvider()); + } + } + }; + + /** + * A listener for addition of <tt>ProtocolProviderService</tt> + */ + private static ServiceListener serviceListener = new ServiceListener() + { + + @Override + public void serviceChanged(ServiceEvent event) + { + Object sService + = bundleContext.getService(event.getServiceReference()); + + // we don't care if the source service is not a protocol provider + if (! (sService instanceof ProtocolProviderService)) + { + return; + } + + ProtocolProviderService pps = (ProtocolProviderService)sService; + + if (event.getType() == ServiceEvent.REGISTERED) + { + synchronized(providers) + { + providers.add(pps); + } + pps.addRegistrationStateChangeListener(providerListener); + + } + if (event.getType() == ServiceEvent.UNREGISTERING) + { + synchronized(providers) + { + providers.remove(pps); + } + pps.removeRegistrationStateChangeListener(providerListener); + } + } + }; /** * Gets the <tt>ResourceManagementService</tt> to be used by the @@ -110,6 +185,11 @@ public class AddrBookActivator } return resourceService; } + + public static CalendarServiceImpl getCalendarService() + { + return calendarService; + } /** * Gets the <tt>ConfigurationService</tt> to be used by the @@ -164,8 +244,9 @@ public class AddrBookActivator "plugin.addrbook.ADDRESS_BOOKS", 101, false), properties); - + startService(); + startCalendarService(); } /** @@ -186,6 +267,7 @@ public class AddrBookActivator + "\" ... [STOPPED]"); stopService(); + stopCalendarService(); } /** @@ -251,6 +333,14 @@ public class AddrBookActivator css = (ContactSourceService) Class.forName(cssClassName).newInstance(); + if(css.equals("net.java.sip.communicator.plugin.addrbook" + + ".msoutlook.MsOutlookAddrBookContactSourceService")) + { + MsOutlookAddrBookContactSourceService contactSource + = ((MsOutlookAddrBookContactSourceService)css); + MsOutlookAddrBookContactSourceService.initMAPI( + contactSource.createNotificationDelegate()); + } } catch (Exception ex) { @@ -263,6 +353,7 @@ public class AddrBookActivator logger.debug(msg, ex); return; } + try { cssServiceRegistration @@ -270,6 +361,7 @@ public class AddrBookActivator ContactSourceService.class.getName(), css, null); + } finally { @@ -288,6 +380,64 @@ public class AddrBookActivator } } } + + /** + * Tries to start the calendar service. + */ + static void startCalendarService() + { + if(OSUtils.IS_WINDOWS && !getConfigService().getBoolean( + CalendarService.PNAME_FREE_BUSY_STATUS_DISABLED, false)) + { + try + { + MsOutlookAddrBookContactSourceService.initMAPI(null); + } + catch (MsOutlookMAPIHResultException ex) + { + String msg + = "Failed to initialize MAPI: " + + ex.getMessage(); + + logger.error(msg); + if (logger.isDebugEnabled()) + logger.debug(msg, ex); + return; + } + + bundleContext.addServiceListener(serviceListener); + for(ProtocolProviderService pps : getProtocolProviders()) + { + synchronized(providers) + { + providers.add(pps); + } + pps.addRegistrationStateChangeListener(providerListener); + } + calendarService.start(); + } + } + + /** + * Stops the calendar service. + */ + static void stopCalendarService() + { + if(OSUtils.IS_WINDOWS && !getConfigService().getBoolean( + CalendarService.PNAME_FREE_BUSY_STATUS_DISABLED, false)) + { + bundleContext.removeServiceListener(serviceListener); + synchronized(providers) + { + for(ProtocolProviderService pps : providers) + { + pps.removeRegistrationStateChangeListener(providerListener); + } + } + calendarService = null; + MsOutlookAddrBookContactSourceService.UninitializeMAPI(); + } + } /** * Stop the previously registered service. @@ -340,4 +490,37 @@ public class AddrBookActivator DefaultIMApp.unsetDefaultApp(); } } + + public static List<ProtocolProviderService> getProtocolProviders() + { + ServiceReference[] ppsRefs; + List<ProtocolProviderService> result + = new ArrayList<ProtocolProviderService>(); + try + { + ppsRefs + = bundleContext.getServiceReferences( + ProtocolProviderService.class.getName(), + null); + } + catch (InvalidSyntaxException ise) + { + ppsRefs = null; + } + if ((ppsRefs == null) || (ppsRefs.length == 0)) + { + return result; + } + + for (ServiceReference ppsRef : ppsRefs) + { + ProtocolProviderService pps + = (ProtocolProviderService) + bundleContext.getService(ppsRef); + result.add(pps); + } + + return result; + + } } 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 c006173..6e20fee 100644 --- a/src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf +++ b/src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf @@ -11,6 +11,7 @@ Import-Package: javax.swing, net.java.sip.communicator.service.contactsource,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.service.protocol.event,
org.jitsi.service.resources, net.java.sip.communicator.service.resources,
net.java.sip.communicator.util, net.java.sip.communicator.plugin.desktoputil,
diff --git a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java index 508b0d2..5529c20 100644 --- a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java +++ b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java @@ -66,7 +66,12 @@ public class MsOutlookAddrBookContactSourceService * The latest query created. */ private MsOutlookAddrBookContactQuery latestQuery = null; - + + /** + * Indicates whether MAPI is initialized or not. + */ + private static boolean isMAPIInitialized = false; + static { String lib = "jmsoutlookaddrbook"; @@ -112,18 +117,32 @@ public class MsOutlookAddrBookContactSourceService /** * Initializes a new <tt>MsOutlookAddrBookContactSourceService</tt> * instance. - * + * @param notificationDelegate the object to be notified for addressbook + * changes * @throws MsOutlookMAPIHResultException if anything goes wrong while * initializing the new <tt>MsOutlookAddrBookContactSourceService</tt> * instance */ - public MsOutlookAddrBookContactSourceService() + public static void initMAPI(NotificationsDelegate notificationDelegate) throws MsOutlookMAPIHResultException { - MAPIInitialize( - MAPI_INIT_VERSION, - MAPI_MULTITHREAD_NOTIFICATIONS, - new NotificationsDelegate()); + if(!isMAPIInitialized) + { + MAPIInitialize( + MAPI_INIT_VERSION, + MAPI_MULTITHREAD_NOTIFICATIONS, + notificationDelegate); + isMAPIInitialized = true; + } + } + + /** + * Creates new <tt>NotificationsDelegate</tt> instance. + * @return the <tt>NotificationsDelegate</tt> instance + */ + public NotificationsDelegate createNotificationDelegate() + { + return new NotificationsDelegate(); } /** @@ -158,6 +177,18 @@ public class MsOutlookAddrBookContactSourceService NotificationsDelegate callback) throws MsOutlookMAPIHResultException; + /** + * Uninitializes MAPI. + */ + public static void UninitializeMAPI() + { + if(isMAPIInitialized) + { + MAPIUninitialize(); + isMAPIInitialized = false; + } + } + private static native void MAPIUninitialize(); public static native int getOutlookBitnessVersion(); @@ -200,7 +231,7 @@ public class MsOutlookAddrBookContactSourceService latestQuery.clear(); latestQuery = null; } - MAPIUninitialize(); + UninitializeMAPI(); } /** diff --git a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/CalendarItemTimerTask.java b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/CalendarItemTimerTask.java new file mode 100644 index 0000000..817f2f2 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/CalendarItemTimerTask.java @@ -0,0 +1,225 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.addrbook.msoutlook.calendar; + +import java.util.*; + +import net.java.sip.communicator.plugin.addrbook.*; +import net.java.sip.communicator.service.calendar.*; + +/** + * A class that represents one calendar item. It schedules tasks for the + * beginning and for the end of the calendar item to update the free busy status + * + * @author Hristo Terezov + */ +public class CalendarItemTimerTask +{ + /** + * The status of the calendar item. + */ + private final CalendarService.BusyStatusEnum state; + + /** + * The start date of the calendar item. + */ + private final Date startDate; + + /** + * The end date of the calendar item. + */ + private final Date endDate; + + /** + * The ID of the calendar item. + */ + private final String id; + + /** + * Indicates if the start task should be executed immediately or not. This + * flag is <tt>true</tt> if the start date is before the current date. + */ + private final boolean executeNow; + + /** + * The <tt>CalendarServiceImpl</tt> instance. + */ + private final CalendarServiceImpl calendarService + = AddrBookActivator.getCalendarService(); + + /** + * The <tt>Timer</tt> instance that schedules the tasks. + */ + private static Timer timer = new Timer(); + + /** + * The <tt>RecurringPattern</tt> instance associated with the calendar item. + * This must be <tt>null</tt> if the calendar item is not recurring. + */ + private RecurringPattern pattern; + + /** + * The task that will be executed at the beginning of the task. + */ + private TimerTask startTask = new TimerTask() + { + @Override + public void run() + { + start(); + } + }; + + /** + * The task that will be executed at the end of the task. + */ + private TimerTask endTask = new TimerTask() + { + @Override + public void run() + { + stop(); + } + }; + + /** + * Constructs new <tt>CalendarItemTimerTask</tt> instance. + * @param state the state of the calendar item. + * @param startDate the start date of the calendar item. + * @param endDate the end date of the calendar item. + * @param id the ID of the calendar item. + * @param executeNow Indicates if the start task should be executed + * immediately or not + * @param pattern the <tt>RecurringPattern</tt> instance associated with the + * calendar item. It must be <tt>null</tt> if the calendar item is not + * recurring. + */ + public CalendarItemTimerTask(CalendarService.BusyStatusEnum state, + Date startDate, Date endDate, String id, boolean executeNow, + RecurringPattern pattern) + { + this.state = state; + this.startDate = startDate; + this.endDate = endDate; + this.id = id; + calendarService.addToTaskMap(id, this); + this.executeNow = executeNow; + this.pattern = pattern; + } + + /** + * Returns the <tt>RecurringPattern</tt> instance associated with the + * calendar item. + * @return the <tt>RecurringPattern</tt> instance associated with the + * calendar item. + */ + public RecurringPattern getPattern() + { + return pattern; + } + + /** + * Returns the ID of the calendar item. + * @return the ID of the calendar item. + */ + public String getId() + { + return id; + } + + /** + * This method is executed in the beginning of the calendar item. + */ + protected void start() + { + calendarService.addToCurrentItems(this); + calendarService.updateStateFromCurrentItems(); + } + + /** + * This method is executed in the end of the calendar item. + */ + protected void stop() + { + calendarService.removeFromTaskMap(id); + calendarService.removeFromCurrentItems(this); + calendarService.updateStateFromCurrentItems(); + if(pattern != null) + { + CalendarItemTimerTask nextTask + = pattern.next(startDate, endDate); + this.pattern = null; + nextTask.scheduleTasks(); + } + + } + + /** + * Schedules the start and end tasks of the calendar item. + */ + public void scheduleTasks() + { + if(!executeNow) + { + timer.schedule(startTask, startDate); + } + else + { + startTask.run(); + } + timer.schedule(endTask, endDate); + } + + /** + * Removes the task. + */ + public void remove() + { + startTask.cancel(); + endTask.cancel(); + calendarService.removeFromTaskMap(id); + calendarService.removeFromCurrentItems(this); + calendarService.updateStateFromCurrentItems(); + } + + /** + * Returns the free busy status of the calendar item. + * @return the free busy status of the calendar item. + */ + public CalendarService.BusyStatusEnum getStatus() + { + return state; + } + + + /** + * Returns the start date of the calendar item + * @return the start date of the calendar item + */ + public Date getStartDate() + { + return startDate; + } + + /** + * Returns the end date of the calendar item + * @return the end date of the calendar item + */ + public Date getEndDate() + { + return endDate; + } + + /** + * Sets the <tt>RecurringPattern</tt> associated with the calendar item. + * @param pattern the pattern to set + */ + public void setPattern(RecurringPattern pattern) + { + this.pattern = pattern; + } +}
\ No newline at end of file diff --git a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/CalendarServiceImpl.java b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/CalendarServiceImpl.java new file mode 100644 index 0000000..ba82ee5 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/CalendarServiceImpl.java @@ -0,0 +1,746 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.addrbook.msoutlook.calendar; + + +import java.text.*; +import java.util.*; +import java.util.regex.*; + +import net.java.sip.communicator.plugin.addrbook.*; +import net.java.sip.communicator.plugin.addrbook.msoutlook.*; +import net.java.sip.communicator.util.*; +import net.java.sip.communicator.service.calendar.*; +import net.java.sip.communicator.service.protocol.*; + + +/** + * A implementation of <tt>CalendarService</tt> for MS Outlook calendar. + * The class resolves the free busy status and also changes the presence status + * according to free busy status. + * + * @author Hristo Terezov + */ +public class CalendarServiceImpl implements CalendarService +{ + /** + * Types for the MAPI properties values. + */ + public enum MAPIType + { + PT_SYSTIME, + PT_LONG, + PT_BOOL, + PT_BINARY + }; + + /** + * MAPI properties that we use to get information about the calendar items. + */ + public static enum MAPICalendarProperties + { + /** + * A property for the start date of the calendar item. + */ + PidLidAppointmentStartWhole(0x0000820D, MAPIType.PT_SYSTIME), + + /** + * A property for the end date of the calendar item. + */ + PidLidAppointmentEndWhole(0x0000820E, MAPIType.PT_SYSTIME), + + /** + * A property for the free busy status of the calendar item. + */ + PidLidBusyStatus(0x00008205, MAPIType.PT_LONG), + + /** + * A property that indicates if the calendar item is recurring or not. + */ + PidLidRecurring(0x00008223, MAPIType.PT_BOOL), + + /** + * A property with information about the recurrent pattern of the event. + */ + PidLidAppointmentRecur(0x00008216, MAPIType.PT_BINARY); + + /** + * The id of the property + */ + private final long id; + + /** + * The <tt>MAPIType</tt> of the property. + */ + private final MAPIType type; + + /** + * Constructs new property. + * @param id the id + * @param type the type + */ + MAPICalendarProperties(long id, MAPIType type) + { + this.id = id; + this.type = type; + } + + /** + * Returns array of IDs of created properties. + * @return array of IDs of created properties. + */ + public static long[] getALLPropertyIDs() + { + MAPICalendarProperties properties[] = values(); + long[] result = new long[properties.length]; + for(int i = 0; i < properties.length; i++) + { + result[i] = properties[i].getID(); + } + return result; + } + + public long getID() + { + return id; + } + + public MAPIType getType() + { + return type; + } + + /** + * Returns <tt>MAPICalendarProperties</tt> instance by given order ID + * @param i the order ID + * @return <tt>MAPICalendarProperties</tt> instance + */ + public static MAPICalendarProperties getByOrderId(int i) + { + return values()[i]; + } + } + + /** + * The <tt>Logger</tt> used by the <tt>CalendarServiceImpl</tt> + * class and its instances for logging output. + */ + private static final Logger logger + = Logger.getLogger(CalendarServiceImpl.class); + + /** + * A list with currently active <tt>CalendarItemTimerTask</tt>s + */ + private List<CalendarItemTimerTask> currentCalendarItems + = new LinkedList<CalendarItemTimerTask>(); + + /** + * A map with the calendar items IDs and <tt>CalendarItemTimerTask</tt>s. + * The map contains the current and future calendar items. + */ + private Map<String, CalendarItemTimerTask> taskMap + = new HashMap<String, CalendarItemTimerTask>(); + + /** + * The current free busy status. + */ + private BusyStatusEnum currentState = BusyStatusEnum.FREE; + + /** + * Instance of <tt>InMeetingStatusPolicy</tt> class which is used to update + * the presence status according the current free busy status. + */ + private InMeetingStatusPolicy inMeetingStatusPolicy + = new InMeetingStatusPolicy(); + + /** + * The flag which signals that MAPI strings should be returned in the + * unicode character set. + */ + public static final long MAPI_UNICODE = 0x80000000; + + static + { + System.loadLibrary("jmsoutlookaddrbook"); + } + + /** + * Adds <tt>CalendarItemTimerTask</tt> to the map of tasks. + * @param id the id of the calendar item to be added. + * @param task the <tt>CalendarItemTimerTask</tt> instance to be added. + */ + public void addToTaskMap(String id, CalendarItemTimerTask task) + { + synchronized(taskMap) + { + taskMap.put(id, task); + } + } + + /** + * Removes <tt>CalendarItemTimerTask</tt> from the map of tasks. + * @param id the id of the calendar item to be removed. + */ + public void removeFromTaskMap(String id) + { + synchronized(taskMap) + { + taskMap.remove(id); + } + } + + /** + * Adds <tt>CalendarItemTimerTask</tt> to the list of current tasks. + * @param task the <tt>CalendarItemTimerTask</tt> instance to be added. + */ + public void addToCurrentItems(CalendarItemTimerTask task) + { + synchronized(currentCalendarItems) + { + currentCalendarItems.add(task); + } + } + + /** + * Removes <tt>CalendarItemTimerTask</tt> from the list of current tasks. + * @param task the task of the calendar item to be removed. + */ + public void removeFromCurrentItems(CalendarItemTimerTask task) + { + synchronized(currentCalendarItems) + { + currentCalendarItems.remove(task); + } + } + + /** + * Retrieves, parses and stores all the calendar items from the outlook. + */ + public void start() + { + getAllCalendarItems(new NotificationsDelegate()); + } + + /** + * Retrieves, parses and stores all the calendar items from the outlook. + * @param callback the callback object that receives the results. + */ + private static native void getAllCalendarItems( + NotificationsDelegate callback); + + /** + * Returns array of property values for the given calendar item. + * @param entryId the entry id of the calendar item. + * @param propIds the IDs of the properties that we are interested for. + * @param flags the flags. + * @return array of property values for the given calendar item. + * @throws MsOutlookMAPIHResultException + */ + public static native Object[] IMAPIProp_GetProps(String entryId, + long[] propIds, long flags) + throws MsOutlookMAPIHResultException; + + /** + * Gets the property values of given calendar item and creates + * <tt>CalendarItemTimerTask</tt> instance for it. + * @param id The outlook calendar item identifier. + * + * @throws MsOutlookMAPIHResultException if anything goes wrong while + * getting the properties of the calendar item. + */ + private synchronized void insert(String id) + throws MsOutlookMAPIHResultException + { + Object[] props = null; + props + = IMAPIProp_GetProps(id, MAPICalendarProperties.getALLPropertyIDs(), + MAPI_UNICODE); + + addCalendarItem(props, id); + } + + /** + * Parses the property values of calendar item and creates + * <tt>CalendarItemTimerTask</tt> instance for the calendar item. + * @param props the property values. + * @param id the ID of the calendar item. + */ + private void addCalendarItem(Object[] props, String id) + { + Date startTime = null, endTime = null; + BusyStatusEnum status = BusyStatusEnum.FREE; + boolean isRecurring = false; + byte[] recurringData = null; + for(int i = 0; i < props.length; i++) + { + if(props[i] == null) + continue; + MAPICalendarProperties propertyName + = MAPICalendarProperties.getByOrderId(i); + switch(propertyName) + { + case PidLidAppointmentStartWhole: + try + { + long time + = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z") + .parse((String)props[i] + " UTC").getTime(); + startTime = new Date(time); + } + catch (ParseException e) + { + logger.error("Cannot parse date string: " + props[i]); + return; + } + break; + case PidLidAppointmentEndWhole: + try + { + long time + = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z") + .parse((String)props[i] + " UTC").getTime(); + endTime = new Date(time); + } + catch (ParseException e) + { + logger.error("Cannot parse date string: " + props[i]); + return; + } + break; + case PidLidBusyStatus: + status = BusyStatusEnum.getFromLong((Long)props[i]); + break; + case PidLidRecurring: + isRecurring = (Boolean)props[i]; + break; + case PidLidAppointmentRecur: + recurringData = ((byte[])props[i]); + break; + } + } + + if(status == BusyStatusEnum.FREE || startTime == null || endTime == null) + return; + + Date currentTime = new Date(); + + boolean executeNow = false; + + if(startTime.before(currentTime) || startTime.equals(currentTime)) + executeNow = true; + + CalendarItemTimerTask task = null; + if(recurringData != null) + { + task = new CalendarItemTimerTask(status, startTime, endTime, id, + executeNow, null); + RecurringPattern pattern + = new RecurringPattern(recurringData, task); + task.setPattern(pattern); + } + + if(endTime.before(currentTime) || endTime.equals(currentTime)) + { + if(isRecurring) + { + task = task.getPattern().next(startTime, endTime); + } + else + return; + } + + if(task == null) + task = new CalendarItemTimerTask(status, startTime, endTime, id, + executeNow, null); + + task.scheduleTasks(); + } + + /** + * Changes the value of the current status + * @param state the new value. + */ + protected void setCurrentState(BusyStatusEnum state) + { + if(currentState == state) + return; + BusyStatusEnum oldState = currentState; + this.currentState = state; + if((oldState == BusyStatusEnum.FREE && state != BusyStatusEnum.FREE) + || (oldState != BusyStatusEnum.FREE && state == BusyStatusEnum.FREE)) + { + inMeetingStatusPolicy.freeBusyStateChanged(); + } + + } + + /** + * Calculates and changes the value of current status using the current + * active calendar items and their statuses. + */ + public void updateStateFromCurrentItems() + { + BusyStatusEnum tmpState = BusyStatusEnum.FREE; + synchronized(currentCalendarItems) + { + for(CalendarItemTimerTask task : currentCalendarItems) + { + if(tmpState.getPriority() < task.getStatus().getPriority()) + { + tmpState = task.getStatus(); + } + } + } + setCurrentState(tmpState); + } + + @Override + public BusyStatusEnum getStatus() + { + return currentState; + } + + /** + * The method is not implemented yet. + */ + @Override + public void addFreeBusySateListener(FreeBusySateListener listener) + { + + } + + /** + * The method is not implemented yet. + */ + @Override + public void removeFreeBusySateListener(FreeBusySateListener listener) + { + + } + + /** + * Implements the policy to have the presence statuses of online accounts + * (i.e. registered <tt>ProtocolProviderService</tt>s) set to + * "In meeting" according the free busy status. + * + */ + private class InMeetingStatusPolicy + { + /** + * The regular expression which removes whitespace from the + * <tt>statusName</tt> property value of <tt>PresenceStatus</tt> + * instances in order to recognize the <tt>PresenceStatus</tt> which + * represents "In meeting". + */ + private final Pattern inMeetingPresenceStatusNameWhitespace + = Pattern.compile("\\p{Space}"); + + /** + * The <tt>PresenceStatus</tt>es of <tt>ProtocolProviderService</tt>s + * before they were changed to "In meeting" remembered so + * that they can be restored. + */ + private final Map<ProtocolProviderService,PresenceStatus> + presenceStatuses + = Collections.synchronizedMap( + new WeakHashMap<ProtocolProviderService,PresenceStatus>()); + + /** + * Notifies this instance that the free busy status has changed. + */ + public void freeBusyStateChanged() + { + run(); + } + + /** + * Finds the first <tt>PresenceStatus</tt> among the set of + * <tt>PresenceStatus</tt>es supported by a specific + * <tt>OperationSetPresence</tt> which represents + * "In meeting". + * + * @param presence the <tt>OperationSetPresence</tt> which represents + * the set of supported <tt>PresenceStatus</tt>es + * @return the first <tt>PresenceStatus</tt> among the set of + * <tt>PresenceStatus</tt>es supported by <tt>presence</tt> which + * represents "In meeting" if such a <tt>PresenceStatus</tt> + * was found; otherwise, <tt>null</tt> + */ + private PresenceStatus findInMeetingPresenceStatus( + OperationSetPresence presence) + { + for (Iterator<PresenceStatus> i = presence.getSupportedStatusSet(); + i.hasNext();) + { + PresenceStatus presenceStatus = i.next(); + + if (inMeetingPresenceStatusNameWhitespace + .matcher(presenceStatus.getStatusName()) + .replaceAll("") + .equalsIgnoreCase("InAMeeting")) + { + return presenceStatus; + } + } + return null; + } + + /** + * Removes the remembered presence status for given provider + * @param pps the provider + * @return the removed value + */ + private PresenceStatus forgetPresenceStatus(ProtocolProviderService pps) + { + return presenceStatuses.remove(pps); + } + + /** + * Removes all remembered presence statuses. + */ + private void forgetPresenceStatuses() + { + presenceStatuses.clear(); + } + + /** + * Determines whether the free busy status is busy or not + * + * @return <tt>true</tt> if the status is busy and <tt>false</tt> if the + * status is free + */ + private boolean isInMeeting() + { + return currentState != BusyStatusEnum.FREE; + } + + /** + * Invokes + * {@link OperationSetPresence#publishPresenceStatus(PresenceStatus, + * String)} on a specific <tt>OperationSetPresence</tt> with a specific + * <tt>PresenceStatus</tt> and catches any exceptions. + * + * @param presence the <tt>OperationSetPresence</tt> on which the method + * is to be invoked + * @param presenceStatus the <tt>PresenceStatus</tt> to provide as the + * respective method argument value + */ + private void publishPresenceStatus( + OperationSetPresence presence, + PresenceStatus presenceStatus) + { + try + { + presence.publishPresenceStatus(presenceStatus, null); + } + catch (Throwable t) + { + if (t instanceof InterruptedException) + Thread.currentThread().interrupt(); + else if (t instanceof ThreadDeath) + throw (ThreadDeath) t; + } + } + + private PresenceStatus rememberPresenceStatus( + ProtocolProviderService pps, + PresenceStatus presenceStatus) + { + return presenceStatuses.put(pps, presenceStatus); + } + + /** + * Applies this policy to the current state of the application. + */ + private void run() + { + List<ProtocolProviderService> providers + = AddrBookActivator.getProtocolProviders(); + + if ((providers == null) || (providers.size() == 0)) + { + forgetPresenceStatuses(); + } + else + { + boolean isInMeeting = isInMeeting(); + + for (ProtocolProviderService pps : providers) + { + if (pps == null) + continue; + + handleProtocolProvider(pps, isInMeeting); + } + } + } + + public void handleProtocolProvider(ProtocolProviderService pps, + Boolean isInMeeting) + { + if(isInMeeting == null) + isInMeeting = isInMeeting(); + + OperationSetPresence presence + = pps.getOperationSet(OperationSetPresence.class); + + if (presence == null) + { + /* + * "In meeting" is a PresenceStatus so it is available + * only to accounts which support presence in the first + * place. + */ + forgetPresenceStatus(pps); + } + else if (pps.isRegistered()) + { + PresenceStatus inMeetingPresenceStatus + = findInMeetingPresenceStatus(presence); + + if (inMeetingPresenceStatus == null) + { + /* + * If do not know how to define "On the phone" for + * an OperationSetPresence, then we'd better not + * mess with it in the first place. + */ + forgetPresenceStatus(pps); + } + else if (isInMeeting) + { + PresenceStatus presenceStatus + = presence.getPresenceStatus(); + + if (presenceStatus == null) + { + /* + * It is strange that an OperationSetPresence + * does not have a PresenceStatus so it may be + * safer to not mess with it. + */ + forgetPresenceStatus(pps); + } + else if (!inMeetingPresenceStatus.equals( + presenceStatus)) + { + publishPresenceStatus( + presence, + inMeetingPresenceStatus); + if (inMeetingPresenceStatus.equals( + presence.getPresenceStatus())) + { + rememberPresenceStatus(pps, presenceStatus); + } + else + { + forgetPresenceStatus(pps); + } + } + } + else + { + PresenceStatus presenceStatus + = forgetPresenceStatus(pps); + + if ((presenceStatus != null) + && inMeetingPresenceStatus.equals( + presence.getPresenceStatus())) + { + publishPresenceStatus(presence, presenceStatus); + } + } + } + else + { + /* + * Offline accounts do not get their PresenceStatus + * modified for the purposes of "On the phone". + */ + forgetPresenceStatus(pps); + } + + } + } + + /** + * Delegate class to be notified for calendar changes. + */ + public class NotificationsDelegate + { + /** + * Callback method when receiving notifications for inserted items. + */ + public void inserted(String id) + { + try + { + insert(id); + } + catch (MsOutlookMAPIHResultException e) + { + e.printStackTrace(); + } + } + + /** + * Callback method when receiving notifications for updated items. + */ + public void updated(String id) + { + synchronized(taskMap) + { + CalendarItemTimerTask task = taskMap.get(id); + if(task != null) + task.remove(); + } + try + { + insert(id); + } + catch (MsOutlookMAPIHResultException e) + { + e.printStackTrace(); + } + } + + /** + * Callback method when receiving notifications for deleted items. + */ + public void deleted(String id) + { + synchronized(taskMap) + { + CalendarItemTimerTask task = taskMap.get(id); + if(task != null) + task.remove(); + } + } + + /** + * Callback method when receiving notifications for deleted items. + */ + public boolean callback(String id) + { + try + { + insert(id); + } + catch (MsOutlookMAPIHResultException e) + { + e.printStackTrace(); + } + return true; + } + } + + public void handleProviderAdded(ProtocolProviderService pps) + { + inMeetingStatusPolicy.handleProtocolProvider(pps, null); + } + +} diff --git a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/RecurringPattern.java b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/RecurringPattern.java new file mode 100644 index 0000000..68fb9bd --- /dev/null +++ b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/RecurringPattern.java @@ -0,0 +1,1006 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.addrbook.msoutlook.calendar; + +import java.nio.*; +import java.text.*; +import java.util.*; + +import net.java.sip.communicator.service.calendar.*; +import net.java.sip.communicator.util.*; + +/** + * The class represents the recurring pattern structure of calendar item. + * + * @author Hristo Terezov + */ +public class RecurringPattern +{ + /** + * The <tt>Logger</tt> used by the <tt>RecurringPattern</tt> + * class and its instances for logging output. + */ + private static final Logger logger + = Logger.getLogger(RecurringPattern.class); + + /** + * Enum for the type of the pattern. + */ + public enum PatternType + { + /** + * Daily recurrence. + */ + Day((short)0x0000), + + /** + * Weekly recurrence. + */ + Week((short)0x0001), + + /** + * Monthly recurrence. + */ + Month((short)0x0002), + + /** + * Monthly recurrence. + */ + MonthNth((short)0x0003), + + /** + * Monthly recurrence. + */ + MonthEnd((short)0x004), + + /** + * Monthly recurrence. + */ + HjMonth((short)0x000A), + + /** + * Monthly recurrence. + */ + HjMonthNth((short)0x000B), + + /** + * Monthly recurrence. + */ + HjMonthEnd((short)0x000C); + + /** + * The value of the type. + */ + private short value = 0; + + /** + * Constructs new <tt>PatternType</tt> instance. + * @param value the value. + */ + PatternType(short value) + { + this.value = value; + } + + /** + * Returns the value of the <tt>PatternType</tt> instance. + * @return the value + */ + public short getValue() + { + return value; + } + + /** + * Finds the <tt>PatternType</tt> by given value. + * @param value the value + * @return the found <tt>PatternType</tt> instance or null if no type is + * found. + */ + public static PatternType getFromShort(short value) + { + for(PatternType type : values()) + { + if(type.getValue() == value) + { + return type; + } + } + return null; + } + }; + + /** + * The value of recurFrequency field. + */ + private short recurFrequency; + + /** + * The value of patternType field. + */ + private PatternType patternType; + + /** + * The value of calendarType field. + */ + private short calendarType; + + /** + * The value of firstDateTime field. + */ + private int firstDateTime; + + /** + * The value of period field. + */ + private int period; + + /** + * The value of slidingFlag field. + */ + private int slidingFlag; + + /** + * The value of patternSpecific1 field. + */ + private int patternSpecific1; + + /** + * The value of patternSpecific2 field. + */ + private int patternSpecific2; + + /** + * The value of endType field. + */ + private int endType; + + /** + * The value of occurenceCount field. + */ + private int occurenceCount; + + /** + * The value of firstDow field. + */ + private int firstDow; + + /** + * The value of deletedInstanceCount field. + */ + private int deletedInstanceCount; + + /** + * The value of modifiedInstanceCount field. + */ + private int modifiedInstanceCount; + + /** + * The value of startDate field. + */ + private int startDate; + + /** + * The value of endDate field. + */ + private int endDate; + + /** + * List with the start dates of deleted instances. + */ + private List<Date> deletedInstances = new ArrayList<Date>(); + + /** + * Array with the start dates of modified instances. + */ + private int[] modifiedInstances; + + /** + * List of exception info structures included in the pattern. + */ + private List<ExceptionInfo> exceptionInfo; + + /** + * The source calendar item of the recurrent series. + */ + private CalendarItemTimerTask sourceTask; + + /** + * List of days of week when the calendar item occurred. + */ + private List<Integer> allowedDaysOfWeek = new LinkedList<Integer>(); + + /** + * The binary data of the pattern. + */ + private ByteBuffer dataBuffer; + + /** + * Array with masks for days of week when the calendar item occurs. + */ + public static int[] weekOfDayMask + = {0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, + 0x00000020, 0x00000040}; + + /** + * Parses the binary data that describes the recurrent pattern. + * @param data the binary data. + * @param sourceTask the calendar item. + */ + public RecurringPattern(byte[] data, CalendarItemTimerTask sourceTask) + { + this.sourceTask = sourceTask; + dataBuffer + = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN); + + int offset = 4; + recurFrequency = dataBuffer.getShort(offset); + offset += 2; + + patternType = PatternType.getFromShort(dataBuffer.getShort(offset)); + offset += 2; + + calendarType = dataBuffer.getShort(offset); + offset += 2; + + firstDateTime = dataBuffer.getInt(offset); + offset += 4; + + period = dataBuffer.getInt(offset); + offset += 4; + + slidingFlag = dataBuffer.getInt(offset); + offset += 4; + + switch(patternType) + { + case Week: + case Month: + case MonthEnd: + case HjMonth: + case HjMonthEnd: + patternSpecific1 = dataBuffer.getInt(offset); + patternSpecific2 = 0; + offset +=4; + if(patternType == PatternType.Week) + { + for(int day = firstDow; day < firstDow + 7; day++) + { + if((patternSpecific1 & (weekOfDayMask[day%7])) != 0) + { + allowedDaysOfWeek.add((day%7) + 1); + } + } + } + break; + case MonthNth: + case HjMonthNth: + patternSpecific1 = dataBuffer.getInt(offset); + patternSpecific2 = dataBuffer.getInt(offset + 4); + if(patternSpecific1 == 0x7f && patternSpecific2 != 0x5) + { + patternType = PatternType.Month; + } + for(int day = 0; day < 7; day++) + { + if((patternSpecific1 & (weekOfDayMask[day])) != 0) + { + allowedDaysOfWeek.add((day) + 1); + } + } + offset +=8; + break; + default: + break; + } + + //endType + endType = dataBuffer.getInt(offset); + offset += 4; + + occurenceCount = dataBuffer.getInt(offset); + offset += 4; + + firstDow = dataBuffer.getInt(offset); + offset += 4; + + deletedInstanceCount = dataBuffer.getInt(offset); + offset += 4; + + //deleted instances + for(int i = 0; i < deletedInstanceCount; i ++) + { + deletedInstances.add( + windowsTimeToDateObject(dataBuffer.getInt(offset))); + offset += 4; + } + + + modifiedInstanceCount = dataBuffer.getInt(offset); + offset += 4; + + //modified instances + modifiedInstances = new int[modifiedInstanceCount]; + + for(int i = 0; i < modifiedInstanceCount; i ++) + { + modifiedInstances[i] = dataBuffer.getInt(offset); + offset += 4; + } + + + startDate = dataBuffer.getInt(offset); + offset += 4; + + endDate = dataBuffer.getInt(offset); + offset += 4; + + offset += 16; + + short exceptionCount = dataBuffer.getShort(offset); + offset += 2; + exceptionInfo = new ArrayList<ExceptionInfo>(exceptionCount); + for(int i = 0; i < exceptionCount;i++) + { + ExceptionInfo tmpExceptionInfo = new ExceptionInfo(offset); + exceptionInfo.add(tmpExceptionInfo); + offset += tmpExceptionInfo.sizeInBytes(); + + CalendarService.BusyStatusEnum status + = tmpExceptionInfo.getBusyStatus(); + Date startTime = tmpExceptionInfo.getStartDate(); + Date endTime = tmpExceptionInfo.getEndDate(); + if(status == CalendarService.BusyStatusEnum.FREE + || startTime == null || endTime == null) + continue; + Date currentTime = new Date(); + + if(endTime.before(currentTime) || endTime.equals(currentTime)) + return; + + boolean executeNow = false; + + if(startTime.before(currentTime) || startTime.equals(currentTime)) + executeNow = true; + + CalendarItemTimerTask task = new CalendarItemTimerTask(status, + startTime, endTime, sourceTask.getId(), executeNow, this); + + task.scheduleTasks(); + } + } + + /** + * Converts windows time in minutes from 1/1/1601 to <tt>Date</tt> object. + * @param time the number of minutes from 1/1/1601 + * @return the <tt>Date</tt> object + */ + public static Date windowsTimeToDateObject(long time) { + // Date.parse("1/1/1601") == 11644473600000L + long date = time * 60000 - 11644473600000L; + date -= TimeZone.getDefault().getOffset(date); + return new Date(date); + } + + /** + * Prints the properties of the class for debugging purpose. + */ + @Override + public String toString() + { + String result = ""; + result + += "recurFrequency: " + String.format("%#02x", this.recurFrequency) + + "\n"; + result += "patternType: " + + String.format("%#02x", this.patternType.getValue()) + "\n"; + result += "calendarType: " + + String.format("%#02x", this.calendarType) + "\n"; + result += "endType: " + String.format("%#04x", this.endType) + "\n"; + + result += "period: " + this.period + "\n"; + result += "occurenceCount: " + + String.format("%#04x", this.occurenceCount) + "\n"; + result += "patternSpecific1: " + + String.format("%#04x", this.patternSpecific1) + "\n"; + result += "patternSpecific2: " + + String.format("%#04x", this.patternSpecific2) + "\n"; + result += "startDate hex: " + String.format("%#04x", this.startDate) + + "\n"; + result += "endDate hex: " + String.format("%#04x", this.endDate) + "\n"; + + result += "startDate: " + + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format( + windowsTimeToDateObject(this.startDate)) + "\n"; + result += "endDate: " + + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format( + windowsTimeToDateObject(this.endDate)) + "\n"; + + + for(int i = 0; i < modifiedInstanceCount; i++) + { + result += "modified Instance date hex: " + + String.format("%#04x", this.modifiedInstances[i]) + "\n"; + + result += "modified Instance date: " + + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format( + windowsTimeToDateObject(this.modifiedInstances[i])) + "\n"; + } + + for(int i = 0; i < deletedInstanceCount; i++) + { + result += "deleted Instance date: " + + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format( + deletedInstances.get(i)) + "\n"; + } + result += "patternSpecific2: " + + String.format("%#04x", this.patternSpecific2) + "\n"; + + result += "\n\n =====================Exeptions====================\n\n"; + + for(ExceptionInfo info : exceptionInfo) + { + result += info.toString() + "\n\n"; + } + return result; + } + + /** + * Checks whether the given date is in the recurrent pattern range or not + * @param date the date + * @return <tt>true</tt> if the date is in the pattern range. + */ + private boolean dateOutOfRange(Date date) + { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE,0); + cal.set(Calendar.SECOND,0); + if((endType != 0x00002023) && (endType != 0xFFFFFFFF) + && cal.getTime().after(windowsTimeToDateObject(this.endDate))) + { + return true;// the series are finished + } + return false; + } + + /** + * Calculates and creates the next calendar item. + * @param previousStartDate the start date of the previous occurrence. + * @param previousEndDate the end date of the previous occurrence. + * @return the new calendar item or null if there are no more calendar items + * from that recurrent series. + */ + public CalendarItemTimerTask next(Date previousStartDate, + Date previousEndDate) + { + if(dateOutOfRange(new Date())) + { + return null; + } + Date startDate = previousStartDate; + Date endDate = null; + boolean executeNow = false; + long duration = sourceTask.getEndDate().getTime() + - sourceTask.getStartDate().getTime(); + switch(patternType) + { + case Day: + { + startDate + = new Date(startDate.getTime() + period * 60000); + endDate = new Date( + previousEndDate.getTime() + period * 60000); + Date currentDate = new Date(); + if(endDate.before(currentDate)) + { + long offset + = currentDate.getTime() - endDate.getTime(); + offset -= offset % (period * 60000); + if(endDate.getTime() + offset < currentDate.getTime()) + { + offset += period * 60000; + } + + startDate = new Date(startDate.getTime() + offset); + + } + + Calendar cal = Calendar.getInstance(); + cal.setTime(startDate); + Calendar cal2 = (Calendar) cal.clone(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + while(deletedInstances.contains(cal.getTime())) + { + cal.add(Calendar.MINUTE, period); + cal2.add(Calendar.MINUTE, period); + } + + if(dateOutOfRange(cal.getTime())) + { + return null; + } + startDate = cal2.getTime(); + endDate = new Date(startDate.getTime() + duration); + if(startDate.before(currentDate)) + { + executeNow = true; + } + + return new CalendarItemTimerTask( + sourceTask.getStatus(), + startDate, endDate, sourceTask.getId(), executeNow, this); + } + case Week: + { + Calendar cal = Calendar.getInstance(); + /** + * The enum for the firstDow field is the same as Calendar day of + * week enum + 1 day + */ + cal.setFirstDayOfWeek(firstDow + 1); + cal.setTime(startDate); + int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); + int index = allowedDaysOfWeek.indexOf(dayOfWeek); + if(++index < allowedDaysOfWeek.size()) + { + cal.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(index)); + startDate = cal.getTime(); + endDate = new Date(startDate.getTime() + duration); + } + else + { + cal.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(0)); + cal.add(Calendar.WEEK_OF_YEAR, period); + startDate = cal.getTime(); + endDate = new Date(startDate.getTime() + duration); + } + Date currentDate = new Date(); + if(endDate.before(currentDate)) + { + cal.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(0)); + endDate = new Date(cal.getTimeInMillis() + duration); + long offset = (currentDate.getTime() - endDate.getTime()); + + //1 week = 604800000 is milliseconds + offset -= offset % (period * 604800000); + if(endDate.getTime() + offset < currentDate.getTime()) + { + cal.add(Calendar.WEEK_OF_YEAR, + (int)(offset / (period * 604800000))); + int i = 1; + while(((cal.getTimeInMillis() + duration) + < (currentDate.getTime()))) + { + if(i == allowedDaysOfWeek.size()) + { + cal.add(Calendar.WEEK_OF_YEAR, period); + i = 0; + } + cal.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(i)); + i++; + } + + startDate = cal.getTime(); + } + else + { + startDate = new Date(cal.getTimeInMillis() + offset); + } + } + + cal.setTime(startDate); + Calendar cal2 = (Calendar) cal.clone(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); + index = allowedDaysOfWeek.indexOf(dayOfWeek) + 1; + while(deletedInstances.contains(cal.getTime())) + { + if(index >= allowedDaysOfWeek.size()) + { + index = 0; + cal.add(Calendar.WEEK_OF_YEAR, period); + cal2.add(Calendar.WEEK_OF_YEAR, period); + } + cal.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(index)); + cal2.set(Calendar.DAY_OF_WEEK, allowedDaysOfWeek.get(index)); + index++; + + } + startDate = cal2.getTime(); + endDate = new Date(startDate.getTime() + duration); + if(dateOutOfRange(endDate)) + return null; + if(startDate.before(currentDate)) + { + executeNow = true; + } + + return new CalendarItemTimerTask( + sourceTask.getStatus(), + startDate, endDate, sourceTask.getId(), executeNow, this); + } + case Month: + case MonthEnd: + case HjMonth: + case HjMonthEnd: + { + return nextMonth(startDate, endDate, false); + } + case MonthNth: + case HjMonthNth: + { + if(patternSpecific1 == 0x7f && patternSpecific2 == 0x05) + { + return nextMonth(startDate, endDate, true); + + } + + return nextMonthN(startDate, endDate); + + } + } + return null; + } + + /** + * Finds the occurrence of the events in the next months + * @param cal the calendar object + * @param lastDay if <tt>true</tt> it will return the last day of the month + * @param period the number of months to add + * @return the calendar object with set date + */ + private Calendar incrementMonths(Calendar cal, boolean lastDay, + int period) + { + int dayOfMonth = patternSpecific1; + cal.set(Calendar.DAY_OF_MONTH, 1); + cal.add(Calendar.MONTH, period); + if(lastDay + || (cal.getActualMaximum(Calendar.DAY_OF_MONTH) < dayOfMonth)) + dayOfMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH); + + cal.set(Calendar.DAY_OF_MONTH, dayOfMonth); + return cal; + } + + /** + * Finds the next occurrence for monthly recurrence. + * @param startDate the start date of the previous calendar item. + * @param endDate the end date of the previous calendar item. + * @param lastDay if <tt>true</tt> we are interested in last day of the + * month + * @return the next item + */ + public CalendarItemTimerTask nextMonth(Date startDate, Date endDate, + boolean lastDay) + { + long duration = sourceTask.getEndDate().getTime() + - sourceTask.getStartDate().getTime(); + Calendar cal = Calendar.getInstance(); + cal.setTime(startDate); + cal = incrementMonths(cal, lastDay, period); + Date currentDate = new Date(); + if(cal.getTimeInMillis() + duration < currentDate.getTime()) + { + Calendar cal2 = Calendar.getInstance(); + cal2.setTime(currentDate); + int years + = cal2.get(Calendar.YEAR) - cal.get(Calendar.YEAR); + int months = (years * 12) + + (cal2.get(Calendar.MONTH) - cal.get(Calendar.MONTH)); + int monthsToAdd = months; + monthsToAdd -= months % period; + cal = incrementMonths(cal, lastDay, monthsToAdd); + if(cal.getTimeInMillis() + duration < currentDate.getTime()) + { + cal = incrementMonths(cal, lastDay, period); + } + } + + Calendar cal2 = (Calendar) cal.clone(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + while(deletedInstances.contains(cal.getTime())) + { + cal = incrementMonths(cal, lastDay, period); + cal2 = incrementMonths(cal2, lastDay, period); + } + + startDate = cal2.getTime(); + endDate = new Date(startDate.getTime() + duration); + if(dateOutOfRange(endDate)) + { + return null; + + } + boolean executeNow = false; + if(startDate.before(currentDate)) + { + executeNow = true; + } + + + + return new CalendarItemTimerTask( + sourceTask.getStatus(), + startDate, endDate, sourceTask.getId(), executeNow, this); + } + + /** + * Finds the occurrence of the events in the next months + * @param startDate the start date if the calendar item + * @param dayOfWeekInMonth the number of week days occurrences + * @return the date of the next occurrence + */ + private Date getMonthNStartDate(Date startDate, int dayOfWeekInMonth) + { + Calendar cal = Calendar.getInstance(); + cal.setTime(startDate); + + if(dayOfWeekInMonth == -1) + { + Date result = null; + cal.set(Calendar.DAY_OF_WEEK_IN_MONTH, dayOfWeekInMonth); + for(int day : allowedDaysOfWeek) + { + cal.set(Calendar.DAY_OF_WEEK, day); + if(result == null || result.before(cal.getTime())) + result = cal.getTime(); + } + return result; + } + else + while(dayOfWeekInMonth > 0) + { + int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); + if(allowedDaysOfWeek.contains(dayOfWeek)) + dayOfWeekInMonth--; + if(dayOfWeekInMonth > 0) + cal.add(Calendar.DAY_OF_MONTH, 1); + + } + return cal.getTime(); + } + + /** + * Finds the next occurrence for monthly Nth recurrence. + * @param startDate the start date of the previous calendar item. + * @param endDate the end date of the previous calendar item. + * @return the next item + */ + public CalendarItemTimerTask nextMonthN(Date startDate, Date endDate) + { + int dayOfWeekInMonth = (patternSpecific2 == 5? -1 : patternSpecific2); + long duration = sourceTask.getEndDate().getTime() + - sourceTask.getStartDate().getTime(); + Calendar cal = Calendar.getInstance(); + cal.setTime(startDate); + cal.set(Calendar.DAY_OF_MONTH, 1); + cal.add(Calendar.MONTH, period); + cal.setTime(getMonthNStartDate(cal.getTime(), dayOfWeekInMonth)); + Date currentDate = new Date(); + if(cal.getTimeInMillis() + duration < currentDate.getTime()) + { + Calendar cal2 = Calendar.getInstance(); + cal2.setTime(currentDate); + int years + = cal2.get(Calendar.YEAR) - cal.get(Calendar.YEAR); + int months = (years * 12) + + (cal2.get(Calendar.MONTH) - cal.get(Calendar.MONTH)); + int monthsToAdd = months; + monthsToAdd -= months % period; + cal.set(Calendar.DAY_OF_MONTH, 1); + cal.add(Calendar.MONTH, monthsToAdd); + cal.setTime(getMonthNStartDate(cal.getTime(), dayOfWeekInMonth)); + if(cal.getTimeInMillis() + duration < currentDate.getTime()) + { + cal.set(Calendar.DAY_OF_MONTH, 1); + cal.add(Calendar.MONTH, monthsToAdd); + cal.setTime(getMonthNStartDate(cal.getTime(), dayOfWeekInMonth)); + } + } + + Calendar cal2 = (Calendar) cal.clone(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + while(deletedInstances.contains(cal.getTime())) + { + cal.set(Calendar.DAY_OF_MONTH, 1); + cal.add(Calendar.MONTH, period); + startDate = null; + for(int dayOfWeek : allowedDaysOfWeek) + { + cal.set(Calendar.DAY_OF_WEEK, dayOfWeek); + cal.set(Calendar.DAY_OF_WEEK_IN_MONTH,dayOfWeekInMonth); + if((cal.after(startDate) && dayOfWeekInMonth == -1) + || (cal.before(startDate) && dayOfWeekInMonth != -1) + || startDate == null) + { + startDate = cal.getTime(); + cal2.set(Calendar.YEAR,cal.get(Calendar.YEAR)); + cal2.set(Calendar.MONTH,cal.get(Calendar.MONTH)); + cal2.set(Calendar.DATE,cal.get(Calendar.DATE)); + } + } + } + + startDate = cal2.getTime(); + endDate = new Date(startDate.getTime() + duration); + + if(dateOutOfRange(endDate)) + return null; + + boolean executeNow = false; + if(startDate.before(currentDate)) + { + executeNow = true; + } + + return new CalendarItemTimerTask( + sourceTask.getStatus(), + startDate, endDate, sourceTask.getId(), executeNow, this); + } + + /** + * Represents the exception info structure. + */ + public class ExceptionInfo + { + /** + * The start date of the exception. + */ + private final Date startDate; + + /** + * The end date of the exception. + */ + private final Date endDate; + + /** + * The original start date of the exception. + */ + private final Date originalStartDate; + + /** + * The modified flags of the exception. + */ + private final short overrideFlags; + + /** + * The new busy status of the exception. + */ + private CalendarService.BusyStatusEnum busyStatus; + + /** + * The size of the fixed fields. + */ + private int size = 22; + + /** + * Parses the data of the exception. + * @param offset the position where the exception starts in the binary + * data + */ + public ExceptionInfo(int offset) + { + startDate = windowsTimeToDateObject(dataBuffer.getInt(offset)); + offset += 4; + + endDate = windowsTimeToDateObject(dataBuffer.getInt(offset)); + offset += 4; + + originalStartDate + = windowsTimeToDateObject(dataBuffer.getInt(offset)); + offset += 4; + + overrideFlags = dataBuffer.getShort(offset); + offset += 2; + int[] fieldMasks = {0x0001, 0x0002, 0x0004, 0x0008, 0x0010, + 0x0020, 0x0040, 0x0080}; + for(int mask : fieldMasks) + { + if(mask == 0x0020) + { + if((overrideFlags & mask) != 0) + { + busyStatus = CalendarService.BusyStatusEnum.getFromLong( + (long)dataBuffer.getInt(offset)); + } + + if(busyStatus == null) + { + busyStatus = sourceTask.getStatus(); + } + } + + if((overrideFlags & mask) != 0) + { + if(mask == 0x0010 || mask == 0x0001) + { + short size = dataBuffer.getShort(offset + 2); + offset += size; + size += size; + } + offset += 4; + size += 4; + } + } + + offset += 4; + int reservedBlockSize = dataBuffer.getShort(offset); + size += reservedBlockSize; + + } + + /** + * Returns the size of the exception + * @return the size of the exception + */ + public int sizeInBytes() + { + return size; + } + + /** + * Returns the start date + * @return the start date + */ + public Date getStartDate() + { + return startDate; + } + + /** + * Returns the end date + * @return the end date + */ + public Date getEndDate() + { + return endDate; + } + + /** + * Returns the busy status + * @return the busy status + */ + public CalendarService.BusyStatusEnum getBusyStatus() + { + return busyStatus; + } + + /** + * Prints the properties of the class for debugging purpose. + */ + @Override + public String toString() + { + String result = ""; + result += "startDate: " + + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z") + .format(startDate) + "\n"; + result += "endDate: " + + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z") + .format(endDate) + "\n"; + result += "originalStartDate: " + + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z") + .format(originalStartDate) + "\n"; + return result; + } + } +}
\ No newline at end of file diff --git a/src/net/java/sip/communicator/plugin/msofficecomm/Messenger.java b/src/net/java/sip/communicator/plugin/msofficecomm/Messenger.java index 20220da..e8e5b91 100644 --- a/src/net/java/sip/communicator/plugin/msofficecomm/Messenger.java +++ b/src/net/java/sip/communicator/plugin/msofficecomm/Messenger.java @@ -63,6 +63,8 @@ public class Messenger * client user is on the phone. */ static final int MISTATUS_ON_THE_PHONE = 0x0032; + + static final int MISTATUS_IN_A_MEETING = 0x0052; static final int MISTATUS_ONLINE = 0x0002; @@ -1122,6 +1124,18 @@ public class Messenger { mistatus = MISTATUS_ON_THE_PHONE; } + else if ((i == 32 /* FIXME */) + && ProtocolNames.JABBER.equalsIgnoreCase(protocolName) + && JabberStatusEnum.IN_A_MEETING.equalsIgnoreCase( + presenceStatus.getStatusName())) + { + mistatus = MISTATUS_IN_A_MEETING; + } + else if (ProtocolNames.MSN.equalsIgnoreCase(protocolName) + && MsnStatusEnum.IN_A_MEETING.equals(presenceStatus)) + { + mistatus = MISTATUS_IN_A_MEETING; + } else if (i < PresenceStatus.ONLINE_THRESHOLD) mistatus = MISTATUS_OFFLINE; else if (i < PresenceStatus.AWAY_THRESHOLD) diff --git a/src/net/java/sip/communicator/service/calendar/CalendarService.java b/src/net/java/sip/communicator/service/calendar/CalendarService.java new file mode 100644 index 0000000..24d1ea8 --- /dev/null +++ b/src/net/java/sip/communicator/service/calendar/CalendarService.java @@ -0,0 +1,129 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.calendar; + +/** + * A service for calendar. It defines for accessing the current free busy status + * and add / remove listeners for the free busy status. + * + * @author Hristo Terezov + */ +public interface CalendarService +{ + /** + * Defines the possible free busy statuses. + * @author Hristo Terezov + */ + public enum BusyStatusEnum + { + /** + * The Free status. + */ + FREE((long)0x00000000), + + /** + * The In meeting status. + */ + IN_MEETING((long)0x00000001), + + /** + * The busy status. + */ + BUSY((long)0x00000002), + + /** + * The out of office status. + */ + OUT_OF_OFFICE((long)0x00000003); + + /** + * The value of the status. + */ + private final long value; + + /** + * The priority of the status + */ + private final Integer priority; + + /** + * Constructs new status. + * @param value the value of the status + */ + BusyStatusEnum(Long value) + { + this.value = value; + this.priority = null; + } + + /** + * Returns the value of the status. + * @return the value of the status. + */ + public long getValue() + { + return value; + } + + /** + * Finds <tt>BusyStatusEnum</tt> instance by given value of the status. + * @param value the value of the status we are searching for. + * @return the status or <tt>FREE</tt> if no status is found. + */ + public static BusyStatusEnum getFromLong(Long value) + { + for(BusyStatusEnum state : values()) + { + if(state.getValue() == value) + { + return state; + } + } + return FREE; + } + + /** + * Returns the priority of the status + * @return the priority of the status + */ + public int getPriority() + { + if(priority != null) + { + return priority; + } + return ordinal(); + } + }; + + /** + * The name of the configuration property which specifies whether + * free busy status is disabled i.e. whether it should set the + * presence statuses of online accounts to "In Meeting". + */ + public static final String PNAME_FREE_BUSY_STATUS_DISABLED + = "net.java.sip.communicator.service.calendar.FreeBusyStatus" + + ".disabled"; + + /** + * Returns the current value of the free busy status. + * @return the current value of the free busy status. + */ + public BusyStatusEnum getStatus(); + + /** + * Adds free busy listener. + * @param listener the listener to be added. + */ + public void addFreeBusySateListener(FreeBusySateListener listener); + + /** + * Removes free busy listener. + * @param listener the listener to be removed. + */ + public void removeFreeBusySateListener(FreeBusySateListener listener); + +} diff --git a/src/net/java/sip/communicator/service/calendar/FreeBusySateListener.java b/src/net/java/sip/communicator/service/calendar/FreeBusySateListener.java new file mode 100644 index 0000000..0972733 --- /dev/null +++ b/src/net/java/sip/communicator/service/calendar/FreeBusySateListener.java @@ -0,0 +1,21 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.calendar; + +/** + * A interface for listener that listens for calendar free busy status changes. + * @author Hristo Terezov + */ +public interface FreeBusySateListener +{ + /** + * A method that is called when the free busy status is changed. + * @param oldStatus the old value of the status. + * @param newStatus the new value of the status. + */ + public void onStatusChanged(CalendarService.BusyStatusEnum oldStatus, + CalendarService.BusyStatusEnum newStatus); +} diff --git a/src/net/java/sip/communicator/service/protocol/jabberconstants/JabberStatusEnum.java b/src/net/java/sip/communicator/service/protocol/jabberconstants/JabberStatusEnum.java index ecea2f8..f9d088e 100644 --- a/src/net/java/sip/communicator/service/protocol/jabberconstants/JabberStatusEnum.java +++ b/src/net/java/sip/communicator/service/protocol/jabberconstants/JabberStatusEnum.java @@ -60,6 +60,12 @@ public class JabberStatusEnum * Indicates that the user is talking to the phone. */ public static final String ON_THE_PHONE = "On the phone"; + + /** + * In meeting Chat status. + * Indicates that the user is in meeting. + */ + public static final String IN_A_MEETING = "In a meeting"; /** * The Free For Chat status. Indicates that the user is eager to @@ -111,6 +117,11 @@ public class JabberStatusEnum * Indicates an On The Phone status. */ private final JabberPresenceStatus onThePhoneStatus; + + /** + * Indicates an On The Phone status. + */ + private final JabberPresenceStatus inMeetingStatus; /** * Indicates an Extended Away status or status. @@ -176,6 +187,10 @@ public class JabberStatusEnum this.onThePhoneStatus = new JabberPresenceStatus(31, ON_THE_PHONE, loadIcon(iconPath + "/status16x16-phone.png")); + + this.inMeetingStatus = + new JabberPresenceStatus(32, IN_A_MEETING, loadIcon(iconPath + + "/status16x16-meeting.png")); this.extendedAwayStatus = new JabberPresenceStatus(35, EXTENDED_AWAY, loadIcon(iconPath @@ -202,6 +217,7 @@ public class JabberStatusEnum supportedStatusSet.add(availableStatus); supportedStatusSet.add(awayStatus); supportedStatusSet.add(onThePhoneStatus); + supportedStatusSet.add(inMeetingStatus); supportedStatusSet.add(extendedAwayStatus); supportedStatusSet.add(doNotDisturbStatus); supportedStatusSet.add(offlineStatus); @@ -227,6 +243,8 @@ public class JabberStatusEnum return awayStatus; else if (statusName.equals(ON_THE_PHONE)) return onThePhoneStatus; + else if(statusName.equals(IN_A_MEETING)) + return inMeetingStatus; else if (statusName.equals(EXTENDED_AWAY)) return extendedAwayStatus; else diff --git a/src/net/java/sip/communicator/service/protocol/msnconstants/MsnStatusEnum.java b/src/net/java/sip/communicator/service/protocol/msnconstants/MsnStatusEnum.java index 3c3298d..2fbbcec 100644 --- a/src/net/java/sip/communicator/service/protocol/msnconstants/MsnStatusEnum.java +++ b/src/net/java/sip/communicator/service/protocol/msnconstants/MsnStatusEnum.java @@ -87,6 +87,13 @@ public class MsnStatusEnum public static final MsnStatusEnum ON_THE_PHONE = new MsnStatusEnum(31, "On the phone", loadIcon("resources/images/protocol/msn/msn16x16-phone.png")); + + /** + * The In Meeting status. Indicates that the user is in meeting. + */ + public static final MsnStatusEnum IN_A_MEETING + = new MsnStatusEnum(32, "In a meeting", + loadIcon("resources/images/protocol/msn/msn16x16-meeting.png")); /** * The DND status. Indicates that the user has connectivity but prefers @@ -109,9 +116,11 @@ public class MsnStatusEnum */ public static final ArrayList<MsnStatusEnum> msnStatusSet = new ArrayList<MsnStatusEnum>(); + static{ msnStatusSet.add(OUT_TO_LUNCH); msnStatusSet.add(ON_THE_PHONE); + msnStatusSet.add(IN_A_MEETING); msnStatusSet.add(ONLINE); msnStatusSet.add(OFFLINE); msnStatusSet.add(IDLE); |