4035 lines
104 KiB
C++
4035 lines
104 KiB
C++
// XTPCalendarMAPIDataProvider.cpp: implementation of the CXTPCalendarMAPIDataProvider class.
|
|
//
|
|
// This file is a part of the XTREME CALENDAR MFC class library.
|
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
|
//
|
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
|
// CONSENT OF CODEJOCK SOFTWARE.
|
|
//
|
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
|
// SINGLE COMPUTER.
|
|
//
|
|
// CONTACT INFORMATION:
|
|
// support@codejock.com
|
|
// http://www.codejock.com
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "Common/XTPSmartPtrInternalT.h"
|
|
#include "Common/XTPVC80Helpers.h"
|
|
|
|
#include "XTPCalendarDefines.h"
|
|
#include "XTPCalendarUtils.h"
|
|
|
|
#include "XTPCalendarEvent.h"
|
|
#include "XTPCalendarEvents.h"
|
|
#include "XTPCalendarRecurrencePattern.h"
|
|
|
|
#include "XTPCalendarCustomProperties.h"
|
|
|
|
#include "XTPCalendarData.h"
|
|
|
|
#include "XTPCalendarMemoryDataProvider.h"
|
|
|
|
#include "XTPCalendarMAPIWrapper.h"
|
|
#include "XTPCalendarMAPIDataProvider.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
//#define XTP_TRACE_READ_EVENTS TRACE
|
|
#ifndef XTP_TRACE_READ_EVENTS
|
|
#define XTP_TRACE_READ_EVENTS //1 ? (void)0 : TRACE
|
|
#endif
|
|
|
|
//#define XTP_TRACE_READ_IDS TRACE
|
|
#ifndef XTP_TRACE_READ_IDS
|
|
#define XTP_TRACE_READ_IDS //1 ? (void)0 : TRACE
|
|
#endif
|
|
|
|
//#define XTP_TRACE_MAPI_NF TRACE
|
|
#ifndef XTP_TRACE_MAPI_NF
|
|
#define XTP_TRACE_MAPI_NF //1 ? (void)0 : TRACE
|
|
#endif
|
|
|
|
#define MAPI_FREEBUFFER(pProvider, pBuffer) if (pProvider && pBuffer) { pProvider->MAPIFreeBuffer(pBuffer); pBuffer = NULL;}
|
|
#define MAPI_RELEASE(pProvider, x) if (pProvider && x) { pProvider->UlRelease(x); x = 0;}
|
|
|
|
#define cFileTimeUnitsPerSecond 10000000i64
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
IMPLEMENT_DYNAMIC(CXTPCalendarMAPIDataProvider, CXTPCalendarData)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
template<class _T>
|
|
_T xtpGetDataT(const CByteArray& arData, int nOffset)
|
|
{
|
|
if (nOffset < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
if ((int)(nOffset + sizeof(_T)) > (int)arData.GetSize())
|
|
{
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
const _T* pDataT = (const _T*)(arData.GetData() + nOffset);
|
|
|
|
return *pDataT;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
template<class _T>
|
|
_T xtpGetNextDataT(const BYTE*& rpData, const BYTE* pMax = NULL)
|
|
{
|
|
if (!rpData || pMax && (rpData + sizeof(_T)) > pMax)
|
|
{
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
const _T* pDataT = (const _T*)(rpData);
|
|
rpData += sizeof(_T);
|
|
|
|
return *pDataT;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
CString xtpGetNextData_MapiExcStr8(const BYTE*& rpData, const BYTE* pMax = NULL)
|
|
{
|
|
if (!rpData)
|
|
{
|
|
ASSERT(FALSE);
|
|
return _T("");
|
|
}
|
|
|
|
// layout: [w:buf-size][w:str-len][ascii-char: count=len]
|
|
int nBuffer = (int)xtpGetNextDataT<WORD>(rpData, pMax);
|
|
UNUSED_ALWAYS(nBuffer);
|
|
int nStrLen = (int)xtpGetNextDataT<WORD>(rpData, pMax);
|
|
|
|
if (pMax && (rpData + nStrLen) > pMax)
|
|
{
|
|
ASSERT(FALSE);
|
|
return _T("");
|
|
}
|
|
|
|
CString strData = CString((char*)rpData, nStrLen);
|
|
rpData += nStrLen;
|
|
|
|
return strData;
|
|
}
|
|
|
|
//===========================================================================
|
|
template<class _T>
|
|
void xtpAddDataT(CByteArray& rarData, _T tValue)
|
|
{
|
|
int nSize = sizeof(_T);
|
|
BYTE* pBytes = (BYTE*)&tValue;
|
|
for (int i = 0; i < nSize; i++)
|
|
{
|
|
rarData.Add(pBytes[i]);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
template<class _T>
|
|
int xtpSetDataT(CByteArray& rarData, int nOffset, _T tValue)
|
|
{
|
|
if (nOffset < 0)
|
|
{
|
|
return nOffset;
|
|
}
|
|
|
|
int nValueSize = sizeof(_T);
|
|
if (rarData.GetSize() < nOffset + nValueSize)
|
|
{
|
|
rarData.SetSize(nOffset + nValueSize, 4096);
|
|
}
|
|
|
|
_T* pValue = &tValue;
|
|
_T* pDest = (_T*)(rarData.GetData() + nOffset);
|
|
|
|
*pDest = *pValue;
|
|
|
|
return nOffset + nValueSize;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void xtpAddData_MapiExcStr8(CByteArray& rarData, LPCTSTR pcszString)
|
|
{
|
|
// layout: [w:buf-size][w:str-len][ascii-char: count=len]
|
|
int nStrLenW = (int)_tcslen(pcszString);
|
|
int nStrSize = nStrLenW*2 + 1;
|
|
CHAR* pStr = new CHAR[nStrSize];
|
|
if (!pStr)
|
|
{
|
|
xtpAddDataT<WORD>(rarData, 1);
|
|
xtpAddDataT<WORD>(rarData, 0);
|
|
return;
|
|
}
|
|
|
|
ZeroMemory(pStr, nStrSize);
|
|
|
|
WCSTOMBS_S(pStr, pcszString, nStrSize-1);
|
|
|
|
int nStrLen = (int)strlen(pStr);
|
|
int nBuffer = nStrLen + 1;
|
|
|
|
xtpAddDataT<WORD>(rarData, (WORD)nBuffer);
|
|
xtpAddDataT<WORD>(rarData, (WORD)nStrLen);
|
|
|
|
int nSize = (int)rarData.GetSize();
|
|
rarData.SetSize(nSize + nStrLen, 4096);
|
|
void* pDest = rarData.GetData() + nSize;
|
|
|
|
MEMCPY_S(pDest, pStr, nStrLen);
|
|
|
|
delete[] pStr;
|
|
}
|
|
|
|
//===========================================================================
|
|
void xtp_GetWinTZInfo(const CByteArray& arMapiTZInfo, TIME_ZONE_INFORMATION* pTZInfo)
|
|
{
|
|
if (arMapiTZInfo.GetSize() < sizeof(XTP_MAPI_TIME_ZONE_INFORMATION) || !pTZInfo)
|
|
{
|
|
ASSERT(FALSE);
|
|
return;
|
|
}
|
|
XTP_MAPI_TIME_ZONE_INFORMATION* pMapiTZInfo;
|
|
pMapiTZInfo = (XTP_MAPI_TIME_ZONE_INFORMATION*)arMapiTZInfo.GetData();
|
|
|
|
ZeroMemory(pTZInfo, sizeof(TIME_ZONE_INFORMATION));
|
|
|
|
pTZInfo->Bias = pMapiTZInfo->Bias;
|
|
pTZInfo->StandardBias = pMapiTZInfo->StandardBias;
|
|
pTZInfo->DaylightBias = pMapiTZInfo->DaylightBias;
|
|
pTZInfo->StandardDate = pMapiTZInfo->StandardDate;
|
|
pTZInfo->DaylightDate = pMapiTZInfo->DaylightDate;
|
|
}
|
|
|
|
void xtp_GetMapiTZInfo(TIME_ZONE_INFORMATION* pTZInfo, CByteArray& arMapiTZInfo)
|
|
{
|
|
XTP_MAPI_TIME_ZONE_INFORMATION* pMapiTZInfo;
|
|
|
|
arMapiTZInfo.SetSize(sizeof(XTP_MAPI_TIME_ZONE_INFORMATION));
|
|
pMapiTZInfo = (XTP_MAPI_TIME_ZONE_INFORMATION*)arMapiTZInfo.GetData();
|
|
|
|
ZeroMemory(pMapiTZInfo, sizeof(XTP_MAPI_TIME_ZONE_INFORMATION));
|
|
pMapiTZInfo->Bias = pTZInfo->Bias;
|
|
pMapiTZInfo->StandardBias = pTZInfo->StandardBias;
|
|
pMapiTZInfo->DaylightBias = pTZInfo->DaylightBias;
|
|
pMapiTZInfo->StandardDate = pTZInfo->StandardDate;
|
|
pMapiTZInfo->DaylightDate = pTZInfo->DaylightDate;
|
|
}
|
|
|
|
COleDateTime xtp_UtcToTzTime(const TIME_ZONE_INFORMATION* pTZI, const SYSTEMTIME& stUtcTime)
|
|
{
|
|
SYSTEMTIME stTzTime;
|
|
|
|
if (!CXTPCalendarUtils::SystemTimeToTzSpecificLocalTime(pTZI, &stUtcTime, &stTzTime))
|
|
{
|
|
return (DATE)0;
|
|
}
|
|
|
|
COleDateTime dtTzTime(stTzTime);
|
|
|
|
return dtTzTime;
|
|
}
|
|
|
|
SYSTEMTIME xtp_TimeToUtc(const TIME_ZONE_INFORMATION* pTZI, const COleDateTime& dtTzTime)
|
|
{
|
|
SYSTEMTIME stUtcTime;
|
|
ZeroMemory(&stUtcTime, sizeof(stUtcTime));
|
|
|
|
SYSTEMTIME stTzTime;
|
|
if (!CXTPCalendarUtils::GetAsSystemTime(dtTzTime, stTzTime) )
|
|
{
|
|
return stUtcTime;
|
|
}
|
|
|
|
COleDateTime dt = xtp_UtcToTzTime(pTZI, stTzTime);
|
|
dt = dtTzTime + (dtTzTime - dt);
|
|
|
|
if (!CXTPCalendarUtils::GetAsSystemTime(dt, stUtcTime) )
|
|
{
|
|
return stUtcTime;
|
|
}
|
|
return stUtcTime;
|
|
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
class CXTPCalendarMAPI_Recurrence
|
|
{
|
|
public:
|
|
|
|
// Holds byte offsets of data fields within MAPI binary field
|
|
struct XTP_RCDATA_LAYOUT
|
|
{
|
|
int nType; // radioSelector;
|
|
int nType2; // type
|
|
int nRCShiftX; // magic MAPI number. Probably used to generate occurrences.
|
|
int nInterval; // interval;
|
|
int nRegenerate; // regenerate // for tasks only
|
|
int nWeekDayMask; // weekDayMask // week Of Month
|
|
int nInstance; // instance
|
|
int nEndByType; // endByType
|
|
int nOccurrences;
|
|
int nDynData; // Unaligned data offset
|
|
};
|
|
|
|
// 0 - Daily, 1 - Weekly, 2 - MonYearly, 3 - MonYearly_Nth
|
|
static XTP_RCDATA_LAYOUT s_arRCDataLayout[4];
|
|
|
|
//=======================================================================
|
|
class CXTPRcException
|
|
{
|
|
public:
|
|
DWORD dwNewStart;
|
|
DWORD dwNewEnd;
|
|
DWORD dwOrigStart;
|
|
|
|
BOOL bDeleted;
|
|
|
|
WORD wFlags;
|
|
|
|
CString strSubject; // xtpMAPIRcED_Subject
|
|
BOOL bIsMeeting; // xtpMAPIRcED_IsMeeting
|
|
int nReminderTime; // xtpMAPIRcED_ReminderTime
|
|
BOOL bIsReminder; // xtpMAPIRcED_IsReminder
|
|
CString strLocation; // xtpMAPIRcED_Location
|
|
int nBusyStatus; // xtpMAPIRcED_BusyStatus - enum XTPCalendarEventBusyStatus
|
|
BOOL bIsAllDay; // xtpMAPIRcED_IsAllDay
|
|
int nLabel; // xtpMAPIRcED_Label
|
|
|
|
CXTPRcException();
|
|
const CXTPRcException& operator=(const CXTPRcException& rSrc);
|
|
void Set(CXTPCalendarEvent* pExc, CXTPCalendarEvent* pMaster);
|
|
};
|
|
|
|
class CXTPRcExceptions : public CArray<CXTPRcException, CXTPRcException&>
|
|
{
|
|
public:
|
|
CXTPRcExceptions(){};
|
|
virtual ~CXTPRcExceptions(){};
|
|
|
|
int FindByOrigStart(DWORD dwOrigStart);
|
|
|
|
void SortByOrigStart();
|
|
void SortByNewStart();
|
|
protected:
|
|
typedef int (_cdecl* T_CompareFunc)(const CXTPRcException* pExc1, const CXTPRcException* pExc2);
|
|
void _Sort(T_CompareFunc);
|
|
|
|
static int _cdecl CompareAsc_ByOrigStart(const CXTPRcException* pExc1, const CXTPRcException* pExc2);
|
|
static int _cdecl CompareAsc_ByNewStart(const CXTPRcException* pExc1, const CXTPRcException* pExc2);
|
|
};
|
|
|
|
//=======================================================================
|
|
//struct XTP_RCDATA
|
|
class CXTPRcData
|
|
{
|
|
public:
|
|
WORD wType;
|
|
BYTE ucType2;
|
|
DWORD dwRCShiftX;
|
|
DWORD dwInterval;
|
|
DWORD dwWeekDayMask;
|
|
BYTE ucInstance;
|
|
|
|
DWORD dwEndByType;
|
|
DWORD dwOccurrences;
|
|
DWORD dwEndDate;
|
|
|
|
DWORD dwStartDate;
|
|
|
|
DWORD dwOccStartTime;
|
|
DWORD dwOccEndTime;
|
|
|
|
CXTPRcExceptions arExceptions;
|
|
|
|
CXTPRcData();
|
|
virtual ~CXTPRcData(){};
|
|
|
|
};
|
|
|
|
static BOOL ReadRCData(CXTPRcData& rRCData, const CByteArray& arRCData);
|
|
|
|
static void SetRecurrenceOptions(CXTPCalendarRecurrencePattern* pPattern,
|
|
const CXTPRcData& RCData);
|
|
static void SetRecurrenceExceptions(CXTPCalendarEvent* pMasterEvent,
|
|
CXTPCalendarRecurrencePattern* pPattern,
|
|
const CXTPRcData& RCData);
|
|
|
|
//-----------------------------------------------------------------------
|
|
static BOOL FillRCData( CXTPRcData& rRCData,
|
|
CXTPCalendarRecurrencePattern* pPattern,
|
|
CXTPCalendarEvent* pMaster);
|
|
|
|
static BOOL RCDataToBin(CXTPRcData& rRCData, CByteArray& rarRCData);
|
|
|
|
static COleDateTime ConvertRecurrenceMinutesToDate(DWORD dwMinutes);
|
|
static DWORD ConvertRecurrenceDateToMinutes(COleDateTime date);
|
|
|
|
protected:
|
|
static void _ReadRCDataExceptions (CXTPRcData& rRCData, const BYTE* pExcData,
|
|
const BYTE* pMaxPtr, const BYTE* pExclusions);
|
|
|
|
static DWORD _CalcRCShiftX(CXTPCalendarRecurrencePattern* pPattern);
|
|
};
|
|
|
|
//
|
|
// MAPI recurrence layouts definitions
|
|
//
|
|
CXTPCalendarMAPI_Recurrence::XTP_RCDATA_LAYOUT
|
|
CXTPCalendarMAPI_Recurrence::s_arRCDataLayout[] =
|
|
{
|
|
// daily
|
|
{
|
|
4, // type
|
|
6, // type2
|
|
10, // RCShiftX
|
|
14, // interval
|
|
18, // regenerate
|
|
-1, // weekDayMask
|
|
-1, // instance
|
|
22, // endByType
|
|
26, // nOccurrences
|
|
26 + 2 * sizeof(DWORD) // nDynData
|
|
},
|
|
// weakly
|
|
{
|
|
4, // type
|
|
6, // type2
|
|
10, // RCShiftX
|
|
14, // interval
|
|
18, // regenerate
|
|
22, // weekDayMask
|
|
-1, // instance
|
|
26, // endByType
|
|
30, // nOccurrences
|
|
30 + 2 * sizeof(DWORD) // nDynData
|
|
},
|
|
// monthly
|
|
{
|
|
4, // type
|
|
6, // type2
|
|
10, // RCShiftX
|
|
14, // interval
|
|
18, // regenerate
|
|
-1, // weekDayMask
|
|
22, // instance
|
|
26, // endByType
|
|
30, // nOccurrences
|
|
30 + 2 * sizeof(DWORD) // nDynData
|
|
},
|
|
// monthly Nth ()
|
|
{
|
|
4, // type
|
|
6, // type2
|
|
10, // RCShiftX
|
|
14, // interval
|
|
18, // regenerate
|
|
22, // weekDayMask
|
|
26, // instance
|
|
30, // endByType
|
|
34, // nOccurrences
|
|
34 + 2 * sizeof(DWORD) // nDynData
|
|
},
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CXTPCalendarMAPI_Recurrence::CXTPRcException::CXTPRcException()
|
|
{
|
|
dwNewStart = 0;
|
|
dwNewEnd = 0;
|
|
dwOrigStart = 0;
|
|
|
|
bDeleted = FALSE;
|
|
|
|
wFlags = 0;
|
|
//strSubject;
|
|
bIsMeeting = FALSE;
|
|
nReminderTime = 0;
|
|
bIsReminder = FALSE;
|
|
//strLocation;
|
|
nBusyStatus = 0;
|
|
bIsAllDay = FALSE;
|
|
nLabel = 0;
|
|
}
|
|
|
|
void CXTPCalendarMAPI_Recurrence::CXTPRcException::Set(CXTPCalendarEvent* pExc, CXTPCalendarEvent* pMaster)
|
|
{
|
|
CXTPRcException rexZero;
|
|
*this = rexZero;
|
|
|
|
if (!pExc || !pMaster)
|
|
{
|
|
ASSERT(FALSE);
|
|
return;
|
|
}
|
|
|
|
wFlags = 0;
|
|
|
|
bDeleted = pExc->IsRExceptionDeleted();
|
|
|
|
dwOrigStart = CXTPCalendarMAPI_Recurrence::ConvertRecurrenceDateToMinutes(pExc->GetRException_StartTimeOrig());
|
|
|
|
if (bDeleted)
|
|
{
|
|
return;
|
|
}
|
|
|
|
dwNewStart = CXTPCalendarMAPI_Recurrence::ConvertRecurrenceDateToMinutes(pExc->GetStartTime());
|
|
dwNewEnd = CXTPCalendarMAPI_Recurrence::ConvertRecurrenceDateToMinutes(pExc->GetEndTime());
|
|
|
|
if (pExc->GetSubject() != pMaster->GetSubject())
|
|
{
|
|
wFlags |= xtpMAPIRcED_Subject;
|
|
strSubject = pExc->GetSubject();
|
|
}
|
|
if (pExc->IsMeeting() != pMaster->IsMeeting())
|
|
{
|
|
wFlags |= xtpMAPIRcED_IsMeeting;
|
|
bIsMeeting = pExc->IsMeeting();
|
|
}
|
|
if (pExc->GetReminderMinutesBeforeStart() != pMaster->GetReminderMinutesBeforeStart())
|
|
{
|
|
wFlags |= xtpMAPIRcED_ReminderTime;
|
|
nReminderTime = pExc->GetReminderMinutesBeforeStart();
|
|
}
|
|
if (pExc->IsReminder() != pMaster->IsReminder())
|
|
{
|
|
wFlags |= xtpMAPIRcED_IsReminder;
|
|
bIsReminder = pExc->IsReminder();
|
|
}
|
|
if (pExc->GetLocation() != pMaster->GetLocation())
|
|
{
|
|
wFlags |= xtpMAPIRcED_Location;
|
|
strLocation = pExc->GetLocation();
|
|
}
|
|
if (pExc->GetBusyStatus() != pMaster->GetBusyStatus())
|
|
{
|
|
wFlags |= xtpMAPIRcED_BusyStatus;
|
|
nBusyStatus = pExc->GetBusyStatus();
|
|
}
|
|
if (pExc->IsAllDayEvent() != pMaster->IsAllDayEvent())
|
|
{
|
|
wFlags |= xtpMAPIRcED_IsAllDay;
|
|
bIsAllDay = pExc->IsAllDayEvent();
|
|
}
|
|
if (pExc->GetLabelID() != pMaster->GetLabelID())
|
|
{
|
|
wFlags |= xtpMAPIRcED_Label;
|
|
nLabel = pExc->GetLabelID();
|
|
}
|
|
}
|
|
|
|
const CXTPCalendarMAPI_Recurrence::CXTPRcException&
|
|
CXTPCalendarMAPI_Recurrence::CXTPRcException::operator= (
|
|
const CXTPCalendarMAPI_Recurrence::CXTPRcException& rSrc)
|
|
{
|
|
dwNewStart = rSrc.dwNewStart;
|
|
dwNewEnd = rSrc.dwNewEnd;
|
|
dwOrigStart = rSrc.dwOrigStart;
|
|
|
|
bDeleted = rSrc.bDeleted;
|
|
|
|
wFlags = rSrc.wFlags;
|
|
|
|
strSubject = rSrc.strSubject;
|
|
bIsMeeting = rSrc.bIsMeeting;
|
|
nReminderTime = rSrc.nReminderTime;
|
|
bIsReminder = rSrc.bIsReminder;
|
|
strLocation = rSrc.strLocation;
|
|
nBusyStatus = rSrc.nBusyStatus;
|
|
bIsAllDay = rSrc.bIsAllDay;
|
|
nLabel = rSrc.nLabel;
|
|
|
|
return *this;
|
|
}
|
|
|
|
int CXTPCalendarMAPI_Recurrence::CXTPRcExceptions::FindByOrigStart(DWORD dwOrigStart)
|
|
{
|
|
int nCount = (int)GetSize();
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
const CXTPRcException& rce = ElementAt(i);
|
|
|
|
if (rce.dwOrigStart == dwOrigStart)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void CXTPCalendarMAPI_Recurrence::CXTPRcExceptions::SortByOrigStart()
|
|
{
|
|
_Sort(CompareAsc_ByOrigStart);
|
|
}
|
|
|
|
void CXTPCalendarMAPI_Recurrence::CXTPRcExceptions::SortByNewStart()
|
|
{
|
|
_Sort(CompareAsc_ByNewStart);
|
|
}
|
|
|
|
void CXTPCalendarMAPI_Recurrence::CXTPRcExceptions::_Sort(T_CompareFunc pCompareFunc)
|
|
{
|
|
typedef int (_cdecl *GENERICCOMPAREFUNC)(const void *, const void*);
|
|
|
|
qsort(GetData(), (size_t)GetSize(), sizeof(CXTPRcException), (GENERICCOMPAREFUNC)pCompareFunc);
|
|
}
|
|
|
|
int _cdecl CXTPCalendarMAPI_Recurrence::CXTPRcExceptions::CompareAsc_ByOrigStart(const CXTPRcException* pExc1, const CXTPRcException* pExc2)
|
|
{
|
|
if (pExc1->dwOrigStart < pExc2->dwOrigStart)
|
|
{
|
|
return -1;
|
|
}
|
|
if (pExc1->dwOrigStart > pExc2->dwOrigStart)
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int _cdecl CXTPCalendarMAPI_Recurrence::CXTPRcExceptions::CompareAsc_ByNewStart(const CXTPRcException* pExc1, const CXTPRcException* pExc2)
|
|
{
|
|
if (pExc1->dwNewStart < pExc2->dwNewStart)
|
|
{
|
|
return -1;
|
|
}
|
|
if (pExc1->dwNewStart > pExc2->dwNewStart)
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CXTPCalendarMAPI_Recurrence::CXTPRcData::CXTPRcData()
|
|
{
|
|
wType = 0;
|
|
ucType2 = 0;
|
|
dwRCShiftX = 0;
|
|
dwInterval = 0;
|
|
dwWeekDayMask = 0;
|
|
ucInstance = 0;
|
|
|
|
dwEndByType = 0;
|
|
dwOccurrences = 0;
|
|
dwEndDate = 0;
|
|
|
|
dwStartDate = 0;
|
|
|
|
dwOccStartTime = 0;
|
|
dwOccEndTime = 0;
|
|
|
|
//arExceptions;
|
|
}
|
|
|
|
|
|
BOOL CXTPCalendarMAPI_Recurrence::ReadRCData(
|
|
CXTPCalendarMAPI_Recurrence::CXTPRcData& rRCData,
|
|
const CByteArray& arRCData)
|
|
{
|
|
XTPCalendarMAPIRcType eRCType;
|
|
XTPCalendarMAPIRcType2 eRCType2;
|
|
eRCType = (XTPCalendarMAPIRcType)xtpGetDataT<WORD>(arRCData, s_arRCDataLayout[0].nType);
|
|
eRCType2 = (XTPCalendarMAPIRcType2)xtpGetDataT<BYTE>(arRCData, s_arRCDataLayout[0].nType2);
|
|
|
|
BOOL bTypeValid = eRCType == xtpMAPIRcType_Daily || eRCType == xtpMAPIRcType_Weekly ||
|
|
eRCType == xtpMAPIRcType_Monthly || eRCType == xtpMAPIRcType_Yearly;
|
|
|
|
if (eRCType2 < xtpMAPIRcType2_First || eRCType2 > xtpMAPIRcType2_Last || !bTypeValid)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
XTP_RCDATA_LAYOUT RCLayout;
|
|
::ZeroMemory(&RCLayout, sizeof(RCLayout));
|
|
|
|
// select layout
|
|
RCLayout = s_arRCDataLayout[eRCType2];
|
|
|
|
rRCData.wType = xtpGetDataT<WORD>(arRCData, RCLayout.nType);
|
|
rRCData.ucType2 = xtpGetDataT<BYTE>(arRCData, RCLayout.nType2);
|
|
rRCData.dwRCShiftX = xtpGetDataT<DWORD>(arRCData, RCLayout.nRCShiftX);
|
|
rRCData.dwInterval = xtpGetDataT<DWORD>(arRCData, RCLayout.nInterval);
|
|
rRCData.dwWeekDayMask = xtpGetDataT<DWORD>(arRCData, RCLayout.nWeekDayMask);
|
|
rRCData.ucInstance = xtpGetDataT<BYTE>(arRCData, RCLayout.nInstance);
|
|
rRCData.dwEndByType = xtpGetDataT<DWORD>(arRCData, RCLayout.nEndByType);
|
|
rRCData.dwOccurrences = xtpGetDataT<DWORD>(arRCData, RCLayout.nOccurrences);
|
|
|
|
//
|
|
const BYTE* p = arRCData.GetData() + RCLayout.nDynData;
|
|
const BYTE* pMax = arRCData.GetData() + arRCData.GetSize();
|
|
|
|
const BYTE* pExclusions = p;
|
|
|
|
// skip old and new dates
|
|
p += sizeof(DWORD) * (xtpGetNextDataT<DWORD>(p, pMax)); // skip old start dates
|
|
p += sizeof(DWORD) * (xtpGetNextDataT<DWORD>(p, pMax)); // old new start dates
|
|
|
|
// pick up start/end dates
|
|
|
|
//Pattern Start Date
|
|
rRCData.dwStartDate = xtpGetNextDataT<DWORD>(p, pMax);
|
|
// /*DBG*/ ConvertRecurrenceMinutesToDate(rRCData.dwStartDate);
|
|
|
|
//Pattern End Date
|
|
rRCData.dwEndDate = xtpGetNextDataT<DWORD>(p, pMax);
|
|
// /*DBG*/ ConvertRecurrenceMinutesToDate(rRCData.dwEndDate);
|
|
|
|
// skip unknown reserved fields
|
|
xtpGetNextDataT<DWORD>(p, pMax);
|
|
xtpGetNextDataT<DWORD>(p, pMax);
|
|
|
|
// Occurrence start/end time - in minutes from the day begin
|
|
// hour = time / 60, minute = time % 60
|
|
rRCData.dwOccStartTime = xtpGetNextDataT<DWORD>(p, pMax);
|
|
rRCData.dwOccEndTime = xtpGetNextDataT<DWORD>(p, pMax);
|
|
|
|
//p - points to detailed exceptions information.
|
|
|
|
_ReadRCDataExceptions(rRCData, p, pMax, pExclusions);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CXTPCalendarMAPI_Recurrence::_ReadRCDataExceptions(
|
|
CXTPCalendarMAPI_Recurrence::CXTPRcData& rRCData,
|
|
const BYTE* pExcData, const BYTE* pMaxPtr,
|
|
const BYTE* pExclusions
|
|
)
|
|
{
|
|
// read detailed recurrence exceptions information
|
|
int nCount = (int)xtpGetNextDataT<WORD>(pExcData, pMaxPtr);
|
|
int i;
|
|
for (i = 0; i < nCount; i++)
|
|
{
|
|
CXTPRcException RCExc;
|
|
|
|
RCExc.dwNewStart = xtpGetNextDataT<DWORD>(pExcData, pMaxPtr);
|
|
RCExc.dwNewEnd = xtpGetNextDataT<DWORD>(pExcData, pMaxPtr);
|
|
RCExc.dwOrigStart = xtpGetNextDataT<DWORD>(pExcData, pMaxPtr);
|
|
|
|
RCExc.wFlags = xtpGetNextDataT<WORD>(pExcData, pMaxPtr);
|
|
|
|
if (RCExc.wFlags & xtpMAPIRcED_Subject)
|
|
{
|
|
// layout: [w:buf-size][w:str-len][ascii-char: count=len]
|
|
RCExc.strSubject = xtpGetNextData_MapiExcStr8(pExcData, pMaxPtr);
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_IsMeeting)
|
|
{
|
|
// layout: [dw] - bool(0|1)
|
|
RCExc.bIsMeeting = xtpGetNextDataT<DWORD>(pExcData, pMaxPtr) != 0;
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_ReminderTime)
|
|
{
|
|
// layout: [dw] minutes before start
|
|
RCExc.nReminderTime = xtpGetNextDataT<DWORD>(pExcData, pMaxPtr);
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_IsReminder)
|
|
{
|
|
// layout: [dw] - bool(0|1)
|
|
RCExc.bIsReminder = xtpGetNextDataT<DWORD>(pExcData, pMaxPtr) != 0;
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_Location)
|
|
{
|
|
// layout: [w:buf-size][w:str-len][ascii-char: count=len]
|
|
RCExc.strLocation = xtpGetNextData_MapiExcStr8(pExcData, pMaxPtr);
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_BusyStatus)
|
|
{
|
|
// layout: [dw] - busy status [0..3] = XTPCalendarEventBusyStatus
|
|
RCExc.nBusyStatus = xtpGetNextDataT<DWORD>(pExcData, pMaxPtr);
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_IsAllDay)
|
|
{
|
|
// layout: [dw] - bool(0|1)
|
|
RCExc.bIsAllDay = xtpGetNextDataT<DWORD>(pExcData, pMaxPtr) != 0;
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_Label)
|
|
{
|
|
// layout: [dw] -
|
|
RCExc.nLabel = xtpGetNextDataT<DWORD>(pExcData, pMaxPtr);
|
|
}
|
|
|
|
rRCData.arExceptions.Add(RCExc);
|
|
}
|
|
|
|
ASSERT(rRCData.dwOccEndTime >= rRCData.dwOccStartTime);
|
|
|
|
// determine and add deleted exceptions
|
|
nCount = (int)xtpGetNextDataT<DWORD>(pExclusions, pMaxPtr);
|
|
for (i = 0; i < nCount; i++)
|
|
{
|
|
CXTPRcException RCExc;
|
|
RCExc.dwOrigStart = xtpGetNextDataT<DWORD>(pExclusions, pMaxPtr);
|
|
RCExc.dwOrigStart += rRCData.dwOccStartTime;
|
|
RCExc.bDeleted = TRUE;
|
|
|
|
if (rRCData.arExceptions.FindByOrigStart(RCExc.dwOrigStart) < 0)
|
|
{
|
|
rRCData.arExceptions.Add(RCExc);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CXTPCalendarMAPI_Recurrence::SetRecurrenceOptions(
|
|
CXTPCalendarRecurrencePattern* pPattern,
|
|
const CXTPCalendarMAPI_Recurrence::CXTPRcData& RCData)
|
|
{
|
|
ASSERT(pPattern);
|
|
if (!pPattern)
|
|
{
|
|
return;
|
|
}
|
|
|
|
XTP_CALENDAR_RECURRENCE_OPTIONS opt;
|
|
|
|
// Recurrence type
|
|
switch (RCData.wType)
|
|
{
|
|
case xtpMAPIRcType_Daily:
|
|
{
|
|
opt.m_nRecurrenceType = xtpCalendarRecurrenceDaily;
|
|
opt.m_Daily.bEveryWeekDayOnly = (RCData.ucType2 == xtpMAPIRcType2_Weekly);
|
|
|
|
if (opt.m_Daily.bEveryWeekDayOnly)
|
|
{
|
|
opt.m_Daily.nIntervalDays = 1;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(RCData.dwInterval % (24 * 60) == 0);
|
|
opt.m_Daily.nIntervalDays = (int)RCData.dwInterval / (24 * 60);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case xtpMAPIRcType_Weekly:
|
|
{
|
|
opt.m_nRecurrenceType = xtpCalendarRecurrenceWeekly;
|
|
ASSERT(RCData.ucType2 == xtpMAPIRcType2_Weekly); // == 1, 0 only for tasks
|
|
|
|
opt.m_Weekly.nIntervalWeeks = (int)RCData.dwInterval;
|
|
opt.m_Weekly.nDayOfWeekMask = (int)RCData.dwWeekDayMask;
|
|
}
|
|
break;
|
|
|
|
case xtpMAPIRcType_Monthly:
|
|
{
|
|
if (RCData.ucType2 == xtpMAPIRcType2_MonYearly)
|
|
{
|
|
opt.m_nRecurrenceType = xtpCalendarRecurrenceMonthly;
|
|
opt.m_Monthly.nIntervalMonths = (int)RCData.dwInterval;
|
|
opt.m_Monthly.nDayOfMonth = (int)RCData.ucInstance;
|
|
}
|
|
else if (RCData.ucType2 == xtpMAPIRcType2_MonYearly_Nth)
|
|
{
|
|
opt.m_nRecurrenceType = xtpCalendarRecurrenceMonthNth;
|
|
opt.m_MonthNth.nIntervalMonths = (int)RCData.dwInterval;
|
|
opt.m_MonthNth.nWhichDay = (int)RCData.ucInstance; // ???
|
|
opt.m_MonthNth.nWhichDayMask = (int)RCData.dwWeekDayMask; // ???
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case xtpMAPIRcType_Yearly:
|
|
{
|
|
ASSERT(RCData.dwInterval % 12 == 0 && RCData.dwInterval);
|
|
|
|
//---------------------------------------------------------------
|
|
int nMonthOfYear = 1;
|
|
// days per month - jan feb mar apr may jun jul aug sep oct nov dec
|
|
static int arDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
int nDaysInMinutes = 0;
|
|
for (int i = 0; i < 12; i++)
|
|
{
|
|
if (nDaysInMinutes >= (int)RCData.dwRCShiftX)
|
|
{
|
|
nMonthOfYear = i+1;
|
|
break;
|
|
}
|
|
nDaysInMinutes += arDays[i] * 24 * 60;
|
|
}
|
|
ASSERT(nDaysInMinutes == (int)RCData.dwRCShiftX);
|
|
|
|
//---------------------------------------------------------------
|
|
if (RCData.ucType2 == xtpMAPIRcType2_MonYearly)
|
|
{
|
|
opt.m_nRecurrenceType = xtpCalendarRecurrenceYearly;
|
|
opt.m_Yearly.nDayOfMonth = RCData.ucInstance;
|
|
opt.m_Yearly.nMonthOfYear = nMonthOfYear;
|
|
}
|
|
else if (RCData.ucType2 == xtpMAPIRcType2_MonYearly_Nth)
|
|
{
|
|
opt.m_nRecurrenceType = xtpCalendarRecurrenceYearNth;
|
|
opt.m_YearNth.nWhichDay = RCData.ucInstance;
|
|
opt.m_YearNth.nWhichDayMask = RCData.dwWeekDayMask;
|
|
opt.m_YearNth.nMonthOfYear = nMonthOfYear;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
pPattern->SetRecurrenceOptions(opt);
|
|
|
|
pPattern->SetPatternStartDate(ConvertRecurrenceMinutesToDate(RCData.dwStartDate));
|
|
|
|
XTP_CALENDAR_PATTERN_END rpEnd;
|
|
switch (RCData.dwEndByType)
|
|
{
|
|
case xtpMAPIRcEnd_Date:
|
|
rpEnd.m_nUseEnd = xtpCalendarPatternEndDate;
|
|
rpEnd.m_dtPatternEndDate = ConvertRecurrenceMinutesToDate(RCData.dwEndDate);
|
|
break;
|
|
case xtpMAPIRcEnd_Number:
|
|
rpEnd.m_nUseEnd = xtpCalendarPatternEndAfterOccurrences;
|
|
rpEnd.m_nEndAfterOccurrences = RCData.dwOccurrences;
|
|
break;
|
|
case xtpMAPIRcEnd_Never:
|
|
rpEnd.m_nUseEnd = xtpCalendarPatternEndNoDate;
|
|
break;
|
|
default: // Use no end date by default
|
|
rpEnd.m_nUseEnd = xtpCalendarPatternEndNoDate;
|
|
}
|
|
pPattern->SetPatternEnd(rpEnd);
|
|
|
|
COleDateTime dtOccStartTime;
|
|
dtOccStartTime.SetTime(RCData.dwOccStartTime / 60, RCData.dwOccStartTime % 60, 0);
|
|
|
|
pPattern->SetStartTime(dtOccStartTime);
|
|
|
|
int nDuration = RCData.dwOccEndTime - RCData.dwOccStartTime;
|
|
ASSERT(nDuration >= 0);
|
|
pPattern->SetDurationMinutes(nDuration);
|
|
}
|
|
|
|
void CXTPCalendarMAPI_Recurrence::SetRecurrenceExceptions(
|
|
CXTPCalendarEvent* pMasterEvent,
|
|
CXTPCalendarRecurrencePattern* pPattern,
|
|
const CXTPRcData& RCData)
|
|
{
|
|
if (!pMasterEvent || !pPattern)
|
|
{
|
|
ASSERT(FALSE);
|
|
return;
|
|
}
|
|
|
|
int nCount = (int)RCData.arExceptions.GetSize();
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
const CXTPRcException& RCExc = RCData.arExceptions[i];
|
|
|
|
COleDateTime dtOrigStart = ConvertRecurrenceMinutesToDate(RCExc.dwOrigStart);
|
|
|
|
COleDateTime dtOrigEnd = dtOrigStart + pPattern->GetDuration();
|
|
|
|
CXTPCalendarEventPtr ptrExc = pMasterEvent->CloneForOccurrence(dtOrigStart, dtOrigEnd);
|
|
if (!ptrExc)
|
|
{
|
|
return;
|
|
}
|
|
VERIFY( ptrExc->MakeAsRException() );
|
|
|
|
if (RCExc.bDeleted)
|
|
{
|
|
ptrExc->SetRExceptionDeleted(TRUE);
|
|
VERIFY( pPattern->SetException(ptrExc) );
|
|
continue;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
COleDateTime dtNewStart = dtOrigStart;
|
|
COleDateTime dtNewEnd = dtOrigEnd;
|
|
|
|
if (RCExc.dwNewStart)
|
|
{
|
|
dtNewStart = ConvertRecurrenceMinutesToDate(RCExc.dwNewStart);
|
|
}
|
|
if (RCExc.dwNewEnd)
|
|
{
|
|
dtNewEnd = ConvertRecurrenceMinutesToDate(RCExc.dwNewEnd);
|
|
}
|
|
|
|
ptrExc->SetStartTime(dtNewStart);
|
|
ptrExc->SetEndTime(dtNewEnd);
|
|
|
|
//---------------------------------------------------------------
|
|
if (RCExc.wFlags & xtpMAPIRcED_Subject)
|
|
{
|
|
ptrExc->SetSubject(RCExc.strSubject);
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_IsMeeting)
|
|
{
|
|
ptrExc->SetMeeting(RCExc.bIsMeeting);
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_ReminderTime)
|
|
{
|
|
ptrExc->SetReminderMinutesBeforeStart(RCExc.nReminderTime);
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_IsReminder)
|
|
{
|
|
ptrExc->SetReminder(RCExc.bIsReminder);
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_Location)
|
|
{
|
|
ptrExc->SetLocation(RCExc.strLocation);
|
|
}
|
|
if (RCExc.wFlags & xtpMAPIRcED_BusyStatus)
|
|
{
|
|
ASSERT(RCExc.nBusyStatus < 4);
|
|
if (RCExc.nBusyStatus >= 0 && RCExc.nBusyStatus < 4)
|
|
{
|
|
ptrExc->SetBusyStatus(RCExc.nBusyStatus);
|
|
}
|
|
}
|
|
|
|
ASSERT((RCExc.wFlags & xtpMAPIRcED_Reserved) == 0);
|
|
|
|
if (RCExc.wFlags & xtpMAPIRcED_IsAllDay)
|
|
{
|
|
ptrExc->SetAllDayEvent(RCExc.bIsAllDay);
|
|
}
|
|
|
|
if (RCExc.wFlags & xtpMAPIRcED_Label)
|
|
{
|
|
ptrExc->SetLabelID(RCExc.nLabel);
|
|
}
|
|
|
|
VERIFY( pPattern->SetException(ptrExc) );
|
|
}
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPI_Recurrence::FillRCData(CXTPRcData& rRCData,
|
|
CXTPCalendarRecurrencePattern* pPattern,
|
|
CXTPCalendarEvent* pMaster)
|
|
{
|
|
// FileTime zero date
|
|
static const COleDateTime cdtFTZero(1601, 1, 1, 0, 0, 0);
|
|
|
|
if (!pPattern || !pMaster)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
XTP_CALENDAR_RECURRENCE_OPTIONS opt = pPattern->GetRecurrenceOptions();
|
|
|
|
switch (opt.m_nRecurrenceType)
|
|
{
|
|
case xtpCalendarRecurrenceDaily:
|
|
{
|
|
rRCData.wType = xtpMAPIRcType_Daily;
|
|
|
|
if (opt.m_Daily.bEveryWeekDayOnly)
|
|
{
|
|
rRCData.ucType2 = xtpMAPIRcType2_Weekly;
|
|
rRCData.dwInterval = 1;
|
|
rRCData.dwWeekDayMask = xtpCalendarDayMo_Fr;
|
|
}
|
|
else
|
|
{
|
|
rRCData.ucType2 = xtpMAPIRcType2_Daily;
|
|
rRCData.dwInterval = opt.m_Daily.nIntervalDays * 24 * 60;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case xtpCalendarRecurrenceWeekly:
|
|
{
|
|
rRCData.wType = xtpMAPIRcType_Weekly;
|
|
rRCData.ucType2 = xtpMAPIRcType2_Weekly; // = 1, 0 only for tasks
|
|
|
|
rRCData.dwInterval = opt.m_Weekly.nIntervalWeeks;
|
|
rRCData.dwWeekDayMask = opt.m_Weekly.nDayOfWeekMask;
|
|
}
|
|
break;
|
|
|
|
case xtpCalendarRecurrenceMonthly:
|
|
{
|
|
rRCData.wType = xtpMAPIRcType_Monthly;
|
|
rRCData.ucType2 = xtpMAPIRcType2_MonYearly;
|
|
|
|
rRCData.dwInterval = (DWORD)opt.m_Monthly.nIntervalMonths;
|
|
rRCData.ucInstance = (BYTE)opt.m_Monthly.nDayOfMonth;
|
|
}
|
|
break;
|
|
|
|
case xtpCalendarRecurrenceMonthNth:
|
|
{
|
|
rRCData.wType = xtpMAPIRcType_Monthly;
|
|
rRCData.ucType2 = xtpMAPIRcType2_MonYearly_Nth;
|
|
|
|
rRCData.dwInterval = (DWORD)opt.m_MonthNth.nIntervalMonths;
|
|
rRCData.ucInstance = (BYTE)opt.m_MonthNth.nWhichDay;
|
|
rRCData.dwWeekDayMask = (DWORD)opt.m_MonthNth.nWhichDayMask;
|
|
}
|
|
break;
|
|
|
|
case xtpCalendarRecurrenceYearly:
|
|
{
|
|
rRCData.wType = xtpMAPIRcType_Yearly;
|
|
rRCData.ucType2 = xtpMAPIRcType2_MonYearly;
|
|
|
|
rRCData.ucInstance = (BYTE)opt.m_Yearly.nDayOfMonth;
|
|
|
|
rRCData.dwInterval = 12;
|
|
}
|
|
break;
|
|
|
|
case xtpCalendarRecurrenceYearNth:
|
|
{
|
|
rRCData.wType = xtpMAPIRcType_Yearly;
|
|
rRCData.ucType2 = xtpMAPIRcType2_MonYearly_Nth;
|
|
|
|
rRCData.ucInstance = (BYTE)opt.m_YearNth.nWhichDay;
|
|
rRCData.dwWeekDayMask = (DWORD)opt.m_YearNth.nWhichDayMask;
|
|
|
|
rRCData.dwInterval = 12;
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
rRCData.dwRCShiftX = _CalcRCShiftX(pPattern);
|
|
|
|
rRCData.dwStartDate = ConvertRecurrenceDateToMinutes(pPattern->GetPatternStartDate());
|
|
|
|
CXTPCalendarDatesArray arOccDates;
|
|
XTP_CALENDAR_PATTERN_END rpEnd = pPattern->GetPatternEnd();
|
|
switch (rpEnd.m_nUseEnd)
|
|
{
|
|
case xtpCalendarPatternEndDate:
|
|
rRCData.dwEndByType = xtpMAPIRcEnd_Date;
|
|
rRCData.dwEndDate = ConvertRecurrenceDateToMinutes(rpEnd.m_dtPatternEndDate);
|
|
pPattern->GetOccurrencesDates(arOccDates, pPattern->GetPatternStartDate(), pPattern->GetPatternEndDate());
|
|
rRCData.dwOccurrences = (DWORD)arOccDates.GetSize();
|
|
break;
|
|
case xtpCalendarPatternEndAfterOccurrences:
|
|
rRCData.dwEndByType = xtpMAPIRcEnd_Number;
|
|
rRCData.dwOccurrences = rpEnd.m_nEndAfterOccurrences;
|
|
rRCData.dwEndDate = ConvertRecurrenceDateToMinutes(pMaster->GetEndTime());
|
|
break;
|
|
case xtpCalendarPatternEndNoDate:
|
|
rRCData.dwEndByType = xtpMAPIRcEnd_Never;
|
|
break;
|
|
default: // Use No end date by default
|
|
rRCData.dwEndByType = xtpMAPIRcEnd_Never;
|
|
}
|
|
|
|
COleDateTime dtOccStartTime = pPattern->GetStartTime();
|
|
rRCData.dwOccStartTime = dtOccStartTime.GetHour() * 60 + dtOccStartTime.GetMinute();
|
|
|
|
int nOccDuration = pPattern->GetDurationMinutes();
|
|
if (pMaster->IsAllDayEvent() && ( (nOccDuration % (24 * 60)) || nOccDuration == 0) )
|
|
{
|
|
// align occurrence duration for full day(s) duration
|
|
nOccDuration = (nOccDuration / (24 * 60) + 1) * 24 * 60;
|
|
}
|
|
rRCData.dwOccEndTime = rRCData.dwOccStartTime + nOccDuration;
|
|
|
|
//------------------------------------------
|
|
CXTPCalendarEventsPtr ptrExcAr = pPattern->GetExceptions();
|
|
int nExcCount = ptrExcAr ? ptrExcAr->GetCount() : 0;
|
|
for (int i = 0; i < nExcCount; i++)
|
|
{
|
|
CXTPCalendarEvent* pExc = ptrExcAr->GetAt(i);
|
|
|
|
CXTPRcException rceTmp;
|
|
rceTmp.Set(pExc, pMaster);
|
|
|
|
rRCData.arExceptions.Add(rceTmp);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPI_Recurrence::RCDataToBin(CXTPRcData& RCData, CByteArray& rarData)
|
|
{
|
|
XTP_RCDATA_LAYOUT RCLayout;
|
|
::ZeroMemory(&RCLayout, sizeof(RCLayout));
|
|
|
|
ASSERT(RCData.ucType2 <= 3);
|
|
if (RCData.ucType2 > 3)
|
|
{
|
|
return FALSE;
|
|
}
|
|
// select layout
|
|
RCLayout = s_arRCDataLayout[RCData.ucType2];
|
|
|
|
rarData.SetSize(RCLayout.nDynData, 4096);
|
|
|
|
// Set header
|
|
xtpSetDataT<DWORD>(rarData, 0, 0x30043004);
|
|
|
|
// Set generic recurrence fields
|
|
xtpSetDataT<WORD> (rarData, RCLayout.nType, RCData.wType);
|
|
xtpSetDataT<BYTE> (rarData, RCLayout.nType2, RCData.ucType2);
|
|
xtpSetDataT<DWORD>(rarData, RCLayout.nRCShiftX, RCData.dwRCShiftX);
|
|
xtpSetDataT<DWORD>(rarData, RCLayout.nInterval, RCData.dwInterval);
|
|
xtpSetDataT<DWORD>(rarData, RCLayout.nWeekDayMask, RCData.dwWeekDayMask);
|
|
xtpSetDataT<BYTE> (rarData, RCLayout.nInstance, RCData.ucInstance);
|
|
xtpSetDataT<DWORD>(rarData, RCLayout.nEndByType, RCData.dwEndByType);
|
|
xtpSetDataT<DWORD>(rarData, RCLayout.nOccurrences, RCData.dwOccurrences);
|
|
|
|
// Add information about exceptions
|
|
//
|
|
ASSERT(rarData.GetSize() == RCLayout.nDynData);
|
|
|
|
int i = 0;
|
|
|
|
//- add ALL exceptions dates -----------------------------------------
|
|
RCData.arExceptions.SortByOrigStart();
|
|
|
|
int nExcCount = (int)RCData.arExceptions.GetSize();
|
|
xtpAddDataT<DWORD>(rarData, nExcCount);
|
|
for (i = 0; i < nExcCount; i++)
|
|
{
|
|
const CXTPRcException& rce = RCData.arExceptions[i];
|
|
DWORD dwOrigSartDate = (rce.dwOrigStart / 24 / 60) * 24 * 60;
|
|
xtpAddDataT<DWORD>(rarData, dwOrigSartDate);
|
|
}
|
|
|
|
//- add changed exception dates -----------------------------------------
|
|
RCData.arExceptions.SortByNewStart();
|
|
|
|
int nChangExcCountOffset = (int)rarData.GetSize();
|
|
xtpAddDataT<DWORD>(rarData, 0);
|
|
DWORD dwChangExcCount = 0;
|
|
|
|
for (i = 0; i < nExcCount; i++)
|
|
{
|
|
const CXTPRcException& rce = RCData.arExceptions[i];
|
|
if (!rce.bDeleted)
|
|
{
|
|
ASSERT(rce.dwNewStart != 0 && rce.dwNewEnd != 0);
|
|
DWORD dwNewSartDate = (rce.dwNewStart / 24 / 60) * 24 * 60;
|
|
xtpAddDataT<DWORD>(rarData, dwNewSartDate);
|
|
dwChangExcCount++;
|
|
}
|
|
}
|
|
xtpSetDataT<DWORD>(rarData, nChangExcCountOffset, dwChangExcCount);
|
|
|
|
// start/end date
|
|
xtpAddDataT<DWORD>(rarData, RCData.dwStartDate);
|
|
|
|
if (RCData.dwEndByType == xtpMAPIRcEnd_Date || RCData.dwEndByType == xtpMAPIRcEnd_Number)
|
|
{
|
|
xtpAddDataT<DWORD>(rarData, RCData.dwEndDate);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(RCData.dwEndByType == xtpMAPIRcEnd_Never);
|
|
xtpAddDataT<DWORD>(rarData, 0x5AE980DF);
|
|
}
|
|
|
|
// unknown
|
|
xtpAddDataT<DWORD>(rarData, 0x00003006);
|
|
xtpAddDataT<DWORD>(rarData, 0x00003006);
|
|
|
|
// start/end time
|
|
xtpAddDataT<DWORD>(rarData, RCData.dwOccStartTime);
|
|
xtpAddDataT<DWORD>(rarData, RCData.dwOccEndTime);
|
|
|
|
// detailed exceptions
|
|
xtpAddDataT<WORD>(rarData, (WORD)dwChangExcCount);
|
|
|
|
for (i = 0; i < nExcCount; i++)
|
|
{
|
|
const CXTPRcException& rce = RCData.arExceptions[i];
|
|
if (rce.bDeleted)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ASSERT(rce.dwNewStart && rce.dwNewEnd && rce.dwOrigStart);
|
|
|
|
xtpAddDataT<DWORD>(rarData, rce.dwNewStart);
|
|
xtpAddDataT<DWORD>(rarData, rce.dwNewEnd);
|
|
xtpAddDataT<DWORD>(rarData, rce.dwOrigStart);
|
|
|
|
xtpAddDataT<WORD>(rarData, rce.wFlags);
|
|
|
|
if (rce.wFlags & xtpMAPIRcED_Subject)
|
|
{
|
|
xtpAddData_MapiExcStr8(rarData, rce.strSubject);
|
|
}
|
|
if (rce.wFlags & xtpMAPIRcED_IsMeeting)
|
|
{
|
|
// layout: [dw] - bool(0|1)
|
|
xtpAddDataT<DWORD>(rarData, rce.bIsMeeting);
|
|
}
|
|
if (rce.wFlags & xtpMAPIRcED_ReminderTime)
|
|
{
|
|
// layout: [dw] minutes before start
|
|
xtpAddDataT<DWORD>(rarData, rce.nReminderTime);
|
|
}
|
|
if (rce.wFlags & xtpMAPIRcED_IsReminder)
|
|
{
|
|
// layout: [dw] - bool(0|1)
|
|
xtpAddDataT<DWORD>(rarData, rce.bIsReminder);
|
|
}
|
|
if (rce.wFlags & xtpMAPIRcED_Location)
|
|
{
|
|
xtpAddData_MapiExcStr8(rarData, rce.strLocation);
|
|
}
|
|
if (rce.wFlags & xtpMAPIRcED_BusyStatus)
|
|
{
|
|
// layout: [dw] - busy status [0..3] = XTPCalendarEventBusyStatus
|
|
xtpAddDataT<DWORD>(rarData, rce.nBusyStatus);
|
|
}
|
|
if (rce.wFlags & xtpMAPIRcED_IsAllDay)
|
|
{
|
|
// layout: [dw] - bool(0|1)
|
|
xtpAddDataT<DWORD>(rarData, rce.bIsAllDay);
|
|
}
|
|
if (rce.wFlags & xtpMAPIRcED_Label)
|
|
{
|
|
// layout: [dw] -
|
|
xtpAddDataT<DWORD>(rarData, rce.nLabel);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
DWORD CXTPCalendarMAPI_Recurrence::_CalcRCShiftX(CXTPCalendarRecurrencePattern* pPattern)
|
|
{
|
|
// FileTime zero date
|
|
static const COleDateTime cdtFTZero(1601, 1, 1, 0, 0, 0);
|
|
|
|
ASSERT(pPattern);
|
|
if (!pPattern)
|
|
{
|
|
return 0;
|
|
}
|
|
DWORD dwRCShiftX = 0;
|
|
|
|
COleDateTime dtPatternStart = pPattern->GetPatternStartDate();
|
|
COleDateTimeSpan spX;
|
|
|
|
XTP_CALENDAR_RECURRENCE_OPTIONS opt = pPattern->GetRecurrenceOptions();
|
|
|
|
// xtpMAPIRcType2_Daily
|
|
if (opt.m_nRecurrenceType == xtpCalendarRecurrenceDaily && !opt.m_Daily.bEveryWeekDayOnly)
|
|
{
|
|
|
|
spX = dtPatternStart - cdtFTZero;
|
|
int nIntervalDays = max(1, opt.m_Daily.nIntervalDays);
|
|
int nDay = (int)CXTPCalendarUtils::GetTotalDays(spX);
|
|
|
|
dwRCShiftX = nDay % nIntervalDays;
|
|
dwRCShiftX *= 24 * 60; // convert to minutes
|
|
}
|
|
// xtpMAPIRcType2_Weekly
|
|
else if (opt.m_nRecurrenceType == xtpCalendarRecurrenceDaily && opt.m_Daily.bEveryWeekDayOnly ||
|
|
opt.m_nRecurrenceType == xtpCalendarRecurrenceWeekly)
|
|
{
|
|
int nIntervalWeeks = 1;
|
|
if (opt.m_nRecurrenceType == xtpCalendarRecurrenceWeekly)
|
|
{
|
|
nIntervalWeeks = opt.m_Weekly.nIntervalWeeks;
|
|
}
|
|
|
|
spX = dtPatternStart - cdtFTZero;
|
|
int nWeek = ((int)(CXTPCalendarUtils::GetTotalDays(spX) + 1)) / 7;
|
|
|
|
dwRCShiftX = (nWeek * 7 - 1) % (nIntervalWeeks * 7);
|
|
dwRCShiftX *= 24 * 60; // convert to minutes
|
|
}
|
|
else
|
|
{
|
|
//xtpMAPIRcType2_MonYearly
|
|
//xtpMAPIRcType2_MonYearly_Nth
|
|
|
|
int nIntervalMonths = -1;
|
|
|
|
if (opt.m_nRecurrenceType == xtpCalendarRecurrenceMonthly)
|
|
{
|
|
nIntervalMonths = opt.m_Monthly.nIntervalMonths;
|
|
}
|
|
else if (opt.m_nRecurrenceType == xtpCalendarRecurrenceMonthNth)
|
|
{
|
|
nIntervalMonths = opt.m_MonthNth.nIntervalMonths;
|
|
}
|
|
else if (opt.m_nRecurrenceType == xtpCalendarRecurrenceYearly ||
|
|
opt.m_nRecurrenceType == xtpCalendarRecurrenceYearNth)
|
|
{
|
|
nIntervalMonths = 12;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
nIntervalMonths = max(1, nIntervalMonths);
|
|
|
|
// days per month - jan feb mar apr may jun jul aug sep oct nov dec
|
|
static int arDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
int nMonth = dtPatternStart.GetMonth() + 12 * (dtPatternStart.GetYear() - 1601);
|
|
|
|
for (int i = 1 ; i < ((nMonth - 1) % nIntervalMonths) + 1; i++ )
|
|
{
|
|
dwRCShiftX += arDays[(i - 1) % 12];
|
|
}
|
|
dwRCShiftX *= 24 * 60; // convert to minutes
|
|
}
|
|
|
|
return dwRCShiftX;
|
|
}
|
|
|
|
COleDateTime CXTPCalendarMAPI_Recurrence::ConvertRecurrenceMinutesToDate(DWORD dwMinutes)
|
|
{
|
|
COleDateTime dt = (DATE)0;
|
|
|
|
ULONGLONG ullDT = (ULONGLONG) dwMinutes * 60i64 * cFileTimeUnitsPerSecond;
|
|
FILETIME ft = *((FILETIME*)&ullDT); // { (DWORD) ( fileTimeUnitsBeforeStart & 0xFFFFFFFF), (DWORD) ( fileTimeUnitsBeforeStart >> 32)};
|
|
|
|
SYSTEMTIME st;
|
|
BOOL bRes = ::FileTimeToSystemTime(&ft, &st);
|
|
ASSERT(bRes);
|
|
if (bRes)
|
|
{
|
|
dt = st;
|
|
}
|
|
// TRACE(_T("MAPItime to DT %d = %s\n"), dwMinutes, dt.Format());
|
|
|
|
return dt;
|
|
}
|
|
|
|
DWORD CXTPCalendarMAPI_Recurrence::ConvertRecurrenceDateToMinutes(COleDateTime dt)
|
|
{
|
|
SYSTEMTIME st;
|
|
FILETIME ft = {0, 0};
|
|
|
|
if (!CXTPCalendarUtils::GetAsSystemTime(dt, st))
|
|
{
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
if (!SystemTimeToFileTime(&st, &ft))
|
|
{
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
ULONGLONG ullMinutes = *((ULONGLONG*)&ft); //( ( (ULONGLONG) ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
|
ullMinutes = ullMinutes / 60i64;
|
|
ullMinutes = ullMinutes / cFileTimeUnitsPerSecond;
|
|
return (DWORD)ullMinutes;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// see KB239795
|
|
|
|
STDMETHODIMP CXTPCalendarMAPIDataProvider::OpenInbox(
|
|
LPMDB lpMDB, LPMAPIFOLDER *lpInboxFolder, LPMAPIFOLDER *lpCalendarFolder, CXTPCalendarMAPIDataProvider* pProvider)
|
|
{
|
|
if (!lpMDB || !pProvider)
|
|
return E_POINTER;
|
|
|
|
ULONG cbInbox;
|
|
LPENTRYID lpbInbox;
|
|
ULONG ulObjType;
|
|
HRESULT hRes = S_OK;
|
|
LPMAPIFOLDER lpTempFolder = NULL;
|
|
|
|
ULONG pCount; SPropValue *props;
|
|
SizedSPropTagArray(1, spec) = {1, {XTP_TAG_ID_MAPI_CALENDAR_FOLDER}};
|
|
|
|
*lpInboxFolder = NULL;
|
|
*lpCalendarFolder = NULL;
|
|
|
|
// The Inbox is usually the default receive folder for the message store
|
|
// You call this function as a shortcut to get it's Entry ID
|
|
hRes = lpMDB->GetReceiveFolder(
|
|
NULL, // Get default receive folder
|
|
NULL, // Flags
|
|
&cbInbox, // Size and ...
|
|
&lpbInbox, // Value of the EntryID to be returned
|
|
NULL); // You don't care to see the class returned
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = lpMDB->OpenEntry(
|
|
cbInbox, // Size and...
|
|
lpbInbox, // Value of the Inbox's EntryID
|
|
NULL, // We want the default interface (IMAPIFolder)
|
|
MAPI_BEST_ACCESS, // Flags
|
|
&ulObjType, // Object returned type
|
|
(LPUNKNOWN *) &lpTempFolder); // Returned folder
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
// Assign the out parameter
|
|
*lpInboxFolder = lpTempFolder;
|
|
|
|
// Open Calendar Folder
|
|
hRes = (*lpInboxFolder)->GetProps((SPropTagArray*)&spec, 0, &pCount, &props);
|
|
|
|
if (hRes == S_OK || hRes == MAPI_W_ERRORS_RETURNED)
|
|
{
|
|
if (props[0].ulPropTag != PT_ERROR)
|
|
{
|
|
hRes = lpMDB->OpenEntry(
|
|
props[0].Value.bin.cb, // Size and...
|
|
(ENTRYID*)props[0].Value.bin.lpb, // Value of the Calendar's EntryID
|
|
NULL, // We want the default interface (IMAPIFolder)
|
|
MAPI_BEST_ACCESS, // Flags
|
|
&ulObjType, // Object returned type
|
|
(LPUNKNOWN *) &lpTempFolder); // Returned folder
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
// Assign the out parameter
|
|
*lpCalendarFolder = lpTempFolder;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (props)
|
|
{
|
|
pProvider->MAPIFreeBuffer(props);
|
|
props = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cleanup
|
|
pProvider->MAPIFreeBuffer(lpbInbox);
|
|
return hRes;
|
|
}
|
|
|
|
STDMETHODIMP CXTPCalendarMAPIDataProvider::OpenDefaultMessageStore(
|
|
LPMAPISESSION lpMAPISession, LPMDB * lpMDB, CXTPCalendarMAPIDataProvider* pProvider)
|
|
{
|
|
if (!lpMAPISession || !pProvider)
|
|
return E_POINTER;
|
|
|
|
LPMAPITABLE pStoresTbl = NULL;
|
|
LPSRowSet pRow = NULL;
|
|
static SRestriction sres;
|
|
SPropValue spv;
|
|
HRESULT hRes;
|
|
LPMDB lpTempMDB = NULL;
|
|
|
|
enum {EID, NAME, NUM_COLS};
|
|
static SizedSPropTagArray(NUM_COLS,sptCols) = {NUM_COLS, PR_ENTRYID, PR_DISPLAY_NAME};
|
|
|
|
*lpMDB = NULL;
|
|
|
|
//Get the table of all the message stores available
|
|
hRes = lpMAPISession->GetMsgStoresTable(0, &pStoresTbl);
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
//Set up restriction for the default store
|
|
sres.rt = RES_PROPERTY; //Comparing a property
|
|
sres.res.resProperty.relop = RELOP_EQ; //Testing equality
|
|
sres.res.resProperty.ulPropTag = PR_DEFAULT_STORE; //Tag to compare
|
|
sres.res.resProperty.lpProp = &spv; //Prop tag and value to compare against
|
|
|
|
spv.ulPropTag = PR_DEFAULT_STORE; //Tag type
|
|
spv.Value.b = TRUE; //Tag value
|
|
|
|
//Convert the table to an array which can be stepped through
|
|
//Only one message store should have PR_DEFAULT_STORE set to true, so only one will be returned
|
|
hRes = pProvider->HrQueryAllRows(
|
|
pStoresTbl, //Table to query
|
|
(LPSPropTagArray) &sptCols, //Which columns to get
|
|
&sres, //Restriction to use
|
|
NULL, //No sort order
|
|
0, //Max number of rows (0 means no limit)
|
|
&pRow); //Array to return
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
//Open the first returned (default) message store
|
|
hRes = lpMAPISession->OpenMsgStore(
|
|
NULL,//Window handle for dialogs
|
|
pRow->aRow[0].lpProps[EID].Value.bin.cb,//size and...
|
|
(LPENTRYID)pRow->aRow[0].lpProps[EID].Value.bin.lpb,//value of entry to open
|
|
NULL,//Use default interface (IMsgStore) to open store
|
|
MAPI_BEST_ACCESS,//Flags
|
|
&lpTempMDB);//Pointer to place the store in
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
//Assign the out parameter
|
|
*lpMDB = lpTempMDB;
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean up
|
|
pProvider->FreeProws(pRow);
|
|
MAPI_RELEASE(pProvider, pStoresTbl);
|
|
if (FAILED(hRes))
|
|
{
|
|
LPMAPIERROR lpError;
|
|
HRESULT hr = lpMAPISession->GetLastError(hRes, 0, &lpError);
|
|
if (SUCCEEDED(hr) && lpError)
|
|
{
|
|
TRACE(_T("%s\n%s\n"), lpError->lpszError, lpError->lpszComponent);
|
|
pProvider->MAPIFreeBuffer(lpError);
|
|
}
|
|
}
|
|
return hRes;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CXTPCalendarMAPIDataProvider::CXTPCalendarMemDPInternal::CXTPCalendarMemDPInternal(CXTPCalendarData* pDPExternal)
|
|
{
|
|
ASSERT(pDPExternal);
|
|
m_pDPExternal = pDPExternal;
|
|
}
|
|
|
|
void CXTPCalendarMAPIDataProvider::CXTPCalendarMemDPInternal::SendNotification(XTP_NOTIFY_CODE EventCode, WPARAM wParam , LPARAM lParam)
|
|
{
|
|
class CXTPCalendarDataSnNf : public CXTPCalendarData
|
|
{
|
|
public:
|
|
using CXTPCalendarData::SendNotification;
|
|
};
|
|
//===================================
|
|
if (m_bDisableNotificationsSending)
|
|
{
|
|
return;
|
|
}
|
|
if (m_pDPExternal)
|
|
{
|
|
((CXTPCalendarDataSnNf*)m_pDPExternal)->SendNotification(EventCode, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
CXTPCalendarData::SendNotification(EventCode, wParam, lParam);
|
|
}
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CXTPCalendarMAPIDataProvider::CXTPCalendarMAPIDataProvider()
|
|
{
|
|
m_MapiHelper.m_pProvider = this;
|
|
|
|
m_typeProvider = xtpCalendarDataProviderMAPI;
|
|
|
|
m_bMAPIInitialized = FALSE;
|
|
m_lpMAPISession = NULL;
|
|
m_lpMDB = NULL;
|
|
m_lpCalendarFolder = NULL;
|
|
|
|
m_ulMAPIConID0 = 0;
|
|
m_ulMAPIConID1 = 0;
|
|
|
|
m_lpAdviseSink = NULL;
|
|
m_lpAdviseSink_ThrSafe = NULL;
|
|
|
|
//m_pMemDP = new CXTPCalendarMemoryDataProvider();
|
|
m_pMemDP = new CXTPCalendarMemDPInternal(this);
|
|
|
|
}
|
|
|
|
CXTPCalendarMAPIDataProvider::~CXTPCalendarMAPIDataProvider()
|
|
{
|
|
CMDTARGET_RELEASE(m_pMemDP);
|
|
}
|
|
|
|
CXTPCalendarEventsPtr CXTPCalendarMAPIDataProvider::DoRetrieveDayEvents(COleDateTime dtDay)
|
|
{
|
|
return m_pMemDP ? m_pMemDP->RetrieveDayEvents(dtDay) : NULL;
|
|
}
|
|
|
|
void CXTPCalendarMAPIDataProvider::DoRemoveAllEvents()
|
|
{
|
|
if (m_pMemDP)
|
|
{
|
|
m_pMemDP->RemoveAllEvents();
|
|
}
|
|
}
|
|
|
|
CXTPCalendarEventPtr CXTPCalendarMAPIDataProvider::DoRead_Event(DWORD dwEventID)
|
|
{
|
|
return m_pMemDP ? m_pMemDP->GetEvent(dwEventID) : NULL;
|
|
}
|
|
|
|
CXTPCalendarRecurrencePatternPtr CXTPCalendarMAPIDataProvider::DoRead_RPattern(DWORD dwPatternID)
|
|
{
|
|
return m_pMemDP ? m_pMemDP->GetRecurrencePattern(dwPatternID) : NULL;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::DoCreate_Event(CXTPCalendarEvent* pEvent, DWORD& rdwNewEventID)
|
|
{
|
|
CXTPAutoResetValue<BOOL> autoReset(m_bDisableNotificationsSending, FALSE);
|
|
m_bDisableNotificationsSending = TRUE;
|
|
|
|
if (!IsOpen())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!m_lpCalendarFolder || !m_pMemDP || !pEvent)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
DWORD dwEventID = pEvent->GetEventID();
|
|
|
|
int nRState = pEvent->GetRecurrenceState();
|
|
|
|
if (nRState != xtpCalendarRecurrenceNotRecurring &&
|
|
nRState != xtpCalendarRecurrenceMaster)
|
|
{
|
|
ASSERT(nRState == xtpCalendarRecurrenceException);
|
|
rdwNewEventID = GetNextUniqueEventID(dwEventID);
|
|
return TRUE;
|
|
}
|
|
|
|
LPMESSAGE pMessage = NULL;
|
|
HRESULT hr = m_lpCalendarFolder->CreateMessage(NULL, 0, &pMessage);
|
|
if (FAILED(hr) || !pMessage)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!UpdateMAPIEvent(pMessage, pEvent))
|
|
{
|
|
MAPI_RELEASE(this, pMessage);
|
|
return FALSE;
|
|
}
|
|
|
|
// to ensure that PR_SEARCH_KEY property is valid
|
|
hr = pMessage->SaveChanges(KEEP_OPEN_READONLY);
|
|
if (FAILED(hr))
|
|
{
|
|
ASSERT(FALSE);
|
|
|
|
MAPI_RELEASE(this, pMessage);
|
|
return FALSE;
|
|
}
|
|
|
|
_SetEventRuntimeProps(pEvent->GetCustomProperties(), pMessage);
|
|
|
|
//-----------------------------------------------------------------------
|
|
CByteArray arSearchKey;
|
|
HRESULT hrID = _getPropVal(pMessage, PR_SEARCH_KEY, arSearchKey);
|
|
|
|
if (FAILED(hrID))
|
|
{
|
|
ASSERT(FALSE);
|
|
|
|
MAPI_RELEASE(this, pMessage);
|
|
return NULL;
|
|
}
|
|
|
|
rdwNewEventID = GetEventID((int)arSearchKey.GetSize(), (LPENTRYID)arSearchKey.GetData(), TRUE);
|
|
//-----------------------------------------------------------------------
|
|
pEvent->SetEventID(rdwNewEventID);
|
|
BOOL bRes = m_pMemDP->AddEvent(pEvent);
|
|
|
|
MAPI_RELEASE(this, pMessage);
|
|
|
|
return bRes;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::DoUpdate_Event(CXTPCalendarEvent* pEvent)
|
|
{
|
|
CXTPAutoResetValue<BOOL> autoReset(m_bDisableNotificationsSending, FALSE);
|
|
m_bDisableNotificationsSending = TRUE;
|
|
|
|
if (!IsOpen())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!m_lpCalendarFolder || !m_pMemDP || !pEvent)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
//=================================================
|
|
int nRState = pEvent->GetRecurrenceState();
|
|
|
|
if (nRState != xtpCalendarRecurrenceNotRecurring &&
|
|
nRState != xtpCalendarRecurrenceMaster)
|
|
{
|
|
ASSERT(nRState == xtpCalendarRecurrenceException);
|
|
return TRUE;
|
|
}
|
|
|
|
//=================================================
|
|
BOOL bRes = m_pMemDP->ChangeEvent(pEvent);
|
|
if (!bRes)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD dwEventID = pEvent->GetEventID();
|
|
CXTPMAPIBinary eKey;
|
|
|
|
if (!m_mapID.Lookup(dwEventID, eKey))
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
LPMESSAGE pMessage = NULL;
|
|
ULONG ulObjType = NULL;
|
|
|
|
// Get event ID by its SearchKey
|
|
CXTPMAPIBinary eid = GetEntryID(eKey);
|
|
|
|
// open event from Calendar Folder storage
|
|
HRESULT hr = m_lpCalendarFolder->OpenEntry(
|
|
eid.GetBinarySize(), (LPENTRYID)eid.GetBinaryData(),
|
|
NULL,//default interface
|
|
MAPI_BEST_ACCESS,
|
|
&ulObjType,
|
|
(LPUNKNOWN*)&pMessage);
|
|
|
|
ASSERT(ulObjType == 5);
|
|
ASSERT(pMessage);
|
|
if (FAILED(hr) || !pMessage)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!UpdateMAPIEvent(pMessage, pEvent))
|
|
{
|
|
MAPI_RELEASE(this, pMessage);
|
|
return FALSE;
|
|
}
|
|
|
|
hr = pMessage->SaveChanges(KEEP_OPEN_READONLY);
|
|
if (FAILED(hr))
|
|
{
|
|
ASSERT(FALSE);
|
|
|
|
MAPI_RELEASE(this, pMessage);
|
|
return FALSE;
|
|
}
|
|
|
|
MAPI_RELEASE(this, pMessage);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::DoDelete_Event(CXTPCalendarEvent* pEvent)
|
|
{
|
|
CXTPAutoResetValue<BOOL> autoReset(m_bDisableNotificationsSending, FALSE);
|
|
m_bDisableNotificationsSending = TRUE;
|
|
|
|
if (!IsOpen())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!m_lpCalendarFolder || !m_pMemDP || !pEvent)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
int nRState = pEvent->GetRecurrenceState();
|
|
|
|
if (nRState != xtpCalendarRecurrenceNotRecurring &&
|
|
nRState != xtpCalendarRecurrenceMaster)
|
|
{
|
|
ASSERT(nRState == xtpCalendarRecurrenceException);
|
|
return TRUE;
|
|
}
|
|
|
|
CXTPMAPIBinary eKey;
|
|
DWORD dwEventID = pEvent->GetEventID();
|
|
|
|
if (!m_mapID.Lookup(dwEventID, eKey))
|
|
{
|
|
// ASSERT(FALSE); // possible when copied appointments
|
|
return FALSE;
|
|
}
|
|
|
|
// get event ID by its SearchKey
|
|
CXTPMAPIBinary eid = GetEntryID(eKey);
|
|
|
|
// delete event
|
|
ENTRYLIST eidList1;
|
|
SBinary eidBinary;
|
|
|
|
eidList1.cValues = 1;
|
|
eidList1.lpbin = &eidBinary;
|
|
|
|
eidBinary.cb = eid.GetBinarySize();
|
|
eidBinary.lpb = (BYTE*)eid.GetBinaryData();
|
|
|
|
HRESULT hr = m_lpCalendarFolder->DeleteMessages(&eidList1, 0, NULL, 0);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
return m_pMemDP ? m_pMemDP->DeleteEvent(pEvent) : FALSE;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::DoCreate_RPattern(CXTPCalendarRecurrencePattern* pPattern, DWORD& rdwNewPatternID)
|
|
{
|
|
rdwNewPatternID = pPattern->GetPatternID();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::DoUpdate_RPattern(CXTPCalendarRecurrencePattern* pPattern)
|
|
{
|
|
UNREFERENCED_PARAMETER(pPattern);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::DoDelete_RPattern(CXTPCalendarRecurrencePattern* pPattern)
|
|
{
|
|
UNREFERENCED_PARAMETER(pPattern);
|
|
return TRUE;
|
|
}
|
|
|
|
CXTPCalendarEventsPtr CXTPCalendarMAPIDataProvider::DoGetUpcomingEvents(COleDateTime dtFrom, COleDateTimeSpan spPeriod)
|
|
{
|
|
UNREFERENCED_PARAMETER(dtFrom); UNREFERENCED_PARAMETER(spPeriod);
|
|
return DoGetAllEvents_raw();
|
|
}
|
|
|
|
|
|
CXTPCalendarEventsPtr CXTPCalendarMAPIDataProvider::DoGetAllEvents_raw()
|
|
{
|
|
return m_pMemDP ? m_pMemDP->GetAllEvents_raw() : NULL;
|
|
}
|
|
|
|
BOOL AFX_CDECL CXTPCalendarMAPIDataProvider::GetParameterValueFromConStr(LPCTSTR lpszConnectionString, LPCTSTR pcszParameterName, CString& rstrValue)
|
|
{
|
|
rstrValue.Empty();
|
|
|
|
ASSERT(lpszConnectionString && pcszParameterName);
|
|
|
|
if (!lpszConnectionString || !pcszParameterName ||
|
|
0 == _tcslen(lpszConnectionString) || 0 == _tcslen(pcszParameterName))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CString strConnStr_lower = lpszConnectionString;
|
|
strConnStr_lower.MakeLower();
|
|
|
|
CString strParameterName_lower = pcszParameterName;
|
|
strParameterName_lower.MakeLower();
|
|
|
|
int nIndex = strConnStr_lower.Find(strParameterName_lower + _T("="));
|
|
if (nIndex == -1)
|
|
nIndex = strConnStr_lower.Find(strParameterName_lower + _T(" ="));
|
|
|
|
if (nIndex == -1)
|
|
return FALSE;
|
|
|
|
int nParamNameLen = (int)_tcslen(pcszParameterName);
|
|
CString strParam = lpszConnectionString;
|
|
strParam = strParam.Mid(nIndex + nParamNameLen);
|
|
|
|
if (strParam[0] == _T(' '))
|
|
strParam.Delete(0);
|
|
if (strParam[0] == _T('='))
|
|
strParam.Delete(0);
|
|
|
|
if (strParam.IsEmpty())
|
|
return TRUE;
|
|
|
|
if (strParam[0] == _T('\'') || strParam[0] == _T('"'))
|
|
{
|
|
if (strParam.GetLength() <= 2)
|
|
return TRUE;
|
|
|
|
TCHAR chQuot = strParam[0];
|
|
|
|
strParam.Delete(0);
|
|
|
|
int nQuot2Idx = strParam.Find(chQuot, 0);
|
|
|
|
if (nQuot2Idx >= 0)
|
|
{
|
|
strParam.Delete(nQuot2Idx, strParam.GetLength() - nQuot2Idx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int nParamEndIdx = strParam.Find(_T(';'), 0);
|
|
if (nParamEndIdx >= 0)
|
|
{
|
|
strParam.Delete(nParamEndIdx, strParam.GetLength() - nParamEndIdx);
|
|
}
|
|
}
|
|
|
|
rstrValue = strParam;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CXTPCalendarMAPIDataProvider::GetMAPILogonParams(LPTSTR& rpszProfile, LPTSTR& rpszPassword, FLAGS& ruFlags)
|
|
{
|
|
rpszProfile = NULL;
|
|
rpszPassword = NULL;
|
|
ruFlags = MAPI_LOGON_UI; //Allow a profile picker box to show if not logged in
|
|
|
|
if (GetParameterValueFromConStr(m_strConnectionString, cszMAPIProfileName, m_strProfile_tmp))
|
|
rpszProfile = (LPTSTR)(LPCTSTR)m_strProfile_tmp;
|
|
|
|
if (GetParameterValueFromConStr(m_strConnectionString, cszMAPIPassword, m_strPassword_tmp))
|
|
rpszPassword = (LPTSTR)(LPCTSTR)m_strPassword_tmp;
|
|
|
|
CString strFlags;
|
|
|
|
if (GetParameterValueFromConStr(m_strConnectionString, cszMAPIFlags, strFlags))
|
|
{
|
|
DWORD dwFlags = 0;
|
|
SCANF_S(strFlags, _T("%x"), &dwFlags);
|
|
|
|
ruFlags = dwFlags;
|
|
}
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::Open()
|
|
{
|
|
if (m_pMemDP)
|
|
{
|
|
m_pMemDP->Open();
|
|
}
|
|
|
|
HRESULT hRes;
|
|
LPMAPIFOLDER lpInboxFolder = NULL;
|
|
LPSPropValue lpCalendarFolderEntryID = NULL;
|
|
|
|
hRes = this->MAPIInitialize(NULL);
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
|
|
LPTSTR pcszProfile;
|
|
LPTSTR pcszPassword;
|
|
FLAGS uFlags;
|
|
|
|
GetMAPILogonParams(pcszProfile, pcszPassword, uFlags);
|
|
|
|
m_bMAPIInitialized = TRUE;
|
|
|
|
hRes = this->MAPILogonEx(0, pcszProfile, pcszPassword, uFlags, &m_lpMAPISession);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = OpenDefaultMessageStore(m_lpMAPISession, &m_lpMDB, this);
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = OpenInbox(m_lpMDB, &lpInboxFolder, &m_lpCalendarFolder, this);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
//Checking to see that we did get the Calendar folder
|
|
hRes = this->HrGetOneProp(m_lpCalendarFolder, PR_ENTRYID,
|
|
&lpCalendarFolderEntryID);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
m_eidCalendarFolder.Set(lpCalendarFolderEntryID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
// copy all events to the cache data provider
|
|
if (m_pMemDP)
|
|
{
|
|
CXTPAutoResetValue<BOOL> autoReset(m_bDisableNotificationsSending, FALSE);
|
|
m_bDisableNotificationsSending = TRUE;
|
|
|
|
m_pMemDP->AddEvents(ImportAllEvents());
|
|
}
|
|
|
|
// advise to MAPI notifications
|
|
hRes = this->HrAllocAdviseSink(MAPICallBack_OnNotify, this, &m_lpAdviseSink);
|
|
ASSERT(SUCCEEDED(hRes) && m_lpAdviseSink);
|
|
|
|
hRes = this->HrThisThreadAdviseSink(m_lpAdviseSink, &m_lpAdviseSink_ThrSafe);
|
|
ASSERT(SUCCEEDED(hRes) && m_lpAdviseSink_ThrSafe);
|
|
|
|
if (SUCCEEDED(hRes) && m_lpAdviseSink_ThrSafe)
|
|
{
|
|
ULONG uEventsMask = fnevObjectCreated | fnevObjectDeleted | fnevObjectModified |
|
|
fnevObjectMoved; // | fnevObjectCopied;
|
|
|
|
ULONG uEIDsize = lpCalendarFolderEntryID->Value.bin.cb;
|
|
LPENTRYID pEIDdata = (LPENTRYID)lpCalendarFolderEntryID->Value.bin.lpb;
|
|
|
|
hRes = m_lpMDB->Advise(0, NULL, uEventsMask, m_lpAdviseSink_ThrSafe,
|
|
&m_ulMAPIConID0);
|
|
ASSERT(SUCCEEDED(hRes));
|
|
|
|
// to receive fnevObjectDeleted notification
|
|
hRes = m_lpMDB->Advise(uEIDsize, pEIDdata, uEventsMask,
|
|
m_lpAdviseSink_ThrSafe, &m_ulMAPIConID1);
|
|
ASSERT(SUCCEEDED(hRes));
|
|
|
|
// to force Advise call in the RPC.
|
|
ULONG nValues = 0;
|
|
LPSPropValue pPropArray;
|
|
hRes = m_lpMDB->GetProps(NULL, 0, &nValues, &pPropArray);
|
|
ASSERT(SUCCEEDED(hRes));
|
|
|
|
MAPI_FREEBUFFER(this, pPropArray);
|
|
}
|
|
}
|
|
|
|
MAPI_FREEBUFFER(this, lpCalendarFolderEntryID);
|
|
MAPI_RELEASE(this, lpInboxFolder);
|
|
|
|
if (FAILED(hRes))
|
|
{
|
|
// cleanup
|
|
m_bOpened = TRUE; // to let Close run.
|
|
Close();
|
|
}
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
CXTPCalendarData::Open();
|
|
}
|
|
|
|
return SUCCEEDED(hRes);
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::Create()
|
|
{
|
|
return Open();
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::Save()
|
|
{
|
|
CXTPCalendarData::Save();
|
|
return TRUE;
|
|
}
|
|
|
|
void CXTPCalendarMAPIDataProvider::Close()
|
|
{
|
|
if (!m_bOpened)
|
|
return;
|
|
|
|
if (m_pMemDP)
|
|
{
|
|
m_pMemDP->Close();
|
|
}
|
|
|
|
HRESULT hRes = 0;
|
|
|
|
// Unadvise -------------------------------------
|
|
if (m_ulMAPIConID0)
|
|
{
|
|
hRes = m_lpMDB->Unadvise(m_ulMAPIConID0);
|
|
ASSERT(SUCCEEDED(hRes));
|
|
m_ulMAPIConID0 = 0;
|
|
}
|
|
|
|
if (m_ulMAPIConID1)
|
|
{
|
|
hRes = m_lpMDB->Unadvise(m_ulMAPIConID1);
|
|
ASSERT(SUCCEEDED(hRes));
|
|
m_ulMAPIConID1 = 0;
|
|
}
|
|
|
|
// release opened objects -----------------------
|
|
MAPI_RELEASE(this, m_lpAdviseSink_ThrSafe);
|
|
MAPI_RELEASE(this, m_lpAdviseSink);
|
|
|
|
MAPI_RELEASE(this, m_lpCalendarFolder);
|
|
MAPI_RELEASE(this, m_lpMDB);
|
|
|
|
// LogOff session -------------------------------
|
|
if (m_lpMAPISession)
|
|
{
|
|
hRes = m_lpMAPISession->Logoff(0, 0, 0);
|
|
ASSERT(SUCCEEDED(hRes));
|
|
}
|
|
MAPI_RELEASE(this, m_lpMAPISession);
|
|
|
|
// Initialize MAPI dll --------------------------
|
|
if (m_bMAPIInitialized)
|
|
{
|
|
this->MAPIUninitialize();
|
|
m_bMAPIInitialized = FALSE;
|
|
}
|
|
|
|
CXTPCalendarData::Close();
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::IsOpen() const
|
|
{
|
|
return m_lpCalendarFolder != NULL;
|
|
}
|
|
|
|
LPSRestriction CXTPCalendarMAPIDataProvider::BuildBinaryRestriction(ULONG cbSize, LPBYTE lpData, ULONG ulPropTag)
|
|
{
|
|
static SRestriction sres;
|
|
static SPropValue spv;
|
|
ZeroMemory(&spv, sizeof(SPropValue));
|
|
// Set up restriction for the current day event
|
|
sres.rt = RES_PROPERTY; // Comparing a property
|
|
sres.res.resProperty.relop = RELOP_EQ; // Equal
|
|
sres.res.resProperty.ulPropTag = ulPropTag; // Entry ID
|
|
sres.res.resProperty.lpProp = &spv; // Prop tag and value to compare against
|
|
|
|
spv.ulPropTag = ulPropTag; // Tag type
|
|
spv.Value.bin.cb = cbSize;
|
|
spv.Value.bin.lpb = lpData;
|
|
|
|
return &sres;
|
|
}
|
|
|
|
void CXTPCalendarMAPIDataProvider::_SetEventRuntimeProps(CXTPCalendarCustomProperties* pEventProps, LPMESSAGE pMessage)
|
|
{
|
|
ASSERT(pEventProps && pMessage);
|
|
if (!pEventProps || !pMessage)
|
|
return;
|
|
|
|
CByteArray arEntryID, arSearchKey;
|
|
|
|
HRESULT hrID = _getPropVal(pMessage, PR_ENTRYID, arEntryID);
|
|
if (SUCCEEDED(hrID))
|
|
{
|
|
COleVariant varEntryID(arEntryID);
|
|
pEventProps->SetProperty(cszMAPIpropVal_EntryID, varEntryID);
|
|
}
|
|
|
|
hrID = _getPropVal(pMessage, PR_SEARCH_KEY, arSearchKey);
|
|
if (SUCCEEDED(hrID))
|
|
{
|
|
COleVariant varSearchKey(arSearchKey);
|
|
pEventProps->SetProperty(cszMAPIpropVal_SearchKey, varSearchKey);
|
|
}
|
|
}
|
|
|
|
void CXTPCalendarMAPIDataProvider::_MoveMAPIEventRuntimeProps(CXTPCalendarCustomProperties* pDest,
|
|
CXTPCalendarCustomProperties* pSrc)
|
|
{
|
|
ASSERT(pSrc && pDest);
|
|
if (!pSrc || !pDest)
|
|
return;
|
|
|
|
COleVariant varValue;
|
|
|
|
if (pDest && pSrc->GetProperty(cszMAPIpropVal_EntryID, varValue))
|
|
{
|
|
pDest->SetProperty(cszMAPIpropVal_EntryID, varValue);
|
|
}
|
|
pSrc->RemoveProperty(cszMAPIpropVal_EntryID);
|
|
|
|
if (pDest && pSrc->GetProperty(cszMAPIpropVal_SearchKey, varValue))
|
|
{
|
|
pDest->SetProperty(cszMAPIpropVal_SearchKey, varValue);
|
|
}
|
|
pSrc->RemoveProperty(cszMAPIpropVal_SearchKey);
|
|
}
|
|
|
|
CXTPCalendarEventPtr CXTPCalendarMAPIDataProvider::ImportEvent_FromCalendarFolderOnly(
|
|
ULONG cbEntryID, LPENTRYID lpEntryID)
|
|
{
|
|
LPSRestriction pRestriction = BuildBinaryRestriction(cbEntryID, (LPBYTE)lpEntryID, PR_ENTRYID);
|
|
CXTPCalendarEventsPtr ptrEvents = ImportAllEvents(pRestriction);
|
|
|
|
CXTPCalendarEventPtr ptrEvent;
|
|
if (ptrEvents && ptrEvents->GetCount())
|
|
{
|
|
ASSERT(ptrEvents->GetCount() == 1);
|
|
ptrEvent = ptrEvents->GetAt(0, TRUE);
|
|
}
|
|
return ptrEvent;
|
|
}
|
|
|
|
CXTPCalendarEventPtr CXTPCalendarMAPIDataProvider::ImportEvent(LPSRow lpRow)
|
|
{
|
|
if (!lpRow)
|
|
return NULL;
|
|
|
|
// ------- ID --------
|
|
if (PR_ENTRYID != lpRow->lpProps[0].ulPropTag)
|
|
{
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
CXTPCalendarEventPtr ptrEvent = ImportEvent(lpRow->lpProps[0].Value.bin.cb,
|
|
(LPENTRYID)lpRow->lpProps[0].Value.bin.lpb);
|
|
|
|
return ptrEvent;
|
|
}
|
|
|
|
CXTPCalendarEventPtr CXTPCalendarMAPIDataProvider::ImportEvent(ULONG cbEntryID,
|
|
LPENTRYID lpEntryID)
|
|
{
|
|
if (cbEntryID == 0 || !lpEntryID)
|
|
{
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
LPMESSAGE pMessage = NULL;
|
|
ULONG ulObjType = NULL;
|
|
|
|
// open event from Calendar Folder storage
|
|
m_lpCalendarFolder->OpenEntry(cbEntryID, lpEntryID,
|
|
NULL,//default interface
|
|
MAPI_BEST_ACCESS,
|
|
&ulObjType,
|
|
(LPUNKNOWN*)&pMessage);
|
|
|
|
ASSERT(ulObjType == 5);
|
|
ASSERT(pMessage);
|
|
if (!pMessage)
|
|
return NULL;
|
|
|
|
CXTPCalendarEventPtr ptrEvent = ImportEvent(pMessage);
|
|
|
|
MAPI_RELEASE(this, pMessage);
|
|
|
|
return ptrEvent;
|
|
}
|
|
|
|
|
|
CXTPCalendarEventPtr CXTPCalendarMAPIDataProvider::ImportEvent(LPMESSAGE pMessage)
|
|
{
|
|
ASSERT(pMessage);
|
|
if (!pMessage)
|
|
return NULL;
|
|
|
|
//-----------------------------------------------------------------------
|
|
CByteArray arSearchKey;
|
|
HRESULT hrID = _getPropVal(pMessage, PR_SEARCH_KEY, arSearchKey);
|
|
if (FAILED(hrID))
|
|
{
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
DWORD dwEventID = GetEventID((int)arSearchKey.GetSize(), (LPENTRYID)arSearchKey.GetData(), TRUE);
|
|
|
|
//============================================================
|
|
CXTPCalendarEventPtr ptrEvent(CreateNewEvent(dwEventID));
|
|
|
|
// ------- Is Recurrence --------
|
|
int nIsRecurrence = _getPropVal_int(pMessage, xtpMAPIpropEvent_IsRecuring);
|
|
|
|
// get TimeZone
|
|
TIME_ZONE_INFORMATION tziEvent;
|
|
GetTimeZoneInformation(&tziEvent);
|
|
|
|
if (nIsRecurrence)
|
|
{
|
|
ULONG ulTZTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_TimeZone);
|
|
CByteArray arTZIData;
|
|
HRESULT hrTZ = _getPropVal(pMessage, ulTZTag, arTZIData);
|
|
|
|
if (SUCCEEDED(hrTZ))
|
|
{
|
|
xtp_GetWinTZInfo(arTZIData, &tziEvent);
|
|
}
|
|
}
|
|
|
|
XTP_TRACE_READ_EVENTS(_T("\nEvent:------------------\n"));
|
|
|
|
// ------- Subject --------
|
|
CString strTmp = _getPropVal_str(pMessage, PR_SUBJECT);
|
|
ptrEvent->SetSubject(strTmp);
|
|
XTP_TRACE_READ_EVENTS(_T("Subject: %s\n"), strTmp);
|
|
|
|
// ------- Body --------
|
|
strTmp = _getPropVal_str(pMessage, PR_BODY);
|
|
ptrEvent->SetBody(strTmp);
|
|
XTP_TRACE_READ_EVENTS(_T("Body: %s\n"), strTmp.Left(255));
|
|
|
|
// ------- StartTime --------
|
|
SYSTEMTIME stUTC = _getPropVal_UtcTime(pMessage, xtpMAPIpropEvent_StartTime);
|
|
//TRACE(_T("StartTime orig: %s\n"), dtTmp.Format());
|
|
COleDateTime dtTmp = xtp_UtcToTzTime(&tziEvent, stUTC);
|
|
ptrEvent->SetStartTime(dtTmp);
|
|
XTP_TRACE_READ_EVENTS(_T("StartTime tz : %s\n"), dtTmp.Format());
|
|
|
|
// ------- EndTime --------
|
|
stUTC = _getPropVal_UtcTime(pMessage, xtpMAPIpropEvent_EndTime);
|
|
dtTmp = xtp_UtcToTzTime(&tziEvent, stUTC);
|
|
ptrEvent->SetEndTime(dtTmp);
|
|
//XTP_TRACE_READ_EVENTS(_T("EndTime: %s\n"), ptrEvent->GetEndTime().Format());
|
|
|
|
// ------- LOCATION --------
|
|
strTmp = _getPropVal_str(pMessage, xtpMAPIpropEvent_Location);
|
|
ptrEvent->SetLocation(strTmp);
|
|
XTP_TRACE_READ_EVENTS(_T("LOCATION: %s\n"), strTmp.Left(255));
|
|
|
|
// ------- AllDayEvent --------
|
|
int nTmp = _getPropVal_int(pMessage, xtpMAPIpropEvent_AllDay);
|
|
ptrEvent->SetAllDayEvent(nTmp != 0);
|
|
XTP_TRACE_READ_EVENTS(_T("All day: %d\n"), nTmp);
|
|
|
|
// ------- IsReminder --------
|
|
nTmp = _getPropVal_int(pMessage, xtpMAPIpropCommon_ReminderSet);
|
|
ptrEvent->SetReminder(nTmp);
|
|
|
|
// ------- ReminderMinutesBeforeStart --------
|
|
nTmp = _getPropVal_int(pMessage, xtpMAPIpropCommon_ReminderMinutesBefore);
|
|
ptrEvent->SetReminderMinutesBeforeStart(nTmp);
|
|
|
|
// ------- BusyStatus --------
|
|
nTmp = _getPropVal_int(pMessage, xtpMAPIpropEvent_BusyStatus);
|
|
ptrEvent->SetBusyStatus(nTmp);
|
|
|
|
// ------- Importance --------
|
|
nTmp = _getPropVal_int(pMessage, PR_IMPORTANCE);
|
|
ptrEvent->SetImportance(nTmp);
|
|
|
|
// ------- Label --------
|
|
nTmp = _getPropVal_int(pMessage, xtpMAPIpropEvent_Color);
|
|
ptrEvent->SetLabelID(nTmp);
|
|
|
|
// ------- Meeting --------
|
|
nTmp = _getPropVal_int(pMessage, xtpMAPIpropEvent_MeetingStatus);
|
|
ptrEvent->SetMeeting(nTmp != 0);
|
|
|
|
// ------- Private --------
|
|
nTmp = _getPropVal_int(pMessage, xtpMAPIpropCommon_IsPrivate);
|
|
ptrEvent->SetPrivate(nTmp != 0);
|
|
|
|
// ------- CreationTime --------
|
|
stUTC = _getPropVal_UtcTime(pMessage, PR_CREATION_TIME);
|
|
dtTmp = xtp_UtcToTzTime(&tziEvent, stUTC);
|
|
ptrEvent->SetCreationTime(dtTmp);
|
|
|
|
// ------- LastModificationTime --------
|
|
stUTC = _getPropVal_UtcTime(pMessage, PR_LAST_MODIFICATION_TIME);
|
|
dtTmp = xtp_UtcToTzTime(&tziEvent, stUTC);
|
|
ptrEvent->SetLastModificationTime(dtTmp);
|
|
|
|
// ------- Custom Properties -------
|
|
CXTPCalendarCustomProperties* pProps = ptrEvent->GetCustomProperties();
|
|
if (pProps)
|
|
{
|
|
strTmp = _getPropVal_str(pMessage, xtpMAPIpropEvent_CustomProperties);
|
|
pProps->LoadFromXML(strTmp);
|
|
|
|
_SetEventRuntimeProps(pProps, pMessage);
|
|
}
|
|
|
|
// nIsRecurrence
|
|
if (nIsRecurrence)
|
|
{
|
|
ULONG ulPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_RecurrenceState);
|
|
CByteArray arRecData;
|
|
HRESULT hr = _getPropVal(pMessage, ulPropTag, arRecData);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
VERIFY(ptrEvent->MakeEventAsRecurrence());
|
|
ImportRecurrence(ptrEvent, arRecData);
|
|
}
|
|
// -------
|
|
|
|
return ptrEvent;
|
|
}
|
|
|
|
int CXTPCalendarMAPIDataProvider::GetEventGlobalPropVal_int(LPCTSTR pcszPropName, int nDefault)
|
|
{
|
|
CXTPCalendarCustomProperties* pProps = GetCustomProperties();
|
|
|
|
ASSERT(pProps);
|
|
if (!pProps)
|
|
return nDefault;
|
|
|
|
COleVariant varValue;
|
|
BOOL bRes = pProps->GetProperty(pcszPropName, varValue);
|
|
if (!bRes)
|
|
return nDefault;
|
|
|
|
if (varValue.vt != VT_I4)
|
|
{
|
|
if (FAILED(::VariantChangeType(&varValue, &varValue, 0, VT_I4)))
|
|
return nDefault;
|
|
}
|
|
return V_I4(&varValue);
|
|
}
|
|
|
|
CString CXTPCalendarMAPIDataProvider::GetEventGlobalPropVal_str(LPCTSTR pcszPropName, LPCTSTR pcszDefault)
|
|
{
|
|
CXTPCalendarCustomProperties* pProps = GetCustomProperties();
|
|
|
|
ASSERT(pProps);
|
|
if (!pProps)
|
|
return pcszDefault;
|
|
|
|
COleVariant varValue;
|
|
BOOL bRes = pProps->GetProperty(pcszPropName, varValue);
|
|
if (!bRes)
|
|
return pcszDefault;
|
|
|
|
if (varValue.vt != VT_BSTR)
|
|
{
|
|
if (FAILED(::VariantChangeType(&varValue, &varValue, 0, VT_BSTR)))
|
|
return pcszDefault;
|
|
}
|
|
|
|
return CString(V_BSTR(&varValue));
|
|
}
|
|
|
|
void CXTPCalendarMAPIDataProvider::_SetMAPIEventGlobalPropsIfNeed(LPMESSAGE pMessage, CXTPCalendarEvent* pEvent)
|
|
{
|
|
if (!pMessage || !pEvent)
|
|
{
|
|
ASSERT(FALSE);
|
|
return;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
int nPropTag;
|
|
|
|
//**** Common customizable properties
|
|
int nRState = pEvent->GetRecurrenceState();
|
|
int nApptIcon = (nRState == xtpCalendarRecurrenceMaster) ? cnMAPIpropVal_AppointmentIconRecurr :
|
|
cnMAPIpropVal_AppointmentIcon;
|
|
|
|
VERIFY(_setPropTagVal_int(pMessage, XTP_PR_MAPI_EVENT_ICON_INDEX, nApptIcon));
|
|
|
|
//---------------------------------------
|
|
CString strMsgClass = GetEventGlobalPropVal_str(cszMAPIpropName_AppointmentMessageClass,
|
|
cszMAPIpropVal_AppointmentMessageClass);
|
|
VERIFY(_setPropTagVal_str(pMessage, PR_MESSAGE_CLASS_A, strMsgClass));
|
|
|
|
//---------------------------------------
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropCommon_OutlookInternalVersion);
|
|
|
|
int nOutlookVer = _getPropVal_int(pMessage, nPropTag);
|
|
if (nOutlookVer == 0)
|
|
{
|
|
nOutlookVer = GetEventGlobalPropVal_int(cszMAPIpropName_OutlookInternalVersion,
|
|
cnMAPIpropVal_OutlookInternalVersionDef);
|
|
VERIFY(_setPropTagVal_int(pMessage, nPropTag, nOutlookVer));
|
|
}
|
|
|
|
//---------------------------------------
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropCommon_OutlookVersion);
|
|
CString strOutlookVer = _getPropVal_str(pMessage, nPropTag);
|
|
if (strOutlookVer.IsEmpty())
|
|
{
|
|
strOutlookVer = GetEventGlobalPropVal_str(cszMAPIpropName_OutlookVersion,
|
|
cszMAPIpropVal_OutlookVersionDef);
|
|
VERIFY(_setPropTagVal_str(pMessage, nPropTag, strOutlookVer));
|
|
}
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::UpdateMAPIEvent(LPMESSAGE pMessage, CXTPCalendarEvent* pEvent)
|
|
{
|
|
if (!pMessage || !pEvent)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// ------- Is Recurrence --------
|
|
int nRState = pEvent->GetRecurrenceState();
|
|
|
|
int nIsRecurrence = (nRState == xtpCalendarRecurrenceMaster);
|
|
|
|
if (nRState != xtpCalendarRecurrenceNotRecurring &&
|
|
nRState != xtpCalendarRecurrenceMaster)
|
|
{
|
|
ASSERT(FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
// get TimeZone
|
|
TIME_ZONE_INFORMATION tziEvent;
|
|
GetTimeZoneInformation(&tziEvent);
|
|
|
|
int nPropTag;
|
|
//-------------------
|
|
|
|
//**** Common customizable properties
|
|
_SetMAPIEventGlobalPropsIfNeed(pMessage, pEvent);
|
|
//****
|
|
|
|
// ------- Subject --------
|
|
CString strTmp = pEvent->GetSubject();
|
|
VERIFY(_setPropTagVal_str(pMessage, PR_SUBJECT_A, strTmp));
|
|
|
|
// ------- Body --------
|
|
strTmp = pEvent->GetBody();
|
|
VERIFY(_setPropTagVal_str(pMessage, PR_BODY_A, strTmp));
|
|
|
|
// ======= Verify time values for recurrence events ===========
|
|
// If this is a recurring event, the master event stores the time
|
|
// as the beginning of the recurring event through to the end
|
|
// of the last event. We actually need the time of the first event here
|
|
|
|
// ------- StartTime --------
|
|
COleDateTime dtTmp = (nIsRecurrence == 0) ?
|
|
pEvent->GetStartTime() :
|
|
pEvent->GetStartTime() + pEvent->GetRecurrencePattern()->GetStartTime();
|
|
SYSTEMTIME stUTCstart = xtp_TimeToUtc(&tziEvent, dtTmp);
|
|
ASSERT(stUTCstart.wYear);
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_StartTime);
|
|
VERIFY(_setPropTagVal_UtcTime(pMessage, nPropTag, stUTCstart));
|
|
|
|
// ------- EndTime --------
|
|
dtTmp = (nIsRecurrence == 0) ?
|
|
pEvent->GetEndTime() :
|
|
pEvent->GetStartTime() + pEvent->GetRecurrencePattern()->GetStartTime() + COleDateTimeSpan(0, 0 , pEvent->GetRecurrencePattern()->GetDurationMinutes(), 0);
|
|
SYSTEMTIME stUTCend = xtp_TimeToUtc(&tziEvent, dtTmp);
|
|
ASSERT(stUTCend.wYear);
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_EndTime);
|
|
VERIFY(_setPropTagVal_UtcTime(pMessage, nPropTag, stUTCend));
|
|
|
|
// ------- LOCATION --------
|
|
strTmp = pEvent->GetLocation();
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_Location);
|
|
VERIFY(_setPropTagVal_str(pMessage, nPropTag, strTmp));
|
|
|
|
// ------- AllDayEvent --------
|
|
int nTmp = pEvent->IsAllDayEvent();
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_AllDay);
|
|
VERIFY(_setPropTagVal_int(pMessage, nPropTag, nTmp));
|
|
|
|
// ------- IsReminder --------
|
|
nTmp = pEvent->IsReminder();
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropCommon_ReminderSet);
|
|
VERIFY(_setPropTagVal_int(pMessage, nPropTag, nTmp));
|
|
|
|
// ------- ReminderMinutesBeforeStart --------
|
|
nTmp = pEvent->GetReminderMinutesBeforeStart();
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropCommon_ReminderMinutesBefore);
|
|
VERIFY(_setPropTagVal_int(pMessage, nPropTag, nTmp));
|
|
|
|
// ------- ReminderDate --------
|
|
ULONG nPTagRmdDate = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropCommon_ReminderDate);
|
|
|
|
if (pEvent->IsReminder())
|
|
{
|
|
VERIFY(_setPropTagVal_UtcTime(pMessage, nPTagRmdDate, stUTCstart)); // always equal to start time
|
|
}
|
|
else
|
|
{
|
|
_deletePropTag(pMessage, nPTagRmdDate);
|
|
}
|
|
|
|
// ------- BusyStatus --------
|
|
nTmp = pEvent->GetBusyStatus();
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_BusyStatus);
|
|
VERIFY(_setPropTagVal_int(pMessage, nPropTag, nTmp));
|
|
|
|
// ------- Importance --------
|
|
nTmp = pEvent->GetImportance();
|
|
VERIFY(_setPropTagVal_int(pMessage, PR_IMPORTANCE, nTmp));
|
|
|
|
// ------- Label --------
|
|
nTmp = pEvent->GetLabelID();
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_Color);
|
|
VERIFY(_setPropTagVal_int(pMessage, nPropTag, nTmp));
|
|
|
|
// ------- Meeting --------
|
|
nTmp = pEvent->IsMeeting();
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_MeetingStatus);
|
|
VERIFY(_setPropTagVal_int(pMessage, nPropTag, nTmp));
|
|
|
|
// ------- Private --------
|
|
nTmp = pEvent->IsPrivate();
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropCommon_IsPrivate);
|
|
VERIFY(_setPropTagVal_int(pMessage, nPropTag, nTmp));
|
|
VERIFY(_setPropTagVal_int(pMessage, PR_SENSITIVITY, nTmp ? SENSITIVITY_PRIVATE : SENSITIVITY_NONE));
|
|
|
|
// ------- CreationTime --------
|
|
dtTmp = pEvent->GetCreationTime();
|
|
SYSTEMTIME stUTC = xtp_TimeToUtc(&tziEvent, dtTmp);
|
|
ASSERT(stUTC.wYear);
|
|
VERIFY(_setPropTagVal_UtcTime(pMessage, PR_CREATION_TIME, stUTC));
|
|
|
|
// ------- LastModificationTime --------
|
|
dtTmp = pEvent->GetLastModificationTime();
|
|
stUTC = xtp_TimeToUtc(&tziEvent, dtTmp);
|
|
ASSERT(stUTC.wYear);
|
|
VERIFY(_setPropTagVal_UtcTime(pMessage, PR_LAST_MODIFICATION_TIME, stUTC));
|
|
|
|
// -------- Custom Properties -------
|
|
CXTPCalendarCustomProperties* pProps = pEvent->GetCustomProperties();
|
|
if (pProps)
|
|
{
|
|
CXTPCalendarCustomProperties tmpStorage;
|
|
_MoveMAPIEventRuntimeProps(&tmpStorage, pProps);
|
|
|
|
pProps->SaveToXML(strTmp);
|
|
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_CustomProperties);
|
|
VERIFY(_setPropTagVal_str(pMessage, nPropTag, strTmp));
|
|
|
|
_MoveMAPIEventRuntimeProps(pProps, &tmpStorage);
|
|
}
|
|
|
|
// nIsRecurrence
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_IsRecuring);
|
|
VERIFY(_setPropTagVal_int(pMessage, nPropTag, nIsRecurrence));
|
|
|
|
if (nIsRecurrence)
|
|
{
|
|
CByteArray arRecData;
|
|
CXTPCalendarMAPI_Recurrence::CXTPRcData RCData;
|
|
CXTPCalendarRecurrencePatternPtr ptrPattern = pEvent->GetRecurrencePattern();
|
|
|
|
BOOL bRes = CXTPCalendarMAPI_Recurrence::FillRCData(RCData, ptrPattern, pEvent);
|
|
ASSERT(bRes);
|
|
if (bRes)
|
|
{
|
|
bRes = CXTPCalendarMAPI_Recurrence::RCDataToBin(RCData, arRecData);
|
|
ASSERT(bRes);
|
|
if (bRes)
|
|
{
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_RecurrenceState);
|
|
VERIFY(_setPropTagVal_bin(pMessage, nPropTag, arRecData));
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
CByteArray arTZIData;
|
|
xtp_GetMapiTZInfo(&tziEvent, arTZIData);
|
|
|
|
ULONG ulTZTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_TimeZone);
|
|
VERIFY(_setPropTagVal_bin(pMessage, ulTZTag, arTZIData));
|
|
|
|
//- recurrence Start/end ----------------------------------------------
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_RecurrenceStart);
|
|
VERIFY(_setPropTagVal_UtcTime(pMessage, nPropTag, stUTCstart));
|
|
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_RecurrenceEnd);
|
|
VERIFY(_setPropTagVal_UtcTime(pMessage, nPropTag, stUTCend));
|
|
|
|
if (ptrPattern->GetUseEndMethod() == xtpCalendarPatternEndNoDate)
|
|
{
|
|
// the end date set above was for 1 Jan 9999, which is fine for Outlook
|
|
// but at least some versions of exchange server don't like it. Outlook
|
|
// sets the end date to the end date/time of the first instance of the
|
|
// pattern in this case.
|
|
|
|
// ------- Fixed EndTime --------
|
|
int nDuration = RCData.dwOccEndTime - RCData.dwOccStartTime;
|
|
|
|
dtTmp = pEvent->GetStartTime() + CXTPCalendarUtils::Minutes2Span(nDuration);
|
|
stUTCend = xtp_TimeToUtc(&tziEvent, dtTmp);
|
|
ASSERT(stUTCend.wYear);
|
|
|
|
nPropTag = m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_EndTime);
|
|
VERIFY(_setPropTagVal_UtcTime(pMessage, nPropTag, stUTCend));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CUIntArray arPropsTags;
|
|
arPropsTags.Add( (ULONG)m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_RecurrenceState));
|
|
arPropsTags.Add( (ULONG)m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_RecurrenceStart));
|
|
arPropsTags.Add( (ULONG)m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_RecurrenceEnd));
|
|
arPropsTags.Add( (ULONG)m_MapiHelper.GetPropTagByID(pMessage, xtpMAPIpropEvent_TimeZone));
|
|
|
|
_deletePropsTags(pMessage, arPropsTags);
|
|
}
|
|
|
|
// -------
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
UINT CXTPCalendarMAPIDataProvider::_getStreamSize(IStream* pStream)
|
|
{
|
|
ASSERT(pStream);
|
|
if (!pStream)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ULARGE_INTEGER uliSize = {0, 0};
|
|
LARGE_INTEGER liZero = {0, 0};
|
|
|
|
HRESULT hr = pStream->Seek(liZero, STREAM_SEEK_END, &uliSize);
|
|
if (FAILED(hr))
|
|
return 0;
|
|
|
|
hr = pStream->Seek(liZero, STREAM_SEEK_SET, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
return 0;
|
|
}
|
|
return uliSize.u.LowPart;
|
|
}
|
|
|
|
int CXTPCalendarMAPIDataProvider::_getSimpleMAPITypeSize(int nType)
|
|
{
|
|
switch (nType)
|
|
{
|
|
case PT_I2: return 2; /* Signed 16-bit value */
|
|
case PT_LONG: return 4; /* Signed 32-bit value */
|
|
case PT_R4: return 4; /* 4-byte floating point */
|
|
case PT_DOUBLE: return 8; /* Floating point double */
|
|
case PT_CURRENCY: return 8; /* Signed 64-bit int (decimal w/ 4 digits right of decimal pt) */
|
|
case PT_APPTIME: return sizeof(double); /* Application time */
|
|
case PT_ERROR: return 4; /* 32-bit error value */
|
|
case PT_BOOLEAN: return 2; /* 16-bit boolean (non-zero true) */
|
|
case PT_I8: return 8; /* 8-byte signed integer */
|
|
case PT_SYSTIME: return sizeof(FILETIME); /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */
|
|
case PT_CLSID: return sizeof(GUID); /* OLE GUID */
|
|
|
|
case PT_OBJECT: /* Embedded object in a property */
|
|
|
|
case PT_STRING8: /* Null terminated 8-bit character string */
|
|
case PT_UNICODE: /* Null terminated Unicode string */
|
|
case PT_BINARY: /* Uninterpreted (counted byte array) */
|
|
return 0;
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::_setPropTagVal_int(LPMESSAGE pMessage, ULONG ulPropTag, int nValue)
|
|
{
|
|
int nType = PROP_TYPE(ulPropTag);
|
|
int nTypeSize = _getSimpleMAPITypeSize(nType);
|
|
|
|
if (nTypeSize <= 0 || nTypeSize > 4)
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
SPropValue PropVal;
|
|
ZeroMemory(&PropVal, sizeof(PropVal));
|
|
|
|
PropVal.ulPropTag = ulPropTag;
|
|
|
|
switch (nType)
|
|
{
|
|
case PT_I2:
|
|
PropVal.Value.i = (short int)nValue;
|
|
break;
|
|
case PT_LONG: /* Signed 32-bit value */
|
|
PropVal.Value.l = (long)nValue;
|
|
break;
|
|
case PT_ERROR: /* 32-bit error value */
|
|
PropVal.Value.err = (SCODE)nValue;
|
|
break;
|
|
case PT_BOOLEAN: /* 16-bit boolean (non-zero true) */
|
|
PropVal.Value.b = (unsigned short int)nValue;
|
|
break;
|
|
|
|
// case PT_R4: return 4; /* 4-byte floating point */
|
|
// case PT_DOUBLE: return 8; /* Floating point double */
|
|
// case PT_CURRENCY: return 8; /* Signed 64-bit int (decimal w/ 4 digits right of decimal pt) */
|
|
// case PT_APPTIME: return sizeof(double); /* Application time */
|
|
|
|
// case PT_I8: return 8; /* 8-byte signed integer */
|
|
// case PT_SYSTIME: return sizeof(FILETIME); /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */
|
|
// case PT_CLSID: return sizeof(GUID); /* OLE GUID */
|
|
|
|
// case PT_OBJECT: /* Embedded object in a property */
|
|
|
|
// case PT_STRING8: /* Null terminated 8-bit character string */
|
|
// case PT_UNICODE: /* Null terminated Unicode string */
|
|
// case PT_BINARY: /* Uninterpreted (counted byte array) */
|
|
// return 0;
|
|
default:
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT hRes = this->HrSetOneProp(pMessage, &PropVal);
|
|
return SUCCEEDED(hRes);
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::_setPropTagVal_str(LPMESSAGE pMessage, ULONG ulPropTag, LPCTSTR pcszValue)
|
|
{
|
|
int nType = PROP_TYPE(ulPropTag);
|
|
|
|
LPSPropValue pPropVal = NULL;
|
|
|
|
if (nType == PT_STRING8) /* Null terminated 8-bit character string */
|
|
{
|
|
int nStrBuffSize = (int)_tcslen(pcszValue) * sizeof(TCHAR) + 2;
|
|
int nBufSize = sizeof(SPropValue) + nStrBuffSize + 4;
|
|
|
|
SCODE sc = this->MAPIAllocateBuffer(nBufSize, (void**)&pPropVal);
|
|
if (sc != S_OK || !pPropVal)
|
|
{
|
|
return FALSE;
|
|
}
|
|
ZeroMemory(pPropVal, nBufSize);
|
|
pPropVal->ulPropTag = ulPropTag;
|
|
pPropVal->Value.lpszA = (LPSTR)(pPropVal+1);
|
|
|
|
WCSTOMBS_S(pPropVal->Value.lpszA, pcszValue, nStrBuffSize);
|
|
}
|
|
else if (nType == PT_UNICODE) /* Null terminated Unicode string */
|
|
{
|
|
ASSERT(FALSE); //not implemented
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT hRes = this->HrSetOneProp(pMessage, pPropVal);
|
|
|
|
MAPI_FREEBUFFER(this, pPropVal);
|
|
|
|
return SUCCEEDED(hRes);
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::_setPropTagVal_UtcTime(LPMESSAGE pMessage, ULONG ulPropTag, const SYSTEMTIME& stTime)
|
|
{
|
|
int nType = PROP_TYPE(ulPropTag);
|
|
|
|
SPropValue PropVal;
|
|
ZeroMemory(&PropVal, sizeof(SPropValue));
|
|
|
|
if (nType == PT_SYSTIME) // FILETIME
|
|
{
|
|
PropVal.ulPropTag = ulPropTag;
|
|
|
|
FILETIME ft;
|
|
ZeroMemory(&ft, sizeof(ft));
|
|
|
|
if (!SystemTimeToFileTime(&stTime, &ft))
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
PropVal.Value.ft = ft;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT hRes = this->HrSetOneProp(pMessage, &PropVal);
|
|
return SUCCEEDED(hRes);
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::_setPropTagVal_bin(LPMESSAGE pMessage,
|
|
ULONG ulPropTag, const CByteArray& arData)
|
|
{
|
|
int nType = PROP_TYPE(ulPropTag);
|
|
|
|
SPropValue PropVal;
|
|
ZeroMemory(&PropVal, sizeof(SPropValue));
|
|
|
|
if (nType == PT_BINARY)
|
|
{
|
|
PropVal.ulPropTag = ulPropTag;
|
|
PropVal.Value.bin.cb = (ULONG)arData.GetSize();
|
|
PropVal.Value.bin.lpb = (BYTE*)arData.GetData();
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT hRes = this->HrSetOneProp(pMessage, &PropVal);
|
|
|
|
return SUCCEEDED(hRes);
|
|
}
|
|
|
|
HRESULT CXTPCalendarMAPIDataProvider::_getPropVal(LPMESSAGE pMessage, ULONG ulPropTag, CByteArray& rData)
|
|
{
|
|
rData.RemoveAll();
|
|
|
|
LPSTREAM pStream = NULL;
|
|
LPSPropValue pProp = NULL;
|
|
|
|
HRESULT hRes = this->HrGetOneProp(pMessage, ulPropTag, &pProp);
|
|
|
|
if (hRes == MAPI_E_NOT_ENOUGH_MEMORY)
|
|
{
|
|
hRes = pMessage->OpenProperty(ulPropTag, &IID_IStream, STGM_READ,
|
|
NULL, (LPUNKNOWN*)&pStream);
|
|
|
|
if (FAILED(hRes) || !pStream)
|
|
{
|
|
hRes = FAILED(hRes) ? hRes : E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
UINT nDataSize = _getStreamSize(pStream);
|
|
if (!nDataSize)
|
|
{
|
|
hRes = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
rData.SetSize((int)nDataSize);
|
|
|
|
ULONG nDataSize2 = 0;
|
|
hRes = pStream->Read(rData.GetData(), nDataSize, &nDataSize2);
|
|
|
|
ASSERT(nDataSize == nDataSize2);
|
|
rData.SetSize((int)nDataSize2);
|
|
}
|
|
pStream->Release();
|
|
}
|
|
|
|
}
|
|
else if (SUCCEEDED(hRes))
|
|
{
|
|
int nType = PROP_TYPE(pProp->ulPropTag);
|
|
int nTypeSize = _getSimpleMAPITypeSize(nType);
|
|
|
|
void* pData_src = NULL;
|
|
if (nTypeSize > 0)
|
|
{
|
|
pData_src = (void*)&pProp->Value;
|
|
}
|
|
else
|
|
{
|
|
if (nType == PT_STRING8) /* Null terminated 8-bit character string */
|
|
{
|
|
pData_src = (void*)pProp->Value.lpszA;
|
|
nTypeSize = (int)strlen(pProp->Value.lpszA) + 1;
|
|
}
|
|
else if (nType == PT_UNICODE) /* Null terminated Unicode string */
|
|
{
|
|
pData_src = (void*)pProp->Value.lpszW;
|
|
nTypeSize = (int)wcslen(pProp->Value.lpszW) * 2 + 2;
|
|
}
|
|
else if (nType == PT_BINARY) /* Uninterpreted (counted byte array) */
|
|
{
|
|
pData_src = (void*)pProp->Value.bin.lpb;
|
|
nTypeSize = pProp->Value.bin.cb;
|
|
}
|
|
}
|
|
|
|
rData.SetSize(nTypeSize);
|
|
MEMCPY_S(rData.GetData(), pData_src, nTypeSize);
|
|
}
|
|
|
|
MAPI_FREEBUFFER(this, pProp);
|
|
|
|
return hRes;
|
|
}
|
|
|
|
CString CXTPCalendarMAPIDataProvider::_getPropVal_str(LPMESSAGE pMessage, ULONG ulPropTag)
|
|
{
|
|
CString str;
|
|
CByteArray arData;
|
|
|
|
int nType = PROP_TYPE(ulPropTag);
|
|
ASSERT(nType == PT_STRING8 || nType == PT_UNICODE);
|
|
|
|
HRESULT hr = _getPropVal(pMessage, ulPropTag, arData);
|
|
|
|
if (FAILED(hr) || arData.GetSize() == 0)
|
|
{
|
|
return str;
|
|
}
|
|
|
|
if (nType == PT_STRING8) /* Null terminated 8-bit character string */
|
|
{
|
|
str = (LPCSTR)arData.GetData();
|
|
}
|
|
else if (nType == PT_UNICODE) /* Null terminated Unicode string */
|
|
{
|
|
str = (LPCWSTR)arData.GetData();
|
|
}
|
|
return str;
|
|
}
|
|
|
|
int CXTPCalendarMAPIDataProvider::_getPropVal_int(LPMESSAGE pMessage, ULONG ulPropTag)
|
|
{
|
|
CByteArray arData;
|
|
|
|
int nType = PROP_TYPE(ulPropTag);
|
|
ASSERT( nType == PT_I2 || nType == PT_LONG ||
|
|
nType == PT_ERROR || nType == PT_BOOLEAN ||
|
|
nType == PT_I8);
|
|
|
|
HRESULT hr = _getPropVal(pMessage, ulPropTag, arData);
|
|
|
|
if (FAILED(hr) || arData.GetSize() == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int nSize = (int)arData.GetSize();
|
|
int nValue = 0;
|
|
|
|
ASSERT(sizeof(ULONGLONG) == 8);
|
|
|
|
if (nSize == 1)
|
|
{
|
|
nValue = (int)arData[0];
|
|
}
|
|
else if (nSize == 2)
|
|
{
|
|
nValue = (int)*((WORD*)arData.GetData());
|
|
}
|
|
else if (nSize == 3)
|
|
{
|
|
nValue = (int)RGB(arData[0], arData[1], arData[2]);
|
|
}
|
|
else if (nSize == 4)
|
|
{
|
|
nValue = (int)*((DWORD*)arData.GetData());
|
|
}
|
|
else if (nSize == 8)
|
|
{
|
|
nValue = (int)*((ULONGLONG*)arData.GetData());
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
return nValue;
|
|
}
|
|
|
|
SYSTEMTIME CXTPCalendarMAPIDataProvider::_getPropVal_UtcTime(LPMESSAGE pMessage, ULONG ulPropTag)
|
|
{
|
|
SYSTEMTIME stUTCTime, stUTCTime0;
|
|
ZeroMemory(&stUTCTime, sizeof(stUTCTime));
|
|
ZeroMemory(&stUTCTime0, sizeof(stUTCTime0));
|
|
|
|
if (ulPropTag == 0)
|
|
{
|
|
return stUTCTime0;
|
|
}
|
|
|
|
int nType = PROP_TYPE(ulPropTag);
|
|
|
|
if (nType != PT_SYSTIME)
|
|
{
|
|
ASSERT(FALSE);
|
|
return stUTCTime0;
|
|
}
|
|
|
|
CByteArray arData;
|
|
HRESULT hr = _getPropVal(pMessage, ulPropTag, arData);
|
|
|
|
if (FAILED(hr) || arData.GetSize() == 0)
|
|
{
|
|
return stUTCTime0;
|
|
}
|
|
ASSERT(arData.GetSize() == sizeof(FILETIME));
|
|
|
|
FILETIME* pUTCTime = ((FILETIME*)arData.GetData());
|
|
|
|
if (FileTimeToSystemTime(pUTCTime, &stUTCTime))
|
|
{
|
|
return stUTCTime;
|
|
}
|
|
|
|
return stUTCTime0;
|
|
}
|
|
|
|
CString CXTPCalendarMAPIDataProvider::_getPropVal_str(LPMESSAGE pMessage,
|
|
const XTP_MAPI_PROP_NAME& propNameEx)
|
|
{
|
|
ULONG ulPropTag = m_MapiHelper.GetPropTagByID(pMessage, propNameEx);
|
|
|
|
return _getPropVal_str(pMessage, ulPropTag);
|
|
}
|
|
|
|
int CXTPCalendarMAPIDataProvider::_getPropVal_int(LPMESSAGE pMessage,
|
|
const XTP_MAPI_PROP_NAME& propNameEx)
|
|
{
|
|
ULONG ulPropTag = m_MapiHelper.GetPropTagByID(pMessage, propNameEx);
|
|
|
|
return _getPropVal_int(pMessage, ulPropTag);
|
|
}
|
|
|
|
SYSTEMTIME CXTPCalendarMAPIDataProvider::_getPropVal_UtcTime(LPMESSAGE pMessage,
|
|
const XTP_MAPI_PROP_NAME& propNameEx)
|
|
{
|
|
ULONG ulPropTag = m_MapiHelper.GetPropTagByID(pMessage, propNameEx);
|
|
|
|
return _getPropVal_UtcTime(pMessage, ulPropTag);
|
|
}
|
|
|
|
HRESULT CXTPCalendarMAPIDataProvider::_deletePropTag(LPMESSAGE pMessage, ULONG ulPropTag)
|
|
{
|
|
CUIntArray arPropsTags;
|
|
arPropsTags.Add(ulPropTag);
|
|
|
|
return _deletePropsTags(pMessage, arPropsTags);
|
|
}
|
|
|
|
HRESULT CXTPCalendarMAPIDataProvider::_deletePropsTags(LPMESSAGE pMessage, CUIntArray& arPropsTags)
|
|
{
|
|
if (!pMessage || arPropsTags.GetSize() == 0)
|
|
{
|
|
ASSERT(FALSE);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
int nTagsCount = (int)arPropsTags.GetSize();
|
|
SPropTagArray* pPorpTagsArray = NULL;
|
|
|
|
int nBufSize = sizeof(SPropTagArray) + nTagsCount * sizeof(ULONG) + 4;
|
|
SCODE sc = this->MAPIAllocateBuffer(nBufSize, (void**)&pPorpTagsArray);
|
|
if (sc != S_OK || !pPorpTagsArray)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//---------------------------------------------
|
|
pPorpTagsArray->cValues = nTagsCount;
|
|
for (int i = 0; i < nTagsCount; i++)
|
|
{
|
|
pPorpTagsArray->aulPropTag[i] = (ULONG)arPropsTags[i];
|
|
}
|
|
|
|
HRESULT hrDelete = pMessage->DeleteProps(pPorpTagsArray, NULL);
|
|
|
|
//---------------------------------------------
|
|
MAPI_FREEBUFFER(this, pPorpTagsArray);
|
|
|
|
return hrDelete;
|
|
}
|
|
|
|
void CXTPCalendarMAPIDataProvider::ImportRecurrence(CXTPCalendarEvent* pMasterEvent,
|
|
const CByteArray& arRCData)
|
|
{
|
|
ASSERT(pMasterEvent->GetRecurrenceState() == xtpCalendarRecurrenceMaster);
|
|
|
|
CXTPCalendarRecurrencePatternPtr ptrPattern = pMasterEvent->GetRecurrencePattern();
|
|
ASSERT(ptrPattern);
|
|
if (!ptrPattern)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CXTPCalendarMAPI_Recurrence::CXTPRcData RCData;
|
|
|
|
BOOL bRead = CXTPCalendarMAPI_Recurrence::ReadRCData(RCData, arRCData);
|
|
ASSERT(bRead);
|
|
|
|
if (!bRead)
|
|
{
|
|
return;
|
|
}
|
|
ASSERT((RCData.wType - xtpMAPIRcType_Daily) >= 0 && (RCData.wType - xtpMAPIRcType_Daily) <= 3);
|
|
|
|
CXTPCalendarMAPI_Recurrence::SetRecurrenceOptions(ptrPattern, RCData);
|
|
|
|
CXTPCalendarMAPI_Recurrence::SetRecurrenceExceptions(pMasterEvent, ptrPattern, RCData);
|
|
|
|
VERIFY( pMasterEvent->UpdateRecurrence(ptrPattern) );
|
|
}
|
|
|
|
CXTPCalendarEventsPtr CXTPCalendarMAPIDataProvider::ImportAllEvents(LPSRestriction lpRestriction)
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
LPMAPITABLE lpContentsTable = NULL;
|
|
LPSRowSet pRows = NULL;
|
|
ULONG i;
|
|
CXTPCalendarEventsPtr ptrEvents = new CXTPCalendarEvents();
|
|
|
|
static SizedSPropTagArray(1, sptCols) = {1, {PR_ENTRYID} };
|
|
|
|
hRes = m_lpCalendarFolder->GetContentsTable(0, &lpContentsTable);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = this->HrQueryAllRows(lpContentsTable, (LPSPropTagArray) &sptCols,
|
|
lpRestriction, //restriction...current day
|
|
NULL,//sort order...we're not using this parameter
|
|
0, &pRows);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
for (i = 0; i < pRows->cRows; i++)
|
|
{
|
|
CXTPCalendarEventPtr ptrNextEvent = ImportEvent(&pRows->aRow[i]);
|
|
ASSERT(ptrNextEvent);
|
|
if (ptrNextEvent)
|
|
{
|
|
ptrEvents->Add(ptrNextEvent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
if (pRows)
|
|
{
|
|
this->FreeProws(pRows);
|
|
}
|
|
|
|
MAPI_RELEASE(this, lpContentsTable);
|
|
|
|
return ptrEvents;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::ImportNewEvents()
|
|
{
|
|
ASSERT(m_pMemDP);
|
|
if (!m_pMemDP)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL bChanged = FALSE;
|
|
|
|
HRESULT hRes = S_OK;
|
|
LPMAPITABLE lpContentsTable = NULL;
|
|
LPSRowSet pRows = NULL;
|
|
ULONG i;
|
|
CMap_EventIDs mapExistingEntries;
|
|
CMap_EventIDs mapMissedEntries;
|
|
|
|
// Retrieve EntryID's of all items from the MAPI Calendar folder
|
|
static SizedSPropTagArray(2, sptCols) = {2, {PR_ENTRYID, PR_SEARCH_KEY} };
|
|
|
|
hRes = m_lpCalendarFolder->GetContentsTable(0, &lpContentsTable);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = this->HrQueryAllRows(lpContentsTable, (LPSPropTagArray) &sptCols,
|
|
NULL, //lpRestriction, //restriction...current day??
|
|
NULL,//sort order...we're not using this parameter
|
|
0, &pRows);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
// Iterate all appointment items read from data source
|
|
for (i = 0; i < pRows->cRows; i++)
|
|
{
|
|
// ------- SEARCH_KEY --------
|
|
if (PR_SEARCH_KEY != pRows->aRow[i].lpProps[1].ulPropTag)
|
|
{
|
|
ASSERT(FALSE);
|
|
continue;
|
|
}
|
|
// trying to find this eventID
|
|
DWORD dwEventID = GetEventID(pRows->aRow[i].lpProps[1].Value.bin.cb,
|
|
(LPENTRYID)pRows->aRow[i].lpProps[1].Value.bin.lpb);
|
|
|
|
// if not found - import
|
|
if (XTP_CALENDAR_UNKNOWN_EVENT_ID == dwEventID)
|
|
{
|
|
CXTPCalendarEventPtr ptrNextEvent = ImportEvent(&pRows->aRow[i]);
|
|
ASSERT(ptrNextEvent);
|
|
if (ptrNextEvent)
|
|
{
|
|
bChanged = TRUE;
|
|
VERIFY(m_pMemDP->AddEvent(ptrNextEvent));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if event found - add its ID into a map
|
|
mapExistingEntries.SetAt(dwEventID, TRUE);
|
|
}
|
|
}
|
|
|
|
// Delete all items which exists in internal data storage, but
|
|
// were not just found in the contents table of the external folder.
|
|
m_mapID.FindMissing(mapExistingEntries, mapMissedEntries);
|
|
POSITION pos = mapMissedEntries.GetStartPosition();
|
|
DWORD dwKey;
|
|
BOOL bValue = FALSE;
|
|
while (pos != NULL)
|
|
{
|
|
bChanged = TRUE;
|
|
mapMissedEntries.GetNextAssoc(pos, dwKey, bValue);
|
|
|
|
CXTPCalendarEventPtr ptrEventToDel = m_pMemDP->GetEvent(dwKey);
|
|
// ASSERT(ptrEventToDel); // could be NULL if processing a few notifications in a row
|
|
if (ptrEventToDel)
|
|
{
|
|
VERIFY(m_pMemDP->DeleteEvent(ptrEventToDel));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cleanup
|
|
if (pRows)
|
|
{
|
|
this->FreeProws(pRows);
|
|
}
|
|
MAPI_RELEASE(this, lpContentsTable);
|
|
|
|
return bChanged;
|
|
}
|
|
|
|
LONG STDAPICALLTYPE CXTPCalendarMAPIDataProvider::MAPICallBack_OnNotify(
|
|
LPVOID lpvContext,
|
|
ULONG cNotif,
|
|
LPNOTIFICATION lpNotif)
|
|
{
|
|
BOOL bProcessed = FALSE;
|
|
// get current MAPI data provider
|
|
CXTPCalendarMAPIDataProvider* pThis = (CXTPCalendarMAPIDataProvider*)lpvContext;
|
|
ASSERT(pThis);
|
|
if (!pThis)
|
|
return MAPI_E_INVALID_PARAMETER;
|
|
|
|
CXTPCalendarData* pMemDP = pThis->m_pMemDP;
|
|
|
|
if (!pMemDP)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
//***********************
|
|
SAFE_MANAGE_STATE(pThis->m_pModuleState);
|
|
//***********************
|
|
|
|
XTP_TRACE_MAPI_NF(_T("\n MAPICallBack_OnNotify [%s] (notifications count = %d)\n"),
|
|
COleDateTime::GetCurrentTime().Format(), (int)cNotif);
|
|
|
|
for (int i = 0; i < (int)cNotif; i++)
|
|
{
|
|
ULONG ulNfSender = lpNotif[i].info.obj.ulObjType;
|
|
ULONG ulNfType = lpNotif[i].ulEventType;
|
|
|
|
XTP_TRACE_MAPI_NF(_T(" NfSender = %d (%s)\n"), (int)ulNfSender,
|
|
ulNfSender == MAPI_FOLDER ? _T("MAPI_FOLDER") : (ulNfSender == MAPI_MESSAGE ? _T("MAPI_MESSAGE") : _T("")) );
|
|
|
|
// Check is notification related to active calendar folder ----------
|
|
CString str_dbg_CalRel;
|
|
CXTPMAPIBinary eidObj;
|
|
if (ulNfSender == MAPI_FOLDER)
|
|
{
|
|
eidObj.Set(lpNotif[i].info.obj.cbEntryID, (LPBYTE)lpNotif[i].info.obj.lpEntryID);
|
|
str_dbg_CalRel = _T("this");
|
|
}
|
|
else if (ulNfSender == MAPI_MESSAGE)
|
|
{
|
|
eidObj.Set(lpNotif[i].info.obj.cbParentID, (LPBYTE)lpNotif[i].info.obj.lpParentID);
|
|
str_dbg_CalRel = _T("Parent folder");
|
|
}
|
|
|
|
if (!pThis->Equal(eidObj, pThis->m_eidCalendarFolder))
|
|
{
|
|
if (ulNfSender == MAPI_MESSAGE)
|
|
{
|
|
eidObj.Set(lpNotif[i].info.obj.cbOldParentID, (LPBYTE)lpNotif[i].info.obj.lpOldParentID);
|
|
if (!pThis->Equal(eidObj, pThis->m_eidCalendarFolder))
|
|
{
|
|
XTP_TRACE_MAPI_NF(_T(" Calendar is: not related! SKIP. \n"));
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
str_dbg_CalRel = _T("OLD Parent folder");
|
|
pThis->ImportNewEvents();
|
|
bProcessed = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XTP_TRACE_MAPI_NF(_T(" Calendar is: not related! SKIP. \n"));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
XTP_TRACE_MAPI_NF(_T(" Calendar is: %s\n"), str_dbg_CalRel);
|
|
|
|
CString str_dbg_NF;
|
|
str_dbg_NF += (ulNfType & fnevObjectCreated) ? _T(" | Created") : _T("");
|
|
str_dbg_NF += (ulNfType & fnevObjectDeleted) ? _T(" | Deleted") : _T("");
|
|
str_dbg_NF += (ulNfType & fnevObjectModified) ?_T(" | Modified") : _T("");
|
|
str_dbg_NF += (ulNfType & fnevObjectMoved) ? _T(" | Moved") : _T("");
|
|
str_dbg_NF += (ulNfType & fnevObjectCopied) ? _T(" | Copied") : _T("");
|
|
|
|
XTP_TRACE_MAPI_NF(_T(" fnevObject =%s \n"), str_dbg_NF);
|
|
|
|
if (bProcessed)
|
|
{
|
|
return SUCCESS_SUCCESS;
|
|
}
|
|
//-------------------------------------------------------------------
|
|
CXTPMAPIBinary keyID = pThis->GetSearchKey(lpNotif[i].info.obj.cbEntryID, lpNotif[i].info.obj.lpEntryID);
|
|
DWORD dwEventID = pThis->GetEventID(keyID.GetBinarySize(), (LPENTRYID)keyID.GetBinaryData());
|
|
CXTPCalendarEventPtr ptrEvent = pMemDP->GetEvent(dwEventID);
|
|
|
|
XTP_TRACE_MAPI_NF(_T(" event ID = %d (%s)\n"), dwEventID,
|
|
(LPCTSTR)(ptrEvent ? _T("exists") : _T("non-exists")) );
|
|
|
|
// look what type of change was performed
|
|
if (ulNfType & fnevObjectDeleted)
|
|
{
|
|
// Delete the event
|
|
// Note that this message will never be received for deleted item for Exchange 5.5 and 2000.
|
|
// More info at MS KB261172
|
|
if (ptrEvent)
|
|
{
|
|
VERIFY( pMemDP->DeleteEvent(ptrEvent) );
|
|
XTP_TRACE_MAPI_NF(_T(" Action = DELETE\n"));
|
|
|
|
//#pragma NOTE("Advice to DP notification and resend")
|
|
//pThis->m_pConnect->SendEvent(XTP_NC_CALENDAREVENTWASDELETED, (WPARAM)dwEventID, (LPARAM)(CXTPCalendarEvent*)ptrEvent);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if ((ulNfType & fnevObjectCreated) && ulNfSender == MAPI_MESSAGE)
|
|
{
|
|
if (dwEventID != XTP_CALENDAR_UNKNOWN_EVENT_ID)
|
|
{
|
|
//ASSERT(FALSE);
|
|
XTP_TRACE_MAPI_NF(_T(" Action = skip\n"));
|
|
return SUCCESS_SUCCESS;
|
|
}
|
|
|
|
// Add a new event
|
|
CXTPCalendarEventPtr ptrEvent2 = pThis->ImportEvent(
|
|
lpNotif[i].info.obj.cbEntryID,
|
|
lpNotif[i].info.obj.lpEntryID);
|
|
|
|
if (ptrEvent && ptrEvent2)
|
|
{
|
|
//Event already exists
|
|
VERIFY( pMemDP->ChangeEvent(ptrEvent2) );
|
|
XTP_TRACE_MAPI_NF(_T(" Action = CHANGE\n"));
|
|
}
|
|
else if (ptrEvent2)
|
|
{
|
|
VERIFY( pMemDP->AddEvent(ptrEvent2) );
|
|
XTP_TRACE_MAPI_NF(_T(" Action = ADD\n"));
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ((ulNfType & fnevObjectMoved) && ulNfSender == MAPI_MESSAGE)
|
|
{
|
|
CXTPCalendarEventPtr ptrEvent2 = pThis->ImportEvent_FromCalendarFolderOnly(
|
|
lpNotif[i].info.obj.cbEntryID,
|
|
lpNotif[i].info.obj.lpEntryID);
|
|
|
|
if (ptrEvent && ptrEvent2)
|
|
{
|
|
//Event was moved inside Calendar folder
|
|
VERIFY( pMemDP->ChangeEvent(ptrEvent2) );
|
|
XTP_TRACE_MAPI_NF(_T(" Action = CHANGE\n"));
|
|
}
|
|
else if (ptrEvent)
|
|
{
|
|
//Event was moved Out of Calendar folder (to "Deleted Items" folder)
|
|
VERIFY( pMemDP->DeleteEvent(ptrEvent) );
|
|
XTP_TRACE_MAPI_NF(_T(" Action = DELETE (moved to other folder)\n"));
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if ((ulNfType & fnevObjectModified) && ulNfSender == MAPI_MESSAGE)
|
|
{
|
|
// is Our event changed
|
|
if (ptrEvent)
|
|
{
|
|
// Read new event data
|
|
CXTPCalendarEventPtr ptrEvent2 = pThis->ImportEvent(
|
|
lpNotif[i].info.obj.cbEntryID,
|
|
lpNotif[i].info.obj.lpEntryID);
|
|
ASSERT(ptrEvent2);
|
|
|
|
// Update event properties in the cache
|
|
if (ptrEvent2)
|
|
{
|
|
ASSERT(ptrEvent->GetEventID() == ptrEvent2->GetEventID());
|
|
|
|
DWORD dwPatternID = ptrEvent->GetRecurrencePatternID();
|
|
|
|
if (dwPatternID != XTP_CALENDAR_UNKNOWN_RECURRENCE_PATTERN_ID)
|
|
{
|
|
ptrEvent2->SetRecurrencePatternID(dwPatternID);
|
|
}
|
|
|
|
pMemDP->ChangeEvent(ptrEvent2);
|
|
XTP_TRACE_MAPI_NF(_T(" Action = CHANGE.2\n"));
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return SUCCESS_SUCCESS;
|
|
}
|
|
|
|
DWORD CXTPCalendarMAPIDataProvider::GetNextUniqueEventID(DWORD dwEventID)
|
|
{
|
|
if (XTP_CALENDAR_UNKNOWN_EVENT_ID == dwEventID)
|
|
dwEventID = GetNextFreeTempID();
|
|
|
|
CXTPMAPIBinary eKeyTmp;
|
|
while (m_mapID.Lookup(dwEventID, eKeyTmp))
|
|
{
|
|
dwEventID = GetNextFreeTempID();
|
|
}
|
|
ASSERT(m_mapID.Lookup(dwEventID, eKeyTmp) == FALSE);
|
|
return dwEventID;
|
|
}
|
|
|
|
CXTPMAPIBinary CXTPCalendarMAPIDataProvider::GetSearchKey(ULONG cbEntryID, LPENTRYID lpEntryID)
|
|
{
|
|
CXTPMAPIBinary keySearch;
|
|
|
|
if (cbEntryID == 0 || !lpEntryID || !m_lpCalendarFolder)
|
|
{
|
|
ASSERT(FALSE);
|
|
return keySearch;
|
|
}
|
|
|
|
LPMESSAGE pMessage = NULL;
|
|
ULONG ulObjType = NULL;
|
|
|
|
// open event from Calendar Folder storage
|
|
m_lpCalendarFolder->OpenEntry(cbEntryID, lpEntryID,
|
|
NULL,//default interface
|
|
MAPI_BEST_ACCESS,
|
|
&ulObjType,
|
|
(LPUNKNOWN*)&pMessage);
|
|
|
|
//ASSERT(ulObjType == 5);
|
|
//ASSERT(pMessage); // CHECK
|
|
if (!pMessage)
|
|
{
|
|
return keySearch;
|
|
}
|
|
|
|
// Get SearchKey
|
|
CByteArray arSearchKey;
|
|
HRESULT hrID = _getPropVal(pMessage, PR_SEARCH_KEY, arSearchKey);
|
|
if (SUCCEEDED(hrID))
|
|
{
|
|
keySearch.Set((int)arSearchKey.GetSize(), arSearchKey.GetData());
|
|
}
|
|
|
|
MAPI_RELEASE(this, pMessage);
|
|
|
|
return keySearch;
|
|
}
|
|
|
|
CXTPMAPIBinary CXTPCalendarMAPIDataProvider::GetEntryID(CXTPMAPIBinary& eSearchKey)
|
|
{
|
|
if (eSearchKey.GetBinarySize() == 0 || !eSearchKey.GetBinaryData() || !m_lpCalendarFolder)
|
|
{
|
|
ASSERT(FALSE);
|
|
return eSearchKey;
|
|
}
|
|
|
|
HRESULT hRes = S_OK;
|
|
LPMAPITABLE lpContentsTable = NULL;
|
|
LPSRowSet pRows = NULL;
|
|
CXTPMAPIBinary eid;
|
|
|
|
LPSRestriction pRestriction = BuildBinaryRestriction(eSearchKey.GetBinarySize(), eSearchKey.GetBinaryData(), PR_SEARCH_KEY);
|
|
|
|
static SizedSPropTagArray(1, sptCols) = {1, {PR_ENTRYID} };
|
|
|
|
hRes = m_lpCalendarFolder->GetContentsTable(0, &lpContentsTable);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
{
|
|
hRes = this->HrQueryAllRows(lpContentsTable, (LPSPropTagArray) &sptCols,
|
|
pRestriction, //restriction...
|
|
NULL,//sort order...we're not using this parameter
|
|
0, &pRows);
|
|
|
|
if (SUCCEEDED(hRes) && pRows->cRows > 0)
|
|
{
|
|
// ASSERT(pRows->cRows == 1); // we can get only one item by its Search Key
|
|
ASSERT(PR_ENTRYID == pRows->aRow[0].lpProps[0].ulPropTag); // we asked only for EntryID
|
|
eid.Set(pRows->aRow[0].lpProps[0].Value.bin.cb,
|
|
pRows->aRow[0].lpProps[0].Value.bin.lpb);
|
|
}
|
|
}
|
|
|
|
// cleanup
|
|
if (pRows)
|
|
{
|
|
this->FreeProws(pRows);
|
|
}
|
|
MAPI_RELEASE(this, lpContentsTable);
|
|
|
|
return eid;
|
|
}
|
|
|
|
DWORD CXTPCalendarMAPIDataProvider::GetEventID(
|
|
ULONG cbSearchKey, LPENTRYID lpSearchKey, BOOL bAddNew)
|
|
{
|
|
CXTPMAPIBinary eKey(cbSearchKey, lpSearchKey);
|
|
|
|
DWORD dwNextID = XTP_CALENDAR_UNKNOWN_EVENT_ID;
|
|
|
|
// lookup a map.
|
|
if (m_mapID.Lookup(eKey, dwNextID))
|
|
return dwNextID;
|
|
|
|
// ID not found - add new one if necessary
|
|
if (!bAddNew)
|
|
return XTP_CALENDAR_UNKNOWN_EVENT_ID;
|
|
|
|
dwNextID = GetNextUniqueEventID();
|
|
m_mapID.Add(dwNextID, eKey);
|
|
|
|
return dwNextID;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::Equal(const CXTPMAPIBinary& eid1, const CXTPMAPIBinary& eid2)
|
|
{
|
|
BOOL bRes = FALSE;
|
|
|
|
// 1st check using simple byte-to-byte comparison
|
|
bRes = CXTPMAPIBinary::IsBinaryEqual(eid1, eid2);
|
|
if (bRes)
|
|
return bRes;
|
|
|
|
// 2nd check using CompareEntryIDs method.
|
|
// This is required because EntryID versions can change (i.e. A single
|
|
// provider can support more than one form of entry id) and it is up to
|
|
// a specific provider to decide if two EntryID's compare. The way of
|
|
// doing this is calling the CompareEntryIDs method on the on the
|
|
// appropriate object.
|
|
if (!m_lpMAPISession)
|
|
return bRes;
|
|
|
|
ULONG ulRes;
|
|
if (SUCCEEDED(m_lpMAPISession->CompareEntryIDs(
|
|
eid1.m_cb, (LPENTRYID)eid1.GetBinaryData(),
|
|
eid2.m_cb, (LPENTRYID)eid2.GetBinaryData(),
|
|
0, &ulRes)))
|
|
{
|
|
bRes = (BOOL)ulRes;
|
|
}
|
|
|
|
return bRes;
|
|
}
|
|
|
|
BOOL CXTPCalendarMAPIDataProvider::OnTimeZoneChanged()
|
|
{
|
|
if (IsOpen())
|
|
{
|
|
// Re-Read all events to the cache data provider
|
|
if (m_pMemDP)
|
|
{
|
|
CXTPAutoResetValue<BOOL> autoReset(m_bDisableNotificationsSending, FALSE);
|
|
m_bDisableNotificationsSending = TRUE;
|
|
|
|
m_pMemDP->RemoveAllEvents();
|
|
|
|
m_pMemDP->AddEvents(ImportAllEvents());
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
};
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CXTPMAPIBinary
|
|
//
|
|
|
|
CXTPMAPIBinary::CXTPMAPIBinary()
|
|
{
|
|
m_cb = 0;
|
|
}
|
|
|
|
CXTPMAPIBinary::CXTPMAPIBinary(ULONG cbEntryID, LPENTRYID lpEntryID)
|
|
{
|
|
Set(cbEntryID, (LPBYTE)lpEntryID);
|
|
}
|
|
|
|
CXTPMAPIBinary::CXTPMAPIBinary(const CXTPMAPIBinary& eid)
|
|
{
|
|
m_cb = eid.m_cb;
|
|
m_arBytes.RemoveAll();
|
|
m_arBytes.Append(eid.m_arBytes);
|
|
}
|
|
|
|
CXTPMAPIBinary::~CXTPMAPIBinary()
|
|
{
|
|
}
|
|
|
|
CXTPMAPIBinary& CXTPMAPIBinary::operator=(const CXTPMAPIBinary& eid)
|
|
{
|
|
m_cb = eid.m_cb;
|
|
m_arBytes.SetSize(m_cb);
|
|
MEMCPY_S(m_arBytes.GetData(), eid.GetBinaryData(), m_cb);
|
|
|
|
return *this;
|
|
}
|
|
|
|
ULONG CXTPMAPIBinary::GetBinarySize() const
|
|
{
|
|
return m_cb;
|
|
}
|
|
|
|
LPBYTE CXTPMAPIBinary::GetBinaryData() const
|
|
{
|
|
return (BYTE*)m_arBytes.GetData();
|
|
}
|
|
|
|
void CXTPMAPIBinary::Set(ULONG cbSize, LPBYTE lpData)
|
|
{
|
|
m_cb = cbSize;
|
|
|
|
m_arBytes.SetSize(m_cb);
|
|
MEMCPY_S(m_arBytes.GetData(), lpData, m_cb);
|
|
}
|
|
|
|
void CXTPMAPIBinary::Set(LPSPropValue pPropEntryID)
|
|
{
|
|
if (!pPropEntryID || pPropEntryID->ulPropTag != PR_ENTRYID)
|
|
{
|
|
ASSERT(FALSE);
|
|
Set(0, NULL);
|
|
return;
|
|
}
|
|
|
|
Set(pPropEntryID->Value.bin.cb, pPropEntryID->Value.bin.lpb);
|
|
}
|
|
|
|
BOOL CXTPMAPIBinary::IsBinaryEqual(
|
|
const CXTPMAPIBinary& eid1, const CXTPMAPIBinary& eid2)
|
|
{
|
|
if ((eid1.m_cb != eid2.m_cb) || (eid1.m_arBytes.GetSize() != eid2.m_arBytes.GetSize()) )
|
|
return FALSE;
|
|
|
|
return 0 == memcmp(
|
|
eid1.m_arBytes.GetData(),
|
|
eid2.m_arBytes.GetData(),
|
|
eid1.m_arBytes.GetSize() );
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
void CXTPMAPIBinary::DebugPrint()
|
|
{
|
|
TRACE(_T("Bin size:%d\t"), m_cb);
|
|
for (int i = 0; i < m_arBytes.GetSize(); i++)
|
|
{
|
|
TRACE(_T("%d "), m_arBytes.GetAt(i));
|
|
}
|
|
TRACE(_T("\n"));
|
|
}
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CXTP_ID_Collection
|
|
//
|
|
|
|
CXTP_ID_Collection::CXTP_ID_Collection()
|
|
{
|
|
m_mapEventID.InitHashTable(XTP_OBJECT_CACHE_HASH_TABLE_SIZE, FALSE);
|
|
m_mapEntryID.InitHashTable(XTP_OBJECT_CACHE_HASH_TABLE_SIZE, FALSE);
|
|
}
|
|
|
|
BOOL CXTP_ID_Collection::Lookup(
|
|
const DWORD dwEventID, CXTPMAPIBinary& obEntryID)
|
|
{
|
|
return m_mapEventID.Lookup(dwEventID, obEntryID);
|
|
}
|
|
|
|
BOOL CXTP_ID_Collection::Lookup(
|
|
CXTPMAPIBinary& obEntryID, DWORD& dwEventID)
|
|
{
|
|
return m_mapEntryID.Lookup(obEntryID, dwEventID);
|
|
}
|
|
|
|
BOOL CXTP_ID_Collection::Add(
|
|
const DWORD dwEventID, CXTPMAPIBinary& obEntryID)
|
|
{
|
|
m_mapEventID.SetAt(dwEventID, obEntryID);
|
|
m_mapEntryID.SetAt(obEntryID, dwEventID);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CXTP_ID_Collection::FindMissing(CMap_EventIDs& mapExisting, CMap_EventIDs& mapMissed)
|
|
{
|
|
POSITION pos = m_mapEventID.GetStartPosition();
|
|
DWORD dwKey;
|
|
CXTPMAPIBinary eID;
|
|
BOOL bValue = FALSE;
|
|
while (pos != NULL)
|
|
{
|
|
m_mapEventID.GetNextAssoc(pos, dwKey, eID);
|
|
|
|
BOOL bFound = mapExisting.Lookup(dwKey, bValue);
|
|
if (!bFound)
|
|
{
|
|
mapMissed.SetAt(dwKey, TRUE);
|
|
}
|
|
}
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CMAPIPropIDMap
|
|
//
|
|
|
|
CXTPCalendarMAPIDataProvider::CMAPIPropIDMap::CMAPIPropIDMap()
|
|
: m_pProvider(NULL)
|
|
{
|
|
m_mapPropID2Tag.InitHashTable(199, FALSE);
|
|
m_mapPropTag2ID.InitHashTable(199, FALSE);
|
|
}
|
|
|
|
void CXTPCalendarMAPIDataProvider::CMAPIPropIDMap::_UpdateMaps(LPMESSAGE pMessage)
|
|
{
|
|
ASSERT(pMessage);
|
|
if (!pMessage)
|
|
return;
|
|
|
|
ULONG ulPropNames = 0;
|
|
LPMAPINAMEID* ppArPropNames = NULL;
|
|
LPSPropTagArray pPropTags = NULL;
|
|
|
|
HRESULT hRes = pMessage->GetPropList(0, &pPropTags);
|
|
|
|
if (SUCCEEDED(hRes) && pPropTags)
|
|
{
|
|
hRes = pMessage->GetNamesFromIDs(&pPropTags, NULL, MAPI_NO_STRINGS, &ulPropNames, &ppArPropNames);
|
|
|
|
if (SUCCEEDED(hRes) && ppArPropNames && ulPropNames)
|
|
{
|
|
ASSERT(pPropTags->cValues == ulPropNames);
|
|
XTP_TRACE_READ_IDS(_T("Prop ID -> Tag (%d)\n"), ulPropNames);
|
|
|
|
for (int i = 0; i < (int)ulPropNames; i++)
|
|
{
|
|
if (!ppArPropNames[i])
|
|
{
|
|
continue;
|
|
}
|
|
if (ppArPropNames[i]->ulKind == MNID_ID)
|
|
{
|
|
ULONG ulID = (ULONG)ppArPropNames[i]->Kind.lID;
|
|
ULONG ulTag = pPropTags->aulPropTag[i];
|
|
|
|
m_mapPropID2Tag[ulID] = ulTag;
|
|
m_mapPropTag2ID[ulTag] = ulID;
|
|
|
|
//if (ulID >= 0x8000)
|
|
{
|
|
XTP_TRACE_READ_IDS(_T("Prop ID -> Tag (%x -> %x)\n"), ulID, ulTag);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MAPI_FREEBUFFER(m_pProvider, ppArPropNames);
|
|
MAPI_FREEBUFFER(m_pProvider, pPropTags);
|
|
}
|
|
|
|
ULONG CXTPCalendarMAPIDataProvider::CMAPIPropIDMap::_GetPropTagFromID_ex(LPMESSAGE pMessage,
|
|
const XTP_MAPI_PROP_NAME& propNameEx)
|
|
{
|
|
ASSERT(pMessage);
|
|
if (!pMessage || !m_pProvider)
|
|
return 0;
|
|
|
|
ULONG ulPropTag = 0;
|
|
|
|
LPMAPINAMEID pPropName = NULL;
|
|
LPSPropTagArray pPropTag = NULL;
|
|
|
|
HRESULT hRes = m_pProvider->MAPIAllocateBuffer(sizeof(MAPINAMEID), (void**)&pPropName);
|
|
|
|
if (SUCCEEDED(hRes) && pPropName)
|
|
{
|
|
ZeroMemory(pPropName, sizeof(MAPINAMEID));
|
|
pPropName->lpguid = (LPGUID)&propNameEx.m_GuidPS;
|
|
pPropName->ulKind = MNID_ID;
|
|
pPropName->Kind.lID = propNameEx.m_ulID;
|
|
|
|
hRes = pMessage->GetIDsFromNames(1, &pPropName, MAPI_CREATE, &pPropTag);
|
|
if (SUCCEEDED(hRes) && pPropTag && pPropTag->cValues)
|
|
{
|
|
ulPropTag = pPropTag->aulPropTag[0];
|
|
|
|
// validate prop type
|
|
ulPropTag = CHANGE_PROP_TYPE(ulPropTag, propNameEx.m_ulType);
|
|
}
|
|
}
|
|
MAPI_FREEBUFFER(m_pProvider, pPropName);
|
|
MAPI_FREEBUFFER(m_pProvider, pPropTag);
|
|
|
|
return ulPropTag;
|
|
}
|
|
|
|
ULONG CXTPCalendarMAPIDataProvider::CMAPIPropIDMap::GetPropTagByID(
|
|
LPMESSAGE pMessage, const XTP_MAPI_PROP_NAME& propNameEx)
|
|
{
|
|
ULONG ulTag = 0;
|
|
|
|
if (!m_mapPropID2Tag.Lookup(propNameEx.m_ulID, ulTag))
|
|
{
|
|
_UpdateMaps(pMessage);
|
|
|
|
if (!m_mapPropID2Tag.Lookup(propNameEx.m_ulID, ulTag))
|
|
{
|
|
ulTag = _GetPropTagFromID_ex(pMessage, propNameEx);
|
|
ASSERT(ulTag); // WARNING!
|
|
if (ulTag)
|
|
{
|
|
m_mapPropID2Tag[propNameEx.m_ulID] = ulTag;
|
|
m_mapPropTag2ID[ulTag] = propNameEx.m_ulID;
|
|
|
|
return ulTag;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ulTag;
|
|
}
|
|
|
|
ULONG CXTPCalendarMAPIDataProvider::CMAPIPropIDMap::GetPropIDByTag(LPMESSAGE pMessage, ULONG ulPropTag)
|
|
{
|
|
ULONG ulID = 0;
|
|
|
|
if (!m_mapPropTag2ID.Lookup(ulPropTag, ulID))
|
|
{
|
|
_UpdateMaps(pMessage);
|
|
}
|
|
if (!m_mapPropTag2ID.Lookup(ulPropTag, ulID))
|
|
{
|
|
ulID = 0;
|
|
}
|
|
return ulID;
|
|
}
|