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.

517 lines
11 KiB

  1. /*
  2. * MAPI 1.0 property handling routines
  3. *
  4. *
  5. * MAPIUTIL.C -
  6. *
  7. * Useful routines for manipulating and comparing property values continued
  8. * The difference between this file and proputil.c is that this file doesn't require
  9. * any c-runtimes.
  10. */
  11. #include <_apipch.h>
  12. #ifndef MB_SETFOREGROUND
  13. #define MB_SETFOREGROUND 0
  14. #endif
  15. STDAPI_(BOOL)
  16. FEqualNames(LPMAPINAMEID lpName1, LPMAPINAMEID lpName2)
  17. {
  18. AssertSz(lpName1 && !IsBadReadPtr(lpName1, sizeof(MAPINAMEID)),
  19. TEXT("lpName1 fails address check"));
  20. AssertSz(lpName2 && !IsBadReadPtr(lpName2, sizeof(MAPINAMEID)),
  21. TEXT("lpName2 fails address check"));
  22. //
  23. // Same ptr case - optimization
  24. if (lpName1 == lpName2)
  25. return TRUE;
  26. if (memcmp(lpName1->lpguid, lpName2->lpguid, sizeof(GUID)))
  27. return FALSE;
  28. if (lpName1->ulKind == lpName2->ulKind)
  29. {
  30. if (lpName1->ulKind == MNID_STRING)
  31. {
  32. if (!lstrcmpW(lpName1->Kind.lpwstrName,
  33. lpName2->Kind.lpwstrName))
  34. {
  35. return TRUE;
  36. }
  37. } else
  38. {
  39. if (lpName1->Kind.lID == lpName2->Kind.lID)
  40. {
  41. return TRUE;
  42. }
  43. }
  44. }
  45. return FALSE;
  46. }
  47. /*
  48. * IsBadBoundedStringPtr
  49. *
  50. * Like IsBadStringPtr, but guarantees in addition that there is a
  51. * valid string which will fit in a buffer of cchMax characters.
  52. */
  53. BOOL WINAPI EXPORT_16
  54. IsBadBoundedStringPtr(const void FAR *lpsz, UINT cchMax)
  55. {
  56. if (IsBadStringPtr(lpsz, (UINT) -1) || ((UINT) lstrlenA(lpsz) >= cchMax))
  57. return TRUE;
  58. return FALSE;
  59. }
  60. /*
  61. * For now, internal to HrQueryAllRows.
  62. *
  63. * Merges prows with *pprowsDst, reallocating *pprowsDst if
  64. * necessary. Destroys the container portion of prows (but not the
  65. * individual rows it contains).
  66. */
  67. HRESULT // STDAPI
  68. HrMergeRowSets(LPSRowSet prows, LPSRowSet FAR *pprowsDst)
  69. {
  70. SCODE sc = S_OK;
  71. LPSRowSet prowsT;
  72. UINT crowsSrc;
  73. UINT crowsDst;
  74. Assert(!IsBadWritePtr(pprowsDst, sizeof(LPSRowSet)));
  75. Assert(prows);
  76. if (!*pprowsDst || (*pprowsDst)->cRows == 0)
  77. {
  78. // This is easy. But check this case first, because if the
  79. // table is completely empty we want to return this.
  80. FreeBufferAndNull(pprowsDst); // correct, no '&'
  81. *pprowsDst = prows;
  82. prows = NULL; // don't free it!
  83. goto ret;
  84. }
  85. if (prows->cRows == 0)
  86. {
  87. // This is easy too
  88. goto ret;
  89. }
  90. // OK, now we know there are rows in both rowsets.
  91. // We have to do a real merge.
  92. SideAssert(crowsSrc = (UINT) prows->cRows);
  93. crowsDst = (UINT) (*pprowsDst)->cRows; // handle 0
  94. if (FAILED(sc = MAPIAllocateBuffer(CbNewSRowSet(crowsSrc + crowsDst),
  95. &prowsT)))
  96. goto ret;
  97. if (crowsDst)
  98. CopyMemory(prowsT->aRow, (*pprowsDst)->aRow, crowsDst*sizeof(SRow));
  99. CopyMemory(&prowsT->aRow[crowsDst], prows->aRow, crowsSrc*sizeof(SRow));
  100. prowsT->cRows = crowsSrc + crowsDst;
  101. FreeBufferAndNull(pprowsDst); // correct, no '&'
  102. *pprowsDst = prowsT;
  103. ret:
  104. FreeBufferAndNull(&prows);
  105. DebugTraceSc(HrMergeRowSets, sc);
  106. return ResultFromScode(sc);
  107. }
  108. /*
  109. - HrQueryAllRows
  110. -
  111. * Purpose:
  112. * Retrieves all rows from an IMAPITable interface up to a set
  113. * maximum. It will optionally set the column set, sort order,
  114. * and restriction on the table before querying.
  115. *
  116. * If the table is empty, an SRowSet with zero rows is
  117. * returned (just like QueryRows).
  118. *
  119. * The seek position of the table is undefined both before and
  120. * after this call.
  121. *
  122. * If the function fails with an error other than
  123. * MAPI_E_NOT_ENOUGH_MEMORY, extended error information is
  124. * available through the table interface.
  125. *
  126. * Arguments:
  127. * ptable in the table interface to query
  128. * ptaga in if not NULL, column set for the table
  129. * pres in if not NULL, restriction to be applied
  130. * psos in if not NULL, sort order to be applied
  131. * crowsMax in if nonzero, limits the number of rows
  132. * to be returned.
  133. * pprows out all rows of the table
  134. *
  135. * Returns:
  136. * HRESULT. Extended error information normally is in the
  137. * table.
  138. *
  139. * Side effects:
  140. * Seek position of table is undefined.
  141. *
  142. * Errors:
  143. * MAPI_E_TABLE_TOO_BIG if the table contains more than
  144. * cRowsMax rows.
  145. */
  146. STDAPI
  147. HrQueryAllRows(LPMAPITABLE ptable,
  148. LPSPropTagArray ptaga, LPSRestriction pres, LPSSortOrderSet psos,
  149. LONG crowsMax, LPSRowSet FAR *pprows)
  150. {
  151. HRESULT hr;
  152. LPSRowSet prows = NULL;
  153. UINT crows = 0;
  154. LPSRowSet prowsT;
  155. UINT crowsT;
  156. #if !defined(DOS)
  157. // Why have we commented out the check for PARAMETER_VALIDATION? --gfb
  158. //#ifdef PARAMETER_VALIDATION
  159. if (FBadUnknown(ptable))
  160. {
  161. DebugTraceArg(HrQueryAllRows, TEXT("ptable fails address check"));
  162. goto badArg;
  163. }
  164. if (ptaga && FBadColumnSet(ptaga))
  165. {
  166. DebugTraceArg(HrQueryAllRows, TEXT("ptaga fails address check"));
  167. goto badArg;
  168. }
  169. if (pres && FBadRestriction(pres))
  170. {
  171. DebugTraceArg(HrQueryAllRows, TEXT("pres fails address check"));
  172. goto badArg;
  173. }
  174. if (psos && FBadSortOrderSet(psos))
  175. {
  176. DebugTraceArg(HrQueryAllRows, TEXT("psos fails address check"));
  177. goto badArg;
  178. }
  179. if (IsBadWritePtr(pprows, sizeof(LPSRowSet)))
  180. {
  181. DebugTraceArg(HrQueryAllRows, TEXT("pprows fails address check"));
  182. goto badArg;
  183. }
  184. //#endif
  185. #endif
  186. *pprows = NULL;
  187. // Set up the table, if the corresponding setup parameter
  188. // is present.
  189. if (ptaga &&
  190. HR_FAILED(hr = ptable->lpVtbl->SetColumns(ptable, ptaga, TBL_BATCH)))
  191. goto ret;
  192. if (pres &&
  193. HR_FAILED(hr = ptable->lpVtbl->Restrict(ptable, pres, TBL_BATCH)))
  194. goto ret;
  195. if (psos &&
  196. HR_FAILED(hr = ptable->lpVtbl->SortTable(ptable, psos, TBL_BATCH)))
  197. goto ret;
  198. // Set position to beginning of the table.
  199. if (HR_FAILED(hr = ptable->lpVtbl->SeekRow(ptable, BOOKMARK_BEGINNING,
  200. 0, NULL)))
  201. goto ret;
  202. if (crowsMax == 0)
  203. crowsMax = LONG_MAX;
  204. for (;;)
  205. {
  206. prowsT = NULL;
  207. // Retrieve some rows. Ask for the limit.
  208. hr = ptable->lpVtbl->QueryRows(ptable, crowsMax, 0, &prowsT);
  209. if (HR_FAILED(hr))
  210. {
  211. // Note: the failure may actually have happened during
  212. // one of the setup calls, since we set TBL_BATCH.
  213. goto ret;
  214. }
  215. Assert(prowsT->cRows <= UINT_MAX);
  216. crowsT = (UINT) prowsT->cRows;
  217. // Did we get more rows than caller can handle?
  218. if ((LONG) (crowsT + (prows ? prows->cRows : 0)) > crowsMax)
  219. {
  220. hr = ResultFromScode(MAPI_E_TABLE_TOO_BIG);
  221. FreeProws(prowsT);
  222. goto ret;
  223. }
  224. // Add the rows just retrieved into the set we're building.
  225. // Note: this handles boundary conditions including either
  226. // row set is empty.
  227. if (HR_FAILED(hr = HrMergeRowSets(prowsT, &prows)))
  228. goto ret;
  229. // NOTE: the merge destroys prowsT.
  230. // Did we hit the end of the table?
  231. // Unfortunately, we have to ask twice before we know.
  232. if (crowsT == 0)
  233. break;
  234. }
  235. *pprows = prows;
  236. ret:
  237. if (HR_FAILED(hr))
  238. FreeProws(prows);
  239. DebugTraceResult(HrGetAllRows, hr);
  240. return hr;
  241. #if !defined(DOS)
  242. badArg:
  243. #endif
  244. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  245. }
  246. #ifdef WIN16 // Imported inline function
  247. /*
  248. * IListedPropID
  249. *
  250. * Purpose
  251. * If a tag with ID == PROP_ID(ulPropTag) is listed in lptaga then
  252. * the index of tag is returned. If the tag is not in lptaga then
  253. * -1 is returned.
  254. *
  255. * Arguments
  256. * ulPropTag Property tag to locate.
  257. * lptaga Property tag array to search.
  258. *
  259. * Returns TRUE or FALSE
  260. */
  261. LONG
  262. IListedPropID( ULONG ulPropTag,
  263. LPSPropTagArray lptaga)
  264. {
  265. ULONG FAR *lpulPTag;
  266. /* No tag is contained in a NULL list of tags.
  267. */
  268. if (!lptaga)
  269. {
  270. return -1;
  271. }
  272. /* Mutate ulPropTag to just a PROP_ID.
  273. */
  274. ulPropTag = PROP_ID(ulPropTag);
  275. for ( lpulPTag = lptaga->aulPropTag + lptaga->cValues
  276. ; --lpulPTag >= lptaga->aulPropTag
  277. ; )
  278. {
  279. /* Compare PROP_ID's.
  280. */
  281. if (PROP_ID(*lpulPTag) == ulPropTag)
  282. {
  283. return (lpulPTag - lptaga->aulPropTag);
  284. }
  285. }
  286. return -1;
  287. }
  288. /*
  289. * FListedPropID
  290. *
  291. * Purpose
  292. * Determine if a tag with ID == PROP_ID(ulPropTag) is listed in lptaga.
  293. *
  294. * Arguments
  295. * ulPropTag Property tag to locate.
  296. * lptaga Property tag array to search.
  297. *
  298. * Returns TRUE or FALSE
  299. */
  300. BOOL
  301. FListedPropID( ULONG ulPropTag,
  302. LPSPropTagArray lptaga)
  303. {
  304. ULONG FAR *lpulPTag;
  305. /* No tag is contained in a NULL list of tags.
  306. */
  307. if (!lptaga)
  308. {
  309. return FALSE;
  310. }
  311. /* Mutate ulPropTag to just a PROP_ID.
  312. */
  313. ulPropTag = PROP_ID(ulPropTag);
  314. for ( lpulPTag = lptaga->aulPropTag + lptaga->cValues
  315. ; --lpulPTag >= lptaga->aulPropTag
  316. ; )
  317. {
  318. /* Compare PROP_ID's.
  319. */
  320. if (PROP_ID(*lpulPTag) == ulPropTag)
  321. {
  322. return TRUE;
  323. }
  324. }
  325. return FALSE;
  326. }
  327. /*
  328. * FListedPropTAG
  329. *
  330. * Purpose
  331. * Determine if a the given ulPropTag is listed in lptaga.
  332. *
  333. * Arguments
  334. * ulPropTag Property tag to locate.
  335. * lptaga Property tag array to search.
  336. *
  337. * Returns TRUE or FALSE
  338. */
  339. BOOL
  340. FListedPropTAG( ULONG ulPropTag,
  341. LPSPropTagArray lptaga)
  342. {
  343. ULONG FAR *lpulPTag;
  344. /* No tag is contained in a NULL list of tags.
  345. */
  346. if (!lptaga)
  347. {
  348. return FALSE;
  349. }
  350. /* Compare the entire prop tag to be sure both ID and TYPE match
  351. */
  352. for ( lpulPTag = lptaga->aulPropTag + lptaga->cValues
  353. ; --lpulPTag >= lptaga->aulPropTag
  354. ; )
  355. {
  356. /* Compare PROP_ID's.
  357. */
  358. if (PROP_ID(*lpulPTag) == ulPropTag)
  359. {
  360. return TRUE;
  361. }
  362. }
  363. return FALSE;
  364. }
  365. /*
  366. * AddProblem
  367. *
  368. * Purpose
  369. * Adds a problem to the next available entry of a pre-allocated problem
  370. * array.
  371. * The pre-allocated problem array must be big enough to have another
  372. * problem added. The caller is responsible for making sure this is
  373. * true.
  374. *
  375. * Arguments
  376. * lpProblems Pointer to pre-allocated probelem array.
  377. * ulIndex Index into prop tag/value array of the problem property.
  378. * ulPropTag Prop tag of property which had the problem.
  379. * scode Error code to list for the property.
  380. *
  381. * Returns TRUE or FALSE
  382. */
  383. VOID
  384. AddProblem( LPSPropProblemArray lpProblems,
  385. ULONG ulIndex,
  386. ULONG ulPropTag,
  387. SCODE scode)
  388. {
  389. if (lpProblems)
  390. {
  391. Assert( !IsBadWritePtr( lpProblems->aProblem + lpProblems->cProblem
  392. , sizeof(SPropProblem)));
  393. lpProblems->aProblem[lpProblems->cProblem].ulIndex = ulIndex;
  394. lpProblems->aProblem[lpProblems->cProblem].ulPropTag = ulPropTag;
  395. lpProblems->aProblem[lpProblems->cProblem].scode = scode;
  396. lpProblems->cProblem++;
  397. }
  398. }
  399. BOOL
  400. FIsExcludedIID( LPCIID lpiidToCheck, LPCIID rgiidExclude, ULONG ciidExclude)
  401. {
  402. /* Check the obvious (no exclusions).
  403. */
  404. if (!ciidExclude || !rgiidExclude)
  405. {
  406. return FALSE;
  407. }
  408. /* Check each iid in the list of exclusions.
  409. */
  410. for (; ciidExclude; rgiidExclude++, ciidExclude--)
  411. {
  412. // if (IsEqualGUID( lpiidToCheck, rgiidExclude))
  413. if (!memcmp( lpiidToCheck, rgiidExclude, sizeof(MAPIUID)))
  414. {
  415. return TRUE;
  416. }
  417. }
  418. return FALSE;
  419. }
  420. /*
  421. * Error/Warning Alert Message Boxes
  422. */
  423. int AlertIdsCtx( HWND hwnd,
  424. HINSTANCE hinst,
  425. UINT idsMsg,
  426. LPSTR szComponent,
  427. ULONG ulContext,
  428. ULONG ulLow,
  429. UINT fuStyle);
  430. int
  431. AlertIds(HWND hwnd, HINSTANCE hinst, UINT idsMsg, UINT fuStyle)
  432. {
  433. return AlertIdsCtx(hwnd, hinst, idsMsg, NULL, 0, 0, fuStyle);
  434. }
  435. int AlertSzCtx( HWND hwnd,
  436. LPSTR szMsg,
  437. LPSTR szComponent,
  438. ULONG ulContext,
  439. ULONG ulLow,
  440. UINT fuStyle);
  441. int
  442. AlertSz(HWND hwnd, LPSTR szMsg, UINT fuStyle)
  443. {
  444. return AlertSzCtx(hwnd, szMsg, NULL, 0, 0, fuStyle);
  445. }
  446. #endif // WIN16