windows-nt/Source/XPSP1/NT/enduser/netmeeting/ulsldap/utils.cpp
2020-09-26 16:20:57 +08:00

1014 lines
22 KiB
C++

//****************************************************************************
//
// Module: ULS.DLL
// File: utils.cpp
// Content: Miscellaneous utility functions and classes
//
// Copyright (c) Microsoft Corporation 1996-1997
//
//****************************************************************************
#include "ulsp.h"
//****************************************************************************
// HRESULT
// SetLPTSTR (LPTSTR *ppszName, LPCTSTR pszUserName)
//
// Purpose: Clone the provided string into a newly allocated buffer.
//
// Parameters:
// ppszName The buffer to receive a newly allocated string buffer.
// pszUserName The provided name string.
//
// Return Value:
// S_OK success if the string can be cloned.
// ILS_E_MEMORY if the string cannot be cloned.
//****************************************************************************
HRESULT
SetLPTSTR (LPTSTR *ppszName, LPCTSTR pszUserName)
{
HRESULT hr;
TCHAR *pszNew = My_strdup (pszUserName);
if (pszNew != NULL)
{
// Free the old name
//
::MemFree (*ppszName);
*ppszName = pszNew;
hr = S_OK;
}
else
{
hr = ILS_E_MEMORY;
}
return hr;
}
//****************************************************************************
// HRESULT
// SafeSetLPTSTR (LPTSTR *ppszName, LPCTSTR pszUserName)
//
// Purpose: Clone the provided string into a newly allocated buffer.
// It is ok that the provided string is NULL.
//
// Parameters:
// ppszName The buffer to receive a newly allocated string buffer.
// pszUserName The provided name string.
//
// Return Value:
// S_OK success if the string can be cloned.
// ILS_E_MEMORY if the non-null string cannot be cloned.
//****************************************************************************
HRESULT
SafeSetLPTSTR (LPTSTR *ppszName, LPCTSTR pszUserName)
{
if (pszUserName == NULL)
{
MemFree (*ppszName);
*ppszName = NULL;
return S_FALSE;
}
return SetLPTSTR (ppszName, pszUserName);
}
//****************************************************************************
// HRESULT
// SetOffsetString ( TCHAR **ppszDst, BYTE *pSrcBase, ULONG uSrcOffset )
//
// Purpose: Clone the provided string into a newly allocated buffer.
// If the source string is null or empty, the destination string
// will be null.
//
// Parameters:
//
// Return Value:
// S_OK success if the string can be cloned.
// S_FALSE the destination string is null
// ILS_E_MEMORY if the string cannot be cloned.
//****************************************************************************
HRESULT
SetOffsetString ( TCHAR **ppszDst, BYTE *pSrcBase, ULONG uSrcOffset )
{
HRESULT hr = S_FALSE;
TCHAR *pszNew = NULL;
if (uSrcOffset != INVALID_OFFSET)
{
TCHAR *pszSrc = (TCHAR *) (pSrcBase + uSrcOffset);
if (*pszSrc != TEXT ('\0'))
{
pszNew = My_strdup (pszSrc);
hr = (pszNew != NULL) ? S_OK : ILS_E_MEMORY;
}
}
if (SUCCEEDED (hr))
{
::MemFree (*ppszDst);
*ppszDst = pszNew;
}
return hr;
}
//****************************************************************************
// HRESULT
// LPTSTR_to_BSTR (BSTR *pbstr, LPCTSTR psz)
//
// Purpose: Make a BSTR string from an LPTSTR string
//
// Parameters:
// pbstr The buffer to receive a newly allocated BSTR string.
// psz The LPTSTR string.
//
// Return Value:
// S_OK success if the string can be cloned.
// ILS_E_FAIL cannot convert the string to BSTR
// ILS_E_MEMORY cannot allocate enough memory for the BSTR string.
//****************************************************************************
HRESULT
LPTSTR_to_BSTR (BSTR *pbstr, LPCTSTR psz)
{
#ifndef _UNICODE
BSTR bstr;
int i;
HRESULT hr;
// compute the length of the required BSTR
//
i = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);
if (i <= 0)
{
return ILS_E_FAIL;
};
// allocate the widestr, +1 for terminating null
//
bstr = SysAllocStringLen(NULL, i-1); // SysAllocStringLen adds 1
if (bstr != NULL)
{
MultiByteToWideChar(CP_ACP, 0, psz, -1, (LPWSTR)bstr, i);
((LPWSTR)bstr)[i - 1] = 0;
*pbstr = bstr;
hr = S_OK;
}
else
{
hr = ILS_E_MEMORY;
};
return hr;
#else
BSTR bstr;
bstr = SysAllocString(psz);
if (bstr != NULL)
{
*pbstr = bstr;
return S_OK;
}
else
{
return ILS_E_MEMORY;
};
#endif // _UNICODE
}
//****************************************************************************
// HRESULT
// BSTR_to_LPTSTR (LPTSTR *ppsz, BSTR bstr)
//
// Purpose: Make a LPTSTR string from an BSTR string
//
// Parameters:
// ppsz The buffer to receive a newly allocated LPTSTR string.
// bstr The BSTR string.
//
// Return Value:
// S_OK success if the string can be cloned.
// ILS_E_FAIL cannot convert the string to BSTR
// ILS_E_MEMORY cannot allocate enough memory for the BSTR string.
//****************************************************************************
HRESULT
BSTR_to_LPTSTR (LPTSTR *ppsz, BSTR bstr)
{
#ifndef _UNICODE
LPTSTR psz;
int i;
HRESULT hr;
// compute the length of the required BSTR
//
i = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)bstr, -1, NULL, 0, NULL, NULL);
if (i <= 0)
{
return ILS_E_FAIL;
};
// allocate the widestr, +1 for terminating null
//
psz = (TCHAR *) ::MemAlloc (i * sizeof (TCHAR));
if (psz != NULL)
{
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)bstr, -1, psz, i, NULL, NULL);
*ppsz = psz;
hr = S_OK;
}
else
{
hr = ILS_E_MEMORY;
};
return hr;
#else
LPTSTR psz = NULL;
HRESULT hr;
hr = SetLPTSTR(&psz, (LPTSTR)bstr);
if (hr == S_OK)
{
*ppsz = psz;
};
return hr;
#endif // _UNICODE
}
//****************************************************************************
// CList::CList (void)
//
// Purpose: Constructor for the CList class
//
// Parameters: None
//****************************************************************************
CList::CList (void)
{
pHead = NULL;
pTail = NULL;
return;
}
//****************************************************************************
// CList::~CList (void)
//
// Purpose: Constructor for the CList class
//
// Parameters: None
//****************************************************************************
CList::~CList (void)
{
Flush();
return;
}
//****************************************************************************
// HRESULT
// CList::Insert (LPVOID pv)
//
// Purpose: Insert an object at the beginning of the list
//
// Parameters: None
//****************************************************************************
HRESULT
CList::Insert (LPVOID pv)
{
PNODE pNode;
pNode = new NODE;
if (pNode == NULL)
{
return ILS_E_MEMORY;
};
pNode->pNext = pHead;
pNode->pv = pv;
pHead = pNode;
if (pTail == NULL)
{
// This is the first node
//
pTail = pNode;
};
return NOERROR;
}
//****************************************************************************
// HRESULT
// CList::Append (LPVOID pv)
//
// Purpose: Append an object to the end of the list
//
// Parameters: None
//****************************************************************************
HRESULT
CList::Append (LPVOID pv)
{
PNODE pNode;
pNode = new NODE;
if (pNode == NULL)
{
return ILS_E_MEMORY;
};
pNode->pNext = NULL;
pNode->pv = pv;
if (pHead == NULL)
{
pHead = pNode;
};
if (pTail != NULL)
{
pTail->pNext = pNode;
};
pTail = pNode;
return NOERROR;
}
//****************************************************************************
// HRESULT
// CList::Remove (LPVOID pv)
//
// Purpose: Append an object to the end of the list
//
// Parameters: None
//****************************************************************************
HRESULT
CList::Remove (LPVOID pv)
{
PNODE pNode, pPrev;
HRESULT hr;
pNode = pHead;
pPrev = NULL;
while (pNode != NULL)
{
// Matching the requested node
//
if (pNode->pv == pv)
{
break; // found!!!
};
pPrev = pNode;
pNode = pNode->pNext;
};
if (pNode != NULL)
{
// We found the node to remove
// Update relevant pointer
//
if (pTail == pNode)
{
pTail = pPrev;
};
if (pPrev != NULL)
{
pPrev->pNext = pNode->pNext;
}
else
{
pHead = pNode->pNext;
};
delete pNode;
hr = NOERROR;
}
else
{
hr = S_FALSE;
};
return hr;
}
//****************************************************************************
// HRESULT
// CList::Find (LPVOID pv)
//
// Purpose: Find an object in the list
//
// Parameters: None
//****************************************************************************
HRESULT
CList::Find (LPVOID pv)
{
PNODE pNode;
pNode = pHead;
while (pNode != NULL)
{
// Matching the requested node
//
if (pNode->pv == pv)
{
break; // found!!!
};
pNode = pNode->pNext;
};
return (pNode != NULL ? NOERROR : S_FALSE);
}
//****************************************************************************
// HRESULT
// CList::FindStorage (LPVOID *ppv, LPVOID pv)
//
// Purpose: Find an object in the list and returns the object storage.
// This call is useful for search-and-replace operations.
//
// Parameters: None
//****************************************************************************
HRESULT
CList::FindStorage (LPVOID *ppv, LPVOID pv)
{
PNODE pNode;
HRESULT hr;
pNode = pHead;
while (pNode != NULL)
{
// Matching the requested node
//
if (pNode->pv == pv)
{
break; // found!!!
};
pNode = pNode->pNext;
};
if (pNode != NULL)
{
*ppv = &(pNode->pv);
hr = NOERROR;
}
else
{
*ppv = NULL;
hr = S_FALSE;
};
return hr;
}
//****************************************************************************
// HRESULT
// CList::Enumerate (HANDLE *phEnum)
//
// Purpose: Start object enumeration
//
// Parameters: None
//****************************************************************************
HRESULT
CList::Enumerate (HANDLE *phEnum)
{
*phEnum = (HANDLE)pHead;
return NOERROR;
}
//****************************************************************************
// HRESULT
// CList::Next (HANDLE *phEnum, LPVOID *ppv)
//
// Purpose: Obtain the next enumerated object
//
// Parameters: None
//****************************************************************************
HRESULT
CList::Next (HANDLE *phEnum, LPVOID *ppv)
{
PNODE pNext;
HRESULT hr;
pNext = (PNODE)*phEnum;
if (pNext == NULL)
{
*ppv = NULL;
hr = S_FALSE;
}
else
{
*ppv = pNext->pv;
*phEnum = (HANDLE)(pNext->pNext);
hr = NOERROR;
};
return hr;
}
//****************************************************************************
// HRESULT
// CList::NextStorage (HANDLE *phEnum, LPVOID *ppv)
//
// Purpose: Obtain the storage of the next enumerated object. This call is
// useful for search-and-replace operations.
//
// Parameters: None
//****************************************************************************
HRESULT
CList::NextStorage (HANDLE *phEnum, LPVOID *ppv)
{
PNODE pNext;
HRESULT hr;
pNext = (PNODE)*phEnum;
if (pNext == NULL)
{
*ppv = NULL;
hr = S_FALSE;
}
else
{
*ppv = &(pNext->pv);
*phEnum = (HANDLE)(pNext->pNext);
hr = NOERROR;
};
return hr;
}
//****************************************************************************
// HRESULT
// CList::Flush (void)
//
// Purpose: Flush all the nodes in the list
//
// Parameters: None
//****************************************************************************
HRESULT
CList::Flush (void)
{
PNODE pNode;
while (pHead != NULL)
{
pNode = pHead;
pHead = pHead->pNext;
delete pNode;
};
return NOERROR;
}
//****************************************************************************
// HRESULT
// CList::Clone (CList *pList, HANDLE *phEnum)
//
// Purpose: Flush all the nodes in the list
//
// Parameters: None
//****************************************************************************
HRESULT
CList::Clone (CList *pList, HANDLE *phEnum)
{
PNODE pNode;
HRESULT hr;
// Only allow a null list to be cloned
//
if (pHead != NULL)
{
return ILS_E_FAIL;
};
// Traverse the source list
//
hr = S_OK; // lonchanc: in case of null list
pNode = pList->pHead;
while(pNode != NULL)
{
// Use append to maintain the order
//
hr = Append(pNode->pv);
if (FAILED(hr))
{
break;
};
// Get the enumerator info
//
if ((phEnum != NULL) &&
(*phEnum == (HANDLE)pNode))
{
*phEnum = (HANDLE)pTail;
};
pNode = pNode->pNext;
};
return hr;
}
//****************************************************************************
// CEnumNames::CEnumNames (void)
//
// History:
// Wed 17-Apr-1996 11:15:18 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
CEnumNames::CEnumNames (void)
{
cRef = 0;
pNext = NULL;
pszNames = NULL;
cbSize = 0;
return;
}
//****************************************************************************
// CEnumNames::~CEnumNames (void)
//
// History:
// Wed 17-Apr-1996 11:15:18 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
CEnumNames::~CEnumNames (void)
{
if (pszNames != NULL)
{
::MemFree (pszNames);
};
return;
}
//****************************************************************************
// STDMETHODIMP
// CEnumNames::Init (LPTSTR pList, ULONG cNames)
//
// History:
// Wed 17-Apr-1996 11:15:25 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
STDMETHODIMP
CEnumNames::Init (LPTSTR pList, ULONG cNames)
{
HRESULT hr = NOERROR;
// If no list, do nothing
//
if (cNames != 0)
{
LPTSTR pNextSrc;
ULONG i, cLen, cbSize;
ASSERT(pList != NULL);
// Calculate the list size
//
pNextSrc = pList;
for (i = 0, cbSize = 0; i < cNames; i++)
{
cLen = lstrlen(pNextSrc)+1;
pNextSrc += cLen;
cbSize += cLen;
};
// Allocate the snapshot buffer with the specified length
// plus one for doubly null-termination
//
pszNames = (TCHAR *) ::MemAlloc ((cbSize+1) * sizeof (TCHAR));
if (pszNames != NULL)
{
// Snapshot the name list
//
CopyMemory(pszNames, pList, cbSize*sizeof(TCHAR));
pszNames[cbSize] = '\0';
pNext = pszNames;
this->cbSize = cbSize+1;
}
else
{
hr = ILS_E_MEMORY;
};
};
return hr;
}
//****************************************************************************
// STDMETHODIMP
// CEnumNames::QueryInterface (REFIID riid, void **ppv)
//
// History:
// Wed 17-Apr-1996 11:15:31 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
STDMETHODIMP
CEnumNames::QueryInterface (REFIID riid, void **ppv)
{
if (riid == IID_IEnumIlsNames || riid == IID_IUnknown)
{
*ppv = (IEnumIlsNames *) this;
AddRef();
return S_OK;
}
else
{
*ppv = NULL;
return ILS_E_NO_INTERFACE;
};
}
//****************************************************************************
// STDMETHODIMP_(ULONG)
// CEnumNames::AddRef (void)
//
// History:
// Wed 17-Apr-1996 11:15:37 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
STDMETHODIMP_(ULONG)
CEnumNames::AddRef (void)
{
DllLock();
MyDebugMsg ((DM_REFCOUNT, "CEnumNames::AddRef: ref=%ld\r\n", cRef));
::InterlockedIncrement ((LONG *) &cRef);
return cRef;
}
//****************************************************************************
// STDMETHODIMP_(ULONG)
// CEnumNames::Release (void)
//
// History:
// Wed 17-Apr-1996 11:15:43 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
STDMETHODIMP_(ULONG)
CEnumNames::Release (void)
{
DllRelease();
ASSERT (cRef > 0);
MyDebugMsg ((DM_REFCOUNT, "CEnumNames::Release: ref=%ld\r\n", cRef));
if (::InterlockedDecrement ((LONG *) &cRef) == 0)
{
delete this;
return 0;
}
return cRef;
}
//****************************************************************************
// STDMETHODIMP
// CEnumNames::Next (ULONG cNames, BSTR *rgpbstrName, ULONG *pcFetched)
//
// History:
// Wed 17-Apr-1996 11:15:49 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
STDMETHODIMP
CEnumNames::Next (ULONG cNames, BSTR *rgpbstrName, ULONG *pcFetched)
{
ULONG cCopied;
HRESULT hr;
// Validate the pointer
//
if (rgpbstrName == NULL)
return ILS_E_POINTER;
// Validate the parameters
//
if ((cNames == 0) ||
((cNames > 1) && (pcFetched == NULL)))
return ILS_E_PARAMETER;
// Check the enumeration index
//
cCopied = 0;
if (pNext != NULL)
{
// Can copy if we still have more names
//
while ((cCopied < cNames) &&
(*pNext != '\0'))
{
if (SUCCEEDED(LPTSTR_to_BSTR(&rgpbstrName[cCopied], pNext)))
{
cCopied++;
};
pNext += lstrlen(pNext)+1;
};
};
// Determine the returned information based on other parameters
//
if (pcFetched != NULL)
{
*pcFetched = cCopied;
};
return (cNames == cCopied ? S_OK : S_FALSE);
}
//****************************************************************************
// STDMETHODIMP
// CEnumNames::Skip (ULONG cNames)
//
// History:
// Wed 17-Apr-1996 11:15:56 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
STDMETHODIMP
CEnumNames::Skip (ULONG cNames)
{
ULONG cSkipped;
// Validate the parameters
//
if (cNames == 0)
return ILS_E_PARAMETER;
// Check the enumeration index limit
//
cSkipped = 0;
if (pNext != NULL)
{
// Can skip only if we still have more attributes
//
while ((cSkipped < cNames) &&
(*pNext != '\0'))
{
pNext += lstrlen(pNext)+1;
cSkipped++;
};
};
return (cNames == cSkipped ? S_OK : S_FALSE);
}
//****************************************************************************
// STDMETHODIMP
// CEnumNames::Reset (void)
//
// History:
// Wed 17-Apr-1996 11:16:02 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
STDMETHODIMP
CEnumNames::Reset (void)
{
pNext = pszNames;
return S_OK;
}
//****************************************************************************
// STDMETHODIMP
// CEnumNames::Clone(IEnumIlsNames **ppEnum)
//
// History:
// Wed 17-Apr-1996 11:16:11 -by- Viroon Touranachun [viroont]
// Created.
//****************************************************************************
STDMETHODIMP
CEnumNames::Clone(IEnumIlsNames **ppEnum)
{
CEnumNames *peun;
HRESULT hr;
// Validate parameters
//
if (ppEnum == NULL)
{
return ILS_E_POINTER;
};
*ppEnum = NULL;
// Create an enumerator
//
peun = new CEnumNames;
if (peun == NULL)
return ILS_E_MEMORY;
// Clone the information
//
hr = NOERROR;
peun->cbSize = cbSize;
if (cbSize != 0)
{
peun->pszNames = (TCHAR *) ::MemAlloc (cbSize * sizeof (TCHAR));
if (peun->pszNames != NULL)
{
CopyMemory(peun->pszNames, pszNames, cbSize*sizeof(TCHAR));
peun->pNext = peun->pszNames+(pNext-pszNames);
}
else
{
hr = ILS_E_MEMORY;
};
}
else
{
peun->pNext = NULL;
peun->pszNames = NULL;
};
if (SUCCEEDED(hr))
{
// Return the cloned enumerator
//
peun->AddRef();
*ppEnum = peun;
}
else
{
delete peun;
};
return hr;
}
/* F L E G A L E M A I L S Z */
/*-------------------------------------------------------------------------
%%Function: FLegalEmailSz
RobD created
A legal email name contains only ANSI characters.
"a-z, A-Z, numbers 0-9 and some common symbols"
It cannot include extended characters or < > ( ) /
loncahnc modified
IsLegalEmailName ( TCHAR *pszName ).
A legal email name contains RFC 822 compliant characters.
-------------------------------------------------------------------------*/
BOOL IsLegalEmailName ( TCHAR *pszName )
{
// Null string is not legal
//
if (pszName == NULL)
return FALSE;
TCHAR ch;
while ((ch = *pszName++) != TEXT ('\0'))
{
switch (ch)
{
default:
// Check if ch is in the range
//
if (ch > TEXT (' ') && ch <= TEXT ('~'))
break;
// Fall thru to error code
//
case TEXT ('('): case TEXT (')'):
case TEXT ('<'): case TEXT ('>'):
case TEXT ('['): case TEXT (']'):
case TEXT ('/'): case TEXT ('\\'):
case TEXT (','):
case TEXT (';'):
case TEXT (':'):
case TEXT ('\"'):
return FALSE;
}
} // while
return TRUE;
}