windows-nt/Source/XPSP1/NT/net/tapi/client/dial.cpp
2020-09-26 16:20:57 +08:00

3601 lines
101 KiB
C++

/****************************************************************************
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();
}