From c79b70d6a461d6cf8c9e2de3e7497f2bd4d5002e Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 23 Apr 2004 23:28:27 +0000 Subject: [PATCH] Implement MAPI property & utility functions. --- dlls/mapi32/Makefile.in | 9 +- dlls/mapi32/mapi32.spec | 84 ++-- dlls/mapi32/mapi32_main.c | 25 +- dlls/mapi32/prop.c | 927 ++++++++++++++++++++++++++++++++++++++ dlls/mapi32/util.c | 541 ++++++++++++++++++++++ 5 files changed, 1525 insertions(+), 61 deletions(-) create mode 100644 dlls/mapi32/prop.c create mode 100644 dlls/mapi32/util.c diff --git a/dlls/mapi32/Makefile.in b/dlls/mapi32/Makefile.in index 63211f25bed..58426d24719 100644 --- a/dlls/mapi32/Makefile.in +++ b/dlls/mapi32/Makefile.in @@ -3,8 +3,15 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = mapi32.dll +IMPORTS = shlwapi ole32 kernel32 +EXTRALIBS = -luuid $(LIBUNICODE) -C_SRCS = mapi32_main.c +C_SRCS = \ + mapi32_main.c \ + prop.c \ + util.c + +SUBDIRS = tests @MAKE_DLL_RULES@ diff --git a/dlls/mapi32/mapi32.spec b/dlls/mapi32/mapi32.spec index 992eaa7c694..43b311ab841 100644 --- a/dlls/mapi32/mapi32.spec +++ b/dlls/mapi32/mapi32.spec @@ -3,10 +3,10 @@ 11 stdcall MAPILogonEx@20(long ptr ptr long ptr) MAPILogonEx 12 stdcall MAPIAllocateBuffer(long ptr) 13 stdcall MAPIAllocateBuffer@8(long ptr) MAPIAllocateBuffer - 14 stub MAPIAllocateMore - 15 stub MAPIAllocateMore@12 - 16 stub MAPIFreeBuffer - 17 stub MAPIFreeBuffer@4 + 14 stdcall MAPIAllocateMore(long ptr ptr) + 15 stdcall MAPIAllocateMore@12(long ptr ptr) MAPIAllocateMore + 16 stdcall MAPIFreeBuffer(ptr) + 17 stdcall MAPIFreeBuffer@4(ptr) MAPIFreeBuffer 18 stub MAPIAdminProfiles 19 stub MAPIAdminProfiles@8 20 stdcall MAPIInitialize(ptr) @@ -22,18 +22,18 @@ 30 stub MAPIOpenFormMgr@8 31 stub MAPIOpenLocalFormContainer 32 stub MAPIOpenLocalFormContainer@4 - 33 stub ScInitMapiUtil@4 + 33 stdcall ScInitMapiUtil@4(long) ScInitMapiUtil 34 stdcall DeinitMapiUtil@0() DeinitMapiUtil 35 stub ScGenerateMuid@4 36 stub HrAllocAdviseSink@12 41 stub WrapProgress@20 - 42 stub HrThisThreadAdviseSink@8 + 42 stdcall HrThisThreadAdviseSink@8(ptr ptr) HrThisThreadAdviseSink 43 stub ScBinFromHexBounded@12 44 stub FBinFromHex@8 45 stub HexFromBin@12 46 stub BuildDisplayTable@40 - 47 stub SwapPlong@8 - 48 stub SwapPword@8 + 47 stdcall SwapPlong@8(ptr long) SwapPlong + 48 stdcall SwapPword@8(ptr long) SwapPword 49 stub MAPIInitIdle@4 50 stub MAPIDeinitIdle@0 51 stub InstallFilterHook@4 @@ -44,41 +44,41 @@ 59 stub MAPIGetDefaultMalloc@0 60 stub CreateIProp@24 61 stub CreateTable@36 - 62 stub MNLS_lstrlenW@4 - 63 stub MNLS_lstrcmpW@8 - 64 stub MNLS_lstrcpyW@8 - 65 stub MNLS_CompareStringW@24 - 66 stub MNLS_MultiByteToWideChar@24 - 67 stub MNLS_WideCharToMultiByte@32 - 68 stub MNLS_IsBadStringPtrW@8 + 62 stdcall MNLS_lstrlenW@4(wstr) MNLS_lstrlenW + 63 stdcall MNLS_lstrcmpW@8(wstr wstr) MNLS_lstrcmpW + 64 stdcall MNLS_lstrcpyW@8(ptr wstr) MNLS_lstrcpyW + 65 stdcall MNLS_CompareStringW@24(long wstr wstr) MNLS_CompareStringW + 66 stdcall MNLS_MultiByteToWideChar@24(long long str long ptr long) kernel32.MultiByteToWideChar + 67 stdcall MNLS_WideCharToMultiByte@32(long long wstr long ptr long ptr ptr) kernel32.WideCharToMultiByte + 68 stdcall MNLS_IsBadStringPtrW@8(ptr long) kernel32.IsBadStringPtrW 72 stub FEqualNames@8 73 stub WrapStoreEntryID@24 74 stub IsBadBoundedStringPtr@8 75 stub HrQueryAllRows@24 - 76 stub PropCopyMore@16 - 77 stub UlPropSize@4 - 78 stub FPropContainsProp@12 - 79 stub FPropCompareProp@12 - 80 stub LPropCompareProp@8 + 76 stdcall PropCopyMore@16(ptr ptr ptr ptr) PropCopyMore + 77 stdcall UlPropSize@4(ptr) UlPropSize + 78 stdcall FPropContainsProp@12(ptr ptr long) FPropContainsProp + 79 stdcall FPropCompareProp@12(ptr long ptr) FPropCompareProp + 80 stdcall LPropCompareProp@8(ptr ptr) LPropCompareProp 81 stub HrAddColumns@16 82 stub HrAddColumnsEx@20 -121 stub FtAddFt@16 +121 stdcall -ret64 FtAddFt@16(long long long long) MAPI32_FtAddFt 122 stub FtAdcFt@20 -123 stub FtSubFt@16 -124 stub FtMulDw@12 -125 stub FtMulDwDw@8 -126 stub FtNegFt@8 +123 stdcall -ret64 FtSubFt@16(long long long long) MAPI32_FtSubFt +124 stdcall -ret64 FtMulDw@12(long long long) MAPI32_FtMulDw +125 stdcall -ret64 FtMulDwDw@8(long long) MAPI32_FtMulDwDw +126 stdcall -ret64 FtNegFt@8(long long) MAPI32_FtNegFt 127 stub FtDivFtBogus@20 -128 stub UlAddRef@4 -129 stub UlRelease@4 -130 stub SzFindCh@8 -131 stub SzFindLastCh@8 -132 stub SzFindSz@8 +128 stdcall UlAddRef@4(ptr) UlAddRef +129 stdcall UlRelease@4(ptr) UlRelease +130 stdcall SzFindCh@8(str long) shlwapi.StrChrA +131 stdcall SzFindLastCh@8(str str long) shlwapi.StrRChrA +132 stdcall SzFindSz@8(str str) shlwapi.StrStrA 133 stub UFromSz@4 135 stub HrGetOneProp@12 136 stub HrSetOneProp@8 137 stub FPropExists@8 -138 stub PpropFindProp@12 +138 stdcall PpropFindProp@12(ptr long long) PpropFindProp 139 stub FreePadrlist@4 140 stub FreeProws@4 141 stub HrSzFromEntryID@12 @@ -87,8 +87,8 @@ 144 stub HrDecomposeEID@28 145 stub HrComposeMsgID@24 146 stub HrDecomposeMsgID@24 -147 stub OpenStreamOnFile@24 -148 stub OpenStreamOnFile +147 stdcall OpenStreamOnFile@24(ptr ptr ptr ptr ptr ptr) OpenStreamOnFile +148 stdcall OpenStreamOnFile(ptr ptr ptr ptr ptr ptr) 149 stub OpenTnefStream@28 150 stub OpenTnefStream 151 stub OpenTnefStreamEx@32 @@ -107,19 +107,19 @@ 164 stub ScCountNotifications@12 165 stub ScCopyNotifications@16 166 stub ScRelocNotifications@20 -170 stub ScCountProps@12 +170 stdcall ScCountProps@12(long ptr ptr) ScCountProps 171 stub ScCopyProps@16 172 stub ScRelocProps@20 -173 stub LpValFindProp@12 +173 stdcall LpValFindProp@12(long long ptr) LpValFindProp 174 stub ScDupPropset@16 -175 stub FBadRglpszA@8 -176 stub FBadRglpszW@8 -177 stub FBadRowSet@4 +175 stdcall FBadRglpszA@8(ptr long) FBadRglpszA +176 stdcall FBadRglpszW@8(ptr long) FBadRglpszW +177 stdcall FBadRowSet@4(ptr) FBadRowSet 178 stub FBadRglpNameID@8 -179 stub FBadPropTag@4 -180 stub FBadRow@4 -181 stub FBadProp@4 -182 stub FBadColumnSet@4 +179 stdcall FBadPropTag@4(long) FBadPropTag +180 stdcall FBadRow@4(ptr) FBadRow +181 stdcall FBadProp@4(ptr) FBadProp +182 stdcall FBadColumnSet@4(ptr) FBadColumnSet 183 stub RTFSync@12 184 stub RTFSync 185 stub WrapCompressedRTFStream@12 diff --git a/dlls/mapi32/mapi32_main.c b/dlls/mapi32/mapi32_main.c index 7e2c273df27..ac6cc97c57c 100644 --- a/dlls/mapi32/mapi32_main.c +++ b/dlls/mapi32/mapi32_main.c @@ -23,8 +23,8 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "mapi.h" -#include "mapicode.h" +#include "objbase.h" +#include "mapix.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(mapi); @@ -35,33 +35,22 @@ HRESULT WINAPI MAPIInitialize ( LPVOID lpMapiInit ) return MAPI_E_NOT_INITIALIZED; } -HRESULT WINAPI MAPIAllocateBuffer ( ULONG cvSize, LPVOID *lppBuffer ) -{ - ERR("Stub\n"); - *lppBuffer = NULL; - return MAPI_E_NOT_INITIALIZED; -} - ULONG WINAPI MAPILogon(ULONG ulUIParam, LPSTR lpszProfileName, LPSTR lpszPassword, FLAGS flFlags, ULONG ulReserver, LPLHANDLE lplhSession) { ERR("Stub\n"); - return MAPI_E_FAILURE; + return MAPI_E_LOGON_FAILED; } -HRESULT WINAPI MAPILogonEx( ULONG ulUIParam, LPSTR lpszProfileName, LPSTR -lpszPassword, FLAGS flFlags, VOID* lppSession) +HRESULT WINAPI MAPILogonEx(ULONG_PTR ulUIParam, LPWSTR lpszProfileName, + LPWSTR lpszPassword, ULONG flFlags, + LPMAPISESSION *lppSession) { ERR("Stub\n"); - return MAPI_E_LOGON_FAILURE; + return MAPI_E_LOGON_FAILED; } VOID WINAPI MAPIUninitialize(void) { ERR("Stub\n"); } - -VOID WINAPI DeinitMapiUtil(void) -{ - ERR("Stub\n"); -} diff --git a/dlls/mapi32/prop.c b/dlls/mapi32/prop.c new file mode 100644 index 00000000000..a4fd586ca7a --- /dev/null +++ b/dlls/mapi32/prop.c @@ -0,0 +1,927 @@ +/* + * Property functions + * + * Copyright 2004 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winerror.h" +#include "winternl.h" +#include "objbase.h" +#include "shlwapi.h" +#include "wine/debug.h" +#include "wine/unicode.h" +#include "mapival.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mapi); + +BOOL WINAPI FBadRglpszA(LPSTR*,ULONG); +BOOL WINAPI FBadRglpszW(LPWSTR*,ULONG); + +/* Internal: Check if a property value array is invalid */ +static inline ULONG PROP_BadArray(LPSPropValue lpProp, size_t elemSize) +{ + return IsBadReadPtr(lpProp->Value.MVi.lpi, lpProp->Value.MVi.cValues * elemSize); +} + +/************************************************************************* + * PropCopyMore@16 (MAPI32.76) + * + * Copy a property value. + * + * PARAMS + * lpDest [O] Destination for the copied value + * lpSrc [I] Property value to copy to lpDest + * lpMore [I] Linked memory allocation function (pass MAPIAllocateMore()) + * lpOrig [I] Original allocation to which memory will be linked + * + * RETURNS + * Success: S_OK. lpDest contains a deep copy of lpSrc. + * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid, + * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails. + * + * NOTES + * Any elements within the property returned should not be individually + * freed, as they will be freed when lpOrig is. + */ +SCODE WINAPI PropCopyMore(LPSPropValue lpDest, LPSPropValue lpSrc, + ALLOCATEMORE *lpMore, LPVOID lpOrig) +{ + ULONG ulLen, i; + SCODE scode = S_OK; + + TRACE("(%p,%p,%p,%p)\n", lpDest, lpSrc, lpMore, lpOrig); + + if (!lpDest || IsBadWritePtr(lpDest, sizeof(SPropValue)) || + FBadProp(lpSrc) || !lpMore) + return MAPI_E_INVALID_PARAMETER; + + /* Shallow copy first, this is sufficient for properties without pointers */ + *lpDest = *lpSrc; + + switch (PROP_TYPE(lpSrc->ulPropTag)) + { + case PT_CLSID: + scode = lpMore(sizeof(GUID), lpOrig, (LPVOID*)&lpDest->Value.lpguid); + if (SUCCEEDED(scode)) + memcpy(lpDest->Value.lpguid, lpSrc->Value.lpguid, sizeof(GUID)); + break; + case PT_STRING8: + ulLen = lstrlenA(lpSrc->Value.lpszA) + 1u; + scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.lpszA); + if (SUCCEEDED(scode)) + memcpy(lpDest->Value.lpszA, lpSrc->Value.lpszA, ulLen); + break; + case PT_UNICODE: + ulLen = (strlenW(lpSrc->Value.lpszW) + 1u) * sizeof(WCHAR); + scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.lpszW); + if (SUCCEEDED(scode)) + memcpy(lpDest->Value.lpszW, lpSrc->Value.lpszW, ulLen); + break; + case PT_BINARY: + scode = lpMore(lpSrc->Value.bin.cb, lpOrig, (LPVOID*)&lpDest->Value.bin.lpb); + if (SUCCEEDED(scode)) + memcpy(lpDest->Value.bin.lpb, lpSrc->Value.bin.lpb, lpSrc->Value.bin.cb); + break; + default: + if (lpSrc->ulPropTag & MV_FLAG) + { + ulLen = UlPropSize(lpSrc); + + if (PROP_TYPE(lpSrc->ulPropTag) == PT_MV_STRING8 || + PROP_TYPE(lpSrc->ulPropTag) == PT_MV_UNICODE) + { + /* UlPropSize doesn't account for the string pointers */ + ulLen += lpSrc->Value.MVszA.cValues * sizeof(char*); + } + else if (PROP_TYPE(lpSrc->ulPropTag) == PT_MV_BINARY) + { + /* UlPropSize doesn't account for the SBinary structs */ + ulLen += lpSrc->Value.MVbin.cValues * sizeof(SBinary); + } + + lpDest->Value.MVi.cValues = lpSrc->Value.MVi.cValues; + scode = lpMore(ulLen, lpOrig, (LPVOID*)&lpDest->Value.MVi.lpi); + if (FAILED(scode)) + break; + + /* Note that we could allocate the memory for each value in a + * multi-value property seperately, however if an allocation failed + * we would be left with a bunch of allocated memory, which (while + * not really leaked) is unusable until lpOrig is freed. So for + * strings and binary arrays we make a single allocation for all + * of the data. This is consistent since individual elements can't + * be freed anyway. + */ + + switch (PROP_TYPE(lpSrc->ulPropTag)) + { + case PT_MV_STRING8: + { + char *lpNextStr = (char*)(lpDest->Value.MVszA.lppszA + + lpDest->Value.MVszA.cValues); + + for (i = 0; i < lpSrc->Value.MVszA.cValues; i++) + { + ULONG ulStrLen = lstrlenA(lpSrc->Value.MVszA.lppszA[i]) + 1u; + + lpDest->Value.MVszA.lppszA[i] = lpNextStr; + memcpy(lpNextStr, lpSrc->Value.MVszA.lppszA[i], ulStrLen); + lpNextStr += ulStrLen; + } + break; + } + case PT_MV_UNICODE: + { + WCHAR *lpNextStr = (WCHAR*)(lpDest->Value.MVszW.lppszW + + lpDest->Value.MVszW.cValues); + + for (i = 0; i < lpSrc->Value.MVszW.cValues; i++) + { + ULONG ulStrLen = strlenW(lpSrc->Value.MVszW.lppszW[i]) + 1u; + + lpDest->Value.MVszW.lppszW[i] = lpNextStr; + memcpy(lpNextStr, lpSrc->Value.MVszA.lppszA[i], ulStrLen * sizeof(WCHAR)); + lpNextStr += ulStrLen; + } + break; + } + case PT_MV_BINARY: + { + LPBYTE lpNext = (LPBYTE)(lpDest->Value.MVbin.lpbin + + lpDest->Value.MVbin.cValues); + + for (i = 0; i < lpSrc->Value.MVszW.cValues; i++) + { + lpDest->Value.MVbin.lpbin[i].cb = lpSrc->Value.MVbin.lpbin[i].cb; + lpDest->Value.MVbin.lpbin[i].lpb = lpNext; + memcpy(lpNext, lpSrc->Value.MVbin.lpbin[i].lpb, lpDest->Value.MVbin.lpbin[i].cb); + lpNext += lpDest->Value.MVbin.lpbin[i].cb; + } + break; + } + default: + /* No embedded pointers, just copy the data over */ + memcpy(lpDest->Value.MVi.lpi, lpSrc->Value.MVi.lpi, ulLen); + break; + } + break; + } + } + return scode; +} + +/************************************************************************* + * UlPropSize@4 (MAPI32.77) + * + * Determine the size of a property in bytes. + * + * PARAMS + * lpProp [I] Property to determine the size of + * + * RETURNS + * Success: The size of the value in lpProp. + * Failure: 0, if a multi-value (array) property is invalid or the type of lpProp + * is unknown. + * + * NOTES + * - The size returned does not include the size of the SPropValue struct + * or the size of the array of pointers for multi-valued properties that + * contain pointers (such as PT_MV_STRING8 or PT-MV_UNICODE). + * - MSDN incorrectly states that this function returns MAPI_E_CALL_FAILED if + * lpProp is invalid. In reality no checking is performed and this function + * will crash if passed an invalid property, or return 0 if the property + * type is PT_OBJECT or is unknown. + */ +ULONG WINAPI UlPropSize(LPSPropValue lpProp) +{ + ULONG ulRet = 1u, i; + + TRACE("(%p)\n", lpProp); + + switch (PROP_TYPE(lpProp->ulPropTag)) + { + case PT_MV_I2: ulRet = lpProp->Value.MVi.cValues; + case PT_BOOLEAN: + case PT_I2: ulRet *= sizeof(USHORT); + break; + case PT_MV_I4: ulRet = lpProp->Value.MVl.cValues; + case PT_ERROR: + case PT_I4: ulRet *= sizeof(LONG); + break; + case PT_MV_I8: ulRet = lpProp->Value.MVli.cValues; + case PT_I8: ulRet *= sizeof(LONG64); + break; + case PT_MV_R4: ulRet = lpProp->Value.MVflt.cValues; + case PT_R4: ulRet *= sizeof(float); + break; + case PT_MV_APPTIME: + case PT_MV_R8: ulRet = lpProp->Value.MVdbl.cValues; + case PT_APPTIME: + case PT_R8: ulRet *= sizeof(double); + break; + case PT_MV_CURRENCY: ulRet = lpProp->Value.MVcur.cValues; + case PT_CURRENCY: ulRet *= sizeof(CY); + break; + case PT_MV_SYSTIME: ulRet = lpProp->Value.MVft.cValues; + case PT_SYSTIME: ulRet *= sizeof(FILETIME); + break; + case PT_MV_CLSID: ulRet = lpProp->Value.MVguid.cValues; + case PT_CLSID: ulRet *= sizeof(GUID); + break; + case PT_MV_STRING8: ulRet = 0u; + for (i = 0; i < lpProp->Value.MVszA.cValues; i++) + ulRet += (lstrlenA(lpProp->Value.MVszA.lppszA[i]) + 1u); + break; + case PT_STRING8: ulRet = lstrlenA(lpProp->Value.lpszA) + 1u; + break; + case PT_MV_UNICODE: ulRet = 0u; + for (i = 0; i < lpProp->Value.MVszW.cValues; i++) + ulRet += (strlenW(lpProp->Value.MVszW.lppszW[i]) + 1u); + ulRet *= sizeof(WCHAR); + break; + case PT_UNICODE: ulRet = (lstrlenW(lpProp->Value.lpszW) + 1u) * sizeof(WCHAR); + break; + case PT_MV_BINARY: ulRet = 0u; + for (i = 0; i < lpProp->Value.MVbin.cValues; i++) + ulRet += lpProp->Value.MVbin.lpbin[i].cb; + break; + case PT_BINARY: ulRet = lpProp->Value.bin.cb; + break; + break; + case PT_OBJECT: + default: ulRet = 0u; + break; + } + + return ulRet; +} + +/************************************************************************* + * FPropContainsProp@12 (MAPI32.78) + * + * Find a property with a given property tag in a property array. + * + * PARAMS + * lpHaystack [I] Property to match to + * lpNeedle [I] Property to find in lpHaystack + * ulFuzzy [I] Flags controlling match type and strictness (FL_* flags from "mapidefs.h") + * + * RETURNS + * TRUE, if lpNeedle matches lpHaystack according to the criteria of ulFuzzy. + * + * NOTES + * Only property types of PT_STRING8 and PT_BINARY are handled by this function. + */ +BOOL WINAPI FPropContainsProp(LPSPropValue lpHaystack, LPSPropValue lpNeedle, ULONG ulFuzzy) +{ + TRACE("(%p,%p,0x%08lx)\n", lpHaystack, lpNeedle, ulFuzzy); + + if (FBadProp(lpHaystack) || FBadProp(lpNeedle) || + PROP_TYPE(lpHaystack->ulPropTag) != PROP_TYPE(lpNeedle->ulPropTag)) + return FALSE; + + /* FIXME: Do later versions support Unicode as well? */ + + if (PROP_TYPE(lpHaystack->ulPropTag) == PT_STRING8) + { + DWORD dwFlags = 0, dwNeedleLen, dwHaystackLen; + + if (ulFuzzy & FL_IGNORECASE) + dwFlags |= NORM_IGNORECASE; + if (ulFuzzy & FL_IGNORENONSPACE) + dwFlags |= NORM_IGNORENONSPACE; + if (ulFuzzy & FL_LOOSE) + dwFlags |= (NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS); + + dwNeedleLen = lstrlenA(lpNeedle->Value.lpszA); + dwHaystackLen = lstrlenA(lpHaystack->Value.lpszA); + + if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_PREFIX) + { + if (dwNeedleLen <= dwHaystackLen && + CompareStringA(LOCALE_USER_DEFAULT, dwFlags, + lpHaystack->Value.lpszA, dwNeedleLen, + lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL) + return TRUE; /* needle is a prefix of haystack */ + } + else if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_SUBSTRING) + { + LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD) = StrChrA; + LPSTR lpStr = lpHaystack->Value.lpszA; + + if (dwFlags & NORM_IGNORECASE) + pStrChrFn = StrChrIA; + + while ((lpStr = pStrChrFn(lpStr, *lpNeedle->Value.lpszA)) != NULL) + { + dwHaystackLen -= (lpStr - lpHaystack->Value.lpszA); + if (dwNeedleLen <= dwHaystackLen && + CompareStringA(LOCALE_USER_DEFAULT, dwFlags, + lpStr, dwNeedleLen, + lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL) + return TRUE; /* needle is a substring of haystack */ + lpStr++; + } + } + else if (CompareStringA(LOCALE_USER_DEFAULT, dwFlags, + lpHaystack->Value.lpszA, dwHaystackLen, + lpNeedle->Value.lpszA, dwNeedleLen) == CSTR_EQUAL) + return TRUE; /* full string match */ + } + else if (PROP_TYPE(lpHaystack->ulPropTag) == PT_BINARY) + { + if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_PREFIX) + { + if (lpNeedle->Value.bin.cb <= lpHaystack->Value.bin.cb && + !memcmp(lpNeedle->Value.bin.lpb, lpHaystack->Value.bin.lpb, + lpNeedle->Value.bin.cb)) + return TRUE; /* needle is a prefix of haystack */ + } + else if ((ulFuzzy & (FL_SUBSTRING|FL_PREFIX)) == FL_SUBSTRING) + { + ULONG ulLen = lpHaystack->Value.bin.cb; + LPBYTE lpb = lpHaystack->Value.bin.lpb; + + while ((lpb = memchr(lpb, *lpNeedle->Value.bin.lpb, ulLen)) != NULL) + { + ulLen = lpHaystack->Value.bin.cb - (lpb - lpHaystack->Value.bin.lpb); + if (lpNeedle->Value.bin.cb <= ulLen && + !memcmp(lpNeedle->Value.bin.lpb, lpb, lpNeedle->Value.bin.cb)) + return TRUE; /* needle is a substring of haystack */ + lpb++; + } + } + else if (!LPropCompareProp(lpHaystack, lpNeedle)) + return TRUE; /* needle is an exact match with haystack */ + + } + return FALSE; +} + +/************************************************************************* + * FPropCompareProp@12 (MAPI32.79) + * + * Compare two properties. + * + * PARAMS + * lpPropLeft [I] Left hand property to compare to lpPropRight + * ulOp [I] Comparason operator (RELOP_* enum from "mapidefs.h") + * lpPropRight [I] Right hand property to compare to lpPropLeft + * + * RETURNS + * TRUE, if the comparason is true, FALSE otherwise. + */ +BOOL WINAPI FPropCompareProp(LPSPropValue lpPropLeft, ULONG ulOp, LPSPropValue lpPropRight) +{ + LONG iCmp; + + TRACE("(%p,%ld,%p)\n", lpPropLeft, ulOp, lpPropRight); + + if (ulOp > RELOP_RE || FBadProp(lpPropLeft) || FBadProp(lpPropRight)) + return FALSE; + + if (ulOp == RELOP_RE) + { + FIXME("Comparason operator RELOP_RE not yet implemented!\n"); + return FALSE; + } + + iCmp = LPropCompareProp(lpPropLeft, lpPropRight); + + switch (ulOp) + { + case RELOP_LT: return iCmp < 0 ? TRUE : FALSE; + case RELOP_LE: return iCmp <= 0 ? TRUE : FALSE; + case RELOP_GT: return iCmp > 0 ? TRUE : FALSE; + case RELOP_GE: return iCmp >= 0 ? TRUE : FALSE; + case RELOP_EQ: return iCmp == 0 ? TRUE : FALSE; + case RELOP_NE: return iCmp != 0 ? TRUE : FALSE; + } + return FALSE; +} + +/************************************************************************* + * LPropCompareProp@8 (MAPI32.80) + * + * Compare two properties. + * + * PARAMS + * lpPropLeft [I] Left hand property to compare to lpPropRight + * lpPropRight [I] Right hand property to compare to lpPropLeft + * + * RETURNS + * An integer less than, equal to or greater than 0, indicating that + * lpszStr is less than, the same, or greater than lpszComp. + */ +LONG WINAPI LPropCompareProp(LPSPropValue lpPropLeft, LPSPropValue lpPropRight) +{ + LONG iRet; + + TRACE("(%p->0x%08lx,%p->0x%08lx)\n", lpPropLeft, lpPropLeft->ulPropTag, + lpPropRight, lpPropRight->ulPropTag); + + /* If the properties are not the same, sort by property type */ + if (PROP_TYPE(lpPropLeft->ulPropTag) != PROP_TYPE(lpPropRight->ulPropTag)) + return (LONG)PROP_TYPE(lpPropLeft->ulPropTag) - (LONG)PROP_TYPE(lpPropRight->ulPropTag); + + switch (PROP_TYPE(lpPropLeft->ulPropTag)) + { + case PT_UNSPECIFIED: + case PT_NULL: + return 0; /* NULLs are equal */ + case PT_I2: + return lpPropLeft->Value.i - lpPropRight->Value.i; + case PT_I4: + return lpPropLeft->Value.l - lpPropRight->Value.l; + case PT_I8: + if (lpPropLeft->Value.li.QuadPart > lpPropRight->Value.li.QuadPart) + return 1; + if (lpPropLeft->Value.li.QuadPart == lpPropRight->Value.li.QuadPart) + return 0; + return -1; + case PT_R4: + if (lpPropLeft->Value.flt > lpPropRight->Value.flt) + return 1; + if (lpPropLeft->Value.flt == lpPropRight->Value.flt) + return 0; + return -1; + case PT_APPTIME: + case PT_R8: + if (lpPropLeft->Value.dbl > lpPropRight->Value.dbl) + return 1; + if (lpPropLeft->Value.dbl == lpPropRight->Value.dbl) + return 0; + return -1; + case PT_CURRENCY: + if (lpPropLeft->Value.cur.int64 > lpPropRight->Value.cur.int64) + return 1; + if (lpPropLeft->Value.cur.int64 == lpPropRight->Value.cur.int64) + return 0; + return -1; + case PT_SYSTIME: + return CompareFileTime(&lpPropLeft->Value.ft, &lpPropRight->Value.ft); + case PT_BOOLEAN: + return (lpPropLeft->Value.b ? 1 : 0) - (lpPropRight->Value.b ? 1 : 0); + case PT_BINARY: + if (lpPropLeft->Value.bin.cb == lpPropRight->Value.bin.cb) + iRet = memcmp(lpPropLeft->Value.bin.lpb, lpPropRight->Value.bin.lpb, + lpPropLeft->Value.bin.cb); + else + { + iRet = memcmp(lpPropLeft->Value.bin.lpb, lpPropRight->Value.bin.lpb, + min(lpPropLeft->Value.bin.cb, lpPropRight->Value.bin.cb)); + + if (!iRet) + iRet = lpPropLeft->Value.bin.cb - lpPropRight->Value.bin.cb; + } + return iRet; + case PT_STRING8: + return lstrcmpA(lpPropLeft->Value.lpszA, lpPropRight->Value.lpszA); + case PT_UNICODE: + return strcmpW(lpPropLeft->Value.lpszW, lpPropRight->Value.lpszW); + case PT_ERROR: + if (lpPropLeft->Value.err > lpPropRight->Value.err) + return 1; + if (lpPropLeft->Value.err == lpPropRight->Value.err) + return 0; + return -1; + case PT_CLSID: + return memcmp(lpPropLeft->Value.lpguid, lpPropRight->Value.lpguid, + sizeof(GUID)); + } + FIXME("Unhandled property type %ld", PROP_TYPE(lpPropLeft->ulPropTag)); + return 0; +} + +/************************************************************************* + * PpropFindProp@12 (MAPI32.138) + * + * Find a property with a given property tag in a property array. + * + * PARAMS + * lpProps [I] Property array to search + * cValues [I] Number of properties in lpProps + * ulPropTag [I] Property tag to find + * + * RETURNS + * A pointer to the matching property, or NULL if none was found. + * + * NOTES + * if ulPropTag has a property type of PT_UNSPECIFIED, then only the property + * Ids need to match for a successful match to occur. + */ +LPSPropValue WINAPI PpropFindProp(LPSPropValue lpProps, ULONG cValues, ULONG ulPropTag) +{ + TRACE("(%p,%ld,%ld)\n", lpProps, cValues, ulPropTag); + + if (lpProps && cValues) + { + ULONG i; + for (i = 0; i < cValues; i++) + { + if (!FBadPropTag(lpProps[i].ulPropTag) && + (lpProps[i].ulPropTag == ulPropTag || + (PROP_TYPE(ulPropTag) == PT_UNSPECIFIED && + PROP_ID(lpProps[i].ulPropTag) == PROP_ID(ulPropTag)))) + return &lpProps[i]; + } + } + return NULL; +} + +/************************************************************************* + * ScCountProps@12 (MAPI32.170) + * + * Validate and determine the length of an array of properties. + * + * PARAMS + * iCount [I] Length of the lpProps array + * lpProps [I] Array of properties to validate/size + * pcBytes [O] If non-NULL, destination for the size of the property array + * + * RETURNS + * Success: S_OK. If pcBytes is non-NULL, it contains the size of the propery array. + * Failure: MAPI_E_INVALID_PARAMETER, if any parameter is invalid or validation + * of the property array fails. + */ +SCODE WINAPI ScCountProps(INT iCount, LPSPropValue lpProps, ULONG *pcBytes) +{ + ULONG i, ulCount = iCount, ulBytes = 0; + + TRACE("(%d,%p,%p)\n", iCount, lpProps, pcBytes); + + if (iCount <= 0 || !lpProps || + IsBadReadPtr(lpProps, iCount * sizeof(SPropValue))) + return MAPI_E_INVALID_PARAMETER; + + for (i = 0; i < ulCount; i++) + { + ULONG ulPropSize = 0; + + if (FBadProp(&lpProps[i]) || lpProps[i].ulPropTag == PROP_ID_NULL || + lpProps[i].ulPropTag == PROP_ID_INVALID) + return MAPI_E_INVALID_PARAMETER; + + if (PROP_TYPE(lpProps[i].ulPropTag) != PT_OBJECT) + { + ulPropSize = UlPropSize(&lpProps[i]); + if (!ulPropSize) + return MAPI_E_INVALID_PARAMETER; + } + + switch (PROP_TYPE(lpProps[i].ulPropTag)) + { + case PT_STRING8: + case PT_UNICODE: + case PT_CLSID: + case PT_BINARY: + case PT_MV_I2: + case PT_MV_I4: + case PT_MV_I8: + case PT_MV_R4: + case PT_MV_R8: + case PT_MV_CURRENCY: + case PT_MV_SYSTIME: + case PT_MV_APPTIME: + ulPropSize += sizeof(SPropValue); + break; + case PT_MV_CLSID: + ulPropSize += lpProps[i].Value.MVszA.cValues * sizeof(char*) + sizeof(SPropValue); + break; + case PT_MV_STRING8: + case PT_MV_UNICODE: + ulPropSize += lpProps[i].Value.MVszA.cValues * sizeof(char*) + sizeof(SPropValue); + break; + case PT_MV_BINARY: + ulPropSize += lpProps[i].Value.MVbin.cValues * sizeof(SBinary) + sizeof(SPropValue); + break; + default: + ulPropSize = sizeof(SPropValue); + break; + } + ulBytes += ulPropSize; + } + if (pcBytes) + *pcBytes = ulBytes; + + return S_OK; +} + +/************************************************************************* + * LpValFindProp@12 (MAPI32.173) + * + * Find a property with a given property id in a property array. + * + * PARAMS + * ulPropTag [I] Property tag containing property id to find + * cValues [I] Number of properties in lpProps + * lpProps [I] Property array to search + * + * RETURNS + * A pointer to the matching property, or NULL if none was found. + * + * NOTES + * This function matches only on the property id and does not care if the + * property types differ. + */ +LPSPropValue WINAPI LpValFindProp(ULONG ulPropTag, ULONG cValues, LPSPropValue lpProps) +{ + TRACE("(%ld,%ld,%p)\n", ulPropTag, cValues, lpProps); + + if (lpProps && cValues) + { + ULONG i; + for (i = 0; i < cValues; i++) + { + if (PROP_ID(ulPropTag) == PROP_ID(lpProps[i].ulPropTag)) + return &lpProps[i]; + } + } + return NULL; +} + +/************************************************************************* + * FBadRglpszA@8 (MAPI32.175) + * + * Determine if an array of strings is invalid + * + * PARAMS + * lppszStrs [I] Array of strings to check + * ulCount [I] Number of strings in lppszStrs + * + * RETURNS + * TRUE, if lppszStrs is invalid, FALSE otherwise. + */ +BOOL WINAPI FBadRglpszA(LPSTR *lppszStrs, ULONG ulCount) +{ + ULONG i; + + TRACE("(%p,%ld)\n", lppszStrs, ulCount); + + if (!ulCount) + return FALSE; + + if (!lppszStrs || IsBadReadPtr(lppszStrs, ulCount * sizeof(LPWSTR))) + return TRUE; + + for (i = 0; i < ulCount; i++) + { + if (!lppszStrs[i] || IsBadStringPtrA(lppszStrs[i], -1)) + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * FBadRglpszW@8 (MAPI32.176) + * + * See FBadRglpszA. + */ +BOOL WINAPI FBadRglpszW(LPWSTR *lppszStrs, ULONG ulCount) +{ + ULONG i; + + TRACE("(%p,%ld)\n", lppszStrs, ulCount); + + if (!ulCount) + return FALSE; + + if (!lppszStrs || IsBadReadPtr(lppszStrs, ulCount * sizeof(LPWSTR))) + return TRUE; + + for (i = 0; i < ulCount; i++) + { + if (!lppszStrs[i] || IsBadStringPtrW(lppszStrs[i], -1)) + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * FBadRowSet@4 (MAPI32.177) + * + * Determine if a row is invalid + * + * PARAMS + * lpRow [I] Row to check + * + * RETURNS + * TRUE, if lpRow is invalid, FALSE otherwise. + */ +BOOL WINAPI FBadRowSet(LPSRowSet lpRowSet) +{ + ULONG i; + TRACE("(%p)\n", lpRowSet); + + if (!lpRowSet || IsBadReadPtr(lpRowSet, CbSRowSet(lpRowSet))) + return TRUE; + + for (i = 0; i < lpRowSet->cRows; i++) + { + if (FBadRow(&lpRowSet->aRow[i])) + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * FBadPropTag@4 (MAPI32.179) + * + * Determine if a property tag is invalid + * + * PARAMS + * ulPropTag [I] Property tag to check + * + * RETURNS + * TRUE, if ulPropTag is invalid, FALSE otherwise. + */ +ULONG WINAPI FBadPropTag(ULONG ulPropTag) +{ + TRACE("(0x%08lx)\n", ulPropTag); + + switch (ulPropTag & (~MV_FLAG & PROP_TYPE_MASK)) + { + case PT_UNSPECIFIED: + case PT_NULL: + case PT_I2: + case PT_LONG: + case PT_R4: + case PT_DOUBLE: + case PT_CURRENCY: + case PT_APPTIME: + case PT_ERROR: + case PT_BOOLEAN: + case PT_OBJECT: + case PT_I8: + case PT_STRING8: + case PT_UNICODE: + case PT_SYSTIME: + case PT_CLSID: + case PT_BINARY: + return FALSE; + } + return TRUE; +} + +/************************************************************************* + * FBadRow@4 (MAPI32.180) + * + * Determine if a row is invalid + * + * PARAMS + * lpRow [I] Row to check + * + * RETURNS + * TRUE, if lpRow is invalid, FALSE otherwise. + */ +ULONG WINAPI FBadRow(LPSRow lpRow) +{ + ULONG i; + TRACE("(%p)\n", lpRow); + + if (!lpRow || IsBadReadPtr(lpRow, sizeof(SRow)) || !lpRow->lpProps || + IsBadReadPtr(lpRow->lpProps, lpRow->cValues * sizeof(SPropValue))) + return TRUE; + + for (i = 0; i < lpRow->cValues; i++) + { + if (FBadProp(&lpRow->lpProps[i])) + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * FBadProp@4 (MAPI32.181) + * + * Determine if a property is invalid + * + * PARAMS + * lpProp [I] Property to check + * + * RETURNS + * TRUE, if lpProp is invalid, FALSE otherwise. + */ +ULONG WINAPI FBadProp(LPSPropValue lpProp) +{ + ULONG i; + + if (!lpProp || IsBadReadPtr(lpProp, sizeof(SPropValue)) || + FBadPropTag(lpProp->ulPropTag)) + return TRUE; + + switch (PROP_TYPE(lpProp->ulPropTag)) + { + /* Single value properties containing pointers */ + case PT_STRING8: + if (!lpProp->Value.lpszA || IsBadStringPtrA(lpProp->Value.lpszA, -1)) + return TRUE; + break; + case PT_UNICODE: + if (!lpProp->Value.lpszW || IsBadStringPtrW(lpProp->Value.lpszW, -1)) + return TRUE; + break; + case PT_BINARY: + if (IsBadReadPtr(lpProp->Value.bin.lpb, lpProp->Value.bin.cb)) + return TRUE; + break; + case PT_CLSID: + if (IsBadReadPtr(lpProp->Value.lpguid, sizeof(GUID))) + return TRUE; + break; + + /* Multiple value properties (arrays) containing no pointers */ + case PT_MV_I2: + return PROP_BadArray(lpProp, sizeof(SHORT)); + case PT_MV_LONG: + return PROP_BadArray(lpProp, sizeof(LONG)); + case PT_MV_LONGLONG: + return PROP_BadArray(lpProp, sizeof(LONG64)); + case PT_MV_FLOAT: + return PROP_BadArray(lpProp, sizeof(float)); + case PT_MV_SYSTIME: + return PROP_BadArray(lpProp, sizeof(FILETIME)); + case PT_MV_APPTIME: + case PT_MV_DOUBLE: + return PROP_BadArray(lpProp, sizeof(double)); + case PT_MV_CURRENCY: + return PROP_BadArray(lpProp, sizeof(CY)); + case PT_MV_CLSID: + return PROP_BadArray(lpProp, sizeof(GUID)); + + /* Multiple value properties containing pointers */ + case PT_MV_STRING8: + return FBadRglpszA(lpProp->Value.MVszA.lppszA, + lpProp->Value.MVszA.cValues); + case PT_MV_UNICODE: + return FBadRglpszW(lpProp->Value.MVszW.lppszW, + lpProp->Value.MVszW.cValues); + case PT_MV_BINARY: + if (PROP_BadArray(lpProp, sizeof(SBinary))) + return TRUE; + + for (i = 0; i < lpProp->Value.MVszW.cValues; i++) + { + if (IsBadReadPtr(lpProp->Value.MVbin.lpbin[i].lpb, + lpProp->Value.MVbin.lpbin[i].cb)) + return TRUE; + } + break; + } + return FALSE; +} + +/************************************************************************* + * FBadColumnSet@4 (MAPI32.182) + * + * Determine if an array of property tags is invalid + * + * PARAMS + * lpCols [I] Property tag array to check + * + * RETURNS + * TRUE, if lpCols is invalid, FALSE otherwise. + */ +ULONG WINAPI FBadColumnSet(LPSPropTagArray lpCols) +{ + ULONG ulRet = FALSE, i; + + TRACE("(%p)\n", lpCols); + + if (!lpCols || IsBadReadPtr(lpCols, CbSPropTagArray(lpCols))) + ulRet = TRUE; + else + { + for (i = 0; i < lpCols->cValues; i++) + { + if ((lpCols->aulPropTag[i] & PROP_TYPE_MASK) == PT_ERROR || + FBadPropTag(lpCols->aulPropTag[i])) + { + ulRet = TRUE; + break; + } + } + } + TRACE("Returning %s\n", ulRet ? "TRUE" : "FALSE"); + return ulRet; +} diff --git a/dlls/mapi32/util.c b/dlls/mapi32/util.c new file mode 100644 index 00000000000..f885d6a5b4f --- /dev/null +++ b/dlls/mapi32/util.c @@ -0,0 +1,541 @@ +/* + * MAPI Utility functions + * + * Copyright 2004 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winerror.h" +#include "winternl.h" +#include "objbase.h" +#include "shlwapi.h" +#include "wine/debug.h" +#include "wine/unicode.h" +#include "mapival.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mapi); + +/************************************************************************** + * ScInitMapiUtil (MAPI32.33) + * + * Initialise Mapi utility functions. + * + * PARAMS + * ulReserved [I] Reserved, pass 0. + * + * RETURNS + * Success: S_OK. Mapi utility functions may be called. + * Failure: MAPI_E_INVALID_PARAMETER, if ulReserved is not 0. + * + * NOTES + * Your application does not need to call this function unless it does not + * call MAPIInitialize()/MAPIUninitialize(). + */ +SCODE WINAPI ScInitMapiUtil(ULONG ulReserved) +{ + FIXME("(0x%08lx)stub!\n", ulReserved); + if (ulReserved) + return MAPI_E_INVALID_PARAMETER; + return S_OK; +} + +/************************************************************************** + * DeinitMapiUtil (MAPI32.34) + * + * Uninitialise Mapi utility functions. + * + * PARAMS + * None. + * + * RETURNS + * Nothing. + * + * NOTES + * Your application does not need to call this function unless it does not + * call MAPIInitialize()/MAPIUninitialize(). + */ +VOID WINAPI DeinitMapiUtil(void) +{ + FIXME("()stub!\n"); +} + +typedef LPVOID *LPMAPIALLOCBUFFER; + +/************************************************************************** + * MAPIAllocateBuffer (MAPI32.12) + * MAPIAllocateBuffer@8 (MAPI32.13) + * + * Allocate a block of memory. + * + * PARAMS + * cbSize [I] Size of the block to allocate in bytes + * lppBuffer [O] Destination for pointer to allocated memory + * + * RETURNS + * Success: S_OK. *lppBuffer is filled with a pointer to a memory block of + * length cbSize bytes. + * Failure: MAPI_E_INVALID_PARAMETER, if lppBuffer is NULL. + * MAPI_E_NOT_ENOUGH_MEMORY, if the memory allocation fails. + * + * NOTES + * Memory allocated with this function should be freed with MAPIFreeBuffer(). + * Further allocations of memory may be linked to the pointer returned using + * MAPIAllocateMore(). Linked allocations are freed when the initial pointer + * is feed. + */ +SCODE WINAPI MAPIAllocateBuffer(ULONG cbSize, LPVOID *lppBuffer) +{ + LPMAPIALLOCBUFFER lpBuff; + + TRACE("(%ld,%p)\n", cbSize, lppBuffer); + + if (!lppBuffer) + return E_INVALIDARG; + + lpBuff = (LPMAPIALLOCBUFFER)HeapAlloc(GetProcessHeap(), 0, cbSize + sizeof(*lpBuff)); + if (!lpBuff) + return MAPI_E_NOT_ENOUGH_MEMORY; + + TRACE("initial allocation:%p, returning %p\n", lpBuff, lpBuff + 1); + *lpBuff++ = NULL; + *lppBuffer = lpBuff; + return S_OK; +} + +/************************************************************************** + * MAPIAllocateMore (MAPI32.14) + * MAPIAllocateMore@12 (MAPI32.15) + * + * Allocate a block of memory linked to a previous allocation. + * + * PARAMS + * cbSize [I] Size of the block to allocate in bytes + * lpOrig [I] Initial allocation to link to, from MAPIAllocateBuffer() + * lppBuffer [O] Destination for pointer to allocated memory + * + * RETURNS + * Success: S_OK. *lppBuffer is filled with a pointer to a memory block of + * length cbSize bytes. + * Failure: MAPI_E_INVALID_PARAMETER, if lpOrig or lppBuffer is invalid. + * MAPI_E_NOT_ENOUGH_MEMORY, if memory allocation fails. + * + * NOTES + * Memory allocated with this function and stored in *lppBuffer is freed + * when lpOrig is passed to MAPIFreeBuffer(). It should not be freed independently. + */ +SCODE WINAPI MAPIAllocateMore(ULONG cbSize, LPVOID lpOrig, LPVOID *lppBuffer) +{ + LPMAPIALLOCBUFFER lpBuff = lpOrig; + + TRACE("(%ld,%p,%p)\n", cbSize, lpOrig, lppBuffer); + + if (!lppBuffer || !lpBuff || !--lpBuff) + return E_INVALIDARG; + + /* Find the last allocation in the chain */ + while (*lpBuff) + { + TRACE("linked:%p->%p\n", lpBuff, *lpBuff); + lpBuff = *lpBuff; + } + + if (SUCCEEDED(MAPIAllocateBuffer(cbSize, lppBuffer))) + { + *lpBuff = ((LPMAPIALLOCBUFFER)*lppBuffer) - 1; + TRACE("linking %p->%p\n", lpBuff, *lpBuff); + } + return *lppBuffer ? S_OK : MAPI_E_NOT_ENOUGH_MEMORY; +} + +/************************************************************************** + * MAPIFreeBuffer (MAPI32.16) + * MAPIFreeBuffer@4 (MAPI32.17) + * + * Free a block of memory and any linked allocations associated with it. + * + * PARAMS + * lpBuffer [I] Memory to free, returned from MAPIAllocateBuffer() + * + * RETURNS + * S_OK. + */ +ULONG WINAPI MAPIFreeBuffer(LPVOID lpBuffer) +{ + LPMAPIALLOCBUFFER lpBuff = lpBuffer; + + TRACE("(%p)\n", lpBuffer); + + if (lpBuff && --lpBuff) + { + while (lpBuff) + { + LPVOID lpFree = lpBuff; + + lpBuff = *lpBuff; + + TRACE("linked:%p->%p, freeing %p\n", lpFree, lpBuff, lpFree); + HeapFree(GetProcessHeap(), 0, lpFree); + } + } + return S_OK; +} + +/************************************************************************* + * HrThisThreadAdviseSink@8 (MAPI32.42) + * + * Ensure that an advise sink is only notified in its originating thread. + * + * PARAMS + * lpSink [I] IMAPIAdviseSink interface to be protected + * lppNewSink [I] Destination for wrapper IMAPIAdviseSink interface + * + * RETURNS + * Success: S_OK. *lppNewSink contains a new sink to use in place of lpSink. + * Failure: E_INVALIDARG, if any parameter is invalid. + */ +HRESULT WINAPI HrThisThreadAdviseSink(LPMAPIADVISESINK lpSink, LPMAPIADVISESINK* lppNewSink) +{ + FIXME("(%p,%p)semi-stub\n", lpSink, lppNewSink); + + if (!lpSink || !lppNewSink) + return E_INVALIDARG; + + /* Don't wrap the sink for now, just copy it */ + *lppNewSink = lpSink; + IMAPIAdviseSink_AddRef(lpSink); + return S_OK; +} + +/************************************************************************* + * SwapPlong@8 (MAPI32.47) + * + * Swap the bytes in a ULONG array. + * + * PARAMS + * lpData [O] Array to swap bytes in + * ulLen [I] Number of ULONG element to swap the bytes of + * + * RETURNS + * Nothing. + */ +VOID WINAPI SwapPlong(PULONG lpData, ULONG ulLen) +{ + ULONG i; + + for (i = 0; i < ulLen; i++) + lpData[i] = RtlUlongByteSwap(lpData[i]); +} + +/************************************************************************* + * SwapPword@8 (MAPI32.48) + * + * Swap the bytes in a USHORT array. + * + * PARAMS + * lpData [O] Array to swap bytes in + * ulLen [I] Number of USHORT element to swap the bytes of + * + * RETURNS + * Nothing. + */ +VOID WINAPI SwapPword(PUSHORT lpData, ULONG ulLen) +{ + ULONG i; + + for (i = 0; i < ulLen; i++) + lpData[i] = RtlUshortByteSwap(lpData[i]); +} + +/************************************************************************** + * MNLS_lstrlenW@4 (MAPI32.62) + * + * Calculate the length of a Unicode string. + * + * PARAMS + * lpszStr [I] String to calculate the length of + * + * RETURNS + * The length of lpszStr in Unicode characters. + */ +ULONG WINAPI MNLS_lstrlenW(LPCWSTR lpszStr) +{ + TRACE("(%s)\n", debugstr_w(lpszStr)); + return strlenW(lpszStr); +} + +/************************************************************************* + * MNLS_lstrcmpW@8 (MAPI32.63) + * + * Compare two Unicode strings. + * + * PARAMS + * lpszLeft [I] First string to compare + * lpszRight [I] Second string to compare + * + * RETURNS + * An integer less than, equal to or greater than 0, indicating that + * lpszLeft is less than, the same, or greater than lpszRight. + */ +INT WINAPI MNLS_lstrcmpW(LPCWSTR lpszLeft, LPCWSTR lpszRight) +{ + TRACE("(%s,%s)\n", debugstr_w(lpszLeft), debugstr_w(lpszRight)); + return strcmpW(lpszLeft, lpszRight); +} + +/************************************************************************* + * MNLS_lstrcpyW@8 (MAPI32.64) + * + * Copy a Unicode string to another string. + * + * PARAMS + * lpszDest [O] Destination string + * lpszSrc [I] Source string + * + * RETURNS + * The length lpszDest in Unicode characters. + */ +ULONG WINAPI MNLS_lstrcpyW(LPWSTR lpszDest, LPCWSTR lpszSrc) +{ + ULONG len; + + TRACE("(%p,%s)\n", lpszDest, debugstr_w(lpszSrc)); + len = (strlenW(lpszSrc) + 1) * sizeof(WCHAR); + memcpy(lpszDest, lpszSrc, len); + return len; +} + +/************************************************************************* + * MNLS_CompareStringW@12 (MAPI32.65) + * + * Compare two Unicode strings. + * + * PARAMS + * dwCp [I] Copde page for the comparason + * lpszLeft [I] First string to compare + * lpszRight [I] Second string to compare + * + * RETURNS + * CSTR_LESS_THAN, CSTR_EQUAL or CSTR_GREATER_THAN, indicating that + * lpszLeft is less than, the same, or greater than lpszRight. + */ +INT WINAPI MNLS_CompareStringW(DWORD dwCp, LPCWSTR lpszLeft, LPCWSTR lpszRight) +{ + INT ret; + + TRACE("0x%08lx,%s,%s\n", dwCp, debugstr_w(lpszLeft), debugstr_w(lpszRight)); + ret = MNLS_lstrcmpW(lpszLeft, lpszRight); + return ret < 0 ? CSTR_LESS_THAN : ret ? CSTR_GREATER_THAN : CSTR_EQUAL; +} + + +/************************************************************************** + * FtAddFt@16 (MAPI32.121) + * + * Add two FILETIME's together. + * + * PARAMS + * ftLeft [I] FILETIME to add to ftRight + * ftRight [I] FILETIME to add to ftLeft + * + * RETURNS + * The sum of ftLeft and ftRight + */ +LONGLONG WINAPI MAPI32_FtAddFt(FILETIME ftLeft, FILETIME ftRight) +{ + LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight; + + return *pl + *pr; +} + +/************************************************************************** + * FtSubFt@16 (MAPI32.123) + * + * Subtract two FILETIME's together. + * + * PARAMS + * ftLeft [I] Initial FILETIME + * ftRight [I] FILETIME to subtract from ftLeft + * + * RETURNS + * The remainder after ftRight is subtracted from ftLeft. + */ +LONGLONG WINAPI MAPI32_FtSubFt(FILETIME ftLeft, FILETIME ftRight) +{ + LONGLONG *pl = (LONGLONG*)&ftLeft, *pr = (LONGLONG*)&ftRight; + + return *pr - *pl; +} + +/************************************************************************** + * FtMulDw@12 (MAPI32.124) + * + * Multiply a FILETIME by a DWORD. + * + * PARAMS + * dwLeft [I] DWORD to multiply with ftRight + * ftRight [I] FILETIME to multiply with dwLeft + * + * RETURNS + * The product of dwLeft and ftRight + */ +LONGLONG WINAPI MAPI32_FtMulDw(DWORD dwLeft, FILETIME ftRight) +{ + LONGLONG *pr = (LONGLONG*)&ftRight; + + return (LONGLONG)dwLeft * (*pr); +} + +/************************************************************************** + * FtMulDwDw@8 (MAPI32.125) + * + * Multiply two DWORD, giving the result as a FILETIME. + * + * PARAMS + * dwLeft [I] DWORD to multiply with dwRight + * dwRight [I] DWORD to multiply with dwLeft + * + * RETURNS + * The product of ftMultiplier and ftMultiplicand as a FILETIME. + */ +LONGLONG WINAPI MAPI32_FtMulDwDw(DWORD dwLeft, DWORD dwRight) +{ + return (LONGLONG)dwLeft * (LONGLONG)dwRight; +} + +/************************************************************************** + * FtNegFt@8 (MAPI32.126) + * + * Negate a FILETIME. + * + * PARAMS + * ft [I] FILETIME to negate + * + * RETURNS + * The negation of ft. + */ +LONGLONG WINAPI MAPI32_FtNegFt(FILETIME ft) +{ + LONGLONG *p = (LONGLONG*)&ft; + + return - *p; +} + +/************************************************************************** + * UlAddRef@4 (MAPI32.128) + * + * Add a reference to an object. + * + * PARAMS + * lpUnk [I] Object to add a reference to. + * + * RETURNS + * The new reference count of the object, or 0 if lpUnk is NULL. + * + * NOTES + * See IUnknown_AddRef. + */ +ULONG WINAPI UlAddRef(void *lpUnk) +{ + TRACE("(%p)\n", lpUnk); + + if (!lpUnk) + return 0UL; + return IUnknown_AddRef((LPUNKNOWN)lpUnk); +} + +/************************************************************************** + * UlRelease@4 (MAPI32.129) + * + * Remove a reference from an object. + * + * PARAMS + * lpUnk [I] Object to remove reference from. + * + * RETURNS + * The new reference count of the object, or 0 if lpUnk is NULL. If lpUnk is + * non-NULL and this function returns 0, the object pointed to by lpUnk has + * been released. + * + * NOTES + * See IUnknown_Release. + */ +ULONG WINAPI UlRelease(void *lpUnk) +{ + TRACE("(%p)\n", lpUnk); + + if (!lpUnk) + return 0UL; + return IUnknown_Release((LPUNKNOWN)lpUnk); +} + +/************************************************************************* + * OpenStreamOnFile@24 (MAPI32.147) + * + * Create a stream on a file. + * + * PARAMS + * lpAlloc [I] Memory allocation function + * lpFree [I] Memory free function + * ulFlags [I] Flags controlling the opening process + * lpszPath [I] Path of file to create stream on + * lpszPrefix [I] Prefix of the temporary file name (if ulFlags includes SOF_UNIQUEFILENAME) + * lppStream [O] Destination for created stream + * + * RETURNS + * Success: S_OK. lppStream contains the new stream object + * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code + * describing the error. + */ +HRESULT WINAPI OpenStreamOnFile(LPALLOCATEBUFFER lpAlloc, LPFREEBUFFER lpFree, + ULONG ulFlags, LPWSTR lpszPath, LPWSTR lpszPrefix, + LPSTREAM *lppStream) +{ + WCHAR szBuff[MAX_PATH]; + DWORD dwMode = STGM_READWRITE, dwAttributes = 0; + HRESULT hRet; + + TRACE("(%p,%p,0x%08lx,%s,%s,%p)\n", lpAlloc, lpFree, ulFlags, + debugstr_a((LPSTR)lpszPath), debugstr_a((LPSTR)lpszPrefix), lppStream); + + if (lppStream) + *lppStream = NULL; + + if (ulFlags & SOF_UNIQUEFILENAME) + { + FIXME("Should generate a temporary name\n"); + return E_INVALIDARG; + } + + if (!lpszPath || !lppStream) + return E_INVALIDARG; + + /* FIXME: Should probably munge mode and attributes, and should handle + * Unicode arguments (I assume MAPI_UNICODE is set in ulFlags if + * we are being passed Unicode strings; MSDN doesn't say). + * This implementation is just enough for Outlook97 to start. + */ + MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpszPath, -1, szBuff, MAX_PATH); + hRet = SHCreateStreamOnFileEx(szBuff, dwMode, dwAttributes, TRUE, + NULL, lppStream); + return hRet; +}