Properly cope with get_message being called recursively while
[wine] / dlls / mapi32 / util.c
1 /*
2  * MAPI Utility functions
3  *
4  * Copyright 2004 Jon Griffiths
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winuser.h"
30 #include "winerror.h"
31 #include "winternl.h"
32 #include "objbase.h"
33 #include "shlwapi.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "mapival.h"
37 #include "xcmc.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(mapi);
40
41 static const BYTE digitsToHex[] = {
42   0,1,2,3,4,5,6,7,8,9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,14,15,
43   0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
44   0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,
45   14,15 };
46
47 /**************************************************************************
48  *  ScInitMapiUtil (MAPI32.33)
49  *
50  * Initialise Mapi utility functions.
51  *
52  * PARAMS
53  *  ulReserved [I] Reserved, pass 0.
54  *
55  * RETURNS
56  *  Success: S_OK. Mapi utility functions may be called.
57  *  Failure: MAPI_E_INVALID_PARAMETER, if ulReserved is not 0.
58  *
59  * NOTES
60  *  Your application does not need to call this function unless it does not
61  *  call MAPIInitialize()/MAPIUninitialize().
62  */
63 SCODE WINAPI ScInitMapiUtil(ULONG ulReserved)
64 {
65     FIXME("(0x%08lx)stub!\n", ulReserved);
66     if (ulReserved)
67         return MAPI_E_INVALID_PARAMETER;
68     return S_OK;
69 }
70
71 /**************************************************************************
72  *  DeinitMapiUtil (MAPI32.34)
73  *
74  * Uninitialise Mapi utility functions.
75  *
76  * PARAMS
77  *  None.
78  *
79  * RETURNS
80  *  Nothing.
81  *
82  * NOTES
83  *  Your application does not need to call this function unless it does not
84  *  call MAPIInitialize()/MAPIUninitialize().
85  */
86 VOID WINAPI DeinitMapiUtil(void)
87 {
88     FIXME("()stub!\n");
89 }
90
91 typedef LPVOID *LPMAPIALLOCBUFFER;
92
93 /**************************************************************************
94  *  MAPIAllocateBuffer   (MAPI32.12)
95  *  MAPIAllocateBuffer@8 (MAPI32.13)
96  *
97  * Allocate a block of memory.
98  *
99  * PARAMS
100  *  cbSize    [I] Size of the block to allocate in bytes
101  *  lppBuffer [O] Destination for pointer to allocated memory
102  *
103  * RETURNS
104  *  Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
105  *           length cbSize bytes.
106  *  Failure: MAPI_E_INVALID_PARAMETER, if lppBuffer is NULL.
107  *           MAPI_E_NOT_ENOUGH_MEMORY, if the memory allocation fails.
108  *
109  * NOTES
110  *  Memory allocated with this function should be freed with MAPIFreeBuffer().
111  *  Further allocations of memory may be linked to the pointer returned using
112  *  MAPIAllocateMore(). Linked allocations are freed when the initial pointer
113  *  is feed.
114  */
115 SCODE WINAPI MAPIAllocateBuffer(ULONG cbSize, LPVOID *lppBuffer)
116 {
117     LPMAPIALLOCBUFFER lpBuff;
118
119     TRACE("(%ld,%p)\n", cbSize, lppBuffer);
120
121     if (!lppBuffer)
122         return E_INVALIDARG;
123
124     lpBuff = (LPMAPIALLOCBUFFER)HeapAlloc(GetProcessHeap(), 0, cbSize + sizeof(*lpBuff));
125     if (!lpBuff)
126         return MAPI_E_NOT_ENOUGH_MEMORY;
127
128     TRACE("initial allocation:%p, returning %p\n", lpBuff, lpBuff + 1);
129     *lpBuff++ = NULL;
130     *lppBuffer = lpBuff;
131     return S_OK;
132 }
133
134 /**************************************************************************
135  *  MAPIAllocateMore    (MAPI32.14)
136  *  MAPIAllocateMore@12 (MAPI32.15)
137  *
138  * Allocate a block of memory linked to a previous allocation.
139  *
140  * PARAMS
141  *  cbSize    [I] Size of the block to allocate in bytes
142  *  lpOrig    [I] Initial allocation to link to, from MAPIAllocateBuffer()
143  *  lppBuffer [O] Destination for pointer to allocated memory
144  *
145  * RETURNS
146  *  Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
147  *           length cbSize bytes.
148  *  Failure: MAPI_E_INVALID_PARAMETER, if lpOrig or lppBuffer is invalid.
149  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
150  *
151  * NOTES
152  *  Memory allocated with this function and stored in *lppBuffer is freed
153  *  when lpOrig is passed to MAPIFreeBuffer(). It should not be freed independently.
154  */
155 SCODE WINAPI MAPIAllocateMore(ULONG cbSize, LPVOID lpOrig, LPVOID *lppBuffer)
156 {
157     LPMAPIALLOCBUFFER lpBuff = lpOrig;
158
159     TRACE("(%ld,%p,%p)\n", cbSize, lpOrig, lppBuffer);
160
161     if (!lppBuffer || !lpBuff || !--lpBuff)
162         return E_INVALIDARG;
163
164     /* Find the last allocation in the chain */
165     while (*lpBuff)
166     {
167         TRACE("linked:%p->%p\n", lpBuff, *lpBuff);
168         lpBuff = *lpBuff;
169     }
170
171     if (SUCCEEDED(MAPIAllocateBuffer(cbSize, lppBuffer)))
172     {
173         *lpBuff = ((LPMAPIALLOCBUFFER)*lppBuffer) - 1;
174         TRACE("linking %p->%p\n", lpBuff, *lpBuff);
175     }
176     return *lppBuffer ? S_OK : MAPI_E_NOT_ENOUGH_MEMORY;
177 }
178
179 /**************************************************************************
180  *  MAPIFreeBuffer   (MAPI32.16)
181  *  MAPIFreeBuffer@4 (MAPI32.17)
182  *
183  * Free a block of memory and any linked allocations associated with it.
184  *
185  * PARAMS
186  *  lpBuffer [I] Memory to free, returned from MAPIAllocateBuffer()
187  *
188  * RETURNS
189  *  S_OK.
190  */
191 ULONG WINAPI MAPIFreeBuffer(LPVOID lpBuffer)
192 {
193     LPMAPIALLOCBUFFER lpBuff = lpBuffer;
194
195     TRACE("(%p)\n", lpBuffer);
196
197     if (lpBuff && --lpBuff)
198     {
199         while (lpBuff)
200         {
201             LPVOID lpFree = lpBuff;
202
203             lpBuff = *lpBuff;
204
205             TRACE("linked:%p->%p, freeing %p\n", lpFree, lpBuff, lpFree);
206             HeapFree(GetProcessHeap(), 0, lpFree);
207         }
208     }
209     return S_OK;
210 }
211
212 /**************************************************************************
213  *  WrapProgress@20 (MAPI32.41)
214  */
215 HRESULT WINAPI WrapProgress(PVOID unk1, PVOID unk2, PVOID unk3, PVOID unk4, PVOID unk5)
216 {
217     /* Native does not implement this function */
218     return MAPI_E_NO_SUPPORT;
219 }
220
221 /*************************************************************************
222  * HrThisThreadAdviseSink@8 (MAPI32.42)
223  *
224  * Ensure that an advise sink is only notified in its originating thread.
225  *
226  * PARAMS
227  *  lpSink     [I] IMAPIAdviseSink interface to be protected
228  *  lppNewSink [I] Destination for wrapper IMAPIAdviseSink interface
229  *
230  * RETURNS
231  * Success: S_OK. *lppNewSink contains a new sink to use in place of lpSink.
232  * Failure: E_INVALIDARG, if any parameter is invalid.
233  */
234 HRESULT WINAPI HrThisThreadAdviseSink(LPMAPIADVISESINK lpSink, LPMAPIADVISESINK* lppNewSink)
235 {
236     FIXME("(%p,%p)semi-stub\n", lpSink, lppNewSink);
237
238     if (!lpSink || !lppNewSink)
239         return E_INVALIDARG;
240
241     /* Don't wrap the sink for now, just copy it */
242     *lppNewSink = lpSink;
243     IMAPIAdviseSink_AddRef(lpSink);
244     return S_OK;
245 }
246
247 /*************************************************************************
248  * FBinFromHex (MAPI32.44)
249  *
250  * Create an array of binary data from a string.
251  *
252  * PARAMS
253  *  lpszHex [I] String to convert to binary data
254  *  lpOut   [O] Destination for resulting binary data
255  *
256  * RETURNS
257  *  Success: TRUE. lpOut contains the decoded binary data.
258  *  Failure: FALSE, if lpszHex does not represent a binary string.
259  *
260  * NOTES
261  *  - lpOut must be at least half the length of lpszHex in bytes.
262  *  - Although the Mapi headers prototype this function as both
263  *    Ascii and Unicode, there is only one (Ascii) implementation. This
264  *    means that lpszHex is treated as an Ascii string (i.e. a single NUL
265  *    character in the byte stream terminates the string).
266  */
267 BOOL WINAPI FBinFromHex(LPWSTR lpszHex, LPBYTE lpOut)
268 {
269     LPSTR lpStr = (LPSTR)lpszHex;
270
271     TRACE("(%p,%p)\n", lpszHex, lpOut);
272
273     while (*lpStr)
274     {
275         if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff ||
276             lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff)
277             return FALSE;
278
279         *lpOut++ = (digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0'];
280         lpStr += 2;
281     }
282     return TRUE;
283 }
284
285 /*************************************************************************
286  * HexFromBin (MAPI32.45)
287  *
288  * Create a string from an array of binary data.
289  *
290  * PARAMS
291  *  lpHex   [I] Binary data to convert to string
292  *  iCount  [I] Length of lpHex in bytes
293  *  lpszOut [O] Destination for resulting hex string
294  *
295  * RETURNS
296  *  Nothing.
297  *
298  * NOTES
299  *  - lpszOut must be at least 2 * iCount + 1 bytes characters long.
300  *  - Although the Mapi headers prototype this function as both
301  *    Ascii and Unicode, there is only one (Ascii) implementation. This
302  *    means that the resulting string is not properly NUL terminated
303  *    if the caller expects it to be a Unicode string.
304  */
305 void WINAPI HexFromBin(LPBYTE lpHex, int iCount, LPWSTR lpszOut)
306 {
307     static const char hexDigits[] = { "0123456789ABCDEF" };
308     LPSTR lpStr = (LPSTR)lpszOut;
309
310     TRACE("(%p,%d,%p)\n", lpHex, iCount, lpszOut);
311
312     while (iCount-- > 0)
313     {
314         *lpStr++ = hexDigits[*lpHex >> 4];
315         *lpStr++ = hexDigits[*lpHex & 0xf];
316         lpHex++;
317     }
318     *lpStr = '\0';
319 }
320
321 /*************************************************************************
322  * SwapPlong@8 (MAPI32.47)
323  *
324  * Swap the bytes in a ULONG array.
325  *
326  * PARAMS
327  *  lpData [O] Array to swap bytes in
328  *  ulLen  [I] Number of ULONG element to swap the bytes of
329  *
330  * RETURNS
331  *  Nothing.
332  */
333 VOID WINAPI SwapPlong(PULONG lpData, ULONG ulLen)
334 {
335     ULONG i;
336
337     for (i = 0; i < ulLen; i++)
338         lpData[i] = RtlUlongByteSwap(lpData[i]);
339 }
340
341 /*************************************************************************
342  * SwapPword@8 (MAPI32.48)
343  *
344  * Swap the bytes in a USHORT array.
345  *
346  * PARAMS
347  *  lpData [O] Array to swap bytes in
348  *  ulLen  [I] Number of USHORT element to swap the bytes of
349  *
350  * RETURNS
351  *  Nothing.
352  */
353 VOID WINAPI SwapPword(PUSHORT lpData, ULONG ulLen)
354 {
355     ULONG i;
356
357     for (i = 0; i < ulLen; i++)
358         lpData[i] = RtlUshortByteSwap(lpData[i]);
359 }
360
361 /**************************************************************************
362  *  MNLS_lstrlenW@4 (MAPI32.62)
363  *
364  * Calculate the length of a Unicode string.
365  *
366  * PARAMS
367  *  lpszStr [I] String to calculate the length of
368  *
369  * RETURNS
370  *  The length of lpszStr in Unicode characters.
371  */
372 ULONG WINAPI MNLS_lstrlenW(LPCWSTR lpszStr)
373 {
374     TRACE("(%s)\n", debugstr_w(lpszStr));
375     return strlenW(lpszStr);
376 }
377
378 /*************************************************************************
379  * MNLS_lstrcmpW@8 (MAPI32.63)
380  *
381  * Compare two Unicode strings.
382  *
383  * PARAMS
384  *  lpszLeft  [I] First string to compare
385  *  lpszRight [I] Second string to compare
386  *
387  * RETURNS
388  *  An integer less than, equal to or greater than 0, indicating that
389  *  lpszLeft is less than, the same, or greater than lpszRight.
390  */
391 INT WINAPI MNLS_lstrcmpW(LPCWSTR lpszLeft, LPCWSTR lpszRight)
392 {
393     TRACE("(%s,%s)\n", debugstr_w(lpszLeft), debugstr_w(lpszRight));
394     return strcmpW(lpszLeft, lpszRight);
395 }
396
397 /*************************************************************************
398  * MNLS_lstrcpyW@8 (MAPI32.64)
399  *
400  * Copy a Unicode string to another string.
401  *
402  * PARAMS
403  *  lpszDest [O] Destination string
404  *  lpszSrc  [I] Source string
405  *
406  * RETURNS
407  *  The length lpszDest in Unicode characters.
408  */
409 ULONG WINAPI MNLS_lstrcpyW(LPWSTR lpszDest, LPCWSTR lpszSrc)
410 {
411     ULONG len;
412
413     TRACE("(%p,%s)\n", lpszDest, debugstr_w(lpszSrc));
414     len = (strlenW(lpszSrc) + 1) * sizeof(WCHAR);
415     memcpy(lpszDest, lpszSrc, len);
416     return len;
417 }
418
419 /*************************************************************************
420  * MNLS_CompareStringW@12 (MAPI32.65)
421  *
422  * Compare two Unicode strings.
423  *
424  * PARAMS
425  *  dwCp      [I] Code page for the comparison
426  *  lpszLeft  [I] First string to compare
427  *  lpszRight [I] Second string to compare
428  *
429  * RETURNS
430  *  CSTR_LESS_THAN, CSTR_EQUAL or CSTR_GREATER_THAN, indicating that
431  *  lpszLeft is less than, the same, or greater than lpszRight.
432  */
433 INT WINAPI MNLS_CompareStringW(DWORD dwCp, LPCWSTR lpszLeft, LPCWSTR lpszRight)
434 {
435     INT ret;
436
437     TRACE("0x%08lx,%s,%s\n", dwCp, debugstr_w(lpszLeft), debugstr_w(lpszRight));
438     ret = MNLS_lstrcmpW(lpszLeft, lpszRight);
439     return ret < 0 ? CSTR_LESS_THAN : ret ? CSTR_GREATER_THAN : CSTR_EQUAL;
440 }
441
442 /**************************************************************************
443  *  FEqualNames@8 (MAPI32.72)
444  *
445  * Compare two Mapi names.
446  *
447  * PARAMS
448  *  lpName1 [I] First name to compare to lpName2
449  *  lpName2 [I] Second name to compare to lpName1
450  *
451  * RETURNS
452  *  TRUE, if the names are the same,
453  *  FALSE, Otherwise.
454  */
455 BOOL WINAPI FEqualNames(LPMAPINAMEID lpName1, LPMAPINAMEID lpName2)
456 {
457     TRACE("(%p,%p)\n", lpName1, lpName2);
458
459     if (!lpName1 || !lpName2 ||
460         !IsEqualGUID(lpName1->lpguid, lpName2->lpguid) ||
461         lpName1->ulKind != lpName2->ulKind)
462         return FALSE;
463
464     if (lpName1->ulKind == MNID_STRING)
465         return !strcmpW(lpName1->Kind.lpwstrName, lpName2->Kind.lpwstrName);
466
467     return lpName1->Kind.lID == lpName2->Kind.lID ? TRUE : FALSE;
468 }
469
470 /**************************************************************************
471  *  IsBadBoundedStringPtr@8 (MAPI32.71)
472  *
473  * Determine if a string pointer is valid.
474  *
475  * PARAMS
476  *  lpszStr [I] String to check
477  *  ulLen   [I] Maximum length of lpszStr
478  *
479  * RETURNS
480  *  TRUE, if lpszStr is invalid or longer than ulLen,
481  *  FALSE, otherwise.
482  */
483 BOOL WINAPI IsBadBoundedStringPtr(LPCSTR lpszStr, ULONG ulLen)
484 {
485     if (!lpszStr || IsBadStringPtrA(lpszStr, -1) || strlen(lpszStr) >= ulLen)
486         return TRUE;
487     return FALSE;
488 }
489
490 /**************************************************************************
491  *  FtAddFt@16 (MAPI32.121)
492  *
493  * Add two FILETIME's together.
494  *
495  * PARAMS
496  *  ftLeft  [I] FILETIME to add to ftRight
497  *  ftRight [I] FILETIME to add to ftLeft
498  *
499  * RETURNS
500  *  The sum of ftLeft and ftRight
501  */
502 LONGLONG WINAPI MAPI32_FtAddFt(FILETIME ftLeft, FILETIME ftRight)
503 {
504     LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight;
505
506     return *pl + *pr;
507 }
508
509 /**************************************************************************
510  *  FtSubFt@16 (MAPI32.123)
511  *
512  * Subtract two FILETIME's together.
513  *
514  * PARAMS
515  *  ftLeft  [I] Initial FILETIME
516  *  ftRight [I] FILETIME to subtract from ftLeft
517  *
518  * RETURNS
519  *  The remainder after ftRight is subtracted from ftLeft.
520  */
521 LONGLONG WINAPI MAPI32_FtSubFt(FILETIME ftLeft, FILETIME ftRight)
522 {
523     LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight;
524
525     return *pr - *pl;
526 }
527
528 /**************************************************************************
529  *  FtMulDw@12 (MAPI32.124)
530  *
531  * Multiply a FILETIME by a DWORD.
532  *
533  * PARAMS
534  *  dwLeft  [I] DWORD to multiply with ftRight
535  *  ftRight [I] FILETIME to multiply with dwLeft
536  *
537  * RETURNS
538  *  The product of dwLeft and ftRight
539  */
540 LONGLONG WINAPI MAPI32_FtMulDw(DWORD dwLeft, FILETIME ftRight)
541 {
542     LONGLONG *pr = (LONGLONG*)&ftRight;
543
544     return (LONGLONG)dwLeft * (*pr);
545 }
546
547 /**************************************************************************
548  *  FtMulDwDw@8 (MAPI32.125)
549  *
550  * Multiply two DWORD, giving the result as a FILETIME.
551  *
552  * PARAMS
553  *  dwLeft  [I] DWORD to multiply with dwRight
554  *  dwRight [I] DWORD to multiply with dwLeft
555  *
556  * RETURNS
557  *  The product of ftMultiplier and ftMultiplicand as a FILETIME.
558  */
559 LONGLONG WINAPI MAPI32_FtMulDwDw(DWORD dwLeft, DWORD dwRight)
560 {
561     return (LONGLONG)dwLeft * (LONGLONG)dwRight;
562 }
563
564 /**************************************************************************
565  *  FtNegFt@8 (MAPI32.126)
566  *
567  * Negate a FILETIME.
568  *
569  * PARAMS
570  *  ft [I] FILETIME to negate
571  *
572  * RETURNS
573  *  The negation of ft.
574  */
575 LONGLONG WINAPI MAPI32_FtNegFt(FILETIME ft)
576 {
577     LONGLONG *p = (LONGLONG*)&ft;
578
579     return - *p;
580 }
581
582 /**************************************************************************
583  *  UlAddRef@4 (MAPI32.128)
584  *
585  * Add a reference to an object.
586  *
587  * PARAMS
588  *  lpUnk [I] Object to add a reference to.
589  *
590  * RETURNS
591  *  The new reference count of the object, or 0 if lpUnk is NULL.
592  *
593  * NOTES
594  * See IUnknown_AddRef.
595  */
596 ULONG WINAPI UlAddRef(void *lpUnk)
597 {
598     TRACE("(%p)\n", lpUnk);
599
600     if (!lpUnk)
601         return 0UL;
602     return IUnknown_AddRef((LPUNKNOWN)lpUnk);
603 }
604
605 /**************************************************************************
606  *  UlRelease@4 (MAPI32.129)
607  *
608  * Remove a reference from an object.
609  *
610  * PARAMS
611  *  lpUnk [I] Object to remove reference from.
612  *
613  * RETURNS
614  *  The new reference count of the object, or 0 if lpUnk is NULL. If lpUnk is
615  *  non-NULL and this function returns 0, the object pointed to by lpUnk has
616  *  been released.
617  *
618  * NOTES
619  * See IUnknown_Release.
620  */
621 ULONG WINAPI UlRelease(void *lpUnk)
622 {
623     TRACE("(%p)\n", lpUnk);
624
625     if (!lpUnk)
626         return 0UL;
627     return IUnknown_Release((LPUNKNOWN)lpUnk);
628 }
629
630 /**************************************************************************
631  *  UFromSz@4 (MAPI32.133)
632  *
633  * Read an integer from a string
634  *
635  * PARAMS
636  *  lpszStr [I] String to read the integer from.
637  *
638  * RETURNS
639  *  Success: The integer read from lpszStr.
640  *  Failure: 0, if the first character in lpszStr is not 0-9.
641  *
642  * NOTES
643  *  This function does not accept whitespace and stops at the first non-digit
644  *  character.
645  */
646 UINT WINAPI UFromSz(LPCSTR lpszStr)
647 {
648     ULONG ulRet = 0;
649
650     TRACE("(%s)\n", debugstr_a(lpszStr));
651
652     if (lpszStr)
653     {
654         while (*lpszStr >= '0' && *lpszStr <= '9')
655         {
656             ulRet = ulRet * 10 + (*lpszStr - '0');
657             lpszStr = CharNextA(lpszStr);
658         }
659     }
660     return ulRet;
661 }
662
663 /*************************************************************************
664  * OpenStreamOnFile@24 (MAPI32.147)
665  *
666  * Create a stream on a file.
667  *
668  * PARAMS
669  *  lpAlloc    [I] Memory allocation function
670  *  lpFree     [I] Memory free function
671  *  ulFlags    [I] Flags controlling the opening process
672  *  lpszPath   [I] Path of file to create stream on
673  *  lpszPrefix [I] Prefix of the temporary file name (if ulFlags includes SOF_UNIQUEFILENAME)
674  *  lppStream  [O] Destination for created stream
675  *
676  * RETURNS
677  * Success: S_OK. lppStream contains the new stream object
678  * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code
679  *          describing the error.
680  */
681 HRESULT WINAPI OpenStreamOnFile(LPALLOCATEBUFFER lpAlloc, LPFREEBUFFER lpFree,
682                                 ULONG ulFlags, LPWSTR lpszPath, LPWSTR lpszPrefix,
683                                 LPSTREAM *lppStream)
684 {
685     WCHAR szBuff[MAX_PATH];
686     DWORD dwMode = STGM_READWRITE, dwAttributes = 0;
687     HRESULT hRet;
688
689     TRACE("(%p,%p,0x%08lx,%s,%s,%p)\n", lpAlloc, lpFree, ulFlags,
690           debugstr_a((LPSTR)lpszPath), debugstr_a((LPSTR)lpszPrefix), lppStream);
691
692     if (lppStream)
693         *lppStream = NULL;
694
695     if (ulFlags & SOF_UNIQUEFILENAME)
696     {
697         FIXME("Should generate a temporary name\n");
698         return E_INVALIDARG;
699     }
700
701     if (!lpszPath || !lppStream)
702         return E_INVALIDARG;
703
704     /* FIXME: Should probably munge mode and attributes, and should handle
705      *        Unicode arguments (I assume MAPI_UNICODE is set in ulFlags if
706      *        we are being passed Unicode strings; MSDN doesn't say).
707      *        This implementation is just enough for Outlook97 to start.
708      */
709     MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszPath, -1, szBuff, MAX_PATH);
710     hRet = SHCreateStreamOnFileEx(szBuff, dwMode, dwAttributes, TRUE,
711                                   NULL, lppStream);
712     return hRet;
713 }
714
715 /*************************************************************************
716  * UlFromSzHex@4 (MAPI32.155)
717  *
718  * Read an integer from a hexadecimal string.
719  *
720  * PARAMS
721  *  lpSzHex [I] String containing the hexadecimal number to read
722  *
723  * RETURNS
724  * Success: The number represented by lpszHex.
725  * Failure: 0, if lpszHex does not contain a hex string.
726  *
727  * NOTES
728  *  This function does not accept whitespace and stops at the first non-hex
729  *  character.
730  */
731 ULONG WINAPI UlFromSzHex(LPCWSTR lpszHex)
732 {
733     LPSTR lpStr = (LPSTR)lpszHex;
734     ULONG ulRet = 0;
735
736     TRACE("(%s)\n", debugstr_a(lpStr));
737
738     while (*lpStr)
739     {
740         if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff ||
741             lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff)
742             break;
743
744         ulRet = ulRet * 16 + ((digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0']);
745         lpStr += 2;
746     }
747     return ulRet;
748 }
749
750 /************************************************************************
751  * FBadEntryList@4 (MAPI32.190)
752  *
753  * Determine is an entry list is invalid.
754  *
755  * PARAMS
756  *  lpEntryList [I] List to check
757  *
758  * RETURNS
759  *  TRUE, if lpEntryList is invalid,
760  *  FALSE, otherwise.
761  */
762 BOOL WINAPI FBadEntryList(LPENTRYLIST lpEntryList)
763 {
764     ULONG i;
765
766     if (IsBadReadPtr(lpEntryList, sizeof(*lpEntryList)) ||
767         IsBadReadPtr(lpEntryList->lpbin,
768                      lpEntryList->cValues * sizeof(*lpEntryList->lpbin)))
769         return TRUE;
770
771     for (i = 0; i < lpEntryList->cValues; i++)
772         if(IsBadReadPtr(lpEntryList->lpbin[i].lpb, lpEntryList->lpbin[i].cb))
773             return TRUE;
774
775     return FALSE;
776 }
777
778 /*************************************************************************
779  * CbOfEncoded@4 (MAPI32.207)
780  *
781  * Return the length of an encoded string.
782  *
783  * PARAMS
784  *  lpSzEnc [I] Encoded string to get the length of.
785  *
786  * RETURNS
787  * The length of the encoded string in bytes.
788  */
789 ULONG WINAPI CbOfEncoded(LPCSTR lpszEnc)
790 {
791     ULONG ulRet = 0;
792
793     TRACE("(%s)\n", debugstr_a(lpszEnc));
794
795     if (lpszEnc)
796         ulRet = (((strlen(lpszEnc) | 3) >> 2) + 1) * 3;
797     return ulRet;
798 }
799
800 /*************************************************************************
801  * cmc_query_configuration (MAPI32.235)
802  *
803  * Retrieves the configuration information for the installed CMC
804  *
805  * PARAMS
806  *  session          [I]   MAPI session handle
807  *  item             [I]   Enumerated variable that identifies which 
808  *                         configuration information is being requested
809  *  reference        [O]   Buffer where configuration information is written
810  *  config_extensions[I/O] Path of file to create stream on
811  *
812  * RETURNS
813  * A CMD define
814  */
815 CMC_return_code WINAPI cmc_query_configuration(
816   CMC_session_id session,
817   CMC_enum item,
818   CMC_buffer reference,
819   CMC_extension  *config_extensions)
820 {
821         FIXME("stub");
822         return CMC_E_NOT_SUPPORTED;
823 }