WSMAPIFolderOps.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  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/memory.hpp>
  20. #include "WSMAPIFolderOps.h"
  21. #include "Mem.h"
  22. #include <kopano/ECGuid.h>
  23. // Utils
  24. #include "SOAPUtils.h"
  25. #include "WSUtil.h"
  26. #include <kopano/charset/utf8string.h>
  27. #define START_SOAP_CALL retry:
  28. #define END_SOAP_CALL \
  29. if (er == KCERR_END_OF_SESSION && m_lpTransport->HrReLogon() == hrSuccess) \
  30. goto retry; \
  31. hr = kcerr_to_mapierr(er, MAPI_E_NOT_FOUND); \
  32. if(hr != hrSuccess) \
  33. goto exit;
  34. /*
  35. * The WSMAPIFolderOps for use with the WebServices transport
  36. */
  37. WSMAPIFolderOps::WSMAPIFolderOps(KCmd *lpCmd, std::recursive_mutex &data_lock,
  38. ECSESSIONID ecSessionId, ULONG cbEntryId, LPENTRYID lpEntryId,
  39. WSTransport *lpTransport) :
  40. ECUnknown("WSMAPIFolderOps"), lpDataLock(data_lock),
  41. m_lpTransport(lpTransport)
  42. {
  43. this->lpCmd = lpCmd;
  44. this->ecSessionId = ecSessionId;
  45. lpTransport->AddSessionReloadCallback(this, Reload, &m_ulSessionReloadCallback);
  46. CopyMAPIEntryIdToSOAPEntryId(cbEntryId, lpEntryId, &m_sEntryId);
  47. }
  48. WSMAPIFolderOps::~WSMAPIFolderOps()
  49. {
  50. m_lpTransport->RemoveSessionReloadCallback(m_ulSessionReloadCallback);
  51. FreeEntryId(&m_sEntryId, false);
  52. }
  53. HRESULT WSMAPIFolderOps::Create(KCmd *lpCmd, std::recursive_mutex &lpDataLock,
  54. ECSESSIONID ecSessionId, ULONG cbEntryId, LPENTRYID lpEntryId,
  55. WSTransport *lpTransport, WSMAPIFolderOps **lppFolderOps)
  56. {
  57. HRESULT hr = hrSuccess;
  58. auto lpFolderOps = new(std::nothrow) WSMAPIFolderOps(lpCmd, lpDataLock,
  59. ecSessionId, cbEntryId, lpEntryId, lpTransport);
  60. if (lpFolderOps == nullptr)
  61. return MAPI_E_NOT_ENOUGH_MEMORY;
  62. hr = lpFolderOps->QueryInterface(IID_ECMAPIFolderOps, (void **)lppFolderOps);
  63. if(hr != hrSuccess)
  64. delete lpFolderOps;
  65. return hr;
  66. }
  67. HRESULT WSMAPIFolderOps::QueryInterface(REFIID refiid, void **lppInterface)
  68. {
  69. REGISTER_INTERFACE3(ECMAPIFolderOps, WSMAPIFolderOps, this);
  70. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  71. }
  72. HRESULT WSMAPIFolderOps::HrCreateFolder(ULONG ulFolderType,
  73. const utf8string &strFolderName, const utf8string &strComment,
  74. BOOL fOpenIfExists, ULONG ulSyncId, const SBinary *lpsSourceKey,
  75. ULONG cbNewEntryId, LPENTRYID lpNewEntryId, ULONG* lpcbEntryId,
  76. LPENTRYID *lppEntryId)
  77. {
  78. HRESULT hr = hrSuccess;
  79. ECRESULT er = erSuccess;
  80. struct xsd__base64Binary sSourceKey;
  81. struct createFolderResponse sResponse;
  82. entryId* lpsEntryId = NULL;
  83. LockSoap();
  84. if(lpNewEntryId) {
  85. hr = CopyMAPIEntryIdToSOAPEntryId(cbNewEntryId, lpNewEntryId, &lpsEntryId);
  86. if(hr != hrSuccess)
  87. goto exit;
  88. }
  89. if (lpsSourceKey) {
  90. sSourceKey.__ptr = lpsSourceKey->lpb;
  91. sSourceKey.__size = lpsSourceKey->cb;
  92. } else {
  93. sSourceKey.__ptr = NULL;
  94. sSourceKey.__size = 0;
  95. }
  96. START_SOAP_CALL
  97. {
  98. if(SOAP_OK != lpCmd->ns__createFolder(ecSessionId, m_sEntryId, lpsEntryId, ulFolderType, (char*)strFolderName.c_str(), (char*)strComment.c_str(), fOpenIfExists == 0 ? false : true, ulSyncId, sSourceKey, &sResponse))
  99. er = KCERR_NETWORK_ERROR;
  100. else
  101. er = sResponse.er;
  102. }
  103. END_SOAP_CALL
  104. if(lpcbEntryId != NULL && lppEntryId != NULL)
  105. {
  106. hr = CopySOAPEntryIdToMAPIEntryId(&sResponse.sEntryId, lpcbEntryId, lppEntryId);
  107. if(hr != hrSuccess)
  108. goto exit;
  109. }
  110. exit:
  111. UnLockSoap();
  112. if(lpsEntryId)
  113. FreeEntryId(lpsEntryId, true);
  114. return hr;
  115. }
  116. HRESULT WSMAPIFolderOps::HrDeleteFolder(ULONG cbEntryId, LPENTRYID lpEntryId, ULONG ulFlags, ULONG ulSyncId)
  117. {
  118. ECRESULT er = erSuccess;
  119. HRESULT hr = hrSuccess;
  120. entryId sEntryId;
  121. LockSoap();
  122. // Cheap copy entryid
  123. hr = CopyMAPIEntryIdToSOAPEntryId(cbEntryId, lpEntryId, &sEntryId, true);
  124. if(hr != hrSuccess)
  125. goto exit;
  126. START_SOAP_CALL
  127. {
  128. if(SOAP_OK != lpCmd->ns__deleteFolder(ecSessionId, sEntryId, ulFlags, ulSyncId, &er))
  129. er = KCERR_NETWORK_ERROR;
  130. }
  131. END_SOAP_CALL
  132. exit:
  133. UnLockSoap();
  134. return hr;
  135. }
  136. HRESULT WSMAPIFolderOps::HrEmptyFolder(ULONG ulFlags, ULONG ulSyncId)
  137. {
  138. ECRESULT er = erSuccess;
  139. HRESULT hr = hrSuccess;
  140. LockSoap();
  141. START_SOAP_CALL
  142. {
  143. if(SOAP_OK != lpCmd->ns__emptyFolder(ecSessionId, m_sEntryId, ulFlags, ulSyncId, &er))
  144. er = KCERR_NETWORK_ERROR;
  145. }
  146. END_SOAP_CALL
  147. exit:
  148. UnLockSoap();
  149. return hr;
  150. }
  151. HRESULT WSMAPIFolderOps::HrSetReadFlags(ENTRYLIST *lpMsgList, ULONG ulFlags, ULONG ulSyncId)
  152. {
  153. HRESULT hr = hrSuccess;
  154. ECRESULT er = erSuccess;
  155. struct entryList sEntryList;
  156. memset(&sEntryList, 0, sizeof(struct entryList));
  157. LockSoap();
  158. if(lpMsgList) {
  159. if(lpMsgList->cValues == 0)
  160. goto exit;
  161. hr = CopyMAPIEntryListToSOAPEntryList(lpMsgList, &sEntryList);
  162. if(hr != hrSuccess)
  163. goto exit;
  164. }
  165. START_SOAP_CALL
  166. {
  167. if(SOAP_OK != lpCmd->ns__setReadFlags(ecSessionId, ulFlags, &m_sEntryId, lpMsgList ? &sEntryList : NULL, ulSyncId, &er))
  168. er = KCERR_NETWORK_ERROR;
  169. }
  170. END_SOAP_CALL
  171. exit:
  172. UnLockSoap();
  173. FreeEntryList(&sEntryList, false);
  174. return hr;
  175. }
  176. HRESULT WSMAPIFolderOps::HrSetSearchCriteria(ENTRYLIST *lpMsgList, SRestriction *lpRestriction, ULONG ulFlags)
  177. {
  178. ECRESULT er = erSuccess;
  179. HRESULT hr = hrSuccess;
  180. struct entryList* lpsEntryList = NULL;
  181. struct restrictTable* lpsRestrict = NULL;
  182. LockSoap();
  183. if(lpMsgList) {
  184. lpsEntryList = s_alloc<entryList>(nullptr);
  185. hr = CopyMAPIEntryListToSOAPEntryList(lpMsgList, lpsEntryList);
  186. if(hr != hrSuccess)
  187. goto exit;
  188. }
  189. if(lpRestriction)
  190. {
  191. hr = CopyMAPIRestrictionToSOAPRestriction(&lpsRestrict, lpRestriction);
  192. if(hr != hrSuccess)
  193. goto exit;
  194. }
  195. START_SOAP_CALL
  196. {
  197. if(SOAP_OK != lpCmd->ns__tableSetSearchCriteria(ecSessionId, m_sEntryId, lpsRestrict, lpsEntryList, ulFlags, &er))
  198. er = KCERR_NETWORK_ERROR;
  199. }
  200. END_SOAP_CALL
  201. hr = kcerr_to_mapierr(er);
  202. if(hr != hrSuccess)
  203. goto exit;
  204. exit:
  205. UnLockSoap();
  206. if(lpsRestrict)
  207. FreeRestrictTable(lpsRestrict);
  208. if(lpsEntryList)
  209. FreeEntryList(lpsEntryList, true);
  210. return hr;
  211. }
  212. HRESULT WSMAPIFolderOps::HrGetSearchCriteria(ENTRYLIST **lppMsgList, LPSRestriction *lppRestriction, ULONG *lpulFlags)
  213. {
  214. HRESULT hr = hrSuccess;
  215. ECRESULT er = erSuccess;
  216. ecmem_ptr<ENTRYLIST> lpMsgList;
  217. ecmem_ptr<SRestriction> lpRestriction;
  218. struct tableGetSearchCriteriaResponse sResponse;
  219. LockSoap();
  220. START_SOAP_CALL
  221. {
  222. if(SOAP_OK != lpCmd->ns__tableGetSearchCriteria(ecSessionId, m_sEntryId, &sResponse))
  223. er = KCERR_NETWORK_ERROR;
  224. else
  225. er = sResponse.er;
  226. }
  227. END_SOAP_CALL
  228. if(lppRestriction) {
  229. hr = ECAllocateBuffer(sizeof(SRestriction), &~lpRestriction);
  230. if(hr != hrSuccess)
  231. goto exit;
  232. hr = CopySOAPRestrictionToMAPIRestriction(lpRestriction, sResponse.lpRestrict, lpRestriction);
  233. if(hr != hrSuccess)
  234. goto exit;
  235. }
  236. if(lppMsgList) {
  237. hr = CopySOAPEntryListToMAPIEntryList(sResponse.lpFolderIDs, &~lpMsgList);
  238. if(hr != hrSuccess)
  239. goto exit;
  240. }
  241. if(lppMsgList)
  242. *lppMsgList = lpMsgList.release();
  243. if(lppRestriction)
  244. *lppRestriction = lpRestriction.release();
  245. if(lpulFlags)
  246. *lpulFlags = sResponse.ulFlags;
  247. exit:
  248. UnLockSoap();
  249. return hr;
  250. }
  251. HRESULT WSMAPIFolderOps::HrCopyFolder(ULONG cbEntryFrom, LPENTRYID lpEntryFrom, ULONG cbEntryDest, LPENTRYID lpEntryDest, const utf8string &strNewFolderName, ULONG ulFlags, ULONG ulSyncId)
  252. {
  253. HRESULT hr = hrSuccess;
  254. ECRESULT er = erSuccess;
  255. entryId sEntryFrom; //Do not free, cheap copy
  256. entryId sEntryDest; //Do not free, cheap copy
  257. LockSoap();
  258. hr = CopyMAPIEntryIdToSOAPEntryId(cbEntryFrom, lpEntryFrom, &sEntryFrom, true);
  259. if(hr != hrSuccess)
  260. goto exit;
  261. hr = CopyMAPIEntryIdToSOAPEntryId(cbEntryDest, lpEntryDest, &sEntryDest, true);
  262. if(hr != hrSuccess)
  263. goto exit;
  264. START_SOAP_CALL
  265. {
  266. if(SOAP_OK != lpCmd->ns__copyFolder(ecSessionId, sEntryFrom, sEntryDest, (char*)strNewFolderName.c_str(), ulFlags, ulSyncId, &er))
  267. er = KCERR_NETWORK_ERROR;
  268. }
  269. END_SOAP_CALL
  270. exit:
  271. UnLockSoap();
  272. return hr;
  273. }
  274. HRESULT WSMAPIFolderOps::HrCopyMessage(ENTRYLIST *lpMsgList, ULONG cbEntryDest, LPENTRYID lpEntryDest, ULONG ulFlags, ULONG ulSyncId)
  275. {
  276. HRESULT hr = hrSuccess;
  277. ECRESULT er = erSuccess;
  278. struct entryList sEntryList;
  279. entryId sEntryDest; //Do not free, cheap copy
  280. memset(&sEntryList, 0, sizeof(struct entryList));
  281. LockSoap();
  282. if(lpMsgList->cValues == 0)
  283. goto exit;
  284. hr = CopyMAPIEntryListToSOAPEntryList(lpMsgList, &sEntryList);
  285. if(hr != hrSuccess)
  286. goto exit;
  287. hr = CopyMAPIEntryIdToSOAPEntryId(cbEntryDest, lpEntryDest, &sEntryDest, true);
  288. if(hr != hrSuccess)
  289. goto exit;
  290. START_SOAP_CALL
  291. {
  292. if(SOAP_OK != lpCmd->ns__copyObjects(ecSessionId, &sEntryList, sEntryDest, ulFlags, ulSyncId, &er))
  293. er = KCERR_NETWORK_ERROR;
  294. }
  295. END_SOAP_CALL
  296. exit:
  297. UnLockSoap();
  298. FreeEntryList(&sEntryList, false);
  299. return hr;
  300. }
  301. HRESULT WSMAPIFolderOps::HrGetMessageStatus(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulFlags, ULONG *lpulMessageStatus)
  302. {
  303. HRESULT hr = hrSuccess;
  304. ECRESULT er = erSuccess;
  305. entryId sEntryId; //Do not free, cheap copy
  306. struct messageStatus sMessageStatus;
  307. LockSoap();
  308. if(lpEntryID == NULL) {
  309. hr = MAPI_E_INVALID_ENTRYID;
  310. goto exit;
  311. }
  312. hr = CopyMAPIEntryIdToSOAPEntryId(cbEntryID, lpEntryID, &sEntryId, true);
  313. if(hr != hrSuccess)
  314. goto exit;
  315. START_SOAP_CALL
  316. {
  317. if(SOAP_OK != lpCmd->ns__getMessageStatus(ecSessionId, sEntryId, ulFlags, &sMessageStatus) )
  318. er = KCERR_NETWORK_ERROR;
  319. else
  320. er = sMessageStatus.er;
  321. }
  322. END_SOAP_CALL
  323. *lpulMessageStatus = sMessageStatus.ulMessageStatus;
  324. exit:
  325. UnLockSoap();
  326. return hr;
  327. }
  328. HRESULT WSMAPIFolderOps::HrSetMessageStatus(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulNewStatus, ULONG ulNewStatusMask, ULONG ulSyncId, ULONG *lpulOldStatus)
  329. {
  330. HRESULT hr = hrSuccess;
  331. ECRESULT er = erSuccess;
  332. entryId sEntryId; //Do not free, cheap copy
  333. struct messageStatus sMessageStatus;
  334. LockSoap();
  335. if(lpEntryID == NULL) {
  336. hr = MAPI_E_INVALID_ENTRYID;
  337. goto exit;
  338. }
  339. hr = CopyMAPIEntryIdToSOAPEntryId(cbEntryID, lpEntryID, &sEntryId, true);
  340. if(hr != hrSuccess)
  341. goto exit;
  342. START_SOAP_CALL
  343. {
  344. if(SOAP_OK != lpCmd->ns__setMessageStatus(ecSessionId, sEntryId, ulNewStatus, ulNewStatusMask, ulSyncId, &sMessageStatus) )
  345. er = KCERR_NETWORK_ERROR;
  346. else
  347. er = sMessageStatus.er;
  348. }
  349. END_SOAP_CALL
  350. if(lpulOldStatus)
  351. *lpulOldStatus = sMessageStatus.ulMessageStatus;
  352. exit:
  353. UnLockSoap();
  354. return hr;
  355. }
  356. HRESULT WSMAPIFolderOps::HrGetChangeInfo(ULONG cbEntryID, LPENTRYID lpEntryID, LPSPropValue *lppPropPCL, LPSPropValue *lppPropCK)
  357. {
  358. HRESULT hr = hrSuccess;
  359. ECRESULT er = erSuccess;
  360. entryId sEntryId = {0};
  361. KCHL::memory_ptr<SPropValue> lpSPropValPCL, lpSPropValCK;
  362. getChangeInfoResponse sChangeInfo{__gszeroinit};
  363. LockSoap();
  364. if (lpEntryID == NULL) {
  365. hr = MAPI_E_INVALID_ENTRYID;
  366. goto exit;
  367. }
  368. hr = CopyMAPIEntryIdToSOAPEntryId(cbEntryID, lpEntryID, &sEntryId, true);
  369. if(hr != hrSuccess)
  370. goto exit;
  371. if (SOAP_OK != lpCmd->ns__getChangeInfo(ecSessionId, sEntryId, &sChangeInfo))
  372. er = KCERR_NETWORK_ERROR;
  373. else
  374. er = sChangeInfo.er;
  375. hr = kcerr_to_mapierr(er);
  376. if (hr != hrSuccess)
  377. goto exit;
  378. if (lppPropPCL) {
  379. hr = MAPIAllocateBuffer(sizeof *lpSPropValPCL, &~lpSPropValPCL);
  380. if (hr != hrSuccess)
  381. goto exit;
  382. hr = CopySOAPPropValToMAPIPropVal(lpSPropValPCL, &sChangeInfo.sPropPCL, lpSPropValPCL);
  383. if (hr != hrSuccess)
  384. goto exit;
  385. }
  386. if (lppPropCK) {
  387. hr = MAPIAllocateBuffer(sizeof *lpSPropValCK, &~lpSPropValCK);
  388. if (hr != hrSuccess)
  389. goto exit;
  390. hr = CopySOAPPropValToMAPIPropVal(lpSPropValCK, &sChangeInfo.sPropCK, lpSPropValCK);
  391. if (hr != hrSuccess)
  392. goto exit;
  393. }
  394. // All went well, modify output parameters
  395. if (lppPropPCL != nullptr)
  396. *lppPropPCL = lpSPropValPCL.release();
  397. if (lppPropCK != nullptr)
  398. *lppPropCK = lpSPropValCK.release();
  399. exit:
  400. UnLockSoap();
  401. return hr;
  402. }
  403. //FIXME: one lock/unlock function
  404. HRESULT WSMAPIFolderOps::LockSoap()
  405. {
  406. lpDataLock.lock();
  407. return erSuccess;
  408. }
  409. HRESULT WSMAPIFolderOps::UnLockSoap()
  410. {
  411. //Clean up data create with soap_malloc
  412. if(lpCmd->soap) {
  413. soap_destroy(lpCmd->soap);
  414. soap_end(lpCmd->soap);
  415. }
  416. lpDataLock.unlock();
  417. return erSuccess;
  418. }
  419. HRESULT WSMAPIFolderOps::Reload(void *lpParam, ECSESSIONID sessionid)
  420. {
  421. static_cast<WSMAPIFolderOps *>(lpParam)->ecSessionId = sessionid;
  422. return hrSuccess;
  423. }