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