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