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.

1074 lines
33 KiB

  1. /*
  2. - util.c
  3. -
  4. * Microsoft At Work Fax Messaging Address Book
  5. *
  6. * Revision History:
  7. *
  8. * When Who What
  9. * -------- ------------------ ---------------------------------------
  10. * 7.24.96 Rick Turner ported from old code in fax tree
  11. *
  12. */
  13. /* ***************************************************************************/
  14. /* inculde files */
  15. #include "faxab.h"
  16. /*******************************
  17. **** Utility Functions ****
  18. *******************************/
  19. // ***************************************************************************
  20. // GetCurrentLocationAreaCode *
  21. // Get the area code for the current location *
  22. // returns: the area code of the current location or "" if error *
  23. //
  24. TCHAR g_szAreaCode[ AREA_CODE_SIZE ];
  25. DWORD g_dwTlsIndex; // index for private thread storage
  26. LPTSTR GetCurrentLocationAreaCode()
  27. {
  28. LPLINETRANSLATECAPS lpLineTransCaps;
  29. DWORD lResult, dwNumLocs;
  30. LPLINELOCATIONENTRY lplle, lplleCur;
  31. g_szAreaCode[0] = 0;
  32. /* allocate buffer */
  33. lpLineTransCaps = (LPLINETRANSLATECAPS)LocalAlloc(LPTR, 1024 );
  34. if (!lpLineTransCaps)
  35. {
  36. goto err;
  37. }
  38. lpLineTransCaps->dwTotalSize = 1024;
  39. /* try to get TranslateCaps */
  40. lResult = lineGetTranslateCaps( NULL, TAPI_CURRENT_VERSION, lpLineTransCaps);
  41. if (lResult != NO_ERROR)
  42. {
  43. goto err;
  44. }
  45. /* reallocate buffer if not big enough */
  46. while (lpLineTransCaps->dwNeededSize > lpLineTransCaps->dwTotalSize)
  47. {
  48. DWORD lcbNeeded = lpLineTransCaps->dwNeededSize;
  49. LocalFree(lpLineTransCaps);
  50. lpLineTransCaps = (LPLINETRANSLATECAPS)LocalAlloc(LPTR, lcbNeeded);
  51. if (!lpLineTransCaps)
  52. {
  53. goto err;
  54. }
  55. lpLineTransCaps->dwTotalSize = lcbNeeded;
  56. /* try one more time */
  57. lResult = lineGetTranslateCaps( NULL, TAPI_CURRENT_VERSION, lpLineTransCaps);
  58. if (lResult != NO_ERROR)
  59. {
  60. goto err;
  61. }
  62. } /* while */
  63. dwNumLocs = lpLineTransCaps->dwNumLocations;
  64. // get the name and area code of the current location
  65. lplle = (LPLINELOCATIONENTRY)((LPBYTE)(lpLineTransCaps) + lpLineTransCaps->dwLocationListOffset);
  66. lplleCur = lplle;
  67. while (dwNumLocs-- && lplleCur->dwPermanentLocationID != lpLineTransCaps->dwCurrentLocationID)
  68. ++lplleCur;
  69. // Save the current location information
  70. lstrcpyn( g_szAreaCode,
  71. (LPTSTR)((LPBYTE)(lpLineTransCaps) + lplleCur->dwCityCodeOffset),
  72. min(ARRAYSIZE(g_szAreaCode),lplleCur->dwCityCodeSize)
  73. );
  74. LocalFree( lpLineTransCaps );
  75. return g_szAreaCode;
  76. err:
  77. if (lpLineTransCaps != NULL)
  78. LocalFree(lpLineTransCaps);
  79. return NULL;
  80. } /* GetCurrentLocationAreaCode */
  81. // ***************************************************************************
  82. // GetCurrentLocationCountryID *
  83. // Get the area code for the current location *
  84. // returns: the country ID for the current location or 0 if error
  85. //
  86. DWORD GetCurrentLocationCountryID()
  87. {
  88. LPLINETRANSLATECAPS lpLineTransCaps;
  89. DWORD lResult, dwNumLocs, dwCountryID;
  90. LPLINELOCATIONENTRY lplle, lplleCur;
  91. /* allocate buffer */
  92. lpLineTransCaps = (LPLINETRANSLATECAPS)LocalAlloc(LPTR, 1024 );
  93. if (!lpLineTransCaps)
  94. {
  95. goto err;
  96. }
  97. lpLineTransCaps->dwTotalSize = 1024;
  98. /* try to get TranslateCaps */
  99. lResult = lineGetTranslateCaps( NULL, TAPI_CURRENT_VERSION, lpLineTransCaps);
  100. if (lResult != NO_ERROR)
  101. {
  102. goto err;
  103. }
  104. /* reallocate buffer if not big enough */
  105. while (lpLineTransCaps->dwNeededSize > lpLineTransCaps->dwTotalSize)
  106. {
  107. DWORD lcbNeeded = lpLineTransCaps->dwNeededSize;
  108. LocalFree(lpLineTransCaps);
  109. lpLineTransCaps = (LPLINETRANSLATECAPS)LocalAlloc(LPTR, lcbNeeded);
  110. if (!lpLineTransCaps)
  111. {
  112. goto err;
  113. }
  114. lpLineTransCaps->dwTotalSize = lcbNeeded;
  115. /* try one more time */
  116. lResult = lineGetTranslateCaps( NULL, TAPI_CURRENT_VERSION, lpLineTransCaps);
  117. if (lResult != NO_ERROR)
  118. {
  119. goto err;
  120. }
  121. } /* while */
  122. dwNumLocs = lpLineTransCaps->dwNumLocations;
  123. // get the name and area code of the current location
  124. lplle = (LPLINELOCATIONENTRY)((LPBYTE)(lpLineTransCaps) + lpLineTransCaps->dwLocationListOffset);
  125. lplleCur = lplle;
  126. while (dwNumLocs-- && lplleCur->dwPermanentLocationID != lpLineTransCaps->dwCurrentLocationID)
  127. ++lplleCur;
  128. dwCountryID = lplleCur->dwCountryID;
  129. LocalFree( lpLineTransCaps );
  130. return dwCountryID;
  131. err:
  132. if (lpLineTransCaps != NULL)
  133. LocalFree(lpLineTransCaps);
  134. return 0;
  135. } /* GetCurrentLocationCountryID */
  136. /* ***************************************************************************
  137. * GetCountry
  138. *
  139. * - gets the a country or a country list from TAPI
  140. *
  141. * Parameters: dwReqCountryID - a TAPI country ID. 0 for all countries
  142. *
  143. * Returns: TRUE on success, FALSE on failure.
  144. */
  145. #define SIZE_OF_ONE_COUNTRY_BUFFER 150 // current number is 110
  146. #define SIZE_OF_ALL_COUNTRIES_BUFFER 17000 // current number is 15694
  147. BOOL GetCountry(DWORD dwReqCountryID, LPLINECOUNTRYLIST *lppLineCountryList)
  148. {
  149. ULONG ulMemNeeded;
  150. WORD i;
  151. LONG lError = NO_ERROR;
  152. LPLINECOUNTRYLIST lpLineCountryList = NULL;
  153. BOOL bResult = TRUE;
  154. // See what size of a buffer I need to allocate
  155. ulMemNeeded = (dwReqCountryID ? SIZE_OF_ONE_COUNTRY_BUFFER : SIZE_OF_ALL_COUNTRIES_BUFFER);
  156. // Try to allocate buffer and call lineGetCountry twice
  157. // If this does not work, allocate a buffer of the size
  158. // requested by TAPI and try again
  159. for (i=0; i < 2; i++)
  160. {
  161. // Allocate memory for the LINECOUNTRYLIST structure
  162. lpLineCountryList = (LPLINECOUNTRYLIST)LocalAlloc( LPTR, ulMemNeeded );
  163. if (!lpLineCountryList)
  164. {
  165. DEBUG_TRACE("GetCountry: could not alloc buffer(%d) for LPLINECOUNTRYLIST\n", i);
  166. goto err;
  167. }
  168. // Set the size of the provided buffer for TAPI
  169. lpLineCountryList->dwTotalSize = ulMemNeeded;
  170. // Get the country inofmration for the requested country
  171. lError = lineGetCountry(dwReqCountryID, TAPI_CURRENT_VERSION, lpLineCountryList);
  172. // I give up if error and it's not because the structure passed in was too small
  173. if ( (lError != NO_ERROR) &&
  174. (lError != LINEERR_STRUCTURETOOSMALL) &&
  175. // Remove next line after TAPI fixes bug
  176. (lError != LINEERR_NOMEM)
  177. )
  178. {
  179. DEBUG_TRACE("GetCountry: lineGetCountry returned error %lx\n", lError);
  180. goto err;
  181. }
  182. // If I didn't get it all, free the buffer and try again with bigger size buffer
  183. if (lpLineCountryList->dwNeededSize > lpLineCountryList->dwTotalSize)
  184. {
  185. // +1 is due to TAPI bug. Exactly won't work
  186. ulMemNeeded = lpLineCountryList->dwNeededSize+1;
  187. LocalFree(lpLineCountryList);
  188. }
  189. else // got it
  190. break;
  191. }
  192. // should have valid lpLineCountryList here
  193. if (lError != NO_ERROR)
  194. goto err;
  195. DEBUG_TRACE("GetCountry: %lx of the buffer used\n", lpLineCountryList->dwUsedSize);
  196. out:
  197. *lppLineCountryList = lpLineCountryList;
  198. return bResult;
  199. err:
  200. // Free the buffer
  201. if (lpLineCountryList)
  202. LocalFree( lpLineCountryList );
  203. lpLineCountryList = NULL;
  204. bResult = FALSE;
  205. goto out;
  206. } /* GetCountry */
  207. /* ***************************************************************************
  208. * GetCountryCode
  209. *
  210. * - gets a country code when given a country ID
  211. *
  212. * Parameters: dwReqCountryID - a TAPI country ID
  213. * lpdwCountryCode - an address of a DWORD in which to store the country code
  214. *
  215. * Returns: TRUE on success, FALSE on failure.
  216. */
  217. BOOL GetCountryCode(DWORD dwReqCountryID, DWORD *lpdwCountryCode)
  218. {
  219. ULONG country;
  220. LPLINECOUNTRYLIST lpLineCountryList = NULL;
  221. LPLINECOUNTRYENTRY lprgLineCountryEntry = NULL;
  222. BOOL bResult = FALSE;
  223. // Get the country info structure from TAPI
  224. if (!GetCountry(dwReqCountryID, &lpLineCountryList))
  225. goto out;
  226. // Point to the first country in the structure
  227. lprgLineCountryEntry =
  228. (LPLINECOUNTRYENTRY)((LPBYTE)(lpLineCountryList)
  229. + lpLineCountryList->dwCountryListOffset);
  230. // Loop through LINECOUNTRYENTRY structures and look for the country ID.
  231. for (country=0; country < lpLineCountryList->dwNumCountries; country++)
  232. if ( (lprgLineCountryEntry[country].dwCountryNameSize != 0) &&
  233. (lprgLineCountryEntry[country].dwCountryNameOffset != 0)
  234. )
  235. {
  236. DWORD dwCountryCode = lprgLineCountryEntry[country].dwCountryCode;
  237. DWORD dwCountryID = lprgLineCountryEntry[country].dwCountryID;
  238. // If this is the requested country, get its country code
  239. if (dwCountryID == dwReqCountryID)
  240. {
  241. *lpdwCountryCode = dwCountryCode;
  242. bResult = TRUE;
  243. break;
  244. }
  245. }
  246. out:
  247. // Free the buffer
  248. if (lpLineCountryList)
  249. LocalFree( lpLineCountryList );
  250. if (!bResult)
  251. *lpdwCountryCode = 1; // U.S.
  252. return bResult;
  253. } /* GetCountryCode */
  254. /****************************************************************************
  255. FUNCTION: MakeMessageBox
  256. PURPOSE: Gets resource string and displays an error message box.
  257. PARAMETERS: hInst - Instnace of the caller (for getting strings)
  258. hWnd - Handle to parent window
  259. ulResult - Result/Status code
  260. 0: information message
  261. 100-499: warning message
  262. 500 and up: error message
  263. idString - Resource ID of message in StringTable
  264. fStyle - style of the message box
  265. RETURNS: the return value from MessageBox() function
  266. ****************************************************************************/
  267. int MakeMessageBox(HINSTANCE hInst, HWND hWnd, DWORD ulResult, UINT idString, UINT fStyle, ...)
  268. {
  269. va_list va;
  270. TCHAR szMessage[512]=TEXT("");
  271. TCHAR szTempBuf[400];
  272. TCHAR szTitle[128];
  273. TCHAR szAppName[MAX_PATH];
  274. // Get the application name from the resource file
  275. LoadString (hInst, IDS_APP_NAME, szAppName, MAX_PATH);
  276. // Do the title: 0: information message, 100-499: warning, 500 and up: critical (real error)
  277. // Also, if an error msg, load the standard MAWF error message
  278. if (ulResult == 0)
  279. {
  280. lstrcpy(szMessage, TEXT(""));
  281. LoadString (hInst, IDS_INFORMATION_MESSAGE, szTempBuf, 128);
  282. }
  283. else // Error or warning
  284. {
  285. if ((ulResult >= 100) && (ulResult < 500))
  286. {
  287. // Warning
  288. lstrcpy(szMessage, TEXT(""));
  289. LoadString (hInst, IDS_WARNING_MESSAGE, szTempBuf, 128);
  290. }
  291. else // Error
  292. {
  293. // If an error msg, load the standard MAWF error message
  294. LoadString (hInst, MAWF_E_GENERIC, szMessage, 64);
  295. LoadString (hInst, IDS_CRITICAL_MESSAGE, szTempBuf, 128);
  296. }
  297. }
  298. // Add a 'Microsoft At Work Fax' to the title
  299. lstrcpy(szTitle, szAppName);
  300. lstrcat(szTitle, TEXT(": "));
  301. lstrcat(szTitle, szTempBuf);
  302. // If there is a string ID, load the string from the resource file
  303. if (idString)
  304. {
  305. TCHAR szFormat[400];
  306. // Point to the first optional parameter. fStyle is the last required parameter
  307. va_start(va, fStyle);
  308. LoadString (hInst, idString, szFormat, 255);
  309. wvsprintf(szTempBuf, szFormat, va);
  310. va_end(va);
  311. lstrcat (szMessage, szTempBuf);
  312. }
  313. return(MessageBox (hWnd, szMessage, szTitle, fStyle));
  314. }
  315. /* ***************************************************************************
  316. * EncodeFaxAddress
  317. *
  318. * - encodes fax address components into the format name@+country-code (area-code) fax-number
  319. *
  320. * Parameters: lpszFaxAddr - address of a buffer in which to fill the encoded fax number
  321. * lpParsedFaxAddr - an address of a PARSEDTELNUMBER structure which contains
  322. * the components of the address that need to be encoded
  323. *
  324. * Returns: TRUE on success, FALSE on failure.
  325. *
  326. * CHECK: will need localization
  327. */
  328. BOOL EncodeFaxAddress(LPTSTR lpszFaxAddr, LPPARSEDTELNUMBER lpParsedFaxAddr)
  329. {
  330. // somewhat validate parameters
  331. if (!lpszFaxAddr)
  332. return FALSE;
  333. if (!lpParsedFaxAddr)
  334. return FALSE;
  335. // initialize the encoded string to an empty string
  336. lstrcpy(lpszFaxAddr, TEXT(""));
  337. // start with routing name and @, if any
  338. if ((lpParsedFaxAddr->szRoutingName) && (lstrlen(lpParsedFaxAddr->szRoutingName) != 0))
  339. {
  340. lstrcat(lpszFaxAddr, lpParsedFaxAddr->szRoutingName);
  341. lstrcat(lpszFaxAddr, TEXT("@"));
  342. }
  343. // must have a country code
  344. if (lpParsedFaxAddr->szCountryCode)
  345. {
  346. // if the country code is not 0, start an canonical address
  347. // a 0 country code is a special case, and address generated won't be canonincal
  348. if ( (lstrlen(lpParsedFaxAddr->szCountryCode) != 0) &&
  349. (lstrcmp(lpParsedFaxAddr->szCountryCode, TEXT("0")))
  350. )
  351. {
  352. lstrcat(lpszFaxAddr, TEXT("+"));
  353. lstrcat(lpszFaxAddr, lpParsedFaxAddr->szCountryCode);
  354. lstrcat(lpszFaxAddr, TEXT(" "));
  355. }
  356. }
  357. else
  358. {
  359. goto err;
  360. }
  361. // area code is optional
  362. if ((lpParsedFaxAddr->szAreaCode) && (lstrlen(lpParsedFaxAddr->szAreaCode) != 0))
  363. {
  364. lstrcat(lpszFaxAddr, TEXT("("));
  365. lstrcat(lpszFaxAddr, lpParsedFaxAddr->szAreaCode);
  366. lstrcat(lpszFaxAddr, TEXT(")"));
  367. lstrcat(lpszFaxAddr, TEXT(" "));
  368. }
  369. // must have a telephone number
  370. if ((lpParsedFaxAddr->szTelNumber) && (lstrlen(lpParsedFaxAddr->szTelNumber) != 0))
  371. {
  372. lstrcat(lpszFaxAddr, lpParsedFaxAddr->szTelNumber);
  373. }
  374. else
  375. {
  376. goto err;
  377. }
  378. #ifdef UNICODE
  379. {
  380. CHAR szDebug[ MAX_PATH ];
  381. szDebug[0] = 0;
  382. WideCharToMultiByte( CP_ACP, 0, lpszFaxAddr, -1, szDebug, ARRAYSIZE(szDebug), NULL, NULL );
  383. DEBUG_TRACE("EncodeFaxAddress: Canonical number: %s\n", szDebug);
  384. }
  385. #else
  386. DEBUG_TRACE("EncodeFaxAddress: Canonical number: %s\n", lpszFaxAddr);
  387. #endif
  388. return TRUE;
  389. err:
  390. lstrcpy(lpszFaxAddr, TEXT(""));
  391. return FALSE;
  392. } /* EncodeFaxAddress */
  393. /* ***************************************************************************
  394. * DecodeFaxAddress
  395. *
  396. * - parses a fax address of the format name@+country-code (area-code) fax-number
  397. *
  398. * Parameters: lpszFaxAddr - a Fax address in the above format
  399. * lpParsedFaxAddr - an address of a PARSEDTELNUMBER structure in which to
  400. * fill the parsed information
  401. *
  402. * Returns: TRUE on success, FALSE on failure.
  403. * success: full address
  404. * no routing name
  405. * no area code
  406. * failure: no '+country-code '
  407. * no telephone number
  408. *
  409. * CHECK: will need localization
  410. */
  411. enum tAddrComp {error, country_code, area_code, tel_number};
  412. BOOL DecodeFaxAddress(LPTSTR lpszFaxAddr, LPPARSEDTELNUMBER lpParsedFaxAddr)
  413. {
  414. TCHAR szTempBuf[sizeof(PARSEDTELNUMBER)] = {TEXT("")};
  415. BOOL fRoutingNameAllowed = TRUE;
  416. BOOL fAreaCodeAllowed = TRUE;
  417. BOOL bResult = FALSE;
  418. LPTSTR lpszTempBuf = szTempBuf;
  419. enum tAddrComp nWhatStarted = tel_number;
  420. WORD i;
  421. // somewhat validate parameters
  422. if (!lpszFaxAddr)
  423. return FALSE;
  424. if (!lpParsedFaxAddr)
  425. return FALSE;
  426. // Initialize to empty string values
  427. lstrcpy(lpParsedFaxAddr->szCountryCode, TEXT(""));
  428. lstrcpy(lpParsedFaxAddr->szAreaCode, TEXT(""));
  429. lstrcpy(lpParsedFaxAddr->szTelNumber, TEXT(""));
  430. lstrcpy(lpParsedFaxAddr->szRoutingName, TEXT(""));
  431. // if the string empty, nothing to do
  432. // (else, even if I don't find any "special" charachters in the string,
  433. // I'll stash whatever is in there into the telephone number)
  434. if (!lstrlen(lpszFaxAddr))
  435. return TRUE;
  436. // Scan once through the address. disallow fields as you progress
  437. for (i=0; lpszFaxAddr[i] != 0; i++)
  438. {
  439. switch (lpszFaxAddr[i])
  440. {
  441. case TEXT('@'): // maybe the end of a mailbox name string, or just a @ in the name
  442. if (fRoutingNameAllowed)
  443. {
  444. LPTSTR lpszTemp;
  445. // is this the last @ in the number string ?
  446. #ifdef UNICODE
  447. lpszTemp = wcschr(lpszFaxAddr, TEXT('@'));
  448. #else
  449. lpszTemp = _mbsrchr(lpszFaxAddr, TEXT('@'));
  450. #endif
  451. if (lpszTemp == &(lpszFaxAddr[i]))
  452. {
  453. // end of mailbox name. beginning of "real" canonical number
  454. lstrcpy(lpParsedFaxAddr->szRoutingName, szTempBuf);
  455. lpszTempBuf = szTempBuf;
  456. }
  457. else
  458. {
  459. // not the end of the mailbox name yet. just continue.
  460. *(lpszTempBuf++) = lpszFaxAddr[i];
  461. *(lpszTempBuf) = 0;
  462. }
  463. }
  464. break;
  465. case TEXT('+'):
  466. // next thing in the string should be the country code
  467. // if there is a '+', I do not allow @ sign to be interpreted as a special character
  468. fRoutingNameAllowed = FALSE;
  469. lpszTempBuf = szTempBuf;
  470. nWhatStarted = country_code;
  471. break;
  472. case TEXT('-'):
  473. switch (nWhatStarted)
  474. {
  475. case country_code:
  476. lstrcpy(lpParsedFaxAddr->szCountryCode, szTempBuf);
  477. lpszTempBuf = szTempBuf;
  478. nWhatStarted = area_code;
  479. lstrcpy(szTempBuf, TEXT(""));
  480. break;
  481. case area_code:
  482. lstrcpy (lpParsedFaxAddr->szAreaCode, szTempBuf);
  483. lpszTempBuf = szTempBuf;
  484. nWhatStarted = tel_number;
  485. break;
  486. default: // for any other character, store in a temp buffer
  487. *(lpszTempBuf++) = lpszFaxAddr[i];
  488. *(lpszTempBuf) = 0;
  489. break;
  490. }
  491. break;
  492. case TEXT('('):
  493. // next thing in the string should be the area code
  494. if (fAreaCodeAllowed)
  495. {
  496. lpszTempBuf = szTempBuf;
  497. nWhatStarted = area_code;
  498. }
  499. break;
  500. case TEXT(')'):
  501. // copy without the ()
  502. if ((fAreaCodeAllowed) && (nWhatStarted == area_code))
  503. {
  504. lstrcpy(lpParsedFaxAddr->szAreaCode, szTempBuf);
  505. // advance beyond the space that follows the ')'
  506. i++;
  507. lpszTempBuf = szTempBuf;
  508. nWhatStarted = tel_number;
  509. fAreaCodeAllowed = FALSE;
  510. }
  511. break;
  512. case TEXT(' '):
  513. // this ends something
  514. if (nWhatStarted == country_code)
  515. {
  516. lstrcpy(lpParsedFaxAddr->szCountryCode, szTempBuf);
  517. lpszTempBuf = szTempBuf;
  518. nWhatStarted = tel_number; // may be overriden be area code, if any
  519. // if next character is not '(', I disallow area code
  520. if (lpszFaxAddr[i+1] != '(')
  521. fAreaCodeAllowed = FALSE;
  522. break;
  523. }
  524. else if (nWhatStarted == area_code)
  525. {
  526. // should not happen
  527. DEBUG_TRACE("DecodeFaxAddress: bad address. space in area code\n");
  528. return FALSE;
  529. }
  530. else;
  531. // Spaces are allowed in the mailbox or the phone number,
  532. // so I fall through to the default case
  533. default: // for any other character, store in a temp buffer
  534. *(lpszTempBuf++) = lpszFaxAddr[i];
  535. *(lpszTempBuf) = 0;
  536. break;
  537. } // switch (lpszFaxAddr[i])
  538. } // for
  539. // End of address string. Last component must be the telephone number
  540. if (nWhatStarted == tel_number)
  541. {
  542. lstrcpy(lpParsedFaxAddr->szTelNumber, szTempBuf);
  543. bResult = TRUE;
  544. }
  545. else
  546. {
  547. // we also get here on empty input string
  548. bResult = FALSE;
  549. }
  550. return bResult;
  551. } /* DecodeFaxAddress */
  552. #ifdef DO_WE_REALLY_NEED_TAPI
  553. /****************************************************************************
  554. FUNCTION: DoThreadAttach()
  555. PURPOSE: does the thread attach (DLL_THREAD_ATTACH) actions
  556. PARAMETERS: [in/out] lppPTGData - address where to put the thread's private
  557. storage pointer
  558. RETURNS: TRUE on success, FALSE on failure
  559. ****************************************************************************/
  560. BOOL DoThreadAttach(LPPTGDATA *lppPTGData)
  561. {
  562. LPPTGDATA lpPTGData=NULL;
  563. // initialize the TLS index for this thread
  564. lpPTGData = (LPPTGDATA) LocalAlloc(LPTR, sizeof(PTGDATA));
  565. if (lpPTGData)
  566. {
  567. TlsSetValue(dwTlsIndex, lpPTGData);
  568. }
  569. else
  570. {
  571. DEBUG_TRACE("DoThreadAttach: LocalAlloc() failed for thread %x\n", GetCurrentThreadId());
  572. goto error;
  573. }
  574. /*
  575. * initilialize the per-thread data
  576. */
  577. RtlZeroMemory((PVOID) lpPTGData, sizeof(PTGDATA));
  578. // initialize the critical section that is used to control access to hInst
  579. // to make sure this thread does not call us again
  580. InitializeCriticalSection(&(pt_csInstance));
  581. // initialize allocations array
  582. if (!InitAllocations())
  583. {
  584. DEBUG_TRACE("DoThreadAttach: InitAllocations failed\n");
  585. goto error;
  586. }
  587. // allocate and initialize the TAPI state structure
  588. if (MAWFAllocBuff(SIZEOF(DTS), &pt_lpVdts))
  589. {
  590. DEBUG_TRACE("DoThreadAttach: allocation of vdts failed\n");
  591. goto error;
  592. }
  593. RtlZeroMemory((PVOID) pt_lpVdts, SIZEOF(DTS));
  594. pt_lpVdts->dwCurrentLocationID = (DWORD)-1;
  595. lpPTGData->iLastDeviceAdded=LINEID_NONE; // what kind of device was last added
  596. *lppPTGData = lpPTGData;
  597. return TRUE;
  598. error:
  599. *lppPTGData = NULL;
  600. return FALSE;
  601. }
  602. /****************************************************************************
  603. FUNCTION: GetThreadStoragePointer()
  604. PURPOSE: gets the private storage pointer for a thread, allocating one
  605. if it does not exist (i.e. the thread didn't go through LibMain
  606. THREAD_ATTACH)
  607. PARAMETERS: none
  608. RETURNS: a pointer to the thread's private storage
  609. NULL, if there was a failure (usually memory allocation failure)
  610. ****************************************************************************/
  611. LPPTGDATA GetThreadStoragePointer()
  612. {
  613. LPPTGDATA lpPTGData=TlsGetValue(dwTlsIndex);
  614. // if the thread does not have a private storage, it did not go through
  615. // THREAD_ATTACH and we need to do this here.
  616. if (!lpPTGData)
  617. {
  618. DEBUG_TRACE("GetThreadStoragePointer: no private storage for this thread %x\n",
  619. GetCurrentThreadId());
  620. if (!DoThreadAttach(&lpPTGData))
  621. lpPTGData = NULL;
  622. }
  623. return lpPTGData;
  624. }
  625. /* ***************************************************************************
  626. * InitTAPI
  627. *
  628. * initializes TAPI by calling lineInitialize. enumerates all the available
  629. * lines to set up pt_lpVdts->lprgLineInfo. also opens up each available line for
  630. * monitoring. sets up pt_lpVdts->iLineCur and pt_lpVdts->iAddrCur by checking the
  631. * preferred line/address name stored in the ini file against the available
  632. * line/address names.
  633. *
  634. * Parameters: hInst - the instance of the calling module
  635. * hWnd - window handle for UI
  636. * lpszAppName - the name of the calling module
  637. *
  638. * returns NO_ERROR if success and the corresponding error code otherwise.
  639. */
  640. DWORD
  641. InitTAPI( HINSTANCE hInst,
  642. HWND hWnd,
  643. LPTSTR lpszAppName
  644. )
  645. {
  646. LONG lResult;
  647. LONG lResultLine = NO_ERROR;
  648. DWORD iLine, iLineVoiceFirst = (DWORD)-1;
  649. #ifdef LINE_ADDRESSES
  650. DWORD iAddr, cAddr;
  651. LPLINEADDRESSCAPS lpAddrCaps = NULL;
  652. CHAR szPreferedAddress[cchAddrNameMac];
  653. #endif
  654. LPPTGDATA lpPTGData = GetThreadStoragePointer();
  655. CHECK_THREAD_STORAGE_POINTER(lpPTGData, "InitTAPI", LINEERR_NOMEM);
  656. /***************************************
  657. ********* initialize tapi *************
  658. ***************************************/
  659. DEBUG_TRACE("InitTAPI: thread %x is initializing\n", GetCurrentThreadId());
  660. DEBUG_TRACE("InitTAPI: cRefCount is %d\n", pt_lpVdts->cRefCount);
  661. // see if this thread already initialized TAPI
  662. if (pt_lpVdts->cRefCount)
  663. {
  664. lResult = NO_ERROR;
  665. goto LDone;
  666. }
  667. if ((lResult = TAPIBasicInit(hInst, hWnd, lpszAppName)) != NO_ERROR)
  668. goto LDone;
  669. /***************************************
  670. ********* initialize lines ************
  671. ***************************************/
  672. // initialize pt_lpVdts->lpgrLineInfo and open each available line for
  673. // monitoring
  674. // allocate buffer for storing LINEINFO for all the available lines
  675. pt_lpVdts->lprgLineInfo = (LPLINEINFO)_fmalloc(SIZEOF(LINEINFO)*(int)pt_lpVdts->cLines);
  676. if (pt_lpVdts->lprgLineInfo == NULL)
  677. {
  678. lResult = LINEERR_NOMEM;
  679. goto LDone;
  680. }
  681. _fmemset(pt_lpVdts->lprgLineInfo,0,SIZEOF(LINEINFO)*(int)pt_lpVdts->cLines);
  682. // init pt_lpVdts->lprgLineInfo and open each line to get its caps
  683. // also count the fax lines
  684. pt_lpVdts->cFaxLines = 0;
  685. for (iLine = 0; iLine < pt_lpVdts->cLines; ++iLine)
  686. {
  687. // Open the line and get its capabilities, including its name
  688. lResult = GetCachedLineInfo(iLine);
  689. if (lResult != NO_ERROR)
  690. {
  691. // something went wrong with initializing a line that TAPI told me
  692. // should be OK
  693. // I save the lResult (but doing nothing with it for now)
  694. // and continue with other lines. This line does not get enumerated.
  695. lResultLine = lResult;
  696. // this does not mean InitTAPI failed
  697. lResult = NO_ERROR;
  698. continue;
  699. // goto LDone;
  700. }
  701. if ( (iLineVoiceFirst == (DWORD)-1) &&
  702. pt_lpVdts->lprgLineInfo[iLine].fIsVoiceLine
  703. )
  704. {
  705. iLineVoiceFirst = iLine;
  706. }
  707. // if it's a fax line, count it in
  708. if (pt_lpVdts->lprgLineInfo[iLine].fIsVoiceLine)
  709. // CHECK: && fIsFaxDevice))
  710. {
  711. pt_lpVdts->cFaxLines++;
  712. }
  713. } // for
  714. // No reason to proceed if no Fax lines
  715. if (pt_lpVdts->cFaxLines == 0)
  716. {
  717. /* no voice line, too bad */
  718. lResult = ERROR_NO_LINES;
  719. pt_lpVdts->iLineCur = NO_MODEM;
  720. goto LDone;
  721. }
  722. // If no current line and there is a voice line, set the current line to be this voice line
  723. // This code is probably not needed, as I later (InitLineDeviceLB()) set the current line
  724. // from the profile
  725. else if (pt_lpVdts->iLineCur == NO_MODEM)
  726. {
  727. pt_lpVdts->iLineCur = iLineVoiceFirst;
  728. }
  729. #ifdef LINE_ADDRESSES
  730. /* **************************************************/
  731. /* init pt_lpVdts->iAddrCur */
  732. // Set the line address to a default value of 0 (the only one currently supported)
  733. pt_lpVdts->iAddrCur = 0;
  734. // allocate buffer for the lineGetAddressCaps calls
  735. if ((lpAddrCaps = (LPLINEADDRESSCAPS)_fmalloc(lcbAddrDevCapsInitial))
  736. == NULL)
  737. {
  738. lResult = LINEERR_NOMEM;
  739. goto LDone;
  740. }
  741. lpAddrCaps->dwTotalSize = lcbAddrDevCapsInitial;
  742. // enumerate all the available addresses to match szPreferedAddress with
  743. // an address name
  744. cAddr = pt_lpVdts->lprgLineInfo[pt_lpVdts->iLineCur].cAddr;
  745. for (iAddr = 0; iAddr < cAddr; ++iAddr)
  746. {
  747. char szAddrName[cchAddrNameMac];
  748. LPTSTR lpszAddrName;
  749. // get address capability info
  750. lResult = lineGetAddressCaps( pt_lpVdts->hApp,
  751. pt_lpVdts->iLineCur,
  752. iAddr,
  753. tapiVersionCur,
  754. 0,
  755. lpAddrCaps
  756. );
  757. if (lResult != NO_ERROR)
  758. goto LDone;
  759. // reallocate buffer if not big enough
  760. while (lpAddrCaps->dwNeededSize > lpAddrCaps->dwTotalSize)
  761. {
  762. DWORD lcbNeeded = lpAddrCaps->dwNeededSize;
  763. _ffree(lpAddrCaps);
  764. if ((lpAddrCaps = (LPLINEADDRESSCAPS)_fmalloc((size_t)lcbNeeded))
  765. == NULL)
  766. {
  767. lResult = LINEERR_NOMEM;
  768. goto LDone;
  769. }
  770. lpAddrCaps->dwTotalSize = lcbNeeded;
  771. /* try it one more time */
  772. lResult = lineGetAddressCaps( pt_lpVdts->hApp,
  773. pt_lpVdts->iLineCur,
  774. iAddr,
  775. tapiVersionCur,
  776. 0,
  777. lpAddrCaps
  778. );
  779. if (lResult != NO_ERROR)
  780. goto LDone;
  781. } /* while */
  782. /* get the address's name */
  783. if (lpAddrCaps->dwAddressSize > 0)
  784. lpszAddrName = (LPTSTR)((LPBYTE)(lpAddrCaps)+lpAddrCaps->dwAddressOffset);
  785. else
  786. {
  787. /* use default name */
  788. TCHAR szAddrFormat[32];
  789. LoadString( hInst,
  790. IDS_TAPI_LINE_NAME,
  791. szAddrFormat,
  792. ARRAYSIZEf(szAddrFormat)
  793. );
  794. wsprintf(szAddrName,szAddrFormat,iAddr);
  795. lpszAddrName = (LPTSTR)szAddrName;
  796. } /* else */
  797. if (lstrcmpi(lpszAddrName,szPreferedAddress) == 0)
  798. {
  799. pt_lpVdts->iAddrCur = iAddr;
  800. break;
  801. } /* if */
  802. } /* for */
  803. #endif // #ifdef LINE_ADDRESSES
  804. lResult = NO_ERROR;
  805. LDone:
  806. // free up memory allocated
  807. #ifdef LINE_ADDRESSES
  808. if (lpAddrCaps)
  809. _ffree(lpAddrCaps);
  810. #endif
  811. // if InitTAPI succeeded, bump up the ref count
  812. if ( (lResult == NO_ERROR) ||
  813. (lResult == ERROR_NO_LINES)
  814. )
  815. {
  816. pt_lpVdts->cRefCount++;
  817. }
  818. // else, free unneeded memory
  819. else if (pt_lpVdts->lprgLineInfo)
  820. {
  821. _ffree(pt_lpVdts->lprgLineInfo);
  822. pt_lpVdts->lprgLineInfo = NULL;
  823. }
  824. return lResult;
  825. } /* InitTAPI */
  826. /****************************************************************************
  827. * DeinitTAPI
  828. *
  829. * frees up the memory allocated, closes all the lines we have opened for
  830. * monitoring and calls lineShutDown to disconnect from TAPI.
  831. */
  832. BOOL DeinitTAPI()
  833. {
  834. LPPTGDATA lpPTGData = GetThreadStoragePointer();
  835. CHECK_THREAD_STORAGE_POINTER(lpPTGData, "DeinitTAPI", 0xffffffff);
  836. DEBUG_TRACE("DeinitTAPI: thread %x is deinitializing\n", GetCurrentThreadId());
  837. // if ref count is already 0, unbalanced calls, do nothing
  838. if (!(pt_lpVdts->cRefCount))
  839. return TRUE;
  840. // don't want to deinit if ref count is still > 0
  841. if (--pt_lpVdts->cRefCount)
  842. return TRUE;
  843. /* never mind if lineInitialize failed in the first place */
  844. if (!pt_lpVdts->fLineInited)
  845. return TRUE;
  846. /* unregister STAPI */
  847. FRegisterSimpleTapi(FALSE);
  848. /* closes all the open lines and free pt_lpVdts->lprgLineInfo */
  849. if (pt_lpVdts->lprgLineInfo)
  850. {
  851. DWORD iLine;
  852. for (iLine = 0; iLine < pt_lpVdts->cLines; ++iLine)
  853. {
  854. DEBUG_TRACE( "Thread %x,DeinitTAPI: looking to close line %x...\n",
  855. GetCurrentThreadId(),
  856. iLine
  857. );
  858. if (pt_lpVdts->lprgLineInfo[iLine].dwAPIVersion == 0)
  859. continue;
  860. lineClose(pt_lpVdts->lprgLineInfo[iLine].hLine);
  861. DEBUG_TRACE( "Thread %x,DeinitTAPI: line %x is closed\n",
  862. GetCurrentThreadId(),
  863. iLine
  864. );
  865. } /* for */
  866. _ffree(pt_lpVdts->lprgLineInfo);
  867. } /* if */
  868. /* disconnect from TAPI */
  869. lineShutdown(pt_lpVdts->hApp);
  870. pt_lpVdts->hInst = NULL;
  871. return TRUE;
  872. } /* DeinitTAPI */
  873. #endif // DO_WE_REALLY_NEED_TAPI