ECMemTable.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226
  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/zcdefs.h>
  18. #include <memory>
  19. #include <new>
  20. #include <kopano/platform.h>
  21. #include <kopano/lockhelper.hpp>
  22. #include <kopano/ECInterfaceDefs.h>
  23. #include <mapidefs.h>
  24. #include <mapicode.h>
  25. #include <mapiutil.h>
  26. #include <kopano/ECMemTable.h>
  27. #include <kopano/ECKeyTable.h>
  28. #include <kopano/ECGuid.h>
  29. #include <kopano/Util.h>
  30. #include <kopano/Trace.h>
  31. #include <kopano/CommonUtil.h>
  32. #include <kopano/memory.hpp>
  33. #include <kopano/charset/convert.h>
  34. #include <kopano/kcodes.h>
  35. #include <kopano/ECDebug.h>
  36. #include <algorithm>
  37. // needed for htons()
  38. #include <netdb.h>
  39. using namespace std;
  40. using namespace KCHL;
  41. namespace KC {
  42. static constexpr const SizedSSortOrderSet(1, sSortDefault) = { 0, 0, 0, {} } ;
  43. class FixStringType _kc_final {
  44. public:
  45. FixStringType(ULONG ulFlags) : m_ulFlags(ulFlags) { assert((m_ulFlags & ~MAPI_UNICODE) == 0); }
  46. ULONG operator()(ULONG ulPropTag) const
  47. {
  48. if ((PROP_TYPE(ulPropTag) & 0x0ffe) == 0x1e) // Any string type
  49. return CHANGE_PROP_TYPE(ulPropTag, (((m_ulFlags & MAPI_UNICODE) ? PT_UNICODE : PT_STRING8) | (PROP_TYPE(ulPropTag) & MVI_FLAG)));
  50. else
  51. return ulPropTag;
  52. }
  53. private:
  54. ULONG m_ulFlags;
  55. };
  56. /*
  57. * This is a complete table data / table view implementation, comparable to
  58. * ITableData / IMAPITable. The ECMemTable object holds the information, while
  59. * ECMemTableView is the actual view into the object, implementing the IMAPITable
  60. * interface.
  61. */
  62. ECMemTable::ECMemTable(const SPropTagArray *lpsPropTags, ULONG ulRowPropTag) :
  63. ECUnknown("ECMemTable")
  64. {
  65. this->lpsColumns = (LPSPropTagArray) new BYTE[CbSPropTagArray(lpsPropTags)];
  66. this->lpsColumns->cValues = lpsPropTags->cValues;
  67. memcpy(&this->lpsColumns->aulPropTag, &lpsPropTags->aulPropTag, lpsPropTags->cValues * sizeof(ULONG));
  68. this->ulRowPropTag = ulRowPropTag;
  69. }
  70. ECMemTable::~ECMemTable()
  71. {
  72. HrClear();
  73. delete[] this->lpsColumns;
  74. }
  75. HRESULT ECMemTable::Create(const SPropTagArray *lpsColumns, ULONG ulRowPropTag,
  76. ECMemTable **lppECMemTable)
  77. {
  78. ECMemTable *lpMemTable = NULL;
  79. if(PROP_TYPE(ulRowPropTag) != PT_I8 && PROP_TYPE(ulRowPropTag) != PT_LONG)
  80. {
  81. assert(false);
  82. return MAPI_E_INVALID_TYPE;
  83. }
  84. lpMemTable = new ECMemTable(lpsColumns, ulRowPropTag);
  85. auto ret = lpMemTable->QueryInterface(IID_ECMemTable,
  86. reinterpret_cast<void **>(lppECMemTable));
  87. if (ret != hrSuccess)
  88. delete lpMemTable;
  89. return ret;
  90. }
  91. HRESULT ECMemTable::QueryInterface(REFIID refiid, void **lppInterface)
  92. {
  93. REGISTER_INTERFACE2(ECMemTable, this);
  94. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  95. }
  96. // Get all rowa tables in the table with status type
  97. HRESULT ECMemTable::HrGetAllWithStatus(LPSRowSet *lppRowSet, LPSPropValue *lppIDs, LPULONG *lppulStatus)
  98. {
  99. HRESULT hr = hrSuccess;
  100. rowset_ptr lpRowSet;
  101. memory_ptr<SPropValue> lpIDs;
  102. memory_ptr<ULONG> lpulStatus;
  103. int n = 0;
  104. ulock_rec l_data(m_hDataMutex);
  105. hr = MAPIAllocateBuffer(CbNewSRowSet(mapRows.size()), &~lpRowSet);
  106. if(hr != hrSuccess)
  107. return hr;
  108. hr = MAPIAllocateBuffer(sizeof(SPropValue) * mapRows.size(), &~lpIDs);
  109. if(hr != hrSuccess)
  110. return hr;
  111. hr = MAPIAllocateBuffer(sizeof(ULONG) * mapRows.size(), &~lpulStatus);
  112. if(hr != hrSuccess)
  113. return hr;
  114. for (const auto &rowp : mapRows) {
  115. if (rowp.second.fNew)
  116. lpulStatus[n] = ECROW_ADDED;
  117. else if (rowp.second.fDeleted)
  118. lpulStatus[n] = ECROW_DELETED;
  119. else if (rowp.second.fDirty)
  120. lpulStatus[n] = ECROW_MODIFIED;
  121. else
  122. lpulStatus[n] = ECROW_NORMAL;
  123. lpRowSet->aRow[n].cValues = rowp.second.cValues;
  124. hr = Util::HrCopyPropertyArrayByRef(rowp.second.lpsPropVal, rowp.second.cValues, &lpRowSet->aRow[n].lpProps, &lpRowSet->aRow[n].cValues);
  125. if(hr != hrSuccess)
  126. return hr;
  127. if (rowp.second.lpsID != NULL) {
  128. hr = Util::HrCopyProperty(&lpIDs[n], rowp.second.lpsID, lpIDs);
  129. if(hr != hrSuccess)
  130. return hr;
  131. } else {
  132. lpIDs[n].Value.bin.cb = 0;
  133. lpIDs[n].Value.bin.lpb = NULL;
  134. }
  135. ++n;
  136. }
  137. lpRowSet->cRows = n;
  138. *lppRowSet = lpRowSet.release();
  139. *lppIDs = lpIDs.release();
  140. *lppulStatus = lpulStatus.release();
  141. return hrSuccess;
  142. }
  143. HRESULT ECMemTable::HrGetRowID(LPSPropValue lpRow, LPSPropValue *lppID)
  144. {
  145. std::map<unsigned int, ECTableEntry>::const_iterator iterRows;
  146. scoped_rlock l_data(m_hDataMutex);
  147. if (lpRow->ulPropTag != this->ulRowPropTag)
  148. return MAPI_E_INVALID_PARAMETER;
  149. iterRows = mapRows.find(lpRow->Value.ul);
  150. if (iterRows == mapRows.cend() || iterRows->second.lpsID == NULL)
  151. return MAPI_E_NOT_FOUND;
  152. LPSPropValue lpID = NULL;
  153. HRESULT hr = MAPIAllocateBuffer(sizeof(SPropValue),
  154. reinterpret_cast<void **>(&lpID));
  155. if(hr != hrSuccess)
  156. return hr;
  157. hr = Util::HrCopyProperty(lpID, iterRows->second.lpsID, lpID);
  158. if(hr != hrSuccess)
  159. return hr;
  160. *lppID = lpID;
  161. return hrSuccess;
  162. }
  163. HRESULT ECMemTable::HrGetRowData(LPSPropValue lpRow, ULONG *lpcValues, LPSPropValue *lppRowData)
  164. {
  165. HRESULT hr = hrSuccess;
  166. ULONG cValues = 0;
  167. memory_ptr<SPropValue> lpRowData;
  168. std::map<unsigned int, ECTableEntry>::const_iterator iterRows;
  169. ulock_rec l_data(m_hDataMutex);
  170. if (lpRow->ulPropTag != this->ulRowPropTag)
  171. return MAPI_E_INVALID_PARAMETER;
  172. iterRows = mapRows.find(lpRow->Value.ul);
  173. if (iterRows == mapRows.cend() || iterRows->second.lpsID == NULL)
  174. return MAPI_E_NOT_FOUND;
  175. hr = Util::HrCopyPropertyArray(iterRows->second.lpsPropVal, iterRows->second.cValues, &~lpRowData, &cValues);
  176. if(hr != hrSuccess)
  177. return hr;
  178. *lpcValues = cValues;
  179. *lppRowData = lpRowData.release();
  180. return hrSuccess;
  181. }
  182. // This function is called to reset the add/modify/delete flags of all
  183. // the rows. This is normally called after saving the data from the HrGet* functions
  184. // to the storage.
  185. HRESULT ECMemTable::HrSetClean()
  186. {
  187. HRESULT hr = hrSuccess;
  188. map<unsigned int, ECTableEntry>::iterator iterRows;
  189. map<unsigned int, ECTableEntry>::iterator iterNext;
  190. scoped_rlock l_data(m_hDataMutex);
  191. for (iterRows = mapRows.begin(); iterRows != mapRows.end(); iterRows = iterNext) {
  192. iterNext = iterRows;
  193. ++iterNext;
  194. if(iterRows->second.fDeleted) {
  195. MAPIFreeBuffer(iterRows->second.lpsID);
  196. MAPIFreeBuffer(iterRows->second.lpsPropVal);
  197. mapRows.erase(iterRows);
  198. continue;
  199. }
  200. iterRows->second.fDeleted = false;
  201. iterRows->second.fDirty = false;
  202. iterRows->second.fNew = false;
  203. }
  204. return hr;
  205. }
  206. HRESULT ECMemTable::HrUpdateRowID(LPSPropValue lpId, LPSPropValue lpProps, ULONG cValues)
  207. {
  208. scoped_rlock l_data(m_hDataMutex);
  209. auto lpUniqueProp = PCpropFindProp(lpProps, cValues, ulRowPropTag);
  210. if (lpUniqueProp == NULL)
  211. return MAPI_E_INVALID_PARAMETER;
  212. auto iterRows = mapRows.find(lpUniqueProp->Value.ul);
  213. if (iterRows == mapRows.cend())
  214. return MAPI_E_NOT_FOUND;
  215. MAPIFreeBuffer(iterRows->second.lpsID);
  216. HRESULT hr = MAPIAllocateBuffer(sizeof(SPropValue),
  217. reinterpret_cast<void **>(&iterRows->second.lpsID));
  218. if(hr != hrSuccess)
  219. return hr;
  220. return Util::HrCopyProperty(iterRows->second.lpsID, lpId, iterRows->second.lpsID);
  221. }
  222. /*
  223. * This is not as easy as it seems. This is how we handle updates:
  224. *
  225. * There are really only two operations, ADD and DELETE, in which ADD can either add a
  226. * row or modify an existing row, and DELETE can delete a row. We basically handle TABLE_ROW_ADD
  227. * and TABLE_ROW_MODIFY exactly the same:
  228. *
  229. * - If there is an index column in the row:
  230. * - Existing row, then modify the existing row
  231. * - Non-existing row, then add a new row
  232. * - If there is no index column, exit with an error
  233. *
  234. */
  235. HRESULT ECMemTable::HrModifyRow(ULONG ulUpdateType, const SPropValue *lpsID,
  236. const SPropValue *lpPropVals, ULONG cValues)
  237. {
  238. HRESULT hr = hrSuccess;
  239. ECTableEntry entry;
  240. std::map<unsigned int, ECTableEntry>::iterator iterRows;
  241. scoped_rlock l_data(m_hDataMutex);
  242. auto lpsRowID = PCpropFindProp(lpPropVals, cValues, ulRowPropTag);
  243. if (lpsRowID == NULL)
  244. // you must specify a row number
  245. return MAPI_E_INVALID_PARAMETER;
  246. iterRows = mapRows.find(lpsRowID->Value.ul);
  247. if (ulUpdateType == ECKeyTable::TABLE_ROW_ADD && iterRows != mapRows.cend())
  248. // Row is already in here, move to modify
  249. ulUpdateType = ECKeyTable::TABLE_ROW_MODIFY;
  250. if (ulUpdateType == ECKeyTable::TABLE_ROW_MODIFY && iterRows == mapRows.cend())
  251. // Row not found, move to add
  252. ulUpdateType = ECKeyTable::TABLE_ROW_ADD;
  253. if (ulUpdateType == ECKeyTable::TABLE_ROW_DELETE && iterRows == mapRows.cend())
  254. // Row to delete is nonexistent
  255. return MAPI_E_NOT_FOUND;
  256. if(ulUpdateType == ECKeyTable::TABLE_ROW_DELETE) {
  257. iterRows->second.fDeleted = TRUE;
  258. iterRows->second.fDirty = FALSE;
  259. iterRows->second.fNew = FALSE;
  260. }
  261. if(ulUpdateType == ECKeyTable::TABLE_ROW_MODIFY) {
  262. iterRows->second.fDeleted = FALSE;
  263. iterRows->second.fDirty = TRUE;
  264. if(lpPropVals) {
  265. // We want to support users calling ModifyRow with data that itself
  266. // was retrieved from this table. So, the data passed in lpPropVals may
  267. // refer to data that is allocated from iterRows->second.lpsPropVal.
  268. //
  269. // We therefore save the old value, copy the new properties, and THEN
  270. // free the old row.
  271. LPSPropValue lpOldPropVal = iterRows->second.lpsPropVal;
  272. // Update new row
  273. hr = Util::HrCopyPropertyArray(lpPropVals, cValues, &iterRows->second.lpsPropVal, &iterRows->second.cValues, /* exclude PT_ERRORs */ true);
  274. if(hr != hrSuccess)
  275. return hr;
  276. // Free old row
  277. MAPIFreeBuffer(lpOldPropVal);
  278. }
  279. }
  280. if(ulUpdateType == ECKeyTable::TABLE_ROW_ADD) {
  281. hr = Util::HrCopyPropertyArray(lpPropVals, cValues, &entry.lpsPropVal, &entry.cValues);
  282. if(hr != hrSuccess)
  283. return hr;
  284. entry.fDeleted = FALSE;
  285. entry.fDirty = TRUE;
  286. entry.fNew = TRUE;
  287. if(lpsID) {
  288. hr = MAPIAllocateBuffer(sizeof(SPropValue), (void **)&entry.lpsID);
  289. if(hr != hrSuccess)
  290. return hr;
  291. hr = Util::HrCopyProperty(entry.lpsID, lpsID, entry.lpsID);
  292. if(hr != hrSuccess)
  293. return hr;
  294. } else {
  295. entry.lpsID = NULL;
  296. }
  297. // Add the actual data
  298. mapRows[lpsRowID->Value.ul] = entry;
  299. }
  300. for (auto viewp : lstViews) {
  301. hr = viewp->UpdateRow(ulUpdateType, lpsRowID->Value.ul);
  302. if(hr != hrSuccess)
  303. return hr;
  304. }
  305. return hr;
  306. }
  307. HRESULT ECMemTable::HrGetView(const ECLocale &locale, ULONG ulFlags, ECMemTableView **lppView)
  308. {
  309. ECMemTableView *lpView = NULL;
  310. scoped_rlock l_data(m_hDataMutex);
  311. HRESULT hr = ECMemTableView::Create(this, locale, ulFlags, &lpView);
  312. if (hr != hrSuccess)
  313. return hr;
  314. lstViews.push_back(lpView);
  315. AddChild(lpView);
  316. *lppView = lpView;
  317. return hrSuccess;
  318. }
  319. HRESULT ECMemTable::HrDeleteAll()
  320. {
  321. scoped_rlock l_data(m_hDataMutex);
  322. for (auto &rowp : mapRows) {
  323. rowp.second.fDeleted = TRUE;
  324. rowp.second.fDirty = FALSE;
  325. rowp.second.fNew = FALSE;
  326. }
  327. for (auto viewp : lstViews)
  328. viewp->Clear();
  329. return hrSuccess;
  330. }
  331. HRESULT ECMemTable::HrClear()
  332. {
  333. scoped_rlock l_data(m_hDataMutex);
  334. for (const auto &rowp : mapRows) {
  335. MAPIFreeBuffer(rowp.second.lpsPropVal);
  336. MAPIFreeBuffer(rowp.second.lpsID);
  337. }
  338. // Clear list
  339. mapRows.clear();
  340. // Update views
  341. for (auto viewp : lstViews)
  342. viewp->Clear();
  343. return hrSuccess;
  344. }
  345. /*
  346. * This is the IMAPITable-compatible view section of the ECMemTable. It holds hardly any
  347. * data and is therefore very lightweight. We use the fast ECKeyTable keying system to do
  348. * the actual sorting, etc.
  349. */
  350. ECMemTableView::ECMemTableView(ECMemTable *lpMemTable, const ECLocale &locale,
  351. ULONG ulFlags) :
  352. ECUnknown("ECMemTableView"), lpKeyTable(new ECKeyTable)
  353. {
  354. this->lpMemTable = lpMemTable;
  355. this->lpsPropTags = (LPSPropTagArray) new BYTE[CbNewSPropTagArray(lpMemTable->lpsColumns->cValues)];
  356. lpsPropTags->cValues = lpMemTable->lpsColumns->cValues;
  357. std::transform(lpMemTable->lpsColumns->aulPropTag, lpMemTable->lpsColumns->aulPropTag + lpMemTable->lpsColumns->cValues, (ULONG*)lpsPropTags->aulPropTag, FixStringType(ulFlags & MAPI_UNICODE));
  358. SortTable(sSortDefault, 0);
  359. m_ulConnection = 1;
  360. m_ulFlags = ulFlags & MAPI_UNICODE;
  361. m_locale = locale;
  362. }
  363. ECMemTableView::~ECMemTableView()
  364. {
  365. ECMapMemAdvise::const_iterator iterAdvise, iterAdviseRemove;
  366. // Remove ourselves from the parent's view list
  367. for (auto iterViews = lpMemTable->lstViews.begin();
  368. iterViews != lpMemTable->lstViews.cend(); ++iterViews)
  369. if(*iterViews == this) {
  370. lpMemTable->lstViews.erase(iterViews);
  371. break;
  372. }
  373. // Remove advises
  374. iterAdvise = m_mapAdvise.cbegin();
  375. while (iterAdvise != m_mapAdvise.cend()) {
  376. iterAdviseRemove = iterAdvise;
  377. ++iterAdvise;
  378. Unadvise(iterAdviseRemove->first);
  379. }
  380. delete[] this->lpsPropTags;
  381. delete[] lpsSortOrderSet;
  382. delete lpKeyTable;
  383. MAPIFreeBuffer(lpsRestriction);
  384. }
  385. HRESULT ECMemTableView::Create(ECMemTable *lpMemTable, const ECLocale &locale, ULONG ulFlags, ECMemTableView **lppMemTableView)
  386. {
  387. HRESULT hr = hrSuccess;
  388. auto lpView = new(std::nothrow) ECMemTableView(lpMemTable, locale, ulFlags);
  389. if (lpView == nullptr)
  390. return MAPI_E_NOT_ENOUGH_MEMORY;
  391. hr = lpView->QueryInterface(IID_ECMemTableView, (void **) lppMemTableView);
  392. if(hr != hrSuccess)
  393. delete lpView;
  394. return hr;
  395. }
  396. HRESULT ECMemTableView::QueryInterface(REFIID refiid, void **lppInterface)
  397. {
  398. REGISTER_INTERFACE2(ECMemTableView, this);
  399. REGISTER_INTERFACE2(ECUnknown, this);
  400. REGISTER_INTERFACE2(IMAPITable, &this->m_xMAPITable);
  401. REGISTER_INTERFACE2(IUnknown, &this->m_xMAPITable);
  402. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  403. }
  404. HRESULT ECMemTableView::GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR *lppMAPIError)
  405. {
  406. return MAPI_E_NO_SUPPORT;
  407. }
  408. HRESULT ECMemTableView::Advise(ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink, ULONG * lpulConnection)
  409. {
  410. ECMEMADVISE *lpMemAdvise = NULL;
  411. ULONG ulConnection = m_ulConnection++;
  412. if (lpAdviseSink == NULL || lpulConnection == NULL)
  413. return MAPI_E_INVALID_PARAMETER;
  414. lpAdviseSink->AddRef();
  415. lpMemAdvise = new ECMEMADVISE;
  416. lpMemAdvise->lpAdviseSink = lpAdviseSink;
  417. lpMemAdvise->ulEventMask = ulEventMask;
  418. m_mapAdvise.insert( ECMapMemAdvise::value_type( ulConnection, lpMemAdvise) );
  419. *lpulConnection = ulConnection;
  420. return hrSuccess;
  421. }
  422. HRESULT ECMemTableView::Unadvise(ULONG ulConnection)
  423. {
  424. HRESULT hr = hrSuccess;
  425. // Remove notify from list
  426. ECMapMemAdvise::const_iterator iterAdvise = m_mapAdvise.find(ulConnection);
  427. if (iterAdvise == m_mapAdvise.cend()) {
  428. assert(false);
  429. return hr;
  430. }
  431. if (iterAdvise->second->lpAdviseSink != NULL)
  432. iterAdvise->second->lpAdviseSink->Release();
  433. delete iterAdvise->second;
  434. m_mapAdvise.erase(iterAdvise);
  435. return hr;
  436. }
  437. HRESULT ECMemTableView::Notify(ULONG ulTableEvent, sObjectTableKey* lpsRowItem, sObjectTableKey* lpsPrevRow)
  438. {
  439. HRESULT hr = hrSuccess;
  440. memory_ptr<NOTIFICATION> lpNotification;
  441. rowset_ptr lpRows;
  442. ECObjectTableList sRowList;
  443. hr = MAPIAllocateBuffer(sizeof(NOTIFICATION), &~lpNotification);
  444. if(hr != hrSuccess)
  445. return hr;
  446. memset(lpNotification, 0, sizeof(NOTIFICATION));
  447. lpNotification->ulEventType = fnevTableModified;
  448. lpNotification->info.tab.ulTableEvent = ulTableEvent;
  449. if (lpsPrevRow == NULL || lpsPrevRow->ulObjId == 0) {
  450. lpNotification->info.tab.propPrior.ulPropTag = PR_NULL;
  451. } else {
  452. lpNotification->info.tab.propPrior.ulPropTag = PR_INSTANCE_KEY;
  453. lpNotification->info.tab.propPrior.Value.bin.cb = sizeof(ULONG)*2;
  454. hr = MAPIAllocateMore(lpNotification->info.tab.propPrior.Value.bin.cb, lpNotification, (void**)&lpNotification->info.tab.propPrior.Value.bin.lpb);
  455. if(hr != hrSuccess)
  456. return hr;
  457. memcpy(lpNotification->info.tab.propPrior.Value.bin.lpb, &lpsPrevRow->ulObjId, sizeof(ULONG));
  458. memcpy(lpNotification->info.tab.propPrior.Value.bin.lpb+sizeof(ULONG), &lpsPrevRow->ulOrderId, sizeof(ULONG));
  459. }
  460. if (lpsRowItem == NULL || lpsRowItem->ulObjId == 0) {
  461. lpNotification->info.tab.propIndex.ulPropTag = PR_NULL;
  462. } else {
  463. lpNotification->info.tab.propIndex.ulPropTag = PR_INSTANCE_KEY;
  464. lpNotification->info.tab.propIndex.Value.bin.cb = sizeof(ULONG)*2;
  465. hr = MAPIAllocateMore(lpNotification->info.tab.propIndex.Value.bin.cb, lpNotification, (void**)&lpNotification->info.tab.propIndex.Value.bin.lpb);
  466. if(hr != hrSuccess)
  467. return hr;
  468. memcpy(lpNotification->info.tab.propIndex.Value.bin.lpb, &lpsRowItem->ulObjId, sizeof(ULONG));
  469. memcpy(lpNotification->info.tab.propIndex.Value.bin.lpb+sizeof(ULONG), &lpsRowItem->ulOrderId, sizeof(ULONG));
  470. }
  471. switch(ulTableEvent) {
  472. case TABLE_ROW_ADDED:
  473. case TABLE_ROW_MODIFIED:
  474. if (lpsRowItem == nullptr)
  475. return MAPI_E_INVALID_PARAMETER;
  476. sRowList.push_back(*lpsRowItem);
  477. hr = QueryRowData(&sRowList, &~lpRows);
  478. if(hr != hrSuccess)
  479. return hr;
  480. lpNotification->info.tab.row.cValues = lpRows->aRow[0].cValues;
  481. lpNotification->info.tab.row.lpProps = lpRows->aRow[0].lpProps;
  482. break;
  483. default:
  484. break;// no row needed
  485. }
  486. // Push the notifications
  487. for (const auto &adv : m_mapAdvise)
  488. //FIXME: maybe thought the MAPISupport ?
  489. adv.second->lpAdviseSink->OnNotify(1, lpNotification);
  490. return hrSuccess;
  491. }
  492. HRESULT ECMemTableView::GetStatus(ULONG *lpulTableStatus, ULONG *lpulTableType)
  493. {
  494. *lpulTableStatus = TBLSTAT_COMPLETE;
  495. *lpulTableType = TBLTYPE_DYNAMIC;
  496. return hrSuccess;
  497. }
  498. HRESULT ECMemTableView::SetColumns(const SPropTagArray *lpPropTagArray,
  499. ULONG ulFlags)
  500. {
  501. delete[] this->lpsPropTags;
  502. lpsPropTags = (LPSPropTagArray) new BYTE[CbNewSPropTagArray(lpPropTagArray->cValues)];
  503. lpsPropTags->cValues = lpPropTagArray->cValues;
  504. memcpy(&lpsPropTags->aulPropTag, &lpPropTagArray->aulPropTag, lpPropTagArray->cValues * sizeof(ULONG));
  505. Notify(TABLE_SETCOL_DONE, NULL, NULL);
  506. return hrSuccess;
  507. }
  508. HRESULT ECMemTableView::QueryColumns(ULONG ulFlags, LPSPropTagArray *lppPropTagArray)
  509. {
  510. HRESULT hr;
  511. LPSPropTagArray lpsPropTagArray = NULL;
  512. std::list<ULONG> lstTags;
  513. unsigned int i = 0;
  514. if ((ulFlags & ~TBL_ALL_COLUMNS) != 0)
  515. return MAPI_E_UNKNOWN_FLAGS;
  516. if(ulFlags & TBL_ALL_COLUMNS) {
  517. FixStringType fix(m_ulFlags);
  518. // All columns is an aggregate of .. 1. Our column list of columns that we always support and 2.
  519. // any other columns in our data set that we can find
  520. // Our standard set
  521. for (i = 0; i < lpMemTable->lpsColumns->cValues; ++i)
  522. // Return the string tags based on m_ulFlags (passed when the ECMemTable was created).
  523. lstTags.push_back(fix(lpMemTable->lpsColumns->aulPropTag[i]));
  524. // All other property tags of all rows
  525. for (const auto &rowp : lpMemTable->mapRows)
  526. for (i = 0; i < rowp.second.cValues; ++i)
  527. if (PROP_TYPE(rowp.second.lpsPropVal[i].ulPropTag) != PT_ERROR &&
  528. PROP_TYPE(rowp.second.lpsPropVal[i].ulPropTag) != PT_NULL)
  529. // Return the string tags based on m_ulFlags (passed when the ECMemTable was created).
  530. lstTags.push_back(fix(rowp.second.lpsPropVal[i].ulPropTag));
  531. // Remove doubles
  532. lstTags.sort();
  533. lstTags.unique();
  534. hr = MAPIAllocateBuffer(CbNewSPropTagArray(lstTags.size()), (void **)&lpsPropTagArray);
  535. if(hr != hrSuccess)
  536. return hr;
  537. lpsPropTagArray->cValues = lstTags.size();
  538. i = 0;
  539. for (auto tag : lstTags)
  540. lpsPropTagArray->aulPropTag[i++] = tag;
  541. } else if(this->lpsPropTags) {
  542. hr = MAPIAllocateBuffer(CbNewSPropTagArray(lpsPropTags->cValues),(void **)&lpsPropTagArray);
  543. if(hr != hrSuccess)
  544. return hr;
  545. lpsPropTagArray->cValues = this->lpsPropTags->cValues;
  546. memcpy(&lpsPropTagArray->aulPropTag, &this->lpsPropTags->aulPropTag, sizeof(ULONG) * this->lpsPropTags->cValues);
  547. } else {
  548. return MAPI_E_NOT_FOUND;
  549. }
  550. *lppPropTagArray = lpsPropTagArray;
  551. return hrSuccess;
  552. }
  553. HRESULT ECMemTableView::GetRowCount(ULONG ulFlags, ULONG *lpulCount)
  554. {
  555. unsigned int ulCount;
  556. unsigned int ulCurrentRow;
  557. if(lpulCount == NULL)
  558. return MAPI_E_INVALID_PARAMETER;
  559. ECRESULT er = this->lpKeyTable->GetRowCount(&ulCount, &ulCurrentRow);
  560. HRESULT hr = kcerr_to_mapierr(er);
  561. if(hr != hrSuccess)
  562. return hr;
  563. *lpulCount = ulCount;
  564. return hrSuccess;
  565. }
  566. HRESULT ECMemTableView::SeekRow(BOOKMARK bkOrigin, LONG lRowCount, LONG *lplRowsSought)
  567. {
  568. int lRowsSought;
  569. ECRESULT er = this->lpKeyTable->SeekRow(static_cast<unsigned int>(bkOrigin),
  570. lRowCount, &lRowsSought);
  571. HRESULT hr = kcerr_to_mapierr(er);
  572. if(hr != hrSuccess)
  573. return hr;
  574. if(lplRowsSought)
  575. *lplRowsSought = lRowsSought;
  576. return hrSuccess;
  577. }
  578. HRESULT ECMemTableView::SeekRowApprox(ULONG ulNumerator, ULONG ulDenominator)
  579. {
  580. unsigned int ulRows = 0;
  581. unsigned int ulCurrentRow = 0;
  582. ECRESULT er = lpKeyTable->GetRowCount(&ulRows, &ulCurrentRow);
  583. HRESULT hr = kcerr_to_mapierr(er);
  584. if(hr != hrSuccess)
  585. return hr;
  586. return SeekRow(BOOKMARK_BEGINNING, static_cast<ULONG>(static_cast<double>(ulRows) * (static_cast<double>(ulNumerator) / ulDenominator)), NULL);
  587. }
  588. HRESULT ECMemTableView::QueryPosition(ULONG *lpulRow, ULONG *lpulNumerator, ULONG *lpulDenominator)
  589. {
  590. unsigned int ulRows = 0;
  591. unsigned int ulCurrentRow = 0;
  592. if (lpulRow == NULL || lpulNumerator == NULL || lpulDenominator == NULL)
  593. return MAPI_E_INVALID_PARAMETER;
  594. ECRESULT er = lpKeyTable->GetRowCount(&ulRows, &ulCurrentRow);
  595. HRESULT hr = kcerr_to_mapierr(er);
  596. if(hr != hrSuccess)
  597. return hr;
  598. *lpulRow = ulCurrentRow;
  599. *lpulNumerator = ulCurrentRow;
  600. *lpulDenominator = ulRows;
  601. return hrSuccess;
  602. }
  603. HRESULT ECMemTableView::FindRow(LPSRestriction lpRestriction, BOOKMARK bkOrigin, ULONG ulFlags)
  604. {
  605. HRESULT hr;
  606. ECRESULT er;
  607. ECObjectTableList sRowList;
  608. sObjectTableKey sRowItem;
  609. if (lpRestriction == NULL)
  610. return MAPI_E_INVALID_PARAMETER;
  611. if( lpRestriction->rt == RES_PROPERTY &&
  612. lpRestriction->res.resProperty.lpProp->ulPropTag == this->lpMemTable->ulRowPropTag &&
  613. bkOrigin == BOOKMARK_BEGINNING)
  614. {
  615. sRowItem.ulObjId = lpRestriction->res.resContent.lpProp->Value.ul;
  616. sRowItem.ulOrderId = 0; // FIXME:mvprops ?
  617. return kcerr_to_mapierr(this->lpKeyTable->SeekId(&sRowItem));
  618. }
  619. if (bkOrigin == BOOKMARK_END && ulFlags & DIR_BACKWARD)
  620. // Loop through the rows
  621. er = SeekRow(bkOrigin, -1, NULL);
  622. else
  623. er = SeekRow(bkOrigin, 0, NULL);
  624. hr = kcerr_to_mapierr(er);
  625. if(hr != hrSuccess)
  626. return hr;
  627. // Loop through the rows until one matches.
  628. while(1) {
  629. er = this->lpKeyTable->QueryRows(1, &sRowList, ulFlags & DIR_BACKWARD, 0);
  630. hr = kcerr_to_mapierr(er);
  631. if(hr != hrSuccess)
  632. return hr;
  633. if (sRowList.empty())
  634. return MAPI_E_NOT_FOUND;
  635. if(TestRestriction(lpRestriction,
  636. this->lpMemTable->mapRows[sRowList.begin()->ulObjId].cValues,
  637. this->lpMemTable->mapRows[sRowList.begin()->ulObjId].lpsPropVal,
  638. m_locale) == hrSuccess) {
  639. if (ulFlags & DIR_BACKWARD)
  640. er = SeekRow(BOOKMARK_CURRENT, 1, NULL);
  641. else
  642. er = SeekRow(BOOKMARK_CURRENT, -1, NULL);
  643. hr = kcerr_to_mapierr(er);
  644. break;
  645. }
  646. sRowList.clear();
  647. }
  648. return hr;
  649. }
  650. HRESULT ECMemTableView::Restrict(LPSRestriction lpRestriction, ULONG ulFlags)
  651. {
  652. HRESULT hr = hrSuccess;
  653. MAPIFreeBuffer(this->lpsRestriction);
  654. this->lpsRestriction = NULL;
  655. if(lpRestriction)
  656. hr = Util::HrCopySRestriction(&this->lpsRestriction, lpRestriction);
  657. else
  658. this->lpsRestriction = NULL;
  659. if(hr != hrSuccess)
  660. return hr;
  661. hr = this->UpdateSortOrRestrict();
  662. if (hr == hrSuccess)
  663. Notify(TABLE_RESTRICT_DONE, NULL, NULL);
  664. return hr;
  665. }
  666. HRESULT ECMemTableView::CreateBookmark(BOOKMARK* lpbkPosition)
  667. {
  668. unsigned int bkPosition = 0;
  669. if (lpbkPosition == NULL)
  670. return MAPI_E_INVALID_PARAMETER;
  671. ECRESULT er = this->lpKeyTable->CreateBookmark(&bkPosition);
  672. HRESULT hr = kcerr_to_mapierr(er);
  673. if(hr != hrSuccess)
  674. return hr;
  675. *lpbkPosition = bkPosition;
  676. return hrSuccess;
  677. }
  678. HRESULT ECMemTableView::FreeBookmark(BOOKMARK bkPosition)
  679. {
  680. return kcerr_to_mapierr(this->lpKeyTable->FreeBookmark(static_cast<unsigned int>(bkPosition)));
  681. }
  682. // This is the client version of ECGenericObjectTable::GetBinarySortKey()
  683. HRESULT ECMemTableView::GetBinarySortKey(const SPropValue *lpsPropVal,
  684. unsigned int *lpSortLen, unsigned char *lpFlags,
  685. unsigned char **lppSortData)
  686. {
  687. unsigned char *lpSortData = NULL;
  688. unsigned int ulSortLen = 0;
  689. unsigned char ulFlags = 0;
  690. switch(PROP_TYPE(lpsPropVal->ulPropTag)) {
  691. case PT_BOOLEAN:
  692. case PT_I2:
  693. ulSortLen = 2;
  694. lpSortData = new unsigned char[2];
  695. *(unsigned short *)lpSortData = htons(lpsPropVal->Value.b);
  696. break;
  697. case PT_LONG:
  698. ulSortLen = 4;
  699. lpSortData = new unsigned char[4];
  700. *(unsigned int *)lpSortData = htonl(lpsPropVal->Value.ul);
  701. break;
  702. case PT_R4:
  703. ulSortLen = sizeof(double);
  704. lpSortData = new unsigned char[sizeof(double)];
  705. *(double *)lpSortData = lpsPropVal->Value.flt;
  706. break;
  707. case PT_DOUBLE:
  708. ulSortLen = sizeof(double);
  709. lpSortData = new unsigned char[sizeof(double)];
  710. *(double *)lpSortData = lpsPropVal->Value.dbl;
  711. break;
  712. case PT_APPTIME:
  713. ulSortLen = sizeof(double);
  714. lpSortData = new unsigned char[sizeof(double)];
  715. *(double *)lpSortData = lpsPropVal->Value.at;
  716. break;
  717. case PT_CURRENCY:// FIXME: unsortable
  718. ulSortLen = 0;
  719. lpSortData = NULL;
  720. break;
  721. case PT_SYSTIME:
  722. ulSortLen = 8;
  723. lpSortData = new unsigned char[8];
  724. *(unsigned int *)lpSortData = htonl(lpsPropVal->Value.ft.dwHighDateTime);
  725. *(unsigned int *)(lpSortData+4) = htonl(lpsPropVal->Value.ft.dwLowDateTime);
  726. break;
  727. case PT_I8:
  728. ulSortLen = 8;
  729. lpSortData = new unsigned char[8];
  730. *(unsigned int *)lpSortData = htonl((unsigned int)(lpsPropVal->Value.li.QuadPart >> 32));
  731. *(unsigned int *)(lpSortData+4) = htonl((unsigned int)lpsPropVal->Value.li.QuadPart);
  732. break;
  733. case PT_STRING8:
  734. case PT_UNICODE: {
  735. if (!lpsPropVal->Value.lpszA) { // Checks both lpszA and lpszW
  736. ulSortLen = 0;
  737. lpSortData = NULL;
  738. break;
  739. }
  740. if (PROP_TYPE(lpsPropVal->ulPropTag) == PT_STRING8)
  741. createSortKeyData(lpsPropVal->Value.lpszA, 255, m_locale, &ulSortLen, &lpSortData);
  742. else
  743. createSortKeyData(lpsPropVal->Value.lpszW, 255, m_locale, &ulSortLen, &lpSortData);
  744. }
  745. break;
  746. case PT_CLSID:
  747. case PT_BINARY:
  748. ulSortLen = lpsPropVal->Value.bin.cb;
  749. lpSortData = new unsigned char [ulSortLen];
  750. memcpy(lpSortData, lpsPropVal->Value.bin.lpb, ulSortLen); // could be optimized to one func
  751. break;
  752. case PT_ERROR:
  753. ulSortLen = 0;
  754. lpSortData = NULL;
  755. break;
  756. default:
  757. return MAPI_E_INVALID_TYPE;
  758. }
  759. *lpSortLen = ulSortLen;
  760. *lppSortData = lpSortData;
  761. *lpFlags = ulFlags;
  762. return hrSuccess;
  763. }
  764. HRESULT ECMemTableView::SortTable(const SSortOrderSet *lpSortCriteria,
  765. ULONG ulFlags)
  766. {
  767. HRESULT hr = hrSuccess;
  768. if (!lpSortCriteria)
  769. lpSortCriteria = sSortDefault;
  770. delete[] lpsSortOrderSet;
  771. lpsSortOrderSet = (LPSSortOrderSet) new BYTE[CbSSortOrderSet(lpSortCriteria)];
  772. memcpy(lpsSortOrderSet, lpSortCriteria, CbSSortOrderSet(lpSortCriteria));
  773. hr = UpdateSortOrRestrict();
  774. if (hr == hrSuccess)
  775. Notify(TABLE_SORT_DONE, NULL, NULL);
  776. return hr;
  777. }
  778. HRESULT ECMemTableView::UpdateSortOrRestrict() {
  779. HRESULT hr = hrSuccess;
  780. sObjectTableKey sRowItem;
  781. // Clear the keytable
  782. lpKeyTable->Clear();
  783. // Add the columns into the keytable, which does the actual sorting, etc.
  784. for (const auto &recip : lpMemTable->mapRows) {
  785. if (recip.second.fDeleted)
  786. continue;
  787. sRowItem.ulObjId = recip.first;
  788. sRowItem.ulOrderId = 0;
  789. ModifyRowKey(&sRowItem, NULL, NULL);
  790. }
  791. // Seek to start of table (FIXME should this seek to the previously selected row ?)
  792. lpKeyTable->SeekRow(ECKeyTable::EC_SEEK_SET, 0 , NULL);
  793. return hr;
  794. }
  795. HRESULT ECMemTableView::ModifyRowKey(sObjectTableKey *lpsRowItem, sObjectTableKey* lpsPrevRow, ULONG *lpulAction)
  796. {
  797. std::unique_ptr<unsigned int[]> lpulSortLen;
  798. std::unique_ptr<unsigned char *[]> lpSortKeys;
  799. std::unique_ptr<unsigned char[]> lpFlags;
  800. ULONG j;
  801. // FIXME: mvprops?
  802. // now is only ulObjId used from lpsRowItem
  803. if (lpsRowItem == NULL)
  804. return MAPI_E_INVALID_PARAMETER;
  805. auto iterData = lpMemTable->mapRows.find(lpsRowItem->ulObjId);
  806. if (iterData == lpMemTable->mapRows.cend())
  807. return MAPI_E_NOT_FOUND;
  808. if (lpsSortOrderSet && lpsSortOrderSet->cSorts > 0){
  809. lpulSortLen.reset(new unsigned int [lpsSortOrderSet->cSorts]);
  810. lpFlags.reset(new unsigned char [lpsSortOrderSet->cSorts]);
  811. lpSortKeys.reset(new unsigned char * [lpsSortOrderSet->cSorts]);
  812. }
  813. // Check if there is a restriction in place, and if so, apply it
  814. if (this->lpsRestriction != nullptr &&
  815. TestRestriction(this->lpsRestriction, iterData->second.cValues, iterData->second.lpsPropVal, m_locale) != hrSuccess) {
  816. // no match
  817. // Remove the row, ignore error
  818. lpKeyTable->UpdateRow(ECKeyTable::TABLE_ROW_DELETE, lpsRowItem, 0, NULL, NULL, NULL, lpsPrevRow, false, (ECKeyTable::UpdateType*)lpulAction);
  819. return hrSuccess;
  820. }
  821. if (lpsSortOrderSet == nullptr)
  822. return hrSuccess;
  823. // Get all the sort columns and package them as binary keys
  824. for (j = 0; j < lpsSortOrderSet->cSorts; ++j) {
  825. auto lpsSortID = PCpropFindProp(iterData->second.lpsPropVal, iterData->second.cValues, lpsSortOrderSet->aSort[j].ulPropTag);
  826. if (lpsSortID == NULL || GetBinarySortKey(lpsSortID, &lpulSortLen[j], &lpFlags[j], &lpSortKeys[j]) != hrSuccess) {
  827. lpulSortLen[j] = 0;
  828. lpSortKeys[j] = NULL;
  829. lpFlags[j] = 0;
  830. continue;
  831. }
  832. // Mark as descending if required
  833. if(lpsSortOrderSet->aSort[j].ulOrder == TABLE_SORT_DESCEND)
  834. lpFlags[j] |= TABLEROW_FLAG_DESC;
  835. }
  836. lpKeyTable->UpdateRow(ECKeyTable::TABLE_ROW_ADD, lpsRowItem,
  837. lpsSortOrderSet->cSorts, lpulSortLen.get(), lpFlags.get(),
  838. lpSortKeys.get(), lpsPrevRow, false,
  839. (ECKeyTable::UpdateType*)lpulAction);
  840. // clean up GetBinarySortKey() allocs
  841. for (j = 0; j < lpsSortOrderSet->cSorts; ++j)
  842. delete[] lpSortKeys[j];
  843. return hrSuccess;
  844. }
  845. HRESULT ECMemTableView::QuerySortOrder(LPSSortOrderSet *lppSortCriteria)
  846. {
  847. LPSSortOrderSet lpSortCriteria = NULL;
  848. HRESULT hr = MAPIAllocateBuffer(CbSSortOrderSet(lpsSortOrderSet),
  849. reinterpret_cast<void **>(&lpSortCriteria));
  850. if(hr != hrSuccess)
  851. return hr;
  852. memcpy(lpSortCriteria, lpsSortOrderSet, CbSSortOrderSet(lpsSortOrderSet));
  853. *lppSortCriteria = lpSortCriteria;
  854. return hrSuccess;
  855. }
  856. HRESULT ECMemTableView::Abort()
  857. {
  858. return MAPI_E_NO_SUPPORT;
  859. }
  860. HRESULT ECMemTableView::ExpandRow(ULONG cbInstanceKey, LPBYTE pbInstanceKey, ULONG ulRowCount, ULONG ulFlags, LPSRowSet * lppRows, ULONG *lpulMoreRows)
  861. {
  862. return MAPI_E_NO_SUPPORT;
  863. }
  864. HRESULT ECMemTableView::CollapseRow(ULONG cbInstanceKey, LPBYTE pbInstanceKey, ULONG ulFlags, ULONG *lpulRowCount)
  865. {
  866. return MAPI_E_NO_SUPPORT;
  867. }
  868. HRESULT ECMemTableView::WaitForCompletion(ULONG ulFlags, ULONG ulTimeout, ULONG *lpulTableStatus)
  869. {
  870. *lpulTableStatus = S_OK;
  871. return hrSuccess;
  872. }
  873. HRESULT ECMemTableView::GetCollapseState(ULONG ulFlags, ULONG cbInstanceKey, LPBYTE lpbInstanceKey, ULONG *lpcbCollapseState, LPBYTE *lppbCollapseState)
  874. {
  875. return MAPI_E_NO_SUPPORT;
  876. }
  877. HRESULT ECMemTableView::SetCollapseState(ULONG ulFlags, ULONG cbCollapseState, LPBYTE pbCollapseState, BOOKMARK *lpbkLocation)
  878. {
  879. return MAPI_E_NO_SUPPORT;
  880. }
  881. HRESULT ECMemTableView::QueryRows(LONG lRowCount, ULONG ulFlags, LPSRowSet *lppRows)
  882. {
  883. ECObjectTableList sRowList;
  884. HRESULT hr = kcerr_to_mapierr(lpKeyTable->QueryRows(lRowCount, &sRowList, false, ulFlags));
  885. if(hr != hrSuccess)
  886. return hr;
  887. return QueryRowData(&sRowList, lppRows);
  888. }
  889. HRESULT ECMemTableView::QueryRowData(ECObjectTableList *lpsRowList, LPSRowSet *lppRows)
  890. {
  891. HRESULT hr = hrSuccess;
  892. unsigned int i=0,j=0;
  893. rowset_ptr lpRows;
  894. convert_context converter;
  895. if (lpsRowList == NULL || lppRows == NULL) {
  896. assert(false);
  897. return MAPI_E_INVALID_PARAMETER;
  898. }
  899. // We have the rows we need, just copy them into a new rowset
  900. hr = MAPIAllocateBuffer(CbNewSRowSet(lpsRowList->size()), &~lpRows);
  901. if(hr != hrSuccess)
  902. return hr;
  903. // Copy the rows into the rowset
  904. i = 0;
  905. for (auto rowlist : *lpsRowList) {
  906. auto iterRows = this->lpMemTable->mapRows.find(rowlist.ulObjId);
  907. if (iterRows == this->lpMemTable->mapRows.cend())
  908. // FIXME this could happen during multi-threading
  909. return MAPI_E_NOT_FOUND;
  910. lpRows->aRow[i].cValues = lpsPropTags->cValues;
  911. lpRows->aRow[i].ulAdrEntryPad = 0;
  912. hr = MAPIAllocateBuffer(sizeof(SPropValue) * lpsPropTags->cValues, (void **)&lpRows->aRow[i].lpProps);
  913. if(hr != hrSuccess)
  914. return hr;
  915. for (j = 0; j < lpsPropTags->cValues; ++j) {
  916. // Handle some fixed properties
  917. if(lpsPropTags->aulPropTag[j] == lpMemTable->ulRowPropTag) {
  918. lpRows->aRow[i].lpProps[j].ulPropTag = lpMemTable->ulRowPropTag;
  919. //FIXME: now only support 32 bits of the PT_I8
  920. if(PROP_TYPE(lpMemTable->ulRowPropTag) == PT_I8)
  921. lpRows->aRow[i].lpProps[j].Value.li.QuadPart = 0; //empty memory
  922. lpRows->aRow[i].lpProps[j].Value.ul = rowlist.ulObjId;
  923. continue;
  924. }
  925. if (PROP_TYPE(lpsPropTags->aulPropTag[j]) == PT_NULL) {
  926. lpRows->aRow[i].lpProps[j].Value.ul = 0;
  927. lpRows->aRow[i].lpProps[j].ulPropTag = lpsPropTags->aulPropTag[j];
  928. continue;
  929. } else if(lpsPropTags->aulPropTag[j] == PR_INSTANCE_KEY) {
  930. lpRows->aRow[i].lpProps[j].ulPropTag = PR_INSTANCE_KEY;
  931. lpRows->aRow[i].lpProps[j].Value.bin.cb = sizeof(ULONG)*2;
  932. hr = MAPIAllocateMore(lpRows->aRow[i].lpProps[j].Value.bin.cb, lpRows->aRow[i].lpProps, (void **)&lpRows->aRow[i].lpProps[j].Value.bin.lpb);
  933. if(hr != hrSuccess)
  934. return hr;
  935. memcpy(lpRows->aRow[i].lpProps[j].Value.bin.lpb, &rowlist.ulObjId, sizeof(ULONG));
  936. memcpy(lpRows->aRow[i].lpProps[j].Value.bin.lpb + sizeof(ULONG), &rowlist.ulOrderId, sizeof(ULONG));
  937. continue;
  938. }
  939. // Find the property in the data (locate the property by property ID, since we may need conversion)
  940. auto lpsProp = PCpropFindProp(iterRows->second.lpsPropVal, iterRows->second.cValues, PROP_TAG(PT_UNSPECIFIED, PROP_ID(lpsPropTags->aulPropTag[j])));
  941. if (lpsProp == nullptr) {
  942. /* Not found */
  943. lpRows->aRow[i].lpProps[j].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpsPropTags->aulPropTag[j]));
  944. lpRows->aRow[i].lpProps[j].Value.err = MAPI_E_NOT_FOUND;
  945. continue;
  946. }
  947. if (PROP_TYPE(lpsPropTags->aulPropTag[j]) == PT_UNICODE && PROP_TYPE(lpsProp->ulPropTag) == PT_STRING8) {
  948. // PT_UNICODE requested, and PT_STRING8 provided. Do conversion.
  949. lpRows->aRow[i].lpProps[j].ulPropTag = PROP_TAG(PT_UNICODE, PROP_ID(lpsPropTags->aulPropTag[j]));
  950. const wstring strTmp = converter.convert_to<wstring>(lpsProp->Value.lpszA);
  951. if ((hr = MAPIAllocateMore((strTmp.size() + 1) * sizeof(wstring::value_type), lpRows->aRow[i].lpProps, (void **)&lpRows->aRow[i].lpProps[j].Value.lpszW)) != hrSuccess)
  952. return hr;
  953. memcpy(lpRows->aRow[i].lpProps[j].Value.lpszW, strTmp.c_str(), (strTmp.size() + 1) * sizeof(wstring::value_type));
  954. continue; // Finished with this property
  955. } else if (PROP_TYPE(lpsPropTags->aulPropTag[j]) == PT_STRING8 && PROP_TYPE(lpsProp->ulPropTag) == PT_UNICODE) {
  956. // PT_STRING8 requested, and PT_UNICODE provided. Do conversion.
  957. lpRows->aRow[i].lpProps[j].ulPropTag = PROP_TAG(PT_STRING8, PROP_ID(lpsPropTags->aulPropTag[j]));
  958. const string strTmp = converter.convert_to<string>(lpsProp->Value.lpszW);
  959. if ((hr = MAPIAllocateMore(strTmp.size() + 1, lpRows->aRow[i].lpProps, (void **)&lpRows->aRow[i].lpProps[j].Value.lpszA)) != hrSuccess)
  960. return hr;
  961. memcpy(lpRows->aRow[i].lpProps[j].Value.lpszA, strTmp.c_str(), strTmp.size() + 1);
  962. continue; // Finished with this property
  963. } else if (lpsPropTags->aulPropTag[j] == lpsProp->ulPropTag) {
  964. // Exact property requested that we have
  965. hr = Util::HrCopyProperty(&lpRows->aRow[i].lpProps[j], lpsProp, (void *)lpRows->aRow[i].lpProps);
  966. if (hr != hrSuccess) {
  967. lpRows->aRow[i].lpProps[j].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpsPropTags->aulPropTag[j]));
  968. lpRows->aRow[i].lpProps[j].Value.err = MAPI_E_NOT_FOUND;
  969. hr = hrSuccess; // ignore this error for the return code
  970. }
  971. continue;
  972. }
  973. // Not found
  974. lpRows->aRow[i].lpProps[j].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpsPropTags->aulPropTag[j]));
  975. lpRows->aRow[i].lpProps[j].Value.err = MAPI_E_NOT_FOUND;
  976. }
  977. ++i;
  978. }
  979. lpRows->cRows = lpsRowList->size();
  980. *lppRows = lpRows.release();
  981. return hr;
  982. }
  983. HRESULT ECMemTableView::UpdateRow(ULONG ulUpdateType, ULONG ulId)
  984. {
  985. HRESULT hr = hrSuccess;
  986. ECRESULT er = hrSuccess;
  987. sObjectTableKey sRowItem;
  988. sObjectTableKey sPrevRow;
  989. ULONG ulTableEvent = 0;
  990. sRowItem.ulObjId = ulId;
  991. sRowItem.ulOrderId = 0;
  992. // Optimisation: no sort columns, no restriction, don't need to query the DB
  993. if(((this->lpsSortOrderSet == NULL || this->lpsSortOrderSet->cSorts == 0) && this->lpsRestriction == NULL) ||
  994. ulUpdateType == ECKeyTable::TABLE_ROW_DELETE)
  995. {
  996. er = lpKeyTable->UpdateRow((ECKeyTable::UpdateType)ulUpdateType, &sRowItem, 0, NULL, NULL, NULL, &sPrevRow, false, (ECKeyTable::UpdateType*)&ulTableEvent);
  997. hr = kcerr_to_mapierr(er);
  998. } else {
  999. hr = ModifyRowKey(&sRowItem, &sPrevRow, &ulTableEvent);
  1000. }
  1001. if (hr == hrSuccess)
  1002. Notify(ulTableEvent, &sRowItem, &sPrevRow);
  1003. return hr;
  1004. }
  1005. HRESULT ECMemTableView::Clear()
  1006. {
  1007. HRESULT hr = hrSuccess;
  1008. ECRESULT er = hrSuccess;
  1009. er = lpKeyTable->Clear();
  1010. hr = kcerr_to_mapierr(er);
  1011. // FIXME: Outlook gives a TABLE_ROW_DELETE or TABLE_CHANGE?
  1012. if (hr == hrSuccess)
  1013. Notify(TABLE_CHANGED, NULL, NULL);
  1014. return hr;
  1015. }
  1016. DEF_ULONGMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, AddRef, (void))
  1017. DEF_ULONGMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, Release, (void))
  1018. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  1019. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, GetLastError, (HRESULT, hResult), (ULONG, ulFlags), (LPMAPIERROR *, lppMAPIError))
  1020. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, Advise, (ULONG, ulEventMask), (LPMAPIADVISESINK, lpAdviseSink), (ULONG *, lpulConnection))
  1021. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, Unadvise, (ULONG, ulConnection))
  1022. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, GetStatus, (ULONG *, lpulTableStatus), (ULONG *, lpulTableType))
  1023. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, SetColumns, (const SPropTagArray *, lpPropTagArray), (ULONG, ulFlags))
  1024. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, QueryColumns, (ULONG, ulFlags), (LPSPropTagArray *, lpPropTagArray))
  1025. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, GetRowCount, (ULONG, ulFlags), (ULONG *, lpulCount))
  1026. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, SeekRow, (BOOKMARK, bkOrigin), (LONG, lRowCount), (LONG *, lplRowsSought))
  1027. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, SeekRowApprox, (ULONG, ulNumerator), (ULONG, ulDenominator))
  1028. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, QueryPosition, (ULONG *, lpulRow), (ULONG *, lpulNumerator), (ULONG *, lpulDenominator))
  1029. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, FindRow, (LPSRestriction, lpRestriction), (BOOKMARK, bkOrigin), (ULONG, ulFlags))
  1030. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, Restrict, (LPSRestriction, lpRestriction), (ULONG, ulFlags))
  1031. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, CreateBookmark, (BOOKMARK*, lpbkPosition))
  1032. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, FreeBookmark, (BOOKMARK, bkPosition))
  1033. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, SortTable, (const SSortOrderSet *, lpSortCriteria), (ULONG, ulFlags))
  1034. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, QuerySortOrder, (LPSSortOrderSet *, lppSortCriteria))
  1035. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, QueryRows, (LONG, lRowCount), (ULONG, ulFlags), (LPSRowSet *, lppRows))
  1036. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, Abort, (void))
  1037. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, ExpandRow, (ULONG, cbInstanceKey), (LPBYTE, pbInstanceKey), (ULONG, ulRowCount), (ULONG, ulFlags), (LPSRowSet *, lppRows), (ULONG *, lpulMoreRows))
  1038. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, CollapseRow, (ULONG, cbInstanceKey), (LPBYTE, pbInstanceKey), (ULONG, ulFlags), (ULONG *, lpulRowCount))
  1039. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, WaitForCompletion, (ULONG, ulFlags), (ULONG, ulTimeout), (ULONG *, lpulTableStatus))
  1040. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, GetCollapseState, (ULONG, ulFlags), (ULONG, cbInstanceKey), (LPBYTE, lpbInstanceKey), (ULONG *, lpcbCollapseState), (LPBYTE *, lppbCollapseState))
  1041. DEF_HRMETHOD1(TRACE_MAPI, ECMemTableView, MAPITable, SetCollapseState, (ULONG, ulFlags), (ULONG, cbCollapseState), (LPBYTE, pbCollapseState), (BOOKMARK *, lpbkLocation))
  1042. } /* namespace */