iCal.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  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 "iCal.h"
  19. #include "CalDavUtil.h"
  20. #include <vector>
  21. #include <kopano/CommonUtil.h>
  22. #include <kopano/memory.hpp>
  23. #include <kopano/tie.hpp>
  24. #include "icaluid.h"
  25. #include <libxml/tree.h>
  26. #include <libxml/parser.h>
  27. #include "PublishFreeBusy.h"
  28. #include <kopano/mapi_ptr.h>
  29. using namespace std;
  30. using namespace KCHL;
  31. iCal::iCal(Http *lpRequest, IMAPISession *lpSession,
  32. const std::string &strSrvTz, const std::string &strCharset) :
  33. ProtocolBase(lpRequest, lpSession, strSrvTz, strCharset)
  34. {
  35. }
  36. HRESULT iCal::HrHandleCommand(const std::string &strMethod)
  37. {
  38. HRESULT hr = hrSuccess;
  39. if (!strMethod.compare("GET") || !strMethod.compare("HEAD"))
  40. hr = HrHandleIcalGet(strMethod);
  41. else if (!strMethod.compare("PUT"))
  42. hr = HrHandleIcalPost();
  43. else if (!strMethod.compare("DELETE"))
  44. hr = HrDelFolder();
  45. else
  46. hr = MAPI_E_CALL_FAILED;
  47. return hr;
  48. }
  49. /**
  50. * Handles http GET and HEAD request
  51. *
  52. * The GET request could be to retrieve one paticular msg or all calendar entries
  53. * HEAD is just a GET without the body returned.
  54. *
  55. * @return HRESULT
  56. * @retval MAPI_E_NOT_FOUND Folder or message not found
  57. */
  58. HRESULT iCal::HrHandleIcalGet(const std::string &strMethod)
  59. {
  60. HRESULT hr = hrSuccess;
  61. std::string strIcal;
  62. std::string strMsg;
  63. std::string strModtime;
  64. memory_ptr<SPropValue> lpProp;
  65. object_ptr<IMAPITable> lpContents;
  66. bool blCensorFlag = 0;
  67. if ((m_ulFolderFlag & SHARED_FOLDER) && !HasDelegatePerm(m_lpDefStore, m_lpActiveStore))
  68. blCensorFlag = true;
  69. // retrieve table and restrict as per request
  70. hr = HrGetContents(&~lpContents);
  71. if (hr != hrSuccess) {
  72. ec_log_err("Unable to retrieve contents of folder, error code: 0x%08X", hr);
  73. goto exit;
  74. }
  75. // convert table to ical data
  76. hr = HrGetIcal(lpContents, blCensorFlag, &strIcal);
  77. if (hr != hrSuccess) {
  78. ec_log_warn("Unable to retrieve ical data, error code: 0x%08X", hr);
  79. goto exit;
  80. }
  81. hr = HrGetOneProp(m_lpUsrFld, PR_LOCAL_COMMIT_TIME_MAX, &~lpProp);
  82. if (hr == hrSuccess)
  83. strModtime = SPropValToString(lpProp);
  84. exit:
  85. if (hr == hrSuccess)
  86. {
  87. if (!strModtime.empty())
  88. m_lpRequest->HrResponseHeader("Etag", strModtime);
  89. m_lpRequest->HrResponseHeader("Content-Type", "text/calendar; charset=\"utf-8\"");
  90. if (strIcal.empty()) {
  91. m_lpRequest->HrResponseHeader(204, "No Content");
  92. } else {
  93. m_lpRequest->HrResponseHeader(200, "OK");
  94. strMsg = "attachment; filename=\"" + (m_wstrFldName.empty() ? "Calendar" : W2U(m_wstrFldName.substr(0,10))) + ".ics\"";
  95. m_lpRequest->HrResponseHeader("Content-Disposition", strMsg);
  96. }
  97. if (strMethod.compare("GET") == 0)
  98. m_lpRequest->HrResponseBody(strIcal);
  99. // @todo, send Content-Length header? but HrFinalize in HTTP class will also send with size:0
  100. }
  101. else if (hr == MAPI_E_NOT_FOUND)
  102. {
  103. m_lpRequest->HrResponseHeader(404, "Not Found");
  104. }
  105. else
  106. m_lpRequest->HrResponseHeader(500, "Internal Server Error");
  107. return hr;
  108. }
  109. /**
  110. * Handles ical requests to add, modify & delete calendar entries
  111. *
  112. * @param strServerTZ server timezone string set in ical.cfg
  113. * @return HRESULT
  114. * @retval MAPI_E_NO_ACCESS insufficient permissions on folder or message
  115. * @retval MAPI_E_INVALID_OBJECT no mapi message in ical data
  116. */
  117. HRESULT iCal::HrHandleIcalPost()
  118. {
  119. HRESULT hr = hrSuccess;
  120. object_ptr<IMAPITable> lpContTable;
  121. SBinary sbEid = {0,0};
  122. SBinary sbUid = {0,0};
  123. ULONG ulItemCount = 0;
  124. ULONG ulProptag = 0;
  125. ICalToMapi *lpICalToMapi = NULL;
  126. time_t tLastMod = 0;
  127. bool blCensorPrivate = false;
  128. std::string strUidString;
  129. std::string strIcal;
  130. eIcalType etype = VEVENT;
  131. FILETIME ftModTime;
  132. time_t tUnixModTime;
  133. map<std::string, int> mpIcalEntries;
  134. map<std::string, FILETIME> mpSrvTimes;
  135. map<std::string,SBinary> mpSrvEntries;
  136. map<std::string, int>::const_iterator mpIterI;
  137. map<std::string,SBinary>::const_iterator mpIterJ;
  138. ulProptag = CHANGE_PROP_TYPE(m_lpNamedProps->aulPropTag[PROP_GOID], PT_BINARY);
  139. SizedSPropTagArray(3, proptags) = {3, {PR_ENTRYID, PR_LAST_MODIFICATION_TIME, ulProptag}};
  140. //Include PR_ENTRYID,PR_LAST_MODIFICATION_TIME & Named Prop GlobalObjUid.
  141. //retrive entries from ical data.
  142. CreateICalToMapi(m_lpActiveStore, m_lpAddrBook, false, &lpICalToMapi);
  143. m_lpRequest->HrGetBody(&strIcal);
  144. if(!strIcal.empty())
  145. {
  146. hr = lpICalToMapi->ParseICal(strIcal, m_strCharset, m_strSrvTz, m_lpLoginUser, 0);
  147. if (hr!=hrSuccess)
  148. goto exit;
  149. }
  150. ulItemCount = lpICalToMapi->GetItemCount();
  151. //map of Ical entries.
  152. //generate map for each entry's UID and Position.
  153. for (ULONG i = 0; i < ulItemCount; ++i) {
  154. hr = lpICalToMapi->GetItemInfo(i, &etype, &tLastMod, &sbEid);
  155. if (hr != hrSuccess || etype != VEVENT)
  156. continue;
  157. strUidString = bin2hex((ULONG)sbEid.cb,(LPBYTE)sbEid.lpb);
  158. mpIcalEntries[strUidString] = i;
  159. }
  160. if ((m_ulFolderFlag & SHARED_FOLDER) && !HasDelegatePerm(m_lpDefStore, m_lpActiveStore))
  161. blCensorPrivate = true;
  162. hr = m_lpUsrFld->GetContentsTable(0, &~lpContTable);
  163. if(hr != hrSuccess)
  164. goto exit;
  165. hr = lpContTable->SetColumns(proptags, 0);
  166. if (hr != hrSuccess)
  167. goto exit;
  168. //Map of server Entries.
  169. //Generate map of UID : Modification time & UID : ENTRYID.
  170. while (TRUE)
  171. {
  172. rowset_ptr lpRows;
  173. hr = lpContTable->QueryRows(50, 0, &~lpRows);
  174. if (hr != hrSuccess)
  175. goto exit;
  176. if (lpRows->cRows == 0)
  177. break;
  178. for (ULONG i = 0; i < lpRows->cRows; ++i) {
  179. if (lpRows->aRow[i].lpProps[0].ulPropTag != PR_ENTRYID)
  180. continue;
  181. if (lpRows->aRow[i].lpProps[2].ulPropTag == ulProptag)
  182. sbUid = lpRows->aRow[i].lpProps[2].Value.bin;
  183. else
  184. continue; // skip new entries
  185. sbEid.cb = lpRows->aRow[i].lpProps[0].Value.bin.cb;
  186. if ((hr = MAPIAllocateBuffer(sbEid.cb, (void **)&sbEid.lpb)) != hrSuccess)
  187. goto exit;
  188. memcpy(sbEid.lpb, lpRows->aRow[i].lpProps[0].Value.bin.lpb, sbEid.cb);
  189. strUidString = bin2hex((ULONG)sbUid.cb, (LPBYTE)sbUid.lpb);
  190. mpSrvEntries[strUidString] = sbEid;
  191. if (lpRows->aRow[i].lpProps[1].ulPropTag == PR_LAST_MODIFICATION_TIME)
  192. mpSrvTimes[strUidString] = lpRows->aRow[i].lpProps[1].Value.ft;
  193. }
  194. }
  195. mpIterI = mpIcalEntries.cbegin();
  196. mpIterJ = mpSrvEntries.cbegin();
  197. //Iterate through entries and perform ADD, DELETE, Modify.
  198. while(1)
  199. {
  200. if (mpIterJ == mpSrvEntries.cend() && mpIterI == mpIcalEntries.cend())
  201. break;
  202. if (mpIcalEntries.cend() == mpIterI && mpSrvEntries.cend() != mpIterJ) {
  203. hr = HrDelMessage(mpIterJ->second, blCensorPrivate);
  204. if(hr != hrSuccess)
  205. {
  206. ec_log_err("Unable to Delete Message: 0x%08X", hr);
  207. goto exit;
  208. }
  209. ++mpIterJ;
  210. } else if (mpIcalEntries.cend() != mpIterI && mpSrvEntries.cend() == mpIterJ) {
  211. hr = HrAddMessage(lpICalToMapi, mpIterI->second);
  212. if(hr != hrSuccess)
  213. {
  214. ec_log_err("Unable to Add New Message: 0x%08X", hr);
  215. goto exit;
  216. }
  217. ++mpIterI;
  218. } else if (mpSrvEntries.cend() != mpIterJ && mpIcalEntries.cend() != mpIterI) {
  219. if(!mpIterI->first.compare(mpIterJ->first))
  220. {
  221. lpICalToMapi->GetItemInfo(mpIterI->second, &etype, &tLastMod, &sbEid);
  222. ftModTime = mpSrvTimes[mpIterJ->first];
  223. FileTimeToUnixTime(ftModTime, &tUnixModTime);
  224. if(tUnixModTime != tLastMod && etype == VEVENT)
  225. {
  226. hr = HrModify(lpICalToMapi, mpIterJ->second, mpIterI->second, blCensorPrivate);
  227. if(hr != hrSuccess)
  228. {
  229. ec_log_err("Unable to Modify Message: 0x%08X", hr);
  230. goto exit;
  231. }
  232. }
  233. ++mpIterI;
  234. ++mpIterJ;
  235. }
  236. else if( mpIterI->first.compare(mpIterJ->first) < 0 )
  237. {
  238. hr = HrAddMessage(lpICalToMapi, mpIterI->second);
  239. if(hr != hrSuccess)
  240. {
  241. ec_log_err("Unable to Add New Message: 0x%08X", hr);
  242. goto exit;
  243. }
  244. ++mpIterI;
  245. }
  246. else if(mpIterI->first.compare(mpIterJ->first) > 0 )
  247. {
  248. hr = HrDelMessage(mpIterJ->second, blCensorPrivate);
  249. if(hr != hrSuccess)
  250. {
  251. ec_log_err("Unable to Delete Message: 0x%08X", hr);
  252. goto exit;
  253. }
  254. ++mpIterJ;
  255. }
  256. }//else if
  257. }//while
  258. if(m_ulFolderFlag & DEFAULT_FOLDER)
  259. hr = HrPublishDefaultCalendar(m_lpSession, m_lpDefStore, time(NULL), FB_PUBLISH_DURATION);
  260. if(hr != hrSuccess) {
  261. hr = hrSuccess;
  262. ec_log_err("Error publishing freebusy for user %ls", m_wstrUser.c_str());
  263. }
  264. exit:
  265. if(hr == hrSuccess || hr == MAPI_E_INVALID_OBJECT)
  266. m_lpRequest->HrResponseHeader(200,"OK");
  267. else if (hr == MAPI_E_NO_ACCESS)
  268. m_lpRequest->HrResponseHeader(403,"Forbidden");
  269. else
  270. m_lpRequest->HrResponseHeader(500,"Internal Server Error");
  271. for (mpIterJ = mpSrvEntries.cbegin(); mpIterJ != mpSrvEntries.cend(); ++mpIterJ)
  272. MAPIFreeBuffer(mpIterJ->second.lpb);
  273. if(lpICalToMapi)
  274. delete lpICalToMapi;
  275. mpSrvEntries.clear();
  276. mpIcalEntries.clear();
  277. mpSrvTimes.clear();
  278. return hr;
  279. }
  280. /**
  281. * Edits the existing message in the folder
  282. *
  283. * @param[in] lpIcal2Mapi ical to mapi conversion object
  284. * @param[in] sbSrvEid EntryID of the message to be edited
  285. * @param[in] ulPos Position in the list of messages in conversion object
  286. * @param[in] blCensor boolean to block edit of private items
  287. * @return HRESULT
  288. * @retval MAPI_E_NO_ACCESS unable to edit private item
  289. */
  290. HRESULT iCal::HrModify( ICalToMapi *lpIcal2Mapi, SBinary sbSrvEid, ULONG ulPos, bool blCensor)
  291. {
  292. object_ptr<IMessage> lpMessage;
  293. ULONG ulObjType=0;
  294. ULONG ulTagPrivate = 0;
  295. ulTagPrivate = CHANGE_PROP_TYPE(m_lpNamedProps->aulPropTag[PROP_PRIVATE], PT_BOOLEAN);
  296. HRESULT hr = m_lpUsrFld->OpenEntry(sbSrvEid.cb, reinterpret_cast<ENTRYID *>(sbSrvEid.lpb),
  297. nullptr, MAPI_BEST_ACCESS, &ulObjType, &~lpMessage);
  298. if(hr != hrSuccess)
  299. return hr;
  300. if (blCensor && IsPrivate(lpMessage, ulTagPrivate))
  301. return MAPI_E_NO_ACCESS;
  302. hr = lpIcal2Mapi->GetItem(ulPos, 0, lpMessage);
  303. if(hr != hrSuccess)
  304. return hr;
  305. return lpMessage->SaveChanges(0);
  306. }
  307. /**
  308. * Creates a new message in the folder and sets its properties
  309. *
  310. * @param[in] lpIcal2Mapi ical to mapi conversion object
  311. * @param[in] ulPos the possition of the messasge in list
  312. * @return HRESULT
  313. */
  314. HRESULT iCal::HrAddMessage(ICalToMapi *lpIcal2Mapi, ULONG ulPos)
  315. {
  316. object_ptr<IMessage> lpMessage;
  317. HRESULT hr = m_lpUsrFld->CreateMessage(nullptr, 0, &~lpMessage);
  318. if (hr != hrSuccess)
  319. return hr;
  320. hr = lpIcal2Mapi->GetItem(ulPos, 0, lpMessage);
  321. if (hr != hrSuccess) {
  322. ec_log_err("Error creating a new calendar entry, error code: 0x%08X",hr);
  323. return hr;
  324. }
  325. hr = lpMessage->SaveChanges(0);
  326. if (hr != hrSuccess)
  327. ec_log_err("Error saving a new calendar entry, error code: 0x%08X",hr);
  328. return hr;
  329. }
  330. /**
  331. * Deletes the mapi message
  332. *
  333. * The message is moved to wastebasket(deleted items folder)
  334. *
  335. * @param[in] sbEid EntryID of the message to be deleted
  336. * @param[in] blCensor boolean to block delete of private messages
  337. *
  338. * @return HRESULT
  339. */
  340. HRESULT iCal::HrDelMessage(SBinary sbEid, bool blCensor)
  341. {
  342. memory_ptr<ENTRYLIST> lpEntryList;
  343. object_ptr<IMessage> lpMessage;
  344. ULONG ulObjType = 0;
  345. ULONG ulTagPrivate = 0;
  346. ulTagPrivate = CHANGE_PROP_TYPE(m_lpNamedProps->aulPropTag[PROP_PRIVATE], PT_BOOLEAN);
  347. HRESULT hr = MAPIAllocateBuffer(sizeof(ENTRYLIST), &~lpEntryList);
  348. if (hr != hrSuccess)
  349. {
  350. ec_log_err("Error allocating memory, error code: 0x%08X",hr);
  351. return hr;
  352. }
  353. lpEntryList->cValues = 1;
  354. hr = MAPIAllocateMore(sizeof(SBinary), lpEntryList, (void**)&lpEntryList->lpbin);
  355. if(hr != hrSuccess)
  356. {
  357. ec_log_err("Error allocating memory, error code: 0x%08X",hr);
  358. return hr;
  359. }
  360. hr = m_lpUsrFld->OpenEntry(sbEid.cb, reinterpret_cast<ENTRYID *>(sbEid.lpb), nullptr, MAPI_BEST_ACCESS, &ulObjType, &~lpMessage);
  361. if(hr != hrSuccess)
  362. return hr;
  363. if(blCensor && IsPrivate(lpMessage, ulTagPrivate))
  364. return hrSuccess; /* ignoring private items */
  365. lpEntryList->lpbin[0].cb = sbEid.cb;
  366. if ((hr = MAPIAllocateMore(sbEid.cb, lpEntryList, (void**)&lpEntryList->lpbin[0].lpb)) != hrSuccess)
  367. return hr;
  368. memcpy(lpEntryList->lpbin[0].lpb, sbEid.lpb, sbEid.cb);
  369. hr = m_lpUsrFld->DeleteMessages(lpEntryList, 0, NULL, MESSAGE_DIALOG);
  370. if(hr != hrSuccess)
  371. ec_log_err("Error while deleting a calendar entry, error code: 0x%08X",hr);
  372. return hr;
  373. }
  374. /**
  375. * Returns Table according to the entries requested.
  376. *
  377. * Restction is applied on table only when single calendar entry is requested
  378. * using http GET request, else all the calendar entries are sent.
  379. *
  380. * @param[out] lppTable Table containing rows of calendar entries as requested in URL.
  381. *
  382. * @return HRESULT
  383. * @retval MAPI_E_NOT_FOUND user's folder is not set in m_lpUsrFld
  384. */
  385. HRESULT iCal::HrGetContents(LPMAPITABLE *lppTable)
  386. {
  387. HRESULT hr = hrSuccess;
  388. std::string strUid;
  389. std::string strUrl;
  390. memory_ptr<SRestriction> lpsRestriction;
  391. MAPITablePtr ptrContents;
  392. static constexpr const SizedSPropTagArray(1, sPropEntryIdcol) = {1, {PR_ENTRYID}};
  393. ULONG ulRows = 0;
  394. if (m_lpUsrFld == nullptr)
  395. return MAPI_E_NOT_FOUND;
  396. hr = m_lpUsrFld->GetContentsTable(0, &~ptrContents);
  397. if (hr != hrSuccess) {
  398. ec_log_err("Error retrieving calendar entries, error code: 0x%08X",hr);
  399. return hr;
  400. }
  401. hr = ptrContents->SetColumns(sPropEntryIdcol, 0);
  402. if (hr != hrSuccess)
  403. return hr;
  404. m_lpRequest->HrGetUrl(&strUrl);
  405. strUid = StripGuid(strUrl);
  406. if (!strUid.empty()) {
  407. // single item requested
  408. hr = HrMakeRestriction(strUid, m_lpNamedProps, &~lpsRestriction);
  409. if (hr != hrSuccess)
  410. return hr;
  411. hr = ptrContents->Restrict(lpsRestriction, TBL_BATCH);
  412. if (hr != hrSuccess) {
  413. ec_log_err("Error restricting calendar entries, error code: 0x%08X",hr);
  414. return hr;
  415. }
  416. // single item not present, return 404
  417. hr = ptrContents->GetRowCount(0, &ulRows);
  418. if (hr != hrSuccess || ulRows != 1)
  419. return MAPI_E_NOT_FOUND;
  420. }
  421. return ptrContents->QueryInterface(IID_IMAPITable, (LPVOID*)lppTable);
  422. }
  423. /**
  424. * Converts mapi messages of the table into ical data
  425. *
  426. * @param[in] lpTable Table containing mapi messages
  427. * @param[in] blCensorPrivate Flag to censor private items while accessing shared folders
  428. * @param[out] lpstrIcal Pointer to string containing ical data of the mapi messages
  429. * @return HRESULT
  430. * @retval E_FAIL Error creating MapiToICal object
  431. */
  432. HRESULT iCal::HrGetIcal(IMAPITable *lpTable, bool blCensorPrivate, std::string *lpstrIcal)
  433. {
  434. HRESULT hr = hrSuccess;
  435. SBinary sbEid = {0,0};
  436. ULONG ulObjType = 0;
  437. ULONG ulTagPrivate = 0;
  438. ULONG ulFlag = 0;
  439. bool blCensor = false;
  440. std::unique_ptr<MapiToICal> lpMtIcal;
  441. std::string strical;
  442. ulTagPrivate = CHANGE_PROP_TYPE(m_lpNamedProps->aulPropTag[PROP_PRIVATE], PT_BOOLEAN);
  443. CreateMapiToICal(m_lpAddrBook, "utf-8", &unique_tie(lpMtIcal));
  444. if (lpMtIcal == NULL) {
  445. ec_log_err("Error Creating MapiToIcal object, error code: 0x%08X",hr);
  446. return E_FAIL;
  447. }
  448. while (TRUE)
  449. {
  450. rowset_ptr lpRows;
  451. hr = lpTable->QueryRows(50, 0, &~lpRows);
  452. if (hr != hrSuccess)
  453. {
  454. ec_log_err("Error retrieving table rows, error code: 0x%08X", hr);
  455. return hr;
  456. }
  457. if (lpRows->cRows == 0)
  458. break;
  459. for (ULONG i = 0; i < lpRows->cRows; ++i) {
  460. blCensor = blCensorPrivate; // reset censor flag for next message
  461. ulFlag = 0;
  462. if (lpRows->aRow[i].lpProps[0].ulPropTag != PR_ENTRYID)
  463. continue;
  464. sbEid = lpRows->aRow[i].lpProps[0].Value.bin;
  465. object_ptr<IMessage> lpMessage;
  466. hr = m_lpUsrFld->OpenEntry(sbEid.cb, (LPENTRYID)sbEid.lpb,
  467. nullptr, MAPI_BEST_ACCESS, &ulObjType, &~lpMessage);
  468. if (hr != hrSuccess)
  469. {
  470. ec_log_debug("Error opening message for ical conversion, error code: 0x%08X", hr);
  471. ec_log_debug("%d \n %s", sbEid.cb, bin2hex(sbEid.cb,sbEid.lpb).c_str());
  472. // Ignore error, just skip the message
  473. hr = hrSuccess;
  474. continue;
  475. }
  476. if(blCensor && IsPrivate(lpMessage, ulTagPrivate))
  477. ulFlag = M2IC_CENSOR_PRIVATE;
  478. else
  479. ulFlag = 0;
  480. hr = lpMtIcal->AddMessage(lpMessage, m_strSrvTz, ulFlag);
  481. if (hr != hrSuccess)
  482. {
  483. ec_log_debug("Error converting mapi message to ical, error code: 0x%08X", hr);
  484. // Ignore broken message
  485. hr = hrSuccess;
  486. }
  487. }
  488. }
  489. hr = lpMtIcal->Finalize(0, NULL, lpstrIcal);
  490. if (hr != hrSuccess)
  491. ec_log_debug("Unable to create ical output of calendar, error code 0x%08X", hr);
  492. return hr;
  493. }
  494. /**
  495. * Deletes the current selected folder (m_lpUsrFld)
  496. *
  497. * Used to delete folders created during publish operation in iCal.app,
  498. * the folder is moved to wastebasket(Deleted items folder)
  499. * Only user created folders can be deleted. Special folders which are
  500. * required by the model may not be deleted.
  501. *
  502. * @return HRESULT
  503. * @retval MAPI_E_NO_ACCESS insufficient permissions to delete folder
  504. */
  505. HRESULT iCal::HrDelFolder()
  506. {
  507. HRESULT hr = hrSuccess;
  508. memory_ptr<SPropValue> lpWstBoxEid, lpFldEid;
  509. object_ptr<IMAPIFolder> lpWasteBoxFld;
  510. ULONG ulObjType = 0;
  511. if (m_blFolderAccess == false) {
  512. hr = MAPI_E_NO_ACCESS;
  513. goto exit;
  514. }
  515. // Folder is not protected, so now we can move it to the wastebasket folder
  516. hr = HrGetOneProp(m_lpActiveStore, PR_IPM_WASTEBASKET_ENTRYID, &~lpWstBoxEid);
  517. if (hr != hrSuccess)
  518. goto exit;
  519. hr = m_lpActiveStore->OpenEntry(lpWstBoxEid->Value.bin.cb, reinterpret_cast<ENTRYID *>(lpWstBoxEid->Value.bin.lpb), nullptr, MAPI_MODIFY, &ulObjType, &~lpWasteBoxFld);
  520. if (hr != hrSuccess)
  521. {
  522. ec_log_err("Error opening \"Deleted items\" folder, error code: 0x%08X", hr);
  523. goto exit;
  524. }
  525. hr = HrGetOneProp(m_lpUsrFld, PR_ENTRYID, &~lpFldEid);
  526. if (hr != hrSuccess)
  527. goto exit;
  528. hr = m_lpIPMSubtree->CopyFolder(lpFldEid->Value.bin.cb, (LPENTRYID)lpFldEid->Value.bin.lpb, NULL, lpWasteBoxFld, NULL, 0, NULL, MAPI_MOVE);
  529. if (hr != hrSuccess)
  530. goto exit;
  531. exit:
  532. if (hr == hrSuccess)
  533. m_lpRequest->HrResponseHeader(200,"OK");
  534. else if (hr == MAPI_E_NO_ACCESS)
  535. m_lpRequest->HrResponseHeader(403,"Forbidden");
  536. else
  537. m_lpRequest->HrResponseHeader(500,"Internal Server Error");
  538. return hr;
  539. }