3601 lines
101 KiB
C++
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();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|