windows-nt/Source/XPSP1/NT/net/tapi/client/location.cpp

3161 lines
97 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/****************************************************************************
Copyright (c) 1998-1999 Microsoft Corporation
Module Name: location.cpp
Abstract: Location Object implementation
Author: noela - 09/11/98
Notes:
Rev History:
****************************************************************************/
#include <windows.h>
#include <objbase.h>
#include "tapi.h"
#include "tspi.h"
#include "client.h"
#include "location.h"
#include "clntprivate.h"
#include "countrygroup.h"
#include <strsafe.h>
#define MaxDialStringSize 500
LONG PASCAL ReadCountries( LPLINECOUNTRYLIST *ppLCL,
UINT nCountryID,
DWORD dwDestCountryID
);
HRESULT ReadLocations( PLOCATIONLIST *ppLocationList,
HLINEAPP hLineApp,
DWORD dwDeviceID,
DWORD dwAPIVersion,
DWORD dwOptions
);
LONG PASCAL WriteLocations( PLOCATIONLIST pLocationList,
DWORD dwChangedFlags
);
LONG BreakupCanonicalW( PWSTR pAddressIn,
PWSTR *pCountry,
PWSTR *pCity,
PWSTR *pSubscriber
);
DWORD TapiPackString(LPBYTE pStructure,
DWORD dwOffset,
DWORD dwTotalSize,
PWSTR pszString,
PDWORD pdwOffset,
PDWORD pdwSize
);
LONG AppendDigits( PWSTR pDest,
PWSTR pSrc,
PWSTR pValidChars
);
HRESULT CreateCountryObject(DWORD dwCountryID, CCountry **ppCountry);
int IsCityRule(LPWSTR lpRule);
LONG ApplyRule (PWSTR pszDialString,
PWSTR pszDisplayString,
PWSTR pszRule,
PWSTR pszDestLDRule, // used for Area code adjustments
PWSTR pszLongDistanceCarrier,
PWSTR pszInternationalCarrier,
PWSTR pszCountry,
PWSTR pszCity,
PWSTR pszSubscriber,
PWSTR pCardName,
PWSTR pCardAccessNumber,
PWSTR pCardAccountNumber,
PWSTR pCardPINNumber
);
BOOL PrefixMatch(PWSTR pszPrefix,PWSTR pszSubscriberString, PDWORD pdwMatched);
BOOL AreaCodeMatch(PWSTR pszAreaCode1, PWSTR pszAreaCode2, PWSTR pszRule);
PWSTR SkipLDAccessDigits(PWSTR pszAreaCode, PWSTR pszLDRule);
#define LOCAL 1
#define LONG_DISTANCE 2
#define INTERNATIONAL 3
const WCHAR csSCANTO[] = L"\r";
const WCHAR csDISPSUPRESS[] = L"TtPp,Ww@?!$";
const WCHAR csBADCO[] = L"AaBbCcDdPpTtWw*#!,@$?;()";
const WCHAR csSCANSUB[] = L"^|/";
/*
***************************************************************************
********************* ****************************
******************** CLocation Class ***************************
******************** Definitions ***************************
********************* ****************************
***************************************************************************
*/
/****************************************************************************
Class : CLocation
Method : Constructer
****************************************************************************/
CLocation::CLocation()
{
m_pszLocationName = NULL;
m_pszLongDistanceAccessCode = NULL;
m_pszLocalAccessCode = NULL;
m_pszDisableCallWaitingCode = NULL;
m_pszAreaCode = NULL;
m_bFromRegistry = FALSE;
m_bChanged = FALSE;
m_dwNumRules = 0;
m_hEnumNode = m_AreaCodeRuleList.head();
m_pszTAPIDialingRule = NULL;
}
/****************************************************************************
Class : CLocation
Method : Destructer
Clean up memory allocations
****************************************************************************/
CLocation::~CLocation()
{
if ( m_pszLocationName != NULL )
{
ClientFree(m_pszLocationName);
}
if ( m_pszLongDistanceAccessCode != NULL )
{
ClientFree(m_pszLongDistanceAccessCode);
}
if ( m_pszLocalAccessCode != NULL )
{
ClientFree(m_pszLocalAccessCode);
}
if ( m_pszDisableCallWaitingCode != NULL )
{
ClientFree(m_pszDisableCallWaitingCode);
}
if ( m_pszAreaCode != NULL )
{
ClientFree(m_pszAreaCode);
}
if ( m_pszTAPIDialingRule != NULL )
{
ClientFree(m_pszTAPIDialingRule);
}
if (m_pszLongDistanceCarrierCode != NULL)
{
ClientFree (m_pszLongDistanceCarrierCode);
}
if (m_pszInternationalCarrierCode != NULL)
{
ClientFree (m_pszInternationalCarrierCode);
}
// clean up Area Code List
AreaCodeRulePtrNode *node;
node = m_AreaCodeRuleList.head();
while( !node->beyond_tail() )
{
delete node->value();
node = node->next();
}
m_AreaCodeRuleList.flush();
}
/****************************************************************************
Class : CLocation
Method : Initialize
****************************************************************************/
STDMETHODIMP CLocation::Initialize
(
PWSTR pszLocationName,
PWSTR pszAreaCode,
PWSTR pszLongDistanceCarrierCode,
PWSTR pszInternationalCarrierCode,
PWSTR pszLongDistanceAccessCode,
PWSTR pszLocalAccessCode,
PWSTR pszDisableCallWaitingCode,
DWORD dwLocationID,
DWORD dwCountryID,
DWORD dwPreferredCardID,
DWORD dwOptions ,
BOOL bFromRegistry
)
{
m_pszLocationName = ClientAllocString( pszLocationName );
if (m_pszLocationName == NULL)
{
LOG(( TL_ERROR, "Initialize - alloc m_pszLocationName failed" ));
return E_OUTOFMEMORY;
}
m_pszLongDistanceAccessCode = ClientAllocString( pszLongDistanceAccessCode );
if (m_pszLongDistanceAccessCode == NULL)
{
ClientFree(m_pszLocationName);
LOG(( TL_ERROR, "Initialize - alloc m_pszLongDistanceAccessCode failed" ));
return E_OUTOFMEMORY;
}
m_pszLocalAccessCode = ClientAllocString( pszLocalAccessCode );
if (m_pszLocalAccessCode == NULL)
{
ClientFree(m_pszLocationName);
ClientFree(m_pszLongDistanceAccessCode);
LOG(( TL_ERROR, "Initialize - alloc m_pszLocalAccessCode failed" ));
return E_OUTOFMEMORY;
}
m_pszDisableCallWaitingCode = ClientAllocString( pszDisableCallWaitingCode );
if (m_pszDisableCallWaitingCode == NULL)
{
ClientFree(m_pszLocationName);
ClientFree(m_pszLongDistanceAccessCode);
ClientFree(m_pszLocalAccessCode);
LOG(( TL_ERROR, "Initialize - alloc m_pszDisableCallWaitingCode failed" ));
return E_OUTOFMEMORY;
}
m_pszAreaCode = ClientAllocString( pszAreaCode );
if (m_pszAreaCode == NULL)
{
ClientFree(m_pszLocationName);
ClientFree(m_pszLongDistanceAccessCode);
ClientFree(m_pszLocalAccessCode);
ClientFree(m_pszDisableCallWaitingCode);
LOG(( TL_ERROR, "Initialize - alloc m_pszAreaCode failed" ));
return E_OUTOFMEMORY;
}
m_pszLongDistanceCarrierCode = ClientAllocString( pszLongDistanceCarrierCode );
if (m_pszLongDistanceCarrierCode == NULL)
{
ClientFree(m_pszLocationName);
ClientFree(m_pszLongDistanceAccessCode);
ClientFree(m_pszLocalAccessCode);
ClientFree(m_pszDisableCallWaitingCode);
ClientFree(m_pszAreaCode);
LOG(( TL_ERROR, "Initialize - alloc m_pszLongDistanceCarrierCode failed" ));
return E_OUTOFMEMORY;
}
m_pszInternationalCarrierCode = ClientAllocString( pszInternationalCarrierCode );
if (m_pszInternationalCarrierCode == NULL)
{
ClientFree(m_pszLocationName);
ClientFree(m_pszLongDistanceAccessCode);
ClientFree(m_pszLocalAccessCode);
ClientFree(m_pszDisableCallWaitingCode);
ClientFree(m_pszAreaCode);
ClientFree(m_pszLongDistanceCarrierCode);
LOG(( TL_ERROR, "Initialize - alloc m_pszInternationalCarrierCode failed" ));
return E_OUTOFMEMORY;
}
m_dwLocationID = dwLocationID;
m_dwCountryID = dwCountryID ? dwCountryID : 1; // workaround for a bogus country ID
m_dwPreferredCardID = dwPreferredCardID;
m_dwOptions = dwOptions;
m_bFromRegistry = bFromRegistry;
if (m_bFromRegistry == FALSE)
{
m_bChanged = TRUE;
}
return S_OK;
}
/****************************************************************************
Class : CLocation
Method : UseCallWaiting
****************************************************************************/
void CLocation::UseCallWaiting(BOOL bCw)
{
if(bCw)
{
m_dwOptions |= LOCATION_HASCALLWAITING;
}
else
{
m_dwOptions &= ~LOCATION_HASCALLWAITING;
}
m_bChanged = TRUE;
}
/****************************************************************************
Class : CLocation
Method : UseCallingCard
****************************************************************************/
void CLocation::UseCallingCard(BOOL bCc)
{
if(bCc)
{
m_dwOptions |= LOCATION_USECALLINGCARD;
}
else
{
m_dwOptions &= ~LOCATION_USECALLINGCARD;
}
m_bChanged = TRUE;
}
/****************************************************************************
Class : CLocation
Method : UseToneDialing
****************************************************************************/
void CLocation::UseToneDialing(BOOL bCc)
{
if(bCc)
{
m_dwOptions |= LOCATION_USETONEDIALING;
}
else
{
m_dwOptions &= ~LOCATION_USETONEDIALING;
}
m_bChanged = TRUE;
}
/****************************************************************************
Class : CLocation
Method : setName
****************************************************************************/
STDMETHODIMP CLocation::SetName(PWSTR pszLocationName)
{
HRESULT hr = S_OK;
if (m_pszLocationName != NULL)
{
ClientFree(m_pszLocationName);
m_pszLocationName = NULL;
}
if(pszLocationName != NULL)
{
m_pszLocationName = ClientAllocString( pszLocationName );
if (m_pszLocationName == NULL)
{
LOG(( TL_ERROR, "setName - alloc failed" ));
hr = E_OUTOFMEMORY;
}
}
m_bChanged = TRUE;
return hr;
}
/****************************************************************************
Class : CLocation
Method : setAreaCode
****************************************************************************/
STDMETHODIMP CLocation::SetAreaCode(PWSTR pszAreaCode)
{
HRESULT hr = S_OK;
if (m_pszAreaCode != NULL)
{
ClientFree(m_pszAreaCode);
m_pszAreaCode = NULL;
}
if(pszAreaCode != NULL)
{
m_pszAreaCode = ClientAllocString( pszAreaCode );
if (m_pszAreaCode == NULL)
{
LOG(( TL_ERROR, "setAreaCode - alloc failed" ));
hr = E_OUTOFMEMORY;
}
}
m_bChanged = TRUE;
return hr;
}
/****************************************************************************
Class : CLocation
Method : SetLongDistanceCarrierCode
****************************************************************************/
STDMETHODIMP CLocation::SetLongDistanceCarrierCode(PWSTR pszLongDistanceCarrierCode)
{
HRESULT hr = S_OK;
if (m_pszLongDistanceCarrierCode != NULL)
{
ClientFree(m_pszLongDistanceCarrierCode);
m_pszLongDistanceCarrierCode = NULL;
}
if(pszLongDistanceCarrierCode != NULL)
{
m_pszLongDistanceCarrierCode = ClientAllocString( pszLongDistanceCarrierCode );
if (m_pszLongDistanceCarrierCode == NULL)
{
LOG(( TL_ERROR, "setLongDistanceCarrierCode - alloc failed" ));
hr = E_OUTOFMEMORY;
}
}
m_bChanged = TRUE;
return hr;
}
/****************************************************************************
Class : CLocation
Method : SetInternationalCarrierCode
****************************************************************************/
STDMETHODIMP CLocation::SetInternationalCarrierCode(PWSTR pszInternationalCarrierCode)
{
HRESULT hr = S_OK;
if (m_pszInternationalCarrierCode != NULL)
{
ClientFree(m_pszInternationalCarrierCode);
m_pszInternationalCarrierCode = NULL;
}
if(pszInternationalCarrierCode != NULL)
{
m_pszInternationalCarrierCode = ClientAllocString( pszInternationalCarrierCode );
if (m_pszInternationalCarrierCode == NULL)
{
LOG(( TL_ERROR, "setInternationalCarrierCode - alloc failed" ));
hr = E_OUTOFMEMORY;
}
}
m_bChanged = TRUE;
return hr;
}
/****************************************************************************
Class : CLocation
Method : setLongDistanceAccessCode
****************************************************************************/
STDMETHODIMP CLocation::SetLongDistanceAccessCode(PWSTR pszLongDistanceAccessCode)
{
HRESULT hr = S_OK;
if (m_pszLongDistanceAccessCode != NULL)
{
ClientFree(m_pszLongDistanceAccessCode);
m_pszLongDistanceAccessCode = NULL;
}
if(pszLongDistanceAccessCode != NULL)
{
m_pszLongDistanceAccessCode = ClientAllocString( pszLongDistanceAccessCode );
if (m_pszLongDistanceAccessCode == NULL)
{
LOG(( TL_ERROR, "setLongDistanceAccessCode - alloc failed" ));
hr = E_OUTOFMEMORY;
}
}
m_bChanged = TRUE;
return hr;
}
/****************************************************************************
Class : CLocation
Method : setLocalAccessCode
****************************************************************************/
STDMETHODIMP CLocation::SetLocalAccessCode(PWSTR pszLocalAccessCode)
{
HRESULT hr = S_OK;
if (m_pszLocalAccessCode != NULL)
{
ClientFree(m_pszLocalAccessCode);
m_pszLocalAccessCode = NULL;
}
if(pszLocalAccessCode != NULL)
{
m_pszLocalAccessCode = ClientAllocString( pszLocalAccessCode );
if (m_pszLocalAccessCode == NULL)
{
LOG(( TL_ERROR, "setLocalAccessCode - alloc failed" ));
hr = E_OUTOFMEMORY;
}
}
m_bChanged = TRUE;
return hr;
}
/****************************************************************************
Class : CLocation
Method : SetDisableCallWaitingCode
****************************************************************************/
STDMETHODIMP CLocation::SetDisableCallWaitingCode(PWSTR pszDisableCallWaitingCode)
{
HRESULT hr = S_OK;
if (m_pszDisableCallWaitingCode != NULL)
{
ClientFree(m_pszDisableCallWaitingCode);
m_pszDisableCallWaitingCode = NULL;
}
if(pszDisableCallWaitingCode != NULL)
{
m_pszDisableCallWaitingCode = ClientAllocString( pszDisableCallWaitingCode );
if (m_pszDisableCallWaitingCode == NULL)
{
LOG(( TL_ERROR, "SetDisableCallWaitingCodee - alloc failed" ));
hr = E_OUTOFMEMORY;
}
}
m_bChanged = TRUE;
return hr;
}
/****************************************************************************
Class : CLocation
Method : WriteToRegistry
****************************************************************************/
STDMETHODIMP CLocation::WriteToRegistry()
{
HRESULT hr = S_OK;
DWORD dwTotalSizeNeeded = 0 ;
DWORD dwSize=0, dwOffset = 0;
PLOCATIONLIST pLocationList = NULL;
PLOCATION pEntry = NULL;
// static size
dwTotalSizeNeeded = sizeof(LOCATIONLIST);
dwSize = TapiSize();
dwTotalSizeNeeded += dwSize;
// Allocate the memory buffer;
pLocationList = (PLOCATIONLIST) ClientAlloc( dwTotalSizeNeeded );
if (pLocationList != NULL)
{
// buffer size
pLocationList->dwTotalSize = dwTotalSizeNeeded;
pLocationList->dwNeededSize = dwTotalSizeNeeded;
pLocationList->dwUsedSize = dwTotalSizeNeeded;
pLocationList->dwCurrentLocationID = 0;
pLocationList->dwNumLocationsAvailable = 1;
//list size & offset
dwOffset = sizeof(LOCATIONLIST);
pLocationList->dwNumLocationsInList = 1;
pLocationList->dwLocationListSize = dwSize;
pLocationList->dwLocationListOffset = dwOffset;
// point to the location entry in list
pEntry = (PLOCATION)(((LPBYTE)pLocationList) + dwOffset);
// fill out structure
TapiPack(pEntry, dwSize);
WriteLocations( pLocationList, 0);
// finished with TAPI memory block so release
if ( pLocationList != NULL )
{
ClientFree( pLocationList );
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
/****************************************************************************
Class : CLocation
Method : RemoveRule
****************************************************************************/
void CLocation::RemoveRule(CAreaCodeRule *pRule)
{
AreaCodeRulePtrNode * node = m_AreaCodeRuleList.head();
while( !node->beyond_tail() )
{
if ( pRule == node->value() )
{
node->remove();
delete pRule;
m_dwNumRules--;
break;
}
node = node->next();
}
m_bChanged = TRUE;
}
/****************************************************************************
Class : CLocation
Method : ResetRules
****************************************************************************/
HRESULT CLocation::ResetRules(void)
{
m_hEnumNode = m_AreaCodeRuleList.head();
return S_OK;
}
/****************************************************************************
Class : CLocation
Method : NextRule
****************************************************************************/
HRESULT CLocation::NextRule(DWORD NrElem, CAreaCodeRule **ppRule, DWORD *pNrElemFetched)
{
DWORD dwIndex = 0;
if(pNrElemFetched == NULL && NrElem != 1)
return E_INVALIDARG;
if(ppRule==NULL)
return E_INVALIDARG;
while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
{
*ppRule++ = m_hEnumNode->value();
m_hEnumNode = m_hEnumNode->next();
dwIndex++;
}
if(pNrElemFetched!=NULL)
*pNrElemFetched = dwIndex;
return dwIndex<NrElem ? S_FALSE : S_OK;
}
/****************************************************************************
Class : CLocation
Method : SkipRule
****************************************************************************/
HRESULT CLocation::SkipRule(DWORD NrElem)
{
DWORD dwIndex = 0;
while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
{
m_hEnumNode = m_hEnumNode->next();
dwIndex++;
}
return dwIndex<NrElem ? S_FALSE : S_OK;
}
/****************************************************************************
Class : CLocation
Method : TapiSize
Number of bytes needed to pack this into a TAPI structure to send
to TAPISRV.
If the object has not changed while in memory, we won't save it so
return a zero size.
****************************************************************************/
DWORD CLocation::TapiSize()
{
AreaCodeRulePtrNode * node = m_AreaCodeRuleList.head();
CAreaCodeRule * pRule = NULL;
DWORD dwSize=0;
if(m_bChanged)
{
// Calc size of Location info
dwSize = sizeof(LOCATION);
dwSize += ALIGN((lstrlenW(m_pszLocationName) + 1) * sizeof(WCHAR));
dwSize += ALIGN((lstrlenW(m_pszAreaCode) + 1) * sizeof(WCHAR));
dwSize += ALIGN((lstrlenW(m_pszLongDistanceCarrierCode) + 1) * sizeof(WCHAR));
dwSize += ALIGN((lstrlenW(m_pszInternationalCarrierCode) + 1) * sizeof(WCHAR));
dwSize += ALIGN((lstrlenW(m_pszLongDistanceAccessCode) + 1) * sizeof(WCHAR));
dwSize += ALIGN((lstrlenW(m_pszLocalAccessCode) + 1) * sizeof(WCHAR));
dwSize += ALIGN((lstrlenW(m_pszDisableCallWaitingCode) + 1) * sizeof(WCHAR));
while( !node->beyond_tail() )
{
// Add in size of each Area Code Rule
pRule = node->value();
if (pRule != NULL)
{
dwSize += pRule->TapiSize();
}
node = node->next();
}
}
else // no change so don't save this
{
dwSize = 0;
}
return dwSize;
}
/****************************************************************************
Class : CLocation
Method : TapiPack
Pack this object into a TAPI structure.
Return number of bytes used.
If the object has not changed while in memory, we won't save it so
do mothing except return a zero size.
****************************************************************************/
DWORD CLocation::TapiPack(PLOCATION pLocation, DWORD dwTotalSize)
{
AreaCodeRulePtrNode * node;
CAreaCodeRule * pRule = NULL;
DWORD dwSize =0, dwOffSet =0;
PAREACODERULE pEntry = NULL;
if(m_bChanged)
{
m_bFromRegistry = TRUE;
/////////////////////////////////////////////////////////////////////
// Process fized part of Location info
dwOffSet = sizeof(LOCATION);
pLocation->dwPermanentLocationID= m_dwLocationID;
pLocation->dwCountryCode = m_dwCountryCode;
pLocation->dwCountryID = m_dwCountryID;
pLocation->dwPreferredCardID = m_dwPreferredCardID;
pLocation->dwOptions = m_dwOptions;
/////////////////////////////////////////////////////////////////////
// Process strings
// name
dwOffSet += TapiPackString((LPBYTE)pLocation,
dwOffSet,
dwTotalSize,
m_pszLocationName,
&pLocation->dwLocationNameOffset,
&pLocation->dwLocationNameSize
);
//area code
dwOffSet += TapiPackString((LPBYTE)pLocation,
dwOffSet,
dwTotalSize,
m_pszAreaCode,
&pLocation->dwAreaCodeOffset,
&pLocation->dwAreaCodeSize
);
//LD carrier code
dwOffSet += TapiPackString((LPBYTE)pLocation,
dwOffSet,
dwTotalSize,
m_pszLongDistanceCarrierCode,
&pLocation->dwLongDistanceCarrierCodeOffset,
&pLocation->dwLongDistanceCarrierCodeSize
);
//International carrier code
dwOffSet += TapiPackString((LPBYTE)pLocation,
dwOffSet,
dwTotalSize,
m_pszInternationalCarrierCode,
&pLocation->dwInternationalCarrierCodeOffset,
&pLocation->dwInternationalCarrierCodeSize
);
//LD access
dwOffSet += TapiPackString((LPBYTE)pLocation,
dwOffSet,
dwTotalSize,
m_pszLongDistanceAccessCode,
&pLocation->dwLongDistanceAccessCodeOffset,
&pLocation->dwLongDistanceAccessCodeSize
);
// Local access
dwOffSet += TapiPackString((LPBYTE)pLocation,
dwOffSet,
dwTotalSize,
m_pszLocalAccessCode,
&pLocation->dwLocalAccessCodeOffset,
&pLocation->dwLocalAccessCodeSize
);
// CallWaiting
dwOffSet += TapiPackString((LPBYTE)pLocation,
dwOffSet,
dwTotalSize,
m_pszDisableCallWaitingCode,
&pLocation->dwCancelCallWaitingOffset,
&pLocation->dwCancelCallWaitingSize
);
/////////////////////////////////////////////////////////////////////
// Process Area Code Rules
pLocation->dwNumAreaCodeRules = m_dwNumRules;
pLocation->dwAreaCodeRulesListOffset = dwOffSet;
//pLocation->dwAreaCodeRulesListSize;
// point to the 1st rule
pEntry = (PAREACODERULE)(((LPBYTE)pLocation) + dwOffSet);
//point strings past rule area
dwOffSet += ALIGN(( sizeof(AREACODERULE) * m_dwNumRules ));
// run through list
node = m_AreaCodeRuleList.head();
while( !node->beyond_tail() )
{
// Add in size of each Area Code Rule
pRule = node->value();
if (pRule != NULL)
{
pEntry->dwOptions = pRule->GetOptions();
// Area code
dwOffSet += TapiPackString((LPBYTE)pLocation,
dwOffSet,
dwTotalSize,
pRule->GetAreaCode(),
&pEntry->dwAreaCodeOffset,
&pEntry->dwAreaCodeSize
);
// num to Call
dwOffSet += TapiPackString((LPBYTE)pLocation,
dwOffSet,
dwTotalSize,
pRule->GetNumberToDial(),
&pEntry->dwNumberToDialOffset,
&pEntry->dwNumberToDialSize
);
// prefix list
dwSize = pRule->GetPrefixListSize();
pEntry->dwPrefixesListSize = dwSize;
pEntry->dwPrefixesListOffset = dwOffSet;
CopyMemory((PVOID)(((LPBYTE)pLocation) + dwOffSet),
pRule->GetPrefixList() ,
dwSize);
dwOffSet += ALIGN(dwSize);
}
node = node->next();
pEntry++;
}
// offset gives how many bytes we used
pLocation->dwUsedSize = dwOffSet;
}
else // no change so don't save this
{
dwOffSet = 0;
}
return dwOffSet;
}
/****************************************************************************
Class : CLocation
Method : NewID
gets new ID from server
****************************************************************************/
HRESULT CLocation::NewID()
{
LONG lResult;
DWORD dwId = 0;
FUNC_ARGS funcArgs =
{
MAKELONG (LINE_FUNC | SYNC | 1, tAllocNewID),
{
(DWORD_PTR)&dwId
},
{
lpDword
}
};
//
// Yes, let TAPISRV do it without danger of AV interruption from
// another thread
//
lResult = DOFUNC (&funcArgs, "TAllocNewID");
if(lResult == 0)
{
m_dwLocationID = dwId;
}
return (HRESULT)lResult;
}
/****************************************************************************
Class : CLocation
Method : GetCountryCode
gets GetCountryCode from server
****************************************************************************/
DWORD CLocation::GetCountryCode()
{
CCountry * pCountry = NULL;
if(SUCCEEDED( CreateCountryObject(m_dwCountryID, &pCountry)) )
{
m_dwCountryCode = pCountry->GetCountryCode();
delete pCountry;
}
return m_dwCountryCode;
}
/****************************************************************************
Class : CLocation
Method : TranslateAddress
This is what its all there for, take a input number & figure out
the dialable & display strings
****************************************************************************/
LONG CLocation::TranslateAddress(PCWSTR pszAddressIn,
CCallingCard *pCallingCard,
DWORD dwTranslateOptions,
PDWORD pdwTranslateResults,
PDWORD pdwDestCountryCode,
PWSTR * pszDialableString,
PWSTR * pszDisplayableString
)
{
PWSTR pszDialString = NULL;
PWSTR pszDisplayString = NULL;
PWSTR pszInputString = NULL;
PWSTR pszRule = NULL;
PWSTR pszDestLDRule = NULL;
PWSTR pszCountry = NULL;
PWSTR pszCity = NULL;
PWSTR pszSubscriber = NULL;
PWSTR pCardName = NULL;
PWSTR pCardAccessNumber = NULL;
PWSTR pCardAccountNumber = NULL;
PWSTR pCardPINNumber = NULL;
LONG lResult = 0;
HRESULT hr= S_OK;
CCountry * pCountry = NULL;
CCountry * pDestCountry = NULL;
DWORD dwAccess;
DWORD dwDestCountryCode;
BOOL bSpaceExists, bOutOfMem = FALSE;
*pdwTranslateResults = 0;
if(pdwDestCountryCode)
*pdwDestCountryCode = 0;
//////////////////////////////////////////////////////////////
// Allocate space for our strings
//
pszDialString = (PWSTR)ClientAlloc( MaxDialStringSize * sizeof(WCHAR) );
if (pszDialString == NULL)
{
LOG((TL_TRACE, "TranslateAddress DialString alloc failed"));
return LINEERR_NOMEM;
}
pszDisplayString = (PWSTR)ClientAlloc( MaxDialStringSize * sizeof(WCHAR) );
if (pszDisplayString == NULL)
{
LOG((TL_TRACE, "TranslateAddress DisplayString alloc failed"));
ClientFree(pszDialString);
return LINEERR_NOMEM;
}
*pszDialableString = pszDialString;
*pszDisplayableString = pszDisplayString;
bSpaceExists = TRUE; // for suppressing a first space
//////////////////////////////////////////////////////////////
// Copy the string to our local buffer so we can mangle it
//
pszInputString = ClientAllocString(pszAddressIn);
if (pszInputString == NULL)
{
LOG((TL_TRACE, "TranslateAddress InputString alloc failed"));
ClientFree(pszDialString);
ClientFree(pszDisplayString);
return LINEERR_NOMEM;
}
//////////////////////////////////////////////////////////////
// Mark off the end
//
// Isolate the piece of pszInputString that we will operate upon in
// This piece stops at first CR or \0.
//
pszInputString[wcscspn(pszInputString,csSCANTO)] = L'\0';
////////////////////////////////
// Set T or P, if not set in input
//////////////////////////////////////////////////////////////
// Easy case: first put the T or P in the beginning of the
// dialable string
//
if ( HasToneDialing() )
{
*pszDialString = L'T';
}
else
{
*pszDialString = L'P';
}
pszDialString++;
//////////////////////////////////////////////////////////////
// Set Call Waiting
//if location supports call Waiting AND (TranslateOptions | LINETRANSLATIONOPTION_CANCELCALLWAIT)
if((dwTranslateOptions & LINETRANSLATEOPTION_CANCELCALLWAITING) && HasCallWaiting() )
{
hr = StringCchCatExW(pszDialString, MaxDialStringSize, m_pszDisableCallWaitingCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, m_pszDisableCallWaitingCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = FALSE;
}
//////////////////////////////////////////////////////////////
// Now, do we have a canonical number to deal with, or is it junk?
//
if ( *pszInputString == L'+' ) // Check the real _first_ char
{
//
// Ok, it's canonical
//
//
// Skip the plus
//
lResult = BreakupCanonicalW( pszInputString + 1,
&pszCountry,
&pszCity,
&pszSubscriber
);
if (lResult == 0)
{
// It's canonical
*pdwTranslateResults |= LINETRANSLATERESULT_CANONICAL;
hr = CreateCountryObject(m_dwCountryID, &pCountry);
if(SUCCEEDED( hr) )
{
//////////////////////////////////////////////////////////////
// set LINETRANSLATERESULT result codes
dwDestCountryCode = (DWORD)_wtol((const wchar_t*) pszCountry);
if (dwDestCountryCode == pCountry->GetCountryCode() )
{
// In country Call
pszDestLDRule = pCountry->GetLongDistanceRule();
//if ( (
// CurrentCountry.LongDistanceRule.AreaCodes == Optional
// OR CurrentCountry.LongDistanceRule.AreaCodes == Manditory && cityCode != NULL
// )
// AND AreaCodeString != CurrentLocation.AreaCodeString )
if ( ( (IsCityRule(pszDestLDRule) == CITY_OPTIONAL) ||
( (IsCityRule(pszDestLDRule) == CITY_MANDATORY) && (pszCity != NULL) ) ) &&
(!AreaCodeMatch(pszCity, m_pszAreaCode, pszDestLDRule))
)
{
// Long Distance Call
*pdwTranslateResults |= LINETRANSLATERESULT_LONGDISTANCE;
}
else // Local Call
{
*pdwTranslateResults |= LINETRANSLATERESULT_LOCAL;
}
}
else // International Call
{
// find the LD rule of the destination country using the country code (we don't have the country ID)
hr = CreateCountryObject(dwDestCountryCode, &pDestCountry);
if(SUCCEEDED(hr))
{
if ( pCountry->GetCountryGroup() != 0 &&
pCountry->GetCountryGroup() == pDestCountry->GetCountryGroup()
)
{
// if countries are in the same group, we need to
// apply long distance rule instead of international
*pdwTranslateResults |= LINETRANSLATERESULT_LONGDISTANCE;
}
else
{
*pdwTranslateResults |= LINETRANSLATERESULT_INTERNATIONAL;
}
pszDestLDRule = pDestCountry->GetLongDistanceRule();
}
else
{
*pdwTranslateResults |= LINETRANSLATERESULT_INTERNATIONAL;
// FALL THROUGH if error
}
}
}
if(SUCCEEDED( hr) )
{
// If the caller needs the destination country code
if(pdwDestCountryCode)
*pdwDestCountryCode = dwDestCountryCode;
//////////////////////////////////////////////////////////////
// Now we no what type of call, find the correct rule
// Take in to account LINETRANSLATIONOPTION over-rides
FindRule(
*pdwTranslateResults,
dwTranslateOptions,
pCallingCard,
pCountry,
pszCity,
pszSubscriber,
&pszRule,
&dwAccess
);
//////////////////////////////////////////////////////////////
// Add access String to output string
if (dwAccess == LOCAL)
{
hr = StringCchCatExW(pszDialString, MaxDialStringSize, m_pszLocalAccessCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
if(*m_pszLocalAccessCode)
{
if(!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, m_pszLocalAccessCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = FALSE;
}
}
else // LONG_DISTANCE or INTERNATIONAL
{
hr = StringCchCatExW(pszDialString, MaxDialStringSize, m_pszLongDistanceAccessCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
if(*m_pszLongDistanceAccessCode)
{
if(!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, m_pszLongDistanceAccessCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = FALSE;
}
}
//////////////////////////////////////////////////////////////
// If there's a card get its values
if(pCallingCard != NULL)
{
switch(dwAccess)
{
case INTERNATIONAL:
pCardAccessNumber = pCallingCard->GetInternationalAccessNumber();
break;
case LONG_DISTANCE:
LOG((TL_TRACE, "TranslateAddress: About to do pCallingCard->GetLongDistanceAccessNumber"));
pCardAccessNumber = pCallingCard->GetLongDistanceAccessNumber();
LOG((TL_TRACE, "TranslateAddress: Did pCallingCard->GetLongDistanceAccessNumber"));
break;
default:
pCardAccessNumber = pCallingCard->GetLocalAccessNumber();
break;
}
pCardName = pCallingCard->GetCardName();
pCardAccountNumber = pCallingCard->GetAccountNumber();
pCardPINNumber = pCallingCard->GetPIN();
}
if(!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
//////////////////////////////////////////////////////////////
// Got the rule , now apply it
if (ApplyRule (pszDialString,
pszDisplayString,
pszRule,
pszDestLDRule,
m_pszLongDistanceCarrierCode,
m_pszInternationalCarrierCode,
pszCountry,
pszCity,
pszSubscriber,
pCardName,
pCardAccessNumber,
pCardAccountNumber,
pCardPINNumber
))
{
bOutOfMem = TRUE;
}
else
{
//
// Set LINETRANSLATERESULT_consts based on translation
// results
//
if (wcschr (pszDialString, L'$'))
{
*pdwTranslateResults |= LINETRANSLATERESULT_DIALBILLING;
}
if (wcschr (pszDialString, L'W'))
{
*pdwTranslateResults |= LINETRANSLATERESULT_DIALDIALTONE;
}
if (wcschr (pszDialString, L'?'))
{
*pdwTranslateResults |= LINETRANSLATERESULT_DIALPROMPT;
}
if (wcschr (pszDialString, L'@'))
{
*pdwTranslateResults |= LINETRANSLATERESULT_DIALQUIET;
}
if (wcschr (pszDialString, L':'))
{
*pdwTranslateResults |= LINETRANSLATERESULT_VOICEDETECT;
}
}
}
else // bad country code
{
lResult = LINEERR_INVALCOUNTRYCODE;
ClientFree(*pszDialableString);
ClientFree(*pszDisplayableString);
*pszDialableString = *pszDisplayableString = NULL;
}
if(pCountry)
delete pCountry;
if(pDestCountry)
delete pDestCountry;
}
else // bad canonical address
{
lResult = LINEERR_INVALADDRESS;
ClientFree(*pszDialableString);
ClientFree(*pszDisplayableString);
*pszDialableString = *pszDisplayableString = NULL;
}
}
else // non-canonical string
{
PWSTR pszInputStringLocal = pszInputString;
// if the string starts with T,P,t or p, skip the
// first character.
if (*pszInputString == L'T' ||
*pszInputString == L'P' ||
*pszInputString == L't' ||
*pszInputString == L'p')
{
pszInputStringLocal++;
}
hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszInputStringLocal, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszInputString, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
/////////////////////////////////////////////////////////////////////
// Clean up
//
if (bOutOfMem)
{
lResult = LINEERR_NOMEM;
ClientFree(pszDialString);
ClientFree(pszDisplayString);
}
if(pszInputString != NULL)
{
ClientFree(pszInputString);
}
return lResult;
}
/****************************************************************************
Class : CLocation
Method : FindRule
Decide which TAPI dial string rule to apply
in
dwTranslateResults
dwTranslateOptions
pCard
pCountry
AreaCodeString
SubscriberString
out
ppRule
dwAccess
****************************************************************************/
void CLocation::FindRule(
DWORD dwTranslateResults,
DWORD dwTranslateOptions,
CCallingCard * pCard,
CCountry * pCountry,
PWSTR pszAreaCodeString,
PWSTR pszSubscriberString,
PWSTR * ppszRule,
PDWORD dwAccess
)
{
CRuleSet * pCardRuleSet;
CRuleSet * pCountryRuleSet;
//if using Card
if(pCard != NULL)
{
// Apply card rules
pCardRuleSet = pCard->GetRuleSet();
LOG((TL_INFO, "FindRule - using (eventually) card %ls", pCard->GetCardName() ));
}
else
{
pCardRuleSet = NULL;
}
pCountryRuleSet = pCountry->GetRuleSet();
// use card rule if card is specified. If a specific rule is empty, fallback to country rule
#define SUITABLE_RULE(x) \
( (pCard && pCardRuleSet->x && *(pCardRuleSet->x) ) ? \
pCardRuleSet->x : pCountryRuleSet->x )
// Forced Long Distance Call
if (dwTranslateOptions & LINETRANSLATEOPTION_FORCELD)
{
*dwAccess = LONG_DISTANCE;
*ppszRule = SUITABLE_RULE(m_pszLongDistanceRule);
LOG((TL_INFO, "FindRule - force long distance"));
}
// Force Local Call
else if (dwTranslateOptions & LINETRANSLATEOPTION_FORCELOCAL)
{
*dwAccess = LOCAL;
*ppszRule = SUITABLE_RULE(m_pszLocalRule);
LOG((TL_INFO, "FindRule - force local"));
}
// International Call
else if (dwTranslateResults & LINETRANSLATERESULT_INTERNATIONAL)
{
*dwAccess = INTERNATIONAL;
*ppszRule = SUITABLE_RULE(m_pszInternationalRule);
LOG((TL_INFO, "FindRule - international"));
}
// In Country, Long Distance Call or Local
else
{
CAreaCodeRule * pCrtRule = NULL;
AreaCodeRulePtrNode * pNode = NULL;
PWSTR pszPrefix = NULL;
DWORD dwNumMatchedDigits = 0;
DWORD dwBestMatchedDigits = 0;
DWORD dwBestThisRule = 0;
BOOL bFoundApplicableRule = FALSE;
BOOL bMatchThisRule = FALSE;
BOOL bThisPrefixMatchThisRule = FALSE;
// Enumerate the area code rules
pNode = m_AreaCodeRuleList.head();
while( !pNode->beyond_tail() )
{
pCrtRule = pNode->value();
if(pCrtRule!=NULL)
{
// does this rule match the area code we're calling ?
if(AreaCodeMatch(pszAreaCodeString, pCrtRule->GetAreaCode(), pCountry->GetLongDistanceRule()))
{
LOG((TL_INFO, "FindRule - ACRule applies"));
bMatchThisRule = FALSE;
dwBestThisRule = 0;
if( pCrtRule->HasAppliesToAllPrefixes() )
{
bMatchThisRule = TRUE;
dwNumMatchedDigits = 0;
LOG((TL_INFO, "FindRule - there's a all prefix rule"));
}
else // is there a specific prefix rule ?
{
pszPrefix = pCrtRule->GetPrefixList();
while(*pszPrefix != '\0')
{
bThisPrefixMatchThisRule= PrefixMatch(pszPrefix,
pszSubscriberString,
&dwNumMatchedDigits);
if(bThisPrefixMatchThisRule)
{
LOG((TL_INFO, "FindRule: there's a specific prefix rule %d digit match"
,dwNumMatchedDigits));
bMatchThisRule = TRUE;
if(dwNumMatchedDigits > dwBestThisRule )
{
dwBestThisRule= dwNumMatchedDigits;
}
}
pszPrefix = wcschr( pszPrefix, '\0');
pszPrefix++;
}
}
// have we got a better match than we've had before ?
if(bMatchThisRule && (dwBestThisRule >= dwBestMatchedDigits) )
{
// We have the best prefix match so far so use this rule
dwBestMatchedDigits = dwBestThisRule;
bFoundApplicableRule = TRUE;
LOG((TL_INFO, "FindRule: going with the %d digit match" ,dwBestMatchedDigits));
*ppszRule = NULL;
// Card overides, so if using Card
if(pCard != NULL)
{
LOG((TL_INFO, "FindRule: card override (eventually)"));
if ( pCrtRule->HasDialNumber() )
{
*ppszRule = pCardRuleSet->m_pszLongDistanceRule;
}
else
{
*ppszRule = pCardRuleSet->m_pszLocalRule;
}
}
if(!(*ppszRule && **ppszRule))
// build a tapirulestring for this rule entry
// this might be necessary if the calling card has no suitable rule
{
if(m_pszTAPIDialingRule != NULL)
{
ClientFree(m_pszTAPIDialingRule);
}
if (S_OK ==
CreateDialingRule(&m_pszTAPIDialingRule,
pCrtRule->HasDialNumber()?pCrtRule->GetNumberToDial():NULL,
pCrtRule->HasDialAreaCode()
))
{
*ppszRule = m_pszTAPIDialingRule;
LOG((TL_INFO, "FindRule: built a rule string - %ls",m_pszTAPIDialingRule));
}
}
// Set the correct access, based on the selected rule
if ( pCrtRule->HasDialNumber() )
{
*dwAccess = LONG_DISTANCE;
}
else
{
*dwAccess = LOCAL;
}
} // no better match
} // no not calling this area code
}
pNode = pNode->next();
}
// Did we have a match at all ?
if(bFoundApplicableRule == FALSE)
{
// No area code rule matched, so go with country default rule
if (dwTranslateResults & LINETRANSLATERESULT_LONGDISTANCE)
{
// long Distance
*dwAccess = LONG_DISTANCE;
*ppszRule = SUITABLE_RULE(m_pszLongDistanceRule);
LOG((TL_TRACE, "FindRule - long distance default"));
}
else // Local
{
*dwAccess = LOCAL;
*ppszRule = SUITABLE_RULE(m_pszLocalRule);
LOG((TL_TRACE, "FindRule - local default"));
}
}
}
}
#undef SUITABLE_RULE
/*
***************************************************************************
********************* ****************************
******************** CLocations Class ***************************
******************** Definitions ***************************
********************* ****************************
***************************************************************************
*/
/****************************************************************************
Class : CLocations
Method : Constructer
****************************************************************************/
CLocations::CLocations()
{
m_dwNumEntries = 0;
m_hEnumNode = m_LocationList.head();
}
/****************************************************************************
Class : CLocations
Method : Destructer
****************************************************************************/
CLocations::~CLocations()
{
CLocationNode *node;
node = m_LocationList.head();
while( !node->beyond_tail() )
{
delete node->value();
node = node->next();
}
m_LocationList.flush();
node = m_DeletedLocationList.head();
while( !node->beyond_tail() )
{
delete node->value();
node = node->next();
}
m_DeletedLocationList.flush();
}
/****************************************************************************
Class : CLocations
Method : Initialize
Read the location list from registry via TAPISRV & build our
object list.
****************************************************************************/
HRESULT CLocations::Initialize(void)
{
PLOCATIONLIST pLocationList = NULL;
PLOCATION pEntry = NULL;
PWSTR pszLocationName = NULL;
PWSTR pszAreaCode = NULL;
PWSTR pszLongDistanceCarrierCode = NULL;
PWSTR pszInternationalCarrierCode = NULL;
PWSTR pszLocalAccessCode = NULL;
PWSTR pszLongDistanceAccessCode = NULL;
PWSTR pszCancelCallWaitingCode = NULL;
DWORD dwPermanentLocationID = 0;
CLocation * pNewLocation = NULL;
PAREACODERULE pAreaCodeRuleEntry = NULL;
PWSTR pszNumberToDial = NULL;
PWSTR pszzPrefixesList = NULL;
DWORD dwNumRules = 0;
CAreaCodeRule * pAreaCodeRule = NULL;
DWORD dwNumEntries = 0;
DWORD dwCount,dwCount2 = 0;
HRESULT hr;
hr = ReadLocations(&pLocationList,
0,
0,
0,
0
);
if SUCCEEDED( hr)
{
// current location
m_dwCurrentLocationID = pLocationList->dwCurrentLocationID;
// Find position of 1st LOCATION structure in the LOCATIONLIST structure
pEntry = (PLOCATION) ((BYTE*)(pLocationList) + pLocationList->dwLocationListOffset );
// Number of locations ?
dwNumEntries = pLocationList->dwNumLocationsInList;
for (dwCount = 0; dwCount < dwNumEntries ; dwCount++)
{
// Pull Location Info out of LOCATION structure
pszLocationName = (PWSTR) ((BYTE*)(pEntry)
+ pEntry->dwLocationNameOffset);
pszAreaCode = (PWSTR) ((BYTE*)(pEntry)
+ pEntry->dwAreaCodeOffset);
pszLongDistanceCarrierCode = (PWSTR) ((BYTE*)(pEntry)
+ pEntry->dwLongDistanceCarrierCodeOffset);
pszInternationalCarrierCode = (PWSTR) ((BYTE*)(pEntry)
+ pEntry->dwInternationalCarrierCodeOffset);
pszLocalAccessCode = (PWSTR) ((BYTE*)(pEntry)
+ pEntry->dwLocalAccessCodeOffset);
pszLongDistanceAccessCode = (PWSTR) ((BYTE*)(pEntry)
+ pEntry->dwLongDistanceAccessCodeOffset);
pszCancelCallWaitingCode = (PWSTR) ((BYTE*)(pEntry)
+ pEntry->dwCancelCallWaitingOffset);
// create our new Location Object
pNewLocation = new CLocation;
if (pNewLocation)
{
// initialize the new Location Object
hr = pNewLocation->Initialize(
pszLocationName,
pszAreaCode,
pszLongDistanceCarrierCode,
pszInternationalCarrierCode,
pszLongDistanceAccessCode,
pszLocalAccessCode,
pszCancelCallWaitingCode ,
pEntry->dwPermanentLocationID,
pEntry->dwCountryID,
pEntry->dwPreferredCardID,
pEntry->dwOptions,
TRUE
);
if( SUCCEEDED(hr) )
{
// Find position of 1st AREACODERULE structure in the LOCATIONLIST structure
pAreaCodeRuleEntry = (PAREACODERULE) ((BYTE*)(pEntry)
+ pEntry->dwAreaCodeRulesListOffset );
dwNumRules = pEntry->dwNumAreaCodeRules;
for (dwCount2 = 0; dwCount2 != dwNumRules; dwCount2++)
{
// Pull Rule Info out of AREACODERULE structure
pszAreaCode = (PWSTR) ((BYTE*)(pEntry)
+ pAreaCodeRuleEntry->dwAreaCodeOffset);
pszNumberToDial = (PWSTR) ((BYTE*)(pEntry)
+ pAreaCodeRuleEntry->dwNumberToDialOffset);
pszzPrefixesList = (PWSTR) ((BYTE*)(pEntry)
+ pAreaCodeRuleEntry->dwPrefixesListOffset);
// create our new AreaCodeRule Object
pAreaCodeRule = new CAreaCodeRule;
if (pAreaCodeRule)
{
// initialize the new AreaCodeRule Object
hr = pAreaCodeRule->Initialize ( pszAreaCode,
pszNumberToDial,
pAreaCodeRuleEntry->dwOptions,
pszzPrefixesList,
pAreaCodeRuleEntry->dwPrefixesListSize
);
if( SUCCEEDED(hr) )
{
pNewLocation->AddRule(pAreaCodeRule);
}
else // rule initialization failed
{
delete pAreaCodeRule;
LOG((TL_ERROR, "Initialize: CreateCurrentLoctionObject - rule create failed"));
}
}
else // new CAreaCodeRule failed
{
LOG((TL_ERROR, "CreateCurrentLoctionObject - rule create failed"));
}
// Try next rule in list
pAreaCodeRuleEntry++;
}
Add(pNewLocation);
}
else // location initialize failed
{
delete pNewLocation;
pNewLocation = NULL;
LOG((TL_ERROR, "CreateCurrentLoctionObject - location create failed"));
}
}
else // new CLocation failed
{
LOG((TL_ERROR, "CreateCurrentLoctionObject - location create failed"));
}
// Try next location in list
//pEntry++;
pEntry = (PLOCATION) ((BYTE*)(pEntry) + pEntry->dwUsedSize);
}
}
else // ReadLocations failed
{
LOG((TL_ERROR, "CreateCurrentLoctionObject - ReadLocation create failed"));
}
// finished with TAPI memory block so release
if ( pLocationList != NULL )
ClientFree( pLocationList );
return hr;
}
/****************************************************************************
Class : CLocations
Method : SaveToRegistry
Save object list back to registry via TAPISRV again
****************************************************************************/
HRESULT CLocations::SaveToRegistry(void)
{
HRESULT hr = S_OK;
DWORD dwTotalSizeNeeded = 0, dwNumEntries= 0 ;
DWORD dwSize=0, dwOffset = 0;
CLocationNode * node = NULL;
CLocation * pLocation = NULL;
PLOCATIONLIST pLocationList = NULL;
PLOCATION pEntry = NULL;
// static size
dwTotalSizeNeeded = sizeof(LOCATIONLIST);
dwNumEntries = 0;
// Now add in size of each Location (includes rules)
node = m_LocationList.head();
while( !node->beyond_tail() )
{
pLocation = node->value();
if (pLocation != NULL)
{
dwSize= pLocation->TapiSize();
dwTotalSizeNeeded += dwSize;
if(dwSize)
{
// only save if dwSize >0, i.e. object has changed
dwNumEntries++;
}
}
node = node->next();
}
// Now add in size of each deleted Location
node = m_DeletedLocationList.head();
while( !node->beyond_tail() )
{
pLocation = node->value();
if (pLocation != NULL)
{
dwSize= pLocation->TapiSize();
dwTotalSizeNeeded += dwSize;
if(dwSize)
{
// only save if dwSize > 0, i.e. object has changed
dwNumEntries++;
}
}
node = node->next();
}
// Allocate the memory buffer;
pLocationList = (PLOCATIONLIST) ClientAlloc( dwTotalSizeNeeded );
if (pLocationList != NULL)
{
// buffer size
pLocationList->dwTotalSize = dwTotalSizeNeeded;
pLocationList->dwNeededSize = dwTotalSizeNeeded;
pLocationList->dwUsedSize = dwTotalSizeNeeded;
pLocationList->dwCurrentLocationID = m_dwCurrentLocationID;
pLocationList->dwNumLocationsAvailable = dwNumEntries;
//list size & offset
dwOffset = sizeof(LOCATIONLIST);
pLocationList->dwNumLocationsInList = dwNumEntries;
pLocationList->dwLocationListSize = dwTotalSizeNeeded - sizeof(LOCATIONLIST);
pLocationList->dwLocationListOffset = dwOffset;
// Now add in each Location (includes rules)
node = m_LocationList.head();
while( !node->beyond_tail() )
{
// point to the location entry in list
pEntry = (PLOCATION)(((LPBYTE)pLocationList) + dwOffset);
pLocation = node->value();
if (pLocation != NULL)
{
// fill out structure
dwOffset += pLocation->TapiPack(pEntry, dwTotalSizeNeeded - dwOffset);
}
node = node->next();
}
// Now add in each deleted Location
node = m_DeletedLocationList.head();
while( !node->beyond_tail() )
{
// point to the location entry in list
pEntry = (PLOCATION)(((LPBYTE)pLocationList) + dwOffset);
pLocation = node->value();
if (pLocation != NULL)
{
// fill out structure
dwOffset += pLocation->TapiPack(pEntry, dwTotalSizeNeeded - dwOffset);
}
node = node->next();
}
WriteLocations( pLocationList,CHANGEDFLAGS_CURLOCATIONCHANGED);
// finished with TAPI memory block so release
if ( pLocationList != NULL )
{
ClientFree( pLocationList );
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
/****************************************************************************
Class : CLocations
Method : Remove (with CLocation *)
If location object was read from the registry we must keep it
around so we can remove its entry when writing back to the registry.
If it only existed in memory we can just delete it.
****************************************************************************/
void CLocations::Remove(CLocation * pLocation)
{
CLocationNode *node = m_LocationList.head();
while( !node->beyond_tail() )
{
if ( pLocation == node->value() )
{
node->remove();
m_dwNumEntries--;
pLocation->Changed();
if( pLocation->FromRegistry() )
{
// set name to null so server knows to delete it
pLocation->SetName(NULL);
m_DeletedLocationList.tail()->insert_after(pLocation);
}
else
{
delete pLocation;
}
break;
}
node = node->next();
}
}
/****************************************************************************
Class : CLocations
Method : Remove (with DWORD)
If location object was read from the registry we must keep it
around so we can remove its entry when writing back to the registry.
If it only existed in memory we can just delete it.
****************************************************************************/
void CLocations::Remove(DWORD dwID)
{
CLocationNode *node = m_LocationList.head();
CLocation *pLocation;
while( !node->beyond_tail() )
{
if ( dwID == node->value()->GetLocationID() )
{
pLocation = node->value();
node->remove();
m_dwNumEntries--;
pLocation->Changed();
if( pLocation->FromRegistry() )
{
// set name to null so server knows to delete it
pLocation->SetName(NULL);
m_DeletedLocationList.tail()->insert_after(pLocation);
}
else
{
delete pLocation;
}
break;
}
node = node->next();
}
}
/****************************************************************************
Class : CLocations
Method : Replace
Replace pLocOld with pLocNew. These locations must have the same
location ID.
****************************************************************************/
void CLocations::Replace(CLocation * pLocOld, CLocation * pLocNew)
{
if ( pLocOld->GetLocationID() != pLocNew->GetLocationID() )
{
LOG((TL_ERROR, "Replace: Illegal"));
return;
}
CLocationNode *node = m_LocationList.head();
while( !node->beyond_tail() )
{
if ( pLocOld == node->value() )
{
// node->remove();
// m_LocationList.tail()->insert_after(pLocNew);
node->value() = pLocNew;
delete pLocOld;
break;
}
node = node->next();
}
}
/****************************************************************************
Class : CLocations
Method : Add
Put it in the list
****************************************************************************/
void CLocations::Add(CLocation * pLocation)
{
m_LocationList.tail()->insert_after(pLocation);
m_dwNumEntries++;
}
/****************************************************************************
Class : CLocations
Method : Reset
Set enumerator to start
****************************************************************************/
HRESULT CLocations::Reset(void)
{
m_hEnumNode = m_LocationList.head();
return S_OK;
}
/****************************************************************************
Class : CLocations
Method : Next
get next location in list
****************************************************************************/
HRESULT CLocations::Next(DWORD NrElem, CLocation **ppLocation, DWORD *pNrElemFetched)
{
DWORD dwIndex = 0;
if(pNrElemFetched == NULL && NrElem != 1)
return E_INVALIDARG;
if(ppLocation==NULL)
return E_INVALIDARG;
while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
{
*ppLocation++ = m_hEnumNode->value();
m_hEnumNode = m_hEnumNode->next();
dwIndex++;
}
if(pNrElemFetched!=NULL)
*pNrElemFetched = dwIndex;
return dwIndex<NrElem ? S_FALSE : S_OK;
}
/****************************************************************************
Class : CLocations
Method : Skip
Miss a few
****************************************************************************/
HRESULT CLocations::Skip(DWORD NrElem)
{
DWORD dwIndex = 0;
while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
{
m_hEnumNode = m_hEnumNode->next();
dwIndex++;
}
return dwIndex<NrElem ? S_FALSE : S_OK;
}
/*
***************************************************************************
********************* ****************************
******************** CCountry Class ***************************
******************** Definitions ***************************
********************* ****************************
***************************************************************************
*/
/****************************************************************************
Class : CCountry
Method : Constructer
****************************************************************************/
CCountry::CCountry()
{
m_dwCountryID = 0;
m_dwCountryCode = 0;
m_dwCountryGroup = 0;
m_pszCountryName = NULL;
}
/****************************************************************************
Class : CCountry
Method : Destructer
Clean up memory allocations
****************************************************************************/
CCountry::~CCountry()
{
if ( m_pszCountryName != NULL )
{
ClientFree(m_pszCountryName);
}
}
/****************************************************************************
Class : CCountry
Method : Initialize
****************************************************************************/
STDMETHODIMP CCountry::Initialize
(
DWORD dwCountryID,
DWORD dwCountryCode,
DWORD dwCountryGroup,
PWSTR pszCountryName,
PWSTR pszInternationalRule,
PWSTR pszLongDistanceRule,
PWSTR pszLocalRule
)
{
HRESULT hr = S_OK;
m_dwCountryID = dwCountryID;
m_dwCountryCode = dwCountryCode;
m_dwCountryGroup = dwCountryGroup;
m_pszCountryName = ClientAllocString( pszCountryName );
if (m_pszCountryName == NULL)
{
LOG(( TL_ERROR, "Initialize - alloc pszLocationName failed" ));
hr = E_OUTOFMEMORY;
}
else
{
hr = m_Rules.Initialize(pszInternationalRule,
pszLongDistanceRule,
pszLocalRule
);
if(FAILED(hr) )
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
/*
***************************************************************************
********************* ****************************
******************** CCountries Class ***************************
******************** Definitions ***************************
********************* ****************************
***************************************************************************
*/
/****************************************************************************
Class : CCountries
Method : Constructer
****************************************************************************/
CCountries::CCountries()
{
m_dwNumEntries = 0;
m_hEnumNode = m_CountryList.head();
}
/****************************************************************************
Class : CCountries
Method : Destructer
****************************************************************************/
CCountries::~CCountries()
{
CCountryNode *node;
node = m_CountryList.head();
while( !node->beyond_tail() )
{
delete node->value();
node = node->next();
}
m_CountryList.flush();
}
/****************************************************************************
Class : CCountries
Method : Initialize
Read the countries list from registry via TAPISRV & build our
object list.
****************************************************************************/
HRESULT CCountries::Initialize(void)
{
LPLINECOUNTRYLIST_INTERNAL pCountryList = NULL;
LPLINECOUNTRYENTRY_INTERNAL pEntry = NULL;
PWSTR pszCountryName = NULL;
PWSTR pszInternationalRule = NULL;
PWSTR pszLongDistanceRule = NULL;
PWSTR pszLocalRule = NULL;
CCountry * pCountry = NULL;
DWORD dwCount = 0;
DWORD dwNumEntries = 0;
LONG lResult;
HRESULT hr;
lResult = ReadCountriesAndGroups( &pCountryList, 0, 0);
if (lResult == 0)
{
// Find position of 1st LINECOUNTRYENTRY structure in the LINECOUNTRYLIST structure
pEntry = (LPLINECOUNTRYENTRY_INTERNAL) ((BYTE*)(pCountryList) + pCountryList->dwCountryListOffset );
dwNumEntries = pCountryList->dwNumCountries;
for (dwCount = 0; dwCount < dwNumEntries ; dwCount++)
{
// Pull Country Info out of LINECOUNTRYENTRY structure
pszCountryName = (PWSTR) ((BYTE*)(pCountryList)
+ pEntry->dwCountryNameOffset);
pszInternationalRule = (PWSTR) ((BYTE*)(pCountryList)
+ pEntry->dwInternationalRuleOffset);
pszLongDistanceRule = (PWSTR) ((BYTE*)(pCountryList)
+ pEntry->dwLongDistanceRuleOffset);
pszLocalRule = (PWSTR) ((BYTE*)(pCountryList)
+ pEntry->dwSameAreaRuleOffset);
// create our new CCountry Object
pCountry = new CCountry;
if (pCountry)
{
// initialize the new CCountry Object
hr = pCountry->Initialize(pEntry->dwCountryID,
pEntry->dwCountryCode,
pEntry->dwCountryGroup,
pszCountryName,
pszInternationalRule,
pszLongDistanceRule,
pszLocalRule
);
if( SUCCEEDED(hr) )
{
m_CountryList.tail()->insert_after(pCountry);
m_dwNumEntries++;
}
else // country initialization failed
{
delete pCountry;
LOG((TL_ERROR, "Initialize - country create failed"));
}
}
else // new CCountry failed
{
LOG((TL_ERROR, "Initialize - country create failed"));
}
// Try next country in list
pEntry++;
}
}
else // ReadLocations failed
{
LOG((TL_ERROR, "Initialize - ReadCountries failed"));
hr = (HRESULT)lResult;
}
// finished with TAPI memory block so release
if ( pCountryList != NULL )
{
ClientFree( pCountryList );
}
return hr;
}
/****************************************************************************
Class : CCountries
Method : Reset
****************************************************************************/
HRESULT CCountries::Reset(void)
{
m_hEnumNode = m_CountryList.head();
return S_OK;
}
/****************************************************************************
Class : CCountries
Method : Next
****************************************************************************/
HRESULT CCountries::Next(DWORD NrElem, CCountry **ppCcountry, DWORD *pNrElemFetched)
{
DWORD dwIndex = 0;
if(pNrElemFetched == NULL && NrElem != 1)
return E_INVALIDARG;
if(ppCcountry==NULL)
return E_INVALIDARG;
while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
{
*ppCcountry++ = m_hEnumNode->value();
m_hEnumNode = m_hEnumNode->next();
dwIndex++;
}
if(pNrElemFetched!=NULL)
*pNrElemFetched = dwIndex;
return dwIndex<NrElem ? S_FALSE : S_OK;
}
/****************************************************************************
Class : CCountries
Method : Skip
****************************************************************************/
HRESULT CCountries::Skip(DWORD NrElem)
{
DWORD dwIndex = 0;
while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
{
m_hEnumNode = m_hEnumNode->next();
dwIndex++;
}
return dwIndex<NrElem ? S_FALSE : S_OK;
}
/*
***************************************************************************
********************* ****************************
******************** Helper ***************************
******************** Functions ***************************
********************* ****************************
***************************************************************************
*/
/****************************************************************************
Function : ApplyRule
Parse though a tapi rule string & build dialable & displayable
strings from the required components.
out pszDialString
pszDisplayString
in pszRule
pszLongDistanceCarrier
pszInternationalCarrier
pszCountry
pszCity
pszSubscriber
pszCardName
pszCardAccessNumber
pszCardAccountNumber
pszCardPINNumber
****************************************************************************/
LONG ApplyRule (PWSTR pszDialString,
PWSTR pszDisplayString,
PWSTR pszRule,
PWSTR pszDestLDRule,
PWSTR pszLongDistanceCarrier,
PWSTR pszInternationalCarrier,
PWSTR pszCountry,
PWSTR pszCity,
PWSTR pszSubscriber,
PWSTR pszCardName,
PWSTR pszCardAccessNumber,
PWSTR pszCardAccountNumber,
PWSTR pszCardPINNumber
)
{
WCHAR * pRuleChar;
DWORD dwEndString;
PWSTR pszAdjustedCity;
PWSTR pszSubaddress;
WCHAR wcSubaddrSep;
BOOL bSpaceExists, bOutOfMem = FALSE;
bSpaceExists = TRUE;
HRESULT hr;
for (pRuleChar = pszRule; *pRuleChar != '\0' && !bOutOfMem; pRuleChar++)
{
switch(*pRuleChar)
{
//Dial the Long Distance Carrier Code
case 'L':
case 'l':
case 'N':
case 'n':
{
if (pszLongDistanceCarrier)
{
hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszLongDistanceCarrier, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
if (!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszLongDistanceCarrier, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = TRUE;
}
break;
}
//Dial the International Carrier Code
case 'M':
case 'm':
case 'S':
case 's':
{
if (pszInternationalCarrier)
{
hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszInternationalCarrier, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
if (!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszInternationalCarrier, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = TRUE;
}
break;
}
// Dial the Country Code
case 'E':
case 'e':
{
hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszCountry, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
if(!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszCountry, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = TRUE;
break;
}
// Dial the City/Area Code
case 'F':
case 'f':
case 'I':
case 'i':
{
// adjust the area code (see bug 279092)
pszAdjustedCity = SkipLDAccessDigits(pszCity, pszDestLDRule);
if(pszAdjustedCity && *pszAdjustedCity!=L'\0')
{
hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszAdjustedCity, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
if(!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszAdjustedCity, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = TRUE;
}
break;
}
// Dial the Subscriber Number
case 'G':
case 'g':
{
// we let through digits & "AaBbCcDdPpTtWw*#!,@$?;()"
// but after a '|' or '^' we let all through
pszSubaddress = pszSubscriber + wcscspn(pszSubscriber, (PWSTR)csSCANSUB);
wcSubaddrSep = *pszSubaddress;
*pszSubaddress = L'\0';
if(AppendDigits( pszDialString, pszSubscriber, (PWSTR)csBADCO))
{
bOutOfMem = TRUE;
}
else
{
if(wcSubaddrSep != L'\0')
{
*pszSubaddress = wcSubaddrSep;
hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszSubaddress, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
if(!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszSubscriber, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = FALSE;
}
break;
}
// Dial the Calling Card Access Number
case 'J':
case 'j':
{
// just let through digits
if (AppendDigits( pszDialString, pszCardAccessNumber, L""))
{
bOutOfMem = TRUE;
}
else
{
if(!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszCardAccessNumber, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = TRUE;
}
break;
}
// Dial the Calling Card Account Number
case 'K':
case 'k':
{
// just let through digits
if (AppendDigits( pszDialString, pszCardAccountNumber, L""))
{
bOutOfMem = TRUE;
}
else
{
if(!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L"[", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszCardName, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L"] ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = TRUE;
}
break;
}
// Dial the Calling Card PIN Number
case 'H':
case 'h':
{
hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszCardPINNumber, NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
if(!bSpaceExists)
{
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
}
hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L"**** ", NULL, NULL, STRSAFE_NO_TRUNCATION);
bOutOfMem = bOutOfMem && FAILED(hr);
bSpaceExists = TRUE;
break;
}
// Just append the character to the dial/display string
default:
{
dwEndString = lstrlenW(pszDialString);
if (dwEndString < MaxDialStringSize - 1)
{
pszDialString[dwEndString] = *pRuleChar;
pszDialString[dwEndString+1] = '\0';
}
else
{
bOutOfMem = TRUE;
}
// don't display certain chars
if (!wcschr(csDISPSUPRESS,*pRuleChar))
{
dwEndString = lstrlenW(pszDisplayString);
if (dwEndString < MaxDialStringSize - 1)
{
pszDisplayString[dwEndString] = *pRuleChar;
pszDisplayString[dwEndString+1] = '\0';
}
else
{
bOutOfMem = TRUE;
}
}
bSpaceExists = FALSE;
break;
}
}
}
if (bOutOfMem)
{
return LINEERR_NOMEM;
}
return 0;
}
/****************************************************************************
Function : TapiPackString
Takes a string & copys it to a tapi location + offset
updates the entry offset & size dwords
returns size of copied string (used to adjust offset for next string)
****************************************************************************/
DWORD TapiPackString(LPBYTE pStructure,
DWORD dwOffset,
DWORD dwTotalSize,
PWSTR pszString,
PDWORD pdwOffset,
PDWORD pdwSize
)
{
DWORD dwSize;
dwSize = ALIGN((lstrlenW(pszString) + 1) * sizeof(WCHAR));
if (NULL != pszString)
{
StringCchCopyEx((PWSTR)(pStructure + dwOffset), (dwTotalSize - dwOffset)/sizeof(WCHAR), pszString, NULL, NULL, STRSAFE_NO_TRUNCATION);
}
else
{
*(PWSTR)(pStructure + dwOffset) = L'\0';
}
*pdwOffset = dwOffset;
*pdwSize = dwSize;
return dwSize;
}
/****************************************************************************
Function : PrefixMatch
Checks if Subscriber number starts with the given prefix
Takes into account the only the digits.
returns FALSE if not matched, else TRUE & number of matched chars
****************************************************************************/
BOOL PrefixMatch(PWSTR pszPrefix,PWSTR pszSubscriberString, PDWORD pdwMatched)
{
DWORD dwCount =0;
PWSTR pPrefixChar = pszPrefix;
PWSTR pSSChar = pszSubscriberString;
// The prefix must be contiguous (without commas etc.)
while( (*pPrefixChar != '\0') && (*pSSChar != '\0') )
{
if(iswdigit(*pSSChar))
{
if(*pPrefixChar == *pSSChar)
{
dwCount++;
pPrefixChar++;
pSSChar++;
}
else // no match
{
dwCount= 0;
break;
}
}
else
{
// This was not a digit, skip it
pSSChar++;
}
}
// just in case subscriber string was shorter than the prefix
if(*pPrefixChar != '\0')
{
dwCount = 0;
}
// return values
*pdwMatched = dwCount;
if(dwCount !=0)
{
return TRUE;
}
else
{
return FALSE;
}
}
/****************************************************************************
Function : AppendDigits
Copies only digits up to end of string.
Simply exit if string is NULL
****************************************************************************/
LONG AppendDigits( PWSTR pDest,
PWSTR pSrc,
PWSTR pValidChars
)
{
WCHAR * pSrcChar;
WCHAR * pDestChar;
LONG lReturn = 0;
if (pSrc != NULL)
{
pDestChar = pDest + lstrlenW(pDest);
pSrcChar = pSrc;
while (*pSrcChar != '\0' && (pDestChar - pDest < MaxDialStringSize - 1))
{
if ( iswdigit(*pSrcChar) || (wcschr(pValidChars, *pSrcChar)) )
{
*pDestChar++ = *pSrcChar;
}
pSrcChar++;
}
if (*pSrcChar != '\0')
{
lReturn = LINEERR_NOMEM;
}
}
return lReturn;
}
/****************************************************************************
Function : AreaCodeMatch
Compares two areas codes. Returns TRUE if they are the same.
Adjusts internally the area codes using the LD rule given as a parameter.
See bug 279092
****************************************************************************/
BOOL AreaCodeMatch(PWSTR pszAreaCode1, PWSTR pszAreaCode2, PWSTR pszRule)
{
PWSTR pszAdjustedAreaCode1;
PWSTR pszAdjustedAreaCode2;
BOOL bRet = FALSE;
pszAdjustedAreaCode1 = SkipLDAccessDigits(pszAreaCode1, pszRule);
pszAdjustedAreaCode2 = SkipLDAccessDigits(pszAreaCode2, pszRule);
if (NULL != pszAdjustedAreaCode1 &&
NULL != pszAdjustedAreaCode2)
{
bRet = (0==lstrcmpW(pszAdjustedAreaCode1, pszAdjustedAreaCode2));
}
return bRet;
}
/****************************************************************************
Function : SkipLDAccessDigits
Skips the characters from an area code which corespond to a LD access prefix
Returns a pointer to the correct area code.
Presumes that the first digits of the rule are in fact the LD acces prefix.
See bug 279092
****************************************************************************/
PWSTR SkipLDAccessDigits(PWSTR pszAreaCode, PWSTR pszLDRule)
{
if(pszAreaCode!=NULL)
{
// A space in the rule prevents the matching/striping mechanism
// Uncomment if you don't want that.
// while(*pszLDRule == L' ')
// pszLDRule++;
//
// A long distance rule may have a L/l or N/n at the beginning, need to skip it
//
if (*pszLDRule == L'L' ||
*pszLDRule == L'l' ||
*pszLDRule == L'N' ||
*pszLDRule == L'n'
)
{
pszLDRule++;
}
while(*pszLDRule && iswdigit(*pszLDRule) && *pszAreaCode==*pszLDRule)
{
pszAreaCode++;
pszLDRule++;
}
}
return pszAreaCode;
}