Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

736 lines
14 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. tapiutil.c
  5. Abstract:
  6. Functions for working with TAPI
  7. Environment:
  8. Fax configuration applet
  9. Revision History:
  10. 03/16/96 -davidx-
  11. Created it.
  12. mm/dd/yy -author-
  13. description
  14. NOTE:
  15. We are calling W-version of TAPI APIs explicitly here because
  16. tapi.h doesn't properly expand them to A- or W-version.
  17. --*/
  18. #include "faxcpl.h"
  19. #include <tapi.h>
  20. //
  21. // Global variables used for accessing TAPI services
  22. //
  23. static HLINEAPP tapiLineApp = NULL;
  24. static DWORD tapiVersion = TAPI_CURRENT_VERSION;
  25. static LPLINECOUNTRYLIST pLineCountryList = NULL;
  26. BOOL
  27. GetCountries(
  28. VOID
  29. )
  30. /*++
  31. Routine Description:
  32. Return a list of countries from TAPI
  33. Arguments:
  34. NONE
  35. Return Value:
  36. TRUE if successful, FALSE if there is an error
  37. NOTE:
  38. We cache the result of lineGetCountry here since it's incredibly slow.
  39. This function must be invoked inside a critical section since it updates
  40. globally shared information.
  41. --*/
  42. #define INITIAL_SIZE_ALL_COUNTRY 22000 // Initial buffer size
  43. {
  44. DWORD cbNeeded = INITIAL_SIZE_ALL_COUNTRY;
  45. INT repeatCnt = 0;
  46. LONG status;
  47. if (pLineCountryList == NULL) {
  48. while (TRUE) {
  49. //
  50. // Free existing buffer and allocate a new buffer of required size
  51. //
  52. MemFree(pLineCountryList);
  53. if (! (pLineCountryList = MemAlloc(cbNeeded))) {
  54. Error(("Memory allocation failed\n"));
  55. break;
  56. }
  57. //
  58. // Call TAPI to get the list of countries
  59. //
  60. pLineCountryList->dwTotalSize = cbNeeded;
  61. status = lineGetCountry(0, tapiVersion, pLineCountryList);
  62. //
  63. // Retries with a larger buffer size if our initial estimate was too small
  64. //
  65. if ((pLineCountryList->dwNeededSize > pLineCountryList->dwTotalSize) &&
  66. (status == NO_ERROR ||
  67. status == LINEERR_STRUCTURETOOSMALL ||
  68. status == LINEERR_NOMEM) &&
  69. (repeatCnt++ == 0))
  70. {
  71. cbNeeded = pLineCountryList->dwNeededSize + 1;
  72. Warning(("LINECOUNTRYLIST size: %d\n", cbNeeded));
  73. continue;
  74. }
  75. if (status != NO_ERROR) {
  76. Error(("lineGetCountry failed: %x\n", status));
  77. MemFree(pLineCountryList);
  78. pLineCountryList = NULL;
  79. } else
  80. Verbose(("Number of countries: %d\n", pLineCountryList->dwNumCountries));
  81. break;
  82. }
  83. }
  84. return pLineCountryList != NULL;
  85. }
  86. VOID CALLBACK
  87. TapiLineCallback(
  88. DWORD hDevice,
  89. DWORD dwMessage,
  90. DWORD dwInstance,
  91. DWORD dwParam1,
  92. DWORD dwParam2,
  93. DWORD dwParam3
  94. )
  95. /*++
  96. Routine Description:
  97. TAPI line callback function: Even though we don't actually have anything
  98. to do here, we must provide a callback function to keep TAPI happy.
  99. Arguments:
  100. hDevice - Line or call handle
  101. dwMessage - Reason for the callback
  102. dwInstance - LINE_INFO index
  103. dwParam1 - Callback parameter #1
  104. dwParam2 - Callback parameter #2
  105. dwParam3 - Callback parameter #3
  106. Return Value:
  107. NONE
  108. --*/
  109. {
  110. }
  111. BOOL
  112. InitTapiService(
  113. VOID
  114. )
  115. /*++
  116. Routine Description:
  117. Perform TAPI initialization if necessary
  118. Arguments:
  119. NONE
  120. Return Value:
  121. TRUE if successful, FALSE if there is an error
  122. --*/
  123. {
  124. DWORD nLineDevs;
  125. LONG status;
  126. if (tapiLineApp == NULL) {
  127. status = lineInitialize(&tapiLineApp,
  128. ghInstance,
  129. TapiLineCallback,
  130. "Fax Configuration",
  131. &nLineDevs);
  132. if (status != NO_ERROR) {
  133. Error(("lineInitialize failed: %x\n", status));
  134. tapiLineApp = NULL;
  135. } else {
  136. //
  137. // Don't call lineNegotiateAPIVersion if nLineDevs is 0.
  138. //
  139. Verbose(("Number of lines: %d\n", nLineDevs));
  140. if (nLineDevs > 0) {
  141. LINEEXTENSIONID lineExtensionID;
  142. status = lineNegotiateAPIVersion(tapiLineApp,
  143. 0,
  144. TAPI_CURRENT_VERSION,
  145. TAPI_CURRENT_VERSION,
  146. &tapiVersion,
  147. &lineExtensionID);
  148. if (status != NO_ERROR) {
  149. Error(("lineNegotiateAPIVersion failed: %x\n", status));
  150. tapiVersion = TAPI_CURRENT_VERSION;
  151. }
  152. }
  153. //
  154. // Get a list of countries from TAPI
  155. //
  156. GetCountries();
  157. }
  158. }
  159. return tapiLineApp != NULL;
  160. }
  161. VOID
  162. DeinitTapiService(
  163. VOID
  164. )
  165. /*++
  166. Routine Description:
  167. Perform TAPI deinitialization if necessary
  168. Arguments:
  169. NONE
  170. Return Value:
  171. NONE
  172. --*/
  173. {
  174. MemFree(pLineCountryList);
  175. pLineCountryList = NULL;
  176. if (tapiLineApp) {
  177. lineShutdown(tapiLineApp);
  178. tapiLineApp = NULL;
  179. }
  180. }
  181. LPLINECOUNTRYENTRY
  182. FindCountry(
  183. DWORD countryId
  184. )
  185. /*++
  186. Routine Description:
  187. Find the specified country from a list of all countries and
  188. return a pointer to the corresponding LINECOUNTRYENTRY structure
  189. Arguments:
  190. countryId - Specifies the country ID we're interested in
  191. Return Value:
  192. Pointer to a LINECOUNTRYENTRY structure corresponding to the specified country ID
  193. NULL if there is an error
  194. --*/
  195. {
  196. LPLINECOUNTRYENTRY pEntry;
  197. DWORD index;
  198. if (pLineCountryList == NULL || countryId == 0)
  199. return NULL;
  200. //
  201. // Look at each LINECOUNTRYENTRY structure and compare its country ID with
  202. // the specified country ID
  203. //
  204. pEntry = (LPLINECOUNTRYENTRY)
  205. ((PBYTE) pLineCountryList + pLineCountryList->dwCountryListOffset);
  206. for (index=0; index < pLineCountryList->dwNumCountries; index++, pEntry++) {
  207. if (pEntry->dwCountryID == countryId)
  208. return pEntry;
  209. }
  210. return NULL;
  211. }
  212. INT
  213. AreaCodeRules(
  214. LPLINECOUNTRYENTRY pEntry
  215. )
  216. /*++
  217. Routine Description:
  218. Given a LINECOUNTRYENTRY structure, determine if area code is needed in that country
  219. Arguments:
  220. pEntry - Points to a LINECOUNTRYENTRY structure
  221. Return Value:
  222. AREACODE_DONTNEED - Area code is not used in the specified country
  223. AREACODE_OPTIONAL - Area code is optional in the specified country
  224. AREACODE_REQUIRED - Area code is required in the specified country
  225. --*/
  226. #define AREACODE_DONTNEED 0
  227. #define AREACODE_REQUIRED 1
  228. #define AREACODE_OPTIONAL 2
  229. {
  230. if ((pEntry != NULL) &&
  231. (pEntry->dwLongDistanceRuleSize != 0) &&
  232. (pEntry->dwLongDistanceRuleOffset != 0))
  233. {
  234. LPTSTR pLongDistanceRule;
  235. //
  236. // Get the long distance rules for the specified country
  237. //
  238. Assert(pLineCountryList != NULL);
  239. pLongDistanceRule = (LPTSTR)
  240. ((PBYTE) pLineCountryList + pEntry->dwLongDistanceRuleOffset);
  241. //
  242. // Area code is required in this country
  243. //
  244. if (_tcschr(pLongDistanceRule, TEXT('F')) != NULL)
  245. return AREACODE_REQUIRED;
  246. //
  247. // Area code is not needed in this country
  248. //
  249. if (_tcschr(pLongDistanceRule, TEXT('I')) == NULL)
  250. return AREACODE_DONTNEED;
  251. }
  252. //
  253. // Default case: area code is optional in this country
  254. //
  255. return AREACODE_OPTIONAL;
  256. }
  257. VOID
  258. UpdateAreaCodeField(
  259. HWND hwndAreaCode,
  260. DWORD countryId
  261. )
  262. /*++
  263. Routine Description:
  264. Update any area code text field associated with a country list box
  265. Arguments:
  266. hwndAreaCode - Specifies the text field associated with the country list box
  267. countryId - Currently selected country ID
  268. Return Value:
  269. NONE
  270. --*/
  271. {
  272. if (hwndAreaCode != NULL) {
  273. if (AreaCodeRules(FindCountry(countryId)) == AREACODE_DONTNEED) {
  274. SendMessage(hwndAreaCode, WM_SETTEXT, 0, (LPARAM) TEXT(""));
  275. EnableWindow(hwndAreaCode, FALSE);
  276. } else
  277. EnableWindow(hwndAreaCode, TRUE);
  278. }
  279. }
  280. VOID
  281. InitCountryListBox(
  282. HWND hwndList,
  283. HWND hwndAreaCode,
  284. DWORD countryId
  285. )
  286. /*++
  287. Routine Description:
  288. Initialize the country list box
  289. Arguments:
  290. hwndList - Handle to the country list box window
  291. hwndAreaCode - Handle to an associated area code text field
  292. countryId - Initially selected country ID
  293. Return Value:
  294. NONE
  295. --*/
  296. #define MAX_COUNTRY_NAME 256
  297. {
  298. DWORD index;
  299. TCHAR buffer[MAX_COUNTRY_NAME];
  300. LPLINECOUNTRYENTRY pEntry;
  301. //
  302. // Disable redraw on the list box and reset its content
  303. //
  304. SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
  305. SendMessage(hwndList, CB_RESETCONTENT, FALSE, 0);
  306. //
  307. // Loop through LINECOUNTRYENTRY structures and
  308. // add the available selections to the country list box.
  309. //
  310. if (pLineCountryList != NULL) {
  311. pEntry = (LPLINECOUNTRYENTRY)
  312. ((PBYTE) pLineCountryList + pLineCountryList->dwCountryListOffset);
  313. for (index=0; index < pLineCountryList->dwNumCountries; index++, pEntry++) {
  314. if (pEntry->dwCountryNameSize && pEntry->dwCountryNameOffset) {
  315. wsprintf(buffer, TEXT("%s (%d)"),
  316. (PBYTE) pLineCountryList + pEntry->dwCountryNameOffset,
  317. pEntry->dwCountryCode);
  318. SendMessage(hwndList,
  319. CB_SETITEMDATA,
  320. SendMessage(hwndList, CB_ADDSTRING, 0, (LPARAM) buffer),
  321. pEntry->dwCountryID);
  322. }
  323. }
  324. }
  325. //
  326. // Insert None as the very first selection
  327. //
  328. LoadString(ghInstance, IDS_NO_COUNTRY, buffer, MAX_COUNTRY_NAME);
  329. SendMessage(hwndList, CB_INSERTSTRING, 0, (LPARAM) buffer);
  330. SendMessage(hwndList, CB_SETITEMDATA, 0, 0);
  331. //
  332. // Figure out which item in the list should be selected
  333. //
  334. if (pLineCountryList != NULL) {
  335. for (index=0; index <= pLineCountryList->dwNumCountries; index++) {
  336. if ((DWORD) SendMessage(hwndList, CB_GETITEMDATA, index, 0) == countryId)
  337. break;
  338. }
  339. if (index > pLineCountryList->dwNumCountries)
  340. index = countryId = 0;
  341. } else
  342. index = countryId = 0;
  343. SendMessage(hwndList, CB_SETCURSEL, index, 0);
  344. SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
  345. //
  346. // Update the associated area code text field
  347. //
  348. UpdateAreaCodeField(hwndAreaCode, countryId);
  349. }
  350. VOID
  351. SelChangeCountryListBox(
  352. HWND hwndList,
  353. HWND hwndAreaCode
  354. )
  355. /*++
  356. Routine Description:
  357. Handle dialog selection changes in the country list box
  358. Arguments:
  359. hwndList - Handle to the country list box window
  360. hwndAreaCode - Handle to an associated area code text field
  361. Return Value:
  362. NONE
  363. --*/
  364. {
  365. UpdateAreaCodeField(hwndAreaCode, GetCountryListBoxSel(hwndList));
  366. }
  367. DWORD
  368. GetCountryListBoxSel(
  369. HWND hwndList
  370. )
  371. /*++
  372. Routine Description:
  373. Return the country ID of the currently selected country in the list box
  374. Arguments:
  375. hwndList - Handle to the country list box window
  376. Return Value:
  377. Currently selected country ID
  378. --*/
  379. {
  380. LONG msgResult;
  381. if ((msgResult = SendMessage(hwndList, CB_GETCURSEL, 0, 0)) == CB_ERR ||
  382. (msgResult = SendMessage(hwndList, CB_GETITEMDATA, msgResult, 0)) == CB_ERR)
  383. {
  384. return 0;
  385. }
  386. return msgResult;
  387. }
  388. DWORD
  389. GetCountryCodeFromCountryID(
  390. DWORD countryId
  391. )
  392. /*++
  393. Routine Description:
  394. Return a country code corresponding to the specified country ID
  395. Arguments:
  396. countryId - Specified the interested country ID
  397. Return Value:
  398. Country code corresponding to the specified country ID
  399. --*/
  400. {
  401. LPLINECOUNTRYENTRY pLineCountryEntry;
  402. pLineCountryEntry = FindCountry(countryId);
  403. return pLineCountryEntry ? pLineCountryEntry->dwCountryCode : 0;
  404. }
  405. DWORD
  406. GetDefaultCountryID(
  407. VOID
  408. )
  409. /*++
  410. Routine Description:
  411. Return the default country ID for the current location
  412. Arguments:
  413. NONE
  414. Return Value:
  415. Default country ID
  416. --*/
  417. #define INITIAL_LINETRANSLATECAPS_SIZE 5000 // Initial buffer size
  418. {
  419. DWORD cbNeeded = INITIAL_LINETRANSLATECAPS_SIZE;
  420. DWORD countryId = 0;
  421. LONG status;
  422. INT repeatCnt = 0;
  423. LPLINETRANSLATECAPS pTranslateCaps = NULL;
  424. if (tapiLineApp == NULL)
  425. return 0;
  426. while (TRUE) {
  427. //
  428. // Free any existing buffer and allocate a new one with larger size
  429. //
  430. MemFree(pTranslateCaps);
  431. if (! (pTranslateCaps = MemAlloc(cbNeeded))) {
  432. Error(("Memory allocation failed\n"));
  433. return 0;
  434. }
  435. //
  436. // Get the LINETRANSLATECAPS structure from TAPI
  437. //
  438. pTranslateCaps->dwTotalSize = cbNeeded;
  439. status = lineGetTranslateCaps(tapiLineApp, tapiVersion, pTranslateCaps);
  440. //
  441. // Retry if our initial estimated buffer size was too small
  442. //
  443. if ((pTranslateCaps->dwNeededSize > pTranslateCaps->dwTotalSize) &&
  444. (status == NO_ERROR ||
  445. status == LINEERR_STRUCTURETOOSMALL ||
  446. status == LINEERR_NOMEM) &&
  447. (repeatCnt++ == 0))
  448. {
  449. cbNeeded = pTranslateCaps->dwNeededSize;
  450. Warning(("LINETRANSLATECAPS size: %d\n", cbNeeded));
  451. continue;
  452. }
  453. break;
  454. }
  455. //
  456. // Find the current location entry
  457. //
  458. if (status != NO_ERROR) {
  459. Error(("lineGetTranslateCaps failed: %x\n", status));
  460. } else if (pTranslateCaps->dwLocationListSize && pTranslateCaps->dwLocationListOffset) {
  461. LPLINELOCATIONENTRY pLineLocationEntry;
  462. DWORD index;
  463. pLineLocationEntry = (LPLINELOCATIONENTRY)
  464. ((PBYTE) pTranslateCaps + pTranslateCaps->dwLocationListOffset);
  465. for (index=0; index < pTranslateCaps->dwNumLocations; index++, pLineLocationEntry++) {
  466. if (pLineLocationEntry->dwPermanentLocationID == pTranslateCaps->dwCurrentLocationID) {
  467. countryId = pLineLocationEntry->dwCountryID;
  468. break;
  469. }
  470. }
  471. }
  472. MemFree(pTranslateCaps);
  473. return countryId;
  474. }