ECMemTablePublic.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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/ECRestriction.h>
  20. #include <kopano/memory.hpp>
  21. #include "ECMemTablePublic.h"
  22. #include "Mem.h"
  23. #include <kopano/ECGuid.h>
  24. #include <edkguid.h>
  25. #include <kopano/Util.h>
  26. #include "ClientUtil.h"
  27. #include <edkmdb.h>
  28. #include <kopano/mapiext.h>
  29. #include "ECMsgStorePublic.h"
  30. #include "favoritesutil.h"
  31. #include <mapiutil.h>
  32. using namespace KCHL;
  33. //FIXME: add the classname "ECMemTablePublic"
  34. ECMemTablePublic::ECMemTablePublic(ECMAPIFolderPublic *lpECParentFolder,
  35. const SPropTagArray *lpsPropTags, ULONG ulRowPropTag) :
  36. ECMemTable(lpsPropTags, ulRowPropTag),
  37. m_lpECParentFolder(lpECParentFolder)
  38. {
  39. if (m_lpECParentFolder)
  40. m_lpECParentFolder->AddRef();
  41. }
  42. ECMemTablePublic::~ECMemTablePublic(void)
  43. {
  44. if (m_lpShortcutTable)
  45. m_lpShortcutTable->Release();
  46. if (m_lpShortCutAdviseSink)
  47. m_lpShortCutAdviseSink->Release();
  48. for (auto &p : m_mapRelation) {
  49. if (p.second.ulAdviseConnectionId > 0)
  50. m_lpECParentFolder->GetMsgStore()->Unadvise(p.second.ulAdviseConnectionId);
  51. FreeRelation(&p.second);
  52. }
  53. if (m_lpECParentFolder)
  54. m_lpECParentFolder->Release();
  55. }
  56. HRESULT ECMemTablePublic::Create(ECMAPIFolderPublic *lpECParentFolder, ECMemTablePublic **lppECMemTable)
  57. {
  58. static constexpr const SizedSPropTagArray(12, sPropsHierarchyColumns) =
  59. {12, {PR_ENTRYID, PR_DISPLAY_NAME, PR_CONTENT_COUNT,
  60. PR_CONTENT_UNREAD, PR_STORE_ENTRYID, PR_STORE_RECORD_KEY,
  61. PR_STORE_SUPPORT_MASK, PR_INSTANCE_KEY, PR_RECORD_KEY,
  62. PR_ACCESS, PR_ACCESS_LEVEL, PR_CONTAINER_CLASS}};
  63. auto lpMemTable = new(std::nothrow) ECMemTablePublic(lpECParentFolder,
  64. sPropsHierarchyColumns, PR_ROWID);
  65. if (lpMemTable == nullptr)
  66. return MAPI_E_NOT_ENOUGH_MEMORY;
  67. auto ret = lpMemTable->QueryInterface(IID_ECMemTablePublic,
  68. reinterpret_cast<void **>(lppECMemTable));
  69. if (ret != hrSuccess)
  70. delete lpMemTable;
  71. return ret;
  72. }
  73. HRESULT ECMemTablePublic::QueryInterface(REFIID refiid, void **lppInterface)
  74. {
  75. REGISTER_INTERFACE2(ECMemTable, this);
  76. REGISTER_INTERFACE2(ECMemTablePublic, this);
  77. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  78. }
  79. /*
  80. Advise function to check if there something is changed in the shortcut folder of you private store.
  81. This is used to build the favorits tree
  82. */
  83. static LONG __stdcall AdviseShortCutCallback(void *lpContext, ULONG cNotif,
  84. LPNOTIFICATION lpNotif)
  85. {
  86. if (lpContext == NULL) {
  87. return S_OK;
  88. }
  89. HRESULT hr = hrSuccess;
  90. auto lpMemTablePublic = static_cast<ECMemTablePublic *>(lpContext);
  91. lpMemTablePublic->AddRef(); // Besure we have the object
  92. for (ULONG i = 0; i < cNotif; ++i) {
  93. if(lpNotif[i].ulEventType != fnevTableModified)
  94. {
  95. assert(false);
  96. continue;
  97. }
  98. // NOTE: ignore errors at all.
  99. switch (lpNotif[i].info.tab.ulTableEvent)
  100. {
  101. case TABLE_ROW_ADDED:
  102. case TABLE_ROW_MODIFIED:
  103. lpMemTablePublic->ModifyRow(&lpNotif[i].info.tab.propIndex.Value.bin, &lpNotif[i].info.tab.row);
  104. break;
  105. case TABLE_ROW_DELETED:
  106. lpMemTablePublic->DelRow(&lpNotif[i].info.tab.propIndex.Value.bin);
  107. break;
  108. case TABLE_CHANGED:
  109. lpMemTablePublic->HrClear();
  110. hr = lpMemTablePublic->m_lpShortcutTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
  111. if (hr != hrSuccess)
  112. continue; // Next notification
  113. while(true)
  114. {
  115. rowset_ptr lpRows;
  116. hr = lpMemTablePublic->m_lpShortcutTable->QueryRows(1, 0, &~lpRows);
  117. if (hr != hrSuccess)
  118. break; // Next notification
  119. if (lpRows->cRows == 0)
  120. break;
  121. lpMemTablePublic->ModifyRow(&lpRows->aRow[0].lpProps[SC_INSTANCE_KEY].Value.bin, &lpRows->aRow[0]);
  122. }
  123. break;
  124. default:
  125. break;
  126. }
  127. }
  128. lpMemTablePublic->Release();
  129. return S_OK;
  130. }
  131. static LONG __stdcall AdviseFolderCallback(void *lpContext, ULONG cNotif,
  132. LPNOTIFICATION lpNotif)
  133. {
  134. if (lpContext == NULL)
  135. return S_OK;
  136. auto lpMemTablePublic = static_cast<ECMemTablePublic *>(lpContext);
  137. ULONG ulResult;
  138. SBinary sInstanceKey;
  139. lpMemTablePublic->AddRef(); // Besure we have the object
  140. for (ULONG i = 0; i < cNotif; ++i) {
  141. switch (lpNotif[i].ulEventType)
  142. {
  143. case fnevObjectModified:
  144. case fnevObjectDeleted:
  145. for (const auto &p : lpMemTablePublic->m_mapRelation)
  146. if (lpMemTablePublic->m_lpECParentFolder->GetMsgStore()->CompareEntryIDs(p.second.cbEntryID, p.second.lpEntryID, lpNotif[i].info.obj.cbEntryID, lpNotif[i].info.obj.lpEntryID, 0, &ulResult) == hrSuccess && ulResult == TRUE)
  147. {
  148. sInstanceKey.cb = p.first.size();
  149. sInstanceKey.lpb = reinterpret_cast<BYTE *>(const_cast<char *>(p.first.c_str()));
  150. switch (lpNotif[i].ulEventType)
  151. {
  152. case fnevObjectModified:
  153. lpMemTablePublic->ModifyRow(&sInstanceKey, NULL);
  154. TRACE_MAPI(TRACE_ENTRY, "AdviseFolderCallback", "fnevObjectModified fnevObjectModified");
  155. break;
  156. case fnevObjectDeleted:
  157. TRACE_MAPI(TRACE_ENTRY, "AdviseFolderCallback", "fnevObjectDeleted fnevObjectDeleted");
  158. lpMemTablePublic->DelRow(&sInstanceKey);
  159. break;
  160. }
  161. break;
  162. }
  163. break;
  164. //TODO: Move (Unknown what to update)
  165. }
  166. }
  167. lpMemTablePublic->Release();
  168. return S_OK;
  169. }
  170. HRESULT ECMemTablePublic::Init(ULONG ulFlags)
  171. {
  172. object_ptr<IMAPIFolder> lpShortcutFolder;
  173. object_ptr<IMAPITable> lpShortcutTable;
  174. memory_ptr<SPropValue> lpPropTmp;
  175. ULONG ulConnection;
  176. m_ulFlags = ulFlags;
  177. // Get the messages to build a folder list
  178. if (((ECMsgStorePublic *)m_lpECParentFolder->GetMsgStore())->GetDefaultShortcutFolder(&~lpShortcutFolder) == hrSuccess) {
  179. HRESULT hr = lpShortcutFolder->GetContentsTable(ulFlags | MAPI_DEFERRED_ERRORS, &~lpShortcutTable);
  180. if(hr != hrSuccess)
  181. return hr;
  182. hr = lpShortcutTable->SetColumns(GetShortCutTagArray(), MAPI_DEFERRED_ERRORS);
  183. if(hr != hrSuccess)
  184. return hr;
  185. // build restriction
  186. if (HrGetOneProp(&m_lpECParentFolder->m_xMAPIFolder, PR_SOURCE_KEY, &~lpPropTmp) != hrSuccess)
  187. {
  188. hr = ECNotRestriction(ECExistRestriction(PR_FAV_PARENT_SOURCE_KEY)).RestrictTable(lpShortcutTable, MAPI_DEFERRED_ERRORS);
  189. }else {
  190. hr = HrGetOneProp(&m_lpECParentFolder->m_xMAPIFolder, PR_SOURCE_KEY, &~lpPropTmp);
  191. if (hr != hrSuccess)
  192. return hr;
  193. hr = ECPropertyRestriction(RELOP_EQ, PR_FAV_PARENT_SOURCE_KEY, lpPropTmp, ECRestriction::Cheap).RestrictTable(lpShortcutTable, MAPI_DEFERRED_ERRORS);
  194. }
  195. if (hr != hrSuccess)
  196. return hr;
  197. // No advise needed because the client disable notifications
  198. // If you remove this check the webaccess favorites doesn't work.
  199. if(! (m_lpECParentFolder->GetMsgStore()->m_ulProfileFlags & EC_PROFILE_FLAGS_NO_NOTIFICATIONS) )
  200. {
  201. hr = HrAllocAdviseSink(AdviseShortCutCallback, this, &m_lpShortCutAdviseSink);
  202. if (hr != hrSuccess)
  203. return hr;
  204. // NOTE: the advise will destruct at release time
  205. hr = lpShortcutTable->Advise(fnevTableModified, m_lpShortCutAdviseSink, &ulConnection);
  206. if (hr != hrSuccess)
  207. return hr;
  208. }
  209. while(true)
  210. {
  211. rowset_ptr lpRows;
  212. hr = lpShortcutTable->QueryRows(1, 0, &~lpRows);
  213. if (hr != hrSuccess)
  214. return hr;
  215. if (lpRows->cRows == 0)
  216. break;
  217. ModifyRow(&lpRows->aRow[0].lpProps[SC_INSTANCE_KEY].Value.bin, &lpRows->aRow[0]);
  218. }
  219. hr = lpShortcutTable->QueryInterface(IID_IMAPITable, (void **)&m_lpShortcutTable);
  220. if (hr != hrSuccess)
  221. return hr;
  222. }
  223. return hrSuccess;
  224. }
  225. /*
  226. lpInstanceKey Instance key of the item
  227. lpsRow is a property array from the shortcuts
  228. */
  229. HRESULT ECMemTablePublic::ModifyRow(SBinary* lpInstanceKey, LPSRow lpsRow)
  230. {
  231. HRESULT hr = hrSuccess;
  232. memory_ptr<SPropValue> lpProps, lpPropsFolder;
  233. ULONG cProps = 0;
  234. SPropValue sKeyProp;
  235. object_ptr<IMAPIFolder> lpFolderReal;
  236. ULONG ulPropsFolder;
  237. ULONG ulObjType;
  238. ULONG cbEntryID = 0;
  239. ULONG cbFolderID = 0;
  240. LPENTRYID lpEntryID = NULL; //Do not free this
  241. memory_ptr<ENTRYID> lpFolderID, lpRecordKeyID;
  242. std::string strInstanceKey;
  243. ECMAPFolderRelation::const_iterator iterRel;
  244. ECKeyTable::UpdateType ulUpdateType;
  245. ULONG ulRowId;
  246. ULONG ulConnection = 0;
  247. object_ptr<IMAPIAdviseSink> lpFolderAdviseSink;
  248. rowset_ptr lpsRowsInternal;
  249. SPropValue sPropTmp;
  250. t_sRelation sRelFolder = {0};
  251. static constexpr const SizedSPropTagArray(11, sPropsFolderReal) =
  252. {11, { PR_ACCESS, PR_ACCESS_LEVEL, PR_STORE_ENTRYID,
  253. PR_STORE_RECORD_KEY, PR_STORE_SUPPORT_MASK, PR_ACCESS_LEVEL,
  254. PR_CONTENT_COUNT, PR_CONTENT_UNREAD, PR_CONTAINER_CLASS,
  255. PR_ENTRYID}};
  256. if (lpInstanceKey == NULL) {
  257. assert(false);
  258. hr = MAPI_E_INVALID_PARAMETER;
  259. goto exit;
  260. }
  261. strInstanceKey.assign((char*)lpInstanceKey->lpb, lpInstanceKey->cb);
  262. iterRel = m_mapRelation.find(strInstanceKey);
  263. if (iterRel != m_mapRelation.cend()) {
  264. sRelFolder = iterRel->second;
  265. ulRowId = sRelFolder.ulRowID;
  266. ulUpdateType = ECKeyTable::TABLE_ROW_MODIFY;
  267. cbEntryID = sRelFolder.cbEntryID;
  268. lpEntryID = sRelFolder.lpEntryID;
  269. } else {
  270. ulRowId = m_ulRowId;
  271. ulUpdateType = ECKeyTable::TABLE_ROW_ADD;
  272. if (lpsRow == NULL || lpsRow->lpProps[SC_FAV_PUBLIC_SOURCE_KEY].ulPropTag != PR_FAV_PUBLIC_SOURCE_KEY) {
  273. assert(false);
  274. hr = MAPI_E_INVALID_PARAMETER;
  275. goto exit;
  276. }
  277. hr = ((ECMsgStorePublic*)m_lpECParentFolder->GetMsgStore())->EntryIDFromSourceKey(lpsRow->lpProps[SC_FAV_PUBLIC_SOURCE_KEY].Value.bin.cb, lpsRow->lpProps[SC_FAV_PUBLIC_SOURCE_KEY].Value.bin.lpb, 0, NULL, &cbFolderID, &~lpFolderID);
  278. if (hr != hrSuccess)
  279. goto exit;
  280. cbEntryID = cbFolderID;
  281. lpEntryID = lpFolderID;
  282. }
  283. cProps = 0;
  284. hr = MAPIAllocateBuffer(sizeof(SPropValue) * 20, &~lpProps);
  285. if(hr != hrSuccess)
  286. goto exit;
  287. // Default table rows
  288. lpProps[cProps].ulPropTag = PR_ROWID;
  289. lpProps[cProps++].Value.ul = ulRowId;
  290. hr = MAPIAllocateBuffer(cbEntryID, &~lpRecordKeyID);
  291. if (hr != hrSuccess)
  292. goto exit;
  293. memcpy(lpRecordKeyID, lpEntryID, cbEntryID);
  294. lpRecordKeyID->abFlags[3] = KOPANO_FAVORITE;
  295. lpProps[cProps].ulPropTag = PR_RECORD_KEY;
  296. lpProps[cProps].Value.bin.cb = cbEntryID;
  297. lpProps[cProps].Value.bin.lpb = reinterpret_cast<BYTE *>(lpRecordKeyID.get());
  298. ++cProps;
  299. // Set this folder as parent
  300. if (ECGenericProp::DefaultGetProp(PR_ENTRYID, m_lpECParentFolder->GetMsgStore(), 0, &lpProps[cProps], m_lpECParentFolder, lpProps) == hrSuccess) {
  301. lpProps[cProps].ulPropTag = PR_PARENT_ENTRYID;
  302. ((LPENTRYID)lpProps[cProps].Value.bin.lpb)->abFlags[3] = KOPANO_FAVORITE;
  303. ++cProps;
  304. }
  305. lpProps[cProps].ulPropTag = PR_DISPLAY_TYPE;
  306. lpProps[cProps++].Value.ul = DT_FOLDER_LINK;
  307. //FIXME: check if there are subfolders. Do a restriction on the shortcut folder with this folder sourcekey as parent source
  308. lpProps[cProps].ulPropTag = PR_SUBFOLDERS;
  309. lpProps[cProps++].Value.b = TRUE;
  310. // Properties from the real folder
  311. if (ulUpdateType == ECKeyTable::TABLE_ROW_ADD) {
  312. hr = m_lpECParentFolder->OpenEntry(cbEntryID, lpEntryID, &IID_IMAPIFolder, MAPI_BEST_ACCESS, &ulObjType, &~lpFolderReal);
  313. if(hr != hrSuccess)
  314. goto exit;
  315. // No advise needed because the client disable notifications
  316. // If you remove this check the webaccess favorites doesn't work.
  317. if(! (m_lpECParentFolder->GetMsgStore()->m_ulProfileFlags & EC_PROFILE_FLAGS_NO_NOTIFICATIONS) )
  318. {
  319. hr = HrAllocAdviseSink(AdviseFolderCallback, this, &~lpFolderAdviseSink);
  320. if (hr != hrSuccess)
  321. goto exit;
  322. hr = m_lpECParentFolder->GetMsgStore()->Advise(cbEntryID, lpEntryID, fnevObjectModified|fnevObjectCreated|fnevObjectMoved|fnevObjectDeleted, lpFolderAdviseSink, &ulConnection);
  323. if (hr != hrSuccess)
  324. goto exit;
  325. }
  326. }else {
  327. if (sRelFolder.lpFolder)
  328. hr = sRelFolder.lpFolder->QueryInterface(IID_IMAPIFolder, &~lpFolderReal);
  329. else
  330. hr = MAPI_E_CALL_FAILED;
  331. if(hr != hrSuccess)
  332. goto exit;
  333. // Get shortcut folder information
  334. if(lpsRow == NULL)
  335. {
  336. sPropTmp.ulPropTag = PR_INSTANCE_KEY;
  337. sPropTmp.Value.bin = *lpInstanceKey;
  338. hr = ECPropertyRestriction(RELOP_EQ, PR_INSTANCE_KEY, &sPropTmp, ECRestriction::Cheap)
  339. .FindRowIn(m_lpShortcutTable, BOOKMARK_BEGINNING, 0);
  340. if (hr != hrSuccess)
  341. goto exit;
  342. hr = m_lpShortcutTable->QueryRows(1, 0, &~lpsRowsInternal);
  343. if (hr != hrSuccess)
  344. goto exit;
  345. if (lpsRowsInternal->cRows == 0) {
  346. hr = MAPI_E_CALL_FAILED;
  347. goto exit;
  348. }
  349. lpsRow = lpsRowsInternal->aRow;
  350. }
  351. }
  352. // Set the name of the folder, use alias if available otherwise displayname
  353. lpProps[cProps].ulPropTag = PR_DISPLAY_NAME;
  354. if (lpsRow != NULL && lpsRow->cValues == SHORTCUT_NUM && lpsRow->lpProps[SC_FAV_DISPLAY_ALIAS].ulPropTag == PR_FAV_DISPLAY_ALIAS) {
  355. lpProps[cProps++].Value.lpszA = lpsRow->lpProps[SC_FAV_DISPLAY_ALIAS].Value.lpszA;
  356. }else if (lpsRow != NULL && lpsRow->cValues == SHORTCUT_NUM && lpsRow->lpProps[SC_FAV_DISPLAY_NAME].ulPropTag == PR_FAV_DISPLAY_NAME) {
  357. lpProps[cProps++].Value.lpszA = lpsRow->lpProps[SC_FAV_DISPLAY_NAME].Value.lpszA;
  358. } else {
  359. assert(false);
  360. hr = MAPI_E_INVALID_PARAMETER;
  361. goto exit;
  362. }
  363. hr = lpFolderReal->GetProps(sPropsFolderReal, m_ulFlags, &ulPropsFolder, &~lpPropsFolder);
  364. if (FAILED(hr))
  365. goto exit;
  366. else
  367. hr = hrSuccess;
  368. for (ULONG i = 0; i < ulPropsFolder; ++i) {
  369. if (PROP_TYPE(lpPropsFolder[i].ulPropTag) == PT_ERROR)
  370. continue;
  371. if (lpPropsFolder[i].ulPropTag == PR_ACCESS) {
  372. lpPropsFolder[i].Value.ul &=~(MAPI_ACCESS_CREATE_HIERARCHY | MAPI_ACCESS_CREATE_ASSOCIATED);
  373. lpPropsFolder[i].Value.ul |=MAPI_ACCESS_DELETE;
  374. }
  375. if (lpPropsFolder[i].ulPropTag == PR_ENTRYID)
  376. ((LPENTRYID)lpPropsFolder[i].Value.bin.lpb)->abFlags[3] = KOPANO_FAVORITE;
  377. lpProps[cProps].ulPropTag = lpPropsFolder[i].ulPropTag;
  378. lpProps[cProps++].Value = lpPropsFolder[i].Value;
  379. }
  380. // Add the row in the list
  381. sKeyProp.ulPropTag = PR_ROWID;
  382. sKeyProp.Value.ul = ulRowId;
  383. hr = this->HrModifyRow(ulUpdateType, &sKeyProp, lpProps, cProps);
  384. if (hr != hrSuccess)
  385. goto exit;
  386. // Add relation id
  387. if (ulUpdateType == ECKeyTable::TABLE_ROW_ADD) {
  388. sRelFolder.ulRowID = ulRowId;
  389. sRelFolder.cbEntryID = cbEntryID;
  390. hr = MAPIAllocateBuffer(sRelFolder.cbEntryID, (void**)&sRelFolder.lpEntryID);
  391. if (hr != hrSuccess)
  392. goto exit;
  393. memcpy(sRelFolder.lpEntryID, lpEntryID, sRelFolder.cbEntryID);
  394. hr = lpFolderReal->QueryInterface(IID_IMAPIFolder, (void **)&sRelFolder.lpFolder);
  395. if (hr != hrSuccess)
  396. goto exit;
  397. if (lpFolderAdviseSink) { // is NULL when the notification is disabled
  398. hr = lpFolderAdviseSink->QueryInterface(IID_IMAPIAdviseSink, (void **)&sRelFolder.lpAdviseSink);
  399. if (hr != hrSuccess)
  400. goto exit;
  401. sRelFolder.ulAdviseConnectionId = ulConnection;
  402. } else {
  403. sRelFolder.lpAdviseSink = NULL;
  404. sRelFolder.ulAdviseConnectionId = 0;
  405. }
  406. m_mapRelation.insert(ECMAPFolderRelation::value_type(strInstanceKey, sRelFolder));
  407. ++m_ulRowId;
  408. }
  409. exit:
  410. if (hr != hrSuccess && ulConnection > 0)
  411. m_lpECParentFolder->GetMsgStore()->Unadvise(ulConnection);
  412. return hr;
  413. }
  414. HRESULT ECMemTablePublic::DelRow(SBinary* lpInstanceKey)
  415. {
  416. std::string strInstanceKey;
  417. SPropValue sKeyProp;
  418. ECMAPFolderRelation::iterator iterRel;
  419. if (lpInstanceKey == NULL)
  420. return MAPI_E_INVALID_PARAMETER;
  421. strInstanceKey.assign((char*)lpInstanceKey->lpb, lpInstanceKey->cb);
  422. iterRel = m_mapRelation.find(strInstanceKey);
  423. if (iterRel == m_mapRelation.cend())
  424. return hrSuccess;
  425. sKeyProp.ulPropTag = PR_ROWID;
  426. sKeyProp.Value.ul = iterRel->second.ulRowID;
  427. this->HrModifyRow(ECKeyTable::TABLE_ROW_DELETE, NULL, &sKeyProp, 1); //ignore error
  428. if (iterRel->second.ulAdviseConnectionId > 0)
  429. m_lpECParentFolder->GetMsgStore()->Unadvise(iterRel->second.ulAdviseConnectionId);
  430. FreeRelation(&iterRel->second);
  431. m_mapRelation.erase(iterRel);
  432. return hrSuccess;
  433. }
  434. void ECMemTablePublic::FreeRelation(t_sRelation* lpRelation)
  435. {
  436. if (lpRelation == NULL)
  437. return;
  438. if (lpRelation->lpFolder)
  439. lpRelation->lpFolder->Release();
  440. if (lpRelation->lpAdviseSink)
  441. lpRelation->lpAdviseSink->Release();
  442. MAPIFreeBuffer(lpRelation->lpEntryID);
  443. }