|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
tapiutil.c
Abstract:
Utility functions for working with TAPI
Environment:
Windows fax driver user interface
Revision History:
09/18/96 -davidx- Created it.
22/07/99 -v-sashab- Replaced a direct access to TAPI by Server calls
mm/dd/yy -author- description
--*/
#include "faxui.h"
#include "tapiutil.h"
#define STRSAFE_NO_DEPRECATE
#include <strsafe.h>
#define UNKNOWN_DIALING_LOCATION (0xffffffff)
static HLINEAPP g_hLineApp = 0; static DWORD g_dwTapiVersion = 0x00020000; static DWORD g_dwDefaultDialingLocation = UNKNOWN_DIALING_LOCATION;
BOOL CurrentLocationUsesCallingCard ();
VOID CALLBACK TapiLineCallback( DWORD hDevice, DWORD dwMessage, ULONG_PTR dwInstance, ULONG_PTR dwParam1, ULONG_PTR dwParam2, ULONG_PTR dwParam3 )
/*++
Routine Description:
TAPI line callback function: Even though we don't actually have anything to do here, we must provide a callback function to keep TAPI happy.
Arguments:
hDevice - Line or call handle dwMessage - Reason for the callback dwInstance - LINE_INFO index dwParam1 - Callback parameter #1 dwParam2 - Callback parameter #2 dwParam3 - Callback parameter #3
Return Value:
NONE
--*/
{ }
BOOL InitTapi () {
//
// TAPI does not work properly on Win95
// and does not relevant for remote fax connection
//
#ifdef UNICODE
DWORD nLineDevs; LONG status; LINEINITIALIZEEXPARAMS lineInitParams;
Assert (!g_hLineApp); if (g_hLineApp) { return TRUE; }
ZeroMemory(&lineInitParams, sizeof(lineInitParams)); lineInitParams.dwTotalSize = lineInitParams.dwNeededSize = lineInitParams.dwUsedSize = sizeof(lineInitParams);
status = lineInitializeEx (&g_hLineApp, g_hModule, TapiLineCallback, TEXT("Fax Send Wizard"), &nLineDevs, &g_dwTapiVersion, &lineInitParams);
if (NO_ERROR != status) { Error(("lineInitializeEx failed: %x\n", status)); g_hLineApp = 0; return FALSE; } #endif // UNICODE
return TRUE; }
void ShutdownTapi () { if (!g_hLineApp) { return; } //
// Restore the last dialing location the user selected
//
if (UNKNOWN_DIALING_LOCATION != g_dwDefaultDialingLocation) { SetCurrentLocation (g_dwDefaultDialingLocation); } lineShutdown (g_hLineApp); g_hLineApp = 0; } // ShutdownTapi
DWORD GetDefaultCountryID( VOID )
/*++
Routine Description:
Return the default country ID for the current location
Arguments:
NONE
Return Value:
The current ID for the current location
--*/
{ //
// We assume the correct information has already been saved to the
// registry during the installation process.
//
return 0; }
PFAX_TAPI_LINECOUNTRY_ENTRY FindCountry( PFAX_TAPI_LINECOUNTRY_LIST pCountryList, DWORD countryId )
/*++
Routine Description:
Find the specified country from a list of all countries and return a pointer to the corresponding FAX_TAPI_LINECOUNTRY_ENTRY structure
Arguments:
pCountryList - pointer to the country list countryId - Specifies the country ID we're interested in
Return Value:
Pointer to a FAX_TAPI_LINECOUNTRY_ENTRY structure corresponding to the specified country ID NULL if there is an error
--*/
{ DWORD dwIndex;
if (pCountryList == NULL || countryId == 0) return NULL;
//
// Look at each FAX_TAPI_LINECOUNTRY_ENTRY structure and compare its country ID with
// the specified country ID
//
for (dwIndex=0; dwIndex < pCountryList->dwNumCountries; dwIndex++) {
if (pCountryList->LineCountryEntries[dwIndex].dwCountryID == countryId) return &pCountryList->LineCountryEntries[dwIndex]; }
return NULL; }
DWORD GetCountryIdFromCountryCode( PFAX_TAPI_LINECOUNTRY_LIST pCountryList, DWORD dwCountryCode )
/*++
Routine Description:
Arguments:
pCountryList - pointer to the country list dwCountryCode - Specifies the country code we're interested in
Return Value:
Country ID --*/
{ DWORD dwIndex;
if (pCountryList == NULL || dwCountryCode == 0) return 0;
//
// Look at each FAX_TAPI_LINECOUNTRY_ENTRY structure and compare its country ID with
// the specified country ID
//
for (dwIndex=0; dwIndex < pCountryList->dwNumCountries; dwIndex++) {
if (pCountryList->LineCountryEntries[dwIndex].dwCountryCode == dwCountryCode) return pCountryList->LineCountryEntries[dwIndex].dwCountryID; }
return 0; }
INT AreaCodeRules( PFAX_TAPI_LINECOUNTRY_ENTRY pEntry )
/*++
Routine Description:
Given a FAX_TAPI_LINECOUNTRY_ENTRY structure, determine if area code is needed in that country
Arguments:
pEntry - Points to a FAX_TAPI_LINECOUNTRY_ENTRY structure
Return Value:
AREACODE_DONTNEED - Area code is not used in the specified country AREACODE_OPTIONAL - Area code is optional in the specified country AREACODE_REQUIRED - Area code is required in the specified country
--*/
{ if ((pEntry != NULL) && (pEntry->lpctstrLongDistanceRule != 0)) {
//
// Area code is required in this country
//
if (_tcschr(pEntry->lpctstrLongDistanceRule, TEXT('F')) != NULL) return AREACODE_REQUIRED;
//
// Area code is not needed in this country
//
if (_tcschr(pEntry->lpctstrLongDistanceRule, TEXT('I')) == NULL) return AREACODE_DONTNEED; }
//
// Default case: area code is optional in this country
//
return AREACODE_OPTIONAL; }
VOID AssemblePhoneNumber( OUT LPTSTR pAddress, IN UINT cchAddress, IN DWORD countryCode, IN LPTSTR pAreaCode, IN LPTSTR pPhoneNumber )
/*++
Routine Description:
Assemble a canonical phone number given the following: country code, area code, and phone number
Arguments:
pAddress - Specifies a buffer to hold the resulting fax address cchAddress - The size of the pAddress OUT buffer in TCHARs countryCode - Specifies the country code pAreaCode - Specifies the area code string pPhoneNumber - Specifies the phone number string
Return Value:
NONE
--*/
{ //
// Country code if neccessary
//
HRESULT hRc;
if (countryCode != 0) { hRc = StringCchPrintf(pAddress, cchAddress, TEXT("+%d "), countryCode); if(FAILED(hRc)) { Assert(0); return; } }
//
// Area code if necessary
//
if (pAreaCode && !IsEmptyString(pAreaCode)) {
if (countryCode != 0) { hRc = StringCchCat(pAddress, cchAddress, TEXT("(") ); if(FAILED(hRc)) { Assert(0); return; } }
hRc = StringCchCat(pAddress, cchAddress, pAreaCode); if(FAILED(hRc)) { Assert(0); return; }
if (countryCode != 0) { hRc = StringCchCat(pAddress, cchAddress, TEXT(")")); if(FAILED(hRc)) { Assert(0); return; } }
hRc = StringCchCat(pAddress, cchAddress, TEXT(" ")); if(FAILED(hRc)) { Assert(0); return; } }
//
// Phone number at last
//
Assert(pPhoneNumber != NULL);
hRc = StringCchCat(pAddress, cchAddress, pPhoneNumber); if(FAILED(hRc)) { Assert(0); } }
VOID UpdateAreaCodeField( HWND hwndAreaCode, PFAX_TAPI_LINECOUNTRY_LIST pCountryList, DWORD countryId )
/*++
Routine Description:
Update any area code text field associated with a country list box
Arguments:
hwndAreaCode - Specifies the text field associated with the country list box pCountryList - pointer to the country list countryId - Currently selected country ID
Return Value:
NONE
--*/
{ if (hwndAreaCode == NULL) return;
if (AreaCodeRules(FindCountry(pCountryList,countryId)) == AREACODE_DONTNEED) {
SendMessage(hwndAreaCode, WM_SETTEXT, 0, (LPARAM) TEXT("")); EnableWindow(hwndAreaCode, FALSE);
} else EnableWindow(hwndAreaCode, TRUE); }
DWORD GetLocalCountryCode() /*++
Routine Description:
Retrieve local country code
Arguments:
None
Return Value:
Local country code if success NULL if failed
--*/ { HMODULE hTapi = NULL; TCHAR tszLocalCountryCode[16] = {0}; TCHAR tszLocalCityCode[16] = {0}; DWORD dwCountryCode = 0;
typedef LONG (WINAPI *TAPI_GET_LOCATION_INFO)(LPTSTR, LPTSTR); TAPI_GET_LOCATION_INFO pfnTapiGetLocationInfo;
hTapi = LoadLibrary(TEXT("tapi32.dll")); if(!hTapi) { Error(("LoadLibrary(tapi32.dll) failed. ec = 0x%X\n",GetLastError())); return dwCountryCode; }
#ifdef UNICODE
pfnTapiGetLocationInfo = (TAPI_GET_LOCATION_INFO)GetProcAddress(hTapi, "tapiGetLocationInfoW"); #else
pfnTapiGetLocationInfo = (TAPI_GET_LOCATION_INFO)GetProcAddress(hTapi, "tapiGetLocationInfoA"); if(!pfnTapiGetLocationInfo) { pfnTapiGetLocationInfo = (TAPI_GET_LOCATION_INFO)GetProcAddress(hTapi, "tapiGetLocationInfo"); } #endif
if(pfnTapiGetLocationInfo) { if(0 == pfnTapiGetLocationInfo(tszLocalCountryCode, tszLocalCityCode)) { if (1 != _stscanf(tszLocalCountryCode, TEXT("%u"), &dwCountryCode)) { Error(("_stscanf failed.")); dwCountryCode = 0; } } } else { Error(("tapiGetLocationInfo failed. ec = 0x%X\n",GetLastError())); }
FreeLibrary(hTapi);
return dwCountryCode;
} // GetLocalCountryCode
VOID InitCountryListBox( PFAX_TAPI_LINECOUNTRY_LIST pCountryList, HWND hwndList, HWND hwndAreaCode, LPTSTR lptstrCountry, DWORD countryId, BOOL bAddCountryCode )
/*++
Routine Description:
Initialize the country list box
Arguments:
pCountryList - pointer to the country list hwndList - Handle to the country list box window hwndAreaCode - Handle to an associated area code text field lptstrCountry - Country that should be selected or NULL countryId - Initially selected country ID bAddCountryCode - if TRUE add a country code to a country name
Return Value:
NONE
--*/
#define MAX_COUNTRY_NAME 256
{ DWORD dwIndex; TCHAR buffer[MAX_COUNTRY_NAME]={0};
if(0 == countryId) { //
// if no country selected, select the local
//
countryId = GetLocalCountryCode(); if(0 == countryId) { //
// The default location is not configured.
//
DoTapiProps(hwndList); countryId = GetLocalCountryCode(); } }
//
// Disable redraw on the list box and reset its content
//
SendMessage(hwndList, WM_SETREDRAW, FALSE, 0); SendMessage(hwndList, CB_RESETCONTENT, FALSE, 0);
//
// Loop through FAX_TAPI_LINECOUNTRY_ENTRY structures and add the available selections to
// the country list box.
//
if (pCountryList) { TCHAR szFormat[64] = { TEXT("%s (%d)") }; #ifdef UNICODE
if(pCountryList->dwNumCountries && IsWindowRTL(hwndList) && !StrHasRTLChar(LOCALE_SYSTEM_DEFAULT, pCountryList->LineCountryEntries[0].lpctstrCountryName)) { //
// The Combo Box has RTL layout
// but the country name has not RTL characters.
// So, we add LEFT-TO-RIGHT OVERRIDE UNICODE character.
//
_tcscpy(szFormat, TEXT("\x202D%s (%d)")); } #endif
for (dwIndex=0; dwIndex < pCountryList->dwNumCountries; dwIndex++) { if (pCountryList->LineCountryEntries[dwIndex].lpctstrCountryName) { if(bAddCountryCode) { _sntprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, szFormat, pCountryList->LineCountryEntries[dwIndex].lpctstrCountryName, pCountryList->LineCountryEntries[dwIndex].dwCountryCode); } else { _tcsncpy(buffer, pCountryList->LineCountryEntries[dwIndex].lpctstrCountryName, sizeof(buffer)/sizeof(buffer[0]) - 1); }
if (lptstrCountry && _tcsstr(buffer,lptstrCountry) && !countryId) { // search for a first occurence of lptstrCountry
countryId = pCountryList->LineCountryEntries[dwIndex].dwCountryID; }
SendMessage(hwndList, CB_SETITEMDATA, SendMessage(hwndList, CB_ADDSTRING, 0, (LPARAM) buffer), pCountryList->LineCountryEntries[dwIndex].dwCountryID); } } } //
// Figure out which item in the list should be selected
//
if (pCountryList != NULL) { for (dwIndex=0; dwIndex <= pCountryList->dwNumCountries; dwIndex++) { if ((DWORD) SendMessage(hwndList, CB_GETITEMDATA, dwIndex, 0) == countryId) break; }
if (dwIndex > pCountryList->dwNumCountries) { dwIndex = countryId = 0; } } else { dwIndex = countryId = 0; } SendMessage(hwndList, CB_SETCURSEL, dwIndex, 0); SendMessage(hwndList, WM_SETREDRAW, TRUE, 0); //
// Update the associated area code text field
//
UpdateAreaCodeField(hwndAreaCode, pCountryList, countryId); }
VOID SelChangeCountryListBox( HWND hwndList, HWND hwndAreaCode, PFAX_TAPI_LINECOUNTRY_LIST pCountryList )
/*++
Routine Description:
Handle dialog selection changes in the country list box
Arguments:
hwndList - Handle to the country list box window hwndAreaCode - Handle to an associated area code text field pCountryList - pointer to the country list
Return Value:
NONE
--*/
{ UpdateAreaCodeField(hwndAreaCode, pCountryList, GetCountryListBoxSel(hwndList)); }
DWORD GetCountryListBoxSel( HWND hwndList )
/*++
Routine Description:
Return the current selection of country list box
Arguments:
hwndList - Handle to the country list box window
Return Value:
Currently selected country ID
--*/
{ INT msgResult;
if ((msgResult = (INT)SendMessage(hwndList, CB_GETCURSEL, 0, 0)) == CB_ERR || (msgResult = (INT)SendMessage(hwndList, CB_GETITEMDATA, msgResult, 0)) == CB_ERR) { return 0; }
return msgResult; }
BOOL DoTapiProps( HWND hDlg ) {
DWORD dwRes;
dwRes = lineTranslateDialog(g_hLineApp, 0, // Device ID
g_dwTapiVersion, hDlg, NULL); // Address
if(0 != dwRes) { Error(("lineTranslateDialog failed. ec = 0x%X\n", dwRes)); return FALSE; }
return TRUE; } // DoTapiProps
LPLINETRANSLATECAPS GetTapiLocationInfo( HWND hWnd ) /*++
Routine Description:
Get a list of locations from TAPI
Arguments:
NONE
Return Value:
Pointer to a LINETRANSLATECAPS structure, NULL if there is an error
--*/
#define INITIAL_LINETRANSLATECAPS_SIZE 5000
{
LPLINETRANSLATECAPS pTranslateCaps = NULL;
//
// TAPI does not work properly on Win95
// and does not relevant for remote fax connection
//
#ifdef UNICODE
DWORD cbNeeded = INITIAL_LINETRANSLATECAPS_SIZE; LONG status; INT i;
if (!g_hLineApp) { return NULL; }
for (i = 0; i < 2; i++) { //
// Free any existing buffer and allocate a new one with larger size
//
MemFree(pTranslateCaps);
if (! (pTranslateCaps = MemAlloc(cbNeeded))) { Error(("Memory allocation failed\n")); return NULL; } //
// Get the LINETRANSLATECAPS structure from TAPI
//
pTranslateCaps->dwTotalSize = cbNeeded; status = lineGetTranslateCaps(g_hLineApp, g_dwTapiVersion, pTranslateCaps); //
// Try to bring up UI if there are no locations.
//
if (LINEERR_INIFILECORRUPT == status) { if (lineTranslateDialog( g_hLineApp, 0, g_dwTapiVersion, hWnd, NULL )) { MemFree(pTranslateCaps); return NULL; } continue; } if ((pTranslateCaps->dwNeededSize > pTranslateCaps->dwTotalSize) || (LINEERR_STRUCTURETOOSMALL == status) || (LINEERR_NOMEM == status)) { //
// Retry since our initial estimated buffer size was too small
//
if (cbNeeded >= pTranslateCaps->dwNeededSize) { cbNeeded = cbNeeded * 5; } else { cbNeeded = pTranslateCaps->dwNeededSize; } Warning(("LINETRANSLATECAPS resized to: %d\n", cbNeeded)); } else { //
// Either success of real error - break now and let the code after the loop handle it.
//
break; } }
if (NO_ERROR != status) { Error(("lineGetTranslateCaps failed: %x\n", status)); MemFree(pTranslateCaps); SetLastError (status); pTranslateCaps = NULL; } if (pTranslateCaps) { //
// Update the current default dialing location.
// We save it here and restore it when the wizard exists in ShutdownTapi().
//
g_dwDefaultDialingLocation = pTranslateCaps->dwCurrentLocationID; }
#endif // UNICODE
return pTranslateCaps; } // GetTapiLocationInfo
BOOL SetCurrentLocation( DWORD locationID )
/*++
Routine Description:
Change the default TAPI location
Arguments:
locationID - The permanant ID for the new default TAPI location
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ LONG lResult;
Assert (g_hLineApp); if (!g_hLineApp) { SetLastError (ERROR_GEN_FAILURE); return FALSE; }
lResult = lineSetCurrentLocation(g_hLineApp, locationID); if (NO_ERROR == lResult) { Verbose(("Current location changed: ID = %d\n", locationID)); return TRUE; } else { Error(("Couldn't change current TAPI location\n")); SetLastError (lResult); return FALSE; } } // SetCurrentLocation
BOOL TranslateAddress ( LPCTSTR lpctstrCanonicalAddress, DWORD dwLocationId, LPTSTR *lpptstrDialableAndDisplayableAddress ) /*++
Routine name : TranslateAddress
Routine description:
Translates a canonical address
Author:
Eran Yariv (EranY), Feb, 2001
Arguments:
lpctstrCanonicalAddress [in] - Canonical address string dwLocationId [in] - Location id to use lpptstrDialableAndDisplayableAddress [out] - Allocated string holding a combination of translated dialable and displayable addresses
Return Value:
TRUE if successful, FALSE otherwise (sets last error0.
--*/ {
//
// TAPI does not work properly on Win95
// and does not relevant for remote fax connection
//
#ifdef UNICODE
DWORD dwLineTransOutSize = sizeof(LINETRANSLATEOUTPUT) + 4096; LPLINETRANSLATEOUTPUT lpTranslateOutput = NULL; LONG lRslt = ERROR_SUCCESS; DWORD dwRes; LPTSTR lptstrTranslatedDialableString; LPTSTR lptstrTranslatedDisplayableString; DWORD dwTranslatedStringsSize; BOOL bCanonicCheck;
dwRes = IsCanonicalAddress(lpctstrCanonicalAddress, &bCanonicCheck, NULL, NULL, NULL); if (ERROR_SUCCESS != dwRes) { SetLastError (dwRes); return FALSE; } Assert (bCanonicCheck); if (!bCanonicCheck) { SetLastError (ERROR_GEN_FAILURE); return FALSE; }
Assert (g_hLineApp); if (!g_hLineApp) { SetLastError (ERROR_GEN_FAILURE); return FALSE; }
if (!SetCurrentLocation(dwLocationId)) { return FALSE; }
lpTranslateOutput = MemAlloc (dwLineTransOutSize); if (!lpTranslateOutput) { Error(("Couldn't allocate translation results buffer\n")); return FALSE; } lpTranslateOutput->dwTotalSize = dwLineTransOutSize; lRslt = lineTranslateAddress( g_hLineApp, 0, g_dwTapiVersion, lpctstrCanonicalAddress, 0, LINETRANSLATEOPTION_CANCELCALLWAITING, lpTranslateOutput ); if ((lpTranslateOutput->dwNeededSize > lpTranslateOutput->dwTotalSize) || (LINEERR_STRUCTURETOOSMALL == lRslt) || (LINEERR_NOMEM == lRslt)) { //
// Retry since our initial estimated buffer size was too small
//
if (dwLineTransOutSize >= lpTranslateOutput->dwNeededSize) { dwLineTransOutSize = dwLineTransOutSize * 5; } else { dwLineTransOutSize = lpTranslateOutput->dwNeededSize; } //
// Re-allocate the LineTransCaps structure
//
dwLineTransOutSize = lpTranslateOutput->dwNeededSize;
MemFree(lpTranslateOutput);
lpTranslateOutput = (LPLINETRANSLATEOUTPUT) MemAlloc(dwLineTransOutSize); if (!dwLineTransOutSize) { Error(("Couldn't allocate translation results buffer\n")); return FALSE; }
lpTranslateOutput->dwTotalSize = dwLineTransOutSize;
lRslt = lineTranslateAddress( g_hLineApp, 0, g_dwTapiVersion, lpctstrCanonicalAddress, 0, LINETRANSLATEOPTION_CANCELCALLWAITING, lpTranslateOutput ); } if (ERROR_SUCCESS != lRslt) { //
// Other error
//
Error(("lineGetTranslateAddress() failed, ec=0x%08x\n", lRslt)); MemFree (lpTranslateOutput); SetLastError (lRslt); return FALSE; } //
// We now hold the valid translated address in lpTranslateOutput
//
//
// Calc required buffer size to hold combined strings.
//
if (CurrentLocationUsesCallingCard ()) { //
// Calling card is used.
// TAPI returns credit card numbers in the displayable string.
// return the input canonical number as the displayable string.
//
lptstrTranslatedDisplayableString = (LPTSTR)lpctstrCanonicalAddress; } else { //
// Calling card isn't used - use displayable string as is.
//
Assert (lpTranslateOutput->dwDisplayableStringSize > 0); lptstrTranslatedDisplayableString = (LPTSTR)((LPBYTE)lpTranslateOutput + lpTranslateOutput->dwDisplayableStringOffset); }
dwTranslatedStringsSize = _tcslen (lptstrTranslatedDisplayableString); Assert (lpTranslateOutput->dwDialableStringSize > 0); lptstrTranslatedDialableString = (LPTSTR)((LPBYTE)lpTranslateOutput + lpTranslateOutput->dwDialableStringOffset); dwTranslatedStringsSize += _tcslen (lptstrTranslatedDialableString); //
// Add NULL + Formatting extra length
//
dwTranslatedStringsSize += COMBINED_TRANSLATED_STRING_EXTRA_LEN + 1; //
// Allocate return buffer
//
*lpptstrDialableAndDisplayableAddress = (LPTSTR)MemAlloc (dwTranslatedStringsSize * sizeof (TCHAR)); if (!*lpptstrDialableAndDisplayableAddress) { MemFree (lpTranslateOutput); Error(("Couldn't allocate translation results buffer\n")); return FALSE; } _stprintf (*lpptstrDialableAndDisplayableAddress, COMBINED_TRANSLATED_STRING_FORMAT, lptstrTranslatedDialableString, lptstrTranslatedDisplayableString); MemFree (lpTranslateOutput); return TRUE;
#endif // UNICODE
return FALSE;
} // TranslateAddress
BOOL CurrentLocationUsesCallingCard () { LPLINETRANSLATECAPS pTranslateCaps = GetTapiLocationInfo (NULL); DWORD dwIndex; BOOL bRes = TRUE; LPLINELOCATIONENTRY pLocationEntry = NULL;
if (!pTranslateCaps) { return TRUE; }
//
// Find current location
//
pLocationEntry = (LPLINELOCATIONENTRY) ((PBYTE) pTranslateCaps + pTranslateCaps->dwLocationListOffset); for (dwIndex = 0; dwIndex < pTranslateCaps->dwNumLocations; dwIndex++) { if (pLocationEntry->dwPermanentLocationID == pTranslateCaps->dwCurrentLocationID) { //
// We found the current calling location
// Let's see if it uses calling cards.
//
if (pLocationEntry->dwPreferredCardID) { bRes = TRUE; goto exit; } else { //
// Not using calling card
//
bRes = FALSE; goto exit; } } pLocationEntry++; } exit: MemFree (pTranslateCaps); return bRes; } // CurrentLocationUsesCallingCard
|