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