fsck-calendar.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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 <iostream>
  19. #include <utility>
  20. #include <kopano/CommonUtil.h>
  21. #include <kopano/mapiext.h>
  22. #include <kopano/mapiguidext.h>
  23. #include <kopano/memory.hpp>
  24. #include <mapiutil.h>
  25. #include <mapix.h>
  26. #include <kopano/namedprops.h>
  27. #include <kopano/charset/convert.h>
  28. #include <kopano/RecurrenceState.h>
  29. #include "fsck.h"
  30. using namespace KCHL;
  31. HRESULT FsckCalendar::ValidateMinimalNamedFields(LPMESSAGE lpMessage)
  32. {
  33. HRESULT hr = hrSuccess;
  34. memory_ptr<SPropValue> lpPropertyArray;
  35. memory_ptr<SPropTagArray> lpPropertyTagArray;
  36. memory_ptr<MAPINAMEID *> lppTagArray;
  37. enum {
  38. E_REMINDER,
  39. E_ALLDAYEVENT,
  40. TAG_COUNT
  41. };
  42. std::string strTagName[TAG_COUNT];
  43. /*
  44. * Allocate the NamedID list and initialize it to all
  45. * properties which could give us some information about the name.
  46. */
  47. hr = allocNamedIdList(TAG_COUNT, &~lppTagArray);
  48. if (hr != hrSuccess)
  49. return hr;
  50. lppTagArray[E_REMINDER]->lpguid = (LPGUID)&PSETID_Common;
  51. lppTagArray[E_REMINDER]->ulKind = MNID_ID;
  52. lppTagArray[E_REMINDER]->Kind.lID = dispidReminderSet;
  53. lppTagArray[E_ALLDAYEVENT]->lpguid = (LPGUID)&PSETID_Appointment;
  54. lppTagArray[E_ALLDAYEVENT]->ulKind = MNID_ID;
  55. lppTagArray[E_ALLDAYEVENT]->Kind.lID = dispidAllDayEvent;
  56. strTagName[E_REMINDER] = "dispidReminderSet";
  57. strTagName[E_ALLDAYEVENT] = "dispidAllDayEvent";
  58. hr = ReadNamedProperties(lpMessage, TAG_COUNT, lppTagArray,
  59. &~lpPropertyTagArray, &~lpPropertyArray);
  60. if (FAILED(hr))
  61. return hr;
  62. for (ULONG i = 0; i < TAG_COUNT; ++i) {
  63. if (PROP_TYPE(lpPropertyArray[i].ulPropTag) == PT_ERROR) {
  64. __UPV Value;
  65. Value.b = false;
  66. hr = AddMissingProperty(lpMessage, strTagName[i],
  67. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[i], PT_BOOLEAN),
  68. Value);
  69. if (hr != hrSuccess)
  70. return hr;
  71. }
  72. }
  73. return hrSuccess;
  74. }
  75. HRESULT FsckCalendar::ValidateTimestamps(LPMESSAGE lpMessage)
  76. {
  77. HRESULT hr = hrSuccess;
  78. memory_ptr<SPropValue> lpPropertyArray;
  79. memory_ptr<SPropTagArray> lpPropertyTagArray;
  80. memory_ptr<MAPINAMEID *> lppTagArray;
  81. const FILETIME *lpStart, *lpEnd, *lpCommonStart, *lpCommonEnd;
  82. LONG ulDuration;
  83. enum {
  84. E_START,
  85. E_END,
  86. E_CSTART,
  87. E_CEND,
  88. E_DURATION,
  89. TAG_COUNT
  90. };
  91. /*
  92. * Allocate the NamedID list and initialize it to all
  93. * properties which could give us some information about the name.
  94. */
  95. hr = allocNamedIdList(TAG_COUNT, &~lppTagArray);
  96. if (hr != hrSuccess)
  97. return hr;
  98. lppTagArray[E_START]->lpguid = (LPGUID)&PSETID_Appointment;
  99. lppTagArray[E_START]->ulKind = MNID_ID;
  100. lppTagArray[E_START]->Kind.lID = dispidApptStartWhole;
  101. lppTagArray[E_END]->lpguid = (LPGUID)&PSETID_Appointment;
  102. lppTagArray[E_END]->ulKind = MNID_ID;
  103. lppTagArray[E_END]->Kind.lID = dispidApptEndWhole;
  104. lppTagArray[E_CSTART]->lpguid = (LPGUID)&PSETID_Common;
  105. lppTagArray[E_CSTART]->ulKind = MNID_ID;
  106. lppTagArray[E_CSTART]->Kind.lID = dispidCommonStart;
  107. lppTagArray[E_CEND]->lpguid = (LPGUID)&PSETID_Common;
  108. lppTagArray[E_CEND]->ulKind = MNID_ID;
  109. lppTagArray[E_CEND]->Kind.lID = dispidCommonEnd;
  110. lppTagArray[E_DURATION]->lpguid = (LPGUID)&PSETID_Appointment;
  111. lppTagArray[E_DURATION]->ulKind = MNID_ID;
  112. lppTagArray[E_DURATION]->Kind.lID = dispidApptDuration;
  113. hr = ReadNamedProperties(lpMessage, TAG_COUNT, lppTagArray,
  114. &~lpPropertyTagArray, &~lpPropertyArray);
  115. if (FAILED(hr))
  116. return hr;
  117. /*
  118. * Validate parameters:
  119. * If E_START is missing it can be substituted with E_CSTART and vice versa
  120. * If E_END is missing it can be substituted with E_CEND and vice versa
  121. * E_{C}START < E_{C}END
  122. * E_{C}END - E_{C}START / 60 = Duration
  123. * If duration is missing, calculate and set it.
  124. */
  125. if (PROP_TYPE(lpPropertyArray[E_START].ulPropTag) == PT_ERROR) {
  126. if (PROP_TYPE(lpPropertyArray[E_CSTART].ulPropTag) == PT_ERROR) {
  127. std::cout << "No valid starting address could be detected." << std::endl;
  128. return E_INVALIDARG;
  129. }
  130. hr = AddMissingProperty(lpMessage, "dispidApptStartWhole",
  131. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_START], PT_SYSTIME),
  132. lpPropertyArray[E_CSTART].Value);
  133. if (hr != hrSuccess)
  134. return hr;
  135. lpStart = &lpPropertyArray[E_CSTART].Value.ft;
  136. } else
  137. lpStart = &lpPropertyArray[E_START].Value.ft;
  138. if (PROP_TYPE(lpPropertyArray[E_CSTART].ulPropTag) == PT_ERROR) {
  139. if (PROP_TYPE(lpPropertyArray[E_START].ulPropTag) == PT_ERROR) {
  140. std::cout << "No valid starting address could be detected." << std::endl;
  141. return E_INVALIDARG;
  142. }
  143. hr = AddMissingProperty(lpMessage, "dispidCommonStart",
  144. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_CSTART], PT_SYSTIME),
  145. lpPropertyArray[E_START].Value);
  146. if (hr != hrSuccess)
  147. return hr;
  148. lpCommonStart = &lpPropertyArray[E_START].Value.ft;
  149. } else
  150. lpCommonStart = &lpPropertyArray[E_CSTART].Value.ft;
  151. if (PROP_TYPE(lpPropertyArray[E_END].ulPropTag) == PT_ERROR) {
  152. if (PROP_TYPE(lpPropertyArray[E_CEND].ulPropTag) == PT_ERROR) {
  153. std::cout << "No valid end address could be detected." << std::endl;
  154. return E_INVALIDARG;
  155. }
  156. hr = AddMissingProperty(lpMessage, "dispidApptEndWhole",
  157. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_END], PT_SYSTIME),
  158. lpPropertyArray[E_CEND].Value);
  159. if (hr != hrSuccess)
  160. return hr;
  161. lpEnd = &lpPropertyArray[E_CEND].Value.ft;
  162. } else
  163. lpEnd = &lpPropertyArray[E_END].Value.ft;
  164. if (PROP_TYPE(lpPropertyArray[E_CEND].ulPropTag) == PT_ERROR) {
  165. if (PROP_TYPE(lpPropertyArray[E_END].ulPropTag) == PT_ERROR) {
  166. std::cout << "No valid starting address could be detected." << std::endl;
  167. return E_INVALIDARG;
  168. }
  169. hr = AddMissingProperty(lpMessage, "dispidCommonEnd",
  170. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_CEND], PT_SYSTIME),
  171. lpPropertyArray[E_END].Value);
  172. if (hr != hrSuccess)
  173. return hr;
  174. lpCommonEnd = &lpPropertyArray[E_END].Value.ft;
  175. } else
  176. lpCommonEnd = &lpPropertyArray[E_CEND].Value.ft;
  177. if (*lpStart > *lpEnd && *lpCommonStart < *lpCommonEnd) {
  178. hr = ReplaceProperty(lpMessage, "dispidApptStartWhole",
  179. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_START], PT_SYSTIME),
  180. "Whole start after whole end date.",
  181. lpPropertyArray[E_CSTART].Value);
  182. if (hr != hrSuccess)
  183. return hr;
  184. hr = ReplaceProperty(lpMessage, "dispidApptEndWhole",
  185. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_END], PT_SYSTIME),
  186. "Whole start after whole end date.",
  187. lpPropertyArray[E_CEND].Value);
  188. if (hr != hrSuccess)
  189. return hr;
  190. }
  191. if (*lpCommonStart > *lpCommonEnd && *lpStart < *lpEnd) {
  192. hr = ReplaceProperty(lpMessage, "dispidCommonStart",
  193. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_CSTART], PT_SYSTIME),
  194. "Common start after common end date.",
  195. lpPropertyArray[E_START].Value);
  196. if (hr != hrSuccess)
  197. return hr;
  198. hr = ReplaceProperty(lpMessage, "dispidCommonEnd",
  199. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_CEND], PT_SYSTIME),
  200. "Common start after common end date.",
  201. lpPropertyArray[E_END].Value);
  202. if (hr != hrSuccess)
  203. return hr;
  204. }
  205. if ((*lpEnd - *lpStart) != (*lpCommonEnd - *lpCommonStart)) {
  206. std::cout << "Difference in duration: " << endl;
  207. std::cout << "Common duration (" << (*lpCommonEnd - *lpCommonStart) << ") ";
  208. std::cout << "- Whole duration (" << (*lpEnd - *lpStart) << ")" <<std::endl;
  209. return E_INVALIDARG;
  210. }
  211. /*
  212. * Common duration matches whole duration,
  213. * now we need to compare the duration itself.
  214. */
  215. __UPV Value;
  216. Value.l = (*lpEnd - *lpStart) / 60;
  217. if (PROP_TYPE(lpPropertyArray[E_DURATION].ulPropTag) == PT_ERROR)
  218. return AddMissingProperty(lpMessage, "dispidApptDuration",
  219. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_DURATION], PT_LONG),
  220. Value);
  221. ulDuration = lpPropertyArray[E_DURATION].Value.l;
  222. /*
  223. * We already compared duration between common and start,
  224. * now we have to check if that duration also equals what was set.
  225. */
  226. if (ulDuration != Value.l)
  227. return ReplaceProperty(lpMessage, "dispidApptDuration",
  228. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_DURATION], PT_LONG),
  229. "Duration does not match (End - Start / 60)",
  230. Value);
  231. return hrSuccess;
  232. }
  233. HRESULT FsckCalendar::ValidateRecurrence(LPMESSAGE lpMessage)
  234. {
  235. HRESULT hr = hrSuccess;
  236. memory_ptr<SPropValue> lpPropertyArray;
  237. memory_ptr<SPropTagArray> lpPropertyTagArray;
  238. BOOL bRecurring = FALSE;
  239. LONG ulType = 0;
  240. memory_ptr<char> lpData;
  241. memory_ptr<MAPINAMEID *> lppTagArray;
  242. unsigned int ulLen = 0;
  243. enum {
  244. E_RECURRENCE,
  245. E_RECURRENCE_TYPE,
  246. E_RECURRENCE_PATTERN,
  247. E_RECURRENCE_STATE,
  248. TAG_COUNT
  249. };
  250. /*
  251. * Allocate the NamedID list and initialize it to all
  252. * properties which could give us some information about the name.
  253. */
  254. hr = allocNamedIdList(TAG_COUNT, &~lppTagArray);
  255. if (hr != hrSuccess)
  256. return hr;
  257. lppTagArray[E_RECURRENCE]->lpguid = (LPGUID)&PSETID_Appointment;
  258. lppTagArray[E_RECURRENCE]->ulKind = MNID_ID;
  259. lppTagArray[E_RECURRENCE]->Kind.lID = dispidRecurring;
  260. lppTagArray[E_RECURRENCE_TYPE]->lpguid = (LPGUID)&PSETID_Appointment;
  261. lppTagArray[E_RECURRENCE_TYPE]->ulKind = MNID_ID;
  262. lppTagArray[E_RECURRENCE_TYPE]->Kind.lID = dispidRecurrenceType;
  263. lppTagArray[E_RECURRENCE_PATTERN]->lpguid = (LPGUID)&PSETID_Appointment;
  264. lppTagArray[E_RECURRENCE_PATTERN]->ulKind = MNID_ID;
  265. lppTagArray[E_RECURRENCE_PATTERN]->Kind.lID = dispidRecurrencePattern;
  266. lppTagArray[E_RECURRENCE_STATE]->lpguid = (LPGUID)&PSETID_Appointment;
  267. lppTagArray[E_RECURRENCE_STATE]->ulKind = MNID_ID;
  268. lppTagArray[E_RECURRENCE_STATE]->Kind.lID = dispidRecurrenceState;
  269. hr = ReadNamedProperties(lpMessage, TAG_COUNT, lppTagArray,
  270. &~lpPropertyTagArray, &~lpPropertyArray);
  271. if (FAILED(hr))
  272. return hr;
  273. if (PROP_TYPE(lpPropertyArray[E_RECURRENCE].ulPropTag) == PT_ERROR) {
  274. __UPV Value;
  275. /*
  276. * Check if the recurrence type is set, and if this is the case,
  277. * if the type indicates recurrence.
  278. */
  279. if (PROP_TYPE(lpPropertyArray[E_RECURRENCE_TYPE].ulPropTag) == PT_ERROR ||
  280. lpPropertyArray[E_RECURRENCE_TYPE].Value.l == 0)
  281. Value.b = false;
  282. else
  283. Value.b = true;
  284. hr = AddMissingProperty(lpMessage, "dispidRecurring",
  285. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_RECURRENCE], PT_BOOLEAN),
  286. Value);
  287. if (hr != hrSuccess)
  288. return hr;
  289. bRecurring = Value.b;
  290. } else
  291. bRecurring = lpPropertyArray[E_RECURRENCE].Value.b;
  292. /*
  293. * The type has 4 possible values:
  294. * 0 - No recurrence
  295. * 1 - Daily
  296. * 2 - Weekly
  297. * 3 - Monthly
  298. * 4 - Yearly
  299. */
  300. if (PROP_TYPE(lpPropertyArray[E_RECURRENCE_TYPE].ulPropTag) == PT_ERROR) {
  301. if (bRecurring) {
  302. std::cout << "Item is recurring but is missing recurrence type" << std::endl;
  303. return E_INVALIDARG;
  304. } else
  305. ulType = 0;
  306. } else
  307. ulType = lpPropertyArray[E_RECURRENCE_TYPE].Value.l;
  308. if (!bRecurring && ulType > 0) {
  309. __UPV Value;
  310. Value.l = 0;
  311. hr = ReplaceProperty(lpMessage, "dispidRecurrenceType",
  312. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_RECURRENCE_TYPE], PT_LONG),
  313. "No recurrence, but recurrence type is > 0.",
  314. Value);
  315. if (hr != hrSuccess)
  316. return hr;
  317. } else if (bRecurring && ulType == 0) {
  318. __UPV Value;
  319. Value.b = false;
  320. hr = ReplaceProperty(lpMessage, "dispidRecurring",
  321. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_RECURRENCE], PT_BOOLEAN),
  322. "Recurrence has been set, but type indicates no recurrence.",
  323. Value);
  324. if (hr != hrSuccess)
  325. return hr;
  326. } else if (ulType > 4) {
  327. __UPV Value;
  328. if (bRecurring) {
  329. Value.b = false;
  330. bRecurring = false;
  331. hr = ReplaceProperty(lpMessage, "dispidRecurring",
  332. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_RECURRENCE], PT_BOOLEAN),
  333. "Invalid recurrence type, disabling recurrence.",
  334. Value);
  335. if (hr != hrSuccess)
  336. return hr;
  337. }
  338. Value.l = 0;
  339. ulType = 0;
  340. hr = ReplaceProperty(lpMessage, "dispidRecurrenceType",
  341. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_RECURRENCE], PT_LONG),
  342. "Invalid recurrence type, disabling recurrence.",
  343. Value);
  344. if (hr != hrSuccess)
  345. return hr;
  346. }
  347. if (PROP_TYPE(lpPropertyArray[E_RECURRENCE_PATTERN].ulPropTag) == PT_ERROR ||
  348. strcmp(lpPropertyArray[E_RECURRENCE_PATTERN].Value.lpszA, "") == 0) {
  349. if (bRecurring) {
  350. __UPV Value;
  351. switch (ulType) {
  352. case 1:
  353. Value.lpszA = const_cast<char *>("Daily");
  354. break;
  355. case 2:
  356. Value.lpszA = const_cast<char *>("Weekly");
  357. break;
  358. case 3:
  359. Value.lpszA = const_cast<char *>("Monthly");
  360. break;
  361. case 4:
  362. Value.lpszA = const_cast<char *>("Yearly");
  363. break;
  364. default:
  365. Value.lpszA = const_cast<char *>("Invalid");
  366. break;
  367. }
  368. hr = AddMissingProperty(lpMessage, "dispidRecurrencePattern",
  369. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_RECURRENCE_PATTERN], PT_STRING8),
  370. Value);
  371. if (hr != hrSuccess)
  372. return hr;
  373. }
  374. }
  375. if (bRecurring && PROP_TYPE(lpPropertyArray[E_RECURRENCE_STATE].ulPropTag) != PT_ERROR) {
  376. // Check the actual recurrence state
  377. RecurrenceState r;
  378. __UPV Value;
  379. std::vector<RecurrenceState::Exception>::iterator iEx;
  380. std::vector<RecurrenceState::ExtendedException>::iterator iEEx;
  381. convert_context convertContext;
  382. switch (r.ParseBlob(reinterpret_cast<char *>(lpPropertyArray[E_RECURRENCE_STATE].Value.bin.lpb), lpPropertyArray[E_RECURRENCE_STATE].Value.bin.cb, RECURRENCE_STATE_CALENDAR)) {
  383. case hrSuccess:
  384. case MAPI_W_ERRORS_RETURNED:
  385. // Recurrence state is readable, but may have errors.
  386. // First, make sure the number of extended exceptions is correct
  387. while (r.lstExtendedExceptions.size() > r.lstExceptions.size())
  388. r.lstExtendedExceptions.erase(--r.lstExtendedExceptions.end());
  389. // Add new extendedexceptions if missing
  390. iEx = r.lstExceptions.begin();
  391. for (size_t i = 0; i < r.lstExtendedExceptions.size(); ++i)
  392. ++iEx;
  393. while(r.lstExtendedExceptions.size() < r.lstExceptions.size()) {
  394. wstring wstr;
  395. RecurrenceState::ExtendedException ex;
  396. ex.ulStartDateTime = iEx->ulStartDateTime;
  397. ex.ulEndDateTime = iEx->ulEndDateTime;
  398. ex.ulOriginalStartDate = iEx->ulOriginalStartDate;
  399. TryConvert(convertContext, iEx->strSubject, rawsize(iEx->strSubject), "windows-1252", wstr);
  400. ex.strWideCharSubject.assign(wstr.c_str(), wstr.size());
  401. TryConvert(convertContext, iEx->strLocation, rawsize(iEx->strLocation), "windows-1252", wstr);
  402. ex.strWideCharLocation.assign(wstr.c_str(), wstr.size());
  403. r.lstExtendedExceptions.push_back(std::move(ex));
  404. ++iEx;
  405. }
  406. // Set some defaults right for exceptions
  407. for (iEx = r.lstExceptions.begin(); iEx != r.lstExceptions.end(); ++iEx)
  408. iEx->ulOriginalStartDate = (iEx->ulOriginalStartDate / 1440) * 1440;
  409. // Set some defaults for extended exceptions
  410. iEx = r.lstExceptions.begin();
  411. for (iEEx = r.lstExtendedExceptions.begin(); iEEx != r.lstExtendedExceptions.end(); ++iEEx) {
  412. wstring wstr;
  413. iEEx->strReservedBlock1 = "";
  414. iEEx->strReservedBlock2 = "";
  415. iEEx->ulChangeHighlightValue = 0;
  416. iEEx->ulOriginalStartDate = (iEx->ulOriginalStartDate / 1440) * 1440;
  417. TryConvert(convertContext, iEx->strSubject, rawsize(iEx->strSubject), "windows-1252", wstr);
  418. iEEx->strWideCharSubject.assign(wstr.c_str(), wstr.size());
  419. TryConvert(convertContext, iEx->strLocation, rawsize(iEx->strLocation), "windows-1252", wstr);
  420. iEEx->strWideCharLocation.assign(wstr.c_str(), wstr.size());
  421. ++iEx;
  422. }
  423. // Reset reserved data to 0
  424. r.strReservedBlock1 = "";
  425. r.strReservedBlock2 = "";
  426. // These are constant
  427. r.ulReaderVersion = 0x3004;
  428. r.ulWriterVersion = 0x3004;
  429. r.GetBlob(&~lpData, &ulLen);
  430. Value.bin.lpb = reinterpret_cast<unsigned char *>(lpData.get());
  431. Value.bin.cb = ulLen;
  432. // Update the recurrence if there is a change
  433. if (ulLen != lpPropertyArray[E_RECURRENCE_STATE].Value.bin.cb ||
  434. memcmp(lpPropertyArray[E_RECURRENCE_STATE].Value.bin.lpb, lpData, ulLen) != 0)
  435. hr = ReplaceProperty(lpMessage, "dispidRecurrenceState", CHANGE_PROP_TYPE(lpPropertyArray[E_RECURRENCE_STATE].ulPropTag, PT_BINARY), "Recoverable recurrence state.", Value);
  436. break;
  437. default:
  438. /* Recurrence state is useless */
  439. Value.l = 0;
  440. hr = ReplaceProperty(lpMessage, "dispidRecurrenceState",
  441. CHANGE_PROP_TYPE(lpPropertyTagArray->aulPropTag[E_RECURRENCE], PT_LONG),
  442. "Invalid recurrence state, disabling recurrence.",
  443. Value);
  444. break;
  445. }
  446. if (hr != hrSuccess)
  447. return hr;
  448. }
  449. return hrSuccess;
  450. }
  451. HRESULT FsckCalendar::ValidateItem(LPMESSAGE lpMessage,
  452. const std::string &strClass)
  453. {
  454. HRESULT hr;
  455. bool bChanged = false;
  456. if (strClass != "IPM.Appointment") {
  457. std::cout << "Illegal class: \"" << strClass << "\"" << std::endl;
  458. return E_INVALIDARG;
  459. }
  460. hr = ValidateMinimalNamedFields(lpMessage);
  461. if (hr != hrSuccess)
  462. return hr;
  463. hr = ValidateTimestamps(lpMessage);
  464. if (hr != hrSuccess)
  465. return hr;
  466. hr = ValidateRecurrence(lpMessage);
  467. if (hr != hrSuccess)
  468. return hr;
  469. return ValidateRecursiveDuplicateRecipients(lpMessage, bChanged);
  470. }