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.

875 lines
17 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. tapiutil.c
  5. Abstract:
  6. Utility functions for working with TAPI
  7. Environment:
  8. Windows NT fax driver user interface
  9. Revision History:
  10. 09/18/96 -davidx-
  11. Created it.
  12. mm/dd/yy -author-
  13. description
  14. --*/
  15. #include "faxui.h"
  16. #include "tapiutil.h"
  17. //
  18. // Global variables used for accessing TAPI services
  19. //
  20. static INT tapiRefCount = 0;
  21. static HLINEAPP tapiLineApp = 0;
  22. static DWORD tapiVersion = 0x00020000; //TAPI_CURRENT_VERSION;
  23. static LPLINECOUNTRYLIST pLineCountryList = NULL;
  24. BOOL
  25. GetCountries(
  26. VOID
  27. )
  28. /*++
  29. Routine Description:
  30. Return a list of countries from TAPI
  31. Arguments:
  32. NONE
  33. Return Value:
  34. TRUE if successful, FALSE if there is an error
  35. NOTE:
  36. We cache the result of lineGetCountry here since it's incredibly slow.
  37. This function must be invoked inside a critical section since it updates
  38. globally shared information.
  39. --*/
  40. #define INITIAL_SIZE_ALL_COUNTRY 22000
  41. {
  42. DWORD cbNeeded;
  43. LONG status;
  44. INT repeatCnt = 0;
  45. if (pLineCountryList == NULL) {
  46. //
  47. // Initial buffer size
  48. //
  49. cbNeeded = INITIAL_SIZE_ALL_COUNTRY;
  50. while (TRUE) {
  51. MemFree(pLineCountryList);
  52. if (! (pLineCountryList = MemAlloc(cbNeeded))) {
  53. Error(("Memory allocation failed\n"));
  54. break;
  55. }
  56. pLineCountryList->dwTotalSize = cbNeeded;
  57. status = lineGetCountryW(0, tapiVersion, pLineCountryList);
  58. if ((pLineCountryList->dwNeededSize > pLineCountryList->dwTotalSize) &&
  59. (status == NO_ERROR ||
  60. status == LINEERR_STRUCTURETOOSMALL ||
  61. status == LINEERR_NOMEM) &&
  62. (repeatCnt++ == 0))
  63. {
  64. cbNeeded = pLineCountryList->dwNeededSize + 1;
  65. Warning(("LINECOUNTRYLIST size: %d\n", cbNeeded));
  66. continue;
  67. }
  68. if (status != NO_ERROR) {
  69. Error(("lineGetCountry failed: %x\n", status));
  70. MemFree(pLineCountryList);
  71. pLineCountryList = NULL;
  72. } else
  73. Verbose(("Number of countries: %d\n", pLineCountryList->dwNumCountries));
  74. break;
  75. }
  76. }
  77. return pLineCountryList != NULL;
  78. }
  79. VOID CALLBACK
  80. TapiLineCallback(
  81. DWORD hDevice,
  82. DWORD dwMessage,
  83. ULONG_PTR dwInstance,
  84. ULONG_PTR dwParam1,
  85. ULONG_PTR dwParam2,
  86. ULONG_PTR dwParam3
  87. )
  88. /*++
  89. Routine Description:
  90. TAPI line callback function: Even though we don't actually have anything
  91. to do here, we must provide a callback function to keep TAPI happy.
  92. Arguments:
  93. hDevice - Line or call handle
  94. dwMessage - Reason for the callback
  95. dwInstance - LINE_INFO index
  96. dwParam1 - Callback parameter #1
  97. dwParam2 - Callback parameter #2
  98. dwParam3 - Callback parameter #3
  99. Return Value:
  100. NONE
  101. --*/
  102. {
  103. }
  104. BOOL
  105. InitTapiService(
  106. VOID
  107. )
  108. /*++
  109. Routine Description:
  110. Initialize the TAPI service if necessary
  111. Arguments:
  112. NONE
  113. Return Value:
  114. TRUE if successful, FALSE otherwise
  115. NOTE:
  116. Every call to this function must be balanced by a call to DeinitTapiService.
  117. --*/
  118. {
  119. EnterDrvSem();
  120. tapiRefCount++;
  121. //
  122. // Perform TAPI initialization if necessary
  123. //
  124. if (!tapiLineApp) {
  125. DWORD nLineDevs;
  126. LONG status;
  127. LINEINITIALIZEEXPARAMS lineInitParams;
  128. ZeroMemory(&lineInitParams, sizeof(lineInitParams));
  129. lineInitParams.dwTotalSize =
  130. lineInitParams.dwNeededSize =
  131. lineInitParams.dwUsedSize = sizeof(lineInitParams);
  132. status = lineInitializeExW(&tapiLineApp,
  133. ghInstance,
  134. TapiLineCallback,
  135. L"Fax Configuration",
  136. &nLineDevs,
  137. &tapiVersion,
  138. &lineInitParams);
  139. if (status != NO_ERROR) {
  140. Error(("lineInitializeEx failed: %x\n", status));
  141. tapiLineApp = 0;
  142. }
  143. }
  144. //
  145. // Get the list of countries from TAPI and cache it
  146. //
  147. if (tapiLineApp && !pLineCountryList) {
  148. DWORD startTimer;
  149. startTimer = GetCurrentTime();
  150. GetCountries();
  151. Verbose(("lineGetCountryW took %d milliseconds\n", GetCurrentTime() - startTimer));
  152. }
  153. LeaveDrvSem();
  154. if (! tapiLineApp)
  155. Error(("TAPI initialization failed\n"));
  156. return tapiLineApp ? TRUE : FALSE;
  157. }
  158. VOID
  159. DeinitTapiService(
  160. VOID
  161. )
  162. /*++
  163. Routine Description:
  164. Deinitialize the TAPI service if necessary
  165. Arguments:
  166. NONE
  167. Return Value:
  168. NONE
  169. --*/
  170. {
  171. EnterDrvSem();
  172. if (tapiRefCount > 0 && --tapiRefCount == 0) {
  173. if (tapiLineApp) {
  174. lineShutdown(tapiLineApp);
  175. tapiLineApp = 0;
  176. }
  177. MemFree(pLineCountryList);
  178. pLineCountryList = NULL;
  179. }
  180. LeaveDrvSem();
  181. }
  182. DWORD
  183. GetDefaultCountryID(
  184. VOID
  185. )
  186. /*++
  187. Routine Description:
  188. Return the default country ID for the current location
  189. Arguments:
  190. NONE
  191. Return Value:
  192. The current ID for the current location
  193. --*/
  194. {
  195. //
  196. // We assume the correct information has already been saved to the
  197. // registry during the installation process.
  198. //
  199. return 0;
  200. }
  201. LPLINETRANSLATECAPS
  202. GetTapiLocationInfo(
  203. HWND hWnd
  204. )
  205. /*++
  206. Routine Description:
  207. Get a list of locations from TAPI
  208. Arguments:
  209. NONE
  210. Return Value:
  211. Pointer to a LINETRANSLATECAPS structure,
  212. NULL if there is an error
  213. --*/
  214. #define INITIAL_LINETRANSLATECAPS_SIZE 5000
  215. {
  216. DWORD cbNeeded = INITIAL_LINETRANSLATECAPS_SIZE;
  217. LONG status;
  218. INT repeatCnt = 0;
  219. LPLINETRANSLATECAPS pTranslateCaps = NULL;
  220. if (!tapiLineApp)
  221. return NULL;
  222. while (TRUE) {
  223. //
  224. // Free any existing buffer and allocate a new one with larger size
  225. //
  226. MemFree(pTranslateCaps);
  227. if (! (pTranslateCaps = MemAlloc(cbNeeded))) {
  228. Error(("Memory allocation failed\n"));
  229. return NULL;
  230. }
  231. //
  232. // Get the LINETRANSLATECAPS structure from TAPI
  233. //
  234. pTranslateCaps->dwTotalSize = cbNeeded;
  235. status = lineGetTranslateCapsW(tapiLineApp, tapiVersion, pTranslateCaps);
  236. //
  237. // try to bring up UI if there are no locations.
  238. //
  239. if (status == LINEERR_INIFILECORRUPT) {
  240. if (lineTranslateDialog( tapiLineApp, 0, tapiVersion, hWnd, NULL )) {
  241. MemFree(pTranslateCaps);
  242. return NULL;
  243. }
  244. continue;
  245. }
  246. //
  247. // Retry if our initial estimated buffer size was too small
  248. //
  249. if ((pTranslateCaps->dwNeededSize > pTranslateCaps->dwTotalSize) &&
  250. (status == NO_ERROR ||
  251. status == LINEERR_STRUCTURETOOSMALL ||
  252. status == LINEERR_NOMEM) &&
  253. (repeatCnt++ == 0))
  254. {
  255. cbNeeded = pTranslateCaps->dwNeededSize;
  256. Warning(("LINETRANSLATECAPS size: %d\n", cbNeeded));
  257. continue;
  258. }
  259. break;
  260. }
  261. if (status != NO_ERROR) {
  262. Error(("lineGetTranslateCaps failed: %x\n", status));
  263. MemFree(pTranslateCaps);
  264. pTranslateCaps = NULL;
  265. }
  266. return pTranslateCaps;
  267. }
  268. BOOL
  269. SetCurrentLocation(
  270. DWORD locationID
  271. )
  272. /*++
  273. Routine Description:
  274. Change the default TAPI location
  275. Arguments:
  276. locationID - The permanant ID for the new default TAPI location
  277. Return Value:
  278. TRUE if successful, FALSE if there is an error
  279. --*/
  280. {
  281. if (tapiLineApp && (lineSetCurrentLocation(tapiLineApp, locationID) == NO_ERROR))
  282. {
  283. Verbose(("Current location changed: ID = %d\n", locationID));
  284. return TRUE;
  285. } else {
  286. Error(("Couldn't change current TAPI location\n"));
  287. return FALSE;
  288. }
  289. }
  290. LPLINECOUNTRYENTRY
  291. FindCountry(
  292. DWORD countryId
  293. )
  294. /*++
  295. Routine Description:
  296. Find the specified country from a list of all countries and
  297. return a pointer to the corresponding LINECOUNTRYENTRY structure
  298. Arguments:
  299. countryId - Specifies the country ID we're interested in
  300. Return Value:
  301. Pointer to a LINECOUNTRYENTRY structure corresponding to the specified country ID
  302. NULL if there is an error
  303. --*/
  304. {
  305. LPLINECOUNTRYENTRY pEntry;
  306. DWORD index;
  307. if (pLineCountryList == NULL || countryId == 0)
  308. return NULL;
  309. //
  310. // Look at each LINECOUNTRYENTRY structure and compare its country ID with
  311. // the specified country ID
  312. //
  313. pEntry = (LPLINECOUNTRYENTRY)
  314. ((PBYTE) pLineCountryList + pLineCountryList->dwCountryListOffset);
  315. for (index=0; index < pLineCountryList->dwNumCountries; index++, pEntry++) {
  316. if (pEntry->dwCountryID == countryId)
  317. return pEntry;
  318. }
  319. return NULL;
  320. }
  321. INT
  322. AreaCodeRules(
  323. LPLINECOUNTRYENTRY pEntry
  324. )
  325. /*++
  326. Routine Description:
  327. Given a LINECOUNTRYENTRY structure, determine if area code is needed in that country
  328. Arguments:
  329. pEntry - Points to a LINECOUNTRYENTRY structure
  330. Return Value:
  331. AREACODE_DONTNEED - Area code is not used in the specified country
  332. AREACODE_OPTIONAL - Area code is optional in the specified country
  333. AREACODE_REQUIRED - Area code is required in the specified country
  334. --*/
  335. {
  336. if ((pEntry != NULL) &&
  337. (pEntry->dwLongDistanceRuleSize != 0) &&
  338. (pEntry->dwLongDistanceRuleOffset != 0))
  339. {
  340. LPTSTR pLongDistanceRule;
  341. //
  342. // Get the long distance rules for the specified country
  343. //
  344. Assert(pLineCountryList != NULL);
  345. pLongDistanceRule = (LPTSTR)
  346. ((PBYTE) pLineCountryList + pEntry->dwLongDistanceRuleOffset);
  347. //
  348. // Area code is required in this country
  349. //
  350. if (_tcschr(pLongDistanceRule, TEXT('F')) != NULL)
  351. return AREACODE_REQUIRED;
  352. //
  353. // Area code is not needed in this country
  354. //
  355. if (_tcschr(pLongDistanceRule, TEXT('I')) == NULL)
  356. return AREACODE_DONTNEED;
  357. }
  358. //
  359. // Default case: area code is optional in this country
  360. //
  361. return AREACODE_OPTIONAL;
  362. }
  363. VOID
  364. AssemblePhoneNumber(
  365. LPTSTR pAddress,
  366. DWORD countryCode,
  367. LPTSTR pAreaCode,
  368. LPTSTR pPhoneNumber
  369. )
  370. /*++
  371. Routine Description:
  372. Assemble a canonical phone number given the following:
  373. country code, area code, and phone number
  374. Arguments:
  375. pAddress - Specifies a buffer to hold the resulting fax address
  376. countryCode - Specifies the country code
  377. pAreaCode - Specifies the area code string
  378. pPhoneNumber - Specifies the phone number string
  379. Return Value:
  380. NONE
  381. Note:
  382. We assume the caller has allocated a large enough destination buffer.
  383. --*/
  384. {
  385. //
  386. // Country code if neccessary
  387. //
  388. if (countryCode != 0) {
  389. *pAddress++ = TEXT('+');
  390. wsprintf(pAddress, TEXT("%d "), countryCode);
  391. pAddress += _tcslen(pAddress);
  392. }
  393. //
  394. // Area code if necessary
  395. //
  396. if (pAreaCode && !IsEmptyString(pAreaCode)) {
  397. if (countryCode != 0)
  398. *pAddress++ = TEXT('(');
  399. _tcscpy(pAddress, pAreaCode);
  400. pAddress += _tcslen(pAddress);
  401. if (countryCode != 0)
  402. *pAddress++ = TEXT(')');
  403. *pAddress++ = TEXT(' ');
  404. }
  405. //
  406. // Phone number at last
  407. //
  408. Assert(pPhoneNumber != NULL);
  409. _tcscpy(pAddress, pPhoneNumber);
  410. }
  411. VOID
  412. UpdateAreaCodeField(
  413. HWND hwndAreaCode,
  414. DWORD countryId
  415. )
  416. /*++
  417. Routine Description:
  418. Update any area code text field associated with a country list box
  419. Arguments:
  420. hwndAreaCode - Specifies the text field associated with the country list box
  421. countryId - Currently selected country ID
  422. Return Value:
  423. NONE
  424. --*/
  425. {
  426. static TCHAR AreaCode[11] = TEXT("");
  427. static BOOL bGetAreaCode = TRUE;
  428. if (hwndAreaCode == NULL)
  429. return;
  430. if ((countryId == -1) || (AreaCodeRules(FindCountry(countryId)) == AREACODE_DONTNEED)) {
  431. if (bGetAreaCode == TRUE) {
  432. bGetAreaCode = FALSE;
  433. SendMessage(hwndAreaCode, WM_GETTEXT, sizeof(AreaCode) / sizeof(TCHAR), (LPARAM) AreaCode);
  434. }
  435. SendMessage(hwndAreaCode, WM_SETTEXT, 0, (LPARAM) TEXT(""));
  436. EnableWindow(hwndAreaCode, FALSE);
  437. } else {
  438. EnableWindow(hwndAreaCode, TRUE);
  439. if (bGetAreaCode == FALSE) {
  440. bGetAreaCode = TRUE;
  441. SendMessage(hwndAreaCode, WM_SETTEXT, 0, (LPARAM) AreaCode);
  442. }
  443. }
  444. }
  445. VOID
  446. InitCountryListBox(
  447. HWND hwndList,
  448. HWND hwndAreaCode,
  449. DWORD countryId
  450. )
  451. /*++
  452. Routine Description:
  453. Initialize the country list box
  454. Arguments:
  455. hwndList - Handle to the country list box window
  456. hwndAreaCode - Handle to an associated area code text field
  457. countryId - Initially selected country ID
  458. Return Value:
  459. NONE
  460. --*/
  461. #define MAX_COUNTRY_NAME 256
  462. {
  463. DWORD index;
  464. TCHAR buffer[MAX_COUNTRY_NAME];
  465. LPLINECOUNTRYENTRY pEntry;
  466. //
  467. // Disable redraw on the list box and reset its content
  468. //
  469. SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
  470. SendMessage(hwndList, CB_RESETCONTENT, FALSE, 0);
  471. //
  472. // Loop through LINECOUNTRYENTRY structures and add the available selections to
  473. // the country list box.
  474. //
  475. if (pLineCountryList != NULL) {
  476. pEntry = (LPLINECOUNTRYENTRY)
  477. ((PBYTE) pLineCountryList + pLineCountryList->dwCountryListOffset);
  478. for (index=0; index < pLineCountryList->dwNumCountries; index++, pEntry++) {
  479. if (pEntry->dwCountryNameSize && pEntry->dwCountryNameOffset) {
  480. wsprintf(buffer, TEXT("%s (%d)"),
  481. (PBYTE) pLineCountryList + pEntry->dwCountryNameOffset,
  482. pEntry->dwCountryCode);
  483. SendMessage(hwndList,
  484. CB_SETITEMDATA,
  485. SendMessage(hwndList, CB_ADDSTRING, 0, (LPARAM) buffer),
  486. pEntry->dwCountryID);
  487. }
  488. }
  489. }
  490. //
  491. // Insert None as the very first selection
  492. //
  493. //LoadString(ghInstance, IDS_NO_COUNTRY, buffer, MAX_COUNTRY_NAME);
  494. //SendMessage(hwndList, CB_INSERTSTRING, 0, (LPARAM) buffer);
  495. //SendMessage(hwndList, CB_SETITEMDATA, 0, 0);
  496. //
  497. // Figure out which item in the list should be selected
  498. //
  499. if (pLineCountryList != NULL) {
  500. for (index=0; index <= pLineCountryList->dwNumCountries; index++) {
  501. if ((DWORD) SendMessage(hwndList, CB_GETITEMDATA, index, 0) == countryId)
  502. break;
  503. }
  504. if (index > pLineCountryList->dwNumCountries)
  505. index = countryId = 0;
  506. } else
  507. index = countryId = 0;
  508. SendMessage(hwndList, CB_SETCURSEL, index, 0);
  509. SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
  510. //
  511. // Update the associated area code text field
  512. //
  513. //UpdateAreaCodeField(hwndAreaCode, countryId);
  514. }
  515. VOID
  516. SelChangeCountryListBox(
  517. HWND hwndList,
  518. HWND hwndAreaCode
  519. )
  520. /*++
  521. Routine Description:
  522. Handle dialog selection changes in the country list box
  523. Arguments:
  524. hwndList - Handle to the country list box window
  525. hwndAreaCode - Handle to an associated area code text field
  526. Return Value:
  527. NONE
  528. --*/
  529. {
  530. UpdateAreaCodeField(hwndAreaCode, GetCountryListBoxSel(hwndList));
  531. }
  532. DWORD
  533. GetCountryListBoxSel(
  534. HWND hwndList
  535. )
  536. /*++
  537. Routine Description:
  538. Return the current selection of country list box
  539. Arguments:
  540. hwndList - Handle to the country list box window
  541. Return Value:
  542. Currently selected country ID
  543. --*/
  544. {
  545. INT msgResult;
  546. if ((msgResult = (INT)SendMessage(hwndList, CB_GETCURSEL, 0, 0)) == CB_ERR ||
  547. (msgResult = (INT)SendMessage(hwndList, CB_GETITEMDATA, msgResult, 0)) == CB_ERR)
  548. {
  549. return -1;
  550. }
  551. return msgResult;
  552. }
  553. BOOL
  554. DoTapiProps(
  555. HWND hDlg
  556. )
  557. {
  558. SHELLEXECUTEINFO shellExeInfo = {
  559. sizeof(SHELLEXECUTEINFO),
  560. SEE_MASK_NOCLOSEPROCESS,
  561. hDlg,
  562. L"Open",
  563. L"rundll32",
  564. L"shell32.dll,Control_RunDLL telephon.cpl",
  565. NULL,
  566. SW_SHOWNORMAL,
  567. };
  568. //
  569. // if they said yes, then launch the control panel applet
  570. //
  571. if (!ShellExecuteEx(&shellExeInfo)) {
  572. DisplayMessageDialog(hDlg, 0, 0, IDS_ERR_TAPI_CPL_LAUNCH);
  573. return FALSE;
  574. }
  575. WaitForSingleObject( shellExeInfo.hProcess, INFINITE );
  576. CloseHandle( shellExeInfo.hProcess ) ;
  577. return TRUE;
  578. }