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.

3160 lines
97 KiB

  1. /****************************************************************************
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name: location.cpp
  4. Abstract: Location Object implementation
  5. Author: noela - 09/11/98
  6. Notes:
  7. Rev History:
  8. ****************************************************************************/
  9. #include <windows.h>
  10. #include <objbase.h>
  11. #include "tapi.h"
  12. #include "tspi.h"
  13. #include "client.h"
  14. #include "location.h"
  15. #include "clntprivate.h"
  16. #include "countrygroup.h"
  17. #include <strsafe.h>
  18. #define MaxDialStringSize 500
  19. LONG PASCAL ReadCountries( LPLINECOUNTRYLIST *ppLCL,
  20. UINT nCountryID,
  21. DWORD dwDestCountryID
  22. );
  23. HRESULT ReadLocations( PLOCATIONLIST *ppLocationList,
  24. HLINEAPP hLineApp,
  25. DWORD dwDeviceID,
  26. DWORD dwAPIVersion,
  27. DWORD dwOptions
  28. );
  29. LONG PASCAL WriteLocations( PLOCATIONLIST pLocationList,
  30. DWORD dwChangedFlags
  31. );
  32. LONG BreakupCanonicalW( PWSTR pAddressIn,
  33. PWSTR *pCountry,
  34. PWSTR *pCity,
  35. PWSTR *pSubscriber
  36. );
  37. DWORD TapiPackString(LPBYTE pStructure,
  38. DWORD dwOffset,
  39. DWORD dwTotalSize,
  40. PWSTR pszString,
  41. PDWORD pdwOffset,
  42. PDWORD pdwSize
  43. );
  44. LONG AppendDigits( PWSTR pDest,
  45. PWSTR pSrc,
  46. PWSTR pValidChars
  47. );
  48. HRESULT CreateCountryObject(DWORD dwCountryID, CCountry **ppCountry);
  49. int IsCityRule(LPWSTR lpRule);
  50. LONG ApplyRule (PWSTR pszDialString,
  51. PWSTR pszDisplayString,
  52. PWSTR pszRule,
  53. PWSTR pszDestLDRule, // used for Area code adjustments
  54. PWSTR pszLongDistanceCarrier,
  55. PWSTR pszInternationalCarrier,
  56. PWSTR pszCountry,
  57. PWSTR pszCity,
  58. PWSTR pszSubscriber,
  59. PWSTR pCardName,
  60. PWSTR pCardAccessNumber,
  61. PWSTR pCardAccountNumber,
  62. PWSTR pCardPINNumber
  63. );
  64. BOOL PrefixMatch(PWSTR pszPrefix,PWSTR pszSubscriberString, PDWORD pdwMatched);
  65. BOOL AreaCodeMatch(PWSTR pszAreaCode1, PWSTR pszAreaCode2, PWSTR pszRule);
  66. PWSTR SkipLDAccessDigits(PWSTR pszAreaCode, PWSTR pszLDRule);
  67. #define LOCAL 1
  68. #define LONG_DISTANCE 2
  69. #define INTERNATIONAL 3
  70. const WCHAR csSCANTO[] = L"\r";
  71. const WCHAR csDISPSUPRESS[] = L"TtPp,Ww@?!$";
  72. const WCHAR csBADCO[] = L"AaBbCcDdPpTtWw*#!,@$?;()";
  73. const WCHAR csSCANSUB[] = L"^|/";
  74. /*
  75. ***************************************************************************
  76. ********************* ****************************
  77. ******************** CLocation Class ***************************
  78. ******************** Definitions ***************************
  79. ********************* ****************************
  80. ***************************************************************************
  81. */
  82. /****************************************************************************
  83. Class : CLocation
  84. Method : Constructer
  85. ****************************************************************************/
  86. CLocation::CLocation()
  87. {
  88. m_pszLocationName = NULL;
  89. m_pszLongDistanceAccessCode = NULL;
  90. m_pszLocalAccessCode = NULL;
  91. m_pszDisableCallWaitingCode = NULL;
  92. m_pszAreaCode = NULL;
  93. m_bFromRegistry = FALSE;
  94. m_bChanged = FALSE;
  95. m_dwNumRules = 0;
  96. m_hEnumNode = m_AreaCodeRuleList.head();
  97. m_pszTAPIDialingRule = NULL;
  98. }
  99. /****************************************************************************
  100. Class : CLocation
  101. Method : Destructer
  102. Clean up memory allocations
  103. ****************************************************************************/
  104. CLocation::~CLocation()
  105. {
  106. if ( m_pszLocationName != NULL )
  107. {
  108. ClientFree(m_pszLocationName);
  109. }
  110. if ( m_pszLongDistanceAccessCode != NULL )
  111. {
  112. ClientFree(m_pszLongDistanceAccessCode);
  113. }
  114. if ( m_pszLocalAccessCode != NULL )
  115. {
  116. ClientFree(m_pszLocalAccessCode);
  117. }
  118. if ( m_pszDisableCallWaitingCode != NULL )
  119. {
  120. ClientFree(m_pszDisableCallWaitingCode);
  121. }
  122. if ( m_pszAreaCode != NULL )
  123. {
  124. ClientFree(m_pszAreaCode);
  125. }
  126. if ( m_pszTAPIDialingRule != NULL )
  127. {
  128. ClientFree(m_pszTAPIDialingRule);
  129. }
  130. if (m_pszLongDistanceCarrierCode != NULL)
  131. {
  132. ClientFree (m_pszLongDistanceCarrierCode);
  133. }
  134. if (m_pszInternationalCarrierCode != NULL)
  135. {
  136. ClientFree (m_pszInternationalCarrierCode);
  137. }
  138. // clean up Area Code List
  139. AreaCodeRulePtrNode *node;
  140. node = m_AreaCodeRuleList.head();
  141. while( !node->beyond_tail() )
  142. {
  143. delete node->value();
  144. node = node->next();
  145. }
  146. m_AreaCodeRuleList.flush();
  147. }
  148. /****************************************************************************
  149. Class : CLocation
  150. Method : Initialize
  151. ****************************************************************************/
  152. STDMETHODIMP CLocation::Initialize
  153. (
  154. PWSTR pszLocationName,
  155. PWSTR pszAreaCode,
  156. PWSTR pszLongDistanceCarrierCode,
  157. PWSTR pszInternationalCarrierCode,
  158. PWSTR pszLongDistanceAccessCode,
  159. PWSTR pszLocalAccessCode,
  160. PWSTR pszDisableCallWaitingCode,
  161. DWORD dwLocationID,
  162. DWORD dwCountryID,
  163. DWORD dwPreferredCardID,
  164. DWORD dwOptions ,
  165. BOOL bFromRegistry
  166. )
  167. {
  168. m_pszLocationName = ClientAllocString( pszLocationName );
  169. if (m_pszLocationName == NULL)
  170. {
  171. LOG(( TL_ERROR, "Initialize - alloc m_pszLocationName failed" ));
  172. return E_OUTOFMEMORY;
  173. }
  174. m_pszLongDistanceAccessCode = ClientAllocString( pszLongDistanceAccessCode );
  175. if (m_pszLongDistanceAccessCode == NULL)
  176. {
  177. ClientFree(m_pszLocationName);
  178. LOG(( TL_ERROR, "Initialize - alloc m_pszLongDistanceAccessCode failed" ));
  179. return E_OUTOFMEMORY;
  180. }
  181. m_pszLocalAccessCode = ClientAllocString( pszLocalAccessCode );
  182. if (m_pszLocalAccessCode == NULL)
  183. {
  184. ClientFree(m_pszLocationName);
  185. ClientFree(m_pszLongDistanceAccessCode);
  186. LOG(( TL_ERROR, "Initialize - alloc m_pszLocalAccessCode failed" ));
  187. return E_OUTOFMEMORY;
  188. }
  189. m_pszDisableCallWaitingCode = ClientAllocString( pszDisableCallWaitingCode );
  190. if (m_pszDisableCallWaitingCode == NULL)
  191. {
  192. ClientFree(m_pszLocationName);
  193. ClientFree(m_pszLongDistanceAccessCode);
  194. ClientFree(m_pszLocalAccessCode);
  195. LOG(( TL_ERROR, "Initialize - alloc m_pszDisableCallWaitingCode failed" ));
  196. return E_OUTOFMEMORY;
  197. }
  198. m_pszAreaCode = ClientAllocString( pszAreaCode );
  199. if (m_pszAreaCode == NULL)
  200. {
  201. ClientFree(m_pszLocationName);
  202. ClientFree(m_pszLongDistanceAccessCode);
  203. ClientFree(m_pszLocalAccessCode);
  204. ClientFree(m_pszDisableCallWaitingCode);
  205. LOG(( TL_ERROR, "Initialize - alloc m_pszAreaCode failed" ));
  206. return E_OUTOFMEMORY;
  207. }
  208. m_pszLongDistanceCarrierCode = ClientAllocString( pszLongDistanceCarrierCode );
  209. if (m_pszLongDistanceCarrierCode == NULL)
  210. {
  211. ClientFree(m_pszLocationName);
  212. ClientFree(m_pszLongDistanceAccessCode);
  213. ClientFree(m_pszLocalAccessCode);
  214. ClientFree(m_pszDisableCallWaitingCode);
  215. ClientFree(m_pszAreaCode);
  216. LOG(( TL_ERROR, "Initialize - alloc m_pszLongDistanceCarrierCode failed" ));
  217. return E_OUTOFMEMORY;
  218. }
  219. m_pszInternationalCarrierCode = ClientAllocString( pszInternationalCarrierCode );
  220. if (m_pszInternationalCarrierCode == NULL)
  221. {
  222. ClientFree(m_pszLocationName);
  223. ClientFree(m_pszLongDistanceAccessCode);
  224. ClientFree(m_pszLocalAccessCode);
  225. ClientFree(m_pszDisableCallWaitingCode);
  226. ClientFree(m_pszAreaCode);
  227. ClientFree(m_pszLongDistanceCarrierCode);
  228. LOG(( TL_ERROR, "Initialize - alloc m_pszInternationalCarrierCode failed" ));
  229. return E_OUTOFMEMORY;
  230. }
  231. m_dwLocationID = dwLocationID;
  232. m_dwCountryID = dwCountryID ? dwCountryID : 1; // workaround for a bogus country ID
  233. m_dwPreferredCardID = dwPreferredCardID;
  234. m_dwOptions = dwOptions;
  235. m_bFromRegistry = bFromRegistry;
  236. if (m_bFromRegistry == FALSE)
  237. {
  238. m_bChanged = TRUE;
  239. }
  240. return S_OK;
  241. }
  242. /****************************************************************************
  243. Class : CLocation
  244. Method : UseCallWaiting
  245. ****************************************************************************/
  246. void CLocation::UseCallWaiting(BOOL bCw)
  247. {
  248. if(bCw)
  249. {
  250. m_dwOptions |= LOCATION_HASCALLWAITING;
  251. }
  252. else
  253. {
  254. m_dwOptions &= ~LOCATION_HASCALLWAITING;
  255. }
  256. m_bChanged = TRUE;
  257. }
  258. /****************************************************************************
  259. Class : CLocation
  260. Method : UseCallingCard
  261. ****************************************************************************/
  262. void CLocation::UseCallingCard(BOOL bCc)
  263. {
  264. if(bCc)
  265. {
  266. m_dwOptions |= LOCATION_USECALLINGCARD;
  267. }
  268. else
  269. {
  270. m_dwOptions &= ~LOCATION_USECALLINGCARD;
  271. }
  272. m_bChanged = TRUE;
  273. }
  274. /****************************************************************************
  275. Class : CLocation
  276. Method : UseToneDialing
  277. ****************************************************************************/
  278. void CLocation::UseToneDialing(BOOL bCc)
  279. {
  280. if(bCc)
  281. {
  282. m_dwOptions |= LOCATION_USETONEDIALING;
  283. }
  284. else
  285. {
  286. m_dwOptions &= ~LOCATION_USETONEDIALING;
  287. }
  288. m_bChanged = TRUE;
  289. }
  290. /****************************************************************************
  291. Class : CLocation
  292. Method : setName
  293. ****************************************************************************/
  294. STDMETHODIMP CLocation::SetName(PWSTR pszLocationName)
  295. {
  296. HRESULT hr = S_OK;
  297. if (m_pszLocationName != NULL)
  298. {
  299. ClientFree(m_pszLocationName);
  300. m_pszLocationName = NULL;
  301. }
  302. if(pszLocationName != NULL)
  303. {
  304. m_pszLocationName = ClientAllocString( pszLocationName );
  305. if (m_pszLocationName == NULL)
  306. {
  307. LOG(( TL_ERROR, "setName - alloc failed" ));
  308. hr = E_OUTOFMEMORY;
  309. }
  310. }
  311. m_bChanged = TRUE;
  312. return hr;
  313. }
  314. /****************************************************************************
  315. Class : CLocation
  316. Method : setAreaCode
  317. ****************************************************************************/
  318. STDMETHODIMP CLocation::SetAreaCode(PWSTR pszAreaCode)
  319. {
  320. HRESULT hr = S_OK;
  321. if (m_pszAreaCode != NULL)
  322. {
  323. ClientFree(m_pszAreaCode);
  324. m_pszAreaCode = NULL;
  325. }
  326. if(pszAreaCode != NULL)
  327. {
  328. m_pszAreaCode = ClientAllocString( pszAreaCode );
  329. if (m_pszAreaCode == NULL)
  330. {
  331. LOG(( TL_ERROR, "setAreaCode - alloc failed" ));
  332. hr = E_OUTOFMEMORY;
  333. }
  334. }
  335. m_bChanged = TRUE;
  336. return hr;
  337. }
  338. /****************************************************************************
  339. Class : CLocation
  340. Method : SetLongDistanceCarrierCode
  341. ****************************************************************************/
  342. STDMETHODIMP CLocation::SetLongDistanceCarrierCode(PWSTR pszLongDistanceCarrierCode)
  343. {
  344. HRESULT hr = S_OK;
  345. if (m_pszLongDistanceCarrierCode != NULL)
  346. {
  347. ClientFree(m_pszLongDistanceCarrierCode);
  348. m_pszLongDistanceCarrierCode = NULL;
  349. }
  350. if(pszLongDistanceCarrierCode != NULL)
  351. {
  352. m_pszLongDistanceCarrierCode = ClientAllocString( pszLongDistanceCarrierCode );
  353. if (m_pszLongDistanceCarrierCode == NULL)
  354. {
  355. LOG(( TL_ERROR, "setLongDistanceCarrierCode - alloc failed" ));
  356. hr = E_OUTOFMEMORY;
  357. }
  358. }
  359. m_bChanged = TRUE;
  360. return hr;
  361. }
  362. /****************************************************************************
  363. Class : CLocation
  364. Method : SetInternationalCarrierCode
  365. ****************************************************************************/
  366. STDMETHODIMP CLocation::SetInternationalCarrierCode(PWSTR pszInternationalCarrierCode)
  367. {
  368. HRESULT hr = S_OK;
  369. if (m_pszInternationalCarrierCode != NULL)
  370. {
  371. ClientFree(m_pszInternationalCarrierCode);
  372. m_pszInternationalCarrierCode = NULL;
  373. }
  374. if(pszInternationalCarrierCode != NULL)
  375. {
  376. m_pszInternationalCarrierCode = ClientAllocString( pszInternationalCarrierCode );
  377. if (m_pszInternationalCarrierCode == NULL)
  378. {
  379. LOG(( TL_ERROR, "setInternationalCarrierCode - alloc failed" ));
  380. hr = E_OUTOFMEMORY;
  381. }
  382. }
  383. m_bChanged = TRUE;
  384. return hr;
  385. }
  386. /****************************************************************************
  387. Class : CLocation
  388. Method : setLongDistanceAccessCode
  389. ****************************************************************************/
  390. STDMETHODIMP CLocation::SetLongDistanceAccessCode(PWSTR pszLongDistanceAccessCode)
  391. {
  392. HRESULT hr = S_OK;
  393. if (m_pszLongDistanceAccessCode != NULL)
  394. {
  395. ClientFree(m_pszLongDistanceAccessCode);
  396. m_pszLongDistanceAccessCode = NULL;
  397. }
  398. if(pszLongDistanceAccessCode != NULL)
  399. {
  400. m_pszLongDistanceAccessCode = ClientAllocString( pszLongDistanceAccessCode );
  401. if (m_pszLongDistanceAccessCode == NULL)
  402. {
  403. LOG(( TL_ERROR, "setLongDistanceAccessCode - alloc failed" ));
  404. hr = E_OUTOFMEMORY;
  405. }
  406. }
  407. m_bChanged = TRUE;
  408. return hr;
  409. }
  410. /****************************************************************************
  411. Class : CLocation
  412. Method : setLocalAccessCode
  413. ****************************************************************************/
  414. STDMETHODIMP CLocation::SetLocalAccessCode(PWSTR pszLocalAccessCode)
  415. {
  416. HRESULT hr = S_OK;
  417. if (m_pszLocalAccessCode != NULL)
  418. {
  419. ClientFree(m_pszLocalAccessCode);
  420. m_pszLocalAccessCode = NULL;
  421. }
  422. if(pszLocalAccessCode != NULL)
  423. {
  424. m_pszLocalAccessCode = ClientAllocString( pszLocalAccessCode );
  425. if (m_pszLocalAccessCode == NULL)
  426. {
  427. LOG(( TL_ERROR, "setLocalAccessCode - alloc failed" ));
  428. hr = E_OUTOFMEMORY;
  429. }
  430. }
  431. m_bChanged = TRUE;
  432. return hr;
  433. }
  434. /****************************************************************************
  435. Class : CLocation
  436. Method : SetDisableCallWaitingCode
  437. ****************************************************************************/
  438. STDMETHODIMP CLocation::SetDisableCallWaitingCode(PWSTR pszDisableCallWaitingCode)
  439. {
  440. HRESULT hr = S_OK;
  441. if (m_pszDisableCallWaitingCode != NULL)
  442. {
  443. ClientFree(m_pszDisableCallWaitingCode);
  444. m_pszDisableCallWaitingCode = NULL;
  445. }
  446. if(pszDisableCallWaitingCode != NULL)
  447. {
  448. m_pszDisableCallWaitingCode = ClientAllocString( pszDisableCallWaitingCode );
  449. if (m_pszDisableCallWaitingCode == NULL)
  450. {
  451. LOG(( TL_ERROR, "SetDisableCallWaitingCodee - alloc failed" ));
  452. hr = E_OUTOFMEMORY;
  453. }
  454. }
  455. m_bChanged = TRUE;
  456. return hr;
  457. }
  458. /****************************************************************************
  459. Class : CLocation
  460. Method : WriteToRegistry
  461. ****************************************************************************/
  462. STDMETHODIMP CLocation::WriteToRegistry()
  463. {
  464. HRESULT hr = S_OK;
  465. DWORD dwTotalSizeNeeded = 0 ;
  466. DWORD dwSize=0, dwOffset = 0;
  467. PLOCATIONLIST pLocationList = NULL;
  468. PLOCATION pEntry = NULL;
  469. // static size
  470. dwTotalSizeNeeded = sizeof(LOCATIONLIST);
  471. dwSize = TapiSize();
  472. dwTotalSizeNeeded += dwSize;
  473. // Allocate the memory buffer;
  474. pLocationList = (PLOCATIONLIST) ClientAlloc( dwTotalSizeNeeded );
  475. if (pLocationList != NULL)
  476. {
  477. // buffer size
  478. pLocationList->dwTotalSize = dwTotalSizeNeeded;
  479. pLocationList->dwNeededSize = dwTotalSizeNeeded;
  480. pLocationList->dwUsedSize = dwTotalSizeNeeded;
  481. pLocationList->dwCurrentLocationID = 0;
  482. pLocationList->dwNumLocationsAvailable = 1;
  483. //list size & offset
  484. dwOffset = sizeof(LOCATIONLIST);
  485. pLocationList->dwNumLocationsInList = 1;
  486. pLocationList->dwLocationListSize = dwSize;
  487. pLocationList->dwLocationListOffset = dwOffset;
  488. // point to the location entry in list
  489. pEntry = (PLOCATION)(((LPBYTE)pLocationList) + dwOffset);
  490. // fill out structure
  491. TapiPack(pEntry, dwSize);
  492. WriteLocations( pLocationList, 0);
  493. // finished with TAPI memory block so release
  494. if ( pLocationList != NULL )
  495. {
  496. ClientFree( pLocationList );
  497. }
  498. }
  499. else
  500. {
  501. hr = E_OUTOFMEMORY;
  502. }
  503. return hr;
  504. }
  505. /****************************************************************************
  506. Class : CLocation
  507. Method : RemoveRule
  508. ****************************************************************************/
  509. void CLocation::RemoveRule(CAreaCodeRule *pRule)
  510. {
  511. AreaCodeRulePtrNode * node = m_AreaCodeRuleList.head();
  512. while( !node->beyond_tail() )
  513. {
  514. if ( pRule == node->value() )
  515. {
  516. node->remove();
  517. delete pRule;
  518. m_dwNumRules--;
  519. break;
  520. }
  521. node = node->next();
  522. }
  523. m_bChanged = TRUE;
  524. }
  525. /****************************************************************************
  526. Class : CLocation
  527. Method : ResetRules
  528. ****************************************************************************/
  529. HRESULT CLocation::ResetRules(void)
  530. {
  531. m_hEnumNode = m_AreaCodeRuleList.head();
  532. return S_OK;
  533. }
  534. /****************************************************************************
  535. Class : CLocation
  536. Method : NextRule
  537. ****************************************************************************/
  538. HRESULT CLocation::NextRule(DWORD NrElem, CAreaCodeRule **ppRule, DWORD *pNrElemFetched)
  539. {
  540. DWORD dwIndex = 0;
  541. if(pNrElemFetched == NULL && NrElem != 1)
  542. return E_INVALIDARG;
  543. if(ppRule==NULL)
  544. return E_INVALIDARG;
  545. while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
  546. {
  547. *ppRule++ = m_hEnumNode->value();
  548. m_hEnumNode = m_hEnumNode->next();
  549. dwIndex++;
  550. }
  551. if(pNrElemFetched!=NULL)
  552. *pNrElemFetched = dwIndex;
  553. return dwIndex<NrElem ? S_FALSE : S_OK;
  554. }
  555. /****************************************************************************
  556. Class : CLocation
  557. Method : SkipRule
  558. ****************************************************************************/
  559. HRESULT CLocation::SkipRule(DWORD NrElem)
  560. {
  561. DWORD dwIndex = 0;
  562. while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
  563. {
  564. m_hEnumNode = m_hEnumNode->next();
  565. dwIndex++;
  566. }
  567. return dwIndex<NrElem ? S_FALSE : S_OK;
  568. }
  569. /****************************************************************************
  570. Class : CLocation
  571. Method : TapiSize
  572. Number of bytes needed to pack this into a TAPI structure to send
  573. to TAPISRV.
  574. If the object has not changed while in memory, we won't save it so
  575. return a zero size.
  576. ****************************************************************************/
  577. DWORD CLocation::TapiSize()
  578. {
  579. AreaCodeRulePtrNode * node = m_AreaCodeRuleList.head();
  580. CAreaCodeRule * pRule = NULL;
  581. DWORD dwSize=0;
  582. if(m_bChanged)
  583. {
  584. // Calc size of Location info
  585. dwSize = sizeof(LOCATION);
  586. dwSize += ALIGN((lstrlenW(m_pszLocationName) + 1) * sizeof(WCHAR));
  587. dwSize += ALIGN((lstrlenW(m_pszAreaCode) + 1) * sizeof(WCHAR));
  588. dwSize += ALIGN((lstrlenW(m_pszLongDistanceCarrierCode) + 1) * sizeof(WCHAR));
  589. dwSize += ALIGN((lstrlenW(m_pszInternationalCarrierCode) + 1) * sizeof(WCHAR));
  590. dwSize += ALIGN((lstrlenW(m_pszLongDistanceAccessCode) + 1) * sizeof(WCHAR));
  591. dwSize += ALIGN((lstrlenW(m_pszLocalAccessCode) + 1) * sizeof(WCHAR));
  592. dwSize += ALIGN((lstrlenW(m_pszDisableCallWaitingCode) + 1) * sizeof(WCHAR));
  593. while( !node->beyond_tail() )
  594. {
  595. // Add in size of each Area Code Rule
  596. pRule = node->value();
  597. if (pRule != NULL)
  598. {
  599. dwSize += pRule->TapiSize();
  600. }
  601. node = node->next();
  602. }
  603. }
  604. else // no change so don't save this
  605. {
  606. dwSize = 0;
  607. }
  608. return dwSize;
  609. }
  610. /****************************************************************************
  611. Class : CLocation
  612. Method : TapiPack
  613. Pack this object into a TAPI structure.
  614. Return number of bytes used.
  615. If the object has not changed while in memory, we won't save it so
  616. do mothing except return a zero size.
  617. ****************************************************************************/
  618. DWORD CLocation::TapiPack(PLOCATION pLocation, DWORD dwTotalSize)
  619. {
  620. AreaCodeRulePtrNode * node;
  621. CAreaCodeRule * pRule = NULL;
  622. DWORD dwSize =0, dwOffSet =0;
  623. PAREACODERULE pEntry = NULL;
  624. if(m_bChanged)
  625. {
  626. m_bFromRegistry = TRUE;
  627. /////////////////////////////////////////////////////////////////////
  628. // Process fized part of Location info
  629. dwOffSet = sizeof(LOCATION);
  630. pLocation->dwPermanentLocationID= m_dwLocationID;
  631. pLocation->dwCountryCode = m_dwCountryCode;
  632. pLocation->dwCountryID = m_dwCountryID;
  633. pLocation->dwPreferredCardID = m_dwPreferredCardID;
  634. pLocation->dwOptions = m_dwOptions;
  635. /////////////////////////////////////////////////////////////////////
  636. // Process strings
  637. // name
  638. dwOffSet += TapiPackString((LPBYTE)pLocation,
  639. dwOffSet,
  640. dwTotalSize,
  641. m_pszLocationName,
  642. &pLocation->dwLocationNameOffset,
  643. &pLocation->dwLocationNameSize
  644. );
  645. //area code
  646. dwOffSet += TapiPackString((LPBYTE)pLocation,
  647. dwOffSet,
  648. dwTotalSize,
  649. m_pszAreaCode,
  650. &pLocation->dwAreaCodeOffset,
  651. &pLocation->dwAreaCodeSize
  652. );
  653. //LD carrier code
  654. dwOffSet += TapiPackString((LPBYTE)pLocation,
  655. dwOffSet,
  656. dwTotalSize,
  657. m_pszLongDistanceCarrierCode,
  658. &pLocation->dwLongDistanceCarrierCodeOffset,
  659. &pLocation->dwLongDistanceCarrierCodeSize
  660. );
  661. //International carrier code
  662. dwOffSet += TapiPackString((LPBYTE)pLocation,
  663. dwOffSet,
  664. dwTotalSize,
  665. m_pszInternationalCarrierCode,
  666. &pLocation->dwInternationalCarrierCodeOffset,
  667. &pLocation->dwInternationalCarrierCodeSize
  668. );
  669. //LD access
  670. dwOffSet += TapiPackString((LPBYTE)pLocation,
  671. dwOffSet,
  672. dwTotalSize,
  673. m_pszLongDistanceAccessCode,
  674. &pLocation->dwLongDistanceAccessCodeOffset,
  675. &pLocation->dwLongDistanceAccessCodeSize
  676. );
  677. // Local access
  678. dwOffSet += TapiPackString((LPBYTE)pLocation,
  679. dwOffSet,
  680. dwTotalSize,
  681. m_pszLocalAccessCode,
  682. &pLocation->dwLocalAccessCodeOffset,
  683. &pLocation->dwLocalAccessCodeSize
  684. );
  685. // CallWaiting
  686. dwOffSet += TapiPackString((LPBYTE)pLocation,
  687. dwOffSet,
  688. dwTotalSize,
  689. m_pszDisableCallWaitingCode,
  690. &pLocation->dwCancelCallWaitingOffset,
  691. &pLocation->dwCancelCallWaitingSize
  692. );
  693. /////////////////////////////////////////////////////////////////////
  694. // Process Area Code Rules
  695. pLocation->dwNumAreaCodeRules = m_dwNumRules;
  696. pLocation->dwAreaCodeRulesListOffset = dwOffSet;
  697. //pLocation->dwAreaCodeRulesListSize;
  698. // point to the 1st rule
  699. pEntry = (PAREACODERULE)(((LPBYTE)pLocation) + dwOffSet);
  700. //point strings past rule area
  701. dwOffSet += ALIGN(( sizeof(AREACODERULE) * m_dwNumRules ));
  702. // run through list
  703. node = m_AreaCodeRuleList.head();
  704. while( !node->beyond_tail() )
  705. {
  706. // Add in size of each Area Code Rule
  707. pRule = node->value();
  708. if (pRule != NULL)
  709. {
  710. pEntry->dwOptions = pRule->GetOptions();
  711. // Area code
  712. dwOffSet += TapiPackString((LPBYTE)pLocation,
  713. dwOffSet,
  714. dwTotalSize,
  715. pRule->GetAreaCode(),
  716. &pEntry->dwAreaCodeOffset,
  717. &pEntry->dwAreaCodeSize
  718. );
  719. // num to Call
  720. dwOffSet += TapiPackString((LPBYTE)pLocation,
  721. dwOffSet,
  722. dwTotalSize,
  723. pRule->GetNumberToDial(),
  724. &pEntry->dwNumberToDialOffset,
  725. &pEntry->dwNumberToDialSize
  726. );
  727. // prefix list
  728. dwSize = pRule->GetPrefixListSize();
  729. pEntry->dwPrefixesListSize = dwSize;
  730. pEntry->dwPrefixesListOffset = dwOffSet;
  731. CopyMemory((PVOID)(((LPBYTE)pLocation) + dwOffSet),
  732. pRule->GetPrefixList() ,
  733. dwSize);
  734. dwOffSet += ALIGN(dwSize);
  735. }
  736. node = node->next();
  737. pEntry++;
  738. }
  739. // offset gives how many bytes we used
  740. pLocation->dwUsedSize = dwOffSet;
  741. }
  742. else // no change so don't save this
  743. {
  744. dwOffSet = 0;
  745. }
  746. return dwOffSet;
  747. }
  748. /****************************************************************************
  749. Class : CLocation
  750. Method : NewID
  751. gets new ID from server
  752. ****************************************************************************/
  753. HRESULT CLocation::NewID()
  754. {
  755. LONG lResult;
  756. DWORD dwId = 0;
  757. FUNC_ARGS funcArgs =
  758. {
  759. MAKELONG (LINE_FUNC | SYNC | 1, tAllocNewID),
  760. {
  761. (DWORD_PTR)&dwId
  762. },
  763. {
  764. lpDword
  765. }
  766. };
  767. //
  768. // Yes, let TAPISRV do it without danger of AV interruption from
  769. // another thread
  770. //
  771. lResult = DOFUNC (&funcArgs, "TAllocNewID");
  772. if(lResult == 0)
  773. {
  774. m_dwLocationID = dwId;
  775. }
  776. return (HRESULT)lResult;
  777. }
  778. /****************************************************************************
  779. Class : CLocation
  780. Method : GetCountryCode
  781. gets GetCountryCode from server
  782. ****************************************************************************/
  783. DWORD CLocation::GetCountryCode()
  784. {
  785. CCountry * pCountry = NULL;
  786. if(SUCCEEDED( CreateCountryObject(m_dwCountryID, &pCountry)) )
  787. {
  788. m_dwCountryCode = pCountry->GetCountryCode();
  789. delete pCountry;
  790. }
  791. return m_dwCountryCode;
  792. }
  793. /****************************************************************************
  794. Class : CLocation
  795. Method : TranslateAddress
  796. This is what its all there for, take a input number & figure out
  797. the dialable & display strings
  798. ****************************************************************************/
  799. LONG CLocation::TranslateAddress(PCWSTR pszAddressIn,
  800. CCallingCard *pCallingCard,
  801. DWORD dwTranslateOptions,
  802. PDWORD pdwTranslateResults,
  803. PDWORD pdwDestCountryCode,
  804. PWSTR * pszDialableString,
  805. PWSTR * pszDisplayableString
  806. )
  807. {
  808. PWSTR pszDialString = NULL;
  809. PWSTR pszDisplayString = NULL;
  810. PWSTR pszInputString = NULL;
  811. PWSTR pszRule = NULL;
  812. PWSTR pszDestLDRule = NULL;
  813. PWSTR pszCountry = NULL;
  814. PWSTR pszCity = NULL;
  815. PWSTR pszSubscriber = NULL;
  816. PWSTR pCardName = NULL;
  817. PWSTR pCardAccessNumber = NULL;
  818. PWSTR pCardAccountNumber = NULL;
  819. PWSTR pCardPINNumber = NULL;
  820. LONG lResult = 0;
  821. HRESULT hr= S_OK;
  822. CCountry * pCountry = NULL;
  823. CCountry * pDestCountry = NULL;
  824. DWORD dwAccess;
  825. DWORD dwDestCountryCode;
  826. BOOL bSpaceExists, bOutOfMem = FALSE;
  827. *pdwTranslateResults = 0;
  828. if(pdwDestCountryCode)
  829. *pdwDestCountryCode = 0;
  830. //////////////////////////////////////////////////////////////
  831. // Allocate space for our strings
  832. //
  833. pszDialString = (PWSTR)ClientAlloc( MaxDialStringSize * sizeof(WCHAR) );
  834. if (pszDialString == NULL)
  835. {
  836. LOG((TL_TRACE, "TranslateAddress DialString alloc failed"));
  837. return LINEERR_NOMEM;
  838. }
  839. pszDisplayString = (PWSTR)ClientAlloc( MaxDialStringSize * sizeof(WCHAR) );
  840. if (pszDisplayString == NULL)
  841. {
  842. LOG((TL_TRACE, "TranslateAddress DisplayString alloc failed"));
  843. ClientFree(pszDialString);
  844. return LINEERR_NOMEM;
  845. }
  846. *pszDialableString = pszDialString;
  847. *pszDisplayableString = pszDisplayString;
  848. bSpaceExists = TRUE; // for suppressing a first space
  849. //////////////////////////////////////////////////////////////
  850. // Copy the string to our local buffer so we can mangle it
  851. //
  852. pszInputString = ClientAllocString(pszAddressIn);
  853. if (pszInputString == NULL)
  854. {
  855. LOG((TL_TRACE, "TranslateAddress InputString alloc failed"));
  856. ClientFree(pszDialString);
  857. ClientFree(pszDisplayString);
  858. return LINEERR_NOMEM;
  859. }
  860. //////////////////////////////////////////////////////////////
  861. // Mark off the end
  862. //
  863. // Isolate the piece of pszInputString that we will operate upon in
  864. // This piece stops at first CR or \0.
  865. //
  866. pszInputString[wcscspn(pszInputString,csSCANTO)] = L'\0';
  867. ////////////////////////////////
  868. // Set T or P, if not set in input
  869. //////////////////////////////////////////////////////////////
  870. // Easy case: first put the T or P in the beginning of the
  871. // dialable string
  872. //
  873. if ( HasToneDialing() )
  874. {
  875. *pszDialString = L'T';
  876. }
  877. else
  878. {
  879. *pszDialString = L'P';
  880. }
  881. pszDialString++;
  882. //////////////////////////////////////////////////////////////
  883. // Set Call Waiting
  884. //if location supports call Waiting AND (TranslateOptions | LINETRANSLATIONOPTION_CANCELCALLWAIT)
  885. if((dwTranslateOptions & LINETRANSLATEOPTION_CANCELCALLWAITING) && HasCallWaiting() )
  886. {
  887. hr = StringCchCatExW(pszDialString, MaxDialStringSize, m_pszDisableCallWaitingCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
  888. bOutOfMem = bOutOfMem && FAILED(hr);
  889. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, m_pszDisableCallWaitingCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
  890. bOutOfMem = bOutOfMem && FAILED(hr);
  891. bSpaceExists = FALSE;
  892. }
  893. //////////////////////////////////////////////////////////////
  894. // Now, do we have a canonical number to deal with, or is it junk?
  895. //
  896. if ( *pszInputString == L'+' ) // Check the real _first_ char
  897. {
  898. //
  899. // Ok, it's canonical
  900. //
  901. //
  902. // Skip the plus
  903. //
  904. lResult = BreakupCanonicalW( pszInputString + 1,
  905. &pszCountry,
  906. &pszCity,
  907. &pszSubscriber
  908. );
  909. if (lResult == 0)
  910. {
  911. // It's canonical
  912. *pdwTranslateResults |= LINETRANSLATERESULT_CANONICAL;
  913. hr = CreateCountryObject(m_dwCountryID, &pCountry);
  914. if(SUCCEEDED( hr) )
  915. {
  916. //////////////////////////////////////////////////////////////
  917. // set LINETRANSLATERESULT result codes
  918. dwDestCountryCode = (DWORD)_wtol((const wchar_t*) pszCountry);
  919. if (dwDestCountryCode == pCountry->GetCountryCode() )
  920. {
  921. // In country Call
  922. pszDestLDRule = pCountry->GetLongDistanceRule();
  923. //if ( (
  924. // CurrentCountry.LongDistanceRule.AreaCodes == Optional
  925. // OR CurrentCountry.LongDistanceRule.AreaCodes == Manditory && cityCode != NULL
  926. // )
  927. // AND AreaCodeString != CurrentLocation.AreaCodeString )
  928. if ( ( (IsCityRule(pszDestLDRule) == CITY_OPTIONAL) ||
  929. ( (IsCityRule(pszDestLDRule) == CITY_MANDATORY) && (pszCity != NULL) ) ) &&
  930. (!AreaCodeMatch(pszCity, m_pszAreaCode, pszDestLDRule))
  931. )
  932. {
  933. // Long Distance Call
  934. *pdwTranslateResults |= LINETRANSLATERESULT_LONGDISTANCE;
  935. }
  936. else // Local Call
  937. {
  938. *pdwTranslateResults |= LINETRANSLATERESULT_LOCAL;
  939. }
  940. }
  941. else // International Call
  942. {
  943. // find the LD rule of the destination country using the country code (we don't have the country ID)
  944. hr = CreateCountryObject(dwDestCountryCode, &pDestCountry);
  945. if(SUCCEEDED(hr))
  946. {
  947. if ( pCountry->GetCountryGroup() != 0 &&
  948. pCountry->GetCountryGroup() == pDestCountry->GetCountryGroup()
  949. )
  950. {
  951. // if countries are in the same group, we need to
  952. // apply long distance rule instead of international
  953. *pdwTranslateResults |= LINETRANSLATERESULT_LONGDISTANCE;
  954. }
  955. else
  956. {
  957. *pdwTranslateResults |= LINETRANSLATERESULT_INTERNATIONAL;
  958. }
  959. pszDestLDRule = pDestCountry->GetLongDistanceRule();
  960. }
  961. else
  962. {
  963. *pdwTranslateResults |= LINETRANSLATERESULT_INTERNATIONAL;
  964. // FALL THROUGH if error
  965. }
  966. }
  967. }
  968. if(SUCCEEDED( hr) )
  969. {
  970. // If the caller needs the destination country code
  971. if(pdwDestCountryCode)
  972. *pdwDestCountryCode = dwDestCountryCode;
  973. //////////////////////////////////////////////////////////////
  974. // Now we no what type of call, find the correct rule
  975. // Take in to account LINETRANSLATIONOPTION over-rides
  976. FindRule(
  977. *pdwTranslateResults,
  978. dwTranslateOptions,
  979. pCallingCard,
  980. pCountry,
  981. pszCity,
  982. pszSubscriber,
  983. &pszRule,
  984. &dwAccess
  985. );
  986. //////////////////////////////////////////////////////////////
  987. // Add access String to output string
  988. if (dwAccess == LOCAL)
  989. {
  990. hr = StringCchCatExW(pszDialString, MaxDialStringSize, m_pszLocalAccessCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
  991. bOutOfMem = bOutOfMem && FAILED(hr);
  992. if(*m_pszLocalAccessCode)
  993. {
  994. if(!bSpaceExists)
  995. {
  996. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  997. bOutOfMem = bOutOfMem && FAILED(hr);
  998. }
  999. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, m_pszLocalAccessCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
  1000. bOutOfMem = bOutOfMem && FAILED(hr);
  1001. bSpaceExists = FALSE;
  1002. }
  1003. }
  1004. else // LONG_DISTANCE or INTERNATIONAL
  1005. {
  1006. hr = StringCchCatExW(pszDialString, MaxDialStringSize, m_pszLongDistanceAccessCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
  1007. bOutOfMem = bOutOfMem && FAILED(hr);
  1008. if(*m_pszLongDistanceAccessCode)
  1009. {
  1010. if(!bSpaceExists)
  1011. {
  1012. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  1013. bOutOfMem = bOutOfMem && FAILED(hr);
  1014. }
  1015. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, m_pszLongDistanceAccessCode, NULL, NULL, STRSAFE_NO_TRUNCATION);
  1016. bOutOfMem = bOutOfMem && FAILED(hr);
  1017. bSpaceExists = FALSE;
  1018. }
  1019. }
  1020. //////////////////////////////////////////////////////////////
  1021. // If there's a card get its values
  1022. if(pCallingCard != NULL)
  1023. {
  1024. switch(dwAccess)
  1025. {
  1026. case INTERNATIONAL:
  1027. pCardAccessNumber = pCallingCard->GetInternationalAccessNumber();
  1028. break;
  1029. case LONG_DISTANCE:
  1030. LOG((TL_TRACE, "TranslateAddress: About to do pCallingCard->GetLongDistanceAccessNumber"));
  1031. pCardAccessNumber = pCallingCard->GetLongDistanceAccessNumber();
  1032. LOG((TL_TRACE, "TranslateAddress: Did pCallingCard->GetLongDistanceAccessNumber"));
  1033. break;
  1034. default:
  1035. pCardAccessNumber = pCallingCard->GetLocalAccessNumber();
  1036. break;
  1037. }
  1038. pCardName = pCallingCard->GetCardName();
  1039. pCardAccountNumber = pCallingCard->GetAccountNumber();
  1040. pCardPINNumber = pCallingCard->GetPIN();
  1041. }
  1042. if(!bSpaceExists)
  1043. {
  1044. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  1045. bOutOfMem = bOutOfMem && FAILED(hr);
  1046. }
  1047. //////////////////////////////////////////////////////////////
  1048. // Got the rule , now apply it
  1049. if (ApplyRule (pszDialString,
  1050. pszDisplayString,
  1051. pszRule,
  1052. pszDestLDRule,
  1053. m_pszLongDistanceCarrierCode,
  1054. m_pszInternationalCarrierCode,
  1055. pszCountry,
  1056. pszCity,
  1057. pszSubscriber,
  1058. pCardName,
  1059. pCardAccessNumber,
  1060. pCardAccountNumber,
  1061. pCardPINNumber
  1062. ))
  1063. {
  1064. bOutOfMem = TRUE;
  1065. }
  1066. else
  1067. {
  1068. //
  1069. // Set LINETRANSLATERESULT_consts based on translation
  1070. // results
  1071. //
  1072. if (wcschr (pszDialString, L'$'))
  1073. {
  1074. *pdwTranslateResults |= LINETRANSLATERESULT_DIALBILLING;
  1075. }
  1076. if (wcschr (pszDialString, L'W'))
  1077. {
  1078. *pdwTranslateResults |= LINETRANSLATERESULT_DIALDIALTONE;
  1079. }
  1080. if (wcschr (pszDialString, L'?'))
  1081. {
  1082. *pdwTranslateResults |= LINETRANSLATERESULT_DIALPROMPT;
  1083. }
  1084. if (wcschr (pszDialString, L'@'))
  1085. {
  1086. *pdwTranslateResults |= LINETRANSLATERESULT_DIALQUIET;
  1087. }
  1088. if (wcschr (pszDialString, L':'))
  1089. {
  1090. *pdwTranslateResults |= LINETRANSLATERESULT_VOICEDETECT;
  1091. }
  1092. }
  1093. }
  1094. else // bad country code
  1095. {
  1096. lResult = LINEERR_INVALCOUNTRYCODE;
  1097. ClientFree(*pszDialableString);
  1098. ClientFree(*pszDisplayableString);
  1099. *pszDialableString = *pszDisplayableString = NULL;
  1100. }
  1101. if(pCountry)
  1102. delete pCountry;
  1103. if(pDestCountry)
  1104. delete pDestCountry;
  1105. }
  1106. else // bad canonical address
  1107. {
  1108. lResult = LINEERR_INVALADDRESS;
  1109. ClientFree(*pszDialableString);
  1110. ClientFree(*pszDisplayableString);
  1111. *pszDialableString = *pszDisplayableString = NULL;
  1112. }
  1113. }
  1114. else // non-canonical string
  1115. {
  1116. PWSTR pszInputStringLocal = pszInputString;
  1117. // if the string starts with T,P,t or p, skip the
  1118. // first character.
  1119. if (*pszInputString == L'T' ||
  1120. *pszInputString == L'P' ||
  1121. *pszInputString == L't' ||
  1122. *pszInputString == L'p')
  1123. {
  1124. pszInputStringLocal++;
  1125. }
  1126. hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszInputStringLocal, NULL, NULL, STRSAFE_NO_TRUNCATION);
  1127. bOutOfMem = bOutOfMem && FAILED(hr);
  1128. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszInputString, NULL, NULL, STRSAFE_NO_TRUNCATION);
  1129. bOutOfMem = bOutOfMem && FAILED(hr);
  1130. }
  1131. /////////////////////////////////////////////////////////////////////
  1132. // Clean up
  1133. //
  1134. if (bOutOfMem)
  1135. {
  1136. lResult = LINEERR_NOMEM;
  1137. ClientFree(pszDialString);
  1138. ClientFree(pszDisplayString);
  1139. }
  1140. if(pszInputString != NULL)
  1141. {
  1142. ClientFree(pszInputString);
  1143. }
  1144. return lResult;
  1145. }
  1146. /****************************************************************************
  1147. Class : CLocation
  1148. Method : FindRule
  1149. Decide which TAPI dial string rule to apply
  1150. in
  1151. dwTranslateResults
  1152. dwTranslateOptions
  1153. pCard
  1154. pCountry
  1155. AreaCodeString
  1156. SubscriberString
  1157. out
  1158. ppRule
  1159. dwAccess
  1160. ****************************************************************************/
  1161. void CLocation::FindRule(
  1162. DWORD dwTranslateResults,
  1163. DWORD dwTranslateOptions,
  1164. CCallingCard * pCard,
  1165. CCountry * pCountry,
  1166. PWSTR pszAreaCodeString,
  1167. PWSTR pszSubscriberString,
  1168. PWSTR * ppszRule,
  1169. PDWORD dwAccess
  1170. )
  1171. {
  1172. CRuleSet * pCardRuleSet;
  1173. CRuleSet * pCountryRuleSet;
  1174. //if using Card
  1175. if(pCard != NULL)
  1176. {
  1177. // Apply card rules
  1178. pCardRuleSet = pCard->GetRuleSet();
  1179. LOG((TL_INFO, "FindRule - using (eventually) card %ls", pCard->GetCardName() ));
  1180. }
  1181. else
  1182. {
  1183. pCardRuleSet = NULL;
  1184. }
  1185. pCountryRuleSet = pCountry->GetRuleSet();
  1186. // use card rule if card is specified. If a specific rule is empty, fallback to country rule
  1187. #define SUITABLE_RULE(x) \
  1188. ( (pCard && pCardRuleSet->x && *(pCardRuleSet->x) ) ? \
  1189. pCardRuleSet->x : pCountryRuleSet->x )
  1190. // Forced Long Distance Call
  1191. if (dwTranslateOptions & LINETRANSLATEOPTION_FORCELD)
  1192. {
  1193. *dwAccess = LONG_DISTANCE;
  1194. *ppszRule = SUITABLE_RULE(m_pszLongDistanceRule);
  1195. LOG((TL_INFO, "FindRule - force long distance"));
  1196. }
  1197. // Force Local Call
  1198. else if (dwTranslateOptions & LINETRANSLATEOPTION_FORCELOCAL)
  1199. {
  1200. *dwAccess = LOCAL;
  1201. *ppszRule = SUITABLE_RULE(m_pszLocalRule);
  1202. LOG((TL_INFO, "FindRule - force local"));
  1203. }
  1204. // International Call
  1205. else if (dwTranslateResults & LINETRANSLATERESULT_INTERNATIONAL)
  1206. {
  1207. *dwAccess = INTERNATIONAL;
  1208. *ppszRule = SUITABLE_RULE(m_pszInternationalRule);
  1209. LOG((TL_INFO, "FindRule - international"));
  1210. }
  1211. // In Country, Long Distance Call or Local
  1212. else
  1213. {
  1214. CAreaCodeRule * pCrtRule = NULL;
  1215. AreaCodeRulePtrNode * pNode = NULL;
  1216. PWSTR pszPrefix = NULL;
  1217. DWORD dwNumMatchedDigits = 0;
  1218. DWORD dwBestMatchedDigits = 0;
  1219. DWORD dwBestThisRule = 0;
  1220. BOOL bFoundApplicableRule = FALSE;
  1221. BOOL bMatchThisRule = FALSE;
  1222. BOOL bThisPrefixMatchThisRule = FALSE;
  1223. // Enumerate the area code rules
  1224. pNode = m_AreaCodeRuleList.head();
  1225. while( !pNode->beyond_tail() )
  1226. {
  1227. pCrtRule = pNode->value();
  1228. if(pCrtRule!=NULL)
  1229. {
  1230. // does this rule match the area code we're calling ?
  1231. if(AreaCodeMatch(pszAreaCodeString, pCrtRule->GetAreaCode(), pCountry->GetLongDistanceRule()))
  1232. {
  1233. LOG((TL_INFO, "FindRule - ACRule applies"));
  1234. bMatchThisRule = FALSE;
  1235. dwBestThisRule = 0;
  1236. if( pCrtRule->HasAppliesToAllPrefixes() )
  1237. {
  1238. bMatchThisRule = TRUE;
  1239. dwNumMatchedDigits = 0;
  1240. LOG((TL_INFO, "FindRule - there's a all prefix rule"));
  1241. }
  1242. else // is there a specific prefix rule ?
  1243. {
  1244. pszPrefix = pCrtRule->GetPrefixList();
  1245. while(*pszPrefix != '\0')
  1246. {
  1247. bThisPrefixMatchThisRule= PrefixMatch(pszPrefix,
  1248. pszSubscriberString,
  1249. &dwNumMatchedDigits);
  1250. if(bThisPrefixMatchThisRule)
  1251. {
  1252. LOG((TL_INFO, "FindRule: there's a specific prefix rule %d digit match"
  1253. ,dwNumMatchedDigits));
  1254. bMatchThisRule = TRUE;
  1255. if(dwNumMatchedDigits > dwBestThisRule )
  1256. {
  1257. dwBestThisRule= dwNumMatchedDigits;
  1258. }
  1259. }
  1260. pszPrefix = wcschr( pszPrefix, '\0');
  1261. pszPrefix++;
  1262. }
  1263. }
  1264. // have we got a better match than we've had before ?
  1265. if(bMatchThisRule && (dwBestThisRule >= dwBestMatchedDigits) )
  1266. {
  1267. // We have the best prefix match so far so use this rule
  1268. dwBestMatchedDigits = dwBestThisRule;
  1269. bFoundApplicableRule = TRUE;
  1270. LOG((TL_INFO, "FindRule: going with the %d digit match" ,dwBestMatchedDigits));
  1271. *ppszRule = NULL;
  1272. // Card overides, so if using Card
  1273. if(pCard != NULL)
  1274. {
  1275. LOG((TL_INFO, "FindRule: card override (eventually)"));
  1276. if ( pCrtRule->HasDialNumber() )
  1277. {
  1278. *ppszRule = pCardRuleSet->m_pszLongDistanceRule;
  1279. }
  1280. else
  1281. {
  1282. *ppszRule = pCardRuleSet->m_pszLocalRule;
  1283. }
  1284. }
  1285. if(!(*ppszRule && **ppszRule))
  1286. // build a tapirulestring for this rule entry
  1287. // this might be necessary if the calling card has no suitable rule
  1288. {
  1289. if(m_pszTAPIDialingRule != NULL)
  1290. {
  1291. ClientFree(m_pszTAPIDialingRule);
  1292. }
  1293. if (S_OK ==
  1294. CreateDialingRule(&m_pszTAPIDialingRule,
  1295. pCrtRule->HasDialNumber()?pCrtRule->GetNumberToDial():NULL,
  1296. pCrtRule->HasDialAreaCode()
  1297. ))
  1298. {
  1299. *ppszRule = m_pszTAPIDialingRule;
  1300. LOG((TL_INFO, "FindRule: built a rule string - %ls",m_pszTAPIDialingRule));
  1301. }
  1302. }
  1303. // Set the correct access, based on the selected rule
  1304. if ( pCrtRule->HasDialNumber() )
  1305. {
  1306. *dwAccess = LONG_DISTANCE;
  1307. }
  1308. else
  1309. {
  1310. *dwAccess = LOCAL;
  1311. }
  1312. } // no better match
  1313. } // no not calling this area code
  1314. }
  1315. pNode = pNode->next();
  1316. }
  1317. // Did we have a match at all ?
  1318. if(bFoundApplicableRule == FALSE)
  1319. {
  1320. // No area code rule matched, so go with country default rule
  1321. if (dwTranslateResults & LINETRANSLATERESULT_LONGDISTANCE)
  1322. {
  1323. // long Distance
  1324. *dwAccess = LONG_DISTANCE;
  1325. *ppszRule = SUITABLE_RULE(m_pszLongDistanceRule);
  1326. LOG((TL_TRACE, "FindRule - long distance default"));
  1327. }
  1328. else // Local
  1329. {
  1330. *dwAccess = LOCAL;
  1331. *ppszRule = SUITABLE_RULE(m_pszLocalRule);
  1332. LOG((TL_TRACE, "FindRule - local default"));
  1333. }
  1334. }
  1335. }
  1336. }
  1337. #undef SUITABLE_RULE
  1338. /*
  1339. ***************************************************************************
  1340. ********************* ****************************
  1341. ******************** CLocations Class ***************************
  1342. ******************** Definitions ***************************
  1343. ********************* ****************************
  1344. ***************************************************************************
  1345. */
  1346. /****************************************************************************
  1347. Class : CLocations
  1348. Method : Constructer
  1349. ****************************************************************************/
  1350. CLocations::CLocations()
  1351. {
  1352. m_dwNumEntries = 0;
  1353. m_hEnumNode = m_LocationList.head();
  1354. }
  1355. /****************************************************************************
  1356. Class : CLocations
  1357. Method : Destructer
  1358. ****************************************************************************/
  1359. CLocations::~CLocations()
  1360. {
  1361. CLocationNode *node;
  1362. node = m_LocationList.head();
  1363. while( !node->beyond_tail() )
  1364. {
  1365. delete node->value();
  1366. node = node->next();
  1367. }
  1368. m_LocationList.flush();
  1369. node = m_DeletedLocationList.head();
  1370. while( !node->beyond_tail() )
  1371. {
  1372. delete node->value();
  1373. node = node->next();
  1374. }
  1375. m_DeletedLocationList.flush();
  1376. }
  1377. /****************************************************************************
  1378. Class : CLocations
  1379. Method : Initialize
  1380. Read the location list from registry via TAPISRV & build our
  1381. object list.
  1382. ****************************************************************************/
  1383. HRESULT CLocations::Initialize(void)
  1384. {
  1385. PLOCATIONLIST pLocationList = NULL;
  1386. PLOCATION pEntry = NULL;
  1387. PWSTR pszLocationName = NULL;
  1388. PWSTR pszAreaCode = NULL;
  1389. PWSTR pszLongDistanceCarrierCode = NULL;
  1390. PWSTR pszInternationalCarrierCode = NULL;
  1391. PWSTR pszLocalAccessCode = NULL;
  1392. PWSTR pszLongDistanceAccessCode = NULL;
  1393. PWSTR pszCancelCallWaitingCode = NULL;
  1394. DWORD dwPermanentLocationID = 0;
  1395. CLocation * pNewLocation = NULL;
  1396. PAREACODERULE pAreaCodeRuleEntry = NULL;
  1397. PWSTR pszNumberToDial = NULL;
  1398. PWSTR pszzPrefixesList = NULL;
  1399. DWORD dwNumRules = 0;
  1400. CAreaCodeRule * pAreaCodeRule = NULL;
  1401. DWORD dwNumEntries = 0;
  1402. DWORD dwCount,dwCount2 = 0;
  1403. HRESULT hr;
  1404. hr = ReadLocations(&pLocationList,
  1405. 0,
  1406. 0,
  1407. 0,
  1408. 0
  1409. );
  1410. if SUCCEEDED( hr)
  1411. {
  1412. // current location
  1413. m_dwCurrentLocationID = pLocationList->dwCurrentLocationID;
  1414. // Find position of 1st LOCATION structure in the LOCATIONLIST structure
  1415. pEntry = (PLOCATION) ((BYTE*)(pLocationList) + pLocationList->dwLocationListOffset );
  1416. // Number of locations ?
  1417. dwNumEntries = pLocationList->dwNumLocationsInList;
  1418. for (dwCount = 0; dwCount < dwNumEntries ; dwCount++)
  1419. {
  1420. // Pull Location Info out of LOCATION structure
  1421. pszLocationName = (PWSTR) ((BYTE*)(pEntry)
  1422. + pEntry->dwLocationNameOffset);
  1423. pszAreaCode = (PWSTR) ((BYTE*)(pEntry)
  1424. + pEntry->dwAreaCodeOffset);
  1425. pszLongDistanceCarrierCode = (PWSTR) ((BYTE*)(pEntry)
  1426. + pEntry->dwLongDistanceCarrierCodeOffset);
  1427. pszInternationalCarrierCode = (PWSTR) ((BYTE*)(pEntry)
  1428. + pEntry->dwInternationalCarrierCodeOffset);
  1429. pszLocalAccessCode = (PWSTR) ((BYTE*)(pEntry)
  1430. + pEntry->dwLocalAccessCodeOffset);
  1431. pszLongDistanceAccessCode = (PWSTR) ((BYTE*)(pEntry)
  1432. + pEntry->dwLongDistanceAccessCodeOffset);
  1433. pszCancelCallWaitingCode = (PWSTR) ((BYTE*)(pEntry)
  1434. + pEntry->dwCancelCallWaitingOffset);
  1435. // create our new Location Object
  1436. pNewLocation = new CLocation;
  1437. if (pNewLocation)
  1438. {
  1439. // initialize the new Location Object
  1440. hr = pNewLocation->Initialize(
  1441. pszLocationName,
  1442. pszAreaCode,
  1443. pszLongDistanceCarrierCode,
  1444. pszInternationalCarrierCode,
  1445. pszLongDistanceAccessCode,
  1446. pszLocalAccessCode,
  1447. pszCancelCallWaitingCode ,
  1448. pEntry->dwPermanentLocationID,
  1449. pEntry->dwCountryID,
  1450. pEntry->dwPreferredCardID,
  1451. pEntry->dwOptions,
  1452. TRUE
  1453. );
  1454. if( SUCCEEDED(hr) )
  1455. {
  1456. // Find position of 1st AREACODERULE structure in the LOCATIONLIST structure
  1457. pAreaCodeRuleEntry = (PAREACODERULE) ((BYTE*)(pEntry)
  1458. + pEntry->dwAreaCodeRulesListOffset );
  1459. dwNumRules = pEntry->dwNumAreaCodeRules;
  1460. for (dwCount2 = 0; dwCount2 != dwNumRules; dwCount2++)
  1461. {
  1462. // Pull Rule Info out of AREACODERULE structure
  1463. pszAreaCode = (PWSTR) ((BYTE*)(pEntry)
  1464. + pAreaCodeRuleEntry->dwAreaCodeOffset);
  1465. pszNumberToDial = (PWSTR) ((BYTE*)(pEntry)
  1466. + pAreaCodeRuleEntry->dwNumberToDialOffset);
  1467. pszzPrefixesList = (PWSTR) ((BYTE*)(pEntry)
  1468. + pAreaCodeRuleEntry->dwPrefixesListOffset);
  1469. // create our new AreaCodeRule Object
  1470. pAreaCodeRule = new CAreaCodeRule;
  1471. if (pAreaCodeRule)
  1472. {
  1473. // initialize the new AreaCodeRule Object
  1474. hr = pAreaCodeRule->Initialize ( pszAreaCode,
  1475. pszNumberToDial,
  1476. pAreaCodeRuleEntry->dwOptions,
  1477. pszzPrefixesList,
  1478. pAreaCodeRuleEntry->dwPrefixesListSize
  1479. );
  1480. if( SUCCEEDED(hr) )
  1481. {
  1482. pNewLocation->AddRule(pAreaCodeRule);
  1483. }
  1484. else // rule initialization failed
  1485. {
  1486. delete pAreaCodeRule;
  1487. LOG((TL_ERROR, "Initialize: CreateCurrentLoctionObject - rule create failed"));
  1488. }
  1489. }
  1490. else // new CAreaCodeRule failed
  1491. {
  1492. LOG((TL_ERROR, "CreateCurrentLoctionObject - rule create failed"));
  1493. }
  1494. // Try next rule in list
  1495. pAreaCodeRuleEntry++;
  1496. }
  1497. Add(pNewLocation);
  1498. }
  1499. else // location initialize failed
  1500. {
  1501. delete pNewLocation;
  1502. pNewLocation = NULL;
  1503. LOG((TL_ERROR, "CreateCurrentLoctionObject - location create failed"));
  1504. }
  1505. }
  1506. else // new CLocation failed
  1507. {
  1508. LOG((TL_ERROR, "CreateCurrentLoctionObject - location create failed"));
  1509. }
  1510. // Try next location in list
  1511. //pEntry++;
  1512. pEntry = (PLOCATION) ((BYTE*)(pEntry) + pEntry->dwUsedSize);
  1513. }
  1514. }
  1515. else // ReadLocations failed
  1516. {
  1517. LOG((TL_ERROR, "CreateCurrentLoctionObject - ReadLocation create failed"));
  1518. }
  1519. // finished with TAPI memory block so release
  1520. if ( pLocationList != NULL )
  1521. ClientFree( pLocationList );
  1522. return hr;
  1523. }
  1524. /****************************************************************************
  1525. Class : CLocations
  1526. Method : SaveToRegistry
  1527. Save object list back to registry via TAPISRV again
  1528. ****************************************************************************/
  1529. HRESULT CLocations::SaveToRegistry(void)
  1530. {
  1531. HRESULT hr = S_OK;
  1532. DWORD dwTotalSizeNeeded = 0, dwNumEntries= 0 ;
  1533. DWORD dwSize=0, dwOffset = 0;
  1534. CLocationNode * node = NULL;
  1535. CLocation * pLocation = NULL;
  1536. PLOCATIONLIST pLocationList = NULL;
  1537. PLOCATION pEntry = NULL;
  1538. // static size
  1539. dwTotalSizeNeeded = sizeof(LOCATIONLIST);
  1540. dwNumEntries = 0;
  1541. // Now add in size of each Location (includes rules)
  1542. node = m_LocationList.head();
  1543. while( !node->beyond_tail() )
  1544. {
  1545. pLocation = node->value();
  1546. if (pLocation != NULL)
  1547. {
  1548. dwSize= pLocation->TapiSize();
  1549. dwTotalSizeNeeded += dwSize;
  1550. if(dwSize)
  1551. {
  1552. // only save if dwSize >0, i.e. object has changed
  1553. dwNumEntries++;
  1554. }
  1555. }
  1556. node = node->next();
  1557. }
  1558. // Now add in size of each deleted Location
  1559. node = m_DeletedLocationList.head();
  1560. while( !node->beyond_tail() )
  1561. {
  1562. pLocation = node->value();
  1563. if (pLocation != NULL)
  1564. {
  1565. dwSize= pLocation->TapiSize();
  1566. dwTotalSizeNeeded += dwSize;
  1567. if(dwSize)
  1568. {
  1569. // only save if dwSize > 0, i.e. object has changed
  1570. dwNumEntries++;
  1571. }
  1572. }
  1573. node = node->next();
  1574. }
  1575. // Allocate the memory buffer;
  1576. pLocationList = (PLOCATIONLIST) ClientAlloc( dwTotalSizeNeeded );
  1577. if (pLocationList != NULL)
  1578. {
  1579. // buffer size
  1580. pLocationList->dwTotalSize = dwTotalSizeNeeded;
  1581. pLocationList->dwNeededSize = dwTotalSizeNeeded;
  1582. pLocationList->dwUsedSize = dwTotalSizeNeeded;
  1583. pLocationList->dwCurrentLocationID = m_dwCurrentLocationID;
  1584. pLocationList->dwNumLocationsAvailable = dwNumEntries;
  1585. //list size & offset
  1586. dwOffset = sizeof(LOCATIONLIST);
  1587. pLocationList->dwNumLocationsInList = dwNumEntries;
  1588. pLocationList->dwLocationListSize = dwTotalSizeNeeded - sizeof(LOCATIONLIST);
  1589. pLocationList->dwLocationListOffset = dwOffset;
  1590. // Now add in each Location (includes rules)
  1591. node = m_LocationList.head();
  1592. while( !node->beyond_tail() )
  1593. {
  1594. // point to the location entry in list
  1595. pEntry = (PLOCATION)(((LPBYTE)pLocationList) + dwOffset);
  1596. pLocation = node->value();
  1597. if (pLocation != NULL)
  1598. {
  1599. // fill out structure
  1600. dwOffset += pLocation->TapiPack(pEntry, dwTotalSizeNeeded - dwOffset);
  1601. }
  1602. node = node->next();
  1603. }
  1604. // Now add in each deleted Location
  1605. node = m_DeletedLocationList.head();
  1606. while( !node->beyond_tail() )
  1607. {
  1608. // point to the location entry in list
  1609. pEntry = (PLOCATION)(((LPBYTE)pLocationList) + dwOffset);
  1610. pLocation = node->value();
  1611. if (pLocation != NULL)
  1612. {
  1613. // fill out structure
  1614. dwOffset += pLocation->TapiPack(pEntry, dwTotalSizeNeeded - dwOffset);
  1615. }
  1616. node = node->next();
  1617. }
  1618. WriteLocations( pLocationList,CHANGEDFLAGS_CURLOCATIONCHANGED);
  1619. // finished with TAPI memory block so release
  1620. if ( pLocationList != NULL )
  1621. {
  1622. ClientFree( pLocationList );
  1623. }
  1624. }
  1625. else
  1626. {
  1627. hr = E_OUTOFMEMORY;
  1628. }
  1629. return hr;
  1630. }
  1631. /****************************************************************************
  1632. Class : CLocations
  1633. Method : Remove (with CLocation *)
  1634. If location object was read from the registry we must keep it
  1635. around so we can remove its entry when writing back to the registry.
  1636. If it only existed in memory we can just delete it.
  1637. ****************************************************************************/
  1638. void CLocations::Remove(CLocation * pLocation)
  1639. {
  1640. CLocationNode *node = m_LocationList.head();
  1641. while( !node->beyond_tail() )
  1642. {
  1643. if ( pLocation == node->value() )
  1644. {
  1645. node->remove();
  1646. m_dwNumEntries--;
  1647. pLocation->Changed();
  1648. if( pLocation->FromRegistry() )
  1649. {
  1650. // set name to null so server knows to delete it
  1651. pLocation->SetName(NULL);
  1652. m_DeletedLocationList.tail()->insert_after(pLocation);
  1653. }
  1654. else
  1655. {
  1656. delete pLocation;
  1657. }
  1658. break;
  1659. }
  1660. node = node->next();
  1661. }
  1662. }
  1663. /****************************************************************************
  1664. Class : CLocations
  1665. Method : Remove (with DWORD)
  1666. If location object was read from the registry we must keep it
  1667. around so we can remove its entry when writing back to the registry.
  1668. If it only existed in memory we can just delete it.
  1669. ****************************************************************************/
  1670. void CLocations::Remove(DWORD dwID)
  1671. {
  1672. CLocationNode *node = m_LocationList.head();
  1673. CLocation *pLocation;
  1674. while( !node->beyond_tail() )
  1675. {
  1676. if ( dwID == node->value()->GetLocationID() )
  1677. {
  1678. pLocation = node->value();
  1679. node->remove();
  1680. m_dwNumEntries--;
  1681. pLocation->Changed();
  1682. if( pLocation->FromRegistry() )
  1683. {
  1684. // set name to null so server knows to delete it
  1685. pLocation->SetName(NULL);
  1686. m_DeletedLocationList.tail()->insert_after(pLocation);
  1687. }
  1688. else
  1689. {
  1690. delete pLocation;
  1691. }
  1692. break;
  1693. }
  1694. node = node->next();
  1695. }
  1696. }
  1697. /****************************************************************************
  1698. Class : CLocations
  1699. Method : Replace
  1700. Replace pLocOld with pLocNew. These locations must have the same
  1701. location ID.
  1702. ****************************************************************************/
  1703. void CLocations::Replace(CLocation * pLocOld, CLocation * pLocNew)
  1704. {
  1705. if ( pLocOld->GetLocationID() != pLocNew->GetLocationID() )
  1706. {
  1707. LOG((TL_ERROR, "Replace: Illegal"));
  1708. return;
  1709. }
  1710. CLocationNode *node = m_LocationList.head();
  1711. while( !node->beyond_tail() )
  1712. {
  1713. if ( pLocOld == node->value() )
  1714. {
  1715. // node->remove();
  1716. // m_LocationList.tail()->insert_after(pLocNew);
  1717. node->value() = pLocNew;
  1718. delete pLocOld;
  1719. break;
  1720. }
  1721. node = node->next();
  1722. }
  1723. }
  1724. /****************************************************************************
  1725. Class : CLocations
  1726. Method : Add
  1727. Put it in the list
  1728. ****************************************************************************/
  1729. void CLocations::Add(CLocation * pLocation)
  1730. {
  1731. m_LocationList.tail()->insert_after(pLocation);
  1732. m_dwNumEntries++;
  1733. }
  1734. /****************************************************************************
  1735. Class : CLocations
  1736. Method : Reset
  1737. Set enumerator to start
  1738. ****************************************************************************/
  1739. HRESULT CLocations::Reset(void)
  1740. {
  1741. m_hEnumNode = m_LocationList.head();
  1742. return S_OK;
  1743. }
  1744. /****************************************************************************
  1745. Class : CLocations
  1746. Method : Next
  1747. get next location in list
  1748. ****************************************************************************/
  1749. HRESULT CLocations::Next(DWORD NrElem, CLocation **ppLocation, DWORD *pNrElemFetched)
  1750. {
  1751. DWORD dwIndex = 0;
  1752. if(pNrElemFetched == NULL && NrElem != 1)
  1753. return E_INVALIDARG;
  1754. if(ppLocation==NULL)
  1755. return E_INVALIDARG;
  1756. while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
  1757. {
  1758. *ppLocation++ = m_hEnumNode->value();
  1759. m_hEnumNode = m_hEnumNode->next();
  1760. dwIndex++;
  1761. }
  1762. if(pNrElemFetched!=NULL)
  1763. *pNrElemFetched = dwIndex;
  1764. return dwIndex<NrElem ? S_FALSE : S_OK;
  1765. }
  1766. /****************************************************************************
  1767. Class : CLocations
  1768. Method : Skip
  1769. Miss a few
  1770. ****************************************************************************/
  1771. HRESULT CLocations::Skip(DWORD NrElem)
  1772. {
  1773. DWORD dwIndex = 0;
  1774. while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
  1775. {
  1776. m_hEnumNode = m_hEnumNode->next();
  1777. dwIndex++;
  1778. }
  1779. return dwIndex<NrElem ? S_FALSE : S_OK;
  1780. }
  1781. /*
  1782. ***************************************************************************
  1783. ********************* ****************************
  1784. ******************** CCountry Class ***************************
  1785. ******************** Definitions ***************************
  1786. ********************* ****************************
  1787. ***************************************************************************
  1788. */
  1789. /****************************************************************************
  1790. Class : CCountry
  1791. Method : Constructer
  1792. ****************************************************************************/
  1793. CCountry::CCountry()
  1794. {
  1795. m_dwCountryID = 0;
  1796. m_dwCountryCode = 0;
  1797. m_dwCountryGroup = 0;
  1798. m_pszCountryName = NULL;
  1799. }
  1800. /****************************************************************************
  1801. Class : CCountry
  1802. Method : Destructer
  1803. Clean up memory allocations
  1804. ****************************************************************************/
  1805. CCountry::~CCountry()
  1806. {
  1807. if ( m_pszCountryName != NULL )
  1808. {
  1809. ClientFree(m_pszCountryName);
  1810. }
  1811. }
  1812. /****************************************************************************
  1813. Class : CCountry
  1814. Method : Initialize
  1815. ****************************************************************************/
  1816. STDMETHODIMP CCountry::Initialize
  1817. (
  1818. DWORD dwCountryID,
  1819. DWORD dwCountryCode,
  1820. DWORD dwCountryGroup,
  1821. PWSTR pszCountryName,
  1822. PWSTR pszInternationalRule,
  1823. PWSTR pszLongDistanceRule,
  1824. PWSTR pszLocalRule
  1825. )
  1826. {
  1827. HRESULT hr = S_OK;
  1828. m_dwCountryID = dwCountryID;
  1829. m_dwCountryCode = dwCountryCode;
  1830. m_dwCountryGroup = dwCountryGroup;
  1831. m_pszCountryName = ClientAllocString( pszCountryName );
  1832. if (m_pszCountryName == NULL)
  1833. {
  1834. LOG(( TL_ERROR, "Initialize - alloc pszLocationName failed" ));
  1835. hr = E_OUTOFMEMORY;
  1836. }
  1837. else
  1838. {
  1839. hr = m_Rules.Initialize(pszInternationalRule,
  1840. pszLongDistanceRule,
  1841. pszLocalRule
  1842. );
  1843. if(FAILED(hr) )
  1844. {
  1845. hr = E_OUTOFMEMORY;
  1846. }
  1847. }
  1848. return hr;
  1849. }
  1850. /*
  1851. ***************************************************************************
  1852. ********************* ****************************
  1853. ******************** CCountries Class ***************************
  1854. ******************** Definitions ***************************
  1855. ********************* ****************************
  1856. ***************************************************************************
  1857. */
  1858. /****************************************************************************
  1859. Class : CCountries
  1860. Method : Constructer
  1861. ****************************************************************************/
  1862. CCountries::CCountries()
  1863. {
  1864. m_dwNumEntries = 0;
  1865. m_hEnumNode = m_CountryList.head();
  1866. }
  1867. /****************************************************************************
  1868. Class : CCountries
  1869. Method : Destructer
  1870. ****************************************************************************/
  1871. CCountries::~CCountries()
  1872. {
  1873. CCountryNode *node;
  1874. node = m_CountryList.head();
  1875. while( !node->beyond_tail() )
  1876. {
  1877. delete node->value();
  1878. node = node->next();
  1879. }
  1880. m_CountryList.flush();
  1881. }
  1882. /****************************************************************************
  1883. Class : CCountries
  1884. Method : Initialize
  1885. Read the countries list from registry via TAPISRV & build our
  1886. object list.
  1887. ****************************************************************************/
  1888. HRESULT CCountries::Initialize(void)
  1889. {
  1890. LPLINECOUNTRYLIST_INTERNAL pCountryList = NULL;
  1891. LPLINECOUNTRYENTRY_INTERNAL pEntry = NULL;
  1892. PWSTR pszCountryName = NULL;
  1893. PWSTR pszInternationalRule = NULL;
  1894. PWSTR pszLongDistanceRule = NULL;
  1895. PWSTR pszLocalRule = NULL;
  1896. CCountry * pCountry = NULL;
  1897. DWORD dwCount = 0;
  1898. DWORD dwNumEntries = 0;
  1899. LONG lResult;
  1900. HRESULT hr;
  1901. lResult = ReadCountriesAndGroups( &pCountryList, 0, 0);
  1902. if (lResult == 0)
  1903. {
  1904. // Find position of 1st LINECOUNTRYENTRY structure in the LINECOUNTRYLIST structure
  1905. pEntry = (LPLINECOUNTRYENTRY_INTERNAL) ((BYTE*)(pCountryList) + pCountryList->dwCountryListOffset );
  1906. dwNumEntries = pCountryList->dwNumCountries;
  1907. for (dwCount = 0; dwCount < dwNumEntries ; dwCount++)
  1908. {
  1909. // Pull Country Info out of LINECOUNTRYENTRY structure
  1910. pszCountryName = (PWSTR) ((BYTE*)(pCountryList)
  1911. + pEntry->dwCountryNameOffset);
  1912. pszInternationalRule = (PWSTR) ((BYTE*)(pCountryList)
  1913. + pEntry->dwInternationalRuleOffset);
  1914. pszLongDistanceRule = (PWSTR) ((BYTE*)(pCountryList)
  1915. + pEntry->dwLongDistanceRuleOffset);
  1916. pszLocalRule = (PWSTR) ((BYTE*)(pCountryList)
  1917. + pEntry->dwSameAreaRuleOffset);
  1918. // create our new CCountry Object
  1919. pCountry = new CCountry;
  1920. if (pCountry)
  1921. {
  1922. // initialize the new CCountry Object
  1923. hr = pCountry->Initialize(pEntry->dwCountryID,
  1924. pEntry->dwCountryCode,
  1925. pEntry->dwCountryGroup,
  1926. pszCountryName,
  1927. pszInternationalRule,
  1928. pszLongDistanceRule,
  1929. pszLocalRule
  1930. );
  1931. if( SUCCEEDED(hr) )
  1932. {
  1933. m_CountryList.tail()->insert_after(pCountry);
  1934. m_dwNumEntries++;
  1935. }
  1936. else // country initialization failed
  1937. {
  1938. delete pCountry;
  1939. LOG((TL_ERROR, "Initialize - country create failed"));
  1940. }
  1941. }
  1942. else // new CCountry failed
  1943. {
  1944. LOG((TL_ERROR, "Initialize - country create failed"));
  1945. }
  1946. // Try next country in list
  1947. pEntry++;
  1948. }
  1949. }
  1950. else // ReadLocations failed
  1951. {
  1952. LOG((TL_ERROR, "Initialize - ReadCountries failed"));
  1953. hr = (HRESULT)lResult;
  1954. }
  1955. // finished with TAPI memory block so release
  1956. if ( pCountryList != NULL )
  1957. {
  1958. ClientFree( pCountryList );
  1959. }
  1960. return hr;
  1961. }
  1962. /****************************************************************************
  1963. Class : CCountries
  1964. Method : Reset
  1965. ****************************************************************************/
  1966. HRESULT CCountries::Reset(void)
  1967. {
  1968. m_hEnumNode = m_CountryList.head();
  1969. return S_OK;
  1970. }
  1971. /****************************************************************************
  1972. Class : CCountries
  1973. Method : Next
  1974. ****************************************************************************/
  1975. HRESULT CCountries::Next(DWORD NrElem, CCountry **ppCcountry, DWORD *pNrElemFetched)
  1976. {
  1977. DWORD dwIndex = 0;
  1978. if(pNrElemFetched == NULL && NrElem != 1)
  1979. return E_INVALIDARG;
  1980. if(ppCcountry==NULL)
  1981. return E_INVALIDARG;
  1982. while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
  1983. {
  1984. *ppCcountry++ = m_hEnumNode->value();
  1985. m_hEnumNode = m_hEnumNode->next();
  1986. dwIndex++;
  1987. }
  1988. if(pNrElemFetched!=NULL)
  1989. *pNrElemFetched = dwIndex;
  1990. return dwIndex<NrElem ? S_FALSE : S_OK;
  1991. }
  1992. /****************************************************************************
  1993. Class : CCountries
  1994. Method : Skip
  1995. ****************************************************************************/
  1996. HRESULT CCountries::Skip(DWORD NrElem)
  1997. {
  1998. DWORD dwIndex = 0;
  1999. while( !m_hEnumNode->beyond_tail() && dwIndex<NrElem )
  2000. {
  2001. m_hEnumNode = m_hEnumNode->next();
  2002. dwIndex++;
  2003. }
  2004. return dwIndex<NrElem ? S_FALSE : S_OK;
  2005. }
  2006. /*
  2007. ***************************************************************************
  2008. ********************* ****************************
  2009. ******************** Helper ***************************
  2010. ******************** Functions ***************************
  2011. ********************* ****************************
  2012. ***************************************************************************
  2013. */
  2014. /****************************************************************************
  2015. Function : ApplyRule
  2016. Parse though a tapi rule string & build dialable & displayable
  2017. strings from the required components.
  2018. out pszDialString
  2019. pszDisplayString
  2020. in pszRule
  2021. pszLongDistanceCarrier
  2022. pszInternationalCarrier
  2023. pszCountry
  2024. pszCity
  2025. pszSubscriber
  2026. pszCardName
  2027. pszCardAccessNumber
  2028. pszCardAccountNumber
  2029. pszCardPINNumber
  2030. ****************************************************************************/
  2031. LONG ApplyRule (PWSTR pszDialString,
  2032. PWSTR pszDisplayString,
  2033. PWSTR pszRule,
  2034. PWSTR pszDestLDRule,
  2035. PWSTR pszLongDistanceCarrier,
  2036. PWSTR pszInternationalCarrier,
  2037. PWSTR pszCountry,
  2038. PWSTR pszCity,
  2039. PWSTR pszSubscriber,
  2040. PWSTR pszCardName,
  2041. PWSTR pszCardAccessNumber,
  2042. PWSTR pszCardAccountNumber,
  2043. PWSTR pszCardPINNumber
  2044. )
  2045. {
  2046. WCHAR * pRuleChar;
  2047. DWORD dwEndString;
  2048. PWSTR pszAdjustedCity;
  2049. PWSTR pszSubaddress;
  2050. WCHAR wcSubaddrSep;
  2051. BOOL bSpaceExists, bOutOfMem = FALSE;
  2052. bSpaceExists = TRUE;
  2053. HRESULT hr;
  2054. for (pRuleChar = pszRule; *pRuleChar != '\0' && !bOutOfMem; pRuleChar++)
  2055. {
  2056. switch(*pRuleChar)
  2057. {
  2058. //Dial the Long Distance Carrier Code
  2059. case 'L':
  2060. case 'l':
  2061. case 'N':
  2062. case 'n':
  2063. {
  2064. if (pszLongDistanceCarrier)
  2065. {
  2066. hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszLongDistanceCarrier, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2067. bOutOfMem = bOutOfMem && FAILED(hr);
  2068. if (!bSpaceExists)
  2069. {
  2070. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2071. bOutOfMem = bOutOfMem && FAILED(hr);
  2072. }
  2073. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszLongDistanceCarrier, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2074. bOutOfMem = bOutOfMem && FAILED(hr);
  2075. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2076. bOutOfMem = bOutOfMem && FAILED(hr);
  2077. bSpaceExists = TRUE;
  2078. }
  2079. break;
  2080. }
  2081. //Dial the International Carrier Code
  2082. case 'M':
  2083. case 'm':
  2084. case 'S':
  2085. case 's':
  2086. {
  2087. if (pszInternationalCarrier)
  2088. {
  2089. hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszInternationalCarrier, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2090. bOutOfMem = bOutOfMem && FAILED(hr);
  2091. if (!bSpaceExists)
  2092. {
  2093. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2094. bOutOfMem = bOutOfMem && FAILED(hr);
  2095. }
  2096. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszInternationalCarrier, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2097. bOutOfMem = bOutOfMem && FAILED(hr);
  2098. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2099. bOutOfMem = bOutOfMem && FAILED(hr);
  2100. bSpaceExists = TRUE;
  2101. }
  2102. break;
  2103. }
  2104. // Dial the Country Code
  2105. case 'E':
  2106. case 'e':
  2107. {
  2108. hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszCountry, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2109. bOutOfMem = bOutOfMem && FAILED(hr);
  2110. if(!bSpaceExists)
  2111. {
  2112. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2113. bOutOfMem = bOutOfMem && FAILED(hr);
  2114. }
  2115. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszCountry, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2116. bOutOfMem = bOutOfMem && FAILED(hr);
  2117. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2118. bOutOfMem = bOutOfMem && FAILED(hr);
  2119. bSpaceExists = TRUE;
  2120. break;
  2121. }
  2122. // Dial the City/Area Code
  2123. case 'F':
  2124. case 'f':
  2125. case 'I':
  2126. case 'i':
  2127. {
  2128. // adjust the area code (see bug 279092)
  2129. pszAdjustedCity = SkipLDAccessDigits(pszCity, pszDestLDRule);
  2130. if(pszAdjustedCity && *pszAdjustedCity!=L'\0')
  2131. {
  2132. hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszAdjustedCity, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2133. bOutOfMem = bOutOfMem && FAILED(hr);
  2134. if(!bSpaceExists)
  2135. {
  2136. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2137. bOutOfMem = bOutOfMem && FAILED(hr);
  2138. }
  2139. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszAdjustedCity, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2140. bOutOfMem = bOutOfMem && FAILED(hr);
  2141. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2142. bOutOfMem = bOutOfMem && FAILED(hr);
  2143. bSpaceExists = TRUE;
  2144. }
  2145. break;
  2146. }
  2147. // Dial the Subscriber Number
  2148. case 'G':
  2149. case 'g':
  2150. {
  2151. // we let through digits & "AaBbCcDdPpTtWw*#!,@$?;()"
  2152. // but after a '|' or '^' we let all through
  2153. pszSubaddress = pszSubscriber + wcscspn(pszSubscriber, (PWSTR)csSCANSUB);
  2154. wcSubaddrSep = *pszSubaddress;
  2155. *pszSubaddress = L'\0';
  2156. if(AppendDigits( pszDialString, pszSubscriber, (PWSTR)csBADCO))
  2157. {
  2158. bOutOfMem = TRUE;
  2159. }
  2160. else
  2161. {
  2162. if(wcSubaddrSep != L'\0')
  2163. {
  2164. *pszSubaddress = wcSubaddrSep;
  2165. hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszSubaddress, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2166. bOutOfMem = bOutOfMem && FAILED(hr);
  2167. }
  2168. if(!bSpaceExists)
  2169. {
  2170. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2171. bOutOfMem = bOutOfMem && FAILED(hr);
  2172. }
  2173. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszSubscriber, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2174. bOutOfMem = bOutOfMem && FAILED(hr);
  2175. bSpaceExists = FALSE;
  2176. }
  2177. break;
  2178. }
  2179. // Dial the Calling Card Access Number
  2180. case 'J':
  2181. case 'j':
  2182. {
  2183. // just let through digits
  2184. if (AppendDigits( pszDialString, pszCardAccessNumber, L""))
  2185. {
  2186. bOutOfMem = TRUE;
  2187. }
  2188. else
  2189. {
  2190. if(!bSpaceExists)
  2191. {
  2192. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2193. bOutOfMem = bOutOfMem && FAILED(hr);
  2194. }
  2195. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszCardAccessNumber, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2196. bOutOfMem = bOutOfMem && FAILED(hr);
  2197. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2198. bOutOfMem = bOutOfMem && FAILED(hr);
  2199. bSpaceExists = TRUE;
  2200. }
  2201. break;
  2202. }
  2203. // Dial the Calling Card Account Number
  2204. case 'K':
  2205. case 'k':
  2206. {
  2207. // just let through digits
  2208. if (AppendDigits( pszDialString, pszCardAccountNumber, L""))
  2209. {
  2210. bOutOfMem = TRUE;
  2211. }
  2212. else
  2213. {
  2214. if(!bSpaceExists)
  2215. {
  2216. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2217. bOutOfMem = bOutOfMem && FAILED(hr);
  2218. }
  2219. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L"[", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2220. bOutOfMem = bOutOfMem && FAILED(hr);
  2221. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, pszCardName, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2222. bOutOfMem = bOutOfMem && FAILED(hr);
  2223. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L"] ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2224. bOutOfMem = bOutOfMem && FAILED(hr);
  2225. bSpaceExists = TRUE;
  2226. }
  2227. break;
  2228. }
  2229. // Dial the Calling Card PIN Number
  2230. case 'H':
  2231. case 'h':
  2232. {
  2233. hr = StringCchCatExW(pszDialString, MaxDialStringSize, pszCardPINNumber, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2234. bOutOfMem = bOutOfMem && FAILED(hr);
  2235. if(!bSpaceExists)
  2236. {
  2237. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L" ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2238. bOutOfMem = bOutOfMem && FAILED(hr);
  2239. }
  2240. hr = StringCchCatExW(pszDisplayString, MaxDialStringSize, L"**** ", NULL, NULL, STRSAFE_NO_TRUNCATION);
  2241. bOutOfMem = bOutOfMem && FAILED(hr);
  2242. bSpaceExists = TRUE;
  2243. break;
  2244. }
  2245. // Just append the character to the dial/display string
  2246. default:
  2247. {
  2248. dwEndString = lstrlenW(pszDialString);
  2249. if (dwEndString < MaxDialStringSize - 1)
  2250. {
  2251. pszDialString[dwEndString] = *pRuleChar;
  2252. pszDialString[dwEndString+1] = '\0';
  2253. }
  2254. else
  2255. {
  2256. bOutOfMem = TRUE;
  2257. }
  2258. // don't display certain chars
  2259. if (!wcschr(csDISPSUPRESS,*pRuleChar))
  2260. {
  2261. dwEndString = lstrlenW(pszDisplayString);
  2262. if (dwEndString < MaxDialStringSize - 1)
  2263. {
  2264. pszDisplayString[dwEndString] = *pRuleChar;
  2265. pszDisplayString[dwEndString+1] = '\0';
  2266. }
  2267. else
  2268. {
  2269. bOutOfMem = TRUE;
  2270. }
  2271. }
  2272. bSpaceExists = FALSE;
  2273. break;
  2274. }
  2275. }
  2276. }
  2277. if (bOutOfMem)
  2278. {
  2279. return LINEERR_NOMEM;
  2280. }
  2281. return 0;
  2282. }
  2283. /****************************************************************************
  2284. Function : TapiPackString
  2285. Takes a string & copys it to a tapi location + offset
  2286. updates the entry offset & size dwords
  2287. returns size of copied string (used to adjust offset for next string)
  2288. ****************************************************************************/
  2289. DWORD TapiPackString(LPBYTE pStructure,
  2290. DWORD dwOffset,
  2291. DWORD dwTotalSize,
  2292. PWSTR pszString,
  2293. PDWORD pdwOffset,
  2294. PDWORD pdwSize
  2295. )
  2296. {
  2297. DWORD dwSize;
  2298. dwSize = ALIGN((lstrlenW(pszString) + 1) * sizeof(WCHAR));
  2299. if (NULL != pszString)
  2300. {
  2301. StringCchCopyEx((PWSTR)(pStructure + dwOffset), (dwTotalSize - dwOffset)/sizeof(WCHAR), pszString, NULL, NULL, STRSAFE_NO_TRUNCATION);
  2302. }
  2303. else
  2304. {
  2305. *(PWSTR)(pStructure + dwOffset) = L'\0';
  2306. }
  2307. *pdwOffset = dwOffset;
  2308. *pdwSize = dwSize;
  2309. return dwSize;
  2310. }
  2311. /****************************************************************************
  2312. Function : PrefixMatch
  2313. Checks if Subscriber number starts with the given prefix
  2314. Takes into account the only the digits.
  2315. returns FALSE if not matched, else TRUE & number of matched chars
  2316. ****************************************************************************/
  2317. BOOL PrefixMatch(PWSTR pszPrefix,PWSTR pszSubscriberString, PDWORD pdwMatched)
  2318. {
  2319. DWORD dwCount =0;
  2320. PWSTR pPrefixChar = pszPrefix;
  2321. PWSTR pSSChar = pszSubscriberString;
  2322. // The prefix must be contiguous (without commas etc.)
  2323. while( (*pPrefixChar != '\0') && (*pSSChar != '\0') )
  2324. {
  2325. if(iswdigit(*pSSChar))
  2326. {
  2327. if(*pPrefixChar == *pSSChar)
  2328. {
  2329. dwCount++;
  2330. pPrefixChar++;
  2331. pSSChar++;
  2332. }
  2333. else // no match
  2334. {
  2335. dwCount= 0;
  2336. break;
  2337. }
  2338. }
  2339. else
  2340. {
  2341. // This was not a digit, skip it
  2342. pSSChar++;
  2343. }
  2344. }
  2345. // just in case subscriber string was shorter than the prefix
  2346. if(*pPrefixChar != '\0')
  2347. {
  2348. dwCount = 0;
  2349. }
  2350. // return values
  2351. *pdwMatched = dwCount;
  2352. if(dwCount !=0)
  2353. {
  2354. return TRUE;
  2355. }
  2356. else
  2357. {
  2358. return FALSE;
  2359. }
  2360. }
  2361. /****************************************************************************
  2362. Function : AppendDigits
  2363. Copies only digits up to end of string.
  2364. Simply exit if string is NULL
  2365. ****************************************************************************/
  2366. LONG AppendDigits( PWSTR pDest,
  2367. PWSTR pSrc,
  2368. PWSTR pValidChars
  2369. )
  2370. {
  2371. WCHAR * pSrcChar;
  2372. WCHAR * pDestChar;
  2373. LONG lReturn = 0;
  2374. if (pSrc != NULL)
  2375. {
  2376. pDestChar = pDest + lstrlenW(pDest);
  2377. pSrcChar = pSrc;
  2378. while (*pSrcChar != '\0' && (pDestChar - pDest < MaxDialStringSize - 1))
  2379. {
  2380. if ( iswdigit(*pSrcChar) || (wcschr(pValidChars, *pSrcChar)) )
  2381. {
  2382. *pDestChar++ = *pSrcChar;
  2383. }
  2384. pSrcChar++;
  2385. }
  2386. if (*pSrcChar != '\0')
  2387. {
  2388. lReturn = LINEERR_NOMEM;
  2389. }
  2390. }
  2391. return lReturn;
  2392. }
  2393. /****************************************************************************
  2394. Function : AreaCodeMatch
  2395. Compares two areas codes. Returns TRUE if they are the same.
  2396. Adjusts internally the area codes using the LD rule given as a parameter.
  2397. See bug 279092
  2398. ****************************************************************************/
  2399. BOOL AreaCodeMatch(PWSTR pszAreaCode1, PWSTR pszAreaCode2, PWSTR pszRule)
  2400. {
  2401. PWSTR pszAdjustedAreaCode1;
  2402. PWSTR pszAdjustedAreaCode2;
  2403. BOOL bRet = FALSE;
  2404. pszAdjustedAreaCode1 = SkipLDAccessDigits(pszAreaCode1, pszRule);
  2405. pszAdjustedAreaCode2 = SkipLDAccessDigits(pszAreaCode2, pszRule);
  2406. if (NULL != pszAdjustedAreaCode1 &&
  2407. NULL != pszAdjustedAreaCode2)
  2408. {
  2409. bRet = (0==lstrcmpW(pszAdjustedAreaCode1, pszAdjustedAreaCode2));
  2410. }
  2411. return bRet;
  2412. }
  2413. /****************************************************************************
  2414. Function : SkipLDAccessDigits
  2415. Skips the characters from an area code which corespond to a LD access prefix
  2416. Returns a pointer to the correct area code.
  2417. Presumes that the first digits of the rule are in fact the LD acces prefix.
  2418. See bug 279092
  2419. ****************************************************************************/
  2420. PWSTR SkipLDAccessDigits(PWSTR pszAreaCode, PWSTR pszLDRule)
  2421. {
  2422. if(pszAreaCode!=NULL)
  2423. {
  2424. // A space in the rule prevents the matching/striping mechanism
  2425. // Uncomment if you don't want that.
  2426. // while(*pszLDRule == L' ')
  2427. // pszLDRule++;
  2428. //
  2429. // A long distance rule may have a L/l or N/n at the beginning, need to skip it
  2430. //
  2431. if (*pszLDRule == L'L' ||
  2432. *pszLDRule == L'l' ||
  2433. *pszLDRule == L'N' ||
  2434. *pszLDRule == L'n'
  2435. )
  2436. {
  2437. pszLDRule++;
  2438. }
  2439. while(*pszLDRule && iswdigit(*pszLDRule) && *pszAreaCode==*pszLDRule)
  2440. {
  2441. pszAreaCode++;
  2442. pszLDRule++;
  2443. }
  2444. }
  2445. return pszAreaCode;
  2446. }