ECFreeBusyData.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <new>
  18. #include <kopano/platform.h>
  19. #include <kopano/ECInterfaceDefs.h>
  20. #include <kopano/memory.hpp>
  21. #include "ECFreeBusyData.h"
  22. #include "ECEnumFBBlock.h"
  23. namespace KC {
  24. ECFreeBusyData::ECFreeBusyData(void)
  25. {
  26. m_rtmStart = 0;
  27. m_rtmEnd = 0;
  28. }
  29. HRESULT ECFreeBusyData::Init(LONG rtmStart, LONG rtmEnd, ECFBBlockList* lpfbBlockList)
  30. {
  31. if(lpfbBlockList == NULL)
  32. return MAPI_E_INVALID_PARAMETER;
  33. m_rtmStart = rtmStart;
  34. m_rtmEnd = rtmEnd;
  35. m_fbBlockList.Copy(lpfbBlockList);
  36. // Update the start time if missing.
  37. if (m_rtmStart == 0) {
  38. FBBlock_1 blk;
  39. if (m_fbBlockList.Next(&blk) == hrSuccess)
  40. m_rtmStart = blk.m_tmStart;
  41. m_fbBlockList.Reset();
  42. }
  43. // Update the end time if missing.
  44. if (m_rtmEnd == 0)
  45. m_fbBlockList.GetEndTime(&m_rtmEnd);
  46. return hrSuccess;
  47. }
  48. HRESULT ECFreeBusyData::Create(ECFreeBusyData **lppECFreeBusyData)
  49. {
  50. HRESULT hr = hrSuccess;
  51. auto lpECFreeBusyData = new(std::nothrow) ECFreeBusyData;
  52. if (lpECFreeBusyData == nullptr)
  53. return MAPI_E_NOT_ENOUGH_MEMORY;
  54. hr = lpECFreeBusyData->QueryInterface(IID_ECFreeBusyData, (void **)lppECFreeBusyData);
  55. if(hr != hrSuccess)
  56. delete lpECFreeBusyData;
  57. return hr;
  58. }
  59. HRESULT ECFreeBusyData::QueryInterface(REFIID refiid, void** lppInterface)
  60. {
  61. REGISTER_INTERFACE2(ECFreeBusyData, this);
  62. REGISTER_INTERFACE2(ECUnknown, this);
  63. REGISTER_INTERFACE2(IFreeBusyData, &this->m_xFreeBusyData);
  64. REGISTER_INTERFACE(IID_ECUnknown, &this->m_xFreeBusyData);
  65. /*NEW*/ REGISTER_INTERFACE2(IUnknown, &this->m_xFreeBusyData);
  66. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  67. }
  68. HRESULT ECFreeBusyData::EnumBlocks(IEnumFBBlock **ppenumfb, FILETIME ftmStart, FILETIME ftmEnd)
  69. {
  70. HRESULT hr = S_OK;
  71. LONG rtmStart = 0;
  72. LONG rtmEnd = 0;
  73. KCHL::object_ptr<ECEnumFBBlock> lpECEnumFBBlock;
  74. if(ppenumfb == NULL)
  75. return MAPI_E_INVALID_PARAMETER;
  76. FileTimeToRTime(&ftmStart, &rtmStart);
  77. FileTimeToRTime(&ftmEnd, &rtmEnd);
  78. hr = m_fbBlockList.Restrict(rtmStart, rtmEnd);
  79. if(hr != hrSuccess)
  80. return hr;
  81. hr = ECEnumFBBlock::Create(&m_fbBlockList, &~lpECEnumFBBlock);
  82. if(hr != hrSuccess)
  83. return hr;
  84. return lpECEnumFBBlock->QueryInterface(IID_IEnumFBBlock, (void**)ppenumfb);
  85. }
  86. /**
  87. * Documentation of this function cannot be found. This is what I think it does.
  88. *
  89. * Find first free block inside the specified range <ulBegin,ulEnd]. Note that ulBegin is non-inclusive, so
  90. * the earliest block that can be returned is starts at ulBegin + 1.
  91. *
  92. * I think that this function should normally look for the first position in the given range in which the specified
  93. * duration (ulMinutes) fits. However, in practice, it is only called to check if range <ulBegin, ulEnd] is free, since
  94. * ulEnd - ulBegin - 1 == ulMinutes. This means we can use a much simpler algorithm, and just check if the entire range
  95. * is free, and return that if it is.
  96. *
  97. * It is my theory that someone made this function, but later found out that it is not very useful since you always want to
  98. * find a specific slot, not the first slot that fits, so now it is only used to check for availability.
  99. *
  100. * @param ulBegin Begin time as RTIME
  101. * @param ulMinutes Duration of the slot to find
  102. * @param ulNumber (Guess) Number of resources that should be free at this moment (always one in my tests)
  103. * @param bA (Unknown) always TRUE
  104. * @param ulEnd End time as RTIME
  105. * @param ulUnknown Unknown, always 0
  106. * @param ulMinutesPerDay Unknown, always set to 1440 ( = 24 * 60 )
  107. * @result 0 for OK, anything else is an error
  108. */
  109. HRESULT ECFreeBusyData::FindFreeBlock(LONG ulBegin, LONG ulMinutes, LONG ulNumber, BOOL bA, LONG ulEnd, LONG ulUnknown, LONG ulMinutesPerDay, FBBlock_1 *lpBlock)
  110. {
  111. HRESULT hr;
  112. FBBlock_1 sBlock;
  113. BOOL bOverlap = false;
  114. if (ulBegin + 1 + ulMinutes > ulEnd)
  115. // Requested slot can never fit between start and end
  116. return MAPI_E_NOT_FOUND;
  117. m_fbBlockList.Reset();
  118. // Loop through FB data to find if there is a block that overlaps the requested slot
  119. while(TRUE) {
  120. hr = m_fbBlockList.Next(&sBlock);
  121. if(hr != hrSuccess)
  122. break;
  123. if(sBlock.m_tmStart >= ulEnd)
  124. break;
  125. if(sBlock.m_tmEnd > ulBegin+1 && sBlock.m_tmStart < ulEnd) {
  126. bOverlap = true;
  127. break;
  128. }
  129. }
  130. if (bOverlap)
  131. return MAPI_E_NOT_FOUND;
  132. lpBlock->m_fbstatus = fbFree;
  133. lpBlock->m_tmStart = ulBegin+1;
  134. lpBlock->m_tmEnd = lpBlock->m_tmStart + ulMinutes;
  135. return hrSuccess;
  136. }
  137. HRESULT ECFreeBusyData::SetFBRange(LONG rtmStart, LONG rtmEnd)
  138. {
  139. m_rtmStart = rtmStart;
  140. m_rtmEnd = rtmEnd;
  141. return S_OK;
  142. }
  143. HRESULT ECFreeBusyData::GetFBPublishRange(LONG *prtmStart, LONG *prtmEnd)
  144. {
  145. if(prtmStart == NULL || prtmEnd == NULL)
  146. return MAPI_E_INVALID_PARAMETER;
  147. *prtmStart = m_rtmStart;
  148. *prtmEnd = m_rtmEnd;
  149. return S_OK;
  150. }
  151. DEF_HRMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, QueryInterface, (REFIID, refiid), (void**, lppInterface))
  152. DEF_ULONGMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, AddRef, (void))
  153. DEF_ULONGMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, Release, (void))
  154. DEF_HRMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, Reload, (void*, lpData))
  155. DEF_HRMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, EnumBlocks, (IEnumFBBlock **, ppenumfb), (FILETIME, ftmStart), (FILETIME, ftmEnd))
  156. DEF_HRMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, Merge, (void*, lpData))
  157. DEF_HRMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, GetDelegateInfo, (void*, lpData))
  158. DEF_HRMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, FindFreeBlock, (LONG, ulBegin), (LONG, ulMinutes), (LONG, ulNumber), (BOOL, bA), (LONG, ulEnd), (LONG, ulUnknown), (LONG, ulMinutesPerDay), (FBBlock_1 *, lpData))
  159. DEF_HRMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, InterSect, (void *, lpData1), (LONG, ulA), (void *, lpData2))
  160. DEF_HRMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, SetFBRange, (LONG, rtmStart), (LONG, rtmEnd))
  161. DEF_HRMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, NextFBAppt, (void *, lpData1), (ULONG, ulA), (void *, lpData2), (ULONG, ulB), (void *, lpData3), (void *, lpData4))
  162. DEF_HRMETHOD1(TRACE_MAPI, ECFreeBusyData, FreeBusyData, GetFBPublishRange, (LONG *, prtmStart), (LONG *, prtmEnd))
  163. } /* namespace */