Removed W->A from DEFWND_ImmIsUIMessageW.
[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
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winreg.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 /**************************************************************************
42  *  ScInitMapiUtil (MAPI32.33)
43  *
44  * Initialise Mapi utility functions.
45  *
46  * PARAMS
47  *  ulReserved [I] Reserved, pass 0.
48  *
49  * RETURNS
50  *  Success: S_OK. Mapi utility functions may be called.
51  *  Failure: MAPI_E_INVALID_PARAMETER, if ulReserved is not 0.
52  *
53  * NOTES
54  *  Your application does not need to call this function unless it does not
55  *  call MAPIInitialize()/MAPIUninitialize().
56  */
57 SCODE WINAPI ScInitMapiUtil(ULONG ulReserved)
58 {
59     FIXME("(0x%08lx)stub!\n", ulReserved);
60     if (ulReserved)
61         return MAPI_E_INVALID_PARAMETER;
62     return S_OK;
63 }
64
65 /**************************************************************************
66  *  DeinitMapiUtil (MAPI32.34)
67  *
68  * Uninitialise Mapi utility functions.
69  *
70  * PARAMS
71  *  None.
72  *
73  * RETURNS
74  *  Nothing.
75  *
76  * NOTES
77  *  Your application does not need to call this function unless it does not
78  *  call MAPIInitialize()/MAPIUninitialize().
79  */
80 VOID WINAPI DeinitMapiUtil(void)
81 {
82     FIXME("()stub!\n");
83 }
84
85 typedef LPVOID *LPMAPIALLOCBUFFER;
86
87 /**************************************************************************
88  *  MAPIAllocateBuffer   (MAPI32.12)
89  *  MAPIAllocateBuffer@8 (MAPI32.13)
90  *
91  * Allocate a block of memory.
92  *
93  * PARAMS
94  *  cbSize    [I] Size of the block to allocate in bytes
95  *  lppBuffer [O] Destination for pointer to allocated memory
96  *
97  * RETURNS
98  *  Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
99  *           length cbSize bytes.
100  *  Failure: MAPI_E_INVALID_PARAMETER, if lppBuffer is NULL.
101  *           MAPI_E_NOT_ENOUGH_MEMORY, if the memory allocation fails.
102  *
103  * NOTES
104  *  Memory allocated with this function should be freed with MAPIFreeBuffer().
105  *  Further allocations of memory may be linked to the pointer returned using
106  *  MAPIAllocateMore(). Linked allocations are freed when the initial pointer
107  *  is feed.
108  */
109 SCODE WINAPI MAPIAllocateBuffer(ULONG cbSize, LPVOID *lppBuffer)
110 {
111     LPMAPIALLOCBUFFER lpBuff;
112
113     TRACE("(%ld,%p)\n", cbSize, lppBuffer);
114
115     if (!lppBuffer)
116         return E_INVALIDARG;
117
118     lpBuff = (LPMAPIALLOCBUFFER)HeapAlloc(GetProcessHeap(), 0, cbSize + sizeof(*lpBuff));
119     if (!lpBuff)
120         return MAPI_E_NOT_ENOUGH_MEMORY;
121
122     TRACE("initial allocation:%p, returning %p\n", lpBuff, lpBuff + 1);
123     *lpBuff++ = NULL;
124     *lppBuffer = lpBuff;
125     return S_OK;
126 }
127
128 /**************************************************************************
129  *  MAPIAllocateMore    (MAPI32.14)
130  *  MAPIAllocateMore@12 (MAPI32.15)
131  *
132  * Allocate a block of memory linked to a previous allocation.
133  *
134  * PARAMS
135  *  cbSize    [I] Size of the block to allocate in bytes
136  *  lpOrig    [I] Initial allocation to link to, from MAPIAllocateBuffer()
137  *  lppBuffer [O] Destination for pointer to allocated memory
138  *
139  * RETURNS
140  *  Success: S_OK. *lppBuffer is filled with a pointer to a memory block of
141  *           length cbSize bytes.
142  *  Failure: MAPI_E_INVALID_PARAMETER, if lpOrig or lppBuffer is invalid.
143  *           MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails.
144  *
145  * NOTES
146  *  Memory allocated with this function and stored in *lppBuffer is freed
147  *  when lpOrig is passed to MAPIFreeBuffer(). It should not be freed independently.
148  */
149 SCODE WINAPI MAPIAllocateMore(ULONG cbSize, LPVOID lpOrig, LPVOID *lppBuffer)
150 {
151     LPMAPIALLOCBUFFER lpBuff = lpOrig;
152
153     TRACE("(%ld,%p,%p)\n", cbSize, lpOrig, lppBuffer);
154
155     if (!lppBuffer || !lpBuff || !--lpBuff)
156         return E_INVALIDARG;
157
158     /* Find the last allocation in the chain */
159     while (*lpBuff)
160     {
161         TRACE("linked:%p->%p\n", lpBuff, *lpBuff);
162         lpBuff = *lpBuff;
163     }
164
165     if (SUCCEEDED(MAPIAllocateBuffer(cbSize, lppBuffer)))
166     {
167         *lpBuff = ((LPMAPIALLOCBUFFER)*lppBuffer) - 1;
168         TRACE("linking %p->%p\n", lpBuff, *lpBuff);
169     }
170     return *lppBuffer ? S_OK : MAPI_E_NOT_ENOUGH_MEMORY;
171 }
172
173 /**************************************************************************
174  *  MAPIFreeBuffer   (MAPI32.16)
175  *  MAPIFreeBuffer@4 (MAPI32.17)
176  *
177  * Free a block of memory and any linked allocations associated with it.
178  *
179  * PARAMS
180  *  lpBuffer [I] Memory to free, returned from MAPIAllocateBuffer()
181  *
182  * RETURNS
183  *  S_OK.
184  */
185 ULONG WINAPI MAPIFreeBuffer(LPVOID lpBuffer)
186 {
187     LPMAPIALLOCBUFFER lpBuff = lpBuffer;
188
189     TRACE("(%p)\n", lpBuffer);
190
191     if (lpBuff && --lpBuff)
192     {
193         while (lpBuff)
194         {
195             LPVOID lpFree = lpBuff;
196
197             lpBuff = *lpBuff;
198
199             TRACE("linked:%p->%p, freeing %p\n", lpFree, lpBuff, lpFree);
200             HeapFree(GetProcessHeap(), 0, lpFree);
201         }
202     }
203     return S_OK;
204 }
205
206 /*************************************************************************
207  * HrThisThreadAdviseSink@8 (MAPI32.42)
208  *
209  * Ensure that an advise sink is only notified in its originating thread.
210  *
211  * PARAMS
212  *  lpSink     [I] IMAPIAdviseSink interface to be protected
213  *  lppNewSink [I] Destination for wrapper IMAPIAdviseSink interface
214  *
215  * RETURNS
216  * Success: S_OK. *lppNewSink contains a new sink to use in place of lpSink.
217  * Failure: E_INVALIDARG, if any parameter is invalid.
218  */
219 HRESULT WINAPI HrThisThreadAdviseSink(LPMAPIADVISESINK lpSink, LPMAPIADVISESINK* lppNewSink)
220 {
221     FIXME("(%p,%p)semi-stub\n", lpSink, lppNewSink);
222
223     if (!lpSink || !lppNewSink)
224         return E_INVALIDARG;
225
226     /* Don't wrap the sink for now, just copy it */
227     *lppNewSink = lpSink;
228     IMAPIAdviseSink_AddRef(lpSink);
229     return S_OK;
230 }
231
232 /*************************************************************************
233  * FBinFromHex (MAPI32.44)
234  *
235  * Create an array of binary data from a string.
236  *
237  * PARAMS
238  *  lpszHex [I] String to convert to binary data
239  *  lpOut   [O] Destination for resulting binary data
240  *
241  * RETURNS
242  *  Success: TRUE. lpOut contains the decoded binary data.
243  *  Failure: FALSE, if lpszHex does not represent a binary string.
244  *
245  * NOTES
246  *  - lpOut must be at least half the length of lpszHex in bytes.
247  *  - Although the Mapi headers prototype this function as both
248  *    Ascii and Unicode, there is only one (Ascii) implementation. This
249  *    means that lpszHex is treated as an Ascii string (i.e. a single NUL
250  *    character in the byte stream terminates the string).
251  */
252 BOOL WINAPI FBinFromHex(LPWSTR lpszHex, LPBYTE lpOut)
253 {
254     static const BYTE digitsToHex[] = {
255       0,1,2,3,4,5,6,7,8,9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,14,15,
256       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
257       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,10,11,12,13,
258       14,15 };
259     LPSTR lpStr = (LPSTR)lpszHex;
260
261     TRACE("(%p,%p)\n", lpszHex, lpOut);
262
263     while (*lpStr)
264     {
265         if (lpStr[0] < '0' || lpStr[0] > 'f' || digitsToHex[lpStr[0] - '0'] == 0xff ||
266             lpStr[1] < '0' || lpStr[1] > 'f' || digitsToHex[lpStr[1] - '0'] == 0xff)
267             return FALSE;
268
269         *lpOut++ = (digitsToHex[lpStr[0] - '0'] << 4) | digitsToHex[lpStr[1] - '0'];
270         lpStr += 2;
271     }
272     return TRUE;
273 }
274
275 /*************************************************************************
276  * HexFromBin (MAPI32.45)
277  *
278  * Create a string from an array of binary data.
279  *
280  * PARAMS
281  *  lpHex   [I] Binary data to convert to string
282  *  iCount  [I] Length of lpHex in bytes
283  *  lpszOut [O] Destination for resulting hex string
284  *
285  * RETURNS
286  *  Nothing.
287  *
288  * NOTES
289  *  - lpszOut must be at least 2 * iCount + 1 bytes characters long.
290  *  - Although the Mapi headers prototype this function as both
291  *    Ascii and Unicode, there is only one (Ascii) implementation. This
292  *    means that the resulting string is not properly NUL terminated
293  *    if the caller expects it to be a Unicode string.
294  */
295 void WINAPI HexFromBin(LPBYTE lpHex, int iCount, LPWSTR lpszOut)
296 {
297     static const char hexDigits[] = { "0123456789ABCDEF" };
298     LPSTR lpStr = (LPSTR)lpszOut;
299
300     TRACE("(%p,%d,%p)\n", lpHex, iCount, lpszOut);
301
302     while (iCount-- > 0)
303     {
304         *lpStr++ = hexDigits[*lpHex >> 4];
305         *lpStr++ = hexDigits[*lpHex & 0xf];
306         lpHex++;
307     }
308     *lpStr = '\0';
309 }
310
311 /*************************************************************************
312  * SwapPlong@8 (MAPI32.47)
313  *
314  * Swap the bytes in a ULONG array.
315  *
316  * PARAMS
317  *  lpData [O] Array to swap bytes in
318  *  ulLen  [I] Number of ULONG element to swap the bytes of
319  *
320  * RETURNS
321  *  Nothing.
322  */
323 VOID WINAPI SwapPlong(PULONG lpData, ULONG ulLen)
324 {
325     ULONG i;
326
327     for (i = 0; i < ulLen; i++)
328         lpData[i] = RtlUlongByteSwap(lpData[i]);
329 }
330
331 /*************************************************************************
332  * SwapPword@8 (MAPI32.48)
333  *
334  * Swap the bytes in a USHORT array.
335  *
336  * PARAMS
337  *  lpData [O] Array to swap bytes in
338  *  ulLen  [I] Number of USHORT element to swap the bytes of
339  *
340  * RETURNS
341  *  Nothing.
342  */
343 VOID WINAPI SwapPword(PUSHORT lpData, ULONG ulLen)
344 {
345     ULONG i;
346
347     for (i = 0; i < ulLen; i++)
348         lpData[i] = RtlUshortByteSwap(lpData[i]);
349 }
350
351 /**************************************************************************
352  *  MNLS_lstrlenW@4 (MAPI32.62)
353  *
354  * Calculate the length of a Unicode string.
355  *
356  * PARAMS
357  *  lpszStr [I] String to calculate the length of
358  *
359  * RETURNS
360  *  The length of lpszStr in Unicode characters.
361  */
362 ULONG WINAPI MNLS_lstrlenW(LPCWSTR lpszStr)
363 {
364     TRACE("(%s)\n", debugstr_w(lpszStr));
365     return strlenW(lpszStr);
366 }
367
368 /*************************************************************************
369  * MNLS_lstrcmpW@8 (MAPI32.63)
370  *
371  * Compare two Unicode strings.
372  *
373  * PARAMS
374  *  lpszLeft  [I] First string to compare
375  *  lpszRight [I] Second string to compare
376  *
377  * RETURNS
378  *  An integer less than, equal to or greater than 0, indicating that
379  *  lpszLeft is less than, the same, or greater than lpszRight.
380  */
381 INT WINAPI MNLS_lstrcmpW(LPCWSTR lpszLeft, LPCWSTR lpszRight)
382 {
383     TRACE("(%s,%s)\n", debugstr_w(lpszLeft), debugstr_w(lpszRight));
384     return strcmpW(lpszLeft, lpszRight);
385 }
386
387 /*************************************************************************
388  * MNLS_lstrcpyW@8 (MAPI32.64)
389  *
390  * Copy a Unicode string to another string.
391  *
392  * PARAMS
393  *  lpszDest [O] Destination string
394  *  lpszSrc  [I] Source string
395  *
396  * RETURNS
397  *  The length lpszDest in Unicode characters.
398  */
399 ULONG WINAPI MNLS_lstrcpyW(LPWSTR lpszDest, LPCWSTR lpszSrc)
400 {
401     ULONG len;
402
403     TRACE("(%p,%s)\n", lpszDest, debugstr_w(lpszSrc));
404     len = (strlenW(lpszSrc) + 1) * sizeof(WCHAR);
405     memcpy(lpszDest, lpszSrc, len);
406     return len;
407 }
408
409 /*************************************************************************
410  * MNLS_CompareStringW@12 (MAPI32.65)
411  *
412  * Compare two Unicode strings.
413  *
414  * PARAMS
415  *  dwCp      [I] Code page for the comparison
416  *  lpszLeft  [I] First string to compare
417  *  lpszRight [I] Second string to compare
418  *
419  * RETURNS
420  *  CSTR_LESS_THAN, CSTR_EQUAL or CSTR_GREATER_THAN, indicating that
421  *  lpszLeft is less than, the same, or greater than lpszRight.
422  */
423 INT WINAPI MNLS_CompareStringW(DWORD dwCp, LPCWSTR lpszLeft, LPCWSTR lpszRight)
424 {
425     INT ret;
426
427     TRACE("0x%08lx,%s,%s\n", dwCp, debugstr_w(lpszLeft), debugstr_w(lpszRight));
428     ret = MNLS_lstrcmpW(lpszLeft, lpszRight);
429     return ret < 0 ? CSTR_LESS_THAN : ret ? CSTR_GREATER_THAN : CSTR_EQUAL;
430 }
431
432 /**************************************************************************
433  *  FEqualNames@8 (MAPI32.72)
434  *
435  * Compare two Mapi names.
436  *
437  * PARAMS
438  *  lpName1 [I] First name to compare to lpName2
439  *  lpName2 [I] Second name to compare to lpName1
440  *
441  * RETURNS
442  *  TRUE, if the names are the same,
443  *  FALSE, Otherwise.
444  */
445 BOOL WINAPI FEqualNames(LPMAPINAMEID lpName1, LPMAPINAMEID lpName2)
446 {
447     TRACE("(%p,%p)\n", lpName1, lpName2);
448
449     if (!lpName1 || !lpName2 ||
450         !IsEqualGUID(lpName1->lpguid, lpName2->lpguid) ||
451         lpName1->ulKind != lpName2->ulKind)
452         return FALSE;
453
454     if (lpName1->ulKind == MNID_STRING)
455         return !strcmpW(lpName1->Kind.lpwstrName, lpName2->Kind.lpwstrName);
456
457     return lpName1->Kind.lID == lpName2->Kind.lID ? TRUE : FALSE;
458 }
459
460 /**************************************************************************
461  *  FtAddFt@16 (MAPI32.121)
462  *
463  * Add two FILETIME's together.
464  *
465  * PARAMS
466  *  ftLeft  [I] FILETIME to add to ftRight
467  *  ftRight [I] FILETIME to add to ftLeft
468  *
469  * RETURNS
470  *  The sum of ftLeft and ftRight
471  */
472 LONGLONG WINAPI MAPI32_FtAddFt(FILETIME ftLeft, FILETIME ftRight)
473 {
474     LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight;
475
476     return *pl + *pr;
477 }
478
479 /**************************************************************************
480  *  FtSubFt@16 (MAPI32.123)
481  *
482  * Subtract two FILETIME's together.
483  *
484  * PARAMS
485  *  ftLeft  [I] Initial FILETIME
486  *  ftRight [I] FILETIME to subtract from ftLeft
487  *
488  * RETURNS
489  *  The remainder after ftRight is subtracted from ftLeft.
490  */
491 LONGLONG WINAPI MAPI32_FtSubFt(FILETIME ftLeft, FILETIME ftRight)
492 {
493     LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight;
494
495     return *pr - *pl;
496 }
497
498 /**************************************************************************
499  *  FtMulDw@12 (MAPI32.124)
500  *
501  * Multiply a FILETIME by a DWORD.
502  *
503  * PARAMS
504  *  dwLeft  [I] DWORD to multiply with ftRight
505  *  ftRight [I] FILETIME to multiply with dwLeft
506  *
507  * RETURNS
508  *  The product of dwLeft and ftRight
509  */
510 LONGLONG WINAPI MAPI32_FtMulDw(DWORD dwLeft, FILETIME ftRight)
511 {
512     LONGLONG *pr = (LONGLONG*)&ftRight;
513
514     return (LONGLONG)dwLeft * (*pr);
515 }
516
517 /**************************************************************************
518  *  FtMulDwDw@8 (MAPI32.125)
519  *
520  * Multiply two DWORD, giving the result as a FILETIME.
521  *
522  * PARAMS
523  *  dwLeft  [I] DWORD to multiply with dwRight
524  *  dwRight [I] DWORD to multiply with dwLeft
525  *
526  * RETURNS
527  *  The product of ftMultiplier and ftMultiplicand as a FILETIME.
528  */
529 LONGLONG WINAPI MAPI32_FtMulDwDw(DWORD dwLeft, DWORD dwRight)
530 {
531     return (LONGLONG)dwLeft * (LONGLONG)dwRight;
532 }
533
534 /**************************************************************************
535  *  FtNegFt@8 (MAPI32.126)
536  *
537  * Negate a FILETIME.
538  *
539  * PARAMS
540  *  ft [I] FILETIME to negate
541  *
542  * RETURNS
543  *  The negation of ft.
544  */
545 LONGLONG WINAPI MAPI32_FtNegFt(FILETIME ft)
546 {
547     LONGLONG *p = (LONGLONG*)&ft;
548     
549     return - *p;
550 }
551
552 /**************************************************************************
553  *  UlAddRef@4 (MAPI32.128)
554  *
555  * Add a reference to an object.
556  *
557  * PARAMS
558  *  lpUnk [I] Object to add a reference to.
559  *
560  * RETURNS
561  *  The new reference count of the object, or 0 if lpUnk is NULL.
562  *
563  * NOTES
564  * See IUnknown_AddRef.
565  */
566 ULONG WINAPI UlAddRef(void *lpUnk)
567 {
568     TRACE("(%p)\n", lpUnk);
569
570     if (!lpUnk)
571         return 0UL;
572     return IUnknown_AddRef((LPUNKNOWN)lpUnk);
573 }
574
575 /**************************************************************************
576  *  UlRelease@4 (MAPI32.129)
577  *
578  * Remove a reference from an object.
579  *
580  * PARAMS
581  *  lpUnk [I] Object to remove reference from.
582  *
583  * RETURNS
584  *  The new reference count of the object, or 0 if lpUnk is NULL. If lpUnk is
585  *  non-NULL and this function returns 0, the object pointed to by lpUnk has
586  *  been released.
587  *
588  * NOTES
589  * See IUnknown_Release.
590  */
591 ULONG WINAPI UlRelease(void *lpUnk)
592 {
593     TRACE("(%p)\n", lpUnk);
594
595     if (!lpUnk)
596         return 0UL;
597     return IUnknown_Release((LPUNKNOWN)lpUnk);
598 }
599
600 /*************************************************************************
601  * OpenStreamOnFile@24 (MAPI32.147)
602  *
603  * Create a stream on a file.
604  *
605  * PARAMS
606  *  lpAlloc    [I] Memory allocation function
607  *  lpFree     [I] Memory free function
608  *  ulFlags    [I] Flags controlling the opening process
609  *  lpszPath   [I] Path of file to create stream on
610  *  lpszPrefix [I] Prefix of the temporary file name (if ulFlags includes SOF_UNIQUEFILENAME)
611  *  lppStream  [O] Destination for created stream
612  *
613  * RETURNS
614  * Success: S_OK. lppStream contains the new stream object
615  * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code
616  *          describing the error.
617  */
618 HRESULT WINAPI OpenStreamOnFile(LPALLOCATEBUFFER lpAlloc, LPFREEBUFFER lpFree,
619                                 ULONG ulFlags, LPWSTR lpszPath, LPWSTR lpszPrefix,
620                                 LPSTREAM *lppStream)
621 {
622     WCHAR szBuff[MAX_PATH];
623     DWORD dwMode = STGM_READWRITE, dwAttributes = 0;
624     HRESULT hRet;
625
626     TRACE("(%p,%p,0x%08lx,%s,%s,%p)\n", lpAlloc, lpFree, ulFlags,
627           debugstr_a((LPSTR)lpszPath), debugstr_a((LPSTR)lpszPrefix), lppStream);
628
629     if (lppStream)
630         *lppStream = NULL;
631
632     if (ulFlags & SOF_UNIQUEFILENAME)
633     {
634         FIXME("Should generate a temporary name\n");
635         return E_INVALIDARG;
636     }
637
638     if (!lpszPath || !lppStream)
639         return E_INVALIDARG;
640
641     /* FIXME: Should probably munge mode and attributes, and should handle
642      *        Unicode arguments (I assume MAPI_UNICODE is set in ulFlags if
643      *        we are being passed Unicode strings; MSDN doesn't say).
644      *        This implementation is just enough for Outlook97 to start.
645      */
646     MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszPath, -1, szBuff, MAX_PATH);
647     hRet = SHCreateStreamOnFileEx(szBuff, dwMode, dwAttributes, TRUE,
648                                   NULL, lppStream);
649     return hRet;
650 }
651
652
653 /*************************************************************************
654  * cmc_query_configuration (MAPI32.235)
655  *
656  * Retrieves the configuration information for the installed CMC
657  *
658  * PARAMS
659  *  session          [I]   MAPI session handle
660  *  item             [I]   Enumerated variable that identifies which 
661  *                         configuration information is being requested
662  *  reference        [O]   Buffer where configuration information is written
663  *  config_extensions[I/O] Path of file to create stream on
664  *
665  * RETURNS
666  * A CMD define
667  */
668 CMC_return_code WINAPI cmc_query_configuration(
669   CMC_session_id session,
670   CMC_enum item,
671   CMC_buffer reference,
672   CMC_extension  *config_extensions)
673 {
674         FIXME("stub");
675         return CMC_E_NOT_SUPPORTED;
676 }