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