Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

619 lines
20 KiB

  1. /*
  2. * CONTABLE.C
  3. *
  4. * Contents table implementation.
  5. *
  6. */
  7. #include "_apipch.h"
  8. STDMETHODIMP
  9. CONTVUE_SetColumns(
  10. LPVUE lpvue,
  11. LPSPropTagArray lpptaCols,
  12. ULONG ulFlags );
  13. // CONTVUE (table view class)
  14. // Implementes in-memory IMAPITable class on top of TADs
  15. // This is a copy of vtblVUE with FindRow overridden with the LDAP FindRow.
  16. VUE_Vtbl vtblCONTVUE =
  17. {
  18. VTABLE_FILL
  19. (VUE_QueryInterface_METHOD FAR *) UNKOBJ_QueryInterface,
  20. (VUE_AddRef_METHOD FAR *) UNKOBJ_AddRef,
  21. VUE_Release,
  22. (VUE_GetLastError_METHOD FAR *) UNKOBJ_GetLastError,
  23. VUE_Advise,
  24. VUE_Unadvise,
  25. VUE_GetStatus,
  26. (VUE_SetColumns_METHOD FAR *) CONTVUE_SetColumns,
  27. VUE_QueryColumns,
  28. VUE_GetRowCount,
  29. VUE_SeekRow,
  30. VUE_SeekRowApprox,
  31. VUE_QueryPosition,
  32. VUE_FindRow,
  33. VUE_Restrict,
  34. VUE_CreateBookmark,
  35. VUE_FreeBookmark,
  36. VUE_SortTable,
  37. VUE_QuerySortOrder,
  38. VUE_QueryRows,
  39. VUE_Abort,
  40. VUE_ExpandRow,
  41. VUE_CollapseRow,
  42. VUE_WaitForCompletion,
  43. VUE_GetCollapseState,
  44. VUE_SetCollapseState
  45. };
  46. //
  47. // Private functions
  48. //
  49. /***************************************************************************
  50. Name : GetEntryProps
  51. Purpose : Open the entry, get it's props, release the entry
  52. Parameters: lpContainer -> AB Container object
  53. cbEntryID = size of entryid
  54. lpEntryID -> entry id to open
  55. lpPropertyStore -> property store structure
  56. lpSPropTagArray -> prop tags to get
  57. lpAllocMoreHere = buffer to allocate more onto (or NULL for allocbuffer)
  58. ulFlags - 0 or MAPI_UNICODE
  59. lpulcProps -> return count of props here
  60. lppSPropValue -> return props here
  61. Returns : HRESULT
  62. Comment :
  63. ***************************************************************************/
  64. HRESULT GetEntryProps(
  65. LPABCONT lpContainer,
  66. ULONG cbEntryID,
  67. LPENTRYID lpEntryID,
  68. LPSPropTagArray lpSPropTagArray,
  69. LPVOID lpAllocMoreHere, // allocate more on here
  70. ULONG ulFlags,
  71. LPULONG lpulcProps, // return count here
  72. LPSPropValue * lppSPropValue) { // return props here
  73. HRESULT hResult = hrSuccess;
  74. SCODE sc;
  75. ULONG ulObjType;
  76. LPMAPIPROP lpObject = NULL;
  77. LPSPropValue lpSPropValue = NULL;
  78. ULONG cb;
  79. if (HR_FAILED(hResult = lpContainer->lpVtbl->OpenEntry(lpContainer,
  80. cbEntryID,
  81. lpEntryID,
  82. NULL,
  83. 0, // read only is fine
  84. &ulObjType,
  85. (LPUNKNOWN *)&lpObject))) {
  86. DebugTrace(TEXT("GetEntryProps OpenEntry failed %x\n"), GetScode(hResult));
  87. return(hResult);
  88. }
  89. if (HR_FAILED(hResult = lpObject->lpVtbl->GetProps(lpObject,
  90. lpSPropTagArray,
  91. ulFlags,
  92. lpulcProps,
  93. &lpSPropValue))) {
  94. DebugTrace(TEXT("GetEntryProps GetProps failed %x\n"), GetScode(hResult));
  95. goto exit;
  96. }
  97. // Allocate more for our return buffer
  98. if (FAILED(sc = ScCountProps(*lpulcProps, lpSPropValue, &cb))) {
  99. hResult = ResultFromScode(sc);
  100. goto exit;
  101. }
  102. if (FAILED(sc = MAPIAllocateMore(cb, lpAllocMoreHere, lppSPropValue))) {
  103. hResult = ResultFromScode(sc);
  104. goto exit;
  105. }
  106. if (FAILED(sc = ScCopyProps(*lpulcProps, lpSPropValue, *lppSPropValue, NULL))) {
  107. hResult = ResultFromScode(sc);
  108. goto exit;
  109. }
  110. exit:
  111. FreeBufferAndNull(&lpSPropValue);
  112. UlRelease(lpObject);
  113. return(hResult);
  114. }
  115. /***************************************************************************
  116. Name : FillTableDataFromPropertyStore
  117. Purpose : Fill in a TableData object from the property store
  118. Parameters: lpIAB
  119. lppta -> prop tags to get
  120. lpTableData
  121. Returns : HRESULT
  122. Comment :
  123. ***************************************************************************/
  124. HRESULT FillTableDataFromPropertyStore(LPIAB lpIAB,
  125. LPSPropTagArray lppta,
  126. LPTABLEDATA lpTableData)
  127. {
  128. HRESULT hResult = S_OK;
  129. SCODE sc;
  130. LPSRowSet lpSRowSet = NULL;
  131. LPSPropValue lpSPropValue = NULL;
  132. LPTSTR lpTemp = NULL;
  133. ULONG i, j, k;
  134. LPCONTENTLIST * lppContentList = NULL;
  135. LPCONTENTLIST lpContentList = NULL;
  136. ULONG ulContainers = 1;
  137. SPropertyRestriction PropRes = {0};
  138. ULONG nLen = 0;
  139. ULONG ulInvalidPropCount = 0;
  140. ULONG ulcPropCount;
  141. ULONG iToAdd;
  142. ULONG iPR_ENTRYID = (ULONG)-1;
  143. ULONG iPR_RECORD_KEY = (ULONG)-1;
  144. ULONG iPR_INSTANCE_KEY = (ULONG)-1;
  145. LPSPropTagArray lpptaNew = NULL;
  146. LPSPropTagArray lpptaRead;
  147. BOOL bUnicodeData = ((LPTAD)lpTableData)->bMAPIUnicodeTable;
  148. // Make certain that we have required properties:
  149. // PR_ENTRYID
  150. // PR_RECORD_KEY
  151. // PR_INSTANCE_KEY
  152. // walk through pta looking for required props
  153. iToAdd = 3;
  154. for (i = 0; i < lppta->cValues; i++) {
  155. switch (lppta->aulPropTag[i]) {
  156. case PR_ENTRYID:
  157. iPR_ENTRYID = i;
  158. iToAdd--;
  159. break;
  160. case PR_RECORD_KEY:
  161. iPR_RECORD_KEY = i;
  162. iToAdd--;
  163. break;
  164. case PR_INSTANCE_KEY:
  165. iPR_INSTANCE_KEY = i;
  166. iToAdd--;
  167. break;
  168. }
  169. }
  170. if (iToAdd) {
  171. if (lpptaNew = LocalAlloc(LPTR, sizeof(SPropTagArray) + (lppta->cValues + iToAdd) * sizeof(DWORD))) {
  172. // Copy the caller's pta into our new one
  173. lpptaNew->cValues = lppta->cValues;
  174. CopyMemory(lpptaNew->aulPropTag, lppta->aulPropTag, lppta->cValues * sizeof(DWORD));
  175. // Add them on at the end.
  176. if (iPR_ENTRYID == (ULONG)-1) {
  177. iPR_ENTRYID = lpptaNew->cValues++;
  178. lpptaNew->aulPropTag[iPR_ENTRYID] = PR_NULL;
  179. }
  180. if (iPR_RECORD_KEY == (ULONG)-1) {
  181. iPR_RECORD_KEY = lpptaNew->cValues++;
  182. lpptaNew->aulPropTag[iPR_RECORD_KEY] = PR_NULL;
  183. }
  184. if (iPR_INSTANCE_KEY == (ULONG)-1) {
  185. iPR_INSTANCE_KEY = lpptaNew->cValues++;
  186. lpptaNew->aulPropTag[iPR_INSTANCE_KEY] = PR_NULL;
  187. }
  188. lpptaRead = lpptaNew;
  189. } else {
  190. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  191. goto exit;
  192. }
  193. } else {
  194. lpptaRead = lppta;
  195. }
  196. Assert(iPR_ENTRYID != (ULONG)-1);
  197. Assert(iPR_RECORD_KEY!= (ULONG)-1);
  198. Assert(iPR_INSTANCE_KEY != (ULONG)-1);
  199. //
  200. // Set filter criteria if none exists - we'll default to DisplayName
  201. //
  202. PropRes.ulPropTag = PR_DISPLAY_NAME;
  203. PropRes.relop = RELOP_EQ;
  204. PropRes.lpProp = NULL;
  205. {
  206. // The way we want GetContentsTable to behave is:
  207. //
  208. // If no profilesAPI enabled and no override, then GetContentsTable works as before and returns
  209. // full set of contents for the current WAB [This is for the PAB container only]
  210. // In cases where old clients dont know how to invoke the new API, the UI will have new stuff
  211. // but the API should have the old stuff meaning that a GetContentsTable on the PAB
  212. // container should return full WAB contents. To make sure that the GetContentsTable on the
  213. // PAB container doesn't contain full contents, caller can force this by passing in
  214. // WAB_ENABLE_PROFILES into the call to GetContentsTable...
  215. //
  216. // If profilesAPI are enabled, then GetContentsTable only returns the contents of
  217. // the specified folder/container
  218. // unless the folder has a NULL entryid in which case we want to get ALL WAB contents
  219. // so we can pump them into the "All Contacts" ui item ..
  220. //
  221. // If ProfilesAPI and WAB_PROFILE_CONTENTS are specified and it's the PAB container
  222. // then we need to return all the contents pertaining to the current profile
  223. //
  224. //
  225. //
  226. SBinary sbEID = {0};
  227. LPSBinary lpsbEID = ((LPTAD)lpTableData)->pbinContEID;
  228. BOOL bProfileContents = FALSE;
  229. // Is this a 'new' WAB showing folders and stuff ?
  230. if(bIsWABSessionProfileAware(lpIAB))
  231. {
  232. // If this WAB is identity aware or we were asked to
  233. // restrict the contents to a single container, then try to
  234. // get the entryid for that container
  235. if( bAreWABAPIProfileAware(lpIAB) ||
  236. ((LPTAD)lpTableData)->bContainerContentsOnly)
  237. {
  238. if(!lpsbEID)
  239. lpsbEID = &sbEID;
  240. }
  241. // if we earlier, during GetContentsTable specified that we
  242. // want the full contents for the current profile (which means
  243. // iterating through all the folders in this profile), we should
  244. // look into this ..
  245. if(((LPTAD)lpTableData)->bAllProfileContents)
  246. {
  247. ulContainers = lpIAB->cwabci;
  248. bProfileContents = TRUE;
  249. }
  250. }
  251. // Allocate a temporary list in which we will get each containers contents
  252. // seperately - later we will collate all these seperate content-lists
  253. // together
  254. lppContentList = LocalAlloc(LMEM_ZEROINIT, sizeof(LPCONTENTLIST)*ulContainers);
  255. if(!lppContentList)
  256. {
  257. hResult = MAPI_E_NOT_ENOUGH_MEMORY;
  258. goto exit;
  259. }
  260. //
  261. // Get the content list
  262. //
  263. if(!bProfileContents)
  264. {
  265. // if we don't care about profile and profile folders,
  266. // just get the bunch'o'contents from the store
  267. if (HR_FAILED(hResult = ReadPropArray(lpIAB->lpPropertyStore->hPropertyStore,
  268. lpsbEID,
  269. &PropRes,
  270. AB_MATCH_PROP_ONLY | (bUnicodeData?AB_UNICODE:0),
  271. lpptaRead->cValues,
  272. (LPULONG)lpptaRead->aulPropTag,
  273. &(lppContentList[0]))))
  274. {
  275. DebugTraceResult( TEXT("NewContentsTable:ReadPropArray"), hResult);
  276. goto exit;
  277. }
  278. }
  279. else
  280. {
  281. // We need to collate together all the contents of all the containers for this profile
  282. //
  283. // The first item is the Virtual PAB "Shared Contacts" folder .. we want the contents of this
  284. // item as part of this ContentsTable by default. This item has a special entryid of 0, NULL so we
  285. // can diffrentiate it from the rest of the pack..
  286. //
  287. for(i=0;i<ulContainers;i++)
  288. {
  289. hResult = ReadPropArray(lpIAB->lpPropertyStore->hPropertyStore,
  290. lpIAB->rgwabci[i].lpEntryID ? lpIAB->rgwabci[i].lpEntryID : &sbEID,
  291. &PropRes,
  292. AB_MATCH_PROP_ONLY | (bUnicodeData?AB_UNICODE:0),
  293. lpptaRead->cValues,
  294. (LPULONG)lpptaRead->aulPropTag,
  295. &(lppContentList[i]));
  296. // ignore MAPI_E_NOT_FOUND errors here ...
  297. if(HR_FAILED(hResult))
  298. {
  299. if(hResult == MAPI_E_NOT_FOUND)
  300. hResult = S_OK;
  301. else
  302. {
  303. DebugTraceResult( TEXT("NewContentsTable:ReadPropArray"), hResult);
  304. goto exit;
  305. }
  306. }
  307. }
  308. }
  309. }
  310. for(k=0;k<ulContainers;k++)
  311. {
  312. lpContentList = lppContentList[k];
  313. if(lpContentList)
  314. {
  315. // Now we need to move the information from the index to
  316. // the SRowSet. In the process, we need to create a few computed
  317. // properties:
  318. // PR_DISPLAY_TYPE ?
  319. // PR_INSTANCE_KEY
  320. // PR_RECORD_KEY
  321. // Allocate the SRowSet
  322. if (FAILED(sc = MAPIAllocateBuffer(sizeof(SRowSet) + lpContentList->cEntries * sizeof(SRow),
  323. &lpSRowSet)))
  324. {
  325. DebugTrace(TEXT("Allocation of SRowSet failed\n"));
  326. hResult = ResultFromScode(sc);
  327. goto exit;
  328. }
  329. lpSRowSet->cRows = lpContentList->cEntries;
  330. for (i = 0; i < lpContentList->cEntries; i++)
  331. {
  332. //
  333. // We look at each of the returned entries - if they dont have a prop
  334. // we set that prop to " "
  335. // (Assuming these are all string props)
  336. //
  337. lpSPropValue = lpContentList->aEntries[i].rgPropVals;
  338. ulcPropCount = lpContentList->aEntries[i].cValues;
  339. // DebugProperties(lpSPropValue, ulcPropCount, "Raw");
  340. for (j = 0; j < ulcPropCount; j++)
  341. {
  342. // Get rid of error valued properties
  343. if (PROP_ERROR(lpSPropValue[j])) {
  344. lpSPropValue[j].ulPropTag = PR_NULL;
  345. }
  346. }
  347. // Make certain we have proper indicies.
  348. // For now, we will equate PR_INSTANCE_KEY and PR_RECORD_KEY to PR_ENTRYID.
  349. if(lpSPropValue[iPR_INSTANCE_KEY].ulPropTag != PR_INSTANCE_KEY)
  350. {
  351. lpSPropValue[iPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
  352. SetSBinary( &lpSPropValue[iPR_INSTANCE_KEY].Value.bin,
  353. lpSPropValue[iPR_ENTRYID].Value.bin.cb,
  354. lpSPropValue[iPR_ENTRYID].Value.bin.lpb);
  355. }
  356. if(lpSPropValue[iPR_RECORD_KEY].ulPropTag != PR_RECORD_KEY)
  357. {
  358. lpSPropValue[iPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY;
  359. SetSBinary( &lpSPropValue[iPR_RECORD_KEY].Value.bin,
  360. lpSPropValue[iPR_ENTRYID].Value.bin.cb,
  361. lpSPropValue[iPR_ENTRYID].Value.bin.lpb);
  362. }
  363. // Put it in the RowSet
  364. lpSRowSet->aRow[i].cValues = ulcPropCount; // number of properties
  365. lpSRowSet->aRow[i].lpProps = lpSPropValue; // LPSPropValue
  366. } //for i
  367. hResult = lpTableData->lpVtbl->HrModifyRows(lpTableData,0,lpSRowSet);
  368. FreeBufferAndNull(&lpSRowSet);
  369. } // for k
  370. }
  371. exit:
  372. for(i=0;i<ulContainers;i++)
  373. {
  374. lpContentList = lppContentList[i];
  375. if (lpContentList) {
  376. FreePcontentlist(lpIAB->lpPropertyStore->hPropertyStore, lpContentList);
  377. }
  378. }
  379. if(lppContentList)
  380. LocalFree(lppContentList);
  381. if(lpptaNew)
  382. LocalFree(lpptaNew);
  383. return(hResult);
  384. }
  385. /***************************************************************************
  386. Name : NewContentsTable
  387. Purpose : Creates a new contents table
  388. Parameters:
  389. lpABContainer - container being opened
  390. lpIAB - AdrBook object
  391. ulFlags - WAB_NO_CONTENTTABLE_DATA
  392. lpInteface ?
  393. lppTble - returned table
  394. Returns : HRESULT
  395. Comment :
  396. ***************************************************************************/
  397. HRESULT NewContentsTable(LPABCONT lpABContainer,
  398. LPIAB lpIAB,
  399. ULONG ulFlags,
  400. LPCIID lpInterface,
  401. LPMAPITABLE * lppTable) {
  402. LPTABLEDATA lpTableData = NULL;
  403. HRESULT hResult = hrSuccess;
  404. SCODE sc;
  405. #ifndef DONT_ADDREF_PROPSTORE
  406. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpIAB->lpPropertyStore)))) {
  407. hResult = ResultFromScode(sc);
  408. goto exitNotAddRefed;
  409. }
  410. #endif
  411. if (FAILED(sc = CreateTableData(
  412. NULL, // LPCIID
  413. (ALLOCATEBUFFER FAR *) MAPIAllocateBuffer,
  414. (ALLOCATEMORE FAR *) MAPIAllocateMore,
  415. MAPIFreeBuffer,
  416. NULL, // lpvReserved,
  417. TBLTYPE_DYNAMIC, // ulTableType,
  418. PR_RECORD_KEY, // ulPropTagIndexCol,
  419. (LPSPropTagArray)&ITableColumns, // LPSPropTagArray lpptaCols,
  420. lpIAB, // lpvDataSource
  421. 0, // cbDataSource
  422. ((LPCONTAINER)lpABContainer)->pmbinOlk,
  423. ulFlags,
  424. &lpTableData))) { // LPTABLEATA FAR * lplptad
  425. DebugTrace(TEXT("CreateTable failed %x\n"), sc);
  426. hResult = ResultFromScode(sc);
  427. goto exit;
  428. }
  429. if (lpTableData)
  430. {
  431. if(!(ulFlags & WAB_CONTENTTABLE_NODATA))
  432. {
  433. // Fill in the data from the property store
  434. if (hResult = FillTableDataFromPropertyStore(lpIAB,
  435. (LPSPropTagArray)&ITableColumns, lpTableData)) {
  436. DebugTraceResult( TEXT("NewContentsTable:FillTableFromPropertyStore"), hResult);
  437. goto exit;
  438. }
  439. }
  440. }
  441. if (hResult = lpTableData->lpVtbl->HrGetView(lpTableData,
  442. NULL, // LPSSortOrderSet lpsos,
  443. ContentsViewGone, // CALLERRELEASE FAR * lpfReleaseCallback,
  444. 0, // ULONG ulReleaseData,
  445. lppTable)) { // LPMAPITABLE FAR * lplpmt)
  446. goto exit;
  447. }
  448. // Replace the vtable with our new one that overrides SetColumns
  449. (*lppTable)->lpVtbl = (IMAPITableVtbl FAR *)&vtblCONTVUE;
  450. exit:
  451. #ifndef DONT_ADDREF_PROPSTORE
  452. ReleasePropertyStore(lpIAB->lpPropertyStore);
  453. exitNotAddRefed:
  454. #endif
  455. // Cleanup table if failure
  456. if (HR_FAILED(hResult)) {
  457. if (lpTableData) {
  458. UlRelease(lpTableData);
  459. }
  460. }
  461. return(hResult);
  462. }
  463. /*
  464. * This is a callback function, invoked by itable.dll when its
  465. * caller does the last release on a view of the contents table. We
  466. * use it to know when to release the underlying table data.
  467. */
  468. void STDAPICALLTYPE
  469. ContentsViewGone(ULONG ulContext, LPTABLEDATA lptad, LPMAPITABLE lpVue)
  470. {
  471. #ifdef OLD_STUFF
  472. LPISPAM pispam = (LPISPAM)ulContext;
  473. if (FBadUnknown((LPUNKNOWN) pispam)
  474. || IsBadWritePtr(pispam, sizeof(ISPAM))
  475. || pispam->cRefTad == 0
  476. || FBadUnknown(pispam->ptad))
  477. {
  478. DebugTrace(TEXT("ContentsViewGone: contents table was apparently already released\n"));
  479. return;
  480. }
  481. if (pispam->ptad != lptad)
  482. {
  483. TrapSz( TEXT("ContentsViewGone: TAD mismatch on VUE release!"));
  484. }
  485. else if (--(pispam->cRefTad) == 0)
  486. {
  487. pispam->ptad = NULL;
  488. UlRelease(lptad);
  489. }
  490. #endif // OLD_STUFF
  491. UlRelease(lptad);
  492. return;
  493. IF_WIN32(UNREFERENCED_PARAMETER(ulContext);)
  494. IF_WIN32(UNREFERENCED_PARAMETER(lpVue);)
  495. }
  496. /*============================================================================
  497. - CONTVUE::SetColumns()
  498. -
  499. * Replaces the current column set with a copy of the specified column set
  500. * and frees the old column set.
  501. */
  502. STDMETHODIMP
  503. CONTVUE_SetColumns(
  504. LPVUE lpvue,
  505. LPSPropTagArray lpptaCols,
  506. ULONG ulFlags )
  507. {
  508. HRESULT hResult = hrSuccess;
  509. #if !defined(NO_VALIDATION)
  510. VALIDATE_OBJ(lpvue,CONTVUE_,SetColumns,lpVtbl);
  511. // Validate_IMAPITable_SetColumns( lpvue, lpptaCols, ulFlags ); // Commented by YST
  512. #endif
  513. Assert(lpvue->lptadParent->lpvDataSource);
  514. // Re-read the table data
  515. if (lpvue->lptadParent && (hResult = FillTableDataFromPropertyStore(
  516. (LPIAB)lpvue->lptadParent->lpvDataSource,
  517. lpptaCols,
  518. (LPTABLEDATA)lpvue->lptadParent))) {
  519. DebugTraceResult( TEXT("CONTVUE_SetColumns:FillTableFromPropertyStore"), hResult);
  520. return(hResult);
  521. }
  522. return(VUE_SetColumns(lpvue, lpptaCols, ulFlags));
  523. }