|
|
/****************************************************************************
Copyright (c) 1995-1999 Microsoft Corporation Module Name: dial.cpp ****************************************************************************/
#include <windows.h>
#include <windowsx.h>
#if WINNT
#else
#include <help.h>
#endif
#include "tchar.h"
#include "prsht.h"
#include "stdlib.h"
#include "tapi.h"
#include "tspi.h"
#include "client.h"
#include "clntprivate.h"
#include "card.h"
#include "location.h"
#include "rules.h"
#include "countrygroup.h"
#include <shlwapi.h>
#include <shlwapip.h> // from private\inc
#undef lineGetTranslateCaps
#undef lineSetTollList
#undef lineTranslateAddress
#undef tapiGetLocationInfo
#undef lineGetCountry
#undef lineTranslateDialog
// moved here from loc_comn.h
#define MAXLEN_NAME 96
#ifdef __cplusplus
extern "C"{ #endif
BOOL gbTranslateSimple = FALSE; BOOL gbTranslateSilent = FALSE;
TCHAR gszTelephonyKey[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony"); TCHAR gszRegKeyNTServer[] = TEXT("System\\CurrentControlSet\\Control\\ProductOptions");
TCHAR gszLocation[] = TEXT("Location"); TCHAR gszLocations[] = TEXT("Locations"); const TCHAR gszNullString[] = TEXT("");
TCHAR gszNumEntries[] = TEXT("NumEntries"); TCHAR gszCurrentID[] = TEXT("CurrentID"); TCHAR gszNextID[] = TEXT("NextID");
TCHAR gszID[] = TEXT("ID"); TCHAR gszFlags[] = TEXT("Flags"); TCHAR gszCallingCard[] = TEXT("CallingCard"); TCHAR gszCards[] = TEXT("Cards"); TCHAR gszCard[] = TEXT("Card");
#ifdef __cplusplus
} #endif
LONG CreateCurrentLocationObject(CLocation **pLocation, HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, DWORD dwOptions);
HRESULT ReadLocations( PLOCATIONLIST *ppLocationList, HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, DWORD dwOptions ); LONG PASCAL ReadCountries( LPLINECOUNTRYLIST *ppLCL, UINT nCountryID, DWORD dwDestCountryID );
LONG BreakupCanonicalW( PWSTR pAddressIn, PWSTR *pCountry, PWSTR *pCity, PWSTR *pSubscriber );
static LONG GetTranslateCapsCommon( HLINEAPP hLineApp, DWORD dwAPIVersion, LPLINETRANSLATECAPS lpTranslateCaps, BOOL bUnicode );
static void LayDownTollList(CLocation *pLocation, PBYTE pBuffer, PBYTE *ppCurrentIndex, PDWORD pPair, BOOL bUnicode, PBYTE pFirstByteAfter ); static void LayDownString( PCWSTR pInString, PBYTE pBuffer, PBYTE *ppCurrentIndex, PDWORD pPair, BOOL bUnicode, PBYTE pFirstByteAfter );
static PWSTR CopyStringWithExpandJAndK(PWSTR pszRule, PWSTR pszAccessNr, PWSTR pszAccountNr); static BOOL IsATollListAreaCodeRule(CAreaCodeRule *pRule, PWSTR pszLocationAreaCode); static BOOL FindTollPrefixInLocation(CLocation *pLocation, PWSTR pPrefix, CAreaCodeRule **ppRule, PWSTR *ppWhere); static PWSTR FindPrefixInMultiSZ(PWSTR pPrefixList, PWSTR pPrefix);
LONG PASCAL WriteLocations( PLOCATIONLIST pLocationList, DWORD dwChangedFlags );
extern "C" char * PASCAL MapResultCodeToText( LONG lResult, char *pszResult );
LONG PASCAL IsThisAPIVersionInvalid( DWORD dwAPIVersion ) { switch (dwAPIVersion) { case TAPI_VERSION3_1: case TAPI_VERSION3_0: case TAPI_VERSION2_2: case TAPI_VERSION2_1: case TAPI_VERSION2_0: case TAPI_VERSION1_4: case TAPI_VERSION1_0:
return 0;
default:
break; }
return LINEERR_INCOMPATIBLEAPIVERSION; }
//***************************************************************************
//
// TAPI API Interfaces
//
//***************************************************************************
//***************************************************************************
LONG WINAPI lineTranslateDialogA( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, HWND hwndOwner, LPCSTR lpszAddressIn ) { PWSTR szAddressInW = NULL; LONG lResult;
LOG((TL_TRACE, "Entering lineTranslateDialogA")); LOG((TL_INFO, " hLineApp=x%lx", hLineApp)); LOG((TL_INFO, " dwAPIVersion=0x%08lx", dwAPIVersion)); LOG((TL_INFO, " hwndOwner=x%p", hwndOwner)); LOG((TL_INFO, " lpszAddressIn=x%p", lpszAddressIn));
if ( lpszAddressIn ) { if ( IsBadStringPtrA(lpszAddressIn, 512) ) { LOG((TL_ERROR, "Bad string pointer passed to lineTranslateDialog")); return LINEERR_INVALPOINTER; } else { szAddressInW = MultiToWide( lpszAddressIn ); } }
//
// Win9x ?
//
#ifndef _WIN64
if ((GetVersion() & 0x80000000) && (0xffff0000 == ((DWORD) hwndOwner & 0xffff0000))) { //
// Yeah. It don't play no ffff.
//
hwndOwner = (HWND) ( (DWORD)hwndOwner & 0x0000ffff ); }
#endif
lResult = lineTranslateDialogW( hLineApp, dwDeviceID, dwAPIVersion, hwndOwner, szAddressInW );
if ( szAddressInW ) { ClientFree( szAddressInW ); }
return lResult; }
//***************************************************************************
LONG WINAPI lineTranslateDialog( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, HWND hwndOwner, LPCSTR lpszAddressIn ) { return lineTranslateDialogA( hLineApp, dwDeviceID, dwAPIVersion, hwndOwner, lpszAddressIn ); }
extern "C" LONG WINAPI internalConfig( HWND hwndParent, PCWSTR pwsz, INT iTab, DWORD dwAPIVersion );
//***************************************************************************
LONG WINAPI lineTranslateDialogW( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, HWND hwndOwner, LPCWSTR lpszAddressIn ) { PLOCATIONLIST pLocTest = NULL; LONG lResult = 0;
LOG((TL_TRACE, "Entering lineTranslateDialogW")); LOG((TL_INFO, " hLineApp=x%lx", hLineApp)); LOG((TL_INFO, " dwAPIVersion=0x%08lx", dwAPIVersion)); LOG((TL_INFO, " hwndOwner=x%p", hwndOwner)); LOG((TL_INFO, " lpszAddressIn=x%p", lpszAddressIn));
// stuff that the old lineTranslateDialog did so I'm just copying it:
lResult = IsThisAPIVersionInvalid( dwAPIVersion ); if ( lResult ) { LOG((TL_ERROR, "Bad dwAPIVersion - 0x%08lx", dwAPIVersion)); return lResult; }
if ( lpszAddressIn && TAPIIsBadStringPtrW(lpszAddressIn, (UINT)-1) ) { LOG((TL_ERROR, "Bad lpszAddressIn pointer (0x%p)", lpszAddressIn)); return LINEERR_INVALPOINTER; }
if (hwndOwner && !IsWindow (hwndOwner)) { LOG((TL_ERROR, " hwndOwner is bogus")); return LINEERR_INVALPARAM; }
// Let TAPISRV test the params for us
lResult = ReadLocations(&pLocTest, hLineApp, dwDeviceID, dwAPIVersion, CHECKPARMS_DWHLINEAPP| CHECKPARMS_DWDEVICEID| CHECKPARMS_DWAPIVERSION| CHECKPARMS_ONLY);
if (pLocTest != NULL) { ClientFree( pLocTest); } if (lResult != ERROR_SUCCESS) { return lResult; }
return internalConfig(hwndOwner, lpszAddressIn, -1, dwAPIVersion); }
//***************************************************************************
LONG WINAPI lineGetTranslateCaps( HLINEAPP hLineApp, DWORD dwAPIVersion, LPLINETRANSLATECAPS lpTranslateCaps ) { LONG lResult;
lResult = lineGetTranslateCapsA( hLineApp, dwAPIVersion, lpTranslateCaps );
//
// Some 1.x apps like Applink (as of version 7.5b) don't call
// lineTranslateDialog when they get a LINEERR_INIFILECORRUPT
// result back from the request (spec says they should call
// lineTranslateDialog), so we do that here for them, otherwise
// some (like Applink) blow up
//
// While it's kind of ugly & intrusive, this is a less awkward
// fix than placing a bogus location entry in the registry &
// setting an Inited flag == 0 like tapi 1.x does
//
// There are cases in which this hack can break the caller (ex. MSWORKS)
// The gbDisableGetTranslateCapsHack flag set to TRUE prevents the hack to be applied
// See bug 306143
if (lResult == LINEERR_INIFILECORRUPT && !gbDisableGetTranslateCapsHack) { lineTranslateDialog( hLineApp, 0, dwAPIVersion, GetActiveWindow(), NULL );
lResult = lineGetTranslateCapsA( hLineApp, dwAPIVersion, lpTranslateCaps ); }
return lResult;
}
//***************************************************************************
LONG WINAPI lineGetTranslateCapsA( HLINEAPP hLineApp, DWORD dwAPIVersion, LPLINETRANSLATECAPS lpTranslateCaps ) { LONG lResult = 0; LOG((TL_TRACE, "Entering lineGetTranslateCapsA")); LOG((TL_INFO, " hLineApp=x%lx", hLineApp)); LOG((TL_INFO, " dwAPIVersion=0x%08lx", dwAPIVersion)); LOG((TL_INFO, " lpTranslateCaps=x%p", lpTranslateCaps));
lResult = GetTranslateCapsCommon(hLineApp, dwAPIVersion, lpTranslateCaps, FALSE); #if DBG
{ char szResult[32];
LOG((TL_TRACE, "lineGetTranslateCapsA: result = %hs", MapResultCodeToText (lResult, szResult) )); } #else
LOG((TL_TRACE, "lineGetTranslateCapsA: result = x%x", lResult )); #endif
return lResult; }
//***************************************************************************
LONG WINAPI lineGetTranslateCapsW( HLINEAPP hLineApp, DWORD dwAPIVersion, LPLINETRANSLATECAPS lpTranslateCaps ) { LONG lResult = 0; LOG((TL_TRACE, "Entering lineGetTranslateCapsW")); LOG((TL_INFO, " hLineApp=x%lx", hLineApp)); LOG((TL_INFO, " dwAPIVersion=0x%08lx", dwAPIVersion)); LOG((TL_INFO, " lpTranslateCaps=x%p", lpTranslateCaps));
lResult = GetTranslateCapsCommon( hLineApp, dwAPIVersion, lpTranslateCaps, TRUE);
#if DBG
{ char szResult[32];
LOG((TL_TRACE, "lineGetTranslateCapsW: result = %hs", MapResultCodeToText (lResult, szResult) )); } #else
LOG((TL_TRACE, "lineGetTranslateCapsW: result = x%x", lResult )); #endif
return lResult; }
//***************************************************************************
LONG WINAPI lineTranslateAddressA( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, LPCSTR lpszAddressIn, DWORD dwCard, DWORD dwTranslateOptions, LPLINETRANSLATEOUTPUT lpTranslateOutput ) { WCHAR szTempStringW[512]; LONG lResult;
if ( IsBadStringPtrA(lpszAddressIn, 512) ) { LOG((TL_ERROR, "Invalid pszAddressIn pointer passed into lineTranslateAddress" ));
return LINEERR_INVALPOINTER; }
MultiByteToWideChar( GetACP(), MB_PRECOMPOSED, lpszAddressIn, -1, szTempStringW, 512 );
lResult = lineTranslateAddressW( hLineApp, dwDeviceID, dwAPIVersion, szTempStringW, dwCard, dwTranslateOptions, lpTranslateOutput );
if ( 0 == lResult ) { WideStringToNotSoWideString( (LPBYTE)lpTranslateOutput, &lpTranslateOutput->dwDialableStringSize );
WideStringToNotSoWideString( (LPBYTE)lpTranslateOutput, &lpTranslateOutput->dwDisplayableStringSize ); }
return lResult; }
LONG WINAPI lineTranslateAddress( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, LPCSTR lpszAddressIn, DWORD dwCard, DWORD dwTranslateOptions, LPLINETRANSLATEOUTPUT lpTranslateOutput ) { LONG lResult;
lResult = lineTranslateAddressA( hLineApp, dwDeviceID, dwAPIVersion, lpszAddressIn, dwCard, dwTranslateOptions, lpTranslateOutput );
//
// Some 1.x apps like Applink (as of version 7.5b) don't call
// lineTranslateDialog when they get a LINEERR_INIFILECORRUPT
// result back from the request (spec says they should call
// lineTranslateDialog), so we do that here for them, otherwise
// some (like Applink) blow up
//
// While it's kind of ugly & intrusive, this is a less awkward
// fix than placing a bogus location entry in the registry &
// setting an Inited flag == 0 like tapi 1.x does
//
if (lResult == LINEERR_INIFILECORRUPT) { lineTranslateDialog( hLineApp, 0, dwAPIVersion, GetActiveWindow(), NULL );
lResult = lineTranslateAddressA( hLineApp, dwDeviceID, dwAPIVersion, lpszAddressIn, dwCard, dwTranslateOptions, lpTranslateOutput ); }
return lResult;
}
//***************************************************************************
LONG WINAPI lineTranslateAddressW( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, LPCWSTR lpszAddressIn, DWORD dwCard, DWORD dwTranslateOptions, LPLINETRANSLATEOUTPUT lpTranslateOutput ) { CLocation * pLocation = NULL; CCallingCard * pCallingCard = NULL; DWORD dwTranslateResults; DWORD dwDestCountryCode; PWSTR pszDialableString = NULL; PWSTR pszDisplayableString = NULL; LONG lResult = 0; HRESULT hr=S_OK;
DWORD dwCardToUse = 0;
DWORD dwDialableSize; DWORD dwDisplayableSize; DWORD dwNeededSize; LOG((TL_TRACE, "Entering lineTranslateAddress"));
lResult = IsThisAPIVersionInvalid( dwAPIVersion ); if ( lResult ) { LOG((TL_ERROR, "Bad dwAPIVersion - 0x%08lx", dwAPIVersion)); return lResult; }
if ( TAPIIsBadStringPtrW(lpszAddressIn,256) ) { LOG((TL_ERROR, "Invalid pointer - lpszAddressInW")); lResult = LINEERR_INVALPOINTER; return lResult; }
if ( dwTranslateOptions & ~(LINETRANSLATEOPTION_CARDOVERRIDE | LINETRANSLATEOPTION_CANCELCALLWAITING | LINETRANSLATEOPTION_FORCELOCAL | LINETRANSLATEOPTION_FORCELD) ) { LOG((TL_ERROR, " Invalid dwTranslateOptions (unknown flag set)")); lResult = LINEERR_INVALPARAM; return lResult; }
if ( ( dwTranslateOptions & ( LINETRANSLATEOPTION_FORCELOCAL | LINETRANSLATEOPTION_FORCELD) ) == ( LINETRANSLATEOPTION_FORCELOCAL | LINETRANSLATEOPTION_FORCELD) ) { LOG((TL_ERROR, " Invalid dwTranslateOptions (both FORCELOCAL & FORCELD set!)")); lResult = LINEERR_INVALPARAM; return lResult; }
//
// Is the structure at least a minimum size?
//
if (IsBadWritePtr(lpTranslateOutput, sizeof(LINETRANSLATEOUTPUT))) { LOG((TL_ERROR, " Leaving lineTranslateAddress INVALIDPOINTER")); lResult = LINEERR_INVALPOINTER; return lResult; }
if (lpTranslateOutput->dwTotalSize < sizeof(LINETRANSLATEOUTPUT)) { LOG((TL_ERROR, " Leaving lineTranslateAddress STRUCTURETOOSMALL")); lResult = LINEERR_STRUCTURETOOSMALL; return lResult; }
if (IsBadWritePtr(lpTranslateOutput, lpTranslateOutput->dwTotalSize) ) { LOG((TL_ERROR, " Leaving lineTranslateAddress lpTanslateOutput->dwTotalSize bad" ));
lResult = LINEERR_INVALPOINTER; return lResult; }
//
// Should we let some bad stuff slide?
//
if ( dwAPIVersion < 0x00020000 ) { hLineApp = NULL; }
lResult = CreateCurrentLocationObject(&pLocation, hLineApp, dwDeviceID, dwAPIVersion, CHECKPARMS_DWHLINEAPP| CHECKPARMS_DWDEVICEID| CHECKPARMS_DWAPIVERSION); if(FAILED(lResult)) { //lResult = lResult==E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED;
return lResult; }
if ( dwTranslateOptions & LINETRANSLATEOPTION_CARDOVERRIDE) { dwCardToUse = dwCard; } else { if(pLocation->HasCallingCard() ) { dwCardToUse = pLocation->GetPreferredCardID(); } } if (dwCardToUse != 0) { pCallingCard = new CCallingCard; if(pCallingCard) { if( FAILED(pCallingCard->Initialize(dwCardToUse)) ) { delete pCallingCard; delete pLocation; lResult = LINEERR_INVALCARD; return lResult; } } }
lResult = pLocation->TranslateAddress((PWSTR)lpszAddressIn, pCallingCard, dwTranslateOptions, &dwTranslateResults, &dwDestCountryCode, &pszDialableString, &pszDisplayableString );
if (lResult == 0)
{ dwDialableSize = sizeof(WCHAR) * (lstrlenW(pszDialableString) + 1); dwDisplayableSize = sizeof(WCHAR) * (lstrlenW(pszDisplayableString) + 1);
dwNeededSize = dwDialableSize + dwDisplayableSize + 3 + // For potential alignment problem
sizeof(LINETRANSLATEOUTPUT);
lpTranslateOutput->dwNeededSize = dwNeededSize;
lpTranslateOutput->dwCurrentCountry = pLocation->GetCountryID();
lpTranslateOutput->dwDestCountry = dwDestCountryCode; // country code, not the ID !!
if (dwNeededSize <= lpTranslateOutput->dwTotalSize) { lpTranslateOutput->dwUsedSize = dwNeededSize;
lpTranslateOutput->dwDialableStringSize = dwDialableSize;
lpTranslateOutput->dwDialableStringOffset = sizeof(LINETRANSLATEOUTPUT);
lpTranslateOutput->dwDisplayableStringSize = dwDisplayableSize;
lpTranslateOutput->dwDisplayableStringOffset = sizeof(LINETRANSLATEOUTPUT) + dwDialableSize;
// lpTranslateOutput->dwDisplayableStringOffset =
// (sizeof(LINETRANSLATEOUTPUT) + dwDialableSize
// + 3) & 0xfffffffc;
lpTranslateOutput->dwTranslateResults = dwTranslateResults;
wcscpy ((WCHAR *)(lpTranslateOutput + 1), pszDialableString);
//
// Be ultra paranoid and make sure the string is DWORD aligned
//
wcscpy( (LPWSTR)(((LPBYTE)(lpTranslateOutput + 1) + dwDialableSize)), // + 3 ) & 0xfffffffc)
pszDisplayableString ); } else { lpTranslateOutput->dwUsedSize = sizeof(LINETRANSLATEOUTPUT);
lpTranslateOutput->dwTranslateResults = lpTranslateOutput->dwDialableStringSize = lpTranslateOutput->dwDialableStringOffset = lpTranslateOutput->dwDisplayableStringSize = lpTranslateOutput->dwDisplayableStringOffset = 0; } }
//cleanup:
if ( pszDisplayableString ) { ClientFree( pszDisplayableString ); } if ( pszDialableString ) { ClientFree( pszDialableString ); } if (pLocation != NULL) { delete pLocation; } if (pCallingCard != NULL) { delete pCallingCard; }
/*
//
// If success & there's an LCR hook for this function then call it
// & allow it to override our results if it wants to
//
if (lResult == 0 && IsLeastCostRoutingEnabled() && pfnLineTranslateAddressWLCR) { lResult = (*pfnLineTranslateAddressWLCR)( hLineApp, dwDeviceID, dwAPIVersion, lpszAddressIn, dwCard, dwTranslateOptions, lpTranslateOutput ); } */ return (lResult); }
//***************************************************************************
LONG WINAPI lineSetCurrentLocation( HLINEAPP hLineApp, DWORD dwLocationID ) {
UINT n; PUINT pnStuff; PLOCATIONLIST pLocationList; PLOCATION pEntry; LONG lResult = 0; HRESULT hr; DWORD dwCurrentLocationID = 0; DWORD dwNumEntries = 0; DWORD dwCount = 0;
LOG((TL_TRACE, "lineSetCurrentLocation: enter, hApp=x%x, dwLoc=x%x", hLineApp, dwLocationID ));
// Let TAPISRV test the params for us
hr = ReadLocations(&pLocationList, hLineApp, 0, 0, CHECKPARMS_DWHLINEAPP );
if SUCCEEDED( hr) { // current location
dwCurrentLocationID = pLocationList->dwCurrentLocationID;
//
// If (specified loc == current loc) then simply return SUCCESS.
//
// Ran into a problem with the Equis (Reuters) DownLoader app in
// which it would call this func, we'd pass the info to tapisrv,
// tapisrv would send a LINE_LINEDEVSTATE\TRANSLATECHANGE msg,
// and the app would respond by doing a lineSetCurrentLocation
// again, effectively winding up in an infinite loop. Fyi, tapi
// 1.x did not send a DEVSTATE\TRANSLATECHANGE msg if the
// specified locationID == the current location ID.
//
if (dwLocationID == dwCurrentLocationID) { lResult = 0; } else { hr = E_FAIL; // fail if we don't find the requested loc
// Find position of 1st LOCATION structure in the LOCATIONLIST structure
pEntry = (PLOCATION) ((BYTE*)(pLocationList) + pLocationList->dwLocationListOffset ); // Number of locations ?
dwNumEntries = pLocationList->dwNumLocationsInList; // Find the current location
for (dwCount = 0; dwCount < dwNumEntries ; dwCount++) { if(pEntry->dwPermanentLocationID == dwLocationID) { hr = S_OK; break; } // Try next location in list
//pEntry++;
pEntry = (PLOCATION) ((BYTE*)(pEntry) + pEntry->dwUsedSize); }
if SUCCEEDED( hr) { LOG((TL_INFO, "lineSetCurrentLocation - reqired location found %d", dwCurrentLocationID));
// write new value
// finished with TAPI memory block so release
if ( pLocationList != NULL ) ClientFree( pLocationList );
// Allocate the memory buffer;
pLocationList = (PLOCATIONLIST) ClientAlloc( sizeof(LOCATIONLIST) ); if (pLocationList != NULL) { // buffer size
pLocationList->dwTotalSize = sizeof(LOCATIONLIST); pLocationList->dwNeededSize = sizeof(LOCATIONLIST); pLocationList->dwUsedSize = sizeof(LOCATIONLIST); pLocationList->dwCurrentLocationID = dwLocationID; pLocationList->dwNumLocationsAvailable = 0; pLocationList->dwNumLocationsInList = 0; pLocationList->dwLocationListSize = 0; pLocationList->dwLocationListOffset = 0; WriteLocations( pLocationList, CHANGEDFLAGS_CURLOCATIONCHANGED); }
} else { LOG((TL_ERROR, "lineSetCurrentLocation - required location not found ")); lResult = LINEERR_INVALLOCATION; } } } else { lResult = hr; }
// finished with TAPI memory block so release
if ( pLocationList != NULL ) ClientFree( pLocationList );
LOG((TL_TRACE, "Leaving lineSetCurrentLocation")); return lResult; }
//***************************************************************************
LONG WINAPI lineSetTollList( HLINEAPP hLineApp, DWORD dwDeviceID, LPCSTR lpszAddressIn, DWORD dwTollListOption ) { return lineSetTollListA( hLineApp, dwDeviceID, lpszAddressIn, dwTollListOption ); }
//***************************************************************************
LONG WINAPI lineSetTollListA( HLINEAPP hLineApp, DWORD dwDeviceID, LPCSTR lpszAddressIn, DWORD dwTollListOption ) { WCHAR szAddressInW[512];
if ( IsBadStringPtrA(lpszAddressIn, 512) ) { LOG((TL_ERROR, "Bad string pointer passed to lineSetTollListA")); return LINEERR_INVALPOINTER; }
MultiByteToWideChar( GetACP(), MB_PRECOMPOSED, lpszAddressIn, -1, szAddressInW, 512 );
return lineSetTollListW( hLineApp, dwDeviceID, szAddressInW, dwTollListOption ); }
//***************************************************************************
LONG WINAPI lineSetTollListW( HLINEAPP hLineApp, DWORD dwDeviceID, PCWSTR pszAddressIn, DWORD dwTollListOption ) { PWSTR pAddressIn = NULL; PWSTR pAreaCode; PWSTR pCountryCode; PWSTR pSubscriber;
CLocation *pLocation = NULL;
BOOL bPrefixPresent; CAreaCodeRule *pRule = NULL; PWSTR pWhere = NULL;
LONG lResult;
// Test the parameters
if ((dwTollListOption != LINETOLLLISTOPTION_ADD) && (dwTollListOption != LINETOLLLISTOPTION_REMOVE)) { LOG((TL_ERROR, "Bad dwTollListOption in lineSetTollListW")); return LINEERR_INVALPARAM; }
if ( TAPIIsBadStringPtrW(pszAddressIn, 256) ) { LOG((TL_ERROR, "Bad pszAddressIn (0x%p)in lineSetTollListW", pszAddressIn)); return LINEERR_INVALPOINTER; } //
// Now, do we have a canonical number to deal with ?
//
if ( *pszAddressIn != L'+' ) // Check the first char
{ //
// Nope, not canonical
//
LOG((TL_ERROR, "Address not canonical in lineSetTollListW")); return LINEERR_INVALADDRESS; } // Alloc a copy of the string
pAddressIn = ClientAllocString((PWSTR)pszAddressIn); if ( !pAddressIn ) { LOG((TL_ERROR, "Memory allocation failed")); return LINEERR_NOMEM; } // separate the string components
lResult = BreakupCanonicalW(pAddressIn + 1, &pCountryCode, &pAreaCode, &pSubscriber ); if(lResult) { goto forced_exit; } // test the prefix validity.
// assuming 3 digits..
if(! (iswdigit(pSubscriber[0]) && iswdigit(pSubscriber[1]) && iswdigit(pSubscriber[2]) && pSubscriber[3] )) { LOG((TL_ERROR, "lineSetTollListW: The prefix is not valid")); lResult = LINEERR_INVALADDRESS; goto forced_exit; } // get the current location object
lResult = CreateCurrentLocationObject(&pLocation, hLineApp, dwDeviceID, 0, CHECKPARMS_DWHLINEAPP| CHECKPARMS_DWDEVICEID); if(FAILED(lResult)) { //lResult = lResult==E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED;
goto forced_exit; }
// are the number and the current location with country code 1 ?
// is this number in the same area code ?
if(pLocation->GetCountryCode() != 1 || pCountryCode[0] != L'1' || pCountryCode[1] != L'\0' || wcscmp(pLocation->GetAreaCode(), pAreaCode) !=0 ) { lResult = 0; goto forced_exit; }
// terminate the 3 digit prefix
pSubscriber[3] = L'\0'; pSubscriber[4] = L'\0';
// is there the prefix in any location toll rules ?
bPrefixPresent = FindTollPrefixInLocation( pLocation, pSubscriber, &pRule, &pWhere);
if(dwTollListOption == LINETOLLLISTOPTION_ADD) { // add toll prefix
if(bPrefixPresent) { ;// Do nothing
lResult = 0; } else { // if we have already a toll rule, try to add the prefix to it
if(pRule) { PWSTR pList; DWORD dwSize = pRule->GetPrefixListSize(); // alloc a bigger list
pList = (PWSTR)ClientAlloc(dwSize + 4*sizeof(WCHAR)); if(pList==NULL) { lResult = LINEERR_NOMEM; goto forced_exit; } // copy the old one
memcpy((PBYTE)pList, (PBYTE)pRule->GetPrefixList(), dwSize); // add our prefix
memcpy((PBYTE)pList + dwSize-sizeof(WCHAR), (PBYTE)pSubscriber, 5*sizeof(WCHAR)); // set the new list
lResult = pRule->SetPrefixList(pList, dwSize + 4*sizeof(WCHAR));
ClientFree(pList); if(FAILED(lResult)) { lResult = lResult==E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; goto forced_exit; } } // else a new rule must be created
else { pRule = new CAreaCodeRule(); if(pRule == NULL) { lResult = LINEERR_NOMEM; goto forced_exit; }
lResult = pRule->Initialize( pAreaCode, L"1", RULE_DIALNUMBER | RULE_DIALAREACODE, pSubscriber, 5*sizeof(WCHAR) ); if(FAILED(lResult)) { delete pRule; lResult = lResult==E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; goto forced_exit; } // add the rule to the location
pLocation->AddRule(pRule); } } } else { // delete the toll prefix
if(bPrefixPresent) { DWORD dwSize = pRule->GetPrefixListSize(); // we have at least a toll rule present. If our prefix is the only one in that rule,
// delete the entire rule
if(dwSize<=5*sizeof(WCHAR)) { // Delete the rule
pLocation->RemoveRule(pRule);
lResult = 0; } else { PWSTR pList; PWSTR pOld; DWORD dwHeadSize; DWORD dwTailSize; pList = (PWSTR)ClientAlloc(dwSize - 4*sizeof(WCHAR)); if(pList==NULL) { lResult = LINEERR_NOMEM; goto forced_exit; }
pOld = pRule->GetPrefixList();
dwHeadSize = (DWORD)((PBYTE)pWhere - (PBYTE)pOld); dwTailSize = dwSize - dwHeadSize - 4*sizeof(WCHAR);
// copy the first part of the old list
memcpy((PBYTE)pList, (PBYTE)pOld, dwHeadSize); // copy the rest of the list
memcpy((PBYTE)pList+dwHeadSize, (PBYTE)pWhere + 4*sizeof(WCHAR), dwTailSize); // set the new list
lResult = pRule->SetPrefixList(pList, dwSize - 4*sizeof(WCHAR));
ClientFree(pList); if(FAILED(lResult)) { lResult = lResult==E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; goto forced_exit; }
}
} else { // prefix not present. Do nothing.
lResult = 0; } }
// Save
lResult = pLocation->WriteToRegistry(); if(FAILED(lResult)) { lResult = lResult==E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; goto forced_exit; }
forced_exit:
if(pLocation) delete pLocation; if(pAddressIn) ClientFree(pAddressIn);
return lResult; }
//***************************************************************************
LONG WINAPI tapiGetLocationInfoW( LPWSTR lpszCountryCode, LPWSTR lpszCityCode ) { CLocation * pLocation; LONG lResult = 0; WCHAR * p; WCHAR * q; DWORD i; if (IsBadWritePtr( lpszCountryCode, 16) ) { LOG((TL_ERROR, "tapiGetLocationInfoW: lpszCountryCode is not a valid, 8-byte pointer" )); return TAPIERR_REQUESTFAILED; } if (IsBadWritePtr( lpszCityCode, 16) ) { LOG((TL_ERROR, "tapiGetLocationInfoW: lpszCityCode is not a valid, 8-byte pointer" )); return TAPIERR_REQUESTFAILED; } lResult = CreateCurrentLocationObject(&pLocation,0,0,0,0); if(FAILED(lResult)) { return TAPIERR_REQUESTFAILED; } TCHAR szTempChar[8]; wsprintf( szTempChar, TEXT("%d"), pLocation->GetCountryCode() ); SHTCharToUnicode(szTempChar, lpszCountryCode, 8); //
// Make sure not to return > (7 chars + NULL char)
//
p = (WCHAR *) lpszCityCode; q = (WCHAR *) pLocation->GetAreaCode(); for (i = 0; (i < 7) && ((p[i] = q[i]) != L'\0'); i++); p[7] = L'\0'; delete pLocation; return 0; }
//***************************************************************************
LONG WINAPI tapiGetLocationInfoA( LPSTR lpszCountryCode, LPSTR lpszCityCode ) {
WCHAR szCountryCodeW[8]; WCHAR szCityCodeW[8]; LONG lResult;
LOG((TL_TRACE, "Entering tapiGetLocationInfoA")); LOG((TL_INFO, " lpszCountryCode=%p", lpszCountryCode )); LOG((TL_INFO, " lpszCityCode=%p", lpszCityCode ));
if (IsBadWritePtr( lpszCountryCode, 8) ) { LOG((TL_ERROR, "tapiGetLocationInfo: lpszCountryCode is not a valid, 8-byte pointer")); return TAPIERR_REQUESTFAILED; }
if (IsBadWritePtr( lpszCityCode, 8) ) { LOG((TL_ERROR, "tapiGetLocationInfo: lpszCityCode is not a valid, 8-byte pointer")); return TAPIERR_REQUESTFAILED; }
lResult = tapiGetLocationInfoW( szCountryCodeW, szCityCodeW );
if ( 0 == lResult ) { WideCharToMultiByte( GetACP(), 0, szCountryCodeW, -1, lpszCountryCode, 8, NULL, NULL );
WideCharToMultiByte( GetACP(), 0, szCityCodeW, -1, lpszCityCode, 8, NULL, NULL ); }
return lResult; }
//***************************************************************************
LONG WINAPI tapiGetLocationInfo( LPSTR lpszCountryCode, LPSTR lpszCityCode ) { return tapiGetLocationInfoA( lpszCountryCode, lpszCityCode ); }
//***************************************************************************
//
// RAS Private Interfaces
//
//***************************************************************************
#ifndef NORASPRIVATES
//***************************************************************************
LOCATION* LocationFromID( IN LOCATION* pLocs, IN UINT cLocs, IN DWORD dwID ) { return NULL; }
//***************************************************************************
LOCATION* LocationFromName( IN LOCATION* pLocs, IN UINT cLocs, IN WCHAR* pszName ) { return NULL; }
//***************************************************************************
//
// internalCreateDefLocation
//
// This API is created to be used by OOBE team internally.
// It expectes a LOCATIONLIST with at least one LOCATION
// specified in it. and pLocation->dwCurrentLocationID needs to
// match dwPermanentLocationID of at least one of the location
// entries specified in the location list.
//
extern "C" HRESULT APIENTRY internalCreateDefLocation( PLOCATIONLIST pLocationList ) { HRESULT hr = S_OK; DWORD dw; PLOCATION pEntry;
// Basic parameter check
if (pLocationList == NULL || pLocationList->dwNumLocationsInList < 1 || pLocationList->dwUsedSize == 0 || pLocationList->dwUsedSize > pLocationList->dwTotalSize || pLocationList->dwTotalSize < sizeof(LOCATIONLIST) + sizeof(LOCATION) || pLocationList->dwLocationListSize < sizeof(LOCATION) ) { hr = E_INVALIDARG; goto ExitHere; }
// Check the validity of the dwCurrentLocationID
pEntry = (PLOCATION)((LPBYTE)pLocationList + pLocationList->dwLocationListOffset); for (dw = 0; dw < pLocationList->dwNumLocationsInList; ++dw) { if (pEntry->dwPermanentLocationID == pLocationList->dwCurrentLocationID) { break; } pEntry = (PLOCATION)((LPBYTE)pEntry + pEntry->dwUsedSize); } if (dw >= pLocationList->dwNumLocationsInList) { hr = E_INVALIDARG; goto ExitHere; }
hr = (HRESULT) WriteLocations ( pLocationList, CHANGEDFLAGS_CURLOCATIONCHANGED );
ExitHere: return hr; }
extern "C" DWORD APIENTRY internalNewLocationW( IN WCHAR* pszName )
{ LONG lResult = 0;
CLocation *pLocation = NULL; CLocation *pNewLocation = NULL; CAreaCodeRule *pAreaCodeRule = NULL; CAreaCodeRule *pNewRule = NULL; // Validate
if (!pszName || lstrlenW( pszName ) > MAXLEN_NAME) return LINEERR_INVALPARAM;
// Read the current location
lResult = CreateCurrentLocationObject(&pLocation,0,0,0,0); if(FAILED(lResult)) { //lResult = lResult==E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED;
return lResult; }
// Create the new object
pNewLocation = new CLocation(); if(pNewLocation==NULL) { delete pLocation; LOG((TL_ERROR, "Cannot allocate a CLocation object")); return LINEERR_NOMEM; } // Clone the location (w/o the ID)
lResult = pNewLocation->Initialize( pszName, pLocation->GetAreaCode(), pLocation->GetLongDistanceCarrierCode(), pLocation->GetInternationalCarrierCode(), pLocation->GetLongDistanceAccessCode(), pLocation->GetLocalAccessCode(), pLocation->GetDisableCallWaitingCode(), 0, pLocation->GetCountryID(), pLocation->GetPreferredCardID(), (pLocation->HasCallingCard() ? LOCATION_USECALLINGCARD : 0) | (pLocation->HasCallWaiting() ? LOCATION_HASCALLWAITING : 0) | (pLocation->HasToneDialing() ? LOCATION_USETONEDIALING : 0) , FALSE); if(FAILED(lResult)) { delete pLocation; delete pNewLocation; lResult = lResult==E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; return lResult; }
// Set the ID
lResult = pNewLocation->NewID(); if(FAILED(lResult)) { delete pLocation; delete pNewLocation; lResult = lResult==E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; return lResult; } // Copy the area code rules
pLocation->ResetRules(); while(S_OK == pLocation->NextRule(1, &pAreaCodeRule, NULL)) { pNewRule = new CAreaCodeRule; pNewRule->Initialize(pAreaCodeRule->GetAreaCode(), pAreaCodeRule->GetNumberToDial(), pAreaCodeRule->GetOptions(), pAreaCodeRule->GetPrefixList(), pAreaCodeRule->GetPrefixListSize() ); pNewLocation->AddRule(pNewRule); }
// Save the new location
lResult = pNewLocation->WriteToRegistry(); if(FAILED(lResult)) { delete pLocation; delete pNewLocation; lResult = lResult==E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; return lResult; } delete pLocation;
delete pNewLocation;
return 0; }
//***************************************************************************
extern "C" DWORD APIENTRY internalRemoveLocation( IN DWORD dwID ) { CLocations *pLocationList = NULL; DWORD dwCurID;
HRESULT Result;
LOG((TL_TRACE, "Entering internalRemoveLocation")); LOG((TL_INFO, " dwID=0x%d", dwID));
// Read the location list
pLocationList = new CLocations(); if(pLocationList==NULL) { LOG((TL_ERROR, "Cannot allocate a CLocations object")); return LINEERR_NOMEM; }
Result = pLocationList->Initialize(); if(FAILED(Result)) { delete pLocationList; LOG((TL_ERROR, "CLocations.Initialize() failed - HRESULT=0x%08lx", Result)); return Result == E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_INIFILECORRUPT; }
// Cannot delete the last location
if(pLocationList->GetNumLocations() <2) { delete pLocationList; return LINEERR_INVALPARAM; }
// If we're deleting the current location make the first location the
// current location, or if we're deleting the first the second.
dwCurID = pLocationList->GetCurrentLocationID();
if(dwCurID==dwID) { CLocation *pLocation; // find the first location
pLocationList->Reset(); pLocationList->Next(1, &pLocation, NULL); // are we deleting the first
if(pLocation->GetLocationID()==dwID) // try the second
pLocationList->Next(1, &pLocation, NULL); // change the current location
pLocationList->SetCurrentLocationID(pLocation->GetLocationID()); }
// Delete the location
pLocationList->Remove(dwID);
// Save
Result = pLocationList->SaveToRegistry(); if(FAILED(Result)) { delete pLocationList; LOG((TL_ERROR, "CLocations.SaveToRegistry() failed - HRESULT=0x%08lx", Result)); return Result == E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; }
delete pLocationList;
return 0; }
//***************************************************************************
extern "C" DWORD APIENTRY internalRenameLocationW( IN WCHAR* pszOldName, IN WCHAR* pszNewName ) {
CLocations *pLocationList; CLocation *pLocation;
HRESULT Result; DWORD dwError;
// Test the arguments
if(!pszOldName || !pszNewName || wcslen(pszNewName) > MAXLEN_NAME) return LINEERR_INVALPARAM;
// Read the locations
pLocationList = new CLocations(); if(pLocationList==NULL) { LOG((TL_ERROR, "Cannot allocate a CLocations object")); return LINEERR_NOMEM; }
Result = pLocationList->Initialize(); if(FAILED(Result)) { delete pLocationList; LOG((TL_ERROR, "CLocations.Initialize() failed - HRESULT=0x%08lx", Result)); return Result == E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_INIFILECORRUPT; }
// find the specified location
dwError = LINEERR_INVALPARAM; // skeptical approach
pLocationList->Reset(); while(pLocationList->Next(1, &pLocation, NULL)==S_OK) { if(wcscmp(pLocation->GetName(), pszOldName)==0) { // found it, change it
Result = pLocation->SetName(pszNewName); if(FAILED(Result)) { delete pLocationList; LOG((TL_ERROR, "CLocations.SetName(Name) failed - HRESULT=0x%08lx", Result)); return Result == E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; } // save
Result = pLocationList->SaveToRegistry(); if(FAILED(Result)) { delete pLocationList; LOG((TL_ERROR, "CLocations.SetName(Name) failed - HRESULT=0x%08lx", Result)); return Result == E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; } dwError = 0;
break; } }
delete pLocationList;
return dwError;
}
#endif // !NORASPRIVATES
//***************************************************************************
//
// Helper functions
//
//***************************************************************************
LONG BreakupCanonicalW( PWSTR pAddressIn, PWSTR *pCountry, PWSTR *pCity, PWSTR *pSubscriber ) { LONG lResult = 0; PWSTR pCountryEnd; PWSTR pAreaEnd;
//
// Get past any (illegal) leading spaces
//
while ( *pAddressIn == L' ' ) { pAddressIn++; }
//
// Leading zeros are very bad. Don't allow them.
// We're now at the first non-space. Better not be a '0'.
//
if ( *pAddressIn == L'0' ) { //
// There are leading zeros!
//
LOG((TL_ERROR, " Canonical numbers are not allowed to have leading zeros")); lResult = LINEERR_INVALADDRESS; goto cleanup; }
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
// Parse the canonical number into its component pieces
//
//
// Do country first
//
*pCountry = pAddressIn;
// At least one digit must be present
if(!(iswdigit(*pAddressIn))) { LOG((TL_ERROR, " Canonical numbers must have a valid country code")); lResult = LINEERR_INVALADDRESS; goto cleanup; }
//
// Now get to past this
//
while (iswdigit(*pAddressIn) ) { pAddressIn++; }
// Save the end of the country code
pCountryEnd = pAddressIn;
//
// We hit something that's not a digit...
// There must be only one space here, but we allow any number of spaces (including none)
//
while (*pAddressIn == L' ') { pAddressIn++; }
// Test the area code delimiter
if ( *pAddressIn == L'(') { pAddressIn++;
// Skip any illegal spaces
while (*pAddressIn == L' ') { pAddressIn++; } /*
// At least one digit must be present
if(!(iswdigit(*pAddressIn))) { LOG((TL_ERROR, TEXT(" Canonical numbers must have a valid area code between ()"))); lResult = LINEERR_INVALADDRESS; goto cleanup; } */ //
// This must be the beginning of the area code
//
*pCity = pAddressIn;
//
// Now get to past this
//
while (iswdigit(*pAddressIn) ) { pAddressIn++; }
// Save the end pointer
pAreaEnd = pAddressIn;
// Skip any illegal spaces
while (*pAddressIn == L' ') { pAddressIn++; }
if(*pAddressIn != L')') { LOG((TL_ERROR, " Canonical numbers must have a ')' after the area code")); lResult = LINEERR_INVALADDRESS; goto cleanup; }
pAddressIn++;
*pAreaEnd = L'\0';
// Return the same NULL string for an empty area code
if(*pCity == pAreaEnd) *pCity = NULL; } else { // there's no area code
*pCity = NULL;
}
// Skip spaces
while (*pAddressIn == L' ') { pAddressIn++; }
*pCountryEnd = L'\0';
//
// Nothing left to do but put the icing on the cake
//
*pSubscriber = pAddressIn;
if ( TAPIIsBadStringPtrW( *pSubscriber, 512 ) || lstrlenW( *pSubscriber ) == 0 ) { //
// Obviously not canonical
//
LOG((TL_ERROR, " Canonical numbers must have a subscriber number")); lResult = LINEERR_INVALADDRESS; goto cleanup; }
cleanup:
return lResult; }
static void LayDownString( PCWSTR pInString, PBYTE pBuffer, PBYTE *ppCurrentIndex, PDWORD pPair, // this is the Len & Offset pair
BOOL bUnicode, PBYTE pFirstByteAfter ) {
#define LDS_FAST_BUF_SIZE 48
DWORD dwLength; PSTR pTempString = NULL; char achFastBuf[LDS_FAST_BUF_SIZE]; if(bUnicode) { dwLength = (lstrlenW( pInString ) + 1)*sizeof(WCHAR); } else {
dwLength = WideCharToMultiByte( GetACP(), 0, pInString, -1, NULL, 0, NULL, NULL );
if (dwLength == 0) { return; }
}
// Make sure we're starting on some boundary
//
*ppCurrentIndex = (PBYTE) (((ULONG_PTR)( *ppCurrentIndex + TALIGN_COUNT)) & (~TALIGN_COUNT));
if(*ppCurrentIndex + dwLength <= pFirstByteAfter) { pPair[0] = dwLength; pPair[1] = (DWORD)(*ppCurrentIndex - pBuffer);
if(bUnicode) { wcscpy( (PWSTR)*ppCurrentIndex, pInString ); } else { //
// Get some space in which to convert Unicode to local
//
pTempString = (dwLength > LDS_FAST_BUF_SIZE ? (PSTR)ClientAlloc (dwLength) : (PSTR) achFastBuf);
if ( !pTempString ) { pPair[0] = 0; pPair[1] = 0; return; }
WideCharToMultiByte( GetACP(), 0, pInString, -1, pTempString, dwLength, NULL, NULL );
lstrcpyA( (PSTR)*ppCurrentIndex, pTempString );
if (pTempString != (PSTR) achFastBuf) { ClientFree (pTempString); } } } *ppCurrentIndex += dwLength;
}
static PWSTR CopyStringWithExpandJAndK(PWSTR pszRule, PWSTR pszAccessNr, PWSTR pszAccountNr) { DWORD dwLength=0; PWSTR pResult = NULL;
PWCHAR pCrt, pOut; WCHAR c;
DWORD dwAccessNrLen, dwAccountNrLen;
dwAccessNrLen = wcslen(pszAccessNr); dwAccountNrLen = wcslen(pszAccountNr);
// Find the space to alloc
pCrt = pszRule; while(*pCrt) { c = *pCrt++;
if(c == L'J' || c == L'j') { dwLength += dwAccessNrLen; } else if (c == L'K' || c == L'k') { dwLength += dwAccountNrLen; } else dwLength++; } // WCHARs and NULL term
dwLength = (dwLength+1)*sizeof(WCHAR);
// Alloc
pResult = (PWSTR)ClientAlloc(dwLength); // allocates zeroed memory
if(pResult == NULL) return NULL;
// Create result
pCrt = pszRule; pOut = pResult;
while(*pCrt) { c = *pCrt++;
if(c == L'J' || c == L'j') { wcscat(pOut, pszAccessNr); pOut += dwAccessNrLen; } else if (c == L'K' || c == L'k') { wcscat(pOut, pszAccountNr); pOut += dwAccountNrLen; } else *pOut++ = c; } return pResult; }
static void LayDownTollList(CLocation *pLocation, PBYTE pBuffer, PBYTE *ppCurrentIndex, PDWORD pPair, BOOL bUnicode, PBYTE pFirstByteAfter ) { DWORD dwLength; DWORD dwTotalLength; DWORD dwListLength; PBYTE pDest; AreaCodeRulePtrNode *pNode; PWSTR pszLocationAreaCode; DWORD dwCountryCode; BOOL bFirst; CAreaCodeRule *pRule; DWORD dwIndex;
pszLocationAreaCode = pLocation->GetAreaCode(); dwCountryCode = pLocation->GetCountryCode();
// Make sure we're starting on some boundary
//
*ppCurrentIndex = (PBYTE) (((ULONG_PTR)( *ppCurrentIndex + TALIGN_COUNT )) & (~TALIGN_COUNT));
// Save the destination pointer
pDest = *ppCurrentIndex;
bFirst = TRUE; dwTotalLength = 0;
// Only for US, Canada, Antigua etc.
if(pLocation->GetCountryCode() == 1) { // Find all rules which could be considered toll rules
pNode = pLocation->m_AreaCodeRuleList.head();
while( !pNode->beyond_tail() ) { pRule = pNode->value();
if( IsATollListAreaCodeRule(pRule, pszLocationAreaCode)) { // Get the size of the prefixes, in bytes
dwListLength = pRule->GetPrefixListSize();
if(bUnicode) { WCHAR *pCrt; WCHAR *pOut; // we strip the last two nulls
dwLength = dwListLength - 2*sizeof(WCHAR); // if this is not the first rule, a comma should be added
if(!bFirst) dwLength += sizeof(WCHAR); dwTotalLength += dwLength;
// we have to convert the single nulls in commas
if(*ppCurrentIndex + dwLength <= pFirstByteAfter) { if(!bFirst) { *(WCHAR *)(*ppCurrentIndex) = L','; *ppCurrentIndex += sizeof(WCHAR); }
pCrt = pRule->GetPrefixList();
dwListLength /= sizeof(WCHAR); dwListLength--; dwListLength--; // now dwListLength is the length in characters without the two ending nulls
// replace nulls with commas
for (dwIndex =0; dwIndex<dwListLength; dwIndex++) { if(*pCrt) *(WCHAR *)(*ppCurrentIndex) = *pCrt; else *(WCHAR *)(*ppCurrentIndex) = L','; pCrt++; *ppCurrentIndex += sizeof(WCHAR); } }
} else { WCHAR *pList; dwListLength /= sizeof(WCHAR); dwListLength--; dwListLength--; // now dwListLength is the length in characters without the two ending nulls
// Length needed
pList = pRule->GetPrefixList(); dwLength = WideCharToMultiByte( GetACP(), 0, pList, dwListLength, NULL, 0, NULL, NULL );
// if this is not the first rule, a comma should be added
if(!bFirst) dwLength+=sizeof(CHAR); dwTotalLength += dwLength;
if(*ppCurrentIndex + dwLength <= pFirstByteAfter) { if(!bFirst) { *(CHAR *)(*ppCurrentIndex) = ','; *ppCurrentIndex += sizeof(CHAR);
dwLength-=sizeof(CHAR); // temporary - the conversion and the null filling routines
// should'nt take into account the space for the separating comma
} // convert
WideCharToMultiByte(GetACP(), 0, pList, dwListLength, (PSTR)(*ppCurrentIndex), dwLength, NULL, NULL ); // Replace inplace the nulls with commas
for (dwIndex =0; dwIndex<dwLength; dwIndex++) { if(*(CHAR *)(*ppCurrentIndex)=='\0') *(CHAR *)(*ppCurrentIndex) = ',';
*ppCurrentIndex += sizeof(CHAR); }
if(!bFirst) dwLength+=sizeof(CHAR); // restore
}
}
bFirst = FALSE; }
pNode = pNode->next(); }
}
// space for a terminating NULL
dwLength = bUnicode ? sizeof(WCHAR) : 1; dwTotalLength += dwLength;
if(*ppCurrentIndex + dwLength <= pFirstByteAfter) { if(bUnicode) *(WCHAR *)(*ppCurrentIndex) = L'\0'; else *(CHAR *)(*ppCurrentIndex) = '\0';
*ppCurrentIndex += dwLength; pPair[0] = (DWORD)(*ppCurrentIndex - pDest); pPair[1] = (DWORD)(pDest - pBuffer); }
// Update the current pointer whatever the buffer size is
*ppCurrentIndex = pDest + dwTotalLength;
}
static LONG GetTranslateCapsCommon( HLINEAPP hLineApp, DWORD dwAPIVersion, LPLINETRANSLATECAPS lpTranslateCaps, BOOL bUnicode ) {
LONG lResult = 0; // good for HRESULTs too
CLocations *pLocationList = NULL; CCallingCards *pCardList = NULL; DWORD dwNumLocations; DWORD dwNumCards;
DWORD dwLenChar;
CCallingCard *pCard = NULL; CLocation *pLocation;
DWORD dwTotalSize; DWORD dwFinalSize; DWORD dwLocationsSize; DWORD dwLocationsStart; DWORD dwCardsSize; DWORD dwCardsStart;
DWORD dwCurrentLocationID; DWORD dwPreferredCardID; DWORD dwTempCardID;
BOOL bOldTapi; BOOL bBufferTooSmall;
LINELOCATIONENTRY *pLineLocationEntry; LINECARDENTRY *pLineCardEntry; PBYTE pCurrentIndex; PBYTE pCurrentIndexSave; PBYTE pFirstByteAfter;
DWORD dwLocEntryLength; DWORD dwCardEntryLength;
DWORD dwIndex; DWORD dwAlignOffset; PLOCATIONLIST pLocTest;
lResult = IsThisAPIVersionInvalid( dwAPIVersion ); if ( lResult ) { LOG((TL_ERROR, "Bad dwAPIVersion - 0x%08lx", dwAPIVersion)); return lResult; }
if ( IsBadWritePtr(lpTranslateCaps, sizeof(DWORD)*3) ) { LOG((TL_ERROR, "lpTranslateCaps not a valid pointer")); return LINEERR_INVALPOINTER; }
if ( IsBadWritePtr(lpTranslateCaps, lpTranslateCaps->dwTotalSize) ) { LOG((TL_ERROR, "lpTranslateCaps not a valid pointer (dwTotalSize)")); return LINEERR_INVALPOINTER; }
LOG((TL_INFO, "lpTranslateCaps->dwTotalSize = %d",lpTranslateCaps->dwTotalSize));
if ( lpTranslateCaps->dwTotalSize < sizeof(LINETRANSLATECAPS)) { LOG((TL_ERROR, "Not even enough room for the fixed portion")); return LINEERR_STRUCTURETOOSMALL; }
// Let TAPISRV test the params for us
lResult = ReadLocations(&pLocTest, hLineApp, 0, dwAPIVersion, CHECKPARMS_DWHLINEAPP| CHECKPARMS_DWAPIVERSION| CHECKPARMS_ONLY);
if (pLocTest != NULL) { ClientFree( pLocTest); } if (lResult != ERROR_SUCCESS) { return lResult; }
// Read the location list
pLocationList = new CLocations(); if(pLocationList==NULL) { LOG((TL_ERROR, "Cannot allocate a CLocations object")); return LINEERR_NOMEM; }
lResult = pLocationList->Initialize(); if(lResult != ERROR_SUCCESS) { delete pLocationList; LOG((TL_ERROR, "CLocations.Initialize() failed - HRESULT=0x%08lx", lResult)); return lResult == E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_INIFILECORRUPT; }
// Read the calling card list
pCardList = new CCallingCards(); if(pCardList==NULL) { delete pLocationList; LOG((TL_ERROR, "Cannot allocate a CCallingCards object")); return LINEERR_NOMEM; }
lResult = pCardList->Initialize(); if(lResult != ERROR_SUCCESS) { delete pCardList; delete pLocationList; LOG((TL_ERROR, "CCallingCards.Initialize() failed - HRESULT=0x%08lx", lResult)); return lResult == E_OUTOFMEMORY ? LINEERR_NOMEM : LINEERR_OPERATIONFAILED; }
// The char length in bytes depends on bUnicode
dwLenChar = bUnicode ? sizeof(WCHAR) : sizeof(CHAR); // The structures for TAPI<=1.3 ar smaller
bOldTapi = (dwAPIVersion<0x00010004);
dwLocEntryLength = (DWORD)(bOldTapi ? 7*sizeof(DWORD) : sizeof(LINELOCATIONENTRY)); dwCardEntryLength = (DWORD)(bOldTapi ? 3*sizeof(DWORD) : sizeof(LINECARDENTRY));
dwNumLocations = pLocationList->GetNumLocations(); dwNumCards = pCardList->GetNumCards();
dwCurrentLocationID = pLocationList->GetCurrentLocationID(); dwPreferredCardID = 0; // Size provided by the caller
dwTotalSize = lpTranslateCaps->dwTotalSize; // First byte after the buffer provided by the caller
pFirstByteAfter = (PBYTE)lpTranslateCaps + dwTotalSize; bBufferTooSmall = FALSE;
dwLocationsStart = sizeof(LINETRANSLATECAPS); // The size of the locations part
dwLocationsSize = dwNumLocations * dwLocEntryLength; // The strings included in locations are stored after the array of LINELOCATIONENTRY structures
pCurrentIndex = ((PBYTE)lpTranslateCaps)+ dwLocationsStart + dwLocationsSize;
// do the first pointer alignment here. This initial offset will help at the end
pCurrentIndexSave = pCurrentIndex; pCurrentIndex = (PBYTE) (((ULONG_PTR)( pCurrentIndex + TALIGN_COUNT )) & (~TALIGN_COUNT)); dwAlignOffset = (DWORD)(pCurrentIndex - pCurrentIndexSave);
// Test the space for the array
if(pCurrentIndex > pFirstByteAfter) bBufferTooSmall = TRUE;
// First, process the locations
pLocationList->Reset(); dwIndex = 0; while(S_OK==pLocationList->Next(1, &pLocation, NULL)) { pLineLocationEntry = (LINELOCATIONENTRY *)(((PBYTE)lpTranslateCaps)+dwLocationsStart+dwIndex*dwLocEntryLength); // string values
LayDownString( pLocation->GetName(), (PBYTE)lpTranslateCaps, &pCurrentIndex, &pLineLocationEntry->dwLocationNameSize, bUnicode, pFirstByteAfter ); LayDownString( pLocation->GetAreaCode(), (PBYTE)lpTranslateCaps, &pCurrentIndex, &pLineLocationEntry->dwCityCodeSize, bUnicode, pFirstByteAfter );
if(!bOldTapi) { LayDownString( pLocation->GetLocalAccessCode(), (PBYTE)lpTranslateCaps, &pCurrentIndex, &pLineLocationEntry->dwLocalAccessCodeSize, bUnicode, pFirstByteAfter );
LayDownString( pLocation->GetLongDistanceAccessCode(), (PBYTE)lpTranslateCaps, &pCurrentIndex, &pLineLocationEntry->dwLongDistanceAccessCodeSize, bUnicode, pFirstByteAfter ); // Toll list
LayDownTollList(pLocation, (PBYTE)lpTranslateCaps, &pCurrentIndex, &pLineLocationEntry->dwTollPrefixListSize, bUnicode, pFirstByteAfter );
LayDownString( pLocation->GetDisableCallWaitingCode(), (PBYTE)lpTranslateCaps, &pCurrentIndex, &pLineLocationEntry->dwCancelCallWaitingSize, bUnicode, pFirstByteAfter );
}
if(pLocation->HasCallingCard()) { dwTempCardID = pLocation->GetPreferredCardID(); // Extract the preferred calling card if current location
if(pLocation->GetLocationID() == dwCurrentLocationID) dwPreferredCardID = dwTempCardID; } else dwTempCardID =0; //Other non string values
if(!bBufferTooSmall) { pLineLocationEntry->dwPermanentLocationID = pLocation->GetLocationID(); pLineLocationEntry->dwPreferredCardID = dwTempCardID;
pLineLocationEntry->dwCountryCode = pLocation->GetCountryCode();
if(!bOldTapi) { pLineLocationEntry->dwCountryID = pLocation->GetCountryID(); pLineLocationEntry->dwOptions = pLocation->HasToneDialing() ? 0 : LINELOCATIONOPTION_PULSEDIAL; } }
dwIndex++; }
// Align the pointer
pCurrentIndex = (PBYTE) (((ULONG_PTR)( pCurrentIndex + TALIGN_COUNT )) & (~TALIGN_COUNT));
// Process the cards
dwCardsStart = (DWORD)(pCurrentIndex - ((PBYTE)lpTranslateCaps)); // The size of the cards part
dwCardsSize = dwCardEntryLength * dwNumCards;
pCurrentIndex += dwCardsSize; // Test the space for the array
if(pCurrentIndex > pFirstByteAfter) bBufferTooSmall = TRUE;
// including the hidden cards
pCardList->Reset(TRUE); dwIndex = 0; while(S_OK==pCardList->Next(1, &pCard, NULL)) { PWSTR pszTemp = NULL; pLineCardEntry = (LINECARDENTRY *)(((PBYTE)lpTranslateCaps)+dwCardsStart+dwIndex*dwCardEntryLength); // String values
LayDownString( pCard->GetCardName(), (PBYTE)lpTranslateCaps, &pCurrentIndex, &pLineCardEntry->dwCardNameSize, bUnicode, pFirstByteAfter ); if(!bOldTapi) { // Convert rules to old format (w/o J and K spec)
pszTemp = CopyStringWithExpandJAndK(pCard->GetLocalRule(), pCard->GetLocalAccessNumber(), pCard->GetAccountNumber()); if(pszTemp==NULL) { delete pCardList; delete pLocationList; LOG((TL_ERROR, "CopyStringWithExpandJAndK failed to allocate memory")); return LINEERR_NOMEM; }
LayDownString( pszTemp, (PBYTE)lpTranslateCaps, &pCurrentIndex, &pLineCardEntry->dwSameAreaRuleSize, bUnicode, pFirstByteAfter );
ClientFree(pszTemp);
LOG((TL_INFO, "About to do CopyStringWithExpandJAndK")); pszTemp = CopyStringWithExpandJAndK( pCard->GetLongDistanceRule(), pCard->GetLongDistanceAccessNumber(), pCard->GetAccountNumber() ); LOG((TL_INFO, "Did CopyStringWithExpandJAndK"));
if(pszTemp==NULL) { delete pCardList; delete pLocationList; LOG((TL_ERROR, "CopyStringWithExpandJAndK failed to allocate memory")); return LINEERR_NOMEM; }
LayDownString( pszTemp, (PBYTE)lpTranslateCaps, &pCurrentIndex, &pLineCardEntry->dwLongDistanceRuleSize, bUnicode, pFirstByteAfter );
ClientFree(pszTemp); pszTemp = CopyStringWithExpandJAndK(pCard->GetInternationalRule(), pCard->GetInternationalAccessNumber(), pCard->GetAccountNumber()); if(pszTemp==NULL) { delete pCardList; delete pLocationList; LOG((TL_ERROR, "CopyStringWithExpandJAndK failed to allocate memory")); return LINEERR_NOMEM; }
LayDownString( pszTemp, (PBYTE)lpTranslateCaps, &pCurrentIndex, &pLineCardEntry->dwInternationalRuleSize, bUnicode, pFirstByteAfter ); ClientFree(pszTemp); }
// Other non-string fields
if(!bBufferTooSmall) { pLineCardEntry->dwPermanentCardID = pCard->GetCardID();
if(!bOldTapi) { pLineCardEntry->dwCardNumberDigits = wcslen(pCard->GetPIN()); pLineCardEntry->dwOptions = (pCard->IsMarkedPermanent() ? LINECARDOPTION_PREDEFINED : 0) | (pCard->IsMarkedHidden() ? LINECARDOPTION_HIDDEN : 0); }
}
dwIndex++; }
dwFinalSize = (DWORD)(pCurrentIndex - (PBYTE)lpTranslateCaps);
// Uhh, the goal is to have the same needed size whatever the alignment of the lpTranslateCaps is..
// A nongoal is to provide similar returned content (in terms of alignments, pads etc) for
// different alignment of lpTranslateCaps
//
dwFinalSize += (TALIGN_COUNT - dwAlignOffset);
if(dwFinalSize>dwTotalSize) { lpTranslateCaps->dwUsedSize = sizeof (LINETRANSLATECAPS); // Fix for alignment problems
lpTranslateCaps->dwNeededSize = dwFinalSize;
ZeroMemory( &lpTranslateCaps->dwNumLocations, dwTotalSize - 3 * sizeof (DWORD) ); lpTranslateCaps->dwCurrentLocationID = dwCurrentLocationID; lpTranslateCaps->dwCurrentPreferredCardID = dwPreferredCardID;
LOG((TL_ERROR, "Buffer too small")); LOG((TL_ERROR, "lpTranslateCaps->dwTotalSize = %d",lpTranslateCaps->dwTotalSize)); LOG((TL_ERROR, "lpTranslateCaps->dwNeededSize = %d",lpTranslateCaps->dwNeededSize));
} else { lpTranslateCaps->dwUsedSize = dwFinalSize; lpTranslateCaps->dwNeededSize = dwFinalSize;
lpTranslateCaps->dwNumLocations = dwNumLocations; lpTranslateCaps->dwNumCards = dwNumCards; lpTranslateCaps->dwCurrentLocationID = dwCurrentLocationID;
lpTranslateCaps->dwLocationListOffset = dwLocationsStart; lpTranslateCaps->dwLocationListSize = dwLocationsSize;
lpTranslateCaps->dwCardListOffset = dwCardsStart; lpTranslateCaps->dwCardListSize = dwCardsSize;
lpTranslateCaps->dwCurrentPreferredCardID = dwPreferredCardID;
LOG((TL_INFO, "Buffer OK")); LOG((TL_INFO, "lpTranslateCaps->dwTotalSize = %d",lpTranslateCaps->dwTotalSize)); LOG((TL_INFO, "lpTranslateCaps->dwNeededSize = %d",lpTranslateCaps->dwNeededSize)); }
delete pCardList; delete pLocationList;
return 0; }
static BOOL FindTollPrefixInLocation(CLocation *pLocation, PWSTR pPrefix, CAreaCodeRule **ppRule, PWSTR *ppWhere) { BOOL bPrefixFound = FALSE; AreaCodeRulePtrNode *pNode; CAreaCodeRule *pCrtRule = NULL; PWSTR pLocationAreaCode; PWSTR pWhere;
pLocationAreaCode = pLocation->GetAreaCode();
// Enumerate the area code rules
// If a rule is appropriate for a toll list, we search the prefix
pNode = pLocation->m_AreaCodeRuleList.head();
while( !pNode->beyond_tail() ) { pCrtRule = pNode->value();
if(IsATollListAreaCodeRule(pCrtRule, pLocationAreaCode)) { // Set this even we don't find the prefix.
// The caller could be interested in the presence of toll rules
*ppRule = pCrtRule; // Try to find the prefix
pWhere = FindPrefixInMultiSZ(pCrtRule->GetPrefixList(), pPrefix); if(pWhere) { *ppWhere = pWhere; return TRUE; }
} pNode = pNode->next(); }
return FALSE; }
static BOOL IsATollListAreaCodeRule(CAreaCodeRule *pRule, PWSTR pszLocationAreaCode) { // conditions for toll rules:
//
// location.Country code == 1 (to be tested outside) AND
// Area Code to dial == Current Area Code AND
// NumberToDial == 1 AND
// BeforeDialingDialNumberToDial == TRUE AND
// BeforeDialingDialAreaCode == TRUE AND
// IncludeAllPrefixesForThisAreaCode == FALSE
return pRule->HasDialNumber() && !pRule->HasAppliesToAllPrefixes() && pRule->HasDialAreaCode() && 0==wcscmp(pszLocationAreaCode, pRule->GetAreaCode()) && 0==wcscmp(pRule->GetNumberToDial(), L"1") ; }
static PWSTR FindPrefixInMultiSZ(PWSTR pPrefixList, PWSTR pPrefix) {
PWSTR pCrt; PWSTR pListCrt; PWSTR pStart;
pListCrt = pPrefixList;
while(TRUE) { pCrt = pPrefix; pStart = pListCrt;
while(*pCrt == *pListCrt) { if(!*pCrt) // found
return pStart;
pCrt++; pListCrt++; } while(*pListCrt++);
if(!*pListCrt) // not found
return NULL; }
}
/****************************************************************************
Function : CreateCurrentLocationObject
****************************************************************************/ LONG CreateCurrentLocationObject(CLocation **pLocation, HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, DWORD dwOptions) { 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 dwCount = 0; DWORD dwNumEntries = 0; DWORD dwCurrentLocationID = 0;
HRESULT hr;
// Let TAPISRV test the params for us
hr = ReadLocations(&pLocationList, hLineApp, dwDeviceID, dwAPIVersion, dwOptions );
if SUCCEEDED( hr) { hr = E_FAIL; // fail if we don't find the current loc
// current location
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;
// Find the current location
for (dwCount = 0; dwCount < dwNumEntries ; dwCount++) { if(pEntry->dwPermanentLocationID == dwCurrentLocationID) { hr = S_OK; break; }
// Try next location in list
//pEntry++;
pEntry = (PLOCATION) ((BYTE*)(pEntry) + pEntry->dwUsedSize);
} if SUCCEEDED( hr) { LOG((TL_INFO, "CreateCurrentLocationObject - current location found %d", dwCurrentLocationID));
// 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 ); if( SUCCEEDED(hr) ) { // Find position of 1st AREACODERULE structure in the LOCATIONLIST structure
pAreaCodeRuleEntry = (PAREACODERULE) ((BYTE*)(pEntry) + pEntry->dwAreaCodeRulesListOffset ); dwNumRules = pEntry->dwNumAreaCodeRules; for (dwCount = 0; dwCount != dwNumRules; dwCount++) { // 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, "CreateCurrentLocationObject - rule create failed")); } } else // new CAreaCodeRule failed
{ LOG((TL_ERROR, "CreateCurrentLocationObject - rule create failed")); } // Try next rule in list
pAreaCodeRuleEntry++; } } else // location initialize failed
{ delete pNewLocation; pNewLocation = NULL; LOG((TL_ERROR, "CreateCurrentLocationObject - location create failed")); hr =LINEERR_OPERATIONFAILED; // hr = E_FAIL;
} } else // new CLocation failed
{ LOG((TL_ERROR, "CreateCurrentLocationObject - location create failed")); hr = LINEERR_NOMEM; //hr = E_OUTOFMEMORY;
} } else { LOG((TL_ERROR, "CreateCurrentLocationObject - current location not found")); hr =LINEERR_OPERATIONFAILED; //hr = E_FAIL;
} } else // ReadLocations failed
{ LOG((TL_ERROR, "CreateCurrentLocationObject - ReadLocation create failed")); // hr = E_FAIL;
}
// finished with TAPI memory block so release
if ( pLocationList != NULL ) ClientFree( pLocationList );
*pLocation = pNewLocation; return hr; }
/****************************************************************************
Function : CreateCountryObject
****************************************************************************/
HRESULT CreateCountryObject(DWORD dwCountryID, CCountry **ppCountry) { 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, dwCountryID, 0); if (lResult == 0) { // Find position of 1st LINECOUNTRYENTRY structure in the LINECOUNTRYLIST structure
pEntry = (LPLINECOUNTRYENTRY_INTERNAL) ((BYTE*)(pCountryList) + pCountryList->dwCountryListOffset ); // 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) ) { *ppCountry = pCountry; } else // country initialization failed
{ delete pCountry; LOG((TL_ERROR, "CreateCountryObject - country create failed")); } } else // new CCountry failed
{ LOG((TL_ERROR, "CreateCountryObject - country create failed")); }
} else // ReadLocations failed
{ LOG((TL_ERROR, "CreateCountryObject - ReadCountries failed")); hr = E_FAIL; }
// finished with TAPI memory block so release
if ( pCountryList != NULL ) { ClientFree( pCountryList ); }
return hr;
}
/****************************************************************************
Function : ReadLocations
****************************************************************************/ HRESULT ReadLocations( PLOCATIONLIST *ppLocationList, HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, DWORD dwOptions ) { HRESULT hr = S_OK; long lResult; DWORD dwSize = sizeof(LOCATIONLIST) + 500;
*ppLocationList = (PLOCATIONLIST) ClientAlloc( dwSize );
if (NULL == *ppLocationList) { return E_OUTOFMEMORY; }
(*ppLocationList)->dwTotalSize = dwSize;
FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 5, tReadLocations),
{ (ULONG_PTR)hLineApp, (ULONG_PTR)dwDeviceID, (ULONG_PTR)dwAPIVersion, (ULONG_PTR)dwOptions, (ULONG_PTR)*ppLocationList // (DWORD) pLocationSpace
},
{ hXxxApp_NULLOK, Dword, Dword, Dword, lpGet_Struct } };
while (TRUE) { lResult = (DOFUNC (&funcArgs, "TReadLocations")); if ((lResult == 0) && ((*ppLocationList)->dwNeededSize > (*ppLocationList)->dwTotalSize)) { // Didn't Work , adjust buffer size & try again
LOG((TL_ERROR, "ReadLocations failed - buffer too small")); dwSize = (*ppLocationList)->dwNeededSize; ClientFree( *ppLocationList ); *ppLocationList = (PLOCATIONLIST) ClientAlloc( dwSize ); if (*ppLocationList == NULL) { LOG((TL_ERROR, "ReadLocations failed - repeat ClientAlloc failed")); hr = E_OUTOFMEMORY; break; } else { (*ppLocationList)->dwTotalSize = dwSize; funcArgs.Args[4] = (ULONG_PTR)*ppLocationList; } } else { hr = (HRESULT)lResult; break; } } // end while(TRUE)
return hr;
}
/****************************************************************************
Function : WriteLocations
****************************************************************************/ LONG PASCAL WriteLocations( PLOCATIONLIST pLocationList, DWORD dwChangedFlags ) { PSTR pString; UINT n; LONG lResult;
FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, tWriteLocations), { (ULONG_PTR)pLocationList->dwNumLocationsInList, (ULONG_PTR)dwChangedFlags, (ULONG_PTR)pLocationList->dwCurrentLocationID, (ULONG_PTR)pLocationList },
{ Dword, Dword, Dword, lpSet_Struct } };
lResult = (DOFUNC (&funcArgs, "TWriteLocations"));
return lResult; }
/****************************************************************************
Function : ReadCountries
****************************************************************************/ LONG PASCAL ReadCountries( LPLINECOUNTRYLIST *ppLCL, UINT nCountryID, DWORD dwDestCountryID ) { LONG lTapiResult; UINT nBufSize = 0x8000; //Start with a buffer of 16K
UINT n; LPLINECOUNTRYLIST pNewLCL;
FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lGetCountry),
{ 0, TAPI_VERSION_CURRENT, (ULONG_PTR)dwDestCountryID, 0 },
{ Dword, Dword, Dword, lpGet_Struct } };
//
// Try until success or the buffer is huge
//
for ( lTapiResult = 1, n = 0; lTapiResult && (n < 5); n++ ) {
pNewLCL = (LPLINECOUNTRYLIST)ClientAlloc( nBufSize );
if(!pNewLCL) return LINEERR_NOMEM;
pNewLCL->dwTotalSize = nBufSize;
//
// Put new values in structure for TAPISRV
//
funcArgs.Args[0] = (ULONG_PTR)nCountryID; funcArgs.Args[3] = (ULONG_PTR)pNewLCL;
//
// Call TAPISRV to get the country list
//
lTapiResult = DOFUNC (&funcArgs, "lineGetCountry");
//
// If the call succeeded, but the buffer was too small, or if the
// call failed, do it again...
//
if ( (lTapiResult == LINEERR_STRUCTURETOOSMALL) || (pNewLCL->dwNeededSize > nBufSize) ) { //
// Complain to anyone who'll listen that this should be tuned
// to start with a larger buffer so we don't have to do this multiple
// times....
//
LOG((TL_ERROR, " TUNING PROBLEM: We're about to call lineGetCountry()")); LOG((TL_ERROR, " _again_ because the buffer wasn't big enough")); LOG((TL_ERROR, " the last time. FIX THIS!!! (0x%lx)", nBufSize));
lTapiResult = 1; // Force error condition if size was bad...
nBufSize += 0x4000; // Try a bit bigger
ClientFree( pNewLCL ); } else { //
// We didn't work for some other reason
//
break; } }
*ppLCL = pNewLCL;
return lTapiResult; }
/****************************************************************************
Function : ReadCountriesAndGroups
****************************************************************************/ LONG PASCAL ReadCountriesAndGroups( LPLINECOUNTRYLIST_INTERNAL *ppLCL, UINT nCountryID, DWORD dwDestCountryID ) { LPLINECOUNTRYLIST_INTERNAL pLCL = NULL; LPLINECOUNTRYENTRY_INTERNAL pLCountry; LONG lResult; LPDWORD pCountryIDs; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lGetCountryGroup), { (ULONG_PTR) 0, (ULONG_PTR) 0, (ULONG_PTR) 0, (ULONG_PTR) 0 },
{ lpSet_SizeToFollow, Size, lpGet_SizeToFollow, Size } };
//
// read the countries
//
lResult = ReadCountries( (LPLINECOUNTRYLIST *)&pLCL, nCountryID, dwDestCountryID ); if (lResult) { LOG((TL_ERROR, "ReadCountriesAndGroups: ReadCountries failed with %d", lResult)); return lResult;
} //
// create the array of country IDs
//
pCountryIDs = (LPDWORD)ClientAlloc( sizeof(DWORD) * pLCL->dwNumCountries ); if(!pCountryIDs) { ClientFree( pLCL ); return LINEERR_NOMEM; } pLCountry = (LPLINECOUNTRYENTRY_INTERNAL) ((LPBYTE)pLCL + pLCL->dwCountryListOffset); for( DWORD dwIdx = 0; dwIdx < pLCL->dwNumCountries; dwIdx++, pLCountry++ ) { *(pCountryIDs + dwIdx) = pLCountry->dwCountryID; } funcArgs.Args[0] = funcArgs.Args[2] = (ULONG_PTR)pCountryIDs; funcArgs.Args[1] = funcArgs.Args[3] = (ULONG_PTR)(sizeof(DWORD) * pLCL->dwNumCountries);
//
// Call TAPISRV to get the country groups
// At return pCountryIDs will have the country groups
//
lResult = DOFUNC (&funcArgs, "lineGetCountryGroups");
if (lResult) { LOG((TL_TRACE, "ReadCountriesAndGroups: lineGetCountryGroups failed with %d", lResult)); //
// consider all the country groups undefined (0)
//
memset( pCountryIDs, 0, sizeof(DWORD) * pLCL->dwNumCountries );
lResult = ERROR_SUCCESS; } pLCountry = (LPLINECOUNTRYENTRY_INTERNAL) ((LPBYTE)pLCL + pLCL->dwCountryListOffset); for( DWORD dwIdx = 0; dwIdx < pLCL->dwNumCountries; dwIdx++, pLCountry++ ) { pLCountry->dwCountryGroup = *(pCountryIDs + dwIdx); }
*ppLCL = pLCL; ClientFree( pCountryIDs ); return lResult; }
//***************************************************************************
// Returns LONG_DISTANCE_CARRIER_MANDATORY if rule contains an 'L' or 'l'
// (ie long distance carrier code - mandatory),
// Returns LONG_DISTANCE_CARRIER_OPTIONAL if rule contains an 'N' or 'n'
// (ie long distance carrier code - optional),
// Returns LONG_DISTANCE_CARRIER_NONE if rule contains neither
//
int IsLongDistanceCarrierCodeRule(LPWSTR lpRule) { WCHAR c;
while ((c = *lpRule++) != '\0') { if (c == 'L' || c == 'l') return LONG_DISTANCE_CARRIER_MANDATORY; if (c == 'N' || c == 'n') return LONG_DISTANCE_CARRIER_OPTIONAL; } return LONG_DISTANCE_CARRIER_NONE; }
//***************************************************************************
// Returns INTERNATIONAL_CARRIER_MANDATORY if rule contains an 'M' or 'm'
// (ie international carrier code - mandatory),
// Returns INTERNATIONAL_CARRIER_OPTIONAL if rule contains an 'S' or 's'
// (ie international carrier code - optional),
// Returns INTERNATIONAL_CARRIER_NONE if rule contains neither
//
int IsInternationalCarrierCodeRule(LPWSTR lpRule) { WCHAR c;
while ((c = *lpRule++) != '\0') { if (c == 'M' || c == 'm') return INTERNATIONAL_CARRIER_MANDATORY; if (c == 'S' || c == 's') return INTERNATIONAL_CARRIER_OPTIONAL; } return INTERNATIONAL_CARRIER_NONE; }
//***************************************************************************
//***************************************************************************
//***************************************************************************
// Returns CITY_MANDATORY if rule contains an F (ie city code mandatory),
// Returns CITY_OPTIONAL if rule contains an I (ie city code optional)
// Returns CITY_NONE if rule contains neither
//
int IsCityRule(LPWSTR lpRule) { WCHAR c;
while ((c = *lpRule++) != '\0') { if (c == 'F') return CITY_MANDATORY; if (c == 'I') return CITY_OPTIONAL; } return CITY_NONE; }
// Initializes/uninitializes the defined node pools based on the templates from list.h
//
void ListNodePoolsInitialize(void) { NodePool<CCallingCard *>::initialize(); NodePool<CCountry *>::initialize(); NodePool<CLocation *>::initialize(); NodePool<CAreaCodeRule*>::initialize(); }
void ListNodePoolsUninitialize(void) { NodePool<CCallingCard *>::uninitialize(); NodePool<CCountry *>::uninitialize(); NodePool<CLocation *>::uninitialize(); NodePool<CAreaCodeRule*>::uninitialize(); }
|