// 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 _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 _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(rpData, pMax); UNUSED_ALWAYS(nBuffer); int nStrLen = (int)xtpGetNextDataT(rpData, pMax); if (pMax && (rpData + nStrLen) > pMax) { ASSERT(FALSE); return _T(""); } CString strData = CString((char*)rpData, nStrLen); rpData += nStrLen; return strData; } //=========================================================================== template 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 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(rarData, 1); xtpAddDataT(rarData, 0); return; } ZeroMemory(pStr, nStrSize); WCSTOMBS_S(pStr, pcszString, nStrSize-1); int nStrLen = (int)strlen(pStr); int nBuffer = nStrLen + 1; xtpAddDataT(rarData, (WORD)nBuffer); xtpAddDataT(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 { 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(arRCData, s_arRCDataLayout[0].nType); eRCType2 = (XTPCalendarMAPIRcType2)xtpGetDataT(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(arRCData, RCLayout.nType); rRCData.ucType2 = xtpGetDataT(arRCData, RCLayout.nType2); rRCData.dwRCShiftX = xtpGetDataT(arRCData, RCLayout.nRCShiftX); rRCData.dwInterval = xtpGetDataT(arRCData, RCLayout.nInterval); rRCData.dwWeekDayMask = xtpGetDataT(arRCData, RCLayout.nWeekDayMask); rRCData.ucInstance = xtpGetDataT(arRCData, RCLayout.nInstance); rRCData.dwEndByType = xtpGetDataT(arRCData, RCLayout.nEndByType); rRCData.dwOccurrences = xtpGetDataT(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(p, pMax)); // skip old start dates p += sizeof(DWORD) * (xtpGetNextDataT(p, pMax)); // old new start dates // pick up start/end dates //Pattern Start Date rRCData.dwStartDate = xtpGetNextDataT(p, pMax); // /*DBG*/ ConvertRecurrenceMinutesToDate(rRCData.dwStartDate); //Pattern End Date rRCData.dwEndDate = xtpGetNextDataT(p, pMax); // /*DBG*/ ConvertRecurrenceMinutesToDate(rRCData.dwEndDate); // skip unknown reserved fields xtpGetNextDataT(p, pMax); xtpGetNextDataT(p, pMax); // Occurrence start/end time - in minutes from the day begin // hour = time / 60, minute = time % 60 rRCData.dwOccStartTime = xtpGetNextDataT(p, pMax); rRCData.dwOccEndTime = xtpGetNextDataT(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(pExcData, pMaxPtr); int i; for (i = 0; i < nCount; i++) { CXTPRcException RCExc; RCExc.dwNewStart = xtpGetNextDataT(pExcData, pMaxPtr); RCExc.dwNewEnd = xtpGetNextDataT(pExcData, pMaxPtr); RCExc.dwOrigStart = xtpGetNextDataT(pExcData, pMaxPtr); RCExc.wFlags = xtpGetNextDataT(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(pExcData, pMaxPtr) != 0; } if (RCExc.wFlags & xtpMAPIRcED_ReminderTime) { // layout: [dw] minutes before start RCExc.nReminderTime = xtpGetNextDataT(pExcData, pMaxPtr); } if (RCExc.wFlags & xtpMAPIRcED_IsReminder) { // layout: [dw] - bool(0|1) RCExc.bIsReminder = xtpGetNextDataT(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(pExcData, pMaxPtr); } if (RCExc.wFlags & xtpMAPIRcED_IsAllDay) { // layout: [dw] - bool(0|1) RCExc.bIsAllDay = xtpGetNextDataT(pExcData, pMaxPtr) != 0; } if (RCExc.wFlags & xtpMAPIRcED_Label) { // layout: [dw] - RCExc.nLabel = xtpGetNextDataT(pExcData, pMaxPtr); } rRCData.arExceptions.Add(RCExc); } ASSERT(rRCData.dwOccEndTime >= rRCData.dwOccStartTime); // determine and add deleted exceptions nCount = (int)xtpGetNextDataT(pExclusions, pMaxPtr); for (i = 0; i < nCount; i++) { CXTPRcException RCExc; RCExc.dwOrigStart = xtpGetNextDataT(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(rarData, 0, 0x30043004); // Set generic recurrence fields xtpSetDataT (rarData, RCLayout.nType, RCData.wType); xtpSetDataT (rarData, RCLayout.nType2, RCData.ucType2); xtpSetDataT(rarData, RCLayout.nRCShiftX, RCData.dwRCShiftX); xtpSetDataT(rarData, RCLayout.nInterval, RCData.dwInterval); xtpSetDataT(rarData, RCLayout.nWeekDayMask, RCData.dwWeekDayMask); xtpSetDataT (rarData, RCLayout.nInstance, RCData.ucInstance); xtpSetDataT(rarData, RCLayout.nEndByType, RCData.dwEndByType); xtpSetDataT(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(rarData, nExcCount); for (i = 0; i < nExcCount; i++) { const CXTPRcException& rce = RCData.arExceptions[i]; DWORD dwOrigSartDate = (rce.dwOrigStart / 24 / 60) * 24 * 60; xtpAddDataT(rarData, dwOrigSartDate); } //- add changed exception dates ----------------------------------------- RCData.arExceptions.SortByNewStart(); int nChangExcCountOffset = (int)rarData.GetSize(); xtpAddDataT(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(rarData, dwNewSartDate); dwChangExcCount++; } } xtpSetDataT(rarData, nChangExcCountOffset, dwChangExcCount); // start/end date xtpAddDataT(rarData, RCData.dwStartDate); if (RCData.dwEndByType == xtpMAPIRcEnd_Date || RCData.dwEndByType == xtpMAPIRcEnd_Number) { xtpAddDataT(rarData, RCData.dwEndDate); } else { ASSERT(RCData.dwEndByType == xtpMAPIRcEnd_Never); xtpAddDataT(rarData, 0x5AE980DF); } // unknown xtpAddDataT(rarData, 0x00003006); xtpAddDataT(rarData, 0x00003006); // start/end time xtpAddDataT(rarData, RCData.dwOccStartTime); xtpAddDataT(rarData, RCData.dwOccEndTime); // detailed exceptions xtpAddDataT(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(rarData, rce.dwNewStart); xtpAddDataT(rarData, rce.dwNewEnd); xtpAddDataT(rarData, rce.dwOrigStart); xtpAddDataT(rarData, rce.wFlags); if (rce.wFlags & xtpMAPIRcED_Subject) { xtpAddData_MapiExcStr8(rarData, rce.strSubject); } if (rce.wFlags & xtpMAPIRcED_IsMeeting) { // layout: [dw] - bool(0|1) xtpAddDataT(rarData, rce.bIsMeeting); } if (rce.wFlags & xtpMAPIRcED_ReminderTime) { // layout: [dw] minutes before start xtpAddDataT(rarData, rce.nReminderTime); } if (rce.wFlags & xtpMAPIRcED_IsReminder) { // layout: [dw] - bool(0|1) xtpAddDataT(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(rarData, rce.nBusyStatus); } if (rce.wFlags & xtpMAPIRcED_IsAllDay) { // layout: [dw] - bool(0|1) xtpAddDataT(rarData, rce.bIsAllDay); } if (rce.wFlags & xtpMAPIRcED_Label) { // layout: [dw] - xtpAddDataT(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 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 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 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 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 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; }