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