[MAPI32] Sync with Wine Staging 2.16. CORE-13762
[reactos.git] / reactos / dll / win32 / mapi32 / prop.c
1 /*
2 * Property functions
3 *
4 * Copyright 2004 Jon Griffiths
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 #include <wine/list.h>
24
25 BOOL WINAPI FBadRglpszA(LPSTR*,ULONG);
26
27 /* Internal: Check if a property value array is invalid */
28 static inline ULONG PROP_BadArray(LPSPropValue lpProp, size_t elemSize)
29 {
30 return IsBadReadPtr(lpProp->Value.MVi.lpi, lpProp->Value.MVi.cValues * elemSize);
31 }
32
33 /*************************************************************************
34 * PropCopyMore@16 (MAPI32.76)
35 *
36 * Copy a property value.
37 *
38 * PARAMS
39 * lpDest [O] Destination for the copied value
40 * lpSrc [I] Property value to copy to lpDest
41 * lpMore [I] Linked memory allocation function (pass MAPIAllocateMore())
42 * lpOrig [I] Original allocation to which memory will be linked
43 *
44 * RETURNS
45 * Success: S_OK. lpDest contains a deep copy of lpSrc.
46 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
47 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
48 *
49 * NOTES
50 * Any elements within the property returned should not be individually
51 * freed, as they will be freed when lpOrig is.
52 */
53 SCODE WINAPI PropCopyMore(LPSPropValue lpDest, LPSPropValue lpSrc,
54 ALLOCATEMORE *lpMore, LPVOID lpOrig)
55 {
56 ULONG ulLen, i;
57 SCODE scode = S_OK;
58
59 TRACE("(%p,%p,%p,%p)\n", lpDest, lpSrc, lpMore, lpOrig);
60
61 if (!lpDest || IsBadWritePtr(lpDest, sizeof(SPropValue)) ||
62 FBadProp(lpSrc) || !lpMore)
63 return MAPI_E_INVALID_PARAMETER;
64
65 /* Shallow copy first, this is sufficient for properties without pointers */
66 *lpDest = *lpSrc;
67
68 switch (PROP_TYPE(lpSrc->ulPropTag))
69 {
70 case PT_CLSID:
71 scode = lpMore(sizeof(GUID), lpOrig, (LPVOID*)&lpDest->Value.lpguid);
72 if (SUCCEEDED(scode))
73 *lpDest->Value.lpguid = *lpSrc->Value.lpguid;
74 break;
75 case PT_STRING8:
76 ulLen = lstrlenA(lpSrc->Value.lpszA) + 1u;
77 scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.lpszA);
78 if (SUCCEEDED(scode))
79 memcpy(lpDest->Value.lpszA, lpSrc->Value.lpszA, ulLen);
80 break;
81 case PT_UNICODE:
82 ulLen = (strlenW(lpSrc->Value.lpszW) + 1u) * sizeof(WCHAR);
83 scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.lpszW);
84 if (SUCCEEDED(scode))
85 memcpy(lpDest->Value.lpszW, lpSrc->Value.lpszW, ulLen);
86 break;
87 case PT_BINARY:
88 scode = lpMore(lpSrc->Value.bin.cb, lpOrig, (LPVOID*)&lpDest->Value.bin.lpb);
89 if (SUCCEEDED(scode))
90 memcpy(lpDest->Value.bin.lpb, lpSrc->Value.bin.lpb, lpSrc->Value.bin.cb);
91 break;
92 default:
93 if (lpSrc->ulPropTag & MV_FLAG)
94 {
95 ulLen = UlPropSize(lpSrc);
96
97 if (PROP_TYPE(lpSrc->ulPropTag) == PT_MV_STRING8 ||
98 PROP_TYPE(lpSrc->ulPropTag) == PT_MV_UNICODE)
99 {
100 /* UlPropSize doesn't account for the string pointers */
101 ulLen += lpSrc->Value.MVszA.cValues * sizeof(char*);
102 }
103 else if (PROP_TYPE(lpSrc->ulPropTag) == PT_MV_BINARY)
104 {
105 /* UlPropSize doesn't account for the SBinary structs */
106 ulLen += lpSrc->Value.MVbin.cValues * sizeof(SBinary);
107 }
108
109 lpDest->Value.MVi.cValues = lpSrc->Value.MVi.cValues;
110 scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.MVi.lpi);
111 if (FAILED(scode))
112 break;
113
114 /* Note that we could allocate the memory for each value in a
115 * multi-value property separately, however if an allocation failed
116 * we would be left with a bunch of allocated memory, which (while
117 * not really leaked) is unusable until lpOrig is freed. So for
118 * strings and binary arrays we make a single allocation for all
119 * of the data. This is consistent since individual elements can't
120 * be freed anyway.
121 */
122
123 switch (PROP_TYPE(lpSrc->ulPropTag))
124 {
125 case PT_MV_STRING8:
126 {
127 char *lpNextStr = (char*)(lpDest->Value.MVszA.lppszA +
128 lpDest->Value.MVszA.cValues);
129
130 for (i = 0; i < lpSrc->Value.MVszA.cValues; i++)
131 {
132 ULONG ulStrLen = lstrlenA(lpSrc->Value.MVszA.lppszA[i]) + 1u;
133
134 lpDest->Value.MVszA.lppszA[i] = lpNextStr;
135 memcpy(lpNextStr, lpSrc->Value.MVszA.lppszA[i], ulStrLen);
136 lpNextStr += ulStrLen;
137 }
138 break;
139 }
140 case PT_MV_UNICODE:
141 {
142 WCHAR *lpNextStr = (WCHAR*)(lpDest->Value.MVszW.lppszW +
143 lpDest->Value.MVszW.cValues);
144
145 for (i = 0; i < lpSrc->Value.MVszW.cValues; i++)
146 {
147 ULONG ulStrLen = strlenW(lpSrc->Value.MVszW.lppszW[i]) + 1u;
148
149 lpDest->Value.MVszW.lppszW[i] = lpNextStr;
150 memcpy(lpNextStr, lpSrc->Value.MVszW.lppszW[i], ulStrLen * sizeof(WCHAR));
151 lpNextStr += ulStrLen;
152 }
153 break;
154 }
155 case PT_MV_BINARY:
156 {
157 LPBYTE lpNext = (LPBYTE)(lpDest->Value.MVbin.lpbin +
158 lpDest->Value.MVbin.cValues);
159
160 for (i = 0; i < lpSrc->Value.MVszW.cValues; i++)
161 {
162 lpDest->Value.MVbin.lpbin[i].cb = lpSrc->Value.MVbin.lpbin[i].cb;
163 lpDest->Value.MVbin.lpbin[i].lpb = lpNext;
164 memcpy(lpNext, lpSrc->Value.MVbin.lpbin[i].lpb, lpDest->Value.MVbin.lpbin[i].cb);
165 lpNext += lpDest->Value.MVbin.lpbin[i].cb;
166 }
167 break;
168 }
169 default:
170 /* No embedded pointers, just copy the data over */
171 memcpy(lpDest->Value.MVi.lpi, lpSrc->Value.MVi.lpi, ulLen);
172 break;
173 }
174 break;
175 }
176 }
177 return scode;
178 }
179
180 /*************************************************************************
181 * UlPropSize@4 (MAPI32.77)
182 *
183 * Determine the size of a property in bytes.
184 *
185 * PARAMS
186 * lpProp [I] Property to determine the size of
187 *
188 * RETURNS
189 * Success: The size of the value in lpProp.
190 * Failure: 0, if a multi-value (array) property is invalid or the type of lpProp
191 * is unknown.
192 *
193 * NOTES
194 * - The size returned does not include the size of the SPropValue struct
195 * or the size of the array of pointers for multi-valued properties that
196 * contain pointers (such as PT_MV_STRING8 or PT-MV_UNICODE).
197 * - MSDN incorrectly states that this function returns MAPI_E_CALL_FAILED if
198 * lpProp is invalid. In reality no checking is performed and this function
199 * will crash if passed an invalid property, or return 0 if the property
200 * type is PT_OBJECT or is unknown.
201 */
202 ULONG WINAPI UlPropSize(LPSPropValue lpProp)
203 {
204 ULONG ulRet = 1u, i;
205
206 TRACE("(%p)\n", lpProp);
207
208 switch (PROP_TYPE(lpProp->ulPropTag))
209 {
210 case PT_MV_I2: ulRet = lpProp->Value.MVi.cValues;
211 /* fall through */
212 case PT_BOOLEAN:
213 case PT_I2: ulRet *= sizeof(USHORT);
214 break;
215 case PT_MV_I4: ulRet = lpProp->Value.MVl.cValues;
216 /* fall through */
217 case PT_ERROR:
218 case PT_I4: ulRet *= sizeof(LONG);
219 break;
220 case PT_MV_I8: ulRet = lpProp->Value.MVli.cValues;
221 /* fall through */
222 case PT_I8: ulRet *= sizeof(LONG64);
223 break;
224 case PT_MV_R4: ulRet = lpProp->Value.MVflt.cValues;
225 /* fall through */
226 case PT_R4: ulRet *= sizeof(float);
227 break;
228 case PT_MV_APPTIME:
229 case PT_MV_R8: ulRet = lpProp->Value.MVdbl.cValues;
230 /* fall through */
231 case PT_APPTIME:
232 case PT_R8: ulRet *= sizeof(double);
233 break;
234 case PT_MV_CURRENCY: ulRet = lpProp->Value.MVcur.cValues;
235 /* fall through */
236 case PT_CURRENCY: ulRet *= sizeof(CY);
237 break;
238 case PT_MV_SYSTIME: ulRet = lpProp->Value.MVft.cValues;
239 /* fall through */
240 case PT_SYSTIME: ulRet *= sizeof(FILETIME);
241 break;
242 case PT_MV_CLSID: ulRet = lpProp->Value.MVguid.cValues;
243 /* fall through */
244 case PT_CLSID: ulRet *= sizeof(GUID);
245 break;
246 case PT_MV_STRING8: ulRet = 0u;
247 for (i = 0; i < lpProp->Value.MVszA.cValues; i++)
248 ulRet += (lstrlenA(lpProp->Value.MVszA.lppszA[i]) + 1u);
249 break;
250 case PT_STRING8: ulRet = lstrlenA(lpProp->Value.lpszA) + 1u;
251 break;
252 case PT_MV_UNICODE: ulRet = 0u;
253 for (i = 0; i < lpProp->Value.MVszW.cValues; i++)
254 ulRet += (strlenW(lpProp->Value.MVszW.lppszW[i]) + 1u);
255 ulRet *= sizeof(WCHAR);
256 break;
257 case PT_UNICODE: ulRet = (lstrlenW(lpProp->Value.lpszW) + 1u) * sizeof(WCHAR);
258 break;
259 case PT_MV_BINARY: ulRet = 0u;
260 for (i = 0; i < lpProp->Value.MVbin.cValues; i++)
261 ulRet += lpProp->Value.MVbin.lpbin[i].cb;
262 break;
263 case PT_BINARY: ulRet = lpProp->Value.bin.cb;
264 break;
265 case PT_OBJECT:
266 default: ulRet = 0u;
267 break;
268 }
269
270 return ulRet;
271 }
272
273 /*************************************************************************
274 * FPropContainsProp@12 (MAPI32.78)
275 *
276 * Find a property with a given property tag in a property array.
277 *
278 * PARAMS
279 * lpHaystack [I] Property to match to
280 * lpNeedle [I] Property to find in lpHaystack
281 * ulFuzzy [I] Flags controlling match type and strictness (FL_* flags from "mapidefs.h")
282 *
283 * RETURNS
284 * TRUE, if lpNeedle matches lpHaystack according to the criteria of ulFuzzy.
285 *
286 * NOTES
287 * Only property types of PT_STRING8 and PT_BINARY are handled by this function.
288 */
289 BOOL WINAPI FPropContainsProp(LPSPropValue lpHaystack, LPSPropValue lpNeedle, ULONG ulFuzzy)
290 {
291 TRACE("(%p,%p,0x%08x)\n", lpHaystack, lpNeedle, ulFuzzy);
292
293 if (FBadProp(lpHaystack) || FBadProp(lpNeedle) ||
294 PROP_TYPE(lpHaystack->ulPropTag) != PROP_TYPE(lpNeedle->ulPropTag))
295 return FALSE;
296
297 /* FIXME: Do later versions support Unicode as well? */
298
299 if (PROP_TYPE(lpHaystack->ulPropTag) == PT_STRING8)
300 {
301 DWORD dwFlags = 0, dwNeedleLen, dwHaystackLen;
302
303 if (ulFuzzy & FL_IGNORECASE)
304 dwFlags |= NORM_IGNORECASE;
305 if (ulFuzzy & FL_IGNORENONSPACE)
306 dwFlags |= NORM_IGNORENONSPACE;
307 if (ulFuzzy & FL_LOOSE)
308 dwFlags |= (NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS);
309
310 dwNeedleLen = lstrlenA(lpNeedle->Value.lpszA);
311 dwHaystackLen = lstrlenA(lpHaystack->Value.lpszA);
312
313 if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_PREFIX)
314 {
315 if (dwNeedleLen <= dwHaystackLen &&
316 CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
317 lpHaystack->Value.lpszA, dwNeedleLen,
318 lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
319 return TRUE; /* needle is a prefix of haystack */
320 }
321 else if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_SUBSTRING)
322 {
323 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD) = StrChrA;
324 LPSTR lpStr = lpHaystack->Value.lpszA;
325
326 if (dwFlags & NORM_IGNORECASE)
327 pStrChrFn = StrChrIA;
328
329 while ((lpStr = pStrChrFn(lpStr, *lpNeedle->Value.lpszA)) != NULL)
330 {
331 dwHaystackLen -= (lpStr - lpHaystack->Value.lpszA);
332 if (dwNeedleLen <= dwHaystackLen &&
333 CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
334 lpStr, dwNeedleLen,
335 lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
336 return TRUE; /* needle is a substring of haystack */
337 lpStr++;
338 }
339 }
340 else if (CompareStringA(LOCALE_USER_DEFAULT, dwFlags,
341 lpHaystack->Value.lpszA, dwHaystackLen,
342 lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL)
343 return TRUE; /* full string match */
344 }
345 else if (PROP_TYPE(lpHaystack->ulPropTag) == PT_BINARY)
346 {
347 if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_PREFIX)
348 {
349 if (lpNeedle->Value.bin.cb <= lpHaystack->Value.bin.cb &&
350 !memcmp(lpNeedle->Value.bin.lpb, lpHaystack->Value.bin.lpb,
351 lpNeedle->Value.bin.cb))
352 return TRUE; /* needle is a prefix of haystack */
353 }
354 else if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_SUBSTRING)
355 {
356 ULONG ulLen = lpHaystack->Value.bin.cb;
357 LPBYTE lpb = lpHaystack->Value.bin.lpb;
358
359 while ((lpb = memchr(lpb, *lpNeedle->Value.bin.lpb, ulLen)) != NULL)
360 {
361 ulLen = lpHaystack->Value.bin.cb - (lpb - lpHaystack->Value.bin.lpb);
362 if (lpNeedle->Value.bin.cb <= ulLen &&
363 !memcmp(lpNeedle->Value.bin.lpb, lpb, lpNeedle->Value.bin.cb))
364 return TRUE; /* needle is a substring of haystack */
365 lpb++;
366 }
367 }
368 else if (!LPropCompareProp(lpHaystack, lpNeedle))
369 return TRUE; /* needle is an exact match with haystack */
370
371 }
372 return FALSE;
373 }
374
375 /*************************************************************************
376 * FPropCompareProp@12 (MAPI32.79)
377 *
378 * Compare two properties.
379 *
380 * PARAMS
381 * lpPropLeft [I] Left hand property to compare to lpPropRight
382 * ulOp [I] Comparison operator (RELOP_* enum from "mapidefs.h")
383 * lpPropRight [I] Right hand property to compare to lpPropLeft
384 *
385 * RETURNS
386 * TRUE, if the comparison is true, FALSE otherwise.
387 */
388 BOOL WINAPI FPropCompareProp(LPSPropValue lpPropLeft, ULONG ulOp, LPSPropValue lpPropRight)
389 {
390 LONG iCmp;
391
392 TRACE("(%p,%d,%p)\n", lpPropLeft, ulOp, lpPropRight);
393
394 if (ulOp > RELOP_RE || FBadProp(lpPropLeft) || FBadProp(lpPropRight))
395 return FALSE;
396
397 if (ulOp == RELOP_RE)
398 {
399 FIXME("Comparison operator RELOP_RE not yet implemented!\n");
400 return FALSE;
401 }
402
403 iCmp = LPropCompareProp(lpPropLeft, lpPropRight);
404
405 switch (ulOp)
406 {
407 case RELOP_LT: return iCmp < 0;
408 case RELOP_LE: return iCmp <= 0;
409 case RELOP_GT: return iCmp > 0;
410 case RELOP_GE: return iCmp >= 0;
411 case RELOP_EQ: return iCmp == 0;
412 case RELOP_NE: return iCmp != 0;
413 }
414 return FALSE;
415 }
416
417 /*************************************************************************
418 * LPropCompareProp@8 (MAPI32.80)
419 *
420 * Compare two properties.
421 *
422 * PARAMS
423 * lpPropLeft [I] Left hand property to compare to lpPropRight
424 * lpPropRight [I] Right hand property to compare to lpPropLeft
425 *
426 * RETURNS
427 * An integer less than, equal to or greater than 0, indicating that
428 * lpszStr is less than, the same, or greater than lpszComp.
429 */
430 LONG WINAPI LPropCompareProp(LPSPropValue lpPropLeft, LPSPropValue lpPropRight)
431 {
432 LONG iRet;
433
434 TRACE("(%p->0x%08x,%p->0x%08x)\n", lpPropLeft, lpPropLeft->ulPropTag,
435 lpPropRight, lpPropRight->ulPropTag);
436
437 /* If the properties are not the same, sort by property type */
438 if (PROP_TYPE(lpPropLeft->ulPropTag) != PROP_TYPE(lpPropRight->ulPropTag))
439 return (LONG)PROP_TYPE(lpPropLeft->ulPropTag) - (LONG)PROP_TYPE(lpPropRight->ulPropTag);
440
441 switch (PROP_TYPE(lpPropLeft->ulPropTag))
442 {
443 case PT_UNSPECIFIED:
444 case PT_NULL:
445 return 0; /* NULLs are equal */
446 case PT_I2:
447 return lpPropLeft->Value.i - lpPropRight->Value.i;
448 case PT_I4:
449 return lpPropLeft->Value.l - lpPropRight->Value.l;
450 case PT_I8:
451 if (lpPropLeft->Value.li.QuadPart > lpPropRight->Value.li.QuadPart)
452 return 1;
453 if (lpPropLeft->Value.li.QuadPart == lpPropRight->Value.li.QuadPart)
454 return 0;
455 return -1;
456 case PT_R4:
457 if (lpPropLeft->Value.flt > lpPropRight->Value.flt)
458 return 1;
459 if (lpPropLeft->Value.flt == lpPropRight->Value.flt)
460 return 0;
461 return -1;
462 case PT_APPTIME:
463 case PT_R8:
464 if (lpPropLeft->Value.dbl > lpPropRight->Value.dbl)
465 return 1;
466 if (lpPropLeft->Value.dbl == lpPropRight->Value.dbl)
467 return 0;
468 return -1;
469 case PT_CURRENCY:
470 if (lpPropLeft->Value.cur.int64 > lpPropRight->Value.cur.int64)
471 return 1;
472 if (lpPropLeft->Value.cur.int64 == lpPropRight->Value.cur.int64)
473 return 0;
474 return -1;
475 case PT_SYSTIME:
476 return CompareFileTime(&lpPropLeft->Value.ft, &lpPropRight->Value.ft);
477 case PT_BOOLEAN:
478 return (lpPropLeft->Value.b ? 1 : 0) - (lpPropRight->Value.b ? 1 : 0);
479 case PT_BINARY:
480 if (lpPropLeft->Value.bin.cb == lpPropRight->Value.bin.cb)
481 iRet = memcmp(lpPropLeft->Value.bin.lpb, lpPropRight->Value.bin.lpb,
482 lpPropLeft->Value.bin.cb);
483 else
484 {
485 iRet = memcmp(lpPropLeft->Value.bin.lpb, lpPropRight->Value.bin.lpb,
486 min(lpPropLeft->Value.bin.cb, lpPropRight->Value.bin.cb));
487
488 if (!iRet)
489 iRet = lpPropLeft->Value.bin.cb - lpPropRight->Value.bin.cb;
490 }
491 return iRet;
492 case PT_STRING8:
493 return lstrcmpA(lpPropLeft->Value.lpszA, lpPropRight->Value.lpszA);
494 case PT_UNICODE:
495 return strcmpW(lpPropLeft->Value.lpszW, lpPropRight->Value.lpszW);
496 case PT_ERROR:
497 if (lpPropLeft->Value.err > lpPropRight->Value.err)
498 return 1;
499 if (lpPropLeft->Value.err == lpPropRight->Value.err)
500 return 0;
501 return -1;
502 case PT_CLSID:
503 return memcmp(lpPropLeft->Value.lpguid, lpPropRight->Value.lpguid,
504 sizeof(GUID));
505 }
506 FIXME("Unhandled property type %d\n", PROP_TYPE(lpPropLeft->ulPropTag));
507 return 0;
508 }
509
510 /*************************************************************************
511 * HrGetOneProp@8 (MAPI32.135)
512 *
513 * Get a property value from an IMAPIProp object.
514 *
515 * PARAMS
516 * lpIProp [I] IMAPIProp object to get the property value in
517 * ulPropTag [I] Property tag of the property to get
518 * lppProp [O] Destination for the returned property
519 *
520 * RETURNS
521 * Success: S_OK. *lppProp contains the property value requested.
522 * Failure: MAPI_E_NOT_FOUND, if no property value has the tag given by ulPropTag.
523 */
524 HRESULT WINAPI HrGetOneProp(LPMAPIPROP lpIProp, ULONG ulPropTag, LPSPropValue *lppProp)
525 {
526 SPropTagArray pta;
527 ULONG ulCount;
528 HRESULT hRet;
529
530 TRACE("(%p,%d,%p)\n", lpIProp, ulPropTag, lppProp);
531
532 pta.cValues = 1u;
533 pta.aulPropTag[0] = ulPropTag;
534 hRet = IMAPIProp_GetProps(lpIProp, &pta, 0u, &ulCount, lppProp);
535 if (hRet == MAPI_W_ERRORS_RETURNED)
536 {
537 MAPIFreeBuffer(*lppProp);
538 *lppProp = NULL;
539 hRet = MAPI_E_NOT_FOUND;
540 }
541 return hRet;
542 }
543
544 /*************************************************************************
545 * HrSetOneProp@8 (MAPI32.136)
546 *
547 * Set a property value in an IMAPIProp object.
548 *
549 * PARAMS
550 * lpIProp [I] IMAPIProp object to set the property value in
551 * lpProp [I] Property value to set
552 *
553 * RETURNS
554 * Success: S_OK. The value in lpProp is set in lpIProp.
555 * Failure: An error result from IMAPIProp_SetProps().
556 */
557 HRESULT WINAPI HrSetOneProp(LPMAPIPROP lpIProp, LPSPropValue lpProp)
558 {
559 TRACE("(%p,%p)\n", lpIProp, lpProp);
560
561 return IMAPIProp_SetProps(lpIProp, 1u, lpProp, NULL);
562 }
563
564 /*************************************************************************
565 * FPropExists@8 (MAPI32.137)
566 *
567 * Find a property with a given property tag in an IMAPIProp object.
568 *
569 * PARAMS
570 * lpIProp [I] IMAPIProp object to find the property tag in
571 * ulPropTag [I] Property tag to find
572 *
573 * RETURNS
574 * TRUE, if ulPropTag matches a property held in lpIProp,
575 * FALSE, otherwise.
576 *
577 * NOTES
578 * if ulPropTag has a property type of PT_UNSPECIFIED, then only the property
579 * Ids need to match for a successful match to occur.
580 */
581 BOOL WINAPI FPropExists(LPMAPIPROP lpIProp, ULONG ulPropTag)
582 {
583 BOOL bRet = FALSE;
584
585 TRACE("(%p,%d)\n", lpIProp, ulPropTag);
586
587 if (lpIProp)
588 {
589 LPSPropTagArray lpTags;
590 ULONG i;
591
592 if (FAILED(IMAPIProp_GetPropList(lpIProp, 0u, &lpTags)))
593 return FALSE;
594
595 for (i = 0; i < lpTags->cValues; i++)
596 {
597 if (!FBadPropTag(lpTags->aulPropTag[i]) &&
598 (lpTags->aulPropTag[i] == ulPropTag ||
599 (PROP_TYPE(ulPropTag) == PT_UNSPECIFIED &&
600 PROP_ID(lpTags->aulPropTag[i]) == lpTags->aulPropTag[i])))
601 {
602 bRet = TRUE;
603 break;
604 }
605 }
606 MAPIFreeBuffer(lpTags);
607 }
608 return bRet;
609 }
610
611 /*************************************************************************
612 * PpropFindProp@12 (MAPI32.138)
613 *
614 * Find a property with a given property tag in a property array.
615 *
616 * PARAMS
617 * lpProps [I] Property array to search
618 * cValues [I] Number of properties in lpProps
619 * ulPropTag [I] Property tag to find
620 *
621 * RETURNS
622 * A pointer to the matching property, or NULL if none was found.
623 *
624 * NOTES
625 * if ulPropTag has a property type of PT_UNSPECIFIED, then only the property
626 * Ids need to match for a successful match to occur.
627 */
628 LPSPropValue WINAPI PpropFindProp(LPSPropValue lpProps, ULONG cValues, ULONG ulPropTag)
629 {
630 TRACE("(%p,%d,%d)\n", lpProps, cValues, ulPropTag);
631
632 if (lpProps && cValues)
633 {
634 ULONG i;
635 for (i = 0; i < cValues; i++)
636 {
637 if (!FBadPropTag(lpProps[i].ulPropTag) &&
638 (lpProps[i].ulPropTag == ulPropTag ||
639 (PROP_TYPE(ulPropTag) == PT_UNSPECIFIED &&
640 PROP_ID(lpProps[i].ulPropTag) == PROP_ID(ulPropTag))))
641 return &lpProps[i];
642 }
643 }
644 return NULL;
645 }
646
647 /*************************************************************************
648 * FreePadrlist@4 (MAPI32.139)
649 *
650 * Free the memory used by an address book list.
651 *
652 * PARAMS
653 * lpAddrs [I] Address book list to free
654 *
655 * RETURNS
656 * Nothing.
657 */
658 VOID WINAPI FreePadrlist(LPADRLIST lpAddrs)
659 {
660 TRACE("(%p)\n", lpAddrs);
661
662 /* Structures are binary compatible; use the same implementation */
663 FreeProws((LPSRowSet)lpAddrs);
664 }
665
666 /*************************************************************************
667 * FreeProws@4 (MAPI32.140)
668 *
669 * Free the memory used by a row set.
670 *
671 * PARAMS
672 * lpRowSet [I] Row set to free
673 *
674 * RETURNS
675 * Nothing.
676 */
677 VOID WINAPI FreeProws(LPSRowSet lpRowSet)
678 {
679 TRACE("(%p)\n", lpRowSet);
680
681 if (lpRowSet)
682 {
683 ULONG i;
684
685 for (i = 0; i < lpRowSet->cRows; i++)
686 MAPIFreeBuffer(lpRowSet->aRow[i].lpProps);
687
688 MAPIFreeBuffer(lpRowSet);
689 }
690 }
691
692 /*************************************************************************
693 * ScCountProps@12 (MAPI32.170)
694 *
695 * Validate and determine the length of an array of properties.
696 *
697 * PARAMS
698 * iCount [I] Length of the lpProps array
699 * lpProps [I] Array of properties to validate/size
700 * pcBytes [O] If non-NULL, destination for the size of the property array
701 *
702 * RETURNS
703 * Success: S_OK. If pcBytes is non-NULL, it contains the size of the
704 * properties array.
705 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid or validation
706 * of the property array fails.
707 */
708 SCODE WINAPI ScCountProps(INT iCount, LPSPropValue lpProps, ULONG *pcBytes)
709 {
710 ULONG i, ulCount = iCount, ulBytes = 0;
711
712 TRACE("(%d,%p,%p)\n", iCount, lpProps, pcBytes);
713
714 if (iCount <= 0 || !lpProps ||
715 IsBadReadPtr(lpProps, iCount * sizeof(SPropValue)))
716 return MAPI_E_INVALID_PARAMETER;
717
718 for (i = 0; i < ulCount; i++)
719 {
720 ULONG ulPropSize = 0;
721
722 if (FBadProp(&lpProps[i]) || lpProps[i].ulPropTag == PROP_ID_NULL ||
723 lpProps[i].ulPropTag == PROP_ID_INVALID)
724 return MAPI_E_INVALID_PARAMETER;
725
726 if (PROP_TYPE(lpProps[i].ulPropTag) != PT_OBJECT)
727 {
728 ulPropSize = UlPropSize(&lpProps[i]);
729 if (!ulPropSize)
730 return MAPI_E_INVALID_PARAMETER;
731 }
732
733 switch (PROP_TYPE(lpProps[i].ulPropTag))
734 {
735 case PT_STRING8:
736 case PT_UNICODE:
737 case PT_CLSID:
738 case PT_BINARY:
739 case PT_MV_I2:
740 case PT_MV_I4:
741 case PT_MV_I8:
742 case PT_MV_R4:
743 case PT_MV_R8:
744 case PT_MV_CURRENCY:
745 case PT_MV_SYSTIME:
746 case PT_MV_APPTIME:
747 ulPropSize += sizeof(SPropValue);
748 break;
749 case PT_MV_CLSID:
750 ulPropSize += lpProps[i].Value.MVszA.cValues * sizeof(char*) + sizeof(SPropValue);
751 break;
752 case PT_MV_STRING8:
753 case PT_MV_UNICODE:
754 ulPropSize += lpProps[i].Value.MVszA.cValues * sizeof(char*) + sizeof(SPropValue);
755 break;
756 case PT_MV_BINARY:
757 ulPropSize += lpProps[i].Value.MVbin.cValues * sizeof(SBinary) + sizeof(SPropValue);
758 break;
759 default:
760 ulPropSize = sizeof(SPropValue);
761 break;
762 }
763 ulBytes += ulPropSize;
764 }
765 if (pcBytes)
766 *pcBytes = ulBytes;
767
768 return S_OK;
769 }
770
771 /*************************************************************************
772 * ScCopyProps@16 (MAPI32.171)
773 *
774 * Copy an array of property values into a buffer suited for serialisation.
775 *
776 * PARAMS
777 * cValues [I] Number of properties in lpProps
778 * lpProps [I] Property array to copy
779 * lpDst [O] Destination for the serialised data
780 * lpCount [O] If non-NULL, destination for the number of bytes of data written to lpDst
781 *
782 * RETURNS
783 * Success: S_OK. lpDst contains the serialised data from lpProps.
784 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
785 *
786 * NOTES
787 * The resulting property value array is stored in a contiguous block starting at lpDst.
788 */
789 SCODE WINAPI ScCopyProps(int cValues, LPSPropValue lpProps, LPVOID lpDst, ULONG *lpCount)
790 {
791 LPSPropValue lpDest = (LPSPropValue)lpDst;
792 char *lpDataDest = (char *)(lpDest + cValues);
793 ULONG ulLen, i;
794 int iter;
795
796 TRACE("(%d,%p,%p,%p)\n", cValues, lpProps, lpDst, lpCount);
797
798 if (!lpProps || cValues < 0 || !lpDest)
799 return MAPI_E_INVALID_PARAMETER;
800
801 memcpy(lpDst, lpProps, cValues * sizeof(SPropValue));
802
803 for (iter = 0; iter < cValues; iter++)
804 {
805 switch (PROP_TYPE(lpProps->ulPropTag))
806 {
807 case PT_CLSID:
808 lpDest->Value.lpguid = (LPGUID)lpDataDest;
809 *lpDest->Value.lpguid = *lpProps->Value.lpguid;
810 lpDataDest += sizeof(GUID);
811 break;
812 case PT_STRING8:
813 ulLen = lstrlenA(lpProps->Value.lpszA) + 1u;
814 lpDest->Value.lpszA = lpDataDest;
815 memcpy(lpDest->Value.lpszA, lpProps->Value.lpszA, ulLen);
816 lpDataDest += ulLen;
817 break;
818 case PT_UNICODE:
819 ulLen = (strlenW(lpProps->Value.lpszW) + 1u) * sizeof(WCHAR);
820 lpDest->Value.lpszW = (LPWSTR)lpDataDest;
821 memcpy(lpDest->Value.lpszW, lpProps->Value.lpszW, ulLen);
822 lpDataDest += ulLen;
823 break;
824 case PT_BINARY:
825 lpDest->Value.bin.lpb = (LPBYTE)lpDataDest;
826 memcpy(lpDest->Value.bin.lpb, lpProps->Value.bin.lpb, lpProps->Value.bin.cb);
827 lpDataDest += lpProps->Value.bin.cb;
828 break;
829 default:
830 if (lpProps->ulPropTag & MV_FLAG)
831 {
832 lpDest->Value.MVi.cValues = lpProps->Value.MVi.cValues;
833 /* Note: Assignment uses lppszA but covers all cases by union aliasing */
834 lpDest->Value.MVszA.lppszA = (char**)lpDataDest;
835
836 switch (PROP_TYPE(lpProps->ulPropTag))
837 {
838 case PT_MV_STRING8:
839 {
840 lpDataDest += lpProps->Value.MVszA.cValues * sizeof(char *);
841
842 for (i = 0; i < lpProps->Value.MVszA.cValues; i++)
843 {
844 ULONG ulStrLen = lstrlenA(lpProps->Value.MVszA.lppszA[i]) + 1u;
845
846 lpDest->Value.MVszA.lppszA[i] = lpDataDest;
847 memcpy(lpDataDest, lpProps->Value.MVszA.lppszA[i], ulStrLen);
848 lpDataDest += ulStrLen;
849 }
850 break;
851 }
852 case PT_MV_UNICODE:
853 {
854 lpDataDest += lpProps->Value.MVszW.cValues * sizeof(WCHAR *);
855
856 for (i = 0; i < lpProps->Value.MVszW.cValues; i++)
857 {
858 ULONG ulStrLen = (strlenW(lpProps->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
859
860 lpDest->Value.MVszW.lppszW[i] = (LPWSTR)lpDataDest;
861 memcpy(lpDataDest, lpProps->Value.MVszW.lppszW[i], ulStrLen);
862 lpDataDest += ulStrLen;
863 }
864 break;
865 }
866 case PT_MV_BINARY:
867 {
868 lpDataDest += lpProps->Value.MVszW.cValues * sizeof(SBinary);
869
870 for (i = 0; i < lpProps->Value.MVszW.cValues; i++)
871 {
872 lpDest->Value.MVbin.lpbin[i].cb = lpProps->Value.MVbin.lpbin[i].cb;
873 lpDest->Value.MVbin.lpbin[i].lpb = (LPBYTE)lpDataDest;
874 memcpy(lpDataDest, lpProps->Value.MVbin.lpbin[i].lpb, lpDest->Value.MVbin.lpbin[i].cb);
875 lpDataDest += lpDest->Value.MVbin.lpbin[i].cb;
876 }
877 break;
878 }
879 default:
880 /* No embedded pointers, just copy the data over */
881 ulLen = UlPropSize(lpProps);
882 memcpy(lpDest->Value.MVi.lpi, lpProps->Value.MVi.lpi, ulLen);
883 lpDataDest += ulLen;
884 break;
885 }
886 break;
887 }
888 }
889 lpDest++;
890 lpProps++;
891 }
892 if (lpCount)
893 *lpCount = lpDataDest - (char *)lpDst;
894
895 return S_OK;
896 }
897
898 /*************************************************************************
899 * ScRelocProps@20 (MAPI32.172)
900 *
901 * Relocate the pointers in an array of property values after it has been copied.
902 *
903 * PARAMS
904 * cValues [I] Number of properties in lpProps
905 * lpProps [O] Property array to relocate the pointers in.
906 * lpOld [I] Position where the data was copied from
907 * lpNew [I] Position where the data was copied to
908 * lpCount [O] If non-NULL, destination for the number of bytes of data at lpDst
909 *
910 * RETURNS
911 * Success: S_OK. Any pointers in lpProps are relocated.
912 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
913 *
914 * NOTES
915 * MSDN states that this function can be used for serialisation by passing
916 * NULL as either lpOld or lpNew, thus converting any pointers in lpProps
917 * between offsets and pointers. This does not work in native (it crashes),
918 * and cannot be made to work in Wine because the original interface design
919 * is deficient. The only use left for this function is to remap pointers
920 * in a contiguous property array that has been copied with memcpy() to
921 * another memory location.
922 */
923 SCODE WINAPI ScRelocProps(int cValues, LPSPropValue lpProps, LPVOID lpOld,
924 LPVOID lpNew, ULONG *lpCount)
925 {
926 static const BOOL bBadPtr = TRUE; /* Windows bug - Assumes source is bad */
927 LPSPropValue lpDest = lpProps;
928 ULONG ulCount = cValues * sizeof(SPropValue);
929 ULONG ulLen, i;
930 int iter;
931
932 TRACE("(%d,%p,%p,%p,%p)\n", cValues, lpProps, lpOld, lpNew, lpCount);
933
934 if (!lpProps || cValues < 0 || !lpOld || !lpNew)
935 return MAPI_E_INVALID_PARAMETER;
936
937 /* The reason native doesn't work as MSDN states is that it assumes that
938 * the lpProps pointer contains valid pointers. This is obviously not
939 * true if the array is being read back from serialisation (the pointers
940 * are just offsets). Native can't actually work converting the pointers to
941 * offsets either, because it converts any array pointers to offsets then
942 * _dereferences the offset_ in order to convert the array elements!
943 *
944 * The code below would handle both cases except that the design of this
945 * function makes it impossible to know when the pointers in lpProps are
946 * valid. If both lpOld and lpNew are non-NULL, native reads the pointers
947 * after converting them, so we must do the same. It seems this
948 * functionality was never tested by MS.
949 */
950
951 #define RELOC_PTR(p) (((char*)(p)) - (char*)lpOld + (char*)lpNew)
952
953 for (iter = 0; iter < cValues; iter++)
954 {
955 switch (PROP_TYPE(lpDest->ulPropTag))
956 {
957 case PT_CLSID:
958 lpDest->Value.lpguid = (LPGUID)RELOC_PTR(lpDest->Value.lpguid);
959 ulCount += sizeof(GUID);
960 break;
961 case PT_STRING8:
962 ulLen = bBadPtr ? 0 : lstrlenA(lpDest->Value.lpszA) + 1u;
963 lpDest->Value.lpszA = RELOC_PTR(lpDest->Value.lpszA);
964 if (bBadPtr)
965 ulLen = lstrlenA(lpDest->Value.lpszA) + 1u;
966 ulCount += ulLen;
967 break;
968 case PT_UNICODE:
969 ulLen = bBadPtr ? 0 : (lstrlenW(lpDest->Value.lpszW) + 1u) * sizeof(WCHAR);
970 lpDest->Value.lpszW = (LPWSTR)RELOC_PTR(lpDest->Value.lpszW);
971 if (bBadPtr)
972 ulLen = (strlenW(lpDest->Value.lpszW) + 1u) * sizeof(WCHAR);
973 ulCount += ulLen;
974 break;
975 case PT_BINARY:
976 lpDest->Value.bin.lpb = (LPBYTE)RELOC_PTR(lpDest->Value.bin.lpb);
977 ulCount += lpDest->Value.bin.cb;
978 break;
979 default:
980 if (lpDest->ulPropTag & MV_FLAG)
981 {
982 /* Since we have to access the array elements, don't map the
983 * array unless it is invalid (otherwise, map it at the end)
984 */
985 if (bBadPtr)
986 lpDest->Value.MVszA.lppszA = (LPSTR*)RELOC_PTR(lpDest->Value.MVszA.lppszA);
987
988 switch (PROP_TYPE(lpProps->ulPropTag))
989 {
990 case PT_MV_STRING8:
991 {
992 ulCount += lpDest->Value.MVszA.cValues * sizeof(char *);
993
994 for (i = 0; i < lpDest->Value.MVszA.cValues; i++)
995 {
996 ULONG ulStrLen = bBadPtr ? 0 : lstrlenA(lpDest->Value.MVszA.lppszA[i]) + 1u;
997
998 lpDest->Value.MVszA.lppszA[i] = RELOC_PTR(lpDest->Value.MVszA.lppszA[i]);
999 if (bBadPtr)
1000 ulStrLen = lstrlenA(lpDest->Value.MVszA.lppszA[i]) + 1u;
1001 ulCount += ulStrLen;
1002 }
1003 break;
1004 }
1005 case PT_MV_UNICODE:
1006 {
1007 ulCount += lpDest->Value.MVszW.cValues * sizeof(WCHAR *);
1008
1009 for (i = 0; i < lpDest->Value.MVszW.cValues; i++)
1010 {
1011 ULONG ulStrLen = bBadPtr ? 0 : (strlenW(lpDest->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
1012
1013 lpDest->Value.MVszW.lppszW[i] = (LPWSTR)RELOC_PTR(lpDest->Value.MVszW.lppszW[i]);
1014 if (bBadPtr)
1015 ulStrLen = (strlenW(lpDest->Value.MVszW.lppszW[i]) + 1u) * sizeof(WCHAR);
1016 ulCount += ulStrLen;
1017 }
1018 break;
1019 }
1020 case PT_MV_BINARY:
1021 {
1022 ulCount += lpDest->Value.MVszW.cValues * sizeof(SBinary);
1023
1024 for (i = 0; i < lpDest->Value.MVszW.cValues; i++)
1025 {
1026 lpDest->Value.MVbin.lpbin[i].lpb = (LPBYTE)RELOC_PTR(lpDest->Value.MVbin.lpbin[i].lpb);
1027 ulCount += lpDest->Value.MVbin.lpbin[i].cb;
1028 }
1029 break;
1030 }
1031 default:
1032 ulCount += UlPropSize(lpDest);
1033 break;
1034 }
1035 if (!bBadPtr)
1036 lpDest->Value.MVszA.lppszA = (LPSTR*)RELOC_PTR(lpDest->Value.MVszA.lppszA);
1037 break;
1038 }
1039 }
1040 lpDest++;
1041 }
1042 if (lpCount)
1043 *lpCount = ulCount;
1044
1045 return S_OK;
1046 }
1047
1048 /*************************************************************************
1049 * LpValFindProp@12 (MAPI32.173)
1050 *
1051 * Find a property with a given property id in a property array.
1052 *
1053 * PARAMS
1054 * ulPropTag [I] Property tag containing property id to find
1055 * cValues [I] Number of properties in lpProps
1056 * lpProps [I] Property array to search
1057 *
1058 * RETURNS
1059 * A pointer to the matching property, or NULL if none was found.
1060 *
1061 * NOTES
1062 * This function matches only on the property id and does not care if the
1063 * property types differ.
1064 */
1065 LPSPropValue WINAPI LpValFindProp(ULONG ulPropTag, ULONG cValues, LPSPropValue lpProps)
1066 {
1067 TRACE("(%d,%d,%p)\n", ulPropTag, cValues, lpProps);
1068
1069 if (lpProps && cValues)
1070 {
1071 ULONG i;
1072 for (i = 0; i < cValues; i++)
1073 {
1074 if (PROP_ID(ulPropTag) == PROP_ID(lpProps[i].ulPropTag))
1075 return &lpProps[i];
1076 }
1077 }
1078 return NULL;
1079 }
1080
1081 /*************************************************************************
1082 * ScDupPropset@16 (MAPI32.174)
1083 *
1084 * Duplicate a property value array into a contiguous block of memory.
1085 *
1086 * PARAMS
1087 * cValues [I] Number of properties in lpProps
1088 * lpProps [I] Property array to duplicate
1089 * lpAlloc [I] Memory allocation function, use MAPIAllocateBuffer()
1090 * lpNewProp [O] Destination for the newly duplicated property value array
1091 *
1092 * RETURNS
1093 * Success: S_OK. *lpNewProp contains the duplicated array.
1094 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
1095 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
1096 */
1097 SCODE WINAPI ScDupPropset(int cValues, LPSPropValue lpProps,
1098 LPALLOCATEBUFFER lpAlloc, LPSPropValue *lpNewProp)
1099 {
1100 ULONG ulCount;
1101 SCODE sc;
1102
1103 TRACE("(%d,%p,%p,%p)\n", cValues, lpProps, lpAlloc, lpNewProp);
1104
1105 sc = ScCountProps(cValues, lpProps, &ulCount);
1106 if (SUCCEEDED(sc))
1107 {
1108 sc = lpAlloc(ulCount, (LPVOID*)lpNewProp);
1109 if (SUCCEEDED(sc))
1110 sc = ScCopyProps(cValues, lpProps, *lpNewProp, &ulCount);
1111 }
1112 return sc;
1113 }
1114
1115 /*************************************************************************
1116 * FBadRglpszA@8 (MAPI32.175)
1117 *
1118 * Determine if an array of strings is invalid
1119 *
1120 * PARAMS
1121 * lppszStrs [I] Array of strings to check
1122 * ulCount [I] Number of strings in lppszStrs
1123 *
1124 * RETURNS
1125 * TRUE, if lppszStrs is invalid, FALSE otherwise.
1126 */
1127 BOOL WINAPI FBadRglpszA(LPSTR *lppszStrs, ULONG ulCount)
1128 {
1129 ULONG i;
1130
1131 TRACE("(%p,%d)\n", lppszStrs, ulCount);
1132
1133 if (!ulCount)
1134 return FALSE;
1135
1136 if (!lppszStrs || IsBadReadPtr(lppszStrs, ulCount * sizeof(LPWSTR)))
1137 return TRUE;
1138
1139 for (i = 0; i < ulCount; i++)
1140 {
1141 if (!lppszStrs[i] || IsBadStringPtrA(lppszStrs[i], -1))
1142 return TRUE;
1143 }
1144 return FALSE;
1145 }
1146
1147 /*************************************************************************
1148 * FBadRglpszW@8 (MAPI32.176)
1149 *
1150 * See FBadRglpszA.
1151 */
1152 BOOL WINAPI FBadRglpszW(LPWSTR *lppszStrs, ULONG ulCount)
1153 {
1154 ULONG i;
1155
1156 TRACE("(%p,%d)\n", lppszStrs, ulCount);
1157
1158 if (!ulCount)
1159 return FALSE;
1160
1161 if (!lppszStrs || IsBadReadPtr(lppszStrs, ulCount * sizeof(LPWSTR)))
1162 return TRUE;
1163
1164 for (i = 0; i < ulCount; i++)
1165 {
1166 if (!lppszStrs[i] || IsBadStringPtrW(lppszStrs[i], -1))
1167 return TRUE;
1168 }
1169 return FALSE;
1170 }
1171
1172 /*************************************************************************
1173 * FBadRowSet@4 (MAPI32.177)
1174 *
1175 * Determine if a row is invalid
1176 *
1177 * PARAMS
1178 * lpRow [I] Row to check
1179 *
1180 * RETURNS
1181 * TRUE, if lpRow is invalid, FALSE otherwise.
1182 */
1183 BOOL WINAPI FBadRowSet(LPSRowSet lpRowSet)
1184 {
1185 ULONG i;
1186 TRACE("(%p)\n", lpRowSet);
1187
1188 if (!lpRowSet || IsBadReadPtr(lpRowSet, CbSRowSet(lpRowSet)))
1189 return TRUE;
1190
1191 for (i = 0; i < lpRowSet->cRows; i++)
1192 {
1193 if (FBadRow(&lpRowSet->aRow[i]))
1194 return TRUE;
1195 }
1196 return FALSE;
1197 }
1198
1199 /*************************************************************************
1200 * FBadPropTag@4 (MAPI32.179)
1201 *
1202 * Determine if a property tag is invalid
1203 *
1204 * PARAMS
1205 * ulPropTag [I] Property tag to check
1206 *
1207 * RETURNS
1208 * TRUE, if ulPropTag is invalid, FALSE otherwise.
1209 */
1210 ULONG WINAPI FBadPropTag(ULONG ulPropTag)
1211 {
1212 TRACE("(0x%08x)\n", ulPropTag);
1213
1214 switch (ulPropTag & (~MV_FLAG & PROP_TYPE_MASK))
1215 {
1216 case PT_UNSPECIFIED:
1217 case PT_NULL:
1218 case PT_I2:
1219 case PT_LONG:
1220 case PT_R4:
1221 case PT_DOUBLE:
1222 case PT_CURRENCY:
1223 case PT_APPTIME:
1224 case PT_ERROR:
1225 case PT_BOOLEAN:
1226 case PT_OBJECT:
1227 case PT_I8:
1228 case PT_STRING8:
1229 case PT_UNICODE:
1230 case PT_SYSTIME:
1231 case PT_CLSID:
1232 case PT_BINARY:
1233 return FALSE;
1234 }
1235 return TRUE;
1236 }
1237
1238 /*************************************************************************
1239 * FBadRow@4 (MAPI32.180)
1240 *
1241 * Determine if a row is invalid
1242 *
1243 * PARAMS
1244 * lpRow [I] Row to check
1245 *
1246 * RETURNS
1247 * TRUE, if lpRow is invalid, FALSE otherwise.
1248 */
1249 ULONG WINAPI FBadRow(LPSRow lpRow)
1250 {
1251 ULONG i;
1252 TRACE("(%p)\n", lpRow);
1253
1254 if (!lpRow || IsBadReadPtr(lpRow, sizeof(SRow)) || !lpRow->lpProps ||
1255 IsBadReadPtr(lpRow->lpProps, lpRow->cValues * sizeof(SPropValue)))
1256 return TRUE;
1257
1258 for (i = 0; i < lpRow->cValues; i++)
1259 {
1260 if (FBadProp(&lpRow->lpProps[i]))
1261 return TRUE;
1262 }
1263 return FALSE;
1264 }
1265
1266 /*************************************************************************
1267 * FBadProp@4 (MAPI32.181)
1268 *
1269 * Determine if a property is invalid
1270 *
1271 * PARAMS
1272 * lpProp [I] Property to check
1273 *
1274 * RETURNS
1275 * TRUE, if lpProp is invalid, FALSE otherwise.
1276 */
1277 ULONG WINAPI FBadProp(LPSPropValue lpProp)
1278 {
1279 if (!lpProp || IsBadReadPtr(lpProp, sizeof(SPropValue)) ||
1280 FBadPropTag(lpProp->ulPropTag))
1281 return TRUE;
1282
1283 switch (PROP_TYPE(lpProp->ulPropTag))
1284 {
1285 /* Single value properties containing pointers */
1286 case PT_STRING8:
1287 if (!lpProp->Value.lpszA || IsBadStringPtrA(lpProp->Value.lpszA, -1))
1288 return TRUE;
1289 break;
1290 case PT_UNICODE:
1291 if (!lpProp->Value.lpszW || IsBadStringPtrW(lpProp->Value.lpszW, -1))
1292 return TRUE;
1293 break;
1294 case PT_BINARY:
1295 if (IsBadReadPtr(lpProp->Value.bin.lpb, lpProp->Value.bin.cb))
1296 return TRUE;
1297 break;
1298 case PT_CLSID:
1299 if (IsBadReadPtr(lpProp->Value.lpguid, sizeof(GUID)))
1300 return TRUE;
1301 break;
1302
1303 /* Multiple value properties (arrays) containing no pointers */
1304 case PT_MV_I2:
1305 return PROP_BadArray(lpProp, sizeof(SHORT));
1306 case PT_MV_LONG:
1307 return PROP_BadArray(lpProp, sizeof(LONG));
1308 case PT_MV_LONGLONG:
1309 return PROP_BadArray(lpProp, sizeof(LONG64));
1310 case PT_MV_FLOAT:
1311 return PROP_BadArray(lpProp, sizeof(float));
1312 case PT_MV_SYSTIME:
1313 return PROP_BadArray(lpProp, sizeof(FILETIME));
1314 case PT_MV_APPTIME:
1315 case PT_MV_DOUBLE:
1316 return PROP_BadArray(lpProp, sizeof(double));
1317 case PT_MV_CURRENCY:
1318 return PROP_BadArray(lpProp, sizeof(CY));
1319 case PT_MV_CLSID:
1320 return PROP_BadArray(lpProp, sizeof(GUID));
1321
1322 /* Multiple value properties containing pointers */
1323 case PT_MV_STRING8:
1324 return FBadRglpszA(lpProp->Value.MVszA.lppszA,
1325 lpProp->Value.MVszA.cValues);
1326 case PT_MV_UNICODE:
1327 return FBadRglpszW(lpProp->Value.MVszW.lppszW,
1328 lpProp->Value.MVszW.cValues);
1329 case PT_MV_BINARY:
1330 return FBadEntryList(&lpProp->Value.MVbin);
1331 }
1332 return FALSE;
1333 }
1334
1335 /*************************************************************************
1336 * FBadColumnSet@4 (MAPI32.182)
1337 *
1338 * Determine if an array of property tags is invalid
1339 *
1340 * PARAMS
1341 * lpCols [I] Property tag array to check
1342 *
1343 * RETURNS
1344 * TRUE, if lpCols is invalid, FALSE otherwise.
1345 */
1346 ULONG WINAPI FBadColumnSet(LPSPropTagArray lpCols)
1347 {
1348 ULONG ulRet = FALSE, i;
1349
1350 TRACE("(%p)\n", lpCols);
1351
1352 if (!lpCols || IsBadReadPtr(lpCols, CbSPropTagArray(lpCols)))
1353 ulRet = TRUE;
1354 else
1355 {
1356 for (i = 0; i < lpCols->cValues; i++)
1357 {
1358 if ((lpCols->aulPropTag[i] & PROP_TYPE_MASK) == PT_ERROR ||
1359 FBadPropTag(lpCols->aulPropTag[i]))
1360 {
1361 ulRet = TRUE;
1362 break;
1363 }
1364 }
1365 }
1366 TRACE("Returning %s\n", ulRet ? "TRUE" : "FALSE");
1367 return ulRet;
1368 }
1369
1370
1371 /**************************************************************************
1372 * IPropData {MAPI32}
1373 *
1374 * A default Mapi interface to provide manipulation of object properties.
1375 *
1376 * DESCRIPTION
1377 * This object provides a default interface suitable in some cases as an
1378 * implementation of the IMAPIProp interface (which has no default
1379 * implementation). In addition to the IMAPIProp() methods inherited, this
1380 * interface allows read/write control over access to the object and its
1381 * individual properties.
1382 *
1383 * To obtain the default implementation of this interface from Mapi, call
1384 * CreateIProp().
1385 *
1386 * METHODS
1387 */
1388
1389 /* A single property in a property data collection */
1390 typedef struct
1391 {
1392 struct list entry;
1393 ULONG ulAccess; /* The property value access level */
1394 LPSPropValue value; /* The property value */
1395 } IPropDataItem, *LPIPropDataItem;
1396
1397 /* The main property data collection structure */
1398 typedef struct
1399 {
1400 IPropData IPropData_iface;
1401 LONG lRef; /* Reference count */
1402 ALLOCATEBUFFER *lpAlloc; /* Memory allocation routine */
1403 ALLOCATEMORE *lpMore; /* Linked memory allocation routine */
1404 FREEBUFFER *lpFree; /* Memory free routine */
1405 ULONG ulObjAccess; /* Object access level */
1406 ULONG ulNumValues; /* Number of items in values list */
1407 struct list values; /* List of property values */
1408 CRITICAL_SECTION cs; /* Lock for thread safety */
1409 } IPropDataImpl;
1410
1411 static inline IPropDataImpl *impl_from_IPropData(IPropData *iface)
1412 {
1413 return CONTAINING_RECORD(iface, IPropDataImpl, IPropData_iface);
1414 }
1415
1416 /* Internal - Get a property value, assumes lock is held */
1417 static IPropDataItem *IMAPIPROP_GetValue(IPropDataImpl *This, ULONG ulPropTag)
1418 {
1419 struct list *cursor;
1420
1421 LIST_FOR_EACH(cursor, &This->values)
1422 {
1423 LPIPropDataItem current = LIST_ENTRY(cursor, IPropDataItem, entry);
1424 /* Note that property types don't have to match, just Id's */
1425 if (PROP_ID(current->value->ulPropTag) == PROP_ID(ulPropTag))
1426 return current;
1427 }
1428 return NULL;
1429 }
1430
1431 /* Internal - Add a new property value, assumes lock is held */
1432 static IPropDataItem *IMAPIPROP_AddValue(IPropDataImpl *This,
1433 LPSPropValue lpProp)
1434 {
1435 LPVOID lpMem;
1436 LPIPropDataItem lpNew;
1437 HRESULT hRet;
1438
1439 hRet = This->lpAlloc(sizeof(IPropDataItem), &lpMem);
1440
1441 if (SUCCEEDED(hRet))
1442 {
1443 lpNew = lpMem;
1444 lpNew->ulAccess = IPROP_READWRITE;
1445
1446 /* Allocate the value separately so we can update it easily */
1447 lpMem = NULL;
1448 hRet = This->lpAlloc(sizeof(SPropValue), &lpMem);
1449 if (SUCCEEDED(hRet))
1450 {
1451 lpNew->value = lpMem;
1452
1453 hRet = PropCopyMore(lpNew->value, lpProp, This->lpMore, lpMem);
1454 if (SUCCEEDED(hRet))
1455 {
1456 list_add_tail(&This->values, &lpNew->entry);
1457 This->ulNumValues++;
1458 return lpNew;
1459 }
1460 This->lpFree(lpNew->value);
1461 }
1462 This->lpFree(lpNew);
1463 }
1464 return NULL;
1465 }
1466
1467 /* Internal - Lock an IPropData object */
1468 static inline void IMAPIPROP_Lock(IPropDataImpl *This)
1469 {
1470 EnterCriticalSection(&This->cs);
1471 }
1472
1473 /* Internal - Unlock an IPropData object */
1474 static inline void IMAPIPROP_Unlock(IPropDataImpl *This)
1475 {
1476 LeaveCriticalSection(&This->cs);
1477 }
1478
1479 /* This one seems to be missing from mapidefs.h */
1480 #define CbNewSPropProblemArray(c) \
1481 (offsetof(SPropProblemArray,aProblem)+(c)*sizeof(SPropProblem))
1482
1483 /**************************************************************************
1484 * IPropData_QueryInterface {MAPI32}
1485 *
1486 * Inherited method from the IUnknown Interface.
1487 * See IUnknown_QueryInterface.
1488 */
1489 static HRESULT WINAPI IPropData_fnQueryInterface(LPPROPDATA iface, REFIID riid, LPVOID *ppvObj)
1490 {
1491 IPropDataImpl *This = impl_from_IPropData(iface);
1492
1493 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppvObj);
1494
1495 if (!ppvObj || !riid)
1496 return MAPI_E_INVALID_PARAMETER;
1497
1498 *ppvObj = NULL;
1499
1500 if(IsEqualIID(riid, &IID_IUnknown) ||
1501 IsEqualIID(riid, &IID_IMAPIProp) ||
1502 IsEqualIID(riid, &IID_IMAPIPropData))
1503 {
1504 *ppvObj = &This->IPropData_iface;
1505 IPropData_AddRef(iface);
1506 TRACE("returning %p\n", *ppvObj);
1507 return S_OK;
1508 }
1509
1510 TRACE("returning E_NOINTERFACE\n");
1511 return MAPI_E_INTERFACE_NOT_SUPPORTED;
1512 }
1513
1514 /**************************************************************************
1515 * IPropData_AddRef {MAPI32}
1516 *
1517 * Inherited method from the IUnknown Interface.
1518 * See IUnknown_AddRef.
1519 */
1520 static ULONG WINAPI IPropData_fnAddRef(LPPROPDATA iface)
1521 {
1522 IPropDataImpl *This = impl_from_IPropData(iface);
1523
1524 TRACE("(%p)->(count before=%u)\n", This, This->lRef);
1525
1526 return InterlockedIncrement(&This->lRef);
1527 }
1528
1529 /**************************************************************************
1530 * IPropData_Release {MAPI32}
1531 *
1532 * Inherited method from the IUnknown Interface.
1533 * See IUnknown_Release.
1534 */
1535 static ULONG WINAPI IPropData_fnRelease(LPPROPDATA iface)
1536 {
1537 IPropDataImpl *This = impl_from_IPropData(iface);
1538 LONG lRef;
1539
1540 TRACE("(%p)->(count before=%u)\n", This, This->lRef);
1541
1542 lRef = InterlockedDecrement(&This->lRef);
1543 if (!lRef)
1544 {
1545 TRACE("Destroying IPropData (%p)\n",This);
1546
1547 /* Note: No need to lock, since no other thread is referencing iface */
1548 while (!list_empty(&This->values))
1549 {
1550 struct list *head = list_head(&This->values);
1551 LPIPropDataItem current = LIST_ENTRY(head, IPropDataItem, entry);
1552 list_remove(head);
1553 This->lpFree(current->value);
1554 This->lpFree(current);
1555 }
1556 This->cs.DebugInfo->Spare[0] = 0;
1557 DeleteCriticalSection(&This->cs);
1558 This->lpFree(This);
1559 }
1560 return (ULONG)lRef;
1561 }
1562
1563 /**************************************************************************
1564 * IPropData_GetLastError {MAPI32}
1565 *
1566 * Get information about the last error that occurred in an IMAPIProp object.
1567 *
1568 * PARAMS
1569 * iface [I] IMAPIProp object that experienced the error
1570 * hRes [I] Result of the call that returned an error
1571 * ulFlags [I] 0=return Ascii strings, MAPI_UNICODE=return Unicode strings
1572 * lppError [O] Destination for detailed error information
1573 *
1574 * RETURNS
1575 * Success: S_OK. *lppError contains details about the last error.
1576 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid,
1577 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
1578 *
1579 * NOTES
1580 * - If this function succeeds, the returned information in *lppError must be
1581 * freed using MAPIFreeBuffer() once the caller is finished with it.
1582 * - It is possible for this function to succeed and set *lppError to NULL,
1583 * if there is no further information to report about hRes.
1584 */
1585 static HRESULT WINAPI IPropData_fnGetLastError(LPPROPDATA iface, HRESULT hRes, ULONG ulFlags,
1586 LPMAPIERROR *lppError)
1587 {
1588 TRACE("(%p,0x%08X,0x%08X,%p)\n", iface, hRes, ulFlags, lppError);
1589
1590 if (!lppError || SUCCEEDED(hRes) || (ulFlags & ~MAPI_UNICODE))
1591 return MAPI_E_INVALID_PARAMETER;
1592
1593 *lppError = NULL;
1594 return S_OK;
1595 }
1596
1597 /**************************************************************************
1598 * IPropData_SaveChanges {MAPI32}
1599 *
1600 * Update any changes made to a transactional IMAPIProp object.
1601 *
1602 * PARAMS
1603 * iface [I] IMAPIProp object to update
1604 * ulFlags [I] Flags controlling the update.
1605 *
1606 * RETURNS
1607 * Success: S_OK. Any outstanding changes are committed to the object.
1608 * Failure: An HRESULT error code describing the error.
1609 */
1610 static HRESULT WINAPI IPropData_fnSaveChanges(LPPROPDATA iface, ULONG ulFlags)
1611 {
1612 TRACE("(%p,0x%08X)\n", iface, ulFlags);
1613
1614 /* Since this object is not transacted we do not need to implement this */
1615 /* FIXME: Should we set the access levels to clean? */
1616 return S_OK;
1617 }
1618
1619 /**************************************************************************
1620 * IPropData_GetProps {MAPI32}
1621 *
1622 * Get property values from an IMAPIProp object.
1623 *
1624 * PARAMS
1625 * iface [I] IMAPIProp object to get the property values from
1626 * lpTags [I] Property tags of property values to be retrieved
1627 * ulFlags [I] Return 0=Ascii MAPI_UNICODE=Unicode strings for
1628 * unspecified types
1629 * lpCount [O] Destination for number of properties returned
1630 * lppProps [O] Destination for returned property values
1631 *
1632 * RETURNS
1633 * Success: S_OK. *lppProps and *lpCount are updated.
1634 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
1635 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
1636 * MAPI_W_ERRORS_RETURNED if not all properties were retrieved
1637 * successfully.
1638 * NOTES
1639 * - If MAPI_W_ERRORS_RETURNED is returned, any properties that could not be
1640 * retrieved from iface are present in lppProps with their type
1641 * changed to PT_ERROR and Id unchanged.
1642 */
1643 static HRESULT WINAPI IPropData_fnGetProps(LPPROPDATA iface, LPSPropTagArray lpTags, ULONG ulFlags,
1644 ULONG *lpCount, LPSPropValue *lppProps)
1645 {
1646 IPropDataImpl *This = impl_from_IPropData(iface);
1647 ULONG i;
1648 HRESULT hRet = S_OK;
1649
1650 TRACE("(%p,%p,0x%08x,%p,%p) stub\n", iface, lpTags, ulFlags,
1651 lpCount, lppProps);
1652
1653 if (!iface || ulFlags & ~MAPI_UNICODE || !lpTags || *lpCount || !lppProps)
1654 return MAPI_E_INVALID_PARAMETER;
1655
1656 FIXME("semi-stub, flags not supported\n");
1657
1658 *lpCount = lpTags->cValues;
1659 *lppProps = NULL;
1660
1661 if (*lpCount)
1662 {
1663 hRet = MAPIAllocateBuffer(*lpCount * sizeof(SPropValue), (LPVOID*)lppProps);
1664 if (FAILED(hRet))
1665 return hRet;
1666
1667 IMAPIPROP_Lock(This);
1668
1669 for (i = 0; i < lpTags->cValues; i++)
1670 {
1671 HRESULT hRetTmp = E_INVALIDARG;
1672 LPIPropDataItem item;
1673
1674 item = IMAPIPROP_GetValue(This, lpTags->aulPropTag[i]);
1675
1676 if (item)
1677 hRetTmp = PropCopyMore(&(*lppProps)[i], item->value,
1678 This->lpMore, *lppProps);
1679 if (FAILED(hRetTmp))
1680 {
1681 hRet = MAPI_W_ERRORS_RETURNED;
1682 (*lppProps)[i].ulPropTag =
1683 CHANGE_PROP_TYPE(lpTags->aulPropTag[i], PT_ERROR);
1684 }
1685 }
1686
1687 IMAPIPROP_Unlock(This);
1688 }
1689 return hRet;
1690 }
1691
1692 /**************************************************************************
1693 * MAPIProp_GetPropList {MAPI32}
1694 *
1695 * Get the list of property tags for all values in an IMAPIProp object.
1696 *
1697 * PARAMS
1698 * iface [I] IMAPIProp object to get the property tag list from
1699 * ulFlags [I] Return 0=Ascii MAPI_UNICODE=Unicode strings for
1700 * unspecified types
1701 * lppTags [O] Destination for the retrieved property tag list
1702 *
1703 * RETURNS
1704 * Success: S_OK. *lppTags contains the tags for all available properties.
1705 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
1706 * MAPI_E_BAD_CHARWIDTH, if Ascii or Unicode strings are requested
1707 * and that type of string is not supported.
1708 */
1709 static HRESULT WINAPI IPropData_fnGetPropList(LPPROPDATA iface, ULONG ulFlags,
1710 LPSPropTagArray *lppTags)
1711 {
1712 IPropDataImpl *This = impl_from_IPropData(iface);
1713 ULONG i;
1714 HRESULT hRet;
1715
1716 TRACE("(%p,0x%08x,%p) stub\n", iface, ulFlags, lppTags);
1717
1718 if (!iface || ulFlags & ~MAPI_UNICODE || !lppTags)
1719 return MAPI_E_INVALID_PARAMETER;
1720
1721 FIXME("semi-stub, flags not supported\n");
1722
1723 *lppTags = NULL;
1724
1725 IMAPIPROP_Lock(This);
1726
1727 hRet = MAPIAllocateBuffer(CbNewSPropTagArray(This->ulNumValues),
1728 (LPVOID*)lppTags);
1729 if (SUCCEEDED(hRet))
1730 {
1731 struct list *cursor;
1732
1733 i = 0;
1734 LIST_FOR_EACH(cursor, &This->values)
1735 {
1736 LPIPropDataItem current = LIST_ENTRY(cursor, IPropDataItem, entry);
1737 (*lppTags)->aulPropTag[i] = current->value->ulPropTag;
1738 i++;
1739 }
1740 (*lppTags)->cValues = This->ulNumValues;
1741 }
1742
1743 IMAPIPROP_Unlock(This);
1744 return hRet;
1745 }
1746
1747 /**************************************************************************
1748 * IPropData_OpenProperty {MAPI32}
1749 *
1750 * Not documented at this time.
1751 *
1752 * RETURNS
1753 * An HRESULT success/failure code.
1754 */
1755 static HRESULT WINAPI IPropData_fnOpenProperty(LPPROPDATA iface, ULONG ulPropTag, LPCIID iid,
1756 ULONG ulOpts, ULONG ulFlags, LPUNKNOWN *lpUnk)
1757 {
1758 FIXME("(%p,%u,%s,%u,0x%08x,%p) stub\n", iface, ulPropTag,
1759 debugstr_guid(iid), ulOpts, ulFlags, lpUnk);
1760 return MAPI_E_NO_SUPPORT;
1761 }
1762
1763
1764 /**************************************************************************
1765 * IPropData_SetProps {MAPI32}
1766 *
1767 * Add or edit the property values in an IMAPIProp object.
1768 *
1769 * PARAMS
1770 * iface [I] IMAPIProp object to get the property tag list from
1771 * ulValues [I] Number of properties in lpProps
1772 * lpProps [I] Property values to set
1773 * lppProbs [O] Optional destination for any problems that occurred
1774 *
1775 * RETURNS
1776 * Success: S_OK. The properties in lpProps are added to iface if they don't
1777 * exist, or changed to the values in lpProps if they do
1778 * Failure: An HRESULT error code describing the error
1779 */
1780 static HRESULT WINAPI IPropData_fnSetProps(LPPROPDATA iface, ULONG ulValues, LPSPropValue lpProps,
1781 LPSPropProblemArray *lppProbs)
1782 {
1783 IPropDataImpl *This = impl_from_IPropData(iface);
1784 HRESULT hRet = S_OK;
1785 ULONG i;
1786
1787 TRACE("(%p,%u,%p,%p)\n", iface, ulValues, lpProps, lppProbs);
1788
1789 if (!iface || !lpProps)
1790 return MAPI_E_INVALID_PARAMETER;
1791
1792 for (i = 0; i < ulValues; i++)
1793 {
1794 if (FBadProp(&lpProps[i]) ||
1795 PROP_TYPE(lpProps[i].ulPropTag) == PT_OBJECT ||
1796 PROP_TYPE(lpProps[i].ulPropTag) == PT_NULL)
1797 return MAPI_E_INVALID_PARAMETER;
1798 }
1799
1800 IMAPIPROP_Lock(This);
1801
1802 /* FIXME: Under what circumstances is lpProbs created? */
1803 for (i = 0; i < ulValues; i++)
1804 {
1805 LPIPropDataItem item = IMAPIPROP_GetValue(This, lpProps[i].ulPropTag);
1806
1807 if (item)
1808 {
1809 HRESULT hRetTmp;
1810 LPVOID lpMem = NULL;
1811
1812 /* Found, so update the existing value */
1813 if (item->value->ulPropTag != lpProps[i].ulPropTag)
1814 FIXME("semi-stub, overwriting type (not coercing)\n");
1815
1816 hRetTmp = This->lpAlloc(sizeof(SPropValue), &lpMem);
1817 if (SUCCEEDED(hRetTmp))
1818 {
1819 hRetTmp = PropCopyMore(lpMem, &lpProps[i], This->lpMore, lpMem);
1820 if (SUCCEEDED(hRetTmp))
1821 {
1822 This->lpFree(item->value);
1823 item->value = lpMem;
1824 continue;
1825 }
1826 This->lpFree(lpMem);
1827 }
1828 hRet = hRetTmp;
1829 }
1830 else
1831 {
1832 /* Add new value */
1833 if (!IMAPIPROP_AddValue(This, &lpProps[i]))
1834 hRet = MAPI_E_NOT_ENOUGH_MEMORY;
1835 }
1836 }
1837
1838 IMAPIPROP_Unlock(This);
1839 return hRet;
1840 }
1841
1842 /**************************************************************************
1843 * IPropData_DeleteProps {MAPI32}
1844 *
1845 * Delete one or more property values from an IMAPIProp object.
1846 *
1847 * PARAMS
1848 * iface [I] IMAPIProp object to remove property values from.
1849 * lpTags [I] Collection of property Id's to remove from iface.
1850 * lppProbs [O] Destination for problems encountered, if any.
1851 *
1852 * RETURNS
1853 * Success: S_OK. Any properties in iface matching property Id's in lpTags have
1854 * been deleted. If lppProbs is non-NULL it contains details of any
1855 * errors that occurred.
1856 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
1857 * E_ACCESSDENIED, if this object was created using CreateIProp() and
1858 * a subsequent call to IPropData_SetObjAccess() was made specifying
1859 * IPROP_READONLY as the access type.
1860 *
1861 * NOTES
1862 * - lppProbs will not be populated for cases where a property Id is present
1863 * in lpTags but not in iface.
1864 * - lppProbs should be deleted with MAPIFreeBuffer() if returned.
1865 */
1866 static HRESULT WINAPI IPropData_fnDeleteProps(LPPROPDATA iface, LPSPropTagArray lpTags,
1867 LPSPropProblemArray *lppProbs)
1868 {
1869 IPropDataImpl *This = impl_from_IPropData(iface);
1870 ULONG i, numProbs = 0;
1871 HRESULT hRet = S_OK;
1872
1873 TRACE("(%p,%p,%p)\n", iface, lpTags, lppProbs);
1874
1875 if (!iface || !lpTags)
1876 return MAPI_E_INVALID_PARAMETER;
1877
1878 if (lppProbs)
1879 *lppProbs = NULL;
1880
1881 for (i = 0; i < lpTags->cValues; i++)
1882 {
1883 if (FBadPropTag(lpTags->aulPropTag[i]) ||
1884 PROP_TYPE(lpTags->aulPropTag[i]) == PT_OBJECT ||
1885 PROP_TYPE(lpTags->aulPropTag[i]) == PT_NULL)
1886 return MAPI_E_INVALID_PARAMETER;
1887 }
1888
1889 IMAPIPROP_Lock(This);
1890
1891 if (This->ulObjAccess != IPROP_READWRITE)
1892 {
1893 IMAPIPROP_Unlock(This);
1894 return E_ACCESSDENIED;
1895 }
1896
1897 for (i = 0; i < lpTags->cValues; i++)
1898 {
1899 LPIPropDataItem item = IMAPIPROP_GetValue(This, lpTags->aulPropTag[i]);
1900
1901 if (item)
1902 {
1903 if (item->ulAccess & IPROP_READWRITE)
1904 {
1905 /* Everything hunky-dory, remove the item */
1906 list_remove(&item->entry);
1907 This->lpFree(item->value); /* Also frees value pointers */
1908 This->lpFree(item);
1909 This->ulNumValues--;
1910 }
1911 else if (lppProbs)
1912 {
1913 /* Can't write the value. Create/populate problems array */
1914 if (!*lppProbs)
1915 {
1916 /* Create problems array */
1917 ULONG ulSize = CbNewSPropProblemArray(lpTags->cValues - i);
1918 HRESULT hRetTmp = MAPIAllocateBuffer(ulSize, (LPVOID*)lppProbs);
1919 if (FAILED(hRetTmp))
1920 hRet = hRetTmp;
1921 }
1922 if (*lppProbs)
1923 {
1924 LPSPropProblem lpProb = &(*lppProbs)->aProblem[numProbs];
1925 lpProb->ulIndex = i;
1926 lpProb->ulPropTag = lpTags->aulPropTag[i];
1927 lpProb->scode = E_ACCESSDENIED;
1928 numProbs++;
1929 }
1930 }
1931 }
1932 }
1933 if (lppProbs && *lppProbs)
1934 (*lppProbs)->cProblem = numProbs;
1935
1936 IMAPIPROP_Unlock(This);
1937 return hRet;
1938 }
1939
1940
1941 /**************************************************************************
1942 * IPropData_CopyTo {MAPI32}
1943 *
1944 * Not documented at this time.
1945 *
1946 * RETURNS
1947 * An HRESULT success/failure code.
1948 */
1949 static HRESULT WINAPI IPropData_fnCopyTo(LPPROPDATA iface, ULONG niids, LPCIID lpiidExcl,
1950 LPSPropTagArray lpPropsExcl, ULONG ulParam,
1951 LPMAPIPROGRESS lpIProgress, LPCIID lpIfaceIid,
1952 LPVOID lpDstObj, ULONG ulFlags,
1953 LPSPropProblemArray *lppProbs)
1954 {
1955 FIXME("(%p,%u,%p,%p,%x,%p,%s,%p,0x%08X,%p) stub\n", iface, niids,
1956 lpiidExcl, lpPropsExcl, ulParam, lpIProgress,
1957 debugstr_guid(lpIfaceIid), lpDstObj, ulFlags, lppProbs);
1958 return MAPI_E_NO_SUPPORT;
1959 }
1960
1961 /**************************************************************************
1962 * IPropData_CopyProps {MAPI32}
1963 *
1964 * Not documented at this time.
1965 *
1966 * RETURNS
1967 * An HRESULT success/failure code.
1968 */
1969 static HRESULT WINAPI IPropData_fnCopyProps(LPPROPDATA iface, LPSPropTagArray lpInclProps,
1970 ULONG ulParam, LPMAPIPROGRESS lpIProgress,
1971 LPCIID lpIface, LPVOID lpDstObj, ULONG ulFlags,
1972 LPSPropProblemArray *lppProbs)
1973 {
1974 FIXME("(%p,%p,%x,%p,%s,%p,0x%08X,%p) stub\n", iface, lpInclProps,
1975 ulParam, lpIProgress, debugstr_guid(lpIface), lpDstObj, ulFlags,
1976 lppProbs);
1977 return MAPI_E_NO_SUPPORT;
1978 }
1979
1980 /**************************************************************************
1981 * IPropData_GetNamesFromIDs {MAPI32}
1982 *
1983 * Get the names of properties from their identifiers.
1984 *
1985 * PARAMS
1986 * iface [I] IMAPIProp object to operate on
1987 * lppPropTags [I/O] Property identifiers to get the names for, or NULL to
1988 * get all names
1989 * iid [I] Property set identifier, or NULL
1990 * ulFlags [I] MAPI_NO_IDS=Don't return numeric named properties,
1991 * or MAPI_NO_STRINGS=Don't return strings
1992 * lpCount [O] Destination for number of properties returned
1993 * lpppNames [O] Destination for returned names
1994 *
1995 * RETURNS
1996 * Success: S_OK. *lppPropTags and lpppNames contain the returned
1997 * name/identifiers.
1998 * Failure: MAPI_E_NO_SUPPORT, if the object does not support named properties,
1999 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
2000 * MAPI_W_ERRORS_RETURNED if not all properties were retrieved
2001 * successfully.
2002 */
2003 static HRESULT WINAPI IPropData_fnGetNamesFromIDs(LPPROPDATA iface, LPSPropTagArray *lppPropTags,
2004 LPGUID iid, ULONG ulFlags, ULONG *lpCount,
2005 LPMAPINAMEID **lpppNames)
2006 {
2007 FIXME("(%p,%p,%s,0x%08X,%p,%p) stub\n", iface, lppPropTags,
2008 debugstr_guid(iid), ulFlags, lpCount, lpppNames);
2009 return MAPI_E_NO_SUPPORT;
2010 }
2011
2012 /**************************************************************************
2013 * IPropData_GetIDsFromNames {MAPI32}
2014 *
2015 * Get property identifiers associated with one or more named properties.
2016 *
2017 * PARAMS
2018 * iface [I] IMAPIProp object to operate on
2019 * ulNames [I] Number of names in lppNames
2020 * lppNames [I] Names to query or create, or NULL to query all names
2021 * ulFlags [I] Pass MAPI_CREATE to create new named properties
2022 * lppPropTags [O] Destination for queried or created property identifiers
2023 *
2024 * RETURNS
2025 * Success: S_OK. *lppPropTags contains the property tags created or requested.
2026 * Failure: MAPI_E_NO_SUPPORT, if the object does not support named properties,
2027 * MAPI_E_TOO_BIG, if the object cannot process the number of
2028 * properties involved.
2029 * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails, or
2030 * MAPI_W_ERRORS_RETURNED if not all properties were retrieved
2031 * successfully.
2032 */
2033 static HRESULT WINAPI IPropData_fnGetIDsFromNames(LPPROPDATA iface, ULONG ulNames,
2034 LPMAPINAMEID *lppNames, ULONG ulFlags,
2035 LPSPropTagArray *lppPropTags)
2036 {
2037 FIXME("(%p,%d,%p,0x%08X,%p) stub\n",
2038 iface, ulNames, lppNames, ulFlags, lppPropTags);
2039 return MAPI_E_NO_SUPPORT;
2040 }
2041
2042 /**************************************************************************
2043 * IPropData_HrSetObjAccess {MAPI32}
2044 *
2045 * Set the access level of an IPropData object.
2046 *
2047 * PARAMS
2048 * iface [I] IPropData object to set the access on
2049 * ulAccess [I] Either IPROP_READONLY or IPROP_READWRITE for read or
2050 * read/write access respectively.
2051 *
2052 * RETURNS
2053 * Success: S_OK. The objects access level is changed.
2054 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
2055 */
2056 static HRESULT WINAPI
2057 IPropData_fnHrSetObjAccess(LPPROPDATA iface, ULONG ulAccess)
2058 {
2059 IPropDataImpl *This = impl_from_IPropData(iface);
2060
2061 TRACE("(%p,%x)\n", iface, ulAccess);
2062
2063 if (!iface || ulAccess < IPROP_READONLY || ulAccess > IPROP_READWRITE)
2064 return MAPI_E_INVALID_PARAMETER;
2065
2066 IMAPIPROP_Lock(This);
2067
2068 This->ulObjAccess = ulAccess;
2069
2070 IMAPIPROP_Unlock(This);
2071 return S_OK;
2072 }
2073
2074 /* Internal - determine if an access value is bad */
2075 static inline BOOL PROP_IsBadAccess(ULONG ulAccess)
2076 {
2077 switch (ulAccess)
2078 {
2079 case IPROP_READONLY|IPROP_CLEAN:
2080 case IPROP_READONLY|IPROP_DIRTY:
2081 case IPROP_READWRITE|IPROP_CLEAN:
2082 case IPROP_READWRITE|IPROP_DIRTY:
2083 return FALSE;
2084 }
2085 return TRUE;
2086 }
2087
2088 /**************************************************************************
2089 * IPropData_HrSetPropAccess {MAPI32}
2090 *
2091 * Set the access levels for a group of property values in an IPropData object.
2092 *
2093 * PARAMS
2094 * iface [I] IPropData object to set access levels in.
2095 * lpTags [I] List of property Id's to set access for.
2096 * lpAccess [O] Access level for each property in lpTags.
2097 *
2098 * RETURNS
2099 * Success: S_OK. The access level of each property value in lpTags that is
2100 * present in iface is changed.
2101 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid.
2102 *
2103 * NOTES
2104 * - Each access level in lpAccess must contain at least one of IPROP_READONLY
2105 * or IPROP_READWRITE, but not both, and also IPROP_CLEAN or IPROP_DIRTY,
2106 * but not both. No other bits should be set.
2107 * - If a property Id in lpTags is not present in iface, it is ignored.
2108 */
2109 static HRESULT WINAPI
2110 IPropData_fnHrSetPropAccess(LPPROPDATA iface, LPSPropTagArray lpTags,
2111 ULONG *lpAccess)
2112 {
2113 IPropDataImpl *This = impl_from_IPropData(iface);
2114 ULONG i;
2115
2116 TRACE("(%p,%p,%p)\n", iface, lpTags, lpAccess);
2117
2118 if (!iface || !lpTags || !lpAccess)
2119 return MAPI_E_INVALID_PARAMETER;
2120
2121 for (i = 0; i < lpTags->cValues; i++)
2122 {
2123 if (FBadPropTag(lpTags->aulPropTag[i]) || PROP_IsBadAccess(lpAccess[i]))
2124 return MAPI_E_INVALID_PARAMETER;
2125 }
2126
2127 IMAPIPROP_Lock(This);
2128
2129 for (i = 0; i < lpTags->cValues; i++)
2130 {
2131 LPIPropDataItem item = IMAPIPROP_GetValue(This, lpTags->aulPropTag[i]);
2132
2133 if (item)
2134 item->ulAccess = lpAccess[i];
2135 }
2136
2137 IMAPIPROP_Unlock(This);
2138 return S_OK;
2139 }
2140
2141 /**************************************************************************
2142 * IPropData_HrGetPropAccess {MAPI32}
2143 *
2144 * Get the access levels for a group of property values in an IPropData object.
2145 *
2146 * PARAMS
2147 * iface [I] IPropData object to get access levels from.
2148 * lppTags [O] Destination for the list of property Id's in iface.
2149 * lppAccess [O] Destination for access level for each property in lppTags.
2150 *
2151 * RETURNS
2152 * Success: S_OK. lppTags and lppAccess contain the property Id's and the
2153 * Access level of each property value in iface.
2154 * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid, or
2155 * MAPI_E_NOT_ENOUGH_MEMORY if memory allocation fails.
2156 *
2157 * NOTES
2158 * - *lppTags and *lppAccess should be freed with MAPIFreeBuffer() by the caller.
2159 */
2160 static HRESULT WINAPI
2161 IPropData_fnHrGetPropAccess(LPPROPDATA iface, LPSPropTagArray *lppTags,
2162 ULONG **lppAccess)
2163 {
2164 IPropDataImpl *This = impl_from_IPropData(iface);
2165 LPVOID lpMem;
2166 HRESULT hRet;
2167 ULONG i;
2168
2169 TRACE("(%p,%p,%p) stub\n", iface, lppTags, lppAccess);
2170
2171 if (!iface || !lppTags || !lppAccess)
2172 return MAPI_E_INVALID_PARAMETER;
2173
2174 *lppTags = NULL;
2175 *lppAccess = NULL;
2176
2177 IMAPIPROP_Lock(This);
2178
2179 hRet = This->lpAlloc(CbNewSPropTagArray(This->ulNumValues), &lpMem);
2180 if (SUCCEEDED(hRet))
2181 {
2182 *lppTags = lpMem;
2183
2184 hRet = This->lpAlloc(This->ulNumValues * sizeof(ULONG), &lpMem);
2185 if (SUCCEEDED(hRet))
2186 {
2187 struct list *cursor;
2188
2189 *lppAccess = lpMem;
2190 (*lppTags)->cValues = This->ulNumValues;
2191
2192 i = 0;
2193 LIST_FOR_EACH(cursor, &This->values)
2194 {
2195 LPIPropDataItem item = LIST_ENTRY(cursor, IPropDataItem, entry);
2196 (*lppTags)->aulPropTag[i] = item->value->ulPropTag;
2197 (*lppAccess)[i] = item->ulAccess;
2198 i++;
2199 }
2200 IMAPIPROP_Unlock(This);
2201 return S_OK;
2202 }
2203 This->lpFree(*lppTags);
2204 *lppTags = 0;
2205 }
2206 IMAPIPROP_Unlock(This);
2207 return MAPI_E_NOT_ENOUGH_MEMORY;
2208 }
2209
2210 /**************************************************************************
2211 * IPropData_HrAddObjProps {MAPI32}
2212 *
2213 * Not documented at this time.
2214 *
2215 * RETURNS
2216 * An HRESULT success/failure code.
2217 */
2218 static HRESULT WINAPI
2219 IPropData_fnHrAddObjProps(LPPROPDATA iface, LPSPropTagArray lpTags,
2220 LPSPropProblemArray *lppProbs)
2221 {
2222 #if 0
2223 ULONG i;
2224 HRESULT hRet;
2225 LPSPropValue lpValues;
2226 #endif
2227
2228 FIXME("(%p,%p,%p) stub\n", iface, lpTags, lppProbs);
2229
2230 if (!iface || !lpTags)
2231 return MAPI_E_INVALID_PARAMETER;
2232
2233 /* FIXME: Below is the obvious implementation, adding all the properties
2234 * in lpTags to the object. However, it doesn't appear that this
2235 * is what this function does.
2236 */
2237 return S_OK;
2238 #if 0
2239 if (!lpTags->cValues)
2240 return S_OK;
2241
2242 lpValues = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2243 lpTags->cValues * sizeof(SPropValue));
2244 if (!lpValues)
2245 return MAPI_E_NOT_ENOUGH_MEMORY;
2246
2247 for (i = 0; i < lpTags->cValues; i++)
2248 lpValues[i].ulPropTag = lpTags->aulPropTag[i];
2249
2250 hRet = IPropData_SetProps(iface, lpTags->cValues, lpValues, lppProbs);
2251 HeapFree(GetProcessHeap(), 0, lpValues);
2252 return hRet;
2253 #endif
2254 }
2255
2256 static const IPropDataVtbl IPropDataImpl_vtbl =
2257 {
2258 IPropData_fnQueryInterface,
2259 IPropData_fnAddRef,
2260 IPropData_fnRelease,
2261 IPropData_fnGetLastError,
2262 IPropData_fnSaveChanges,
2263 IPropData_fnGetProps,
2264 IPropData_fnGetPropList,
2265 IPropData_fnOpenProperty,
2266 IPropData_fnSetProps,
2267 IPropData_fnDeleteProps,
2268 IPropData_fnCopyTo,
2269 IPropData_fnCopyProps,
2270 IPropData_fnGetNamesFromIDs,
2271 IPropData_fnGetIDsFromNames,
2272 IPropData_fnHrSetObjAccess,
2273 IPropData_fnHrSetPropAccess,
2274 IPropData_fnHrGetPropAccess,
2275 IPropData_fnHrAddObjProps
2276 };
2277
2278 /*************************************************************************
2279 * CreateIProp@24 (MAPI32.60)
2280 *
2281 * Create an IPropData object.
2282 *
2283 * PARAMS
2284 * iid [I] GUID of the object to create. Use &IID_IMAPIPropData or NULL
2285 * lpAlloc [I] Memory allocation function. Use MAPIAllocateBuffer()
2286 * lpMore [I] Linked memory allocation function. Use MAPIAllocateMore()
2287 * lpFree [I] Memory free function. Use MAPIFreeBuffer()
2288 * lpReserved [I] Reserved, set to NULL
2289 * lppPropData [O] Destination for created IPropData object
2290 *
2291 * RETURNS
2292 * Success: S_OK. *lppPropData contains the newly created object.
2293 * Failure: MAPI_E_INTERFACE_NOT_SUPPORTED, if iid is non-NULL and not supported,
2294 * MAPI_E_INVALID_PARAMETER, if any parameter is invalid
2295 */
2296 SCODE WINAPI CreateIProp(LPCIID iid, ALLOCATEBUFFER *lpAlloc,
2297 ALLOCATEMORE *lpMore, FREEBUFFER *lpFree,
2298 LPVOID lpReserved, LPPROPDATA *lppPropData)
2299 {
2300 IPropDataImpl *lpPropData;
2301 SCODE scode;
2302
2303 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_guid(iid), lpAlloc, lpMore, lpFree,
2304 lpReserved, lppPropData);
2305
2306 if (lppPropData)
2307 *lppPropData = NULL;
2308
2309 if (iid && !IsEqualGUID(iid, &IID_IMAPIPropData))
2310 return MAPI_E_INTERFACE_NOT_SUPPORTED;
2311
2312 if (!lpAlloc || !lpMore || !lpFree || lpReserved || !lppPropData)
2313 return MAPI_E_INVALID_PARAMETER;
2314
2315 scode = lpAlloc(sizeof(IPropDataImpl), (LPVOID*)&lpPropData);
2316
2317 if (SUCCEEDED(scode))
2318 {
2319 lpPropData->IPropData_iface.lpVtbl = &IPropDataImpl_vtbl;
2320 lpPropData->lRef = 1;
2321 lpPropData->lpAlloc = lpAlloc;
2322 lpPropData->lpMore = lpMore;
2323 lpPropData->lpFree = lpFree;
2324 lpPropData->ulObjAccess = IPROP_READWRITE;
2325 lpPropData->ulNumValues = 0;
2326 list_init(&lpPropData->values);
2327 InitializeCriticalSection(&lpPropData->cs);
2328 lpPropData->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IPropDataImpl.cs");
2329 *lppPropData = &lpPropData->IPropData_iface;
2330 }
2331 return scode;
2332 }