xref: /reactos/dll/win32/mapi32/util.c (revision 0623a6f8)
1 /*
2  * MAPI Utility functions
3  *
4  * Copyright 2004 Jon Griffiths
5  * Copyright 2009 Owen Rudge for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <stdarg.h>
23 #include <stdio.h>
24 
25 #define COBJMACROS
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winreg.h"
30 #include "winuser.h"
31 #include "winerror.h"
32 #include "winternl.h"
33 #include "objbase.h"
34 #include "shlwapi.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "mapival.h"
38 #include "xcmc.h"
39 #include "msi.h"
40 #include "util.h"
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(mapi);
43 
44 static const BYTE digitsToHex[] = {
45   0,1,2,3,4,5,6,7,8,9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,14,15,
46   0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
47   0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,
48   14,15 };
49 
50 MAPI_FUNCTIONS mapiFunctions;
51 
52 /**************************************************************************
53  *  ScInitMapiUtil (MAPI32.33)
54  *
55  * Initialise Mapi utility functions.
56  *
57  * PARAMS
58  *  ulReserved [I] Reserved, pass 0.
59  *
60  * RETURNS
61  *  Success: S_OK. Mapi utility functions may be called.
62  *  Failure: MAPI_E_INVALID_PARAMETER, if ulReserved is not 0.
63  *
64  * NOTES
65  *  Your application does not need to call this function unless it does not
66  *  call MAPIInitialize()/MAPIUninitialize().
67  */
68 SCODE WINAPI ScInitMapiUtil(ULONG ulReserved)
69 {
70     if (mapiFunctions.ScInitMapiUtil)
71         return mapiFunctions.ScInitMapiUtil(ulReserved);
72 
73     FIXME("(0x%08x)stub!\n", ulReserved);
74     if (ulReserved)
75         return MAPI_E_INVALID_PARAMETER;
76     return S_OK;
77 }
78 
79 /**************************************************************************
80  *  DeinitMapiUtil (MAPI32.34)
81  *
82  * Uninitialise Mapi utility functions.
83  *
84  * PARAMS
85  *  None.
86  *
87  * RETURNS
88  *  Nothing.
89  *
90  * NOTES
91  *  Your application does not need to call this function unless it does not
92  *  call MAPIInitialize()/MAPIUninitialize().
93  */
94 VOID WINAPI DeinitMapiUtil(void)
95 {
96     if (mapiFunctions.DeinitMapiUtil)
97         mapiFunctions.DeinitMapiUtil();
98     else
99         FIXME("()stub!\n");
100 }
101 
102 typedef LPVOID *LPMAPIALLOCBUFFER;
103 
104 /**************************************************************************
105  *  MAPIAllocateBuffer   (MAPI32.12)
106  *  MAPIAllocateBuffer@8 (MAPI32.13)
107  *
108  * Allocate a block of memory.
109  *
110  * PARAMS
111  *  cbSize    [I] Size of the block to allocate in bytes
112  *  lppBuffer [O] Destination for pointer to allocated memory
113  *
114  * RETURNS
115  *  Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
116  *           length cbSize bytes.
117  *  Failure: MAPI_E_INVALID_PARAMETER, if lppBuffer is NULL.
118  *           MAPI_E_NOT_ENOUGH_MEMORY, if the memory allocation fails.
119  *
120  * NOTES
121  *  Memory allocated with this function should be freed with MAPIFreeBuffer().
122  *  Further allocations of memory may be linked to the pointer returned using
123  *  MAPIAllocateMore(). Linked allocations are freed when the initial pointer
124  *  is feed.
125  */
126 SCODE WINAPI MAPIAllocateBuffer(ULONG cbSize, LPVOID *lppBuffer)
127 {
128     LPMAPIALLOCBUFFER lpBuff;
129 
130     TRACE("(%d,%p)\n", cbSize, lppBuffer);
131 
132     if (mapiFunctions.MAPIAllocateBuffer)
133         return mapiFunctions.MAPIAllocateBuffer(cbSize, lppBuffer);
134 
135     if (!lppBuffer)
136         return E_INVALIDARG;
137 
138     lpBuff = HeapAlloc(GetProcessHeap(), 0, cbSize + sizeof(*lpBuff));
139     if (!lpBuff)
140         return MAPI_E_NOT_ENOUGH_MEMORY;
141 
142     TRACE("initial allocation:%p, returning %p\n", lpBuff, lpBuff + 1);
143     *lpBuff++ = NULL;
144     *lppBuffer = lpBuff;
145     return S_OK;
146 }
147 
148 /**************************************************************************
149  *  MAPIAllocateMore    (MAPI32.14)
150  *  MAPIAllocateMore@12 (MAPI32.15)
151  *
152  * Allocate a block of memory linked to a previous allocation.
153  *
154  * PARAMS
155  *  cbSize    [I] Size of the block to allocate in bytes
156  *  lpOrig    [I] Initial allocation to link to, from MAPIAllocateBuffer()
157  *  lppBuffer [O] Destination for pointer to allocated memory
158  *
159  * RETURNS
160  *  Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
161  *           length cbSize bytes.
162  *  Failure: MAPI_E_INVALID_PARAMETER, if lpOrig or lppBuffer is invalid.
163  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
164  *
165  * NOTES
166  *  Memory allocated with this function and stored in *lppBuffer is freed
167  *  when lpOrig is passed to MAPIFreeBuffer(). It should not be freed independently.
168  */
169 SCODE WINAPI MAPIAllocateMore(ULONG cbSize, LPVOID lpOrig, LPVOID *lppBuffer)
170 {
171     LPMAPIALLOCBUFFER lpBuff = lpOrig;
172 
173     TRACE("(%d,%p,%p)\n", cbSize, lpOrig, lppBuffer);
174 
175     if (mapiFunctions.MAPIAllocateMore)
176         return mapiFunctions.MAPIAllocateMore(cbSize, lpOrig, lppBuffer);
177 
178     if (!lppBuffer || !lpBuff || !--lpBuff)
179         return E_INVALIDARG;
180 
181     /* Find the last allocation in the chain */
182     while (*lpBuff)
183     {
184         TRACE("linked:%p->%p\n", lpBuff, *lpBuff);
185         lpBuff = *lpBuff;
186     }
187 
188     if (SUCCEEDED(MAPIAllocateBuffer(cbSize, lppBuffer)))
189     {
190         *lpBuff = ((LPMAPIALLOCBUFFER)*lppBuffer) - 1;
191         TRACE("linking %p->%p\n", lpBuff, *lpBuff);
192     }
193     return *lppBuffer ? S_OK : MAPI_E_NOT_ENOUGH_MEMORY;
194 }
195 
196 /**************************************************************************
197  *  MAPIFreeBuffer   (MAPI32.16)
198  *  MAPIFreeBuffer@4 (MAPI32.17)
199  *
200  * Free a block of memory and any linked allocations associated with it.
201  *
202  * PARAMS
203  *  lpBuffer [I] Memory to free, returned from MAPIAllocateBuffer()
204  *
205  * RETURNS
206  *  S_OK.
207  */
208 ULONG WINAPI MAPIFreeBuffer(LPVOID lpBuffer)
209 {
210     LPMAPIALLOCBUFFER lpBuff = lpBuffer;
211 
212     TRACE("(%p)\n", lpBuffer);
213 
214     if (mapiFunctions.MAPIFreeBuffer)
215         return mapiFunctions.MAPIFreeBuffer(lpBuffer);
216 
217     if (lpBuff && --lpBuff)
218     {
219         while (lpBuff)
220         {
221             LPVOID lpFree = lpBuff;
222 
223             lpBuff = *lpBuff;
224 
225             TRACE("linked:%p->%p, freeing %p\n", lpFree, lpBuff, lpFree);
226             HeapFree(GetProcessHeap(), 0, lpFree);
227         }
228     }
229     return S_OK;
230 }
231 
232 /**************************************************************************
233  *  WrapProgress@20 (MAPI32.41)
234  */
235 HRESULT WINAPI WrapProgress(PVOID unk1, PVOID unk2, PVOID unk3, PVOID unk4, PVOID unk5)
236 {
237     /* Native does not implement this function */
238     return MAPI_E_NO_SUPPORT;
239 }
240 
241 /*************************************************************************
242  * HrDispatchNotifications@4 (MAPI32.239)
243  */
244 HRESULT WINAPI HrDispatchNotifications(ULONG flags)
245 {
246     FIXME("(%08x)\n", flags);
247     return S_OK;
248 }
249 
250 /*************************************************************************
251  * HrThisThreadAdviseSink@8 (MAPI32.42)
252  *
253  * Ensure that an advise sink is only notified in its originating thread.
254  *
255  * PARAMS
256  *  lpSink     [I] IMAPIAdviseSink interface to be protected
257  *  lppNewSink [I] Destination for wrapper IMAPIAdviseSink interface
258  *
259  * RETURNS
260  * Success: S_OK. *lppNewSink contains a new sink to use in place of lpSink.
261  * Failure: E_INVALIDARG, if any parameter is invalid.
262  */
263 HRESULT WINAPI HrThisThreadAdviseSink(LPMAPIADVISESINK lpSink, LPMAPIADVISESINK* lppNewSink)
264 {
265     if (mapiFunctions.HrThisThreadAdviseSink)
266         return mapiFunctions.HrThisThreadAdviseSink(lpSink, lppNewSink);
267 
268     FIXME("(%p,%p)semi-stub\n", lpSink, lppNewSink);
269 
270     if (!lpSink || !lppNewSink)
271         return E_INVALIDARG;
272 
273     /* Don't wrap the sink for now, just copy it */
274     *lppNewSink = lpSink;
275     IMAPIAdviseSink_AddRef(lpSink);
276     return S_OK;
277 }
278 
279 /*************************************************************************
280  * FBinFromHex (MAPI32.44)
281  *
282  * Create an array of binary data from a string.
283  *
284  * PARAMS
285  *  lpszHex [I] String to convert to binary data
286  *  lpOut   [O] Destination for resulting binary data
287  *
288  * RETURNS
289  *  Success: TRUE. lpOut contains the decoded binary data.
290  *  Failure: FALSE, if lpszHex does not represent a binary string.
291  *
292  * NOTES
293  *  - lpOut must be at least half the length of lpszHex in bytes.
294  *  - Although the Mapi headers prototype this function as both
295  *    Ascii and Unicode, there is only one (Ascii) implementation. This
296  *    means that lpszHex is treated as an Ascii string (i.e. a single NUL
297  *    character in the byte stream terminates the string).
298  */
299 BOOL WINAPI FBinFromHex(LPWSTR lpszHex, LPBYTE lpOut)
300 {
301     LPSTR lpStr = (LPSTR)lpszHex;
302 
303     TRACE("(%p,%p)\n", lpszHex, lpOut);
304 
305     while (*lpStr)
306     {
307         if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff ||
308             lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff)
309             return FALSE;
310 
311         *lpOut++ = (digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0'];
312         lpStr += 2;
313     }
314     return TRUE;
315 }
316 
317 /*************************************************************************
318  * HexFromBin (MAPI32.45)
319  *
320  * Create a string from an array of binary data.
321  *
322  * PARAMS
323  *  lpHex   [I] Binary data to convert to string
324  *  iCount  [I] Length of lpHex in bytes
325  *  lpszOut [O] Destination for resulting hex string
326  *
327  * RETURNS
328  *  Nothing.
329  *
330  * NOTES
331  *  - lpszOut must be at least 2 * iCount + 1 bytes characters long.
332  *  - Although the Mapi headers prototype this function as both
333  *    Ascii and Unicode, there is only one (Ascii) implementation. This
334  *    means that the resulting string is not properly NUL terminated
335  *    if the caller expects it to be a Unicode string.
336  */
337 void WINAPI HexFromBin(LPBYTE lpHex, int iCount, LPWSTR lpszOut)
338 {
339     static const char hexDigits[] = { "0123456789ABCDEF" };
340     LPSTR lpStr = (LPSTR)lpszOut;
341 
342     TRACE("(%p,%d,%p)\n", lpHex, iCount, lpszOut);
343 
344     while (iCount-- > 0)
345     {
346         *lpStr++ = hexDigits[*lpHex >> 4];
347         *lpStr++ = hexDigits[*lpHex & 0xf];
348         lpHex++;
349     }
350     *lpStr = '\0';
351 }
352 
353 /*************************************************************************
354  * SwapPlong@8 (MAPI32.47)
355  *
356  * Swap the bytes in a ULONG array.
357  *
358  * PARAMS
359  *  lpData [O] Array to swap bytes in
360  *  ulLen  [I] Number of ULONG element to swap the bytes of
361  *
362  * RETURNS
363  *  Nothing.
364  */
365 VOID WINAPI SwapPlong(PULONG lpData, ULONG ulLen)
366 {
367     ULONG i;
368 
369     for (i = 0; i < ulLen; i++)
370         lpData[i] = RtlUlongByteSwap(lpData[i]);
371 }
372 
373 /*************************************************************************
374  * SwapPword@8 (MAPI32.48)
375  *
376  * Swap the bytes in a USHORT array.
377  *
378  * PARAMS
379  *  lpData [O] Array to swap bytes in
380  *  ulLen  [I] Number of USHORT element to swap the bytes of
381  *
382  * RETURNS
383  *  Nothing.
384  */
385 VOID WINAPI SwapPword(PUSHORT lpData, ULONG ulLen)
386 {
387     ULONG i;
388 
389     for (i = 0; i < ulLen; i++)
390         lpData[i] = RtlUshortByteSwap(lpData[i]);
391 }
392 
393 /**************************************************************************
394  *  MNLS_lstrlenW@4 (MAPI32.62)
395  *
396  * Calculate the length of a Unicode string.
397  *
398  * PARAMS
399  *  lpszStr [I] String to calculate the length of
400  *
401  * RETURNS
402  *  The length of lpszStr in Unicode characters.
403  */
404 ULONG WINAPI MNLS_lstrlenW(LPCWSTR lpszStr)
405 {
406     TRACE("(%s)\n", debugstr_w(lpszStr));
407     return strlenW(lpszStr);
408 }
409 
410 /*************************************************************************
411  * MNLS_lstrcmpW@8 (MAPI32.63)
412  *
413  * Compare two Unicode strings.
414  *
415  * PARAMS
416  *  lpszLeft  [I] First string to compare
417  *  lpszRight [I] Second string to compare
418  *
419  * RETURNS
420  *  An integer less than, equal to or greater than 0, indicating that
421  *  lpszLeft is less than, the same, or greater than lpszRight.
422  */
423 INT WINAPI MNLS_lstrcmpW(LPCWSTR lpszLeft, LPCWSTR lpszRight)
424 {
425     TRACE("(%s,%s)\n", debugstr_w(lpszLeft), debugstr_w(lpszRight));
426     return strcmpW(lpszLeft, lpszRight);
427 }
428 
429 /*************************************************************************
430  * MNLS_lstrcpyW@8 (MAPI32.64)
431  *
432  * Copy a Unicode string to another string.
433  *
434  * PARAMS
435  *  lpszDest [O] Destination string
436  *  lpszSrc  [I] Source string
437  *
438  * RETURNS
439  *  The length lpszDest in Unicode characters.
440  */
441 ULONG WINAPI MNLS_lstrcpyW(LPWSTR lpszDest, LPCWSTR lpszSrc)
442 {
443     ULONG len;
444 
445     TRACE("(%p,%s)\n", lpszDest, debugstr_w(lpszSrc));
446     len = (strlenW(lpszSrc) + 1) * sizeof(WCHAR);
447     memcpy(lpszDest, lpszSrc, len);
448     return len;
449 }
450 
451 /*************************************************************************
452  * MNLS_CompareStringW@12 (MAPI32.65)
453  *
454  * Compare two Unicode strings.
455  *
456  * PARAMS
457  *  dwCp      [I] Code page for the comparison
458  *  lpszLeft  [I] First string to compare
459  *  lpszRight [I] Second string to compare
460  *
461  * RETURNS
462  *  CSTR_LESS_THAN, CSTR_EQUAL or CSTR_GREATER_THAN, indicating that
463  *  lpszLeft is less than, the same, or greater than lpszRight.
464  */
465 INT WINAPI MNLS_CompareStringW(DWORD dwCp, LPCWSTR lpszLeft, LPCWSTR lpszRight)
466 {
467     INT ret;
468 
469     TRACE("0x%08x,%s,%s\n", dwCp, debugstr_w(lpszLeft), debugstr_w(lpszRight));
470     ret = MNLS_lstrcmpW(lpszLeft, lpszRight);
471     return ret < 0 ? CSTR_LESS_THAN : ret ? CSTR_GREATER_THAN : CSTR_EQUAL;
472 }
473 
474 /**************************************************************************
475  *  FEqualNames@8 (MAPI32.72)
476  *
477  * Compare two Mapi names.
478  *
479  * PARAMS
480  *  lpName1 [I] First name to compare to lpName2
481  *  lpName2 [I] Second name to compare to lpName1
482  *
483  * RETURNS
484  *  TRUE, if the names are the same,
485  *  FALSE, Otherwise.
486  */
487 BOOL WINAPI FEqualNames(LPMAPINAMEID lpName1, LPMAPINAMEID lpName2)
488 {
489     TRACE("(%p,%p)\n", lpName1, lpName2);
490 
491     if (!lpName1 || !lpName2 ||
492         !IsEqualGUID(lpName1->lpguid, lpName2->lpguid) ||
493         lpName1->ulKind != lpName2->ulKind)
494         return FALSE;
495 
496     if (lpName1->ulKind == MNID_STRING)
497         return !strcmpW(lpName1->Kind.lpwstrName, lpName2->Kind.lpwstrName);
498 
499     return lpName1->Kind.lID == lpName2->Kind.lID;
500 }
501 
502 /**************************************************************************
503  *  IsBadBoundedStringPtr@8 (MAPI32.71)
504  *
505  * Determine if a string pointer is valid.
506  *
507  * PARAMS
508  *  lpszStr [I] String to check
509  *  ulLen   [I] Maximum length of lpszStr
510  *
511  * RETURNS
512  *  TRUE, if lpszStr is invalid or longer than ulLen,
513  *  FALSE, otherwise.
514  */
515 BOOL WINAPI IsBadBoundedStringPtr(LPCSTR lpszStr, ULONG ulLen)
516 {
517     if (!lpszStr || IsBadStringPtrA(lpszStr, -1) || strlen(lpszStr) >= ulLen)
518         return TRUE;
519     return FALSE;
520 }
521 
522 /**************************************************************************
523  *  FtAddFt@16 (MAPI32.121)
524  *
525  * Add two FILETIME's together.
526  *
527  * PARAMS
528  *  ftLeft  [I] FILETIME to add to ftRight
529  *  ftRight [I] FILETIME to add to ftLeft
530  *
531  * RETURNS
532  *  The sum of ftLeft and ftRight
533  */
534 LONGLONG WINAPI MAPI32_FtAddFt(FILETIME ftLeft, FILETIME ftRight)
535 {
536     LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight;
537 
538     return *pl + *pr;
539 }
540 
541 /**************************************************************************
542  *  FtSubFt@16 (MAPI32.123)
543  *
544  * Subtract two FILETIME's together.
545  *
546  * PARAMS
547  *  ftLeft  [I] Initial FILETIME
548  *  ftRight [I] FILETIME to subtract from ftLeft
549  *
550  * RETURNS
551  *  The remainder after ftRight is subtracted from ftLeft.
552  */
553 LONGLONG WINAPI MAPI32_FtSubFt(FILETIME ftLeft, FILETIME ftRight)
554 {
555     LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight;
556 
557     return *pr - *pl;
558 }
559 
560 /**************************************************************************
561  *  FtMulDw@12 (MAPI32.124)
562  *
563  * Multiply a FILETIME by a DWORD.
564  *
565  * PARAMS
566  *  dwLeft  [I] DWORD to multiply with ftRight
567  *  ftRight [I] FILETIME to multiply with dwLeft
568  *
569  * RETURNS
570  *  The product of dwLeft and ftRight
571  */
572 LONGLONG WINAPI MAPI32_FtMulDw(DWORD dwLeft, FILETIME ftRight)
573 {
574     LONGLONG *pr = (LONGLONG*)&ftRight;
575 
576     return (LONGLONG)dwLeft * (*pr);
577 }
578 
579 /**************************************************************************
580  *  FtMulDwDw@8 (MAPI32.125)
581  *
582  * Multiply two DWORD, giving the result as a FILETIME.
583  *
584  * PARAMS
585  *  dwLeft  [I] DWORD to multiply with dwRight
586  *  dwRight [I] DWORD to multiply with dwLeft
587  *
588  * RETURNS
589  *  The product of ftMultiplier and ftMultiplicand as a FILETIME.
590  */
591 LONGLONG WINAPI MAPI32_FtMulDwDw(DWORD dwLeft, DWORD dwRight)
592 {
593     return (LONGLONG)dwLeft * (LONGLONG)dwRight;
594 }
595 
596 /**************************************************************************
597  *  FtNegFt@8 (MAPI32.126)
598  *
599  * Negate a FILETIME.
600  *
601  * PARAMS
602  *  ft [I] FILETIME to negate
603  *
604  * RETURNS
605  *  The negation of ft.
606  */
607 LONGLONG WINAPI MAPI32_FtNegFt(FILETIME ft)
608 {
609     LONGLONG *p = (LONGLONG*)&ft;
610 
611     return - *p;
612 }
613 
614 /**************************************************************************
615  *  UlAddRef@4 (MAPI32.128)
616  *
617  * Add a reference to an object.
618  *
619  * PARAMS
620  *  lpUnk [I] Object to add a reference to.
621  *
622  * RETURNS
623  *  The new reference count of the object, or 0 if lpUnk is NULL.
624  *
625  * NOTES
626  * See IUnknown_AddRef.
627  */
628 ULONG WINAPI UlAddRef(void *lpUnk)
629 {
630     TRACE("(%p)\n", lpUnk);
631 
632     if (!lpUnk)
633         return 0UL;
634     return IUnknown_AddRef((LPUNKNOWN)lpUnk);
635 }
636 
637 /**************************************************************************
638  *  UlRelease@4 (MAPI32.129)
639  *
640  * Remove a reference from an object.
641  *
642  * PARAMS
643  *  lpUnk [I] Object to remove reference from.
644  *
645  * RETURNS
646  *  The new reference count of the object, or 0 if lpUnk is NULL. If lpUnk is
647  *  non-NULL and this function returns 0, the object pointed to by lpUnk has
648  *  been released.
649  *
650  * NOTES
651  * See IUnknown_Release.
652  */
653 ULONG WINAPI UlRelease(void *lpUnk)
654 {
655     TRACE("(%p)\n", lpUnk);
656 
657     if (!lpUnk)
658         return 0UL;
659     return IUnknown_Release((LPUNKNOWN)lpUnk);
660 }
661 
662 /**************************************************************************
663  *  UFromSz@4 (MAPI32.133)
664  *
665  * Read an integer from a string
666  *
667  * PARAMS
668  *  lpszStr [I] String to read the integer from.
669  *
670  * RETURNS
671  *  Success: The integer read from lpszStr.
672  *  Failure: 0, if the first character in lpszStr is not 0-9.
673  *
674  * NOTES
675  *  This function does not accept whitespace and stops at the first non-digit
676  *  character.
677  */
678 UINT WINAPI UFromSz(LPCSTR lpszStr)
679 {
680     ULONG ulRet = 0;
681 
682     TRACE("(%s)\n", debugstr_a(lpszStr));
683 
684     if (lpszStr)
685     {
686         while (*lpszStr >= '0' && *lpszStr <= '9')
687         {
688             ulRet = ulRet * 10 + (*lpszStr - '0');
689             lpszStr++;
690         }
691     }
692     return ulRet;
693 }
694 
695 /*************************************************************************
696  * OpenStreamOnFile@24 (MAPI32.147)
697  *
698  * Create a stream on a file.
699  *
700  * PARAMS
701  *  lpAlloc    [I] Memory allocation function
702  *  lpFree     [I] Memory free function
703  *  ulFlags    [I] Flags controlling the opening process
704  *  lpszPath   [I] Path of file to create stream on
705  *  lpszPrefix [I] Prefix of the temporary file name (if ulFlags includes SOF_UNIQUEFILENAME)
706  *  lppStream  [O] Destination for created stream
707  *
708  * RETURNS
709  * Success: S_OK. lppStream contains the new stream object
710  * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code
711  *          describing the error.
712  */
713 HRESULT WINAPI OpenStreamOnFile(LPALLOCATEBUFFER lpAlloc, LPFREEBUFFER lpFree,
714                                 ULONG ulFlags, LPWSTR lpszPath, LPWSTR lpszPrefix,
715                                 LPSTREAM *lppStream)
716 {
717     WCHAR szBuff[MAX_PATH];
718     DWORD dwMode = STGM_READWRITE, dwAttributes = 0;
719     HRESULT hRet;
720 
721     TRACE("(%p,%p,0x%08x,%s,%s,%p)\n", lpAlloc, lpFree, ulFlags,
722           debugstr_a((LPSTR)lpszPath), debugstr_a((LPSTR)lpszPrefix), lppStream);
723 
724     if (mapiFunctions.OpenStreamOnFile)
725         return mapiFunctions.OpenStreamOnFile(lpAlloc, lpFree, ulFlags, lpszPath, lpszPrefix, lppStream);
726 
727     if (lppStream)
728         *lppStream = NULL;
729 
730     if (ulFlags & SOF_UNIQUEFILENAME)
731     {
732         FIXME("Should generate a temporary name\n");
733         return E_INVALIDARG;
734     }
735 
736     if (!lpszPath || !lppStream)
737         return E_INVALIDARG;
738 
739     /* FIXME: Should probably munge mode and attributes, and should handle
740      *        Unicode arguments (I assume MAPI_UNICODE is set in ulFlags if
741      *        we are being passed Unicode strings; MSDN doesn't say).
742      *        This implementation is just enough for Outlook97 to start.
743      */
744     MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszPath, -1, szBuff, MAX_PATH);
745     hRet = SHCreateStreamOnFileEx(szBuff, dwMode, dwAttributes, TRUE,
746                                   NULL, lppStream);
747     return hRet;
748 }
749 
750 /*************************************************************************
751  * UlFromSzHex@4 (MAPI32.155)
752  *
753  * Read an integer from a hexadecimal string.
754  *
755  * PARAMS
756  *  lpSzHex [I] String containing the hexadecimal number to read
757  *
758  * RETURNS
759  * Success: The number represented by lpszHex.
760  * Failure: 0, if lpszHex does not contain a hex string.
761  *
762  * NOTES
763  *  This function does not accept whitespace and stops at the first non-hex
764  *  character.
765  */
766 ULONG WINAPI UlFromSzHex(LPCWSTR lpszHex)
767 {
768     LPCSTR lpStr = (LPCSTR)lpszHex;
769     ULONG ulRet = 0;
770 
771     TRACE("(%s)\n", debugstr_a(lpStr));
772 
773     while (*lpStr)
774     {
775         if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff ||
776             lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff)
777             break;
778 
779         ulRet = ulRet * 16 + ((digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0']);
780         lpStr += 2;
781     }
782     return ulRet;
783 }
784 
785 /************************************************************************
786  * FBadEntryList@4 (MAPI32.190)
787  *
788  * Determine is an entry list is invalid.
789  *
790  * PARAMS
791  *  lpEntryList [I] List to check
792  *
793  * RETURNS
794  *  TRUE, if lpEntryList is invalid,
795  *  FALSE, otherwise.
796  */
797 BOOL WINAPI FBadEntryList(LPENTRYLIST lpEntryList)
798 {
799     ULONG i;
800 
801     if (IsBadReadPtr(lpEntryList, sizeof(*lpEntryList)) ||
802         IsBadReadPtr(lpEntryList->lpbin,
803                      lpEntryList->cValues * sizeof(*lpEntryList->lpbin)))
804         return TRUE;
805 
806     for (i = 0; i < lpEntryList->cValues; i++)
807         if(IsBadReadPtr(lpEntryList->lpbin[i].lpb, lpEntryList->lpbin[i].cb))
808             return TRUE;
809 
810     return FALSE;
811 }
812 
813 /*************************************************************************
814  * CbOfEncoded@4 (MAPI32.207)
815  *
816  * Return the length of an encoded string.
817  *
818  * PARAMS
819  *  lpSzEnc [I] Encoded string to get the length of.
820  *
821  * RETURNS
822  * The length of the encoded string in bytes.
823  */
824 ULONG WINAPI CbOfEncoded(LPCSTR lpszEnc)
825 {
826     ULONG ulRet = 0;
827 
828     TRACE("(%s)\n", debugstr_a(lpszEnc));
829 
830     if (lpszEnc)
831         ulRet = (((strlen(lpszEnc) | 3) >> 2) + 1) * 3;
832     return ulRet;
833 }
834 
835 /*************************************************************************
836  * cmc_query_configuration (MAPI32.235)
837  *
838  * Retrieves the configuration information for the installed CMC
839  *
840  * PARAMS
841  *  session          [I]   MAPI session handle
842  *  item             [I]   Enumerated variable that identifies which
843  *                         configuration information is being requested
844  *  reference        [O]   Buffer where configuration information is written
845  *  config_extensions[I/O] Path of file to create stream on
846  *
847  * RETURNS
848  * A CMD define
849  */
850 CMC_return_code WINAPI cmc_query_configuration(
851   CMC_session_id session,
852   CMC_enum item,
853   CMC_buffer reference,
854   CMC_extension  *config_extensions)
855 {
856 	FIXME("stub\n");
857 	return CMC_E_NOT_SUPPORTED;
858 }
859 
860 /**************************************************************************
861  *  FGetComponentPath   (MAPI32.254)
862  *  FGetComponentPath@20 (MAPI32.255)
863  *
864  * Return the installed component path, usually to the private mapi32.dll.
865  *
866  * PARAMS
867  *  component       [I] Component ID
868  *  qualifier       [I] Application LCID
869  *  dll_path        [O] returned component path
870  *  dll_path_length [I] component path length
871  *  install         [I] install mode
872  *
873  * RETURNS
874  *  Success: TRUE.
875  *  Failure: FALSE.
876  *
877  * NOTES
878  *  Previously documented in Q229700 "How to locate the correct path
879  *  to the Mapisvc.inf file in Microsoft Outlook".
880  */
881 BOOL WINAPI FGetComponentPath(LPCSTR component, LPCSTR qualifier, LPSTR dll_path,
882                               DWORD dll_path_length, BOOL install)
883 {
884     BOOL ret = FALSE;
885     HMODULE hmsi;
886 
887     TRACE("%s %s %p %u %d\n", component, qualifier, dll_path, dll_path_length, install);
888 
889     if (mapiFunctions.FGetComponentPath)
890         return mapiFunctions.FGetComponentPath(component, qualifier, dll_path, dll_path_length, install);
891 
892     dll_path[0] = 0;
893 
894     hmsi = LoadLibraryA("msi.dll");
895     if (hmsi)
896     {
897         UINT (WINAPI *pMsiProvideQualifiedComponentA)(LPCSTR, LPCSTR, DWORD, LPSTR, LPDWORD);
898 
899         pMsiProvideQualifiedComponentA = (void *)GetProcAddress(hmsi, "MsiProvideQualifiedComponentA");
900         if (pMsiProvideQualifiedComponentA)
901         {
902             static const char * const fmt[] = { "%d\\NT", "%d\\95", "%d" };
903             char lcid_ver[20];
904             UINT i;
905 
906             for (i = 0; i < sizeof(fmt)/sizeof(fmt[0]); i++)
907             {
908                 /* FIXME: what's the correct behaviour here? */
909                 if (!qualifier || qualifier == lcid_ver)
910                 {
911                     sprintf(lcid_ver, fmt[i], GetUserDefaultUILanguage());
912                     qualifier = lcid_ver;
913                 }
914 
915                 if (pMsiProvideQualifiedComponentA(component, qualifier,
916                         install ? INSTALLMODE_DEFAULT : INSTALLMODE_EXISTING,
917                         dll_path, &dll_path_length) == ERROR_SUCCESS)
918                 {
919                     ret = TRUE;
920                     break;
921                 }
922 
923                 if (qualifier != lcid_ver) break;
924             }
925         }
926         FreeLibrary(hmsi);
927     }
928     return ret;
929 }
930 
931 /**************************************************************************
932  *  HrQueryAllRows   (MAPI32.75)
933  */
934 HRESULT WINAPI HrQueryAllRows(LPMAPITABLE lpTable, LPSPropTagArray lpPropTags,
935     LPSRestriction lpRestriction, LPSSortOrderSet lpSortOrderSet,
936     LONG crowsMax, LPSRowSet *lppRows)
937 {
938     if (mapiFunctions.HrQueryAllRows)
939         return mapiFunctions.HrQueryAllRows(lpTable, lpPropTags, lpRestriction, lpSortOrderSet, crowsMax, lppRows);
940 
941     FIXME("(%p, %p, %p, %p, %d, %p): stub\n", lpTable, lpPropTags, lpRestriction, lpSortOrderSet, crowsMax, lppRows);
942     *lppRows = NULL;
943     return MAPI_E_CALL_FAILED;
944 }
945 
946 /**************************************************************************
947  *  WrapCompressedRTFStream   (MAPI32.186)
948  */
949 HRESULT WINAPI WrapCompressedRTFStream(LPSTREAM compressed, ULONG flags, LPSTREAM *uncompressed)
950 {
951     if (mapiFunctions.WrapCompressedRTFStream)
952         return mapiFunctions.WrapCompressedRTFStream(compressed, flags, uncompressed);
953 
954     FIXME("(%p, 0x%08x, %p): stub\n", compressed, flags, uncompressed);
955     return MAPI_E_NO_SUPPORT;
956 }
957 
958 static HMODULE mapi_provider;
959 static HMODULE mapi_ex_provider;
960 
961 /**************************************************************************
962  *  load_mapi_provider
963  *
964  * Attempts to load a MAPI provider from the specified registry key.
965  *
966  * Returns a handle to the loaded module in `mapi_provider' if successful.
967  */
968 static void load_mapi_provider(HKEY hkeyMail, LPCWSTR valueName, HMODULE *mapi_provider)
969 {
970     static const WCHAR mapi32_dll[] = {'m','a','p','i','3','2','.','d','l','l',0 };
971 
972     DWORD dwType, dwLen = 0;
973     LPWSTR dllPath;
974 
975     /* Check if we have a value set for DLLPath */
976     if ((RegQueryValueExW(hkeyMail, valueName, NULL, &dwType, NULL, &dwLen) == ERROR_SUCCESS) &&
977         ((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)) && (dwLen > 0))
978     {
979         dllPath = HeapAlloc(GetProcessHeap(), 0, dwLen);
980 
981         if (dllPath)
982         {
983             RegQueryValueExW(hkeyMail, valueName, NULL, NULL, (LPBYTE)dllPath, &dwLen);
984 
985             /* Check that this value doesn't refer to mapi32.dll (eg, as Outlook does) */
986             if (lstrcmpiW(dllPath, mapi32_dll) != 0)
987             {
988                 if (dwType == REG_EXPAND_SZ)
989                 {
990                     DWORD dwExpandLen;
991                     LPWSTR dllPathExpanded;
992 
993                     /* Expand the path if necessary */
994                     dwExpandLen = ExpandEnvironmentStringsW(dllPath, NULL, 0);
995                     dllPathExpanded = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * dwExpandLen + 1);
996 
997                     if (dllPathExpanded)
998                     {
999                         ExpandEnvironmentStringsW(dllPath, dllPathExpanded, dwExpandLen + 1);
1000 
1001                         HeapFree(GetProcessHeap(), 0, dllPath);
1002                         dllPath = dllPathExpanded;
1003                     }
1004                 }
1005 
1006                 /* Load the DLL */
1007                 TRACE("loading %s\n", debugstr_w(dllPath));
1008                 *mapi_provider = LoadLibraryW(dllPath);
1009             }
1010 
1011             HeapFree(GetProcessHeap(), 0, dllPath);
1012         }
1013     }
1014 }
1015 
1016 /**************************************************************************
1017  *  load_mapi_providers
1018  *
1019  * Scans the registry for MAPI providers and attempts to load a Simple and
1020  * Extended MAPI library.
1021  *
1022  * Returns TRUE if at least one library loaded, FALSE otherwise.
1023  */
1024 void load_mapi_providers(void)
1025 {
1026     static const WCHAR regkey_mail[] = {
1027         'S','o','f','t','w','a','r','e','\\','C','l','i','e','n','t','s','\\',
1028         'M','a','i','l',0 };
1029 
1030     static const WCHAR regkey_dllpath[] = {'D','L','L','P','a','t','h',0 };
1031     static const WCHAR regkey_dllpath_ex[] = {'D','L','L','P','a','t','h','E','x',0 };
1032     static const WCHAR regkey_backslash[] = { '\\', 0 };
1033 
1034     HKEY hkeyMail;
1035     DWORD dwType, dwLen = 0;
1036     LPWSTR appName = NULL, appKey = NULL;
1037 
1038     TRACE("()\n");
1039 
1040     /* Open the Mail key */
1041     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, regkey_mail, 0, KEY_READ, &hkeyMail) != ERROR_SUCCESS)
1042         return;
1043 
1044     /* Check if we have a default value set, and the length of it */
1045     if ((RegQueryValueExW(hkeyMail, NULL, NULL, &dwType, NULL, &dwLen) != ERROR_SUCCESS) ||
1046         !((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)) || (dwLen == 0))
1047         goto cleanUp;
1048 
1049     appName = HeapAlloc(GetProcessHeap(), 0, dwLen);
1050 
1051     if (!appName)
1052         goto cleanUp;
1053 
1054     /* Get the value, and get the path to the app key */
1055     RegQueryValueExW(hkeyMail, NULL, NULL, NULL, (LPBYTE)appName, &dwLen);
1056 
1057     TRACE("appName: %s\n", debugstr_w(appName));
1058 
1059     appKey = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(regkey_mail) +
1060         lstrlenW(regkey_backslash) + lstrlenW(appName) + 1));
1061 
1062     if (!appKey)
1063         goto cleanUp;
1064 
1065     lstrcpyW(appKey, regkey_mail);
1066     lstrcatW(appKey, regkey_backslash);
1067     lstrcatW(appKey, appName);
1068 
1069     RegCloseKey(hkeyMail);
1070 
1071     TRACE("appKey: %s\n", debugstr_w(appKey));
1072 
1073     /* Open the app's key */
1074     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, appKey, 0, KEY_READ, &hkeyMail) != ERROR_SUCCESS)
1075         goto cleanUp;
1076 
1077     /* Try to load the providers */
1078     load_mapi_provider(hkeyMail, regkey_dllpath, &mapi_provider);
1079     load_mapi_provider(hkeyMail, regkey_dllpath_ex, &mapi_ex_provider);
1080 
1081     /* Now try to load our function pointers */
1082     ZeroMemory(&mapiFunctions, sizeof(mapiFunctions));
1083 
1084     /* Simple MAPI functions */
1085     if (mapi_provider)
1086     {
1087         mapiFunctions.MAPIAddress = (void*) GetProcAddress(mapi_provider, "MAPIAddress");
1088         mapiFunctions.MAPIDeleteMail = (void*) GetProcAddress(mapi_provider, "MAPIDeleteMail");
1089         mapiFunctions.MAPIDetails = (void*) GetProcAddress(mapi_provider, "MAPIDetails");
1090         mapiFunctions.MAPIFindNext = (void*) GetProcAddress(mapi_provider, "MAPIFindNext");
1091         mapiFunctions.MAPILogoff = (void*) GetProcAddress(mapi_provider, "MAPILogoff");
1092         mapiFunctions.MAPILogon = (void*) GetProcAddress(mapi_provider, "MAPILogon");
1093         mapiFunctions.MAPIReadMail = (void*) GetProcAddress(mapi_provider, "MAPIReadMail");
1094         mapiFunctions.MAPIResolveName = (void*) GetProcAddress(mapi_provider, "MAPIResolveName");
1095         mapiFunctions.MAPISaveMail = (void*) GetProcAddress(mapi_provider, "MAPISaveMail");
1096         mapiFunctions.MAPISendDocuments = (void*) GetProcAddress(mapi_provider, "MAPISendDocuments");
1097         mapiFunctions.MAPISendMail = (void*) GetProcAddress(mapi_provider, "MAPISendMail");
1098         mapiFunctions.MAPISendMailW = (void*) GetProcAddress(mapi_provider, "MAPISendMailW");
1099     }
1100 
1101     /* Extended MAPI functions */
1102     if (mapi_ex_provider)
1103     {
1104         mapiFunctions.MAPIInitialize = (void*) GetProcAddress(mapi_ex_provider, "MAPIInitialize");
1105         mapiFunctions.MAPILogonEx = (void*) GetProcAddress(mapi_ex_provider, "MAPILogonEx");
1106         mapiFunctions.MAPIUninitialize = (void*) GetProcAddress(mapi_ex_provider, "MAPIUninitialize");
1107 
1108         mapiFunctions.DeinitMapiUtil = (void*) GetProcAddress(mapi_ex_provider, "DeinitMapiUtil@0");
1109         mapiFunctions.DllCanUnloadNow = (void*) GetProcAddress(mapi_ex_provider, "DllCanUnloadNow");
1110         mapiFunctions.DllGetClassObject = (void*) GetProcAddress(mapi_ex_provider, "DllGetClassObject");
1111         mapiFunctions.FGetComponentPath = (void*) GetProcAddress(mapi_ex_provider, "FGetComponentPath");
1112         mapiFunctions.HrThisThreadAdviseSink = (void*) GetProcAddress(mapi_ex_provider, "HrThisThreadAdviseSink@8");
1113         mapiFunctions.HrQueryAllRows = (void*) GetProcAddress(mapi_ex_provider, "HrQueryAllRows@24");
1114         mapiFunctions.MAPIAdminProfiles = (void*) GetProcAddress(mapi_ex_provider, "MAPIAdminProfiles");
1115         mapiFunctions.MAPIAllocateBuffer = (void*) GetProcAddress(mapi_ex_provider, "MAPIAllocateBuffer");
1116         mapiFunctions.MAPIAllocateMore = (void*) GetProcAddress(mapi_ex_provider, "MAPIAllocateMore");
1117         mapiFunctions.MAPIFreeBuffer = (void*) GetProcAddress(mapi_ex_provider, "MAPIFreeBuffer");
1118         mapiFunctions.MAPIGetDefaultMalloc = (void*) GetProcAddress(mapi_ex_provider, "MAPIGetDefaultMalloc@0");
1119         mapiFunctions.MAPIOpenLocalFormContainer = (void *) GetProcAddress(mapi_ex_provider, "MAPIOpenLocalFormContainer");
1120         mapiFunctions.OpenStreamOnFile = (void*) GetProcAddress(mapi_ex_provider, "OpenStreamOnFile@24");
1121         mapiFunctions.ScInitMapiUtil = (void*) GetProcAddress(mapi_ex_provider, "ScInitMapiUtil@4");
1122         mapiFunctions.WrapCompressedRTFStream = (void*) GetProcAddress(mapi_ex_provider, "WrapCompressedRTFStream@12");
1123     }
1124 
1125 cleanUp:
1126     RegCloseKey(hkeyMail);
1127     HeapFree(GetProcessHeap(), 0, appKey);
1128     HeapFree(GetProcessHeap(), 0, appName);
1129 }
1130 
1131 /**************************************************************************
1132  *  unload_mapi_providers
1133  *
1134  * Unloads any loaded MAPI libraries.
1135  */
1136 void unload_mapi_providers(void)
1137 {
1138     TRACE("()\n");
1139 
1140     FreeLibrary(mapi_provider);
1141     FreeLibrary(mapi_ex_provider);
1142 }
1143