freebusyutil.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  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 <kopano/platform.h>
  18. #include <mapi.h>
  19. #include <mapidefs.h>
  20. #include <mapix.h>
  21. #include <mapiutil.h>
  22. #include <kopano/ECRestriction.h>
  23. #include <kopano/memory.hpp>
  24. #include "freebusyutil.h"
  25. #include <kopano/stringutil.h>
  26. #include "freebusytags.h"
  27. #include <kopano/mapiext.h>
  28. #include <edkmdb.h>
  29. using namespace KCHL;
  30. namespace KC {
  31. static bool leapyear(short year)
  32. {
  33. return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
  34. }
  35. static HRESULT getMaxMonthMinutes(short year, short month, short *minutes)
  36. {
  37. short days = 0;
  38. if(month < 0 || month >11 || year < 1601)
  39. return MAPI_E_INVALID_PARAMETER;
  40. switch(month+1)
  41. {
  42. case 1:
  43. case 3:
  44. case 5:
  45. case 7:
  46. case 8:
  47. case 10:
  48. case 12:
  49. days = 31;
  50. break;
  51. case 4:
  52. case 6:
  53. case 9:
  54. case 11:
  55. days = 30;
  56. break;
  57. case 2:
  58. days = 28;
  59. if(leapyear(year))
  60. ++days;
  61. break;
  62. }
  63. *minutes = days * (24*60);
  64. return hrSuccess;
  65. }
  66. static HRESULT GetFreeBusyFolder(IMsgStore *lpPublicStore,
  67. IMAPIFolder **lppFreeBusyFolder)
  68. {
  69. HRESULT hr = S_OK;
  70. ULONG cValuesFreeBusy = 0;
  71. memory_ptr<SPropValue> lpPropArrayFreeBusy;
  72. object_ptr<IMAPIFolder> lpMapiFolder;
  73. ULONG ulObjType = 0;
  74. static constexpr const SizedSPropTagArray(1, sPropsFreeBusy) =
  75. {1, {PR_FREE_BUSY_FOR_LOCAL_SITE_ENTRYID}};
  76. enum eFreeBusyPos{ FBPOS_FREE_BUSY_FOR_LOCAL_SITE_ENTRYID};
  77. // Get freebusy properies
  78. hr = lpPublicStore->GetProps(sPropsFreeBusy, 0, &cValuesFreeBusy, &~lpPropArrayFreeBusy);
  79. if (FAILED(hr))
  80. return hr;
  81. if(lpPropArrayFreeBusy[FBPOS_FREE_BUSY_FOR_LOCAL_SITE_ENTRYID].ulPropTag != PR_FREE_BUSY_FOR_LOCAL_SITE_ENTRYID)
  82. return MAPI_E_NOT_FOUND;
  83. hr = lpPublicStore->OpenEntry(
  84. lpPropArrayFreeBusy[FBPOS_FREE_BUSY_FOR_LOCAL_SITE_ENTRYID].Value.bin.cb,
  85. reinterpret_cast<ENTRYID *>(lpPropArrayFreeBusy[FBPOS_FREE_BUSY_FOR_LOCAL_SITE_ENTRYID].Value.bin.lpb),
  86. &IID_IMAPIFolder, MAPI_MODIFY, &ulObjType, &~lpMapiFolder);
  87. if(hr != hrSuccess)
  88. return hr;
  89. return lpMapiFolder->QueryInterface(IID_IMAPIFolder, (void**)lppFreeBusyFolder);
  90. }
  91. HRESULT GetFreeBusyMessage(IMAPISession* lpSession, IMsgStore* lpPublicStore, IMsgStore* lpUserStore, ULONG cbUserEntryID, LPENTRYID lpUserEntryID, BOOL bCreateIfNotExist, IMessage** lppMessage)
  92. {
  93. HRESULT hr = S_OK;
  94. object_ptr<IMAPIFolder> lpFreeBusyFolder;
  95. object_ptr<IMAPITable> lpMapiTable;
  96. SPropValue sPropUser;
  97. rowset_ptr lpRows;
  98. ULONG ulObjType = 0;
  99. object_ptr<IMessage> lpMessage;
  100. ULONG ulMvItems = 0;
  101. ULONG i;
  102. memory_ptr<SPropValue> lpPropfbEntryids;
  103. memory_ptr<SPropValue> lpPropfbEntryidsNew, lpPropFBMessage;
  104. memory_ptr<SPropValue> lpPropName, lpPropEmail;
  105. ULONG cbInBoxEntry = 0;
  106. memory_ptr<ENTRYID> lpInboxEntry;
  107. static constexpr const SizedSPropTagArray(1, sPropsFreebusyTable) = {1, {PR_ENTRYID}};
  108. enum eFreeBusyTablePos{ FBPOS_ENTRYID};
  109. if(lpSession == NULL || lpPublicStore == NULL || lppMessage == NULL)
  110. return MAPI_E_INVALID_PARAMETER;
  111. if(cbUserEntryID == 0 || lpUserEntryID == nullptr)
  112. return MAPI_E_INVALID_ENTRYID;
  113. // GetFreeBusyFolder
  114. hr = GetFreeBusyFolder(lpPublicStore, &~lpFreeBusyFolder);
  115. if(hr != hrSuccess)
  116. return hr;
  117. hr = lpFreeBusyFolder->GetContentsTable(0, &~lpMapiTable);
  118. if(hr != hrSuccess)
  119. return hr;
  120. sPropUser.ulPropTag = PR_ADDRESS_BOOK_ENTRYID;
  121. sPropUser.Value.bin.cb = cbUserEntryID;
  122. sPropUser.Value.bin.lpb = (LPBYTE)lpUserEntryID;
  123. hr = ECPropertyRestriction(RELOP_EQ, PR_ADDRESS_BOOK_ENTRYID, &sPropUser, ECRestriction::Cheap)
  124. .RestrictTable(lpMapiTable, TBL_BATCH);
  125. if(hr != hrSuccess)
  126. return hr;
  127. hr = lpMapiTable->SetColumns(sPropsFreebusyTable, TBL_BATCH);
  128. if(hr != hrSuccess)
  129. return hr;
  130. hr = lpMapiTable->QueryRows(1, 0, &~lpRows);
  131. if(hr != hrSuccess)
  132. return hr;
  133. if(lpRows->cRows == 1 && lpRows->aRow[0].lpProps[FBPOS_ENTRYID].ulPropTag == PR_ENTRYID)
  134. {
  135. // Open freebusy data
  136. hr = lpPublicStore->OpenEntry(lpRows->aRow[0].lpProps[FBPOS_ENTRYID].Value.bin.cb,
  137. reinterpret_cast<ENTRYID *>(lpRows->aRow[0].lpProps[FBPOS_ENTRYID].Value.bin.lpb),
  138. &IID_IMessage, MAPI_MODIFY, &ulObjType, &~lpMessage);
  139. if(hr != hrSuccess)
  140. return hr;
  141. }
  142. else if (bCreateIfNotExist == TRUE)
  143. {
  144. //Create new freebusymessage
  145. hr = lpFreeBusyFolder->CreateMessage(nullptr, 0, &~lpMessage);
  146. if(hr != hrSuccess)
  147. return hr;
  148. //Set the user entry id
  149. hr = lpMessage->SetProps(1, &sPropUser, NULL);
  150. if(hr != hrSuccess)
  151. return hr;
  152. // Set the accountname in properties PR_DISPLAY_NAME and PR_SUBJECT
  153. object_ptr<IAddrBook> lpAdrBook;
  154. hr = lpSession->OpenAddressBook(0, NULL, AB_NO_DIALOG, &~lpAdrBook);
  155. if(hr != hrSuccess)
  156. return hr;
  157. object_ptr<IMailUser> lpMailUser;
  158. hr = lpAdrBook->OpenEntry(cbUserEntryID, lpUserEntryID, &IID_IMailUser, MAPI_BEST_ACCESS, &ulObjType, &~lpMailUser);
  159. if(hr != hrSuccess)
  160. return hr;
  161. hr = HrGetOneProp(lpMailUser, PR_ACCOUNT, &~lpPropName);
  162. if(hr != hrSuccess)
  163. return hr;
  164. hr = HrGetOneProp(lpMailUser, PR_EMAIL_ADDRESS, &~lpPropEmail);
  165. if(hr != hrSuccess)
  166. return hr;
  167. //Set the displayname with accountname
  168. lpPropName->ulPropTag = PR_DISPLAY_NAME;
  169. hr = lpMessage->SetProps(1, lpPropName, NULL);
  170. if(hr != hrSuccess)
  171. return hr;
  172. //Set the subject with accountname
  173. lpPropName->ulPropTag = PR_SUBJECT;
  174. hr = lpMessage->SetProps(1, lpPropName, NULL);
  175. if(hr != hrSuccess)
  176. return hr;
  177. //Set the PR_FREEBUSY_EMA with the email address
  178. lpPropEmail->ulPropTag = PR_FREEBUSY_EMAIL_ADDRESS;
  179. hr = lpMessage->SetProps(1, lpPropEmail, NULL);
  180. if(hr != hrSuccess)
  181. return hr;
  182. //Save message
  183. hr = lpMessage->SaveChanges(KEEP_OPEN_READWRITE);
  184. if(hr != hrSuccess)
  185. return hr;
  186. // Update the user freebusy entryid array
  187. if (lpUserStore) {
  188. // Get entryid
  189. hr = HrGetOneProp(lpMessage, PR_ENTRYID, &~lpPropFBMessage);
  190. if(hr != hrSuccess)
  191. return hr;
  192. //Open root folder
  193. object_ptr<IMAPIFolder> lpFolder;
  194. hr = lpUserStore->OpenEntry(0, NULL, &IID_IMAPIFolder, MAPI_MODIFY, &ulObjType, &~lpFolder);
  195. if(hr != hrSuccess)
  196. return hr;
  197. ulMvItems = 4;
  198. // Get current freebusy entryid array
  199. if (HrGetOneProp(lpFolder, PR_FREEBUSY_ENTRYIDS, &~lpPropfbEntryids) == hrSuccess)
  200. ulMvItems = (lpPropfbEntryids->Value.MVbin.cValues>ulMvItems)?lpPropfbEntryids->Value.MVbin.cValues:ulMvItems;
  201. hr = MAPIAllocateBuffer(sizeof(SPropValue), &~lpPropfbEntryidsNew);
  202. if(hr != hrSuccess)
  203. return hr;
  204. lpPropfbEntryidsNew->Value.MVbin.cValues = ulMvItems;
  205. hr = MAPIAllocateMore(sizeof(SBinary)*lpPropfbEntryidsNew->Value.MVbin.cValues, lpPropfbEntryidsNew, (void**)&lpPropfbEntryidsNew->Value.MVbin.lpbin);
  206. if(hr != hrSuccess)
  207. return hr;
  208. memset(lpPropfbEntryidsNew->Value.MVbin.lpbin, 0, sizeof(SBinary)*lpPropfbEntryidsNew->Value.MVbin.cValues);
  209. // move the old entryids to the new array
  210. if(lpPropfbEntryids) {
  211. for (i = 0; i < lpPropfbEntryids->Value.MVbin.cValues; ++i) {
  212. lpPropfbEntryidsNew->Value.MVbin.lpbin[i].cb = lpPropfbEntryids->Value.MVbin.lpbin[i].cb;
  213. lpPropfbEntryidsNew->Value.MVbin.lpbin[i].lpb = lpPropfbEntryids->Value.MVbin.lpbin[i].lpb; //cheap copy
  214. }
  215. }
  216. // Add the new entryid on position 3
  217. lpPropfbEntryidsNew->Value.MVbin.lpbin[2].cb = lpPropFBMessage->Value.bin.cb;
  218. lpPropfbEntryidsNew->Value.MVbin.lpbin[2].lpb = lpPropFBMessage->Value.bin.lpb;
  219. lpPropfbEntryidsNew->ulPropTag = PR_FREEBUSY_ENTRYIDS;
  220. hr = lpFolder->SetProps(1, lpPropfbEntryidsNew, NULL);
  221. if(hr != hrSuccess)
  222. return hr;
  223. hr = lpFolder->SaveChanges(KEEP_OPEN_READONLY);
  224. if(hr != hrSuccess)
  225. return hr;
  226. // Get the inbox
  227. hr = lpUserStore->GetReceiveFolder(nullptr, 0, &cbInBoxEntry, &~lpInboxEntry, nullptr);
  228. if(hr != hrSuccess)
  229. return hr;
  230. // Open the inbox
  231. hr = lpUserStore->OpenEntry(cbInBoxEntry, lpInboxEntry, &IID_IMAPIFolder, MAPI_MODIFY, &ulObjType, &~lpFolder);
  232. if(hr != hrSuccess)
  233. return hr;
  234. hr = lpFolder->SetProps(1, lpPropfbEntryidsNew, NULL);
  235. if(hr != hrSuccess)
  236. return hr;
  237. hr = lpFolder->SaveChanges(KEEP_OPEN_READONLY);
  238. if(hr != hrSuccess)
  239. return hr;
  240. }
  241. }
  242. else
  243. {
  244. return MAPI_E_NOT_FOUND;
  245. }
  246. return lpMessage->QueryInterface(IID_IMessage,
  247. reinterpret_cast<void **>(lppMessage));
  248. }
  249. static HRESULT ParseFBEvents(FBStatus fbSts, LPSPropValue lpMonth,
  250. LPSPropValue lpEvent, ECFBBlockList *lpfbBlockList)
  251. {
  252. ULONG cEvents;
  253. sfbEvent* lpfbEvents = NULL;
  254. struct tm tmTmp;
  255. time_t tmUnix;
  256. LONG rtmStart;
  257. LONG rtmEnd;
  258. bool bMerge;
  259. FBBlock_1 fbBlock;
  260. // Check varibales
  261. if(lpEvent == NULL || lpMonth == NULL || lpfbBlockList == NULL ||
  262. lpEvent->Value.MVbin.cValues != lpMonth->Value.MVl.cValues)
  263. return MAPI_E_INVALID_PARAMETER;
  264. memset(&fbBlock, 0, sizeof(fbBlock));
  265. for (ULONG i = 0; i < lpEvent->Value.MVbin.cValues; ++i) {
  266. if(lpEvent->Value.MVbin.lpbin[i].cb == 0) // notting to do
  267. continue;
  268. cEvents = lpEvent->Value.MVbin.lpbin[i].cb / sizeof(sfbEvent);
  269. lpfbEvents = (sfbEvent*)lpEvent->Value.MVbin.lpbin[i].lpb;
  270. for (ULONG j = 0; j < cEvents; ++j) {
  271. memset(&tmTmp, 0, sizeof(struct tm));
  272. tmTmp.tm_year = FB_YEAR(lpMonth->Value.MVl.lpl[i]) - 1900;
  273. tmTmp.tm_mon = FB_MONTH(lpMonth->Value.MVl.lpl[i])-1;
  274. tmTmp.tm_mday = 1;
  275. tmTmp.tm_min = (int)(unsigned short)lpfbEvents[j].rtmStart;
  276. tmTmp.tm_isdst = -1;
  277. tmUnix = timegm(&tmTmp);
  278. UnixTimeToRTime(tmUnix, &rtmStart);
  279. memset(&tmTmp, 0, sizeof(struct tm));
  280. tmTmp.tm_year = FB_YEAR(lpMonth->Value.MVl.lpl[i]) - 1900;
  281. tmTmp.tm_mon = FB_MONTH(lpMonth->Value.MVl.lpl[i])-1;
  282. tmTmp.tm_mday = 1;
  283. tmTmp.tm_min = (int)(unsigned short)lpfbEvents[j].rtmEnd;
  284. tmTmp.tm_isdst = -1;
  285. tmUnix = timegm(&tmTmp);
  286. UnixTimeToRTime(tmUnix, &rtmEnd);
  287. // Don't reset fbBlock.m_tmEnd
  288. bMerge = fbBlock.m_tmEnd == rtmStart;
  289. fbBlock.m_fbstatus = fbSts;
  290. fbBlock.m_tmStart = rtmStart;
  291. fbBlock.m_tmEnd = rtmEnd;
  292. if (bMerge)
  293. lpfbBlockList->Merge(&fbBlock);
  294. else
  295. lpfbBlockList->Add(&fbBlock);
  296. }
  297. }
  298. return S_OK;
  299. }
  300. HRESULT GetFreeBusyMessageData(IMessage* lpMessage, LONG* lprtmStart, LONG* lprtmEnd, ECFBBlockList *lpfbBlockList)
  301. {
  302. HRESULT hr = S_OK;
  303. ULONG cValuesFBData = 0;
  304. memory_ptr<SPropValue> lpPropArrayFBData;
  305. static constexpr const SizedSPropTagArray(9, sPropsFreeBusyData) = {
  306. 9,
  307. {
  308. //PR_FREEBUSY_ALL_EVENTS,
  309. //PR_FREEBUSY_ALL_MONTH,
  310. PR_FREEBUSY_START_RANGE,
  311. PR_FREEBUSY_END_RANGE,
  312. PR_FREEBUSY_BUSY_EVENTS,
  313. PR_FREEBUSY_BUSY_MONTHS,
  314. PR_FREEBUSY_OOF_EVENTS,
  315. PR_FREEBUSY_OOF_MONTHS,
  316. PR_FREEBUSY_TENTATIVE_EVENTS,
  317. PR_FREEBUSY_TENTATIVE_MONTHS,
  318. PR_FREEBUSY_NUM_MONTHS
  319. }
  320. };
  321. enum eFreeBusyData {FBDATA_START_RANGE, FBDATA_END_RANGE,
  322. FBDATA_BUSY_EVENTS, FBDATA_BUSY_MONTHS,
  323. FBDATA_OOF_EVENTS, FBDATA_OOF_MONTHS,
  324. FBDATA_TENTATIVE_EVENTS, FBDATA_TENTATIVE_MONTHS,
  325. FBDATA_NUM_MONTHS
  326. };
  327. if(lpMessage == NULL || lprtmStart == NULL || lprtmEnd == NULL || lpfbBlockList == NULL)
  328. return MAPI_E_INVALID_PARAMETER;
  329. hr = lpMessage->GetProps(sPropsFreeBusyData, 0, &cValuesFBData, &~lpPropArrayFBData);
  330. if(FAILED(hr))
  331. return hr;
  332. // Get busy data
  333. if(lpPropArrayFBData[FBDATA_BUSY_EVENTS].ulPropTag == PR_FREEBUSY_BUSY_EVENTS &&
  334. lpPropArrayFBData[FBDATA_BUSY_MONTHS].ulPropTag == PR_FREEBUSY_BUSY_MONTHS)
  335. {
  336. hr = ParseFBEvents(fbBusy, &lpPropArrayFBData[FBDATA_BUSY_MONTHS], &lpPropArrayFBData[FBDATA_BUSY_EVENTS], lpfbBlockList);
  337. if(hr != hrSuccess)
  338. return hr;
  339. }
  340. // Get Tentative data
  341. if(lpPropArrayFBData[FBDATA_TENTATIVE_EVENTS].ulPropTag == PR_FREEBUSY_TENTATIVE_EVENTS &&
  342. lpPropArrayFBData[FBDATA_TENTATIVE_MONTHS].ulPropTag == PR_FREEBUSY_TENTATIVE_MONTHS)
  343. {
  344. hr = ParseFBEvents(fbTentative, &lpPropArrayFBData[FBDATA_TENTATIVE_MONTHS], &lpPropArrayFBData[FBDATA_TENTATIVE_EVENTS], lpfbBlockList);
  345. if(hr != hrSuccess)
  346. return hr;
  347. }
  348. // Get OutOfOffice data
  349. if(lpPropArrayFBData[FBDATA_OOF_EVENTS].ulPropTag == PR_FREEBUSY_OOF_EVENTS &&
  350. lpPropArrayFBData[FBDATA_OOF_MONTHS].ulPropTag == PR_FREEBUSY_OOF_MONTHS)
  351. {
  352. hr = ParseFBEvents(fbOutOfOffice, &lpPropArrayFBData[FBDATA_OOF_MONTHS], &lpPropArrayFBData[FBDATA_OOF_EVENTS], lpfbBlockList);
  353. if(hr != hrSuccess)
  354. return hr;
  355. }
  356. if (lpPropArrayFBData[FBDATA_START_RANGE].ulPropTag == PR_FREEBUSY_START_RANGE)
  357. *lprtmStart = lpPropArrayFBData[FBDATA_START_RANGE].Value.ul;
  358. else
  359. *lprtmStart = 0;
  360. if (lpPropArrayFBData[FBDATA_END_RANGE].ulPropTag == PR_FREEBUSY_END_RANGE)
  361. *lprtmEnd = lpPropArrayFBData[FBDATA_END_RANGE].Value.ul;
  362. else
  363. *lprtmEnd = 0;
  364. return hr;
  365. }
  366. unsigned int DiffYearMonthToMonth( struct tm *tm1, struct tm *tm2)
  367. {
  368. unsigned int months = 0;
  369. if(tm1->tm_year == tm2->tm_year)
  370. months = tm2->tm_mon - tm1->tm_mon;
  371. else if(tm2->tm_year > tm1->tm_year && tm2->tm_mon >= tm1->tm_mon)
  372. months = (12 * (tm2->tm_year - tm1->tm_year)) + tm2->tm_mon - tm1->tm_mon;
  373. else if(tm2->tm_year > tm1->tm_year && tm2->tm_mon < tm1->tm_mon)
  374. months = (12 * (tm2->tm_year - tm1->tm_year -1)) + (tm2->tm_mon+1) + (11-tm1->tm_mon);
  375. else
  376. months = 0;
  377. return months;
  378. }
  379. HRESULT CreateFBProp(FBStatus fbStatus, ULONG ulMonths, ULONG ulPropMonths, ULONG ulPropEvents, ECFBBlockList* lpfbBlockList, LPSPropValue* lppPropFBDataArray)
  380. {
  381. HRESULT hr = hrSuccess;
  382. ULONG ulMaxItemDataSize = 0;
  383. int i = 0;
  384. int ulDiffMonths = 0;
  385. struct tm tmStart;
  386. struct tm tmEnd;
  387. struct tm tmTmp;
  388. int ulLastMonth = 0;
  389. int ulLastYear = 0;
  390. LONG iMonth = -1;
  391. sfbEvent fbEvent;
  392. FBBlock_1 fbBlk;
  393. bool bFound;
  394. memory_ptr<SPropValue> lpPropFBDataArray;
  395. time_t tmUnixStart = 0;
  396. time_t tmUnixEnd = 0;
  397. //Check of propertys are mv
  398. if(lpfbBlockList == NULL || lppPropFBDataArray == NULL)
  399. return MAPI_E_INVALID_PARAMETER;
  400. // Set the list on the begin
  401. lpfbBlockList->Reset();
  402. ulMaxItemDataSize = (lpfbBlockList->Size() + 1 ) * sizeof(sfbEvent); // +1 block, for free/busy in two months
  403. /*
  404. First item is Months
  405. Second item is the Freebusy data
  406. */
  407. hr = MAPIAllocateBuffer(2 * sizeof(SPropValue), &~lpPropFBDataArray);
  408. if (hr != hrSuccess)
  409. return hr;
  410. lpPropFBDataArray[0].Value.MVl.cValues = 0;
  411. lpPropFBDataArray[1].Value.MVbin.cValues = 0;
  412. if ((hr = MAPIAllocateMore((ulMonths+1) * sizeof(ULONG), lpPropFBDataArray, (void**)&lpPropFBDataArray[0].Value.MVl.lpl)) != hrSuccess) // +1 for free/busy in two months
  413. return hr;
  414. if ((hr = MAPIAllocateMore((ulMonths+1) * sizeof(SBinary), lpPropFBDataArray, (void**)&lpPropFBDataArray[1].Value.MVbin.lpbin)) != hrSuccess) // +1 for free/busy in two months
  415. return hr;
  416. //memset(&lpPropFBDataArray[1].Value.MVbin.lpbin, 0, ulArrayItems);
  417. lpPropFBDataArray[0].ulPropTag = ulPropMonths;
  418. lpPropFBDataArray[1].ulPropTag = ulPropEvents;
  419. iMonth = -1;
  420. bFound = false;
  421. while (lpfbBlockList->Next(&fbBlk) == hrSuccess &&
  422. iMonth < static_cast<LONG>(ulMonths))
  423. {
  424. if(fbBlk.m_fbstatus == fbStatus || fbStatus == fbKopanoAllBusy)
  425. {
  426. RTimeToUnixTime(fbBlk.m_tmStart, &tmUnixStart);
  427. RTimeToUnixTime(fbBlk.m_tmEnd, &tmUnixEnd);
  428. gmtime_safe(&tmUnixStart, &tmStart);
  429. gmtime_safe(&tmUnixEnd, &tmEnd);
  430. if(tmStart.tm_year > ulLastYear || tmStart.tm_mon > ulLastMonth)
  431. {
  432. ++iMonth;
  433. lpPropFBDataArray[0].Value.MVl.lpl[iMonth] = FB_YEARMONTH((tmStart.tm_year+1900), (tmStart.tm_mon+1));
  434. ++lpPropFBDataArray[0].Value.MVl.cValues;
  435. ++lpPropFBDataArray[1].Value.MVbin.cValues;
  436. if ((hr = MAPIAllocateMore(ulMaxItemDataSize, lpPropFBDataArray, (void**)&lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].lpb)) != hrSuccess)
  437. return hr;
  438. lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb = 0;
  439. }
  440. //Different months in a block
  441. if(tmEnd.tm_year > tmStart.tm_year || tmEnd.tm_mon > tmStart.tm_mon)
  442. {
  443. fbEvent.rtmStart = (short)( ((tmStart.tm_mday-1)*24*60) + (tmStart.tm_hour*60) + tmStart.tm_min);
  444. getMaxMonthMinutes((short)tmStart.tm_year+1900, (short)tmStart.tm_mon, (short*)&fbEvent.rtmEnd);
  445. // Add item to struct
  446. memcpy(lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].lpb+lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb, &fbEvent, sizeof(sfbEvent));
  447. lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb += sizeof(sfbEvent);
  448. assert(lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb <= ulMaxItemDataSize);
  449. ulDiffMonths = DiffYearMonthToMonth(&tmStart, &tmEnd);
  450. tmTmp = tmStart;
  451. // Set the day on the begin of the month because: if mday is 31 and the next month is 30 then you get the wrong month
  452. tmTmp.tm_mday = 1;
  453. for (i = 1; i < ulDiffMonths && lpPropFBDataArray[0].Value.MVl.cValues < ulMonths; ++i) {
  454. ++iMonth;
  455. tmTmp.tm_isdst = -1;
  456. ++tmTmp.tm_mon;
  457. mktime(&tmTmp);
  458. lpPropFBDataArray[0].Value.MVl.lpl[iMonth] = FB_YEARMONTH((tmTmp.tm_year+1900), (tmTmp.tm_mon+1));
  459. ++lpPropFBDataArray[0].Value.MVl.cValues;
  460. ++lpPropFBDataArray[1].Value.MVbin.cValues;
  461. if ((hr = MAPIAllocateMore(ulMaxItemDataSize, lpPropFBDataArray, (void**)&lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].lpb)) != hrSuccess)
  462. return hr;
  463. lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb = 0;
  464. fbEvent.rtmStart = 0;
  465. getMaxMonthMinutes((short)tmTmp.tm_year+1900, (short)tmTmp.tm_mon, (short*)&fbEvent.rtmEnd);
  466. // Add item to struct
  467. memcpy(lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].lpb+lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb, &fbEvent, sizeof(sfbEvent));
  468. lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb += sizeof(sfbEvent);
  469. assert(lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb <= ulMaxItemDataSize);
  470. }
  471. ++iMonth;
  472. ++tmTmp.tm_mon;
  473. tmTmp.tm_isdst = -1;
  474. mktime(&tmTmp);
  475. lpPropFBDataArray[0].Value.MVl.lpl[iMonth] = FB_YEARMONTH((tmTmp.tm_year+1900), (tmTmp.tm_mon+1));
  476. ++lpPropFBDataArray[0].Value.MVl.cValues;
  477. ++lpPropFBDataArray[1].Value.MVbin.cValues;
  478. if ((hr = MAPIAllocateMore(ulMaxItemDataSize, lpPropFBDataArray, (void**)&lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].lpb)) != hrSuccess)
  479. return hr;
  480. lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb = 0;
  481. fbEvent.rtmStart = 0;
  482. fbEvent.rtmEnd = (short)( ((tmEnd.tm_mday-1)*24*60) + (tmEnd.tm_hour*60) + tmEnd.tm_min);
  483. } else {
  484. fbEvent.rtmStart = (short)( ((tmStart.tm_mday-1)*24*60) + (tmStart.tm_hour*60) + tmStart.tm_min);
  485. fbEvent.rtmEnd = (short)( ((tmEnd.tm_mday-1)*24*60) + (tmEnd.tm_hour*60) + tmEnd.tm_min);
  486. }
  487. // Add item to struct
  488. memcpy(lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].lpb+lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb, &fbEvent, sizeof(sfbEvent));
  489. lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb += sizeof(sfbEvent);
  490. ulLastYear = tmEnd.tm_year;
  491. ulLastMonth = tmEnd.tm_mon;
  492. bFound = true;
  493. assert(lpPropFBDataArray[1].Value.MVbin.lpbin[iMonth].cb <= ulMaxItemDataSize);
  494. }
  495. assert(iMonth == -1 || (iMonth >= 0 && static_cast<ULONG>(iMonth) < ulMonths + 1));
  496. assert(lpPropFBDataArray[1].Value.MVbin.cValues <= ulMonths + 1);
  497. assert(lpPropFBDataArray[0].Value.MVl.cValues <= ulMonths + 1);
  498. }
  499. if(bFound == false)
  500. return MAPI_E_NOT_FOUND;
  501. *lppPropFBDataArray = lpPropFBDataArray.release();
  502. return hr;
  503. }
  504. /**
  505. * Copies a array of occurrence to another array
  506. * @param[out] lpDest destination array
  507. * @param[in] lpSrc source array
  508. * @param[in] ulcValues number of occurrence in source array
  509. *
  510. * @return HRESULT
  511. */
  512. static HRESULT HrCopyFBBlockSet(OccrInfo *lpDest, const OccrInfo *lpSrc,
  513. ULONG ulcValues)
  514. {
  515. HRESULT hr = hrSuccess;
  516. ULONG i = 0;
  517. for (i = 0; i < ulcValues; ++i)
  518. lpDest[i] = lpSrc[i];
  519. return hr;
  520. }
  521. /**
  522. * Adds a occurrence to the occurrence array
  523. * @param[in] sOccrInfo occurrence to be added to array
  524. * @param[in,out] lppsOccrInfo array to which occurrence is added
  525. * @param[out] lpcValues number of occurrences in array
  526. * @return HRESULT
  527. */
  528. HRESULT HrAddFBBlock(const OccrInfo &sOccrInfo, OccrInfo **lppsOccrInfo,
  529. ULONG *lpcValues)
  530. {
  531. memory_ptr<OccrInfo> lpsNewOccrInfo;
  532. OccrInfo *lpsInputOccrInfo = *lppsOccrInfo;
  533. ULONG ulModVal = lpcValues != NULL ? *lpcValues + 1 : 1;
  534. HRESULT hr = MAPIAllocateBuffer(sizeof(sOccrInfo) * ulModVal, &~lpsNewOccrInfo);
  535. if (hr != hrSuccess)
  536. return hr;
  537. if(lpsInputOccrInfo)
  538. hr = HrCopyFBBlockSet(lpsNewOccrInfo, lpsInputOccrInfo, ulModVal);
  539. if (hr != hrSuccess)
  540. return hr;
  541. if (lpcValues != NULL)
  542. *lpcValues = ulModVal;
  543. lpsNewOccrInfo[ulModVal -1] = sOccrInfo;
  544. *lppsOccrInfo = lpsNewOccrInfo.release();
  545. MAPIFreeBuffer(lpsInputOccrInfo);
  546. return hrSuccess;
  547. }
  548. } /* namespace */