737 lines
14 KiB
C
737 lines
14 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
tapiutil.c
|
||
|
||
Abstract:
|
||
|
||
Functions for working with TAPI
|
||
|
||
Environment:
|
||
|
||
Fax configuration applet
|
||
|
||
Revision History:
|
||
|
||
03/16/96 -davidx-
|
||
Created it.
|
||
|
||
mm/dd/yy -author-
|
||
description
|
||
|
||
NOTE:
|
||
|
||
We are calling W-version of TAPI APIs explicitly here because
|
||
tapi.h doesn't properly expand them to A- or W-version.
|
||
|
||
--*/
|
||
|
||
#include "faxcpl.h"
|
||
#include <tapi.h>
|
||
|
||
|
||
//
|
||
// Global variables used for accessing TAPI services
|
||
//
|
||
|
||
static HLINEAPP tapiLineApp = NULL;
|
||
static DWORD tapiVersion = TAPI_CURRENT_VERSION;
|
||
static LPLINECOUNTRYLIST pLineCountryList = NULL;
|
||
|
||
|
||
|
||
BOOL
|
||
GetCountries(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Return a list of countries from TAPI
|
||
|
||
Arguments:
|
||
|
||
NONE
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE if there is an error
|
||
|
||
NOTE:
|
||
|
||
We cache the result of lineGetCountry here since it's incredibly slow.
|
||
This function must be invoked inside a critical section since it updates
|
||
globally shared information.
|
||
|
||
--*/
|
||
|
||
#define INITIAL_SIZE_ALL_COUNTRY 22000 // Initial buffer size
|
||
|
||
{
|
||
DWORD cbNeeded = INITIAL_SIZE_ALL_COUNTRY;
|
||
INT repeatCnt = 0;
|
||
LONG status;
|
||
|
||
if (pLineCountryList == NULL) {
|
||
|
||
while (TRUE) {
|
||
|
||
//
|
||
// Free existing buffer and allocate a new buffer of required size
|
||
//
|
||
|
||
MemFree(pLineCountryList);
|
||
|
||
if (! (pLineCountryList = MemAlloc(cbNeeded))) {
|
||
|
||
Error(("Memory allocation failed\n"));
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Call TAPI to get the list of countries
|
||
//
|
||
|
||
pLineCountryList->dwTotalSize = cbNeeded;
|
||
status = lineGetCountry(0, tapiVersion, pLineCountryList);
|
||
|
||
//
|
||
// Retries with a larger buffer size if our initial estimate was too small
|
||
//
|
||
|
||
if ((pLineCountryList->dwNeededSize > pLineCountryList->dwTotalSize) &&
|
||
(status == NO_ERROR ||
|
||
status == LINEERR_STRUCTURETOOSMALL ||
|
||
status == LINEERR_NOMEM) &&
|
||
(repeatCnt++ == 0))
|
||
{
|
||
cbNeeded = pLineCountryList->dwNeededSize + 1;
|
||
Warning(("LINECOUNTRYLIST size: %d\n", cbNeeded));
|
||
continue;
|
||
}
|
||
|
||
if (status != NO_ERROR) {
|
||
|
||
Error(("lineGetCountry failed: %x\n", status));
|
||
MemFree(pLineCountryList);
|
||
pLineCountryList = NULL;
|
||
|
||
} else
|
||
Verbose(("Number of countries: %d\n", pLineCountryList->dwNumCountries));
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
return pLineCountryList != NULL;
|
||
}
|
||
|
||
|
||
|
||
VOID CALLBACK
|
||
TapiLineCallback(
|
||
DWORD hDevice,
|
||
DWORD dwMessage,
|
||
DWORD dwInstance,
|
||
DWORD dwParam1,
|
||
DWORD dwParam2,
|
||
DWORD 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
|
||
InitTapiService(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Perform TAPI initialization if necessary
|
||
|
||
Arguments:
|
||
|
||
NONE
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, FALSE if there is an error
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD nLineDevs;
|
||
LONG status;
|
||
|
||
if (tapiLineApp == NULL) {
|
||
|
||
status = lineInitialize(&tapiLineApp,
|
||
ghInstance,
|
||
TapiLineCallback,
|
||
"Fax Configuration",
|
||
&nLineDevs);
|
||
|
||
if (status != NO_ERROR) {
|
||
|
||
Error(("lineInitialize failed: %x\n", status));
|
||
tapiLineApp = NULL;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Don't call lineNegotiateAPIVersion if nLineDevs is 0.
|
||
//
|
||
|
||
Verbose(("Number of lines: %d\n", nLineDevs));
|
||
|
||
if (nLineDevs > 0) {
|
||
|
||
LINEEXTENSIONID lineExtensionID;
|
||
|
||
status = lineNegotiateAPIVersion(tapiLineApp,
|
||
0,
|
||
TAPI_CURRENT_VERSION,
|
||
TAPI_CURRENT_VERSION,
|
||
&tapiVersion,
|
||
&lineExtensionID);
|
||
|
||
if (status != NO_ERROR) {
|
||
|
||
Error(("lineNegotiateAPIVersion failed: %x\n", status));
|
||
tapiVersion = TAPI_CURRENT_VERSION;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Get a list of countries from TAPI
|
||
//
|
||
|
||
GetCountries();
|
||
}
|
||
}
|
||
|
||
return tapiLineApp != NULL;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
DeinitTapiService(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Perform TAPI deinitialization if necessary
|
||
|
||
Arguments:
|
||
|
||
NONE
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
|
||
{
|
||
MemFree(pLineCountryList);
|
||
pLineCountryList = NULL;
|
||
|
||
if (tapiLineApp) {
|
||
|
||
lineShutdown(tapiLineApp);
|
||
tapiLineApp = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
LPLINECOUNTRYENTRY
|
||
FindCountry(
|
||
DWORD countryId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Find the specified country from a list of all countries and
|
||
return a pointer to the corresponding LINECOUNTRYENTRY structure
|
||
|
||
Arguments:
|
||
|
||
countryId - Specifies the country ID we're interested in
|
||
|
||
Return Value:
|
||
|
||
Pointer to a LINECOUNTRYENTRY structure corresponding to the specified country ID
|
||
NULL if there is an error
|
||
|
||
--*/
|
||
|
||
{
|
||
LPLINECOUNTRYENTRY pEntry;
|
||
DWORD index;
|
||
|
||
if (pLineCountryList == NULL || countryId == 0)
|
||
return NULL;
|
||
|
||
//
|
||
// Look at each LINECOUNTRYENTRY structure and compare its country ID with
|
||
// the specified country ID
|
||
//
|
||
|
||
pEntry = (LPLINECOUNTRYENTRY)
|
||
((PBYTE) pLineCountryList + pLineCountryList->dwCountryListOffset);
|
||
|
||
for (index=0; index < pLineCountryList->dwNumCountries; index++, pEntry++) {
|
||
|
||
if (pEntry->dwCountryID == countryId)
|
||
return pEntry;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
|
||
|
||
INT
|
||
AreaCodeRules(
|
||
LPLINECOUNTRYENTRY pEntry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Given a LINECOUNTRYENTRY structure, determine if area code is needed in that country
|
||
|
||
Arguments:
|
||
|
||
pEntry - Points to a LINECOUNTRYENTRY 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
|
||
|
||
--*/
|
||
|
||
#define AREACODE_DONTNEED 0
|
||
#define AREACODE_REQUIRED 1
|
||
#define AREACODE_OPTIONAL 2
|
||
|
||
{
|
||
if ((pEntry != NULL) &&
|
||
(pEntry->dwLongDistanceRuleSize != 0) &&
|
||
(pEntry->dwLongDistanceRuleOffset != 0))
|
||
{
|
||
LPTSTR pLongDistanceRule;
|
||
|
||
//
|
||
// Get the long distance rules for the specified country
|
||
//
|
||
|
||
Assert(pLineCountryList != NULL);
|
||
|
||
pLongDistanceRule = (LPTSTR)
|
||
((PBYTE) pLineCountryList + pEntry->dwLongDistanceRuleOffset);
|
||
|
||
//
|
||
// Area code is required in this country
|
||
//
|
||
|
||
if (_tcschr(pLongDistanceRule, TEXT('F')) != NULL)
|
||
return AREACODE_REQUIRED;
|
||
|
||
//
|
||
// Area code is not needed in this country
|
||
//
|
||
|
||
if (_tcschr(pLongDistanceRule, TEXT('I')) == NULL)
|
||
return AREACODE_DONTNEED;
|
||
}
|
||
|
||
//
|
||
// Default case: area code is optional in this country
|
||
//
|
||
|
||
return AREACODE_OPTIONAL;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
UpdateAreaCodeField(
|
||
HWND hwndAreaCode,
|
||
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
|
||
countryId - Currently selected country ID
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
|
||
{
|
||
if (hwndAreaCode != NULL) {
|
||
|
||
if (AreaCodeRules(FindCountry(countryId)) == AREACODE_DONTNEED) {
|
||
|
||
SendMessage(hwndAreaCode, WM_SETTEXT, 0, (LPARAM) TEXT(""));
|
||
EnableWindow(hwndAreaCode, FALSE);
|
||
|
||
} else
|
||
EnableWindow(hwndAreaCode, TRUE);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
InitCountryListBox(
|
||
HWND hwndList,
|
||
HWND hwndAreaCode,
|
||
DWORD countryId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize the country list box
|
||
|
||
Arguments:
|
||
|
||
hwndList - Handle to the country list box window
|
||
hwndAreaCode - Handle to an associated area code text field
|
||
countryId - Initially selected country ID
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
|
||
#define MAX_COUNTRY_NAME 256
|
||
|
||
{
|
||
DWORD index;
|
||
TCHAR buffer[MAX_COUNTRY_NAME];
|
||
LPLINECOUNTRYENTRY pEntry;
|
||
|
||
//
|
||
// Disable redraw on the list box and reset its content
|
||
//
|
||
|
||
SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
|
||
SendMessage(hwndList, CB_RESETCONTENT, FALSE, 0);
|
||
|
||
//
|
||
// Loop through LINECOUNTRYENTRY structures and
|
||
// add the available selections to the country list box.
|
||
//
|
||
|
||
if (pLineCountryList != NULL) {
|
||
|
||
pEntry = (LPLINECOUNTRYENTRY)
|
||
((PBYTE) pLineCountryList + pLineCountryList->dwCountryListOffset);
|
||
|
||
for (index=0; index < pLineCountryList->dwNumCountries; index++, pEntry++) {
|
||
|
||
if (pEntry->dwCountryNameSize && pEntry->dwCountryNameOffset) {
|
||
|
||
wsprintf(buffer, TEXT("%s (%d)"),
|
||
(PBYTE) pLineCountryList + pEntry->dwCountryNameOffset,
|
||
pEntry->dwCountryCode);
|
||
|
||
SendMessage(hwndList,
|
||
CB_SETITEMDATA,
|
||
SendMessage(hwndList, CB_ADDSTRING, 0, (LPARAM) buffer),
|
||
pEntry->dwCountryID);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Insert None as the very first selection
|
||
//
|
||
|
||
LoadString(ghInstance, IDS_NO_COUNTRY, buffer, MAX_COUNTRY_NAME);
|
||
SendMessage(hwndList, CB_INSERTSTRING, 0, (LPARAM) buffer);
|
||
SendMessage(hwndList, CB_SETITEMDATA, 0, 0);
|
||
|
||
//
|
||
// Figure out which item in the list should be selected
|
||
//
|
||
|
||
if (pLineCountryList != NULL) {
|
||
|
||
for (index=0; index <= pLineCountryList->dwNumCountries; index++) {
|
||
|
||
if ((DWORD) SendMessage(hwndList, CB_GETITEMDATA, index, 0) == countryId)
|
||
break;
|
||
}
|
||
|
||
if (index > pLineCountryList->dwNumCountries)
|
||
index = countryId = 0;
|
||
|
||
} else
|
||
index = countryId = 0;
|
||
|
||
SendMessage(hwndList, CB_SETCURSEL, index, 0);
|
||
SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
|
||
|
||
//
|
||
// Update the associated area code text field
|
||
//
|
||
|
||
UpdateAreaCodeField(hwndAreaCode, countryId);
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
SelChangeCountryListBox(
|
||
HWND hwndList,
|
||
HWND hwndAreaCode
|
||
)
|
||
|
||
/*++
|
||
|
||
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
|
||
|
||
Return Value:
|
||
|
||
NONE
|
||
|
||
--*/
|
||
|
||
{
|
||
UpdateAreaCodeField(hwndAreaCode, GetCountryListBoxSel(hwndList));
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
GetCountryListBoxSel(
|
||
HWND hwndList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Return the country ID of the currently selected country in the list box
|
||
|
||
Arguments:
|
||
|
||
hwndList - Handle to the country list box window
|
||
|
||
Return Value:
|
||
|
||
Currently selected country ID
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG msgResult;
|
||
|
||
if ((msgResult = SendMessage(hwndList, CB_GETCURSEL, 0, 0)) == CB_ERR ||
|
||
(msgResult = SendMessage(hwndList, CB_GETITEMDATA, msgResult, 0)) == CB_ERR)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
return msgResult;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
GetCountryCodeFromCountryID(
|
||
DWORD countryId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Return a country code corresponding to the specified country ID
|
||
|
||
Arguments:
|
||
|
||
countryId - Specified the interested country ID
|
||
|
||
Return Value:
|
||
|
||
Country code corresponding to the specified country ID
|
||
|
||
--*/
|
||
|
||
{
|
||
LPLINECOUNTRYENTRY pLineCountryEntry;
|
||
|
||
pLineCountryEntry = FindCountry(countryId);
|
||
return pLineCountryEntry ? pLineCountryEntry->dwCountryCode : 0;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
GetDefaultCountryID(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Return the default country ID for the current location
|
||
|
||
Arguments:
|
||
|
||
NONE
|
||
|
||
Return Value:
|
||
|
||
Default country ID
|
||
|
||
--*/
|
||
|
||
#define INITIAL_LINETRANSLATECAPS_SIZE 5000 // Initial buffer size
|
||
|
||
{
|
||
DWORD cbNeeded = INITIAL_LINETRANSLATECAPS_SIZE;
|
||
DWORD countryId = 0;
|
||
LONG status;
|
||
INT repeatCnt = 0;
|
||
LPLINETRANSLATECAPS pTranslateCaps = NULL;
|
||
|
||
if (tapiLineApp == NULL)
|
||
return 0;
|
||
|
||
while (TRUE) {
|
||
|
||
//
|
||
// Free any existing buffer and allocate a new one with larger size
|
||
//
|
||
|
||
MemFree(pTranslateCaps);
|
||
|
||
if (! (pTranslateCaps = MemAlloc(cbNeeded))) {
|
||
|
||
Error(("Memory allocation failed\n"));
|
||
return 0;
|
||
}
|
||
|
||
//
|
||
// Get the LINETRANSLATECAPS structure from TAPI
|
||
//
|
||
|
||
pTranslateCaps->dwTotalSize = cbNeeded;
|
||
status = lineGetTranslateCaps(tapiLineApp, tapiVersion, pTranslateCaps);
|
||
|
||
//
|
||
// Retry if our initial estimated buffer size was too small
|
||
//
|
||
|
||
if ((pTranslateCaps->dwNeededSize > pTranslateCaps->dwTotalSize) &&
|
||
(status == NO_ERROR ||
|
||
status == LINEERR_STRUCTURETOOSMALL ||
|
||
status == LINEERR_NOMEM) &&
|
||
(repeatCnt++ == 0))
|
||
{
|
||
cbNeeded = pTranslateCaps->dwNeededSize;
|
||
Warning(("LINETRANSLATECAPS size: %d\n", cbNeeded));
|
||
continue;
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Find the current location entry
|
||
//
|
||
|
||
if (status != NO_ERROR) {
|
||
|
||
Error(("lineGetTranslateCaps failed: %x\n", status));
|
||
|
||
} else if (pTranslateCaps->dwLocationListSize && pTranslateCaps->dwLocationListOffset) {
|
||
|
||
LPLINELOCATIONENTRY pLineLocationEntry;
|
||
DWORD index;
|
||
|
||
pLineLocationEntry = (LPLINELOCATIONENTRY)
|
||
((PBYTE) pTranslateCaps + pTranslateCaps->dwLocationListOffset);
|
||
|
||
for (index=0; index < pTranslateCaps->dwNumLocations; index++, pLineLocationEntry++) {
|
||
|
||
if (pLineLocationEntry->dwPermanentLocationID == pTranslateCaps->dwCurrentLocationID) {
|
||
|
||
countryId = pLineLocationEntry->dwCountryID;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
MemFree(pTranslateCaps);
|
||
return countryId;
|
||
}
|
||
|