aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhristoterezov <hristo@jitsi.org>2014-04-02 17:04:44 +0300
committerhristoterezov <hristo@jitsi.org>2014-04-02 17:04:44 +0300
commit96ef724f2db9365250a7a9d76dbe8b19c3987f55 (patch)
treeef97430715621ab5579739acd4fa75903c048026
parenta325c6bc19214271cf7e98768179b5a71257eb91 (diff)
downloadjitsi-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.
-rw-r--r--build.xml2
-rw-r--r--lib/native/windows-64/IMsOutlookAddrBookClient.tlbbin1892 -> 1992 bytes
-rw-r--r--lib/native/windows-64/IMsOutlookAddrBookServer.tlbbin2604 -> 2740 bytes
-rwxr-xr-xlib/native/windows-64/jmsoutlookaddrbook.dllbin283471 -> 289513 bytes
-rwxr-xr-xlib/native/windows-64/jmsoutlookaddrbookcomserver32.exebin230095 -> 235702 bytes
-rwxr-xr-xlib/native/windows-64/jmsoutlookaddrbookcomserver64.exebin289415 -> 295457 bytes
-rw-r--r--resources/images/protocol/jabber/status16x16-meeting.pngbin0 -> 1986 bytes
-rw-r--r--resources/images/protocol/msn/msn16x16-meeting.pngbin0 -> 1990 bytes
-rw-r--r--resources/images/protocol/sip/sip16x16-meeting.pngbin0 -> 1713 bytes
-rw-r--r--src/native/addrbook/msoutlook/MAPINotification.cxx111
-rw-r--r--src/native/addrbook/msoutlook/MAPINotification.h4
-rw-r--r--src/native/addrbook/msoutlook/MAPISession.cxx1
-rw-r--r--src/native/addrbook/msoutlook/MsOutlookAddrBookContactQuery.cxx237
-rw-r--r--src/native/addrbook/msoutlook/MsOutlookAddrBookContactQuery.h31
-rw-r--r--src/native/addrbook/msoutlook/MsOutlookCalendar.cxx194
-rw-r--r--src/native/addrbook/msoutlook/MsOutlookCalendar.h21
-rw-r--r--src/native/addrbook/msoutlook/MsOutlookUtils.cxx404
-rw-r--r--src/native/addrbook/msoutlook/MsOutlookUtils.h34
-rw-r--r--src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.h23
-rw-r--r--src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.idl3
-rw-r--r--src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.tlbbin1892 -> 1992 bytes
-rw-r--r--src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.h27
-rw-r--r--src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.idl4
-rw-r--r--src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.tlbbin2604 -> 2740 bytes
-rw-r--r--src/native/addrbook/msoutlook/com/MsOutlookAddrBookClient.cxx10
-rw-r--r--src/native/addrbook/msoutlook/com/MsOutlookAddrBookClient.h2
-rw-r--r--src/native/addrbook/msoutlook/com/MsOutlookAddrBookServer.cxx67
-rw-r--r--src/native/addrbook/msoutlook/com/MsOutlookAddrBookServer.h7
-rw-r--r--src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_MsOutlookAddrBookContactQuery.cxx228
-rw-r--r--src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl.cxx44
-rw-r--r--src/native/addrbook/msoutlook/net_java_sip_communicator_plugin_addrbook_msoutlook_calendar_CalendarServiceImpl.h30
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetPersistentPresenceJabberImpl.java11
-rw-r--r--src/net/java/sip/communicator/impl/protocol/msn/OperationSetPersistentPresenceMsnImpl.java1
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/SipStatusEnum.java18
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/AddrBookActivator.java187
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/addrbook.manifest.mf1
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java47
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/CalendarItemTimerTask.java225
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/CalendarServiceImpl.java746
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/msoutlook/calendar/RecurringPattern.java1006
-rw-r--r--src/net/java/sip/communicator/plugin/msofficecomm/Messenger.java14
-rw-r--r--src/net/java/sip/communicator/service/calendar/CalendarService.java129
-rw-r--r--src/net/java/sip/communicator/service/calendar/FreeBusySateListener.java21
-rw-r--r--src/net/java/sip/communicator/service/protocol/jabberconstants/JabberStatusEnum.java18
-rw-r--r--src/net/java/sip/communicator/service/protocol/msnconstants/MsnStatusEnum.java9
45 files changed, 3507 insertions, 410 deletions
diff --git a/build.xml b/build.xml
index 2b636a0..722207c 100644
--- a/build.xml
+++ b/build.xml
@@ -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
index 168d9ad..6873acd 100644
--- a/lib/native/windows-64/IMsOutlookAddrBookClient.tlb
+++ b/lib/native/windows-64/IMsOutlookAddrBookClient.tlb
Binary files differ
diff --git a/lib/native/windows-64/IMsOutlookAddrBookServer.tlb b/lib/native/windows-64/IMsOutlookAddrBookServer.tlb
index 9492af3..267171f 100644
--- a/lib/native/windows-64/IMsOutlookAddrBookServer.tlb
+++ b/lib/native/windows-64/IMsOutlookAddrBookServer.tlb
Binary files differ
diff --git a/lib/native/windows-64/jmsoutlookaddrbook.dll b/lib/native/windows-64/jmsoutlookaddrbook.dll
index f58c4c9..7072f4a 100755
--- a/lib/native/windows-64/jmsoutlookaddrbook.dll
+++ b/lib/native/windows-64/jmsoutlookaddrbook.dll
Binary files differ
diff --git a/lib/native/windows-64/jmsoutlookaddrbookcomserver32.exe b/lib/native/windows-64/jmsoutlookaddrbookcomserver32.exe
index 087e118..b249bfd 100755
--- a/lib/native/windows-64/jmsoutlookaddrbookcomserver32.exe
+++ b/lib/native/windows-64/jmsoutlookaddrbookcomserver32.exe
Binary files differ
diff --git a/lib/native/windows-64/jmsoutlookaddrbookcomserver64.exe b/lib/native/windows-64/jmsoutlookaddrbookcomserver64.exe
index 6cedd98..e78d5fa 100755
--- a/lib/native/windows-64/jmsoutlookaddrbookcomserver64.exe
+++ b/lib/native/windows-64/jmsoutlookaddrbookcomserver64.exe
Binary files differ
diff --git a/resources/images/protocol/jabber/status16x16-meeting.png b/resources/images/protocol/jabber/status16x16-meeting.png
new file mode 100644
index 0000000..9e24e1b
--- /dev/null
+++ b/resources/images/protocol/jabber/status16x16-meeting.png
Binary files differ
diff --git a/resources/images/protocol/msn/msn16x16-meeting.png b/resources/images/protocol/msn/msn16x16-meeting.png
new file mode 100644
index 0000000..c2fd663
--- /dev/null
+++ b/resources/images/protocol/msn/msn16x16-meeting.png
Binary files differ
diff --git a/resources/images/protocol/sip/sip16x16-meeting.png b/resources/images/protocol/sip/sip16x16-meeting.png
new file mode 100644
index 0000000..d196310
--- /dev/null
+++ b/resources/images/protocol/sip/sip16x16-meeting.png
Binary files differ
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
index 168d9ad..6873acd 100644
--- a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.tlb
+++ b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookClient.tlb
Binary files differ
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
index 9492af3..267171f 100644
--- a/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.tlb
+++ b/src/native/addrbook/msoutlook/com/IMsOutlookAddrBookServer.tlb
Binary files differ
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
+ * &quot;In meeting&quot; 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 &quot;In meeting&quot;.
+ */
+ private final Pattern inMeetingPresenceStatusNameWhitespace
+ = Pattern.compile("\\p{Space}");
+
+ /**
+ * The <tt>PresenceStatus</tt>es of <tt>ProtocolProviderService</tt>s
+ * before they were changed to &quot;In meeting&quot; 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
+ * &quot;In meeting&quot;.
+ *
+ * @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 &quot;In meeting&quot; 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 &quot;In Meeting&quot;.
+ */
+ 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);