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.

3954 lines
144 KiB

  1. /*
  2. * IPROP.C
  3. *
  4. * IProperty in memory
  5. */
  6. #include "_apipch.h"
  7. // #pragma SEGMENT(IProp)
  8. //
  9. // IPropData jump table is defined here...
  10. //
  11. IPDAT_Vtbl vtblIPDAT = {
  12. VTABLE_FILL
  13. (IPDAT_QueryInterface_METHOD FAR *) UNKOBJ_QueryInterface,
  14. (IPDAT_AddRef_METHOD FAR *) UNKOBJ_AddRef,
  15. IPDAT_Release,
  16. (IPDAT_GetLastError_METHOD FAR *) UNKOBJ_GetLastError,
  17. IPDAT_SaveChanges,
  18. IPDAT_GetProps,
  19. IPDAT_GetPropList,
  20. IPDAT_OpenProperty,
  21. IPDAT_SetProps,
  22. IPDAT_DeleteProps,
  23. IPDAT_CopyTo,
  24. IPDAT_CopyProps,
  25. IPDAT_GetNamesFromIDs,
  26. IPDAT_GetIDsFromNames,
  27. IPDAT_HrSetObjAccess,
  28. IPDAT_HrSetPropAccess,
  29. IPDAT_HrGetPropAccess,
  30. IPDAT_HrAddObjProps
  31. };
  32. /* Interface which can be queried fro lpIPDAT.
  33. *
  34. * It is important that the order of the interfaces supported be preserved
  35. * and that IID_IUnknown be the last in the list.
  36. */
  37. IID const FAR * argpiidIPDAT[] =
  38. {
  39. &IID_IMAPIPropData,
  40. &IID_IMAPIProp,
  41. &IID_IUnknown
  42. };
  43. #define CIID_IPROP_INHERITS 1
  44. #define CIID_IPROPDATA_INHERITS 2
  45. /*
  46. * Utility functions/macros used by iprop.
  47. */
  48. #define AlignPropVal(_cb) Align8(_cb)
  49. SCODE
  50. ScDupNameID(LPIPDAT lpIPDAT,
  51. LPVOID lpvBaseAlloc,
  52. LPMAPINAMEID lpNameSrc,
  53. LPMAPINAMEID * lppNameDest)
  54. {
  55. SCODE sc;
  56. //
  57. // Allocate space for the name
  58. //
  59. sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT,
  60. sizeof(MAPINAMEID),
  61. lpvBaseAlloc,
  62. lppNameDest);
  63. if (FAILED(sc))
  64. {
  65. goto err;
  66. }
  67. MemCopy(*lppNameDest, lpNameSrc, sizeof(MAPINAMEID));
  68. //
  69. // Copy the lpguid
  70. //
  71. sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT,
  72. sizeof(GUID),
  73. lpvBaseAlloc,
  74. &((*lppNameDest)->lpguid));
  75. if (FAILED(sc))
  76. {
  77. goto err;
  78. }
  79. MemCopy((*lppNameDest)->lpguid, lpNameSrc->lpguid, sizeof(GUID));
  80. //
  81. // conditionally copy the string
  82. //
  83. if (lpNameSrc->ulKind == MNID_STRING)
  84. {
  85. UINT cbString;
  86. cbString = (lstrlenW(lpNameSrc->Kind.lpwstrName)+1)*sizeof(WCHAR);
  87. //
  88. // Copy the lpwstrName
  89. //
  90. sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT,
  91. cbString,
  92. lpvBaseAlloc,
  93. &((*lppNameDest)->Kind.lpwstrName));
  94. if (FAILED(sc))
  95. {
  96. goto err;
  97. }
  98. MemCopy((*lppNameDest)->Kind.lpwstrName,
  99. lpNameSrc->Kind.lpwstrName,
  100. cbString);
  101. }
  102. out:
  103. return sc;
  104. err:
  105. goto out;
  106. }
  107. SCODE
  108. ScMakeMAPINames(LPIPDAT lpIPDAT,
  109. LPSPropTagArray lpsPTaga,
  110. LPMAPINAMEID ** lpppPropNames)
  111. {
  112. SCODE sc;
  113. LPGUID lpMAPIGuid = NULL;
  114. int iProp;
  115. LPMAPINAMEID rgNames = NULL;
  116. //
  117. // First off, allocate enough space in lppPropNames
  118. // to hold all the names.
  119. //
  120. sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT,
  121. lpsPTaga->cValues*sizeof(LPMAPINAMEID),
  122. (LPVOID *)lpppPropNames);
  123. if (FAILED(sc))
  124. {
  125. goto out;
  126. }
  127. //
  128. // Allocate the guid -
  129. //$ Do I really need to do this?? bjd
  130. //
  131. sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT,
  132. sizeof(GUID),
  133. *lpppPropNames,
  134. &lpMAPIGuid);
  135. if (FAILED(sc))
  136. {
  137. goto out;
  138. }
  139. MemCopy(lpMAPIGuid, (LPGUID) &PS_MAPI, sizeof(GUID));
  140. //
  141. // Allocate a block of MAPINAMEIDs
  142. //
  143. sc = UNKOBJ_ScAllocateMore( (LPUNKOBJ) lpIPDAT,
  144. lpsPTaga->cValues*sizeof(MAPINAMEID),
  145. *lpppPropNames,
  146. &rgNames);
  147. if (FAILED(sc))
  148. {
  149. goto out;
  150. }
  151. for (iProp = 0; iProp < (int) lpsPTaga->cValues; iProp++)
  152. {
  153. //
  154. // First make the name
  155. //
  156. rgNames[iProp].lpguid = lpMAPIGuid;
  157. rgNames[iProp].ulKind = MNID_ID;
  158. rgNames[iProp].Kind.lID = PROP_ID(lpsPTaga->aulPropTag[iProp]);
  159. //
  160. // Now put it in the name array
  161. //
  162. (*lpppPropNames)[iProp] = &(rgNames[iProp]);
  163. }
  164. out:
  165. return sc;
  166. }
  167. /*
  168. * FreeLpLstSPV()
  169. *
  170. * Purpose:
  171. * Releases objects and frees memory used by lpLstSPV.
  172. * Handles NULL.
  173. *
  174. * Arguments
  175. * lpIPDAT Pointer to IPropData object (alloc and free heap)
  176. * lpLstSPV The property value list entry which is to be freed.
  177. *
  178. * Returns
  179. * VOID
  180. *
  181. */
  182. VOID
  183. FreeLpLstSPV( LPIPDAT lpIPDAT,
  184. LPLSTSPV lpLstSPV)
  185. {
  186. if (!lpLstSPV)
  187. {
  188. return;
  189. }
  190. /* Free the property list node. This also frees the property value
  191. * and property name string.
  192. */
  193. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPV);
  194. }
  195. /*
  196. * LinkLstSPV()
  197. *
  198. * Purpose:
  199. * Link a new property node after an existing property node in a singly
  200. * linked list. lppLstLnk points to the element that will preceed
  201. * the newly linked element. This element may be the list head.
  202. *
  203. * Arguments
  204. * lppLstLnk Pointer to list entry (or list head) AFTER which
  205. * lpLstLnk will be inserted.
  206. * lpLstLnk The element to be inserted in the singly linked list.
  207. *
  208. * Returns
  209. * VOID
  210. */
  211. VOID
  212. LinkLstLnk( LPLSTLNK FAR * lppLstLnk,
  213. LPLSTLNK lpLstLnk)
  214. {
  215. /* Always insert at the head of the list.
  216. */
  217. lpLstLnk->lpNext = *lppLstLnk;
  218. *lppLstLnk = lpLstLnk;
  219. }
  220. /*
  221. * UnlinkLstLNK()
  222. *
  223. * Purpose:
  224. * Unlink the next element in the list. You pass a pointer the element
  225. * before the one to be unlinked (this can be the list head).
  226. *
  227. * The input is typed as LPPLSTLNK because the element before the one to
  228. * be unlinked should point to the one one that is to be linked.
  229. *
  230. * Arguments
  231. * lppLstLnk Pointer to the element before the element that is to be
  232. * unlinked from the singly linked list.
  233. *
  234. * Returns
  235. * VOID
  236. */
  237. VOID
  238. UnlinkLstLnk( LPPLSTLNK lppLstLnk)
  239. {
  240. /* Unlink the element following the one passed in.
  241. */
  242. if (*lppLstLnk)
  243. {
  244. ((LPLSTLNK) lppLstLnk)->lpNext = (*lppLstLnk)->lpNext;
  245. }
  246. }
  247. /*
  248. * lpplstspvFindProp()
  249. *
  250. * Purpose:
  251. * Locate a property in the linked list of properties (lppLstSPV),
  252. * return a pointer to pointer to it.
  253. *
  254. * Pointer to pointer is returned to make it easy to unlink the singly
  255. * linked list entry if required.
  256. *
  257. * Arguments
  258. * lppLstLnkHead Pointer to the head of a singly linked list which is
  259. * to be searched. It may also point to the element
  260. * before the first one to be searched if a partial list
  261. * search (lppLstLnkHead->next to the end) is desired.
  262. * ulPropTag The property tag for which a match is desired.
  263. * NOTE! Only the PROP_ID portion is compared.
  264. *
  265. * Returns:
  266. * NULL if the requested property is not in the list
  267. * lppLstSPV to the property it found in the list.
  268. */
  269. LPPLSTLNK
  270. LPPLSTLNKFindProp( LPPLSTLNK lppLstLnkHead,
  271. ULONG ulPropTag)
  272. {
  273. ULONG ulID2Find = PROP_ID(ulPropTag);
  274. LPLSTLNK lpLstLnk;
  275. LPPLSTLNK lppLstLnk;
  276. for ( lpLstLnk = *lppLstLnkHead, lppLstLnk = lppLstLnkHead
  277. ; lpLstLnk
  278. ; lppLstLnk = (LPPLSTLNK) lpLstLnk, lpLstLnk = lpLstLnk->lpNext)
  279. {
  280. /* If this property matches the one we are looking for return a
  281. * pointer to the one before it.
  282. */
  283. if (ulID2Find == PROP_ID(lpLstLnk->ulKey))
  284. {
  285. return lppLstLnk;
  286. }
  287. }
  288. return NULL;
  289. }
  290. /*
  291. * ScCreateSPV()
  292. *
  293. * Purpose:
  294. * Create a lstSPV for the given property and copy the property to it.
  295. *
  296. * Arguments
  297. * lpIPDAT Pointer to IPropData object (alloc and free heap)
  298. * lpPropToAdd Pointer to a property value for which a property value
  299. * list entry is to be created.
  300. * lppLstSPV Pointer to the memory location which will receive a pointer
  301. * to the newly allocated list entry.
  302. *
  303. * Returns
  304. * SCODE
  305. */
  306. SCODE
  307. ScCreateSPV(LPIPDAT lpIPDAT,
  308. LPSPropValue lpPropToAdd,
  309. LPLSTSPV FAR * lppLstSPV)
  310. {
  311. SCODE sc = S_OK;
  312. LPLSTSPV lpLstSPV = NULL;
  313. LPSPropValue lpPropNew = NULL;
  314. ULONG cbToAllocate = 0;
  315. /* Calculate the space needed to hold the entire property
  316. */
  317. sc = ScCountProps( 1, lpPropToAdd, &cbToAllocate );
  318. if (FAILED(sc))
  319. {
  320. DebugTrace(TEXT("ScCreateSPV() - ScCountProps failed (SCODE = 0x%08lX)\n"), sc );
  321. goto error;
  322. }
  323. /* Account for the base LSTSPV.
  324. */
  325. cbToAllocate += AlignPropVal(CBLSTSPV);
  326. /* Allocate the whole chunk
  327. */
  328. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, cbToAllocate, &lpLstSPV)))
  329. {
  330. goto error;
  331. }
  332. lpPropNew = (LPSPropValue) (((LPBYTE)lpLstSPV) + AlignPropVal(CBLSTSPV));
  333. /* Initialize the property node.
  334. */
  335. lpLstSPV->ulAccess = IPROP_READWRITE | IPROP_DIRTY;
  336. lpLstSPV->lstlnk.ulKey = lpPropToAdd->ulPropTag;
  337. /* Copy the property.
  338. */
  339. if (sc = ScCopyProps(1, lpPropToAdd, lpPropNew, NULL))
  340. {
  341. DebugTrace(TEXT("ScCreateSPV() - Error copying prop (SCODE = 0x%08lX)\n"), sc );
  342. goto error;
  343. }
  344. /* Link in the new property value...
  345. */
  346. lpLstSPV->lpPropVal = lpPropNew;
  347. /* ...and return the new property node.
  348. */
  349. *lppLstSPV = lpLstSPV;
  350. goto out;
  351. error:
  352. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPV);
  353. out:
  354. return sc;
  355. }
  356. SCODE
  357. ScMakeNamePropList( LPIPDAT lpIPDAT,
  358. ULONG ulCount,
  359. LPLSTSPN lplstSpn,
  360. LPSPropTagArray FAR * lppPropTagArray,
  361. ULONG ulFlags,
  362. LPGUID lpGuid)
  363. {
  364. SCODE sc;
  365. UNALIGNED ULONG FAR * lpulPropTag;
  366. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT,
  367. CbNewSPropTagArray(ulCount),
  368. (LPVOID *) lppPropTagArray)))
  369. {
  370. return sc;
  371. }
  372. /* Initialize the count of PropTags to 0.
  373. */
  374. (*lppPropTagArray)->cValues = 0;
  375. for ( lpulPropTag = (*lppPropTagArray)->aulPropTag
  376. ; lplstSpn
  377. ; lplstSpn = (LPLSTSPN)lplstSpn->lstlnk.lpNext)
  378. {
  379. /* Set the next PropTag and increment the count of PropTags.
  380. */
  381. //
  382. // See if we have a guid to look for.
  383. // If it's not the one we're looking for, then we keep looking.
  384. //
  385. if (lpGuid &&
  386. (memcmp(lpGuid, lplstSpn->lpPropName->lpguid, sizeof(GUID))) )
  387. continue;
  388. //
  389. // Three cases here:
  390. // We don't want strings
  391. // We don't want IDs
  392. // We don't care - we want all.
  393. //
  394. if ( ((lplstSpn->lpPropName->ulKind == MNID_ID) &&
  395. (ulFlags & MAPI_NO_IDS))
  396. || ((lplstSpn->lpPropName->ulKind == MNID_STRING) &&
  397. (ulFlags & MAPI_NO_STRINGS)) )
  398. continue;
  399. //
  400. // We want these tags
  401. //
  402. *lpulPropTag = lplstSpn->lstlnk.ulKey;
  403. lpulPropTag++;
  404. (*lppPropTagArray)->cValues++;
  405. }
  406. return sc;
  407. }
  408. /*
  409. * ScMakePropList
  410. *
  411. * Purpose:
  412. * Allocate memory for, and fill in a complete list of properties for
  413. * the given lpIPDAT.
  414. *
  415. * Arguments
  416. * lpIPDAT Pointer to IPropData object (alloc and free heap)
  417. * lppPropTagArray Pointer to the memory location which will receive a
  418. * pointer to the newly allocated Tag array.
  419. *
  420. * Returns
  421. * SCODE
  422. */
  423. SCODE
  424. ScMakePropList( LPIPDAT lpIPDAT,
  425. ULONG ulCount,
  426. LPLSTLNK lplstLink,
  427. LPSPropTagArray FAR * lppPropTagArray,
  428. ULONG ulUpperBound)
  429. {
  430. SCODE sc;
  431. UNALIGNED ULONG FAR * lpulPropTag;
  432. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT,
  433. CbNewSPropTagArray(ulCount),
  434. (LPVOID *) lppPropTagArray)))
  435. {
  436. return sc;
  437. }
  438. /* Initialize the count of PropTags to 0.
  439. */
  440. (*lppPropTagArray)->cValues = 0;
  441. for ( lpulPropTag = (*lppPropTagArray)->aulPropTag
  442. ; lplstLink
  443. ; lplstLink = lplstLink->lpNext)
  444. {
  445. /* Set the next PropTag and increment the count of PropTags.
  446. */
  447. if (PROP_ID(lplstLink->ulKey) < ulUpperBound) // Not <= !
  448. {
  449. *lpulPropTag = lplstLink->ulKey;
  450. (*lppPropTagArray)->cValues++;
  451. lpulPropTag++;
  452. }
  453. }
  454. return sc;
  455. }
  456. /****************************************************************
  457. *
  458. - CreateIProp
  459. -
  460. * Purpose
  461. * Used for creating a property interface in memory.
  462. *
  463. *
  464. * Arguments
  465. * lpInterface Pointer to the interface ID of the object the caller
  466. * wants. This should match IID_IMAPIPropData for the
  467. * current version of IPROP.DLL.
  468. * lpfAllocateBuffer Pointer to MAPI memory allocator.
  469. * lpfAllocateMore Pointer to MAPI memory allocate more.
  470. * lpfFreeBuffer Pointer to MAPI memory de-allocator.
  471. * lppMAPIPropData Pointer to memory location which will receive a
  472. * pointer to the new IMAPIPropData object.
  473. *
  474. * Notes
  475. * The caller must insure the MAPI support object from which it drew the
  476. * memory allocation routines is not Released before the new IPropData.
  477. *
  478. * Returns
  479. * SCODE
  480. *
  481. */
  482. STDAPI_(SCODE)
  483. CreateIProp(LPCIID lpInterface,
  484. ALLOCATEBUFFER FAR *lpfAllocateBuffer,
  485. ALLOCATEMORE FAR * lpfAllocateMore,
  486. FREEBUFFER FAR * lpfFreeBuffer,
  487. LPVOID lpvReserved,
  488. LPPROPDATA FAR * lppMAPIPropData )
  489. {
  490. SCODE sc;
  491. LPIPDAT lpIPDAT = NULL;
  492. // validate paremeters
  493. AssertSz( lpfAllocateBuffer && !IsBadCodePtr( (FARPROC)lpfAllocateBuffer ),
  494. TEXT("lpfAllocateBuffer fails address check") );
  495. AssertSz( !lpfAllocateMore || !IsBadCodePtr( (FARPROC)lpfAllocateMore ),
  496. TEXT("lpfAllocateMore fails address check") );
  497. AssertSz( !lpfFreeBuffer || !IsBadCodePtr( (FARPROC)lpfFreeBuffer ),
  498. TEXT("lpfFreeBuffer fails address check") );
  499. AssertSz( lppMAPIPropData && !IsBadWritePtr( lppMAPIPropData, sizeof( LPPROPDATA ) ),
  500. TEXT("LppMAPIPropData fails address check") );
  501. /* Make sure that the caller is asking for an object that we support.
  502. */
  503. if ( lpInterface
  504. && !IsEqualGUID(lpInterface, &IID_IMAPIPropData))
  505. {
  506. sc = MAPI_E_INTERFACE_NOT_SUPPORTED;
  507. goto error;
  508. }
  509. //
  510. // Create a IPDAT per object for lpMAPIPropInternal so that it gets
  511. // called first.
  512. if (FAILED(sc = lpfAllocateBuffer(CBIPDAT, &lpIPDAT)))
  513. {
  514. goto error;
  515. }
  516. /* Init the object to 0, NULL
  517. */
  518. memset( (BYTE *) lpIPDAT, 0, sizeof(*lpIPDAT));
  519. /* Fill in the object specific instance data.
  520. */
  521. lpIPDAT->inst.lpfAllocateBuffer = lpfAllocateBuffer;
  522. lpIPDAT->inst.lpfAllocateMore = lpfAllocateMore;
  523. lpIPDAT->inst.lpfFreeBuffer = lpfFreeBuffer;
  524. #ifndef MAC
  525. lpIPDAT->inst.hinst = hinstMapiX;//HinstMapi();
  526. #ifdef DEBUG
  527. if (lpIPDAT->inst.hinst == NULL)
  528. TraceSz1( TEXT("IPROP: GetModuleHandle failed with error %08lX"),
  529. GetLastError());
  530. #endif /* DEBUG */
  531. #else
  532. lpIPDAT->inst.hinst = hinstMapiX;//(HINSTANCE) GetCurrentProcess();
  533. #endif
  534. /* Initialize the TEXT("standard") object.
  535. * This must be the last operation that
  536. * can fail. If not, explicitly call
  537. * UNKOBJ_Deinit() for failures after
  538. * a successful UNKOBJ_Init.
  539. */
  540. if (FAILED(sc = UNKOBJ_Init( (LPUNKOBJ) lpIPDAT
  541. , (UNKOBJ_Vtbl FAR *) &vtblIPDAT
  542. , sizeof(vtblIPDAT)
  543. , (LPIID FAR *) argpiidIPDAT
  544. , dimensionof( argpiidIPDAT)
  545. , &(lpIPDAT->inst))))
  546. {
  547. DebugTrace( TEXT("CreateIProp() - Error initializing IPDAT object (SCODE = 0x%08lX)\n"), sc );
  548. goto error;
  549. }
  550. /* Initialize the defaults in IPROP specific part of the object.
  551. */
  552. lpIPDAT->ulObjAccess = IPROP_READWRITE;
  553. lpIPDAT->ulNextMapID = 0x8000;
  554. *lppMAPIPropData = (LPPROPDATA) lpIPDAT;
  555. return S_OK;
  556. error:
  557. if (lpIPDAT)
  558. {
  559. lpfFreeBuffer(lpIPDAT);
  560. }
  561. return sc;
  562. }
  563. // --------
  564. // IUnknown
  565. /*
  566. - IPDAT_Release
  567. -
  568. * Purpose:
  569. * Decrements reference count on the IPropData object and
  570. * removes instance data if reference count becomes zero.
  571. *
  572. * Arguments:
  573. * lpIPDAT The IPropData object to be released.
  574. *
  575. * Returns:
  576. * Decremented reference count
  577. *
  578. * Side effects:
  579. *
  580. * Errors:
  581. */
  582. STDMETHODIMP_(ULONG)
  583. IPDAT_Release (LPIPDAT lpIPDAT)
  584. {
  585. ULONG ulcRef;
  586. #if !defined(NO_VALIDATION)
  587. /* Make sure the object is valid.
  588. */
  589. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, Release, lpVtbl))
  590. {
  591. DebugTrace( TEXT("IPDAT::Release() - Bad object passed\n") );
  592. return 1;
  593. }
  594. #endif
  595. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  596. ulcRef = --lpIPDAT->ulcRef;
  597. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  598. /* Free the object.
  599. *
  600. * No critical section lock is required since we are guaranteed to be
  601. * the only thread accessing the object (ie ulcRef == 0).
  602. */
  603. if (!ulcRef)
  604. {
  605. LPLSTLNK lpLstLnk;
  606. LPLSTLNK lpLstLnkNext;
  607. FREEBUFFER * lpfFreeBuffer;
  608. /* Free the property value list.
  609. */
  610. for ( lpLstLnk = (LPLSTLNK) (lpIPDAT->lpLstSPV); lpLstLnk; )
  611. {
  612. lpLstLnkNext = lpLstLnk->lpNext;
  613. FreeLpLstSPV( lpIPDAT, (LPLSTSPV) lpLstLnk);
  614. lpLstLnk = lpLstLnkNext;
  615. }
  616. /* Free the ID to NAME map list.
  617. */
  618. for ( lpLstLnk = (LPLSTLNK) (lpIPDAT->lpLstSPN); lpLstLnk; )
  619. {
  620. lpLstLnkNext = lpLstLnk->lpNext;
  621. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstLnk);
  622. lpLstLnk = lpLstLnkNext;
  623. }
  624. /* Free the object.
  625. */
  626. lpfFreeBuffer = lpIPDAT->inst.lpfFreeBuffer;
  627. UNKOBJ_Deinit((LPUNKOBJ) lpIPDAT);
  628. lpIPDAT->lpVtbl = NULL;
  629. lpfFreeBuffer(lpIPDAT);
  630. }
  631. return ulcRef;
  632. }
  633. /*
  634. - IPDAT_SaveChanges
  635. -
  636. * Purpose:
  637. * This DOES not actually save changes since all changes (SetProps etc)
  638. * become effective immediately. This method will invalidate or keep
  639. * the IPropData object open depending on the flags passed in.
  640. *
  641. * Arguments:
  642. * lpIPDAT IPropData object to save changes on.
  643. * ulFlags KEEP_OPEN_READONLY
  644. * KEEP_OPEN_READWRITE
  645. * FORCE_SAVE (valid but no support)
  646. *
  647. * Returns:
  648. * HRESULT
  649. *
  650. */
  651. STDMETHODIMP
  652. IPDAT_SaveChanges (LPIPDAT lpIPDAT,
  653. ULONG ulFlags)
  654. {
  655. SCODE sc = S_OK;
  656. #if !defined(NO_VALIDATION)
  657. /* Make sure the object is valid.
  658. */
  659. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, SaveChanges, lpVtbl))
  660. {
  661. DebugTrace( TEXT("IPDAT::SaveChanges() - Bad object passed\n") );
  662. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  663. }
  664. Validate_IMAPIProp_SaveChanges( lpIPDAT, ulFlags );
  665. #endif
  666. /* The error exit assumes that we are already in a critical section.
  667. */
  668. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  669. //$REVIEW is this really needed?
  670. /* Check object access rights.
  671. */
  672. if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE))
  673. {
  674. sc = MAPI_E_NO_ACCESS;
  675. goto error;
  676. }
  677. /* IPROP objects are always up to date (saved to memory) so all
  678. * we have to do is figure out whether and how to leave it open.
  679. */
  680. if (!(ulFlags & (KEEP_OPEN_READONLY | KEEP_OPEN_READWRITE)))
  681. {
  682. /* We really should invalidate the object here but we have no
  683. * clear cut way to call the MakeInvalid method since
  684. * we don't have a pointer to the support object!
  685. */
  686. //$REVIEW If we are ever going to hand the client an unwrapped interface
  687. //$REVIEW to IMAPIProp then we must get our own support object!
  688. sc = S_OK;
  689. goto out;
  690. }
  691. //$BUG Combine the READWRITE and READONLY flags to IPROP_WRITABLE.
  692. else if (ulFlags & KEEP_OPEN_READWRITE)
  693. {
  694. lpIPDAT->ulObjAccess |= IPROP_READWRITE;
  695. lpIPDAT->ulObjAccess &= ~IPROP_READONLY;
  696. }
  697. else
  698. {
  699. lpIPDAT->ulObjAccess |= IPROP_READONLY;
  700. lpIPDAT->ulObjAccess &= ~IPROP_READWRITE;
  701. }
  702. goto out;
  703. error:
  704. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
  705. out:
  706. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  707. return ResultFromScode(sc);
  708. }
  709. /*
  710. - IPDAT_GetProps
  711. -
  712. * Purpose:
  713. * Returns in lpcValues and lppPropArray the values of the properties
  714. * in lpPropTagArray. If the latter is NULL, all properties available
  715. * (except PT_OBJECT) from the IPropData object are returned.
  716. *
  717. * Arguments:
  718. * lpIPDAT The IPropData object whose properties are requested.
  719. * lpPropTagArray Pointer to a counted array of property tags of
  720. * properties requested.
  721. * lpcValues Pointer to the memory location which will receive the
  722. * number of values returned.
  723. * lppPropArray Pointer to the memory location which will receive the
  724. * address of the returned property value array.
  725. *
  726. * Returns:
  727. * HRESULT
  728. *
  729. * Notes:
  730. * Now UNICODE enabled. If UNICODE is set, then any string properties
  731. * not otherwise specified to be String8 are returned in UNICODE, otherwise
  732. * unspecified string properties are in String8. String Properties with
  733. * unspecified types occur when GetProps() is used with a NULL for the
  734. * lpPropTagArray.
  735. *
  736. */
  737. STDMETHODIMP
  738. IPDAT_GetProps (LPIPDAT lpIPDAT, LPSPropTagArray lpPropTagArray,
  739. ULONG ulFlags,
  740. ULONG FAR * lpcValues, LPSPropValue FAR * lppPropArray)
  741. {
  742. SCODE sc = S_OK;
  743. ULONG ulcWarning = 0;
  744. ULONG iProp = 0;
  745. LPSPropValue lpPropValue = NULL;
  746. #if !defined(NO_VALIDATION)
  747. /* Make sure the object is valid.
  748. */
  749. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetProps, lpVtbl))
  750. {
  751. DebugTrace( TEXT("IPDAT::GetProps() - Bad object passed\n") );
  752. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  753. }
  754. Validate_IMAPIProp_GetProps(lpIPDAT,
  755. lpPropTagArray,
  756. ulFlags,
  757. lpcValues,
  758. lppPropArray);
  759. #endif
  760. /* The error exit assumes that we are already in a critical section.
  761. */
  762. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  763. /* If they aren't asking for anything specific, then
  764. * just copy what we have and be done with it.
  765. */
  766. if (!lpPropTagArray)
  767. {
  768. LPLSTSPV lpLstSPV;
  769. if (!lpIPDAT->ulCount)
  770. {
  771. /* iProp is initialized to 0 on entry. */
  772. *lpcValues = iProp;
  773. *lppPropArray = lpPropValue;
  774. goto out;
  775. }
  776. /* Allocate space for all listed properties. Space allocated for
  777. * properties which are not actually returned is simply wasted.
  778. */
  779. //$REVIEW This would be a good place for a MAPI reallocBuf function.
  780. if (sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT , lpIPDAT->ulCount * sizeof (SPropValue) , &lpPropValue))
  781. {
  782. //
  783. // Memory error
  784. //
  785. goto error;
  786. }
  787. *lpcValues = 0;
  788. /* iProp is initialized to 0 on method entry.
  789. */
  790. for ( lpLstSPV = lpIPDAT->lpLstSPV; lpLstSPV; lpLstSPV = (LPLSTSPV) (lpLstSPV->lstlnk.lpNext))
  791. {
  792. /* Copy the property.
  793. */
  794. switch (PROP_TYPE(lpLstSPV->lpPropVal->ulPropTag))
  795. {
  796. case PT_OBJECT:
  797. case PT_NULL:
  798. /* These properties with type PT_NULL and PT_OBJECT are handled
  799. * specially. PropCopyMore doesn't handle them now.
  800. */
  801. lpPropValue[iProp].ulPropTag = lpLstSPV->lpPropVal->ulPropTag;
  802. iProp++;
  803. break;
  804. default:
  805. if (FAILED(sc = PropCopyMore( &(lpPropValue[iProp]), (LPSPropValue) (lpLstSPV->lpPropVal),
  806. lpIPDAT->inst.lpfAllocateMore, lpPropValue)))
  807. {
  808. goto error;
  809. }
  810. iProp++;
  811. break;
  812. }
  813. }
  814. /* Return the propValue array and the count of properties actually
  815. * returned.
  816. */
  817. *lpcValues = iProp;
  818. *lppPropArray = lpPropValue;
  819. // Handle UNICODE / String conversions depending on ulFlags
  820. //
  821. // Default WAB Handling is going to be in Unicode so don't need to worry about the MAPI_UNICODE
  822. // flag. Only when the flag is not supplied do we have to provide the non-Unicode data
  823. //
  824. // We'll leave the Unicode code in place anyway for now
  825. if (ulFlags & MAPI_UNICODE )
  826. {
  827. if(sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0))
  828. goto error;
  829. }
  830. else
  831. {
  832. if(sc = ScConvertWPropsToA(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0))
  833. goto error;
  834. }
  835. }
  836. else
  837. {
  838. //
  839. // So they want only specific properties
  840. //
  841. // Allocate space for the new stuff - enuf to give them all they want
  842. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, lpPropTagArray->cValues * sizeof (SPropValue),
  843. &lpPropValue)))
  844. goto error;
  845. //
  846. // Go through the list of prop tags they want, find each one
  847. // in lpIPDAT->lpLstSPV, and copy it over to lpPropValue
  848. //
  849. for (iProp = 0; iProp < lpPropTagArray->cValues; iProp++)
  850. {
  851. LPPLSTLNK lppLstLnk;
  852. LPLSTSPV lpLstSPV;
  853. ULONG ulProp2Find = lpPropTagArray->aulPropTag[iProp];
  854. ULONG ulType2Find = PROP_TYPE(ulProp2Find);
  855. /* If the property is in our list try to copy it.
  856. */
  857. if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV), ulProp2Find)) &&
  858. (lpLstSPV = (LPLSTSPV) (*lppLstLnk)))
  859. {
  860. ULONG ulType2Check = PROP_TYPE(lpLstSPV->lpPropVal->ulPropTag);
  861. /* Make sure the property value can be returned in the form the
  862. * caller expects. If not then set a PT_ERROR scode and make
  863. * sure we return an error.
  864. */
  865. if (!( ((ulType2Find == PT_STRING8) && (ulType2Check == PT_UNICODE)) ||
  866. ((ulType2Find == PT_UNICODE) && (ulType2Check == PT_STRING8)) ||
  867. ((ulType2Find == PT_MV_STRING8) && (ulType2Check == PT_MV_UNICODE)) ||
  868. ((ulType2Find == PT_MV_UNICODE) && (ulType2Check == PT_MV_STRING8)) ))
  869. {
  870. if ( (ulType2Find != ulType2Check)
  871. && (ulType2Find != PT_UNSPECIFIED))
  872. {
  873. lpPropValue[iProp].ulPropTag = PROP_TAG( PT_ERROR , PROP_ID(ulProp2Find));
  874. lpPropValue[iProp].Value.err = MAPI_E_INVALID_TYPE;
  875. ulcWarning += 1;
  876. continue;
  877. }
  878. }
  879. /* Copy the property.
  880. * Properties of these types are handled specially because
  881. * PropCopyMore can't handle them now.
  882. */
  883. if ( (ulType2Check == PT_OBJECT) || (ulType2Check == PT_NULL) || (ulType2Check == PT_ERROR))
  884. {
  885. MemCopy( (BYTE *) &(lpPropValue[iProp]), (BYTE *) (lpLstSPV->lpPropVal), sizeof(SPropValue));
  886. }
  887. else
  888. {
  889. // @todo [PaulHi] 1/19/99
  890. // The problem with first copying the string properties and THEN converting
  891. // them if necessary is that an allocation is preformed for each step. The
  892. // original allocation isn't released until the property array is released.
  893. // It would be more efficient (memory wise) to do the allocation once, after
  894. // any necessary conversion is done. Vikram had special code to do this (similar
  895. // to else condition below) but missed multi-valued strings. This makes for more
  896. // complex and duplicate code. Should this code be changed accordingly?
  897. // First copy the property
  898. if (FAILED(sc = PropCopyMore( &(lpPropValue[iProp]), (LPSPropValue)(lpLstSPV->lpPropVal),
  899. lpIPDAT->inst.lpfAllocateMore, lpPropValue)))
  900. {
  901. goto error;
  902. }
  903. //
  904. // Next convert ANSI-UNICODE or UNICODE-ANSI as requested by caller
  905. //
  906. if ( ((ulType2Find == PT_UNICODE) && (ulType2Check == PT_STRING8)) ||
  907. ((ulType2Find == PT_MV_UNICODE) && (ulType2Check == PT_MV_STRING8)) )
  908. {
  909. // Convert single or multiple value ANSI store string to UNICODE
  910. if(FAILED(sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, lpPropValue, iProp+1, iProp)))
  911. goto error;
  912. }
  913. else if ( ((ulType2Find == PT_STRING8) && (ulType2Check == PT_UNICODE)) ||
  914. ((ulType2Find == PT_MV_STRING8) && (ulType2Check == PT_MV_UNICODE)) )
  915. {
  916. // Convert single or multiple value UNICODE store string to ANSI
  917. if(FAILED(sc = ScConvertWPropsToA(lpIPDAT->inst.lpfAllocateMore, lpPropValue, iProp+1, iProp)))
  918. goto error;
  919. }
  920. }
  921. }
  922. /* Property wasn't found.
  923. */
  924. else
  925. {
  926. //
  927. // [PaulHi] 1/14/99 Raid 63006
  928. // If a property of type PR_EMAIL_ADDRESS was requested and not found
  929. // then check to see if an email address is in the multi-valued
  930. // PR_CONTACT_EMAIL_ADDRESSES property. If so copy the first email
  931. // address to the PR_EMAIL_ADDRESS slot.
  932. //
  933. ULONG ulProp2Check = PR_EMAIL_ADDRESS;
  934. if (PROP_ID(ulProp2Find) == PROP_ID(ulProp2Check) )
  935. {
  936. // Look for a PR_CONTACT_EMAIL_ADDRESSES property
  937. LPPLSTLNK lppLstLnk;
  938. LPLSTSPV lpLstSPV;
  939. ULONG ulNewProp2Find = PR_CONTACT_EMAIL_ADDRESSES;
  940. if ( (lppLstLnk = LPPLSTLNKFindProp((LPPLSTLNK) &(lpIPDAT->lpLstSPV), ulNewProp2Find)) &&
  941. (lpLstSPV = (LPLSTSPV) (*lppLstLnk)) )
  942. {
  943. ULONG ulType2Check = PROP_TYPE(lpLstSPV->lpPropVal->ulPropTag);
  944. BYTE * pPropBuf = NULL;
  945. UINT cBufSize = 0;
  946. // We know that we looked up a MV string so just check for ANSI
  947. // or UNICODE property types
  948. if (ulType2Check == PT_MV_STRING8)
  949. {
  950. LPSTR lpstr = NULL;
  951. //
  952. // Get the first ANSI email string in array
  953. //
  954. if ( ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszA.cValues == 0 )
  955. {
  956. Assert(0);
  957. goto convert_error;
  958. }
  959. lpstr = ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszA.lppszA[0];
  960. cBufSize = lstrlenA(lpstr)+1;
  961. // If caller requested UNICODE then convert before allocating MAPI
  962. // buffer space
  963. if (ulType2Find == PT_UNICODE)
  964. {
  965. // Allocate room for the new UNICODE string
  966. if ( lpIPDAT->inst.lpfAllocateMore((cBufSize * sizeof(WCHAR)), lpPropValue, &pPropBuf) )
  967. {
  968. goto error;
  969. }
  970. if ( MultiByteToWideChar(CP_ACP, 0, lpstr, -1, (LPWSTR)pPropBuf, cBufSize) == 0 )
  971. {
  972. Assert(0);
  973. goto convert_error;
  974. }
  975. // Assign property and fix up property tag
  976. lpPropValue[iProp].ulPropTag = PROP_TAG(PT_UNICODE, PROP_ID(ulProp2Find));
  977. lpPropValue[iProp].Value.lpszW = (LPWSTR)pPropBuf;
  978. }
  979. else
  980. {
  981. // Otherwise just copy string property to property value
  982. // array
  983. // Allocate room for the new ANSI string
  984. if (lpIPDAT->inst.lpfAllocateMore(cBufSize, lpPropValue, &pPropBuf))
  985. {
  986. goto error;
  987. }
  988. // Copy property and fix up property tag
  989. MemCopy((BYTE *)pPropBuf, (BYTE *)lpstr, cBufSize);
  990. lpPropValue[iProp].ulPropTag = PROP_TAG(PT_STRING8, PROP_ID(ulProp2Find));
  991. lpPropValue[iProp].Value.lpszA = (LPSTR)pPropBuf;
  992. }
  993. }
  994. else if (ulType2Check == PT_MV_UNICODE)
  995. {
  996. LPWSTR lpwstr = NULL;
  997. //
  998. // Get the first UNICODE email string in array
  999. //
  1000. if ( ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszW.cValues == 0 )
  1001. {
  1002. Assert(0);
  1003. goto convert_error;
  1004. }
  1005. lpwstr = ((LPSPropValue)(lpLstSPV->lpPropVal))->Value.MVszW.lppszW[0];
  1006. // If caller requested ANSI then convert before allocating MAPI
  1007. // buffer space
  1008. if (ulType2Find == PT_STRING8)
  1009. {
  1010. cBufSize = WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, NULL, 0, NULL, NULL) + 1;
  1011. // Allocate room for the new ANSI string
  1012. if ( lpIPDAT->inst.lpfAllocateMore(cBufSize, lpPropValue, &pPropBuf) )
  1013. {
  1014. goto error;
  1015. }
  1016. if ( WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, (LPSTR)pPropBuf, cBufSize, NULL, NULL) == 0 )
  1017. {
  1018. Assert(0);
  1019. goto convert_error;
  1020. }
  1021. // Assign property and fix up property tag
  1022. lpPropValue[iProp].ulPropTag = PROP_TAG(PT_STRING8, PROP_ID(ulProp2Find));
  1023. lpPropValue[iProp].Value.lpszA = (LPSTR)pPropBuf;
  1024. }
  1025. else
  1026. {
  1027. // Otherwise just copy string property to property value
  1028. // array
  1029. cBufSize = lstrlenW(lpwstr)+1;
  1030. // Allocate room for the new UNICODE string
  1031. if (lpIPDAT->inst.lpfAllocateMore((sizeof(WCHAR) * cBufSize), lpPropValue, &pPropBuf))
  1032. {
  1033. goto error;
  1034. }
  1035. // Copy property and fix up property tag
  1036. MemCopy((BYTE *)pPropBuf, (BYTE *)lpwstr, (sizeof(WCHAR) * cBufSize));
  1037. lpPropValue[iProp].ulPropTag = PROP_TAG(PT_UNICODE, PROP_ID(ulProp2Find));
  1038. lpPropValue[iProp].Value.lpszW = (LPWSTR)pPropBuf;
  1039. }
  1040. }
  1041. else
  1042. {
  1043. Assert(0);
  1044. goto convert_error;
  1045. }
  1046. // Success
  1047. continue;
  1048. }
  1049. }
  1050. convert_error:
  1051. // Otherwise return error for this property
  1052. lpPropValue[iProp].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(ulProp2Find));
  1053. lpPropValue[iProp].Value.err = MAPI_E_NOT_FOUND;
  1054. /* Increment the warning count to trigger MAPI_W_ERRORS_RETURNED.
  1055. */
  1056. ulcWarning += 1;
  1057. }
  1058. }
  1059. *lpcValues = iProp;
  1060. *lppPropArray = lpPropValue;
  1061. }
  1062. // [PaulHi] 1/15/99
  1063. // Mass property conversion (ANIS/UNICODE) should only be done when the caller
  1064. // doesn't specifically request property tag types.
  1065. #if 0
  1066. //
  1067. // Handle UNICODE / String conversions depending on ulFlags
  1068. //
  1069. // Default WAB Handling is going to be in Unicode so don't need to worry about the MAPI_UNICODE
  1070. // flag. Only when the flag is not supplied do we have to provide the non-Unicode data
  1071. //
  1072. // We'll leave the Unicode code in place anyway for now
  1073. if (ulFlags & MAPI_UNICODE )
  1074. {
  1075. if(sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0))
  1076. goto error;
  1077. }
  1078. else
  1079. {
  1080. if(sc = ScConvertWPropsToA(lpIPDAT->inst.lpfAllocateMore, *lppPropArray, *lpcValues, 0))
  1081. goto error;
  1082. }
  1083. #endif
  1084. goto out;
  1085. error:
  1086. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPropValue );
  1087. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
  1088. out:
  1089. if (ulcWarning)
  1090. sc = MAPI_W_ERRORS_RETURNED;
  1091. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  1092. return ResultFromScode(sc);
  1093. }
  1094. /*
  1095. - IPDAT_GetPropList
  1096. -
  1097. * Purpose:
  1098. * Returns in lpPropTagArray the list of all currently available properties
  1099. * (including PT_OBJECT) in the IPropData object.
  1100. *
  1101. * Now supports UNICODE flag in ulFlag. Conversion of String Proptags based
  1102. * whether MAPI_UNICODE is set or not.
  1103. *
  1104. * Arguments:
  1105. * lpIPDAT The IPropData object whose properties are requested.
  1106. * lppPropTagArray Pointer to the memory location which will receive
  1107. * a property tag array of the listed properties.
  1108. * Returns:
  1109. * HRESULT
  1110. *
  1111. */
  1112. STDMETHODIMP
  1113. IPDAT_GetPropList (LPIPDAT lpIPDAT,
  1114. ULONG ulFlags,
  1115. LPSPropTagArray FAR * lppPropTagArray)
  1116. {
  1117. SCODE sc = S_OK;
  1118. ULONG uTagA = 0, uTagW = 0, iTag = 0;
  1119. #if !defined(NO_VALIDATION)
  1120. /* Make sure the object is valid.
  1121. */
  1122. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetPropList, lpVtbl))
  1123. {
  1124. DebugTrace( TEXT("IPDAT::GetPropList() - Bad object passed\n") );
  1125. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1126. }
  1127. Validate_IMAPIProp_GetPropList( lpIPDAT, ulFlags, lppPropTagArray );
  1128. #endif // not NO_VALIDATION
  1129. /* The error exit assumes that we are already in a critical section.
  1130. */
  1131. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  1132. sc = ScMakePropList( lpIPDAT, lpIPDAT->ulCount, (LPLSTLNK) lpIPDAT->lpLstSPV,
  1133. lppPropTagArray, (ULONG) -1 );
  1134. if ( FAILED( sc ) )
  1135. goto error;
  1136. // Support for UNICODE / String8
  1137. for ( iTag = 0; iTag < (*lppPropTagArray)->cValues; iTag++ )
  1138. {
  1139. uTagA = uTagW = 0;
  1140. switch(PROP_TYPE( (*lppPropTagArray)->aulPropTag[iTag] ))
  1141. {
  1142. case PT_STRING8:
  1143. uTagW = PT_UNICODE;
  1144. break;
  1145. case PT_MV_STRING8:
  1146. uTagW = PT_MV_UNICODE;
  1147. break;
  1148. case PT_UNICODE:
  1149. uTagA = PT_STRING8;
  1150. break;
  1151. case PT_MV_UNICODE:
  1152. uTagA = PT_MV_STRING8;
  1153. break;
  1154. default:
  1155. continue;
  1156. break;
  1157. }
  1158. if ( ulFlags & MAPI_UNICODE && uTagW)
  1159. (*lppPropTagArray)->aulPropTag[iTag] = CHANGE_PROP_TYPE( (*lppPropTagArray)->aulPropTag[iTag], uTagW);
  1160. else if ( ulFlags & ~MAPI_UNICODE && uTagA)
  1161. (*lppPropTagArray)->aulPropTag[iTag] = CHANGE_PROP_TYPE( (*lppPropTagArray)->aulPropTag[iTag], uTagA);
  1162. }
  1163. goto out;
  1164. error:
  1165. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
  1166. out:
  1167. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  1168. return MakeResult(sc);
  1169. }
  1170. /*
  1171. - IPDAT_OpenProperty
  1172. -
  1173. * Purpose:
  1174. * OpenProperty is not supported for IPROP.DLL. It will, however, validate
  1175. * the input parameters.
  1176. *
  1177. * Arguments:
  1178. * lpIPDAT The IPropData object which contains the property/
  1179. * ulPropTag Property tag for the desired property.
  1180. * lpiid Pointer to the ID for the requested interface.
  1181. * ulInterfaceOptions Specifies interface-specific behavior
  1182. * ulFlags MAPI_CREATE, MAPI_MODIFY, MAPI_DEFERRED_ERRORS
  1183. * lppUnk Pointer to the newly created interface pointer
  1184. *
  1185. * Returns:
  1186. * HRESULT
  1187. *
  1188. */
  1189. STDMETHODIMP
  1190. IPDAT_OpenProperty (LPIPDAT lpIPDAT,
  1191. ULONG ulPropTag,
  1192. LPCIID lpiid,
  1193. ULONG ulInterfaceOptions,
  1194. ULONG ulFlags,
  1195. LPUNKNOWN FAR * lppUnk)
  1196. {
  1197. SCODE sc = S_OK;
  1198. #if !defined(NO_VALIDATION)
  1199. /* Make sure the object is valid.
  1200. */
  1201. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, OpenProperty, lpVtbl))
  1202. {
  1203. DebugTrace( TEXT("IPDAT::OpenProperty() - Bad object passed\n") );
  1204. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1205. }
  1206. Validate_IMAPIProp_OpenProperty(
  1207. lpIPDAT,
  1208. ulPropTag,
  1209. lpiid,
  1210. ulInterfaceOptions,
  1211. ulFlags,
  1212. lppUnk);
  1213. #endif // not NO_VALIDATION
  1214. /* The error exit assumes that we are already in a critical section.
  1215. */
  1216. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  1217. /* We don't support OpenProperty.
  1218. */
  1219. sc = MAPI_E_INTERFACE_NOT_SUPPORTED;
  1220. /*
  1221. *error:
  1222. */
  1223. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
  1224. /*
  1225. *out:
  1226. */
  1227. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  1228. return MakeResult(sc);
  1229. }
  1230. /*
  1231. - IPDAT_SetProps
  1232. -
  1233. * Purpose:
  1234. * Sets the properties listed in <lpPropArray>.
  1235. * Returns an array of problems in <lppProblems> if there were any,
  1236. * NULL If there weren't any.
  1237. *
  1238. * Arguments:
  1239. * lpIPDAT The IPropData object whose properties are to be set.
  1240. * cValues The count of properties to be set.
  1241. * lpPropArray Pointer to a an array of <cValues> property value
  1242. * structures.
  1243. * lppProblems Pointer to memory location which will receive a
  1244. * pointer to a problem array if non-catastrophic
  1245. * errors occur. NULL if no problem array is desired.
  1246. *
  1247. * Returns:
  1248. * HRESULT
  1249. *
  1250. */
  1251. STDMETHODIMP
  1252. IPDAT_SetProps (LPIPDAT lpIPDAT,
  1253. ULONG cValues,
  1254. LPSPropValue lpPropArray,
  1255. LPSPropProblemArray FAR * lppProblems)
  1256. {
  1257. SCODE sc = S_OK;
  1258. int iProp = 0;
  1259. LPLSTSPV lpLstSPVNew = NULL;
  1260. LPSPropProblemArray lpProblems = NULL;
  1261. LPSPropValue lpPropToAdd = NULL;
  1262. #if !defined(NO_VALIDATION)
  1263. // Make sure the object is valid.
  1264. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, SetProps, lpVtbl))
  1265. {
  1266. DebugTrace( TEXT("IPDAT::SetProps() - Bad object passed\n") );
  1267. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1268. }
  1269. Validate_IMAPIProp_SetProps( lpIPDAT, cValues, lpPropArray, lppProblems);
  1270. #endif // not NO_VALIDATION
  1271. /* The error exit assumes that we are already in a critical section.
  1272. */
  1273. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  1274. /* Check access rights...
  1275. */
  1276. if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE))
  1277. {
  1278. sc = MAPI_E_NO_ACCESS;
  1279. goto error;
  1280. }
  1281. if (lppProblems)
  1282. {
  1283. /* Initially indicate no problems.
  1284. */
  1285. *lppProblems = NULL;
  1286. /* Allocate the property problem array.
  1287. * Because we expect the property list to be of TEXT("reasonable") size we
  1288. * go ahead and allocate enough entries for every property to have a
  1289. * problem.
  1290. */
  1291. //$REVIEW This is a place where a MAPI reallocBuf function would be useful.
  1292. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
  1293. , CbNewSPropProblemArray(cValues)
  1294. , &lpProblems)))
  1295. {
  1296. goto error;
  1297. }
  1298. lpProblems->cProblem = 0;
  1299. }
  1300. /* Loop through the list of properties to set..
  1301. */
  1302. for (iProp = 0; iProp < (int)cValues; iProp++)
  1303. {
  1304. ULONG ulProp2Find = lpPropArray[iProp].ulPropTag;
  1305. LPPLSTLNK lppLstLnk;
  1306. LPLSTSPV lpLstSPV;
  1307. /* Reset the temp prop name and value pointers so we don't accidentally
  1308. * free the wrong one on an error.
  1309. */
  1310. lpLstSPVNew = NULL;
  1311. lpPropToAdd = NULL;
  1312. /* Ignore properties with type PT_ERROR or PR_NULL.
  1313. */
  1314. if ((PROP_TYPE(ulProp2Find) == PT_ERROR) || (ulProp2Find == PR_NULL))
  1315. {
  1316. continue;
  1317. }
  1318. /* PT_OBJECT and PT_UNSPECIFIED properties get caught in parameter
  1319. * validation.
  1320. */
  1321. /* If a writable property with the given tag already exists then
  1322. * delete it (we will create another version of it later).
  1323. *
  1324. * If a readonly property with the given tag already exists then
  1325. * include an error in the problem array.
  1326. */
  1327. if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV) , ulProp2Find))
  1328. && (lpLstSPV = (LPLSTSPV) (*lppLstLnk)))
  1329. {
  1330. /* If it is readonly then put an entry into the problem
  1331. * array.
  1332. */
  1333. if (!(lpLstSPV->ulAccess & IPROP_READWRITE))
  1334. {
  1335. AddProblem( lpProblems
  1336. , iProp
  1337. , lpPropArray[iProp].ulPropTag
  1338. , MAPI_E_NO_ACCESS);
  1339. goto nextProp;
  1340. }
  1341. /* Unlink the found property and free its memory.
  1342. */
  1343. UnlinkLstLnk( lppLstLnk);
  1344. lpIPDAT->ulCount -= 1;
  1345. FreeLpLstSPV( lpIPDAT, lpLstSPV);
  1346. }
  1347. // Native string storage within the WAB is now in UNICODE
  1348. // so if any property being set on the object is in ANSI/DBCS .. convert this to UNICODE
  1349. // before trying to add it here ..
  1350. if( PROP_TYPE(lpPropArray[iProp].ulPropTag) == PT_STRING8 ||
  1351. PROP_TYPE(lpPropArray[iProp].ulPropTag) == PT_MV_STRING8 )
  1352. {
  1353. // Create a temp copy of this sepcific property array so that we can munge the
  1354. // data .. I would rather not munge the original array because caller might expect to use it
  1355. // .. there's no gaurantee its safely modifiable
  1356. //
  1357. ULONG cbToAllocate = 0;
  1358. sc = ScCountProps( 1, &(lpPropArray[iProp]), &cbToAllocate );
  1359. if (FAILED(sc))
  1360. {
  1361. DebugTrace(TEXT("SetProps() - ScCountProps failed (SCODE = 0x%08lX)\n"), sc );
  1362. goto error;
  1363. }
  1364. /* Allocate the whole chunk
  1365. */
  1366. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT, cbToAllocate, &lpPropToAdd)))
  1367. {
  1368. goto error;
  1369. }
  1370. /* Copy the property.
  1371. */
  1372. if (sc = ScCopyProps(1, &(lpPropArray[iProp]), lpPropToAdd, NULL))
  1373. {
  1374. DebugTrace(TEXT("SetProps() - Error copying prop (SCODE = 0x%08lX)\n"), sc );
  1375. goto error;
  1376. }
  1377. // Now convert all the strings in this temp duplicate
  1378. if ( sc = ScConvertAPropsToW(lpIPDAT->inst.lpfAllocateMore, lpPropToAdd, 1, 0))
  1379. {
  1380. DebugTrace(TEXT("SetProps() - error convert W to A\n"));
  1381. goto error;
  1382. }
  1383. }
  1384. /* Create a new property value list entry.
  1385. *
  1386. * NOTE! This automatically marks the property as dirty and writeable.
  1387. */
  1388. if (FAILED(sc = ScCreateSPV( lpIPDAT,
  1389. lpPropToAdd ? lpPropToAdd : &(lpPropArray[iProp]),
  1390. &lpLstSPVNew)))
  1391. {
  1392. goto error;
  1393. }
  1394. /* Link the new property to our list of props.
  1395. */
  1396. LinkLstLnk( (LPLSTLNK FAR *) &(lpIPDAT->lpLstSPV)
  1397. , &(lpLstSPVNew->lstlnk));
  1398. lpIPDAT->ulCount += 1;
  1399. nextProp:
  1400. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPropToAdd);
  1401. }
  1402. if (lppProblems && lpProblems->cProblem)
  1403. {
  1404. *lppProblems = lpProblems;
  1405. }
  1406. else
  1407. {
  1408. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
  1409. }
  1410. goto out;
  1411. error:
  1412. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPVNew);
  1413. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
  1414. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
  1415. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPropToAdd);
  1416. out:
  1417. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  1418. return MakeResult(sc);
  1419. }
  1420. /*
  1421. - IPDAT_DeleteProps
  1422. -
  1423. * Purpose:
  1424. * Deletes the properties listed in lpPropTagArray from the IPropData
  1425. * object. Returns a list of problems in <lppProblems) if there were
  1426. * problems deleting specific properties, NULL If there weren't any.
  1427. *
  1428. * Arguments:
  1429. * lpIPDAT The IPropData object whose properties are to be
  1430. * deleted.
  1431. * lpPropTagArray Pointer to a counted array of property tags of the
  1432. * properties to be deleted. Must not be NULL.
  1433. * lppProblems Pointer to address of a property problem structure
  1434. * to be returned. NULL if no problem array is
  1435. * desired.
  1436. * Returns:
  1437. * HRESULT
  1438. */
  1439. STDMETHODIMP
  1440. IPDAT_DeleteProps( LPIPDAT lpIPDAT,
  1441. LPSPropTagArray lpPropTagArray,
  1442. LPSPropProblemArray FAR *lppProblems)
  1443. {
  1444. SCODE sc = S_OK;
  1445. LPSPropProblemArray lpProblems = NULL;
  1446. int iProp;
  1447. LPULONG lpulProp2Find;
  1448. #if !defined(NO_VALIDATION)
  1449. /* Make sure the object is valid.
  1450. */
  1451. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, DeleteProps, lpVtbl))
  1452. {
  1453. DebugTrace( TEXT("IPDAT::DeleteProps() - Bad object passed\n") );
  1454. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1455. }
  1456. Validate_IMAPIProp_DeleteProps( lpIPDAT, lpPropTagArray, lppProblems );
  1457. #endif // not NO_VALIDATION
  1458. /* The error exit assumes that we are already in a critical section.
  1459. */
  1460. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  1461. /* Check access rights...
  1462. */
  1463. if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE))
  1464. {
  1465. sc = MAPI_E_NO_ACCESS;
  1466. goto error;
  1467. }
  1468. if (lppProblems)
  1469. {
  1470. /* Initially indicate no problems.
  1471. */
  1472. *lppProblems = NULL;
  1473. /* Allocate the property problem array.
  1474. * Because we expect the property list to be of TEXT("reasonable") size we
  1475. * go ahead and allocate enough entries for every property to have a
  1476. * problem.
  1477. */
  1478. //$REVIEW This is a place where a MAPI reallocBuf function would be useful.
  1479. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
  1480. , CbNewSPropProblemArray(lpPropTagArray->cValues)
  1481. , &lpProblems)))
  1482. {
  1483. goto error;
  1484. }
  1485. lpProblems->cProblem = 0;
  1486. }
  1487. // Loop through the list of properties to delete..
  1488. for ( iProp = 0, lpulProp2Find = ((LPULONG)(lpPropTagArray->aulPropTag))
  1489. ; iProp < (int)(lpPropTagArray->cValues)
  1490. ; lpulProp2Find++, iProp++)
  1491. {
  1492. LPPLSTLNK lppLstLnk;
  1493. LPLSTSPV lpLstSPV;
  1494. /* If a writable property with the given ID already exists then
  1495. * delete it.
  1496. *
  1497. * If a readonly property with the given ID already exists then
  1498. * include an error in the problem array.
  1499. */
  1500. if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV)
  1501. , *lpulProp2Find))
  1502. && (lpLstSPV = (LPLSTSPV) (*lppLstLnk)))
  1503. {
  1504. /* If it is readonly then put an entry into the problem
  1505. * array.
  1506. */
  1507. if (!(lpLstSPV->ulAccess & IPROP_READWRITE))
  1508. {
  1509. AddProblem( lpProblems
  1510. , iProp
  1511. , *lpulProp2Find
  1512. , MAPI_E_NO_ACCESS);
  1513. continue;
  1514. }
  1515. /* Unlink the found property and free its memory.
  1516. */
  1517. UnlinkLstLnk( lppLstLnk);
  1518. lpIPDAT->ulCount -= 1;
  1519. FreeLpLstSPV( lpIPDAT, lpLstSPV);
  1520. }
  1521. }
  1522. if (lppProblems && lpProblems->cProblem)
  1523. {
  1524. *lppProblems = lpProblems;
  1525. }
  1526. else
  1527. {
  1528. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
  1529. }
  1530. goto out;
  1531. error:
  1532. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
  1533. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
  1534. out:
  1535. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  1536. return MakeResult(sc);
  1537. }
  1538. //---------------------------------------------------------------------------
  1539. // Name: FTagExists()
  1540. //
  1541. // Description:
  1542. // Determines if a Proptag exists in proptag array.
  1543. //
  1544. // Parameters:
  1545. // Returns:
  1546. // Effects:
  1547. // Notes:
  1548. // Revision:
  1549. //---------------------------------------------------------------------------
  1550. static BOOL FTagExists( LPSPropTagArray lptaga, ULONG ulTagToFind )
  1551. {
  1552. LONG ctag = (LONG)lptaga->cValues - 1;
  1553. for ( ; ctag >= 0; --ctag )
  1554. {
  1555. if ( lptaga->aulPropTag[ctag] == ulTagToFind )
  1556. return TRUE;
  1557. }
  1558. return FALSE;
  1559. }
  1560. /*
  1561. - HrCopyProps
  1562. -
  1563. * Purpose:
  1564. * Copies properties from an IPropData object to
  1565. * another object with an IMAPIProp interface.
  1566. *
  1567. * If lpptaInclude is not null then only properties listed by it will
  1568. * be copied. If lpptaExclude is not NULL then none of the properties
  1569. * listed by it will be copied regardless of whether they appear in
  1570. * lpptaInclude. PROP_TYPEs in lpptaInclude and lpptaExclude are
  1571. * ignored.
  1572. *
  1573. * Property names are copied!
  1574. * If a property is named in the source object (lpIPDAT) and the name
  1575. * does not exist in the destination object, a new named property ID
  1576. * will be requested from the destination
  1577. *
  1578. * If the IMAPIPropData interface is supplied for the destination
  1579. * then individual property access flags will be copied to the destination.
  1580. *
  1581. * Arguments:
  1582. * lpIPDATSrc The source IPropData object.
  1583. * lpIPDATDst The destination IPropData object. May be NULL.
  1584. * lpmpDst The destination IMAPIProp object. May NOT be NULL.
  1585. * lpptaInclude Pointer to a counted array of property tags of
  1586. * properties that will be copied. May be NULL.
  1587. * lpptaExclude Pointer to a counted array of property tags of
  1588. * properties not to be copied. May be NULL.
  1589. * ulFlags MAPI_MOVE
  1590. * MAPI_NOREPLACE
  1591. * MAPI_DIALOG (not supported)
  1592. * MAPI_STD_DIALOG (not supported)
  1593. * lppProblems Pointer to memory location which will receive a
  1594. * pointer the the list of problems. NULL if no
  1595. * propblem array is desired.
  1596. *
  1597. * Returns:
  1598. * HRESULT
  1599. *
  1600. * Side effects:
  1601. *
  1602. * Notes:
  1603. *
  1604. * Rewrote copy prop handling to call Destination MAPIProp object twice. Once
  1605. * for Names to ID mappings and the other for one SetProps.
  1606. *
  1607. * Errors:
  1608. */
  1609. STDMETHODIMP
  1610. HrCopyProps ( LPIPDAT lpIPDATSrc,
  1611. LPPROPDATA lpIPDATDst,
  1612. LPMAPIPROP lpmpDst,
  1613. LPSPropTagArray lptagaInclude,
  1614. LPSPropTagArray lptagaExclude,
  1615. ULONG ulFlags,
  1616. LPSPropProblemArray FAR * lppProblems)
  1617. {
  1618. SCODE sc = S_OK;
  1619. HRESULT hr;
  1620. LPSPropProblemArray lpProbDest = NULL;
  1621. LPSPropProblemArray lpOurProblems = NULL;
  1622. LPSPropTagArray lptagaDst = NULL;
  1623. LPSPropValue rgspvSrcProps = NULL;
  1624. ULONG FAR * rgulSrcAccess = NULL;
  1625. ULONG cPropsSrc;
  1626. LPSPropTagArray lptagaSrc = NULL;
  1627. LPSPropTagArray lptagaNamedIDTags = NULL;
  1628. ULONG FAR * rgulSpvRef;
  1629. WORD idx;
  1630. ULONG cPropNames = 0;
  1631. LPMAPINAMEID FAR * lppPropNames = NULL;
  1632. LPSPropTagArray lpNamedTagsDst = NULL;
  1633. LPSPropValue lpspv;
  1634. #if DEBUG
  1635. ULONG cSrcProps = lpIPDATSrc->ulCount;
  1636. #endif
  1637. // If the MAPI_NOREPLACE flag was set then we need to know what properties
  1638. // the destination already has.
  1639. if ( ulFlags & MAPI_NOREPLACE )
  1640. {
  1641. hr = lpmpDst->lpVtbl->GetPropList( lpmpDst, MAPI_UNICODE, &lptagaDst );
  1642. if ( HR_FAILED( hr ) )
  1643. goto error;
  1644. }
  1645. // If MAPI_MOVE, we need to know what props we have to delete from the source.
  1646. // Get source access rights if destination supports IMAPIPropData
  1647. if ( lpIPDATDst || ulFlags & MAPI_MOVE )
  1648. {
  1649. if ( !lptagaInclude )
  1650. {
  1651. hr = IPDAT_GetPropList( lpIPDATSrc, 0, &lptagaSrc );
  1652. if ( HR_FAILED( hr ) )
  1653. goto error;
  1654. }
  1655. else
  1656. {
  1657. // Dup the include prop tag list so we can write in
  1658. // updated Named IDs
  1659. sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc,
  1660. CbSPropTagArray( lptagaInclude ), &lptagaSrc );
  1661. if ( FAILED( sc ) )
  1662. {
  1663. hr = ResultFromScode(sc);
  1664. goto error;
  1665. }
  1666. memcpy( lptagaSrc, lptagaInclude, CbSPropTagArray( lptagaInclude ) );
  1667. }
  1668. if ( lpIPDATDst )
  1669. {
  1670. hr = IPDAT_HrGetPropAccess( lpIPDATSrc, &lptagaInclude, &rgulSrcAccess );
  1671. if ( HR_FAILED( hr ) )
  1672. goto error;
  1673. }
  1674. }
  1675. // Preset the problem array pointer to NULL (ie no problems).
  1676. if ( lppProblems )
  1677. {
  1678. *lppProblems = NULL;
  1679. // Setup our own problem array if there are any problems with
  1680. // GetIDsFromNames or GetNamesFromIDs...
  1681. sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc,
  1682. CbNewSPropProblemArray( lpIPDATSrc->ulCount ), &lpOurProblems );
  1683. if ( FAILED( sc ) )
  1684. {
  1685. hr = ResultFromScode( sc );
  1686. goto error;
  1687. }
  1688. lpOurProblems->cProblem = 0;
  1689. }
  1690. hr = IPDAT_GetProps( lpIPDATSrc, lptagaInclude, 0, &cPropsSrc,
  1691. &rgspvSrcProps );
  1692. if ( HR_FAILED( hr ) )
  1693. {
  1694. goto error;
  1695. }
  1696. // allocate a proptag array to handle named ID mapping
  1697. sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc,
  1698. CbNewSPropTagArray( cPropsSrc ), &lptagaNamedIDTags );
  1699. if ( FAILED( sc ) )
  1700. {
  1701. hr = ResultFromScode( sc );
  1702. goto error;
  1703. }
  1704. // Allocate the Named ID cross ref array to allow cross ref of
  1705. // Named ID back to the original property.
  1706. sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDATSrc, cPropsSrc * sizeof(ULONG),
  1707. &rgulSpvRef );
  1708. if ( FAILED( sc ) )
  1709. {
  1710. hr = ResultFromScode( sc );
  1711. goto error;
  1712. }
  1713. lptagaNamedIDTags->cValues = 0;
  1714. // strafe throught the prop array to deal with excluded
  1715. // and/or named ID proptags
  1716. for ( lpspv = rgspvSrcProps,
  1717. idx = 0;
  1718. idx < cPropsSrc;
  1719. ++idx,
  1720. ++lpspv )
  1721. {
  1722. // check for excluded props
  1723. if ( lptagaExclude )
  1724. {
  1725. if ( FTagExists( lptagaExclude, lpspv->ulPropTag ) )
  1726. {
  1727. if ( lptagaSrc )
  1728. {
  1729. // We're assuming that IMAPIPropData keeps the proplist
  1730. // and the propvalue array in sync.
  1731. Assert( lptagaSrc->aulPropTag[idx] == lpspv->ulPropTag );
  1732. lptagaSrc->aulPropTag[idx] = PR_NULL;
  1733. }
  1734. lpspv->ulPropTag = PR_NULL;
  1735. continue;
  1736. }
  1737. }
  1738. // if in named ID range.
  1739. if ( MIN_NAMED_PROP_ID <= PROP_ID(lpspv->ulPropTag)
  1740. && PROP_ID(lpspv->ulPropTag) <= MAX_NAMED_PROP_ID )
  1741. {
  1742. lptagaNamedIDTags->aulPropTag[lptagaNamedIDTags->cValues] = lpspv->ulPropTag;
  1743. // remember which propval ID references
  1744. rgulSpvRef[lptagaNamedIDTags->cValues] = (ULONG)idx;
  1745. ++lptagaNamedIDTags->cValues;
  1746. }
  1747. }
  1748. // Did we find any named IDs
  1749. if ( lptagaNamedIDTags->cValues )
  1750. {
  1751. hr = IPDAT_GetNamesFromIDs( lpIPDATSrc,
  1752. &lptagaNamedIDTags,
  1753. NULL,
  1754. 0,
  1755. &cPropNames,
  1756. &lppPropNames );
  1757. // Report any failures in our problem array.
  1758. if ( hr )
  1759. {
  1760. goto NameIDProblem;
  1761. }
  1762. // assert that we got what we requested
  1763. Assert( cPropNames == lptagaNamedIDTags->cValues );
  1764. // Get Tag IDs from the Destination, create them if they don't exist.
  1765. hr = lpmpDst->lpVtbl->GetIDsFromNames( lpmpDst, cPropNames, lppPropNames,
  1766. MAPI_CREATE, &lpNamedTagsDst );
  1767. // Deal with Named ID errors/warnings.
  1768. NameIDProblem:
  1769. if ( hr )
  1770. {
  1771. for ( idx = 0; idx < lptagaNamedIDTags->cValues ;idx++ )
  1772. {
  1773. // if we got a MAPI failure set problem array with that error for the
  1774. // affected proptags
  1775. if ( HR_FAILED( hr ) )
  1776. {
  1777. if ( lppProblems )
  1778. {
  1779. AddProblem( lpOurProblems, rgulSpvRef[idx],
  1780. lptagaNamedIDTags->aulPropTag[idx], GetScode( hr ) );
  1781. }
  1782. }
  1783. else
  1784. {
  1785. Assert( cPropNames == lptagaNamedIDTags->cValues );
  1786. if ( !lppPropNames[idx]->Kind.lpwstrName
  1787. || ( lpNamedTagsDst
  1788. && PROP_TYPE(lpNamedTagsDst->aulPropTag[idx]) == PT_ERROR ) )
  1789. {
  1790. if ( lppProblems )
  1791. {
  1792. AddProblem( lpOurProblems, rgulSpvRef[idx],
  1793. lptagaNamedIDTags->aulPropTag[idx], MAPI_E_NOT_FOUND );
  1794. }
  1795. }
  1796. }
  1797. // Set src propval's proptag and proptag to PR_NULL so we don't
  1798. // process it any further.
  1799. rgspvSrcProps[rgulSpvRef[idx]].ulPropTag = PR_NULL;
  1800. lptagaSrc->aulPropTag[rgulSpvRef[idx]] = PR_NULL;
  1801. }
  1802. }
  1803. // Fix up the src propvalue tags
  1804. for ( idx = 0; idx < cPropNames; ++idx )
  1805. {
  1806. if ( rgspvSrcProps[rgulSpvRef[idx]].ulPropTag == PR_NULL )
  1807. continue;
  1808. rgspvSrcProps[rgulSpvRef[idx]].ulPropTag
  1809. = CHANGE_PROP_TYPE( lpNamedTagsDst->aulPropTag[idx],
  1810. PROP_TYPE( rgspvSrcProps[rgulSpvRef[idx]].ulPropTag ) );
  1811. }
  1812. }
  1813. // If propval exists in the destination remove from src propvals.
  1814. // We do this here after the named IDs have been fixed up.
  1815. if ( ulFlags & MAPI_NOREPLACE )
  1816. {
  1817. // spin through the props one more time
  1818. for ( lpspv = rgspvSrcProps,
  1819. idx = 0;
  1820. idx < cPropsSrc;
  1821. ++idx,
  1822. ++lpspv )
  1823. {
  1824. if ( FTagExists( lptagaDst, lpspv->ulPropTag ) )
  1825. {
  1826. // ensure that proptag list and propval array are in sync
  1827. Assert( !lpIPDATDst || lpspv->ulPropTag == lptagaSrc->aulPropTag[idx] );
  1828. lpspv->ulPropTag = PR_NULL;
  1829. if ( lpIPDATDst )
  1830. {
  1831. // We can't be modifying access rights on NOREPLACE
  1832. lptagaSrc->aulPropTag[idx] = PR_NULL;
  1833. }
  1834. }
  1835. }
  1836. }
  1837. // Now set the props...
  1838. hr = lpmpDst->lpVtbl->SetProps( lpmpDst, cPropsSrc, rgspvSrcProps, &lpProbDest );
  1839. if ( HR_FAILED( hr ) )
  1840. goto error;
  1841. // Handle MAPI_MOVE
  1842. if ( ulFlags & MAPI_MOVE )
  1843. {
  1844. // Do we care about problems if delete from the source has any? Nah...
  1845. hr = IPDAT_DeleteProps( lpIPDATSrc, lptagaSrc, NULL );
  1846. if ( HR_FAILED( hr ) )
  1847. goto error;
  1848. }
  1849. // Transfer the access rights
  1850. if ( lpIPDATDst )
  1851. {
  1852. // Did we find any Named IDs
  1853. if ( lptagaNamedIDTags->cValues )
  1854. {
  1855. // fix up the proptags to match the dest.
  1856. for ( idx = 0; idx < cPropNames; ++idx )
  1857. {
  1858. if ( lptagaSrc->aulPropTag[rgulSpvRef[idx]] == PR_NULL )
  1859. continue;
  1860. lptagaSrc->aulPropTag[rgulSpvRef[idx]]
  1861. = CHANGE_PROP_TYPE( lpNamedTagsDst->aulPropTag[idx],
  1862. PROP_TYPE( lptagaSrc->aulPropTag[rgulSpvRef[idx]] ) );
  1863. }
  1864. }
  1865. hr = IPDAT_HrSetPropAccess( (LPIPDAT)lpIPDATDst, lptagaSrc, rgulSrcAccess );
  1866. if ( HR_FAILED( hr ) )
  1867. goto error;
  1868. }
  1869. // Return the problem array if requested and there were problems...
  1870. if ( lppProblems )
  1871. {
  1872. if ( lpProbDest && lpProbDest->cProblem )
  1873. {
  1874. Assert( lpProbDest->cProblem + lpOurProblems->cProblem <= cSrcProps );
  1875. // move/merge the lpProbDest (dest) into our problem array
  1876. for ( idx = 0; idx < lpProbDest->cProblem; idx++ )
  1877. {
  1878. AddProblem( lpOurProblems, lpProbDest->aProblem[idx].ulIndex,
  1879. lpProbDest->aProblem[idx].ulPropTag,
  1880. lpProbDest->aProblem[idx].scode );
  1881. }
  1882. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpProbDest );
  1883. }
  1884. if ( lpOurProblems->cProblem )
  1885. {
  1886. *lppProblems = lpOurProblems;
  1887. hr = ResultFromScode( MAPI_W_ERRORS_RETURNED );
  1888. }
  1889. }
  1890. else
  1891. {
  1892. // ...else dispose of the problem array.
  1893. UNKOBJ_Free( (LPUNKOBJ)lpIPDATSrc, lpOurProblems );
  1894. }
  1895. out:
  1896. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lptagaSrc );
  1897. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lptagaDst );
  1898. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, rgulSrcAccess );
  1899. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, rgspvSrcProps );
  1900. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lptagaNamedIDTags );
  1901. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lppPropNames );
  1902. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpNamedTagsDst );
  1903. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, rgulSpvRef );
  1904. DebugTraceResult( HrCopyProps, hr );
  1905. return hr;
  1906. error:
  1907. /* Free the prop problem array.
  1908. */
  1909. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpOurProblems );
  1910. UNKOBJ_Free( (LPUNKOBJ) lpIPDATSrc, lpProbDest );
  1911. goto out;
  1912. }
  1913. /*
  1914. - IPDAT_CopyTo
  1915. -
  1916. * Purpose:
  1917. * Copies all but the excluded properties from this IPropData object to
  1918. * another object which must support the IMAPIProp interface.
  1919. *
  1920. * Property names are copied!
  1921. * If a property is named in the source object (lpIPDAT) and the name
  1922. * does not exist in the destination object, a new named property ID
  1923. * will be requested from the destination
  1924. *
  1925. * If the IMAPIPropData interface is supported on the destination is not
  1926. * excluded by the caller then individual property access flags will be
  1927. * copied to the destination.
  1928. *
  1929. * Arguments:
  1930. * lpIPDAT The source IPropData object.
  1931. * ciidExclude Count of excluded interfaces in rgiidExclude
  1932. * rgiidExclude Array of iid's specifying excluded interfaces
  1933. * lpPropTagArray Pointer to a counted array of property tags of
  1934. * properties not to be copied, can be NULL
  1935. * ulUIParam Handle of parent window cast to ULONG, NULL if
  1936. * no dialog reqeuested
  1937. * lpInterface Interface ID of the interface of lpDestObj
  1938. * (not used).
  1939. * lpvDestObj destination object
  1940. * ulFlags MAPI_MOVE
  1941. * MAPI_NOREPLACE
  1942. * MAPI_DIALOG (not supported)
  1943. * MAPI_STD_DIALOG (not supported)
  1944. * lppProblems Pointer to memory location which will receive a
  1945. * pointer the the list of problems. NULL if no
  1946. * propblem array is desired.
  1947. *
  1948. * Returns:
  1949. * HRESULT
  1950. *
  1951. * Side effects:
  1952. *
  1953. * Errors:
  1954. */
  1955. STDMETHODIMP
  1956. IPDAT_CopyTo ( LPIPDAT lpIPDAT,
  1957. ULONG ciidExclude,
  1958. LPCIID rgiidExclude,
  1959. LPSPropTagArray lpExcludeProps,
  1960. ULONG_PTR ulUIParam,
  1961. LPMAPIPROGRESS lpProgress,
  1962. LPCIID lpInterface,
  1963. LPVOID lpDestObj,
  1964. ULONG ulFlags,
  1965. LPSPropProblemArray FAR * lppProblems)
  1966. {
  1967. HRESULT hResult = hrSuccess;
  1968. LPUNKNOWN lpunkDest = (LPUNKNOWN) lpDestObj;
  1969. LPPROPDATA lpPropData = NULL;
  1970. LPMAPIPROP lpMapiProp = NULL;
  1971. UINT ucT;
  1972. LPCIID FAR *lppiid;
  1973. #if !defined(NO_VALIDATION)
  1974. /* Make sure the object is valid.
  1975. */
  1976. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, CopyTo, lpVtbl))
  1977. {
  1978. DebugTrace( TEXT("IPDAT::CopyTo() - Bad object passed\n") );
  1979. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  1980. }
  1981. Validate_IMAPIProp_CopyTo(
  1982. lpIPDAT,
  1983. ciidExclude,
  1984. rgiidExclude,
  1985. lpExcludeProps,
  1986. ulUIParam,
  1987. lpProgress,
  1988. lpInterface,
  1989. lpDestObj,
  1990. ulFlags,
  1991. lppProblems);
  1992. #endif // not NO_VALIDATION
  1993. // Make sure we're not copying to ourselves
  1994. if ( (LPVOID)lpIPDAT == (LPVOID)lpDestObj )
  1995. {
  1996. DebugTrace( TEXT("IProp: Copying to self is not supported\n") );
  1997. return ResultFromScode( MAPI_E_NO_ACCESS );
  1998. }
  1999. /* The error exit assumes that we are already in a critical section.
  2000. */
  2001. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  2002. /* Determine the best interface to copy contents into. It really doesn't
  2003. * matter what MAPI specified as the interface ID to the destination. We
  2004. * only understand IMAPIPropData and IMAPIProp.
  2005. *
  2006. * We depend on IUnknown being last in the array of IDs that we support.
  2007. */
  2008. for ( ucT = (UINT)(lpIPDAT->ulcIID), lppiid = (LPCIID FAR *) argpiidIPDAT
  2009. ; ucT > CIID_IPROP_INHERITS
  2010. ; lppiid++, ucT--)
  2011. {
  2012. /* See if the interface is excluded.
  2013. */
  2014. if ( !FIsExcludedIID( *lppiid, rgiidExclude, ciidExclude)
  2015. && !HR_FAILED(lpunkDest->lpVtbl->QueryInterface( lpunkDest
  2016. , *lppiid
  2017. , (LPVOID FAR *)
  2018. &lpMapiProp)))
  2019. {
  2020. /* We found a good destination interface so quit looking.
  2021. */
  2022. break;
  2023. }
  2024. }
  2025. /* Determine which interface we ended up with and set up to use that
  2026. * interface.
  2027. */
  2028. if (ucT <= CIID_IPROP_INHERITS)
  2029. {
  2030. /* Didn't find an interface at least as good as IProp so we can't
  2031. * do the CopyTo.
  2032. */
  2033. hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  2034. goto error;
  2035. }
  2036. /* If we ended up with IPropData as the best common interface then use it.
  2037. */
  2038. if (*lppiid == &IID_IMAPIPropData)
  2039. {
  2040. lpPropData = (LPPROPDATA) lpMapiProp;
  2041. }
  2042. /* Copy all properties that are not excluded. Copy extra prop access
  2043. * information if IPropData is supported by the destination.
  2044. */
  2045. if (HR_FAILED(hResult = HrCopyProps( lpIPDAT
  2046. , lpPropData
  2047. , lpMapiProp
  2048. , NULL
  2049. , lpExcludeProps
  2050. , ulFlags
  2051. , lppProblems)))
  2052. {
  2053. goto error;
  2054. }
  2055. out:
  2056. /* Release the object obtained with QueryInterface.
  2057. */
  2058. if (lpMapiProp) {
  2059. UlRelease(lpMapiProp);
  2060. }
  2061. /* Free the prop tag array that we got from the destination.
  2062. */
  2063. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  2064. DebugTraceResult( IPDAT_CopyTo, hResult);
  2065. return hResult;
  2066. error:
  2067. /* Free the prop problem array.
  2068. */
  2069. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, GetScode(hResult), 0);
  2070. goto out;
  2071. }
  2072. /*
  2073. - IPDAT_CopyProps
  2074. -
  2075. * Purpose:
  2076. * Copies all the listed properties from this IPropData object to
  2077. * another object which must support the IMAPIProp interface.
  2078. *
  2079. * Property names are copied!
  2080. * If a property is named in the source object (lpIPDAT) and the name
  2081. * does not exist in the destination object, a new named property ID
  2082. * will be requested from the destination
  2083. *
  2084. * If the IMAPIPropData interface is supported on the destination is not
  2085. * excluded by the caller then individual property access flags will be
  2086. * copied to the destination.
  2087. *
  2088. * Arguments:
  2089. * lpIPDAT The source IPropData object.
  2090. * lpPropTagArray Pointer to a counted array of property tags of
  2091. * properties to be copied, CAN NOT be NULL
  2092. * ulUIParam Handle of parent window cast to ULONG, NULL if
  2093. * no dialog reqeuested
  2094. * lpInterface Interface ID of the interface of lpDestObj
  2095. * (not used).
  2096. * lpvDestObj destination object
  2097. * ulFlags MAPI_MOVE
  2098. * MAPI_NOREPLACE
  2099. * MAPI_DIALOG (not supported)
  2100. * MAPI_STD_DIALOG (not supported)
  2101. * lppProblems Pointer to memory location which will receive a
  2102. * pointer the the list of problems. NULL if no
  2103. * propblem array is desired.
  2104. *
  2105. * Returns:
  2106. * HRESULT
  2107. *
  2108. * Side effects:
  2109. *
  2110. * Errors:
  2111. */
  2112. STDMETHODIMP
  2113. IPDAT_CopyProps ( LPIPDAT lpIPDAT,
  2114. LPSPropTagArray lpPropTagArray,
  2115. ULONG_PTR ulUIParam,
  2116. LPMAPIPROGRESS lpProgress,
  2117. LPCIID lpInterface,
  2118. LPVOID lpDestObj,
  2119. ULONG ulFlags,
  2120. LPSPropProblemArray FAR * lppProblems)
  2121. {
  2122. HRESULT hResult;
  2123. LPUNKNOWN lpunkDest = (LPUNKNOWN) lpDestObj;
  2124. LPPROPDATA lpPropData = NULL;
  2125. LPMAPIPROP lpMapiProp = NULL;
  2126. UINT ucT;
  2127. LPCIID FAR *lppiid;
  2128. #if !defined(NO_VALIDATION)
  2129. /* Make sure the object is valid.
  2130. */
  2131. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, CopyProps, lpVtbl))
  2132. {
  2133. DebugTrace( TEXT("IPDAT::CopyProps() - Bad object passed\n") );
  2134. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2135. }
  2136. Validate_IMAPIProp_CopyProps(
  2137. lpIPDAT,
  2138. lpPropTagArray,
  2139. ulUIParam,
  2140. lpProgress,
  2141. lpInterface,
  2142. lpDestObj,
  2143. ulFlags,
  2144. lppProblems);
  2145. #endif // not NO_VALIDATION
  2146. /* The error exit assumes that we are already in a critical section.
  2147. */
  2148. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  2149. /* Determine the best interface to copy contents into. It really doesn't
  2150. * matter what MAPI specified as the interface ID to the destination. We
  2151. * only understand IMAPIPropData and IMAPIProp.
  2152. *
  2153. * We depend on IUnknown being last in the array of IDs that we support.
  2154. */
  2155. for ( ucT = (UINT)(lpIPDAT->ulcIID), lppiid = (LPCIID FAR *) argpiidIPDAT
  2156. ; ucT > CIID_IPROP_INHERITS
  2157. ; lppiid++, ucT--)
  2158. {
  2159. /* See if the interface is excluded.
  2160. */
  2161. if (!HR_FAILED(lpunkDest->lpVtbl->QueryInterface( lpunkDest
  2162. , *lppiid
  2163. , (LPVOID FAR *)
  2164. &lpMapiProp)))
  2165. {
  2166. /* We found a good destination interface so quit looking.
  2167. */
  2168. break;
  2169. }
  2170. }
  2171. /* Determine which interface we ended up with and set up to use that
  2172. * interface.
  2173. */
  2174. if (ucT <= CIID_IPROP_INHERITS)
  2175. {
  2176. /* Didn't find an interface at least as good as IProp so we can't
  2177. * do the CopyTo.
  2178. */
  2179. hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  2180. goto error;
  2181. }
  2182. /* If we ended up with IPropData as the best common interface then use it.
  2183. */
  2184. if (*lppiid == &IID_IMAPIPropData)
  2185. {
  2186. lpPropData = (LPPROPDATA) lpMapiProp;
  2187. }
  2188. /* Copy all properties that are not excluded. Copy extra prop access
  2189. * information if IPropData is supported by the destination.
  2190. */
  2191. if (HR_FAILED(hResult = HrCopyProps( lpIPDAT
  2192. , lpPropData
  2193. , lpMapiProp
  2194. , lpPropTagArray
  2195. , NULL
  2196. , ulFlags
  2197. , lppProblems)))
  2198. {
  2199. goto error;
  2200. }
  2201. out:
  2202. /* Release the object obtained with QueryInterface.
  2203. */
  2204. if (lpMapiProp) {
  2205. UlRelease(lpMapiProp);
  2206. }
  2207. /* Free the prop tag array that we got from the destination.
  2208. */
  2209. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  2210. DebugTraceResult( IPDAT_CopyProps, hResult);
  2211. return hResult;
  2212. error:
  2213. /* Free the prop problem array.
  2214. */
  2215. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, GetScode(hResult), 0);
  2216. goto out;
  2217. }
  2218. /*
  2219. - IPDAT_GetNamesFromIDs
  2220. -
  2221. * Purpose:
  2222. * Return the unicode string associated with the given ID
  2223. *
  2224. * Arguments:
  2225. * lpIPDAT The IPropData object whose property name is desired.
  2226. * lppPropTags Pointer to pointer to a property tag array listing
  2227. * the properties whose names are desired. If it
  2228. * points to NULL then we will create a property tag
  2229. * array listing ALL properties available from the
  2230. * IPropData object.
  2231. * ulFlags reserved, must be 0
  2232. * lpcPropNames Pointer to memory location which will receive the
  2233. * count of strings listed in lpppszPropNames.
  2234. * lpppszPropNames pointer to variable for address of an array of
  2235. * unicode property name strings. Freed by
  2236. * MAPIFreeBuffer
  2237. * Returns:
  2238. * HRESULT
  2239. *
  2240. * Side effects:
  2241. *
  2242. * Errors:
  2243. */
  2244. STDMETHODIMP
  2245. IPDAT_GetNamesFromIDs ( LPIPDAT lpIPDAT,
  2246. LPSPropTagArray FAR * lppPropTags,
  2247. LPGUID lpPropSetGuid,
  2248. ULONG ulFlags,
  2249. ULONG FAR * lpcPropNames,
  2250. LPMAPINAMEID FAR * FAR *lpppPropNames)
  2251. {
  2252. SCODE sc = S_OK;
  2253. LPSPropTagArray lpsPTaga = NULL;
  2254. LPSPropTagArray lpsptOut = NULL;
  2255. ULONG cTags;
  2256. ULONG FAR *lpulProp2Find;
  2257. LPMAPINAMEID FAR * lppPropNames = NULL;
  2258. LPMAPINAMEID FAR * lppNameT;
  2259. BOOL fWarning = FALSE;
  2260. #if !defined(NO_VALIDATION)
  2261. /* Make sure the object is valid.
  2262. */
  2263. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetNamesFromIDs, lpVtbl))
  2264. {
  2265. DebugTrace( TEXT("IPDAT::GetNamesFromIDs() - Bad object passed\n") );
  2266. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2267. }
  2268. Validate_IMAPIProp_GetNamesFromIDs(
  2269. lpIPDAT,
  2270. lppPropTags,
  2271. lpPropSetGuid,
  2272. ulFlags,
  2273. lpcPropNames,
  2274. lpppPropNames);
  2275. #endif // not NO_VALIDATION
  2276. /* The error exit assumes that we are already in a critical section.
  2277. */
  2278. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  2279. /* If no prop tag array was passed in then create one...
  2280. */
  2281. if (!(*lppPropTags))
  2282. {
  2283. if (lpPropSetGuid && !memcmp(lpPropSetGuid, &PS_MAPI, sizeof(GUID)))
  2284. {
  2285. //
  2286. // We're dealing with the mapi property set
  2287. // In this case, we need to build up a list
  2288. // of all the properties on this object less
  2289. // than 0x8000 - not quite the same as GetPropList().
  2290. //
  2291. sc = ScMakePropList(lpIPDAT,
  2292. lpIPDAT->ulCount,
  2293. (LPLSTLNK) lpIPDAT->lpLstSPV,
  2294. &lpsPTaga,
  2295. (ULONG)0x8000);
  2296. if (FAILED(sc))
  2297. {
  2298. goto error;
  2299. }
  2300. //
  2301. // For each one of these proptags, we need to
  2302. // build up the names for them using the PS_MAPI
  2303. // guid.
  2304. //
  2305. sc = ScMakeMAPINames(lpIPDAT, lpsPTaga, &lppPropNames);
  2306. if (FAILED(sc))
  2307. {
  2308. goto error;
  2309. }
  2310. *lpppPropNames = lppPropNames;
  2311. *lpcPropNames = lpsPTaga->cValues;
  2312. *lppPropTags = lpsPTaga;
  2313. // Done: we're outta here!
  2314. goto out;
  2315. }
  2316. if (FAILED(sc = ScMakeNamePropList( lpIPDAT,
  2317. (lpIPDAT->ulNextMapID-0x8000),
  2318. lpIPDAT->lpLstSPN,
  2319. &lpsPTaga,
  2320. ulFlags,
  2321. lpPropSetGuid)))
  2322. {
  2323. goto error;
  2324. }
  2325. }
  2326. /* ...else use the one that was passed in.
  2327. */
  2328. else if (*lppPropTags)
  2329. {
  2330. lpsPTaga = *lppPropTags;
  2331. }
  2332. /* Allocate the array of name pointers.
  2333. */
  2334. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
  2335. , lpsPTaga->cValues * sizeof(LPMAPINAMEID)
  2336. , (LPVOID) &lppPropNames)))
  2337. {
  2338. goto error;
  2339. }
  2340. /* Find each property in the list and see if it has a UNICODE name.
  2341. */
  2342. for ( cTags = lpsPTaga->cValues
  2343. , lpulProp2Find = (ULONG FAR *) (lpsPTaga->aulPropTag)
  2344. , lppNameT = lppPropNames
  2345. ; cTags
  2346. ; cTags--, lpulProp2Find++, lppNameT++)
  2347. {
  2348. LPPLSTLNK lppLstLnk;
  2349. LPLSTSPN lpLstSPN;
  2350. /* If there is a ID to NAME map for the property and it has a name.
  2351. * then copy the UNICODE string and pass it back.
  2352. */
  2353. if ( (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK)&(lpIPDAT->lpLstSPN)
  2354. , *lpulProp2Find))
  2355. && (lpLstSPN = (LPLSTSPN) (*lppLstLnk))
  2356. && lpLstSPN->lpPropName)
  2357. {
  2358. sc = ScDupNameID(lpIPDAT,
  2359. lppPropNames, // Alloc'd more here.
  2360. lpLstSPN->lpPropName,
  2361. lppNameT);
  2362. if (FAILED(sc))
  2363. {
  2364. goto error;
  2365. }
  2366. }
  2367. /* Else no ID to NAME map exists for the property so return NULL.
  2368. */
  2369. else
  2370. {
  2371. /* The property has no name, Flag a warning.
  2372. */
  2373. *lppNameT = NULL;
  2374. fWarning = TRUE;
  2375. }
  2376. }
  2377. *lpppPropNames = lppPropNames;
  2378. if (!(*lppPropTags))
  2379. {
  2380. *lppPropTags = lpsPTaga;
  2381. }
  2382. *lpcPropNames = lpsPTaga->cValues;
  2383. goto out;
  2384. error:
  2385. /* If we created the tag array then we need to free it on error.
  2386. * lpsPTaga must be NULL on MAPI_E_INVALID_PARAMETER.
  2387. */
  2388. if (lpsPTaga && !(*lppPropTags))
  2389. {
  2390. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpsPTaga);
  2391. }
  2392. /* Free the array of pointers to names and names.
  2393. */
  2394. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lppPropNames);
  2395. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
  2396. out:
  2397. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  2398. if ( fWarning )
  2399. sc = MAPI_W_ERRORS_RETURNED;
  2400. return MakeResult(sc);
  2401. }
  2402. /*
  2403. - IPDAT_GetIDsFromNames
  2404. -
  2405. * Purpose:
  2406. * Return the property ID for the properties named by the supplied
  2407. * UNICODE strings. If no property ID is currently TEXT("named") by one of
  2408. * the strings and MAPI_CREATE is specified in the flags then a new
  2409. * property ID in the range 0x8000 to 0xfffe will be allocated for that
  2410. * string a returned in the property tag array.
  2411. *
  2412. * If problems occur (eg. no name found and can't create) then the entry
  2413. * for the name that had the problem will be set to have a NULL PROP_ID
  2414. * and PT_ERROR type.
  2415. *
  2416. * All property tags successfully returned will have type PT_UNSPECIFIED.
  2417. *
  2418. * Arguments:
  2419. * lpIPDAT The IPropData object for which property IDs are
  2420. * requested.
  2421. * cPropNames Count of strings in for which IDs are requested.
  2422. * lppszPropNames Pointer ot array of pointers unicode strings which
  2423. * name the properties for which IDs are requested.
  2424. * ulFlags Reserved, must be 0
  2425. * lppPropTags Pointer to memory location which will receive a
  2426. * pointer to a new property tag array listing the
  2427. * requested property tags.
  2428. *
  2429. * Returns:
  2430. * HRESULT
  2431. *
  2432. * Side effects:
  2433. *
  2434. * Errors:
  2435. */
  2436. STDMETHODIMP
  2437. IPDAT_GetIDsFromNames ( LPIPDAT lpIPDAT,
  2438. ULONG cPropNames,
  2439. LPMAPINAMEID FAR * lppPropNames,
  2440. ULONG ulFlags,
  2441. LPSPropTagArray FAR * lppPropTags)
  2442. {
  2443. SCODE sc = S_OK;
  2444. ULONG ulcWarnings = 0;
  2445. LPSPropTagArray lpPTaga = NULL;
  2446. LPULONG lpulProp2Set;
  2447. #if !defined(NO_VALIDATION)
  2448. /* Make sure the object is valid.
  2449. */
  2450. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, GetIDsFromNames, lpVtbl))
  2451. {
  2452. DebugTrace( TEXT("IPDAT::GetIDsFromNames() - Bad object passed\n") );
  2453. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2454. }
  2455. Validate_IMAPIProp_GetIDsFromNames(
  2456. lpIPDAT,
  2457. cPropNames,
  2458. lppPropNames,
  2459. ulFlags,
  2460. lppPropTags);
  2461. #endif // not NO_VALIDATION
  2462. /* The error exit assumes that we are already in a critical section.
  2463. */
  2464. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  2465. /* If the caller wants to change our ID to NAME mapping, make sure access
  2466. * is allowed.
  2467. */
  2468. if ( (ulFlags & MAPI_CREATE)
  2469. && !(lpIPDAT->ulObjAccess & IPROP_READWRITE))
  2470. {
  2471. sc = MAPI_E_NO_ACCESS;
  2472. goto error;
  2473. }
  2474. /*
  2475. * Check to see if there are no names being passed
  2476. */
  2477. if (!cPropNames)
  2478. {
  2479. /*
  2480. * There aren't so build up a list of all proptags > 0x8000
  2481. */
  2482. sc = ScMakeNamePropList( lpIPDAT,
  2483. (lpIPDAT->ulNextMapID-0x8000),
  2484. lpIPDAT->lpLstSPN,
  2485. &lpPTaga,
  2486. 0,
  2487. NULL);
  2488. if (FAILED(sc))
  2489. {
  2490. goto error;
  2491. }
  2492. *lppPropTags = lpPTaga;
  2493. goto out;
  2494. }
  2495. /* Allocate space for the new SPropTagArray.
  2496. */
  2497. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
  2498. , CbNewSPropTagArray(cPropNames)
  2499. , (LPVOID) &lpPTaga)))
  2500. {
  2501. goto error;
  2502. }
  2503. lpPTaga->cValues = cPropNames;
  2504. /* Find each ID in the list passed in.
  2505. */
  2506. for ( lpulProp2Set = (LPULONG) (lpPTaga->aulPropTag)
  2507. ; cPropNames
  2508. ; cPropNames--, lpulProp2Set++, lppPropNames++)
  2509. {
  2510. LPLSTSPN lpLstSPN;
  2511. //
  2512. // First see if it's from PS_MAPI
  2513. //
  2514. if (!memcmp((*lppPropNames)->lpguid, &PS_MAPI, sizeof(GUID)))
  2515. {
  2516. //
  2517. // Yup, it is, so validate that it is a MNID_ID
  2518. //
  2519. if ((*lppPropNames)->ulKind == MNID_ID)
  2520. {
  2521. *lpulProp2Set = (*lppPropNames)->Kind.lID;
  2522. } else
  2523. {
  2524. *lpulProp2Set = PROP_TAG( PT_ERROR, 0);
  2525. ulcWarnings++;
  2526. }
  2527. continue;
  2528. }
  2529. //
  2530. // Next, validate that if we have a PS_PUBLIC_STRINGS...
  2531. //
  2532. if (!memcmp((*lppPropNames)->lpguid, &PS_PUBLIC_STRINGS,
  2533. sizeof(GUID)))
  2534. {
  2535. //
  2536. // ...that it is a MNID_STRING
  2537. //
  2538. if ((*lppPropNames)->ulKind != MNID_STRING)
  2539. {
  2540. //
  2541. // It's not, so it's a malformed name
  2542. //
  2543. *lpulProp2Set = PROP_TAG( PT_ERROR, 0);
  2544. ulcWarnings++;
  2545. continue;
  2546. }
  2547. }
  2548. /* Try to find the name in our list of ID to NAME maps.
  2549. */
  2550. for ( lpLstSPN = lpIPDAT->lpLstSPN
  2551. ; lpLstSPN
  2552. ; lpLstSPN = (LPLSTSPN) (lpLstSPN->lstlnk.lpNext))
  2553. {
  2554. /* If the name doesn't match keep looking.
  2555. */
  2556. if (FEqualNames( *lppPropNames, lpLstSPN->lpPropName ))
  2557. {
  2558. break;
  2559. }
  2560. }
  2561. /* If we found a matching NAME then set the ID.
  2562. */
  2563. if (lpLstSPN)
  2564. {
  2565. *lpulProp2Set = lpLstSPN->lstlnk.ulKey;
  2566. }
  2567. else if (ulFlags & MAPI_CREATE)
  2568. {
  2569. /* Create a new map if we didn't find one and MAPI_CREATE was
  2570. * specified.
  2571. */
  2572. /* Allocate space for the new ID to NAME map.
  2573. */
  2574. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
  2575. , sizeof(LSTSPN)
  2576. , (LPVOID) &lpLstSPN)))
  2577. {
  2578. goto error;
  2579. }
  2580. sc = ScDupNameID(lpIPDAT,
  2581. lpLstSPN, // Alloc'd more here.
  2582. *lppPropNames,
  2583. &(lpLstSPN->lpPropName));
  2584. if (FAILED(sc))
  2585. {
  2586. //
  2587. // Don't try to add it.
  2588. //
  2589. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpLstSPN);
  2590. goto error;
  2591. }
  2592. /* Set the ID to NAME map.
  2593. */
  2594. lpLstSPN->lstlnk.ulKey = PROP_TAG( 0, lpIPDAT->ulNextMapID++);
  2595. /* Link the new map as the first list element.
  2596. */
  2597. LinkLstLnk( (LPLSTLNK FAR *) &(lpIPDAT->lpLstSPN)
  2598. , &(lpLstSPN->lstlnk));
  2599. /* Return the newly created Prop Tag.
  2600. */
  2601. *lpulProp2Set = lpLstSPN->lstlnk.ulKey;
  2602. }
  2603. /* Else we didn't find the NAME and we can't create one so
  2604. * set ID to error.
  2605. */
  2606. else
  2607. {
  2608. *lpulProp2Set = PROP_TAG( PT_ERROR, 0);
  2609. ulcWarnings++;
  2610. }
  2611. }
  2612. *lppPropTags = lpPTaga;
  2613. if (ulcWarnings)
  2614. {
  2615. sc = MAPI_W_ERRORS_RETURNED;
  2616. }
  2617. goto out;
  2618. error:
  2619. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpPTaga);
  2620. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
  2621. out:
  2622. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  2623. return MakeResult(sc);
  2624. }
  2625. /*
  2626. - IPDAT_HrSetObjAccess
  2627. -
  2628. * Purpose:
  2629. * Sets the read/write access and the clean/dirty status of IPropData
  2630. * object as a whole.
  2631. *
  2632. * The read/write access bits can be used to prevent a client from
  2633. * changing or deleting a property via the IMAPIProp methods or from
  2634. * changing the read/write access and status bits of individual properties.
  2635. * It can also be used to prevent the creation of new properties or
  2636. * property names.
  2637. *
  2638. * Arguments:
  2639. * lpIPDAT The IPropData object for which access rights and
  2640. * status will be set.
  2641. * ulAccess The new access/status flags to be set.
  2642. *
  2643. * Returns:
  2644. * HRESULT
  2645. *
  2646. * Side effects:
  2647. *
  2648. * Errors:
  2649. */
  2650. STDMETHODIMP
  2651. IPDAT_HrSetObjAccess ( LPIPDAT lpIPDAT,
  2652. ULONG ulAccess )
  2653. {
  2654. SCODE sc = S_OK;
  2655. #if !defined(NO_VALIDATION)
  2656. /* Make sure the object is valid.
  2657. */
  2658. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrSetObjAccess, lpVtbl))
  2659. {
  2660. DebugTrace( TEXT("IPDAT::HrSetObjAccess() - Bad object passed\n") );
  2661. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2662. }
  2663. #endif
  2664. if (ulAccess & ~(IPROP_READONLY | IPROP_READWRITE))
  2665. {
  2666. return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  2667. }
  2668. if ( !(ulAccess & (IPROP_READONLY | IPROP_READWRITE))
  2669. || ( (ulAccess & (IPROP_READONLY | IPROP_READWRITE))
  2670. == (IPROP_READONLY | IPROP_READWRITE)))
  2671. {
  2672. DebugTrace( TEXT("IPDAT::HrSetObjAccess() - Conflicting access flags.\n") );
  2673. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2674. }
  2675. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  2676. lpIPDAT->ulObjAccess = ulAccess;
  2677. /*
  2678. *out:
  2679. */
  2680. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  2681. return MakeResult(sc);
  2682. }
  2683. /*
  2684. - IPDAT_HrSetPropAccess
  2685. -
  2686. * Purpose:
  2687. * Sets the read/write access and the clean/dirty status of individual
  2688. * properties contained by the IPropData object.
  2689. *
  2690. * The read/write access bits can be used to prevent a client from
  2691. * changing or deleting a property via the IMAPIProp methods.
  2692. *
  2693. * The clean/dirty bits can be used to determine if a client has changed
  2694. * a writable property.
  2695. *
  2696. * Arguments:
  2697. * lpIPDAT The IPropData object for which property access
  2698. * rights and status will be set.
  2699. * lpsPropTagArray List of property tags whose access/status will change.
  2700. * rgulAccess Array of new access/status flags in the same order as
  2701. * as the list of property tags in <lpsPropTagArray>.
  2702. *
  2703. * Returns:
  2704. * HRESULT
  2705. *
  2706. * Side effects:
  2707. *
  2708. * Errors:
  2709. */
  2710. STDMETHODIMP
  2711. IPDAT_HrSetPropAccess( LPIPDAT lpIPDAT,
  2712. LPSPropTagArray lpsPropTagArray,
  2713. ULONG FAR * rgulAccess)
  2714. {
  2715. SCODE sc = S_OK;
  2716. ULONG ulcProps;
  2717. ULONG FAR *lpulPropTag;
  2718. ULONG FAR *lpulAccess;
  2719. #if !defined(NO_VALIDATION)
  2720. /* Make sure the object is valid.
  2721. */
  2722. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrSetPropAccess, lpVtbl))
  2723. {
  2724. DebugTrace( TEXT("IPDAT::HrSetPropAccess() - Bad object passed\n") );
  2725. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2726. }
  2727. /* Validate parameters.
  2728. */
  2729. if ( FBadDelPTA(lpsPropTagArray)
  2730. || IsBadReadPtr(rgulAccess, (UINT) (lpsPropTagArray->cValues)*sizeof(ULONG)))
  2731. {
  2732. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2733. }
  2734. /* Make sure they don't try setting reserved access bits.
  2735. */
  2736. for ( lpulAccess = rgulAccess + lpsPropTagArray->cValues
  2737. ; --lpulAccess >= rgulAccess
  2738. ; )
  2739. {
  2740. if ( (*lpulAccess & ~( IPROP_READONLY | IPROP_READWRITE
  2741. | IPROP_CLEAN | IPROP_DIRTY))
  2742. || !(*lpulAccess & (IPROP_READONLY | IPROP_READWRITE))
  2743. || ( (*lpulAccess & (IPROP_READONLY | IPROP_READWRITE))
  2744. == (IPROP_READONLY | IPROP_READWRITE))
  2745. || !(*lpulAccess & (IPROP_CLEAN | IPROP_DIRTY))
  2746. || ( (*lpulAccess & (IPROP_CLEAN | IPROP_DIRTY))
  2747. == (IPROP_CLEAN | IPROP_DIRTY)))
  2748. {
  2749. DebugTrace( TEXT("IPDAT::HrSetPropAccess() - Conflicting access flags.\n") );
  2750. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2751. }
  2752. }
  2753. #endif
  2754. /* The exit assumes that we are already in a critical section.
  2755. */
  2756. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  2757. // Loop through the list of properties on which to set access/status.
  2758. for ( ulcProps = lpsPropTagArray->cValues
  2759. , lpulPropTag = (ULONG FAR *)(lpsPropTagArray->aulPropTag)
  2760. , lpulAccess = rgulAccess
  2761. ; ulcProps
  2762. ; ulcProps--, lpulPropTag++, lpulAccess++)
  2763. {
  2764. LPPLSTLNK lppLstLnk;
  2765. /* If the property is in our list then set the new access rights and
  2766. * status flags for it. If it's not in our list then ignore it.
  2767. */
  2768. if (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK)
  2769. &(lpIPDAT->lpLstSPV)
  2770. , *lpulPropTag))
  2771. {
  2772. ((LPLSTSPV) (*lppLstLnk))->ulAccess = *lpulAccess;
  2773. }
  2774. }
  2775. /*
  2776. *out:
  2777. */
  2778. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  2779. return MakeResult(sc);
  2780. }
  2781. /*
  2782. - IPDAT_HrGetPropAccess
  2783. -
  2784. * Purpose:
  2785. * Returns the read/write access and the clean/dirty status of individual
  2786. * properties contained by the IPropData object.
  2787. *
  2788. * The read/write access bits can be used to prevent a client from
  2789. * changing or deleting a property via the IMAPIProp methods.
  2790. *
  2791. * The clean/dirty bits can be used to determine if a client has changed
  2792. * a writable property.
  2793. *
  2794. * Arguments:
  2795. * lpIPDAT The IPropData object for which property access
  2796. * rights and status is requested.
  2797. * lpsPropTagArray List of property tags whose access/status is requested.
  2798. * lprgulAccess Pointer to the memory location which will receive a
  2799. * pointer to an array of access/status flags in the same
  2800. * order as the list of property tags in <lpsPropTagArray>.
  2801. *
  2802. * Returns:
  2803. * HRESULT
  2804. *
  2805. * Side effects:
  2806. *
  2807. * Errors:
  2808. */
  2809. STDMETHODIMP
  2810. IPDAT_HrGetPropAccess( LPIPDAT lpIPDAT,
  2811. LPSPropTagArray FAR * lppsPropTagArray,
  2812. ULONG FAR * FAR * lprgulAccess)
  2813. {
  2814. SCODE sc = S_OK;
  2815. HRESULT hResult = hrSuccess;
  2816. ULONG ulcProps;
  2817. LPSPropTagArray lpsPTaga = NULL;
  2818. ULONG FAR *lpulPropTag;
  2819. ULONG FAR *lpulAccessNew = NULL;
  2820. ULONG FAR *lpulAccess;
  2821. #if !defined(NO_VALIDATION)
  2822. /* Make sure the object is valid.
  2823. */
  2824. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrGetPropAccess, lpVtbl))
  2825. {
  2826. DebugTrace( TEXT("IPDAT::HrGetPropAccess() - Bad object passed\n") );
  2827. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2828. }
  2829. /* Validate parameters.
  2830. */
  2831. if ( IsBadReadPtr( lppsPropTagArray, sizeof(LPSPropTagArray))
  2832. || (*lppsPropTagArray && FBadDelPTA(*lppsPropTagArray))
  2833. || IsBadWritePtr( lprgulAccess, sizeof(ULONG FAR *)))
  2834. {
  2835. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2836. }
  2837. #endif
  2838. /* The error exit assumes that we are already in a critical section.
  2839. */
  2840. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  2841. /* If a list of tags was passed in then use it...
  2842. */
  2843. if (lppsPropTagArray && *lppsPropTagArray)
  2844. {
  2845. lpsPTaga = *lppsPropTagArray;
  2846. } else
  2847. {
  2848. /* ...else get a list of tags for all properties in our list.
  2849. */
  2850. sc = ScMakePropList(lpIPDAT,
  2851. lpIPDAT->ulCount,
  2852. (LPLSTLNK) lpIPDAT->lpLstSPV,
  2853. &lpsPTaga,
  2854. (ULONG) -1);
  2855. if (FAILED(sc))
  2856. {
  2857. goto error;
  2858. }
  2859. }
  2860. /* Allocate space for the list of access rights / status flags.
  2861. */
  2862. sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT,
  2863. lpsPTaga->cValues * sizeof(ULONG),
  2864. &lpulAccessNew);
  2865. if (FAILED(sc))
  2866. {
  2867. goto error;
  2868. }
  2869. /* Loop through the list of properties for which rights/flags are
  2870. * requested.
  2871. */
  2872. for ( ulcProps = lpsPTaga->cValues
  2873. , lpulPropTag = (ULONG FAR *)(lpsPTaga->aulPropTag)
  2874. , lpulAccess = lpulAccessNew
  2875. ; ulcProps
  2876. ; ulcProps--, lpulPropTag++, lpulAccess++)
  2877. {
  2878. LPPLSTLNK lppLstLnk;
  2879. /* If the property is in our list then set the new access rights and
  2880. * status flags for it. If it's not in our list then ignore it.
  2881. */
  2882. if (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK)
  2883. &(lpIPDAT->lpLstSPV)
  2884. , *lpulPropTag))
  2885. {
  2886. *lpulAccess = ((LPLSTSPV) (*lppLstLnk))->ulAccess;
  2887. }
  2888. }
  2889. /* If requested return a tag list to the caller.
  2890. */
  2891. if (lppsPropTagArray && !*lppsPropTagArray)
  2892. {
  2893. *lppsPropTagArray = lpsPTaga;
  2894. }
  2895. /* Return the access rights / status flags.
  2896. */
  2897. *lprgulAccess = lpulAccessNew;
  2898. goto out;
  2899. error:
  2900. /* If we created the tag array then free it.
  2901. */
  2902. if (!lppsPropTagArray || !*lppsPropTagArray)
  2903. {
  2904. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpsPTaga);
  2905. }
  2906. /* Free the access rights / status flags list.
  2907. */
  2908. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpulAccessNew);
  2909. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
  2910. out:
  2911. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  2912. return MakeResult(sc);
  2913. }
  2914. /*
  2915. - IPDAT_HrAddObjProps
  2916. -
  2917. * Purpose:
  2918. * Since object properties can not be created by SetProps, this method
  2919. * is included so that object properties can be included in the list
  2920. * of properties available from the IPropData object. Adding an object
  2921. * property will result in the property tag showing up in the list when
  2922. * GetPropList is called.
  2923. *
  2924. * Arguments:
  2925. * lpIPDAT The IPropData object for which object properties are
  2926. * to be added.
  2927. * lpPropTags List of object properties to be added.
  2928. * lprgulAccess Pointer to the memory location which will receive a
  2929. * pointer to an array of problem entries if there
  2930. * were problems entering the new properties. NULL if
  2931. * no problems array is desired.
  2932. *
  2933. * Returns:
  2934. * HRESULT
  2935. *
  2936. * Side effects:
  2937. *
  2938. * Errors:
  2939. */
  2940. STDMETHODIMP
  2941. IPDAT_HrAddObjProps( LPIPDAT lpIPDAT,
  2942. LPSPropTagArray lpPropTags,
  2943. LPSPropProblemArray FAR * lppProblems)
  2944. {
  2945. SCODE sc = S_OK;
  2946. LPSPropProblemArray lpProblems = NULL;
  2947. LPLSTSPV lpLstSPV = NULL;
  2948. SPropValue propVal;
  2949. ULONG UNALIGNED FAR *lpulPropTag;
  2950. ULONG cValues;
  2951. #if !defined(NO_VALIDATION)
  2952. /* Make sure the object is valid.
  2953. */
  2954. if (BAD_STANDARD_OBJ( lpIPDAT, IPDAT_, HrAddObjProps, lpVtbl))
  2955. {
  2956. DebugTrace( TEXT("IPDAT::HrAddObjProps() - Bad object passed\n") );
  2957. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2958. }
  2959. /* Validate parameters.
  2960. */
  2961. if ( IsBadReadPtr(lpPropTags, CbNewSPropTagArray(0))
  2962. || IsBadReadPtr(lpPropTags, CbSPropTagArray(lpPropTags)))
  2963. {
  2964. DebugTrace( TEXT("IPDAT::HrAddObjProps() - Bad Prop Tag Array.\n") );
  2965. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2966. }
  2967. for ( lpulPropTag = lpPropTags->aulPropTag + lpPropTags->cValues
  2968. ; --lpulPropTag >= lpPropTags->aulPropTag
  2969. ; )
  2970. {
  2971. if ( (PROP_ID(*lpulPropTag) == PROP_ID_NULL)
  2972. || (PROP_ID(*lpulPropTag) == PROP_ID_INVALID)
  2973. || (PROP_TYPE(*lpulPropTag) != PT_OBJECT))
  2974. {
  2975. DebugTrace( TEXT("IPDAT::HrAddObjProps() - Bad Prop Tag.\n") );
  2976. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  2977. }
  2978. }
  2979. #endif
  2980. /* The error exit assumes that we are already in a critical section.
  2981. */
  2982. UNKOBJ_EnterCriticalSection((LPUNKOBJ) lpIPDAT);
  2983. /* Check access rights...
  2984. */
  2985. if (!(lpIPDAT->ulObjAccess & IPROP_READWRITE))
  2986. {
  2987. sc = MAPI_E_NO_ACCESS;
  2988. goto error;
  2989. }
  2990. if (lppProblems)
  2991. {
  2992. /* Initially indicate that there were no problems.
  2993. */
  2994. *lppProblems = NULL;
  2995. /* Allocate a problem array that is big enough to report problems on
  2996. * all the properties. Unused entries just end up as wasted space.
  2997. */
  2998. if (FAILED(sc = UNKOBJ_ScAllocate( (LPUNKOBJ) lpIPDAT
  2999. , CbNewSPropProblemArray(lpIPDAT->ulCount)
  3000. , &lpProblems)))
  3001. {
  3002. goto error;
  3003. }
  3004. lpProblems->cProblem = 0;
  3005. }
  3006. /* Loop through the list and add/replace each property listed.
  3007. */
  3008. memset( (BYTE *) &propVal, 0, sizeof(SPropValue));
  3009. for ( cValues = lpPropTags->cValues, lpulPropTag = (ULONG FAR *)(lpPropTags->aulPropTag)
  3010. ; cValues
  3011. ; lpulPropTag++, cValues--)
  3012. {
  3013. LPPLSTLNK lppLstLnk;
  3014. LPLSTSPV lpLstSPV;
  3015. /* If the property is in the list and write enabled then delete it
  3016. * from the list.
  3017. */
  3018. if (lppLstLnk = LPPLSTLNKFindProp( (LPPLSTLNK) &(lpIPDAT->lpLstSPV)
  3019. , *lpulPropTag))
  3020. {
  3021. /* Make sure that we can delete the old property.
  3022. */
  3023. if ( (lpLstSPV = (LPLSTSPV) (*lppLstLnk))
  3024. && !(lpLstSPV->ulAccess & IPROP_READWRITE))
  3025. {
  3026. AddProblem( lpProblems
  3027. , cValues
  3028. , *lpulPropTag
  3029. , MAPI_E_NO_ACCESS);
  3030. continue;
  3031. }
  3032. /* Delete the old property.
  3033. */
  3034. UnlinkLstLnk( lppLstLnk);
  3035. FreeLpLstSPV( lpIPDAT, lpLstSPV);
  3036. lpIPDAT->ulCount -= 1;
  3037. }
  3038. /* Create a new property entry and link it to our list.
  3039. */
  3040. propVal.ulPropTag = *lpulPropTag;
  3041. if (FAILED(sc = ScCreateSPV( lpIPDAT, &propVal, &lpLstSPV)))
  3042. {
  3043. goto error;
  3044. }
  3045. lpLstSPV->ulAccess = IPROP_READWRITE;
  3046. LinkLstLnk( (LPLSTLNK FAR *) &(lpIPDAT->lpLstSPV)
  3047. , (LPLSTLNK) lpLstSPV);
  3048. lpIPDAT->ulCount += 1;
  3049. }
  3050. /* Return the problem array if requested and there were problems...
  3051. */
  3052. if (lppProblems && lpProblems->cProblem)
  3053. {
  3054. *lppProblems = lpProblems;
  3055. }
  3056. /* ...else dispose of the problem array.
  3057. */
  3058. else
  3059. {
  3060. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
  3061. }
  3062. goto out;
  3063. error:
  3064. /* Free the prop problem array.
  3065. */
  3066. UNKOBJ_Free( (LPUNKOBJ) lpIPDAT, lpProblems);
  3067. UNKOBJ_SetLastError((LPUNKOBJ) lpIPDAT, sc, 0);
  3068. out:
  3069. UNKOBJ_LeaveCriticalSection((LPUNKOBJ) lpIPDAT);
  3070. return MakeResult(sc);
  3071. }
  3072. //----------------------------------------------------------------------------
  3073. // Synopsis: SCODE ScWCToAnsi()
  3074. //
  3075. // Description:
  3076. // Converts a Wide Char string to an Ansi string with the passed
  3077. // in MAPI More Allocator.
  3078. // If lpMapiAllocMore and lpBase are NULL and *lppszAnsi is not NULL
  3079. // then we assume *lppszAnsi is a pre allocated buffer
  3080. //
  3081. // Parameters:
  3082. // Returns:
  3083. // Effects:
  3084. // Notes:
  3085. // Revision:
  3086. //----------------------------------------------------------------------------
  3087. SCODE ScWCToAnsiMore( LPALLOCATEMORE lpMapiAllocMore, LPVOID lpBase,
  3088. LPWSTR lpszWC, LPSTR * lppszAnsi )
  3089. {
  3090. SCODE sc = S_OK;
  3091. INT cch;
  3092. if ( !lpszWC )
  3093. {
  3094. if(lpMapiAllocMore && lpBase)
  3095. *lppszAnsi = NULL;
  3096. else
  3097. if(*lppszAnsi)
  3098. *(*lppszAnsi) = '\0';
  3099. goto ret;
  3100. }
  3101. // [PaulHi] 3/31/99 Raid 73845 Determine the actual DBCS buffer size needed
  3102. // cch = lstrlenW( lpszWC ) + 1;
  3103. cch = WideCharToMultiByte(CP_ACP, 0, lpszWC, -1, NULL, 0, NULL, NULL) + 1;
  3104. if(lpMapiAllocMore && lpBase)
  3105. {
  3106. sc = lpMapiAllocMore( cch, lpBase, lppszAnsi );
  3107. if ( FAILED( sc ) )
  3108. {
  3109. DebugTrace( TEXT("ScWCToAnsi() OOM\n") );
  3110. goto ret;
  3111. }
  3112. }
  3113. if (!lppszAnsi || !WideCharToMultiByte(CP_ACP, 0, lpszWC, -1, *lppszAnsi, cch, NULL, NULL))
  3114. {
  3115. DebugTrace( TEXT("ScWcToAnsi(), Conversion from Wide char to multibyte failed\n") );
  3116. sc = MAPI_E_CALL_FAILED;
  3117. goto ret;
  3118. }
  3119. ret:
  3120. DebugTraceSc( ScWCToAnsi, sc );
  3121. return sc;
  3122. }
  3123. /*
  3124. -
  3125. - LPCSTR ConvertWtoA(LPWSTR lpszW);
  3126. *
  3127. * LocalAllocs a ANSI version of an LPWSTR
  3128. *
  3129. * Caller is responsible for freeing
  3130. */
  3131. LPSTR ConvertWtoA(LPCWSTR lpszW)
  3132. {
  3133. int cch;
  3134. LPSTR lpC = NULL;
  3135. if ( !lpszW)
  3136. goto ret;
  3137. // cch = lstrlenW( lpszW ) + 1;
  3138. cch = WideCharToMultiByte( CP_ACP, 0, lpszW, -1, NULL, 0, NULL, NULL );
  3139. cch = cch + 1;
  3140. if(lpC = LocalAlloc(LMEM_ZEROINIT, cch))
  3141. {
  3142. WideCharToMultiByte( CP_ACP, 0, lpszW, -1, lpC, cch, NULL, NULL );
  3143. }
  3144. ret:
  3145. return lpC;
  3146. }
  3147. //----------------------------------------------------------------------------
  3148. // Synopsis: SCODE ScAnsiToWC()
  3149. //
  3150. // Description:
  3151. // Converts an ANSI string to a Wide Character string with the
  3152. // passed in MAPI More allocator.
  3153. // If lpMapiAllocMore and lpBase are NULL and *lppszWC is not NULL
  3154. // then we assume *lppszWC is a pre allocated buffer
  3155. // Parameters:
  3156. // Returns:
  3157. // Effects:
  3158. // Notes:
  3159. // Revision:
  3160. //----------------------------------------------------------------------------
  3161. SCODE ScAnsiToWCMore( LPALLOCATEMORE lpMapiAllocMore, LPVOID lpBase,
  3162. LPSTR lpszAnsi, LPWSTR * lppszWC )
  3163. {
  3164. SCODE sc = S_OK;
  3165. INT cch;
  3166. ULONG ulSize;
  3167. if ( !lpszAnsi )
  3168. {
  3169. if(lpMapiAllocMore && lpBase)
  3170. *lppszWC = NULL;
  3171. goto ret;
  3172. }
  3173. cch = lstrlenA( lpszAnsi ) + 1;
  3174. ulSize = cch * sizeof( WCHAR );
  3175. if(lpMapiAllocMore && lpBase)
  3176. {
  3177. sc = lpMapiAllocMore( ulSize, lpBase, lppszWC );
  3178. if ( FAILED( sc ) )
  3179. {
  3180. DebugTrace( TEXT("ScAnsiToWC() OOM\n") );
  3181. goto ret;
  3182. }
  3183. }
  3184. if ( !MultiByteToWideChar( GetACP(), 0, lpszAnsi, -1, *lppszWC, cch ) )
  3185. {
  3186. DebugTrace( TEXT("ScAnsiToWC(), Conversion from Wide char to multibyte failed\n") );
  3187. sc = MAPI_E_CALL_FAILED;
  3188. goto ret;
  3189. }
  3190. ret:
  3191. DebugTraceSc( ScAnsiToWC, sc );
  3192. return sc;
  3193. }
  3194. /*
  3195. -
  3196. - LPCSTR ConvertWtoA(LPWSTR lpszW);
  3197. *
  3198. * LocalAllocs a ANSI version of an LPWSTR
  3199. *
  3200. * Caller is responsible for freeing
  3201. */
  3202. LPWSTR ConvertAtoW(LPCSTR lpszA)
  3203. {
  3204. int cch;
  3205. LPWSTR lpW = NULL;
  3206. ULONG ulSize;
  3207. if ( !lpszA)
  3208. goto ret;
  3209. cch = (lstrlenA( lpszA ) + 1);
  3210. ulSize = cch*sizeof(WCHAR);
  3211. if(lpW = LocalAlloc(LMEM_ZEROINIT, ulSize))
  3212. {
  3213. MultiByteToWideChar( GetACP(), 0, lpszA, -1, lpW, cch );
  3214. }
  3215. ret:
  3216. return lpW;
  3217. }
  3218. /*
  3219. -
  3220. - ScConvertAPropsToW
  3221. -
  3222. * Takes in an SPropValue array and goes in and adds W versions of all strings
  3223. * to replace the A versions
  3224. * It's assumed that all the MAPIAllocations will take place off the root of the
  3225. * SPropValue array
  3226. *
  3227. */
  3228. SCODE ScConvertAPropsToW(LPALLOCATEMORE lpMapiAllocMore, LPSPropValue lpPropValue, ULONG ulcProps, ULONG ulStart)
  3229. {
  3230. ULONG iProp = 0;
  3231. SCODE sc = 0;
  3232. LPWSTR lpszConvertedW = NULL;
  3233. // There are 2 types of props we want to convert
  3234. // PT_STRING8 and
  3235. // PT_MV_STRING8
  3236. for ( iProp = ulStart; iProp < ulcProps; iProp++ )
  3237. {
  3238. // Convert ANSI strings to UNICODE if required
  3239. if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_STRING8 )
  3240. {
  3241. //if ( !lpPropTagArray ||
  3242. // (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
  3243. {
  3244. sc = ScAnsiToWCMore( lpMapiAllocMore, lpPropValue,
  3245. lpPropValue[iProp].Value.lpszA, (LPWSTR *)&lpszConvertedW );
  3246. if ( FAILED( sc ) )
  3247. goto error;
  3248. lpPropValue[iProp].Value.lpszW = (LPWSTR)lpszConvertedW;
  3249. lpszConvertedW = NULL;
  3250. // Fix up PropTag
  3251. lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag,
  3252. PT_UNICODE );
  3253. }
  3254. }
  3255. else
  3256. if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_MV_STRING8 )
  3257. {
  3258. //if ( !lpPropTagArray ||
  3259. // (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
  3260. {
  3261. ULONG j = 0;
  3262. ULONG ulCount = lpPropValue[iProp].Value.MVszA.cValues;
  3263. LPWSTR * lppszW = NULL;
  3264. if(sc = lpMapiAllocMore(sizeof(LPWSTR)*ulCount,lpPropValue,
  3265. (LPVOID *)&lppszW))
  3266. goto error;
  3267. for(j=0;j<ulCount;j++)
  3268. {
  3269. sc = ScAnsiToWCMore(lpMapiAllocMore, lpPropValue,
  3270. lpPropValue[iProp].Value.MVszA.lppszA[j], (LPWSTR *)&lpszConvertedW );
  3271. if ( FAILED( sc ) )
  3272. goto error;
  3273. lppszW[j] = (LPWSTR)lpszConvertedW;
  3274. lpszConvertedW = NULL;
  3275. // Fix up PropTag
  3276. lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag,
  3277. PT_MV_UNICODE );
  3278. }
  3279. lpPropValue[iProp].Value.MVszW.lppszW = lppszW;
  3280. }
  3281. }
  3282. }
  3283. error:
  3284. return ResultFromScode(sc);
  3285. }
  3286. /*
  3287. -
  3288. - ScConvertWPropsToA
  3289. -
  3290. * Takes in an SPropValue array and goes in and adds A versions of all strings
  3291. * to replace the W versions
  3292. * It's assumed that all the MAPIAllocations will take place off the root of the
  3293. * SPropValue array
  3294. *
  3295. */
  3296. SCODE ScConvertWPropsToA(LPALLOCATEMORE lpMapiAllocMore, LPSPropValue lpPropValue, ULONG ulcProps, ULONG ulStart)
  3297. {
  3298. ULONG iProp = 0;
  3299. SCODE sc = 0;
  3300. LPSTR lpszConvertedA = NULL;
  3301. // There are 2 types of props we want to convert
  3302. // PT_STRING8 and
  3303. // PT_MV_STRING8
  3304. for ( iProp = ulStart; iProp < ulcProps; iProp++ )
  3305. {
  3306. // Convert ANSI strings to UNICODE if required
  3307. if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_UNICODE )
  3308. {
  3309. //if ( !lpPropTagArray ||
  3310. // (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
  3311. {
  3312. sc = ScWCToAnsiMore(lpMapiAllocMore, lpPropValue,
  3313. lpPropValue[iProp].Value.lpszW, (LPSTR *)&lpszConvertedA );
  3314. if ( FAILED( sc ) )
  3315. goto error;
  3316. lpPropValue[iProp].Value.lpszA = (LPSTR)lpszConvertedA;
  3317. lpszConvertedA = NULL;
  3318. // Fix up PropTag
  3319. lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag,
  3320. PT_STRING8 );
  3321. }
  3322. }
  3323. else
  3324. if (PROP_TYPE( lpPropValue[iProp].ulPropTag ) == PT_MV_UNICODE )
  3325. {
  3326. //if ( !lpPropTagArray ||
  3327. // (lpPropTagArray && ( PROP_TYPE( lpPropTagArray->aulPropTag[iProp] ) == PT_UNSPECIFIED ) ) )
  3328. {
  3329. ULONG j = 0;
  3330. ULONG ulCount = lpPropValue[iProp].Value.MVszW.cValues;
  3331. LPSTR * lppszA = NULL;
  3332. if(sc = lpMapiAllocMore(sizeof(LPSTR)*ulCount,lpPropValue,
  3333. (LPVOID *)&lppszA))
  3334. goto error;
  3335. for(j=0;j<ulCount;j++)
  3336. {
  3337. sc = ScWCToAnsiMore(lpMapiAllocMore, lpPropValue,
  3338. lpPropValue[iProp].Value.MVszW.lppszW[j], (LPSTR *)&lpszConvertedA );
  3339. if ( FAILED( sc ) )
  3340. goto error;
  3341. lppszA[j] = (LPSTR)lpszConvertedA;
  3342. lpszConvertedA = NULL;
  3343. // Fix up PropTag
  3344. lpPropValue[iProp].ulPropTag = CHANGE_PROP_TYPE( lpPropValue[iProp].ulPropTag,
  3345. PT_MV_STRING8 );
  3346. }
  3347. lpPropValue[iProp].Value.MVszA.lppszA = lppszA;
  3348. }
  3349. }
  3350. }
  3351. error:
  3352. return ResultFromScode(sc);
  3353. }