/**************************************************************************** Copyright (c) 1995-1999 Microsoft Corporation Module Name: dial.cpp ****************************************************************************/ #include #include #if WINNT #else #include #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 #include // 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; dwIndexGetPrefixList(); 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; dwIndexnext(); } } // 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::initialize(); NodePool::initialize(); NodePool::initialize(); NodePool::initialize(); } void ListNodePoolsUninitialize(void) { NodePool::uninitialize(); NodePool::uninitialize(); NodePool::uninitialize(); NodePool::uninitialize(); }