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.

1315 lines
39 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: phbk.cpp
  4. //
  5. // Module: CMPBK32.DLL
  6. //
  7. // Synopsis: Implementation of CPhoneBook
  8. //
  9. // Copyright (c) 1998-1999 Microsoft Corporation
  10. //
  11. // Author: quintinb created header 08/17/99
  12. //
  13. //+----------------------------------------------------------------------------
  14. // ############################################################################
  15. // Phone book APIs
  16. #include "cmmaster.h"
  17. const TCHAR* const c_pszInfDefault = TEXT("INF_DEFAULT");
  18. const TCHAR* const c_pszInfSuffix = TEXT(".CMS");
  19. //#define ReadVerifyPhoneBookDW(x) CMASSERTMSG(ReadPhoneBookDW(&(x),pcCSVFile),"Invalid DWORD in phone book");
  20. #define ReadVerifyPhoneBookDW(x) if (!ReadPhoneBookDW(&(x),pcCSVFile)) \
  21. { CMASSERTMSG(0,"Invalid DWORD in phone book"); \
  22. goto DataError; }
  23. #define ReadVerifyPhoneBookW(x) if (!ReadPhoneBookW(&(x),pcCSVFile)) \
  24. { CMASSERTMSG(0,"Invalid WORD in phone book"); \
  25. goto DataError; }
  26. #define ReadVerifyPhoneBookB(x) if (!ReadPhoneBookB(&(x),pcCSVFile)) \
  27. { CMASSERTMSG(0,"Invalid BYTE in phone book"); \
  28. goto DataError; }
  29. #define ReadVerifyPhoneBookSZ(x,y) if (!ReadPhoneBookSZ(&x[0],y+sizeof('\0'),pcCSVFile)) \
  30. { CMASSERTMSG(0,"Invalid STRING in phone book"); \
  31. goto DataError; }
  32. #define CHANGE_BUFFER_SIZE 50
  33. #define ERROR_USERBACK 32766
  34. #define ERROR_USERCANCEL 32767
  35. // ############################################################################
  36. void CPhoneBook::EnumNumbersByCountry(DWORD dwCountryID, PPBFS pFilter, CB_PHONEBOOK pfnNumber, DWORD_PTR dwParam)
  37. {
  38. MYDBG(("CPhoneBook::EnumNumbersByCountry"));
  39. PACCESSENTRY pAELast, pAE = NULL;
  40. PIDLOOKUPELEMENT pIDLookUp;
  41. IDLOOKUPELEMENT LookUpTarget;
  42. LookUpTarget.dwID = dwCountryID;
  43. pIDLookUp = NULL;
  44. pIDLookUp = (PIDLOOKUPELEMENT)CmBSearch(&LookUpTarget,m_rgIDLookUp,
  45. (size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),CompareIDLookUpElements);
  46. if (pIDLookUp)
  47. pAE = IdxToPAE(pIDLookUp->iFirstAE);
  48. // Fill the list for whatever AE's we found
  49. //
  50. if (pAE)
  51. {
  52. pAELast = &(m_rgPhoneBookEntry[m_cPhoneBookEntries - 1]);
  53. while (pAELast >= pAE)
  54. {
  55. if (pAE->dwCountryID == dwCountryID && pAE->wStateID == 0) {
  56. if (PhoneBookMatchFilter(pFilter,pAE->fType))
  57. {
  58. pfnNumber((unsigned int) (pAE - m_rgPhoneBookEntry),dwParam);
  59. }
  60. }
  61. pAE++;
  62. }
  63. // Select the first item
  64. //
  65. }
  66. }
  67. // ############################################################################
  68. void CPhoneBook::EnumNumbersByCountry(DWORD dwCountryID, DWORD dwMask, DWORD fType, CB_PHONEBOOK pfnNumber, DWORD_PTR dwParam)
  69. {
  70. MYDBG(("CPhoneBook::EnumNumbersByCountry"));
  71. PhoneBookFilterStruct sFilter = {1,{{dwMask,fType}}};
  72. EnumNumbersByCountry(dwCountryID,&sFilter,pfnNumber,dwParam);
  73. }
  74. // ############################################################################
  75. BOOL CPhoneBook::FHasPhoneType(PPBFS pFilter)
  76. {
  77. MYDBG(("CPhoneBook::FHasPhoneType"));
  78. PACCESSENTRY pAELast, pAE = NULL;
  79. pAE = &(m_rgPhoneBookEntry[0]); // pAE points to the first phone book entry
  80. //
  81. // Examine each entry until we find a match or exhaust the entries
  82. //
  83. if (pAE)
  84. {
  85. pAELast = &(m_rgPhoneBookEntry[m_cPhoneBookEntries - 1]);
  86. while (pAELast >= pAE)
  87. {
  88. //
  89. // See if this pop passes the specified filter
  90. //
  91. if (PhoneBookMatchFilter(pFilter, pAE->fType))
  92. {
  93. return TRUE;
  94. }
  95. pAE++;
  96. }
  97. }
  98. return FALSE;
  99. }
  100. // ############################################################################
  101. void CPhoneBook::EnumNumbersByRegion(unsigned int nRegion, DWORD dwCountryID, PPBFS pFilter, CB_PHONEBOOK pfnNumber, DWORD_PTR dwParam)
  102. {
  103. MYDBG(("CPhoneBook::EnumNumbersByRegion"));
  104. PACCESSENTRY pAELast, pAE = NULL;
  105. pAE = &m_rgPhoneBookEntry[0]; // pAE points to the first phone book entry
  106. // Fill the list for whatever AE's we found
  107. if (pAE)
  108. {
  109. pAELast = &(m_rgPhoneBookEntry[m_cPhoneBookEntries - 1]);
  110. while (pAELast >= pAE)
  111. {
  112. // choose phone number of the same region OR with region ID = 0(which means ALL regions)
  113. if (pAE->dwCountryID == dwCountryID &&
  114. ((pAE->wStateID == nRegion+1) || (pAE->wStateID == 0)))
  115. {
  116. if (PhoneBookMatchFilter(pFilter,pAE->fType))
  117. pfnNumber((unsigned int) (pAE - m_rgPhoneBookEntry), dwParam);
  118. }
  119. pAE++;
  120. }
  121. // Select the first item
  122. //
  123. }
  124. }
  125. // ############################################################################
  126. void CPhoneBook::EnumNumbersByRegion(unsigned int nRegion, DWORD dwCountryID, DWORD dwMask, DWORD fType, CB_PHONEBOOK pfnNumber, DWORD_PTR dwParam)
  127. {
  128. MYDBG(("CPhoneBook::EnumNumbersByRegion"));
  129. PhoneBookFilterStruct sFilter = {1,{{dwMask,fType}}};
  130. EnumNumbersByRegion(nRegion,dwCountryID,&sFilter,pfnNumber,dwParam);
  131. }
  132. // ############################################################################
  133. void CPhoneBook::EnumRegions(DWORD dwCountryID, PPBFS pFilter, CB_PHONEBOOK pfnRegion, DWORD_PTR dwParam)
  134. {
  135. unsigned int idx;
  136. MYDBG(("CPhoneBook::EnumRegions"));
  137. for (idx=0;idx<m_cStates;idx++)
  138. {
  139. PACCESSENTRY pAE = NULL, pAELast = NULL;
  140. pAE = &m_rgPhoneBookEntry[0];
  141. MYDBGASSERT(pAE);
  142. pAELast = &(m_rgPhoneBookEntry[m_cPhoneBookEntries - 1]);
  143. while (pAELast >= pAE)
  144. {
  145. if (pAE->dwCountryID == dwCountryID &&
  146. pAE->wStateID == idx+1)
  147. {
  148. if (PhoneBookMatchFilter(pFilter,pAE->fType))
  149. goto AddRegion;
  150. }
  151. pAE++;
  152. } // while
  153. continue; // start the next 'for' loop
  154. AddRegion:
  155. pfnRegion(idx,dwParam);
  156. }
  157. }
  158. // ############################################################################
  159. void CPhoneBook::EnumRegions(DWORD dwCountryID, DWORD dwMask, DWORD fType, CB_PHONEBOOK pfnRegion, DWORD_PTR dwParam)
  160. {
  161. MYDBG(("CPhoneBook::EnumRegions"));
  162. PhoneBookFilterStruct sFilter = {1,{{dwMask,fType}}};
  163. EnumRegions(dwCountryID,&sFilter,pfnRegion,dwParam);
  164. }
  165. // ############################################################################
  166. void CPhoneBook::EnumCountries(PPBFS pFilter, CB_PHONEBOOK pfnCountry, DWORD_PTR dwParam)
  167. {
  168. unsigned int idx;
  169. MYDBG(("CPhoneBook::EnumCountries"));
  170. for (idx=0;idx<m_pLineCountryList->dwNumCountries;idx++)
  171. {
  172. if (FHasPhoneNumbers(m_rgNameLookUp[idx].pLCE->dwCountryID,pFilter))
  173. {
  174. pfnCountry(idx,dwParam);
  175. }
  176. }
  177. }
  178. // ############################################################################
  179. void CPhoneBook::EnumCountries(DWORD dwMask, DWORD fType, CB_PHONEBOOK pfnCountry, DWORD_PTR dwParam)
  180. {
  181. MYDBG(("CPhoneBook::EnumCountries"));
  182. PhoneBookFilterStruct sFilter = {1,{{dwMask,fType}}};
  183. EnumCountries(&sFilter,pfnCountry,dwParam);
  184. }
  185. // ############################################################################
  186. BOOL CPhoneBook::FHasPhoneNumbers(DWORD dwCountryID, PPBFS pFilter)
  187. {
  188. PIDLOOKUPELEMENT pIDLookUp;
  189. IDLOOKUPELEMENT LookUpTarget;
  190. PACCESSENTRY pAE = NULL, pAELast = NULL;
  191. DWORD dwTmpCountryID;
  192. LookUpTarget.dwID = dwCountryID;
  193. pIDLookUp = NULL;
  194. pIDLookUp = (PIDLOOKUPELEMENT)CmBSearch(&LookUpTarget,m_rgIDLookUp,
  195. (size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),CompareIDLookUpElements);
  196. if (!pIDLookUp) return FALSE; // no such country
  197. pAE = IdxToPAE(pIDLookUp->iFirstAE);
  198. if (!pAE) return FALSE; // no phone numbers at all
  199. dwTmpCountryID = pAE->dwCountryID;
  200. pAELast = &(m_rgPhoneBookEntry[m_cPhoneBookEntries - 1]);
  201. while (pAELast >= pAE) {
  202. if (pAE->dwCountryID == dwTmpCountryID)
  203. {
  204. if (PhoneBookMatchFilter(pFilter,pAE->fType)) return TRUE;
  205. }
  206. pAE++;
  207. }
  208. return FALSE; // no phone numbers of the right type
  209. // return ((BOOL)(pIDLookUp->pFirstAE));
  210. }
  211. // ############################################################################
  212. BOOL CPhoneBook::FHasPhoneNumbers(DWORD dwCountryID, DWORD dwMask, DWORD fType)
  213. {
  214. MYDBG(("CPhoneBook::FHasPhoneNumbers"));
  215. PhoneBookFilterStruct sFilter = {1,{{dwMask,fType}}};
  216. return FHasPhoneNumbers(dwCountryID,&sFilter);
  217. }
  218. // ############################################################################
  219. CPhoneBook::CPhoneBook()
  220. {
  221. m_rgPhoneBookEntry = NULL;
  222. m_cPhoneBookEntries =0;
  223. m_rgLineCountryEntry=NULL;
  224. m_rgState=NULL;
  225. m_cStates=0;
  226. m_rgIDLookUp = NULL;
  227. m_rgNameLookUp = NULL;
  228. m_pLineCountryList = NULL;
  229. MYDBG(("CPhoneBook::CPhoneBook"));
  230. ZeroMemory(&m_szINFFile[0],MAX_PATH);
  231. ZeroMemory(&m_szPhoneBook[0],MAX_PATH);
  232. }
  233. // ############################################################################
  234. CPhoneBook::~CPhoneBook()
  235. {
  236. MYDBG(("CPhoneBook::~CPhoneBook"));
  237. CmFree(m_rgPhoneBookEntry);
  238. m_rgPhoneBookEntry = NULL;
  239. CmFree(m_pLineCountryList);
  240. m_pLineCountryList = NULL;
  241. CmFree(m_rgIDLookUp);
  242. m_rgIDLookUp = NULL;
  243. CmFree(m_rgNameLookUp);
  244. m_rgNameLookUp = NULL;
  245. CmFree(m_rgState);
  246. m_rgState = NULL;
  247. }
  248. // ############################################################################
  249. BOOL CPhoneBook::ReadPhoneBookDW(DWORD *pdw, CCSVFile *pcCSVFile)
  250. {
  251. char szTempBuffer[TEMP_BUFFER_LENGTH];
  252. if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
  253. return FALSE;
  254. return (FSz2Dw(szTempBuffer,pdw));
  255. }
  256. // ############################################################################
  257. BOOL CPhoneBook::ReadPhoneBookW(WORD *pw, CCSVFile *pcCSVFile)
  258. {
  259. char szTempBuffer[TEMP_BUFFER_LENGTH];
  260. if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
  261. return FALSE;
  262. return (FSz2W(szTempBuffer,pw));
  263. }
  264. // ############################################################################
  265. BOOL CPhoneBook::ReadPhoneBookB(BYTE *pb, CCSVFile *pcCSVFile)
  266. {
  267. char szTempBuffer[TEMP_BUFFER_LENGTH];
  268. if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
  269. return FALSE;
  270. return (FSz2B(szTempBuffer,pb));
  271. }
  272. // ############################################################################
  273. BOOL CPhoneBook::ReadPhoneBookSZ(LPSTR psz, DWORD dwSize, CCSVFile *pcCSVFile)
  274. {
  275. if (!pcCSVFile->ReadToken(psz,dwSize))
  276. return FALSE;
  277. return TRUE;
  278. }
  279. // ############################################################################
  280. BOOL CPhoneBook::ReadPhoneBookNL(CCSVFile *pcCSVFile)
  281. {
  282. if (!pcCSVFile->ClearNewLines())
  283. return FALSE;
  284. return TRUE;
  285. }
  286. //
  287. // Note: the new fUnicode parameter has been added so that Whistler and newer releases
  288. // take advantage of the Unicode TAPI functions where available, so that MUI works.
  289. //
  290. static LONG PBlineGetCountry(DWORD dwCountryID, DWORD dwAPIVersion, LPLINECOUNTRYLIST lpLineCountryList, BOOL fUnicode)
  291. {
  292. HINSTANCE hInst;
  293. LONG lRes;
  294. // Try to load the TAPI DLL
  295. hInst = LoadLibrary("tapi32");
  296. if (!hInst)
  297. {
  298. return (LINEERR_NOMEM);
  299. }
  300. // Get the proc address for GetCountry
  301. LONG (WINAPI *pfn)(DWORD,DWORD,LPLINECOUNTRYLIST);
  302. pfn = (LONG (WINAPI *)(DWORD,DWORD,LPLINECOUNTRYLIST)) GetProcAddress(hInst, fUnicode ? "lineGetCountryW" : "lineGetCountryA");
  303. if (!pfn)
  304. {
  305. FreeLibrary(hInst);
  306. return (LINEERR_NOMEM);
  307. }
  308. // Get the country list
  309. lRes = pfn(dwCountryID,dwAPIVersion,lpLineCountryList);
  310. FreeLibrary(hInst);
  311. return (lRes);
  312. }
  313. // ############################################################################
  314. HRESULT CPhoneBook::Init(LPCSTR pszISPCode)
  315. {
  316. char szTempBuffer[TEMP_BUFFER_LENGTH];
  317. LPLINECOUNTRYLIST pLineCountryTemp = NULL;
  318. HRESULT hr = ERROR_NOT_ENOUGH_MEMORY;
  319. DWORD dwLastState = 0;
  320. DWORD dwLastCountry = 0;
  321. DWORD dwNumAllocated;
  322. PACCESSENTRY pCurAccessEntry;
  323. LPLINECOUNTRYENTRY pLCETemp;
  324. DWORD idx;
  325. LPTSTR pszTemp;
  326. LPTSTR pszCmpDir = NULL;
  327. CCSVFile *pcCSVFile=NULL;
  328. PSTATE ps,psLast; //faster to use pointers.
  329. DWORD dwAlloc = 0;
  330. PACCESSENTRY pTempAccessEntry = NULL;
  331. MYDBG(("CPhoneBook::Init"));
  332. // Get TAPI country list
  333. m_pLineCountryList = (LPLINECOUNTRYLIST)CmMalloc(sizeof(LINECOUNTRYLIST));
  334. if (!m_pLineCountryList)
  335. {
  336. goto InitExit;
  337. }
  338. m_pLineCountryList->dwTotalSize = sizeof(LINECOUNTRYLIST);
  339. //
  340. // Note: For Whistler and newer releases, we take advantage of the Unicode TAPI
  341. // functions where available, so that MUI works. Hence the final parameter
  342. // to PBlineGetCountry, and the two different QSorts below.
  343. //
  344. // get ALL country information
  345. idx = PBlineGetCountry(0,0x10003, m_pLineCountryList, OS_NT51);
  346. if (idx && idx != LINEERR_STRUCTURETOOSMALL)
  347. {
  348. goto InitExit;
  349. }
  350. MYDBGASSERT(m_pLineCountryList->dwNeededSize);
  351. // reallocate memory for country list
  352. pLineCountryTemp = (LPLINECOUNTRYLIST)CmMalloc(m_pLineCountryList->dwNeededSize);
  353. if (!pLineCountryTemp)
  354. {
  355. goto InitExit;
  356. }
  357. pLineCountryTemp->dwTotalSize = m_pLineCountryList->dwNeededSize;
  358. CmFree(m_pLineCountryList);
  359. m_pLineCountryList = pLineCountryTemp;
  360. pLineCountryTemp = NULL;
  361. if (PBlineGetCountry(0,0x10003, m_pLineCountryList, OS_NT51))
  362. {
  363. goto InitExit;
  364. }
  365. // Load Look Up arrays
  366. // keyword: country ID,
  367. // keyvalue: pointer to the country entry in m_pLineCountryList
  368. //
  369. #ifdef DEBUG
  370. m_rgIDLookUp = (IDLOOKUPELEMENT*)CmMalloc(sizeof(IDLOOKUPELEMENT)*m_pLineCountryList->dwNumCountries+5);
  371. #else
  372. m_rgIDLookUp = (IDLOOKUPELEMENT*)CmMalloc(sizeof(IDLOOKUPELEMENT)*m_pLineCountryList->dwNumCountries);
  373. #endif
  374. if (!m_rgIDLookUp)
  375. {
  376. goto InitExit;
  377. }
  378. // pLCETemp points to the first country information entry
  379. pLCETemp = (LPLINECOUNTRYENTRY)((DWORD_PTR) m_pLineCountryList +
  380. m_pLineCountryList->dwCountryListOffset);
  381. for (idx=0;idx<m_pLineCountryList->dwNumCountries;idx++)
  382. {
  383. m_rgIDLookUp[idx].dwID = pLCETemp[idx].dwCountryID;
  384. m_rgIDLookUp[idx].pLCE = &pLCETemp[idx];
  385. }
  386. // sort the country lines
  387. CmQSort(m_rgIDLookUp, (size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),
  388. CompareIDLookUpElements);
  389. // m_rgNameLookUp: look-up list for country name
  390. // keyword: country name
  391. // keyvalue: pointer to the country entry in m_pLineCountryList
  392. m_rgNameLookUp = (CNTRYNAMELOOKUPELEMENT*)CmMalloc(sizeof(CNTRYNAMELOOKUPELEMENT) * m_pLineCountryList->dwNumCountries);
  393. if (!m_rgNameLookUp)
  394. {
  395. goto InitExit;
  396. }
  397. for (idx=0;idx<m_pLineCountryList->dwNumCountries;idx++)
  398. {
  399. m_rgNameLookUp[idx].psCountryName = (LPSTR)((DWORD_PTR)m_pLineCountryList + (DWORD)pLCETemp[idx].dwCountryNameOffset);
  400. m_rgNameLookUp[idx].dwNameSize = pLCETemp[idx].dwCountryNameSize;
  401. m_rgNameLookUp[idx].pLCE = &pLCETemp[idx];
  402. }
  403. // sort the country names
  404. if (OS_NT51)
  405. {
  406. CmQSort(m_rgNameLookUp,(size_t) m_pLineCountryList->dwNumCountries,sizeof(CNTRYNAMELOOKUPELEMENTW),
  407. CompareCntryNameLookUpElementsW);
  408. }
  409. else
  410. {
  411. CmQSort(m_rgNameLookUp,(size_t) m_pLineCountryList->dwNumCountries,sizeof(CNTRYNAMELOOKUPELEMENT),
  412. CompareCntryNameLookUpElementsA);
  413. }
  414. //
  415. // Locate ISP's INF file (aka .CMS)
  416. //
  417. if (!SearchPath(NULL, (LPCTSTR) pszISPCode, c_pszInfSuffix, MAX_PATH, m_szINFFile, &pszTemp))
  418. {
  419. wsprintf(szTempBuffer,"Can not find:%s%s (%d)",pszISPCode,c_pszInfSuffix,GetLastError());
  420. CMASSERTMSG(0,szTempBuffer);
  421. hr = ERROR_FILE_NOT_FOUND;
  422. goto InitExit;
  423. }
  424. // Load Region file, get region file name
  425. char szStateFile[sizeof(szTempBuffer)/sizeof(szTempBuffer[0])];
  426. GetPrivateProfileString(c_pszCmSectionIsp, c_pszCmEntryIspRegionFile, NULL, szStateFile, sizeof(szStateFile)-1, m_szINFFile);
  427. //
  428. // Can't assume current directory, construct path to PBK directory
  429. //
  430. pszCmpDir = GetBaseDirFromCms(m_szINFFile);
  431. //
  432. // Look for the .PBR file, using CMP dir as base path for search
  433. //
  434. if (!SearchPath(pszCmpDir, szStateFile, NULL, TEMP_BUFFER_LENGTH, szTempBuffer, &pszTemp))
  435. {
  436. // CMASSERTMSG(0,"STATE.ICW not found");
  437. CMASSERTMSG(0,"region file not found");
  438. hr = ERROR_FILE_NOT_FOUND;
  439. goto InitExit;
  440. }
  441. // open region file
  442. pcCSVFile = new CCSVFile;
  443. if (!pcCSVFile)
  444. {
  445. goto InitExit;
  446. }
  447. if (!pcCSVFile->Open(szTempBuffer))
  448. {
  449. // CMASSERTMSG(0,"Can not open STATE.ICW");
  450. CMASSERTMSG(0,"Can not open region file");
  451. delete pcCSVFile;
  452. pcCSVFile = NULL;
  453. goto InitExit;
  454. }
  455. // first token in region file is the number of regions
  456. if (!pcCSVFile->ClearNewLines() || !pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
  457. {
  458. goto InitExit;
  459. }
  460. if (!FSz2Dw(szTempBuffer,&m_cStates))
  461. {
  462. // CMASSERTMSG(0,"STATE.ICW count is invalid");
  463. CMASSERTMSG(0,"region count is invalid");
  464. goto InitExit;
  465. }
  466. // Now read in all the regions if there are any
  467. if (0 != m_cStates)
  468. {
  469. m_rgState = (PSTATE)CmMalloc(sizeof(STATE)*m_cStates);
  470. if (!m_rgState)
  471. {
  472. goto InitExit;
  473. }
  474. for (ps = m_rgState, psLast = &m_rgState[m_cStates - 1]; ps <= psLast;++ps)
  475. {
  476. if (pcCSVFile->ClearNewLines())
  477. {
  478. pcCSVFile->ReadToken(ps->szStateName,cbStateName);
  479. }
  480. }
  481. }
  482. pcCSVFile->Close();
  483. // load Phone Book Name
  484. if (!GetPrivateProfileString(c_pszCmSectionIsp, c_pszCmEntryIspPbFile,c_pszInfDefault,
  485. szTempBuffer,TEMP_BUFFER_LENGTH,m_szINFFile))
  486. {
  487. CMASSERTMSG(0,"PhoneBookFile not specified in INF file");
  488. hr = ERROR_FILE_NOT_FOUND;
  489. goto InitExit;
  490. }
  491. #ifdef DEBUG
  492. if (!lstrcmp(szTempBuffer,c_pszInfDefault))
  493. {
  494. wsprintf(szTempBuffer, "%s value not found in ISP file", c_pszCmEntryIspPbFile);
  495. CMASSERTMSG(0,szTempBuffer);
  496. }
  497. #endif
  498. //
  499. // Look for the .PBK file, using CMP dir as base path for search
  500. //
  501. if (!SearchPath(pszCmpDir,szTempBuffer,NULL,MAX_PATH,m_szPhoneBook,&pszTemp))
  502. {
  503. CMASSERTMSG(0,"ISP phone book not found");
  504. hr = ERROR_FILE_NOT_FOUND;
  505. goto InitExit;
  506. }
  507. // read in phone book entries
  508. if (!pcCSVFile->Open(m_szPhoneBook))
  509. {
  510. CMASSERTMSG(0,"Can not open phone book");
  511. hr = GetLastError();
  512. goto InitExit;
  513. }
  514. dwNumAllocated = 0;
  515. do {
  516. MYDBGASSERT (dwNumAllocated >= m_cPhoneBookEntries);
  517. if (m_rgPhoneBookEntry)
  518. {
  519. // If we already have an array, make sure its big enough
  520. if (dwNumAllocated == m_cPhoneBookEntries)
  521. {
  522. // We're maxed out, allocate some more memory
  523. dwNumAllocated += PHONE_ENTRY_ALLOC_SIZE;
  524. dwAlloc = (DWORD) dwNumAllocated * sizeof(ACCESSENTRY);
  525. MYDBG(("PhoneBook::Init - Grow ReAlloc = %lu",dwAlloc));
  526. // Realloc
  527. pTempAccessEntry = (PACCESSENTRY)CmRealloc(m_rgPhoneBookEntry, dwAlloc);
  528. if (!pTempAccessEntry)
  529. {
  530. MYDBG(("PhoneBook::Init - Grow ReAlloc of %lu failed", dwAlloc));
  531. goto InitExit;
  532. }
  533. m_rgPhoneBookEntry = pTempAccessEntry;
  534. pTempAccessEntry = NULL;
  535. MYDBG(("Grow phone book to %d entries",dwNumAllocated));
  536. pCurAccessEntry = m_rgPhoneBookEntry + m_cPhoneBookEntries;
  537. }
  538. }
  539. else
  540. {
  541. // Initialization for the first time through
  542. DWORD dwSize = (DWORD) sizeof(ACCESSENTRY);
  543. dwAlloc = (DWORD) dwSize * PHONE_ENTRY_ALLOC_SIZE;
  544. MYDBG(("PhoneBook::Init - sizeof(ACCESSENTRY) = %lu",dwSize));
  545. MYDBG(("PhoneBook::Init - PHONE_ENTRY_ALLOC_SIZE = %d",PHONE_ENTRY_ALLOC_SIZE));
  546. MYDBG(("PhoneBook::Init - Initial Alloc = %lu",dwAlloc));
  547. // Allocate intial array of PHONE_ENTRY_ALLOC_SIZE items
  548. m_rgPhoneBookEntry = (PACCESSENTRY)CmMalloc(dwAlloc);
  549. if (!m_rgPhoneBookEntry)
  550. {
  551. MYDBG(("PhoneBook::Init - Initial Alloc of %lu failed",dwAlloc));
  552. goto InitExit;
  553. }
  554. dwNumAllocated = PHONE_ENTRY_ALLOC_SIZE;
  555. pCurAccessEntry = m_rgPhoneBookEntry;
  556. }
  557. // Read a line from the phonebook
  558. hr = ReadOneLine(pCurAccessEntry,pcCSVFile);
  559. if (hr == ERROR_NO_MORE_ITEMS)
  560. {
  561. break;
  562. }
  563. else if (hr != ERROR_SUCCESS)
  564. {
  565. MYDBG(("PhoneBook::Init - ReadOneLine failed"));
  566. goto InitExit;
  567. }
  568. hr = ERROR_NOT_ENOUGH_MEMORY;
  569. // check the first index pointer to prevent it from being overwritten
  570. // by the second appearance that's scattered around somewhere else -- added by byao
  571. if (pCurAccessEntry->dwCountryID != dwLastCountry)
  572. {
  573. PIDLOOKUPELEMENT pIDLookUpElement;
  574. // NOTE: Not sure about the first parameter here.
  575. pIDLookUpElement = (PIDLOOKUPELEMENT)CmBSearch(&pCurAccessEntry->dwCountryID,
  576. m_rgIDLookUp,(size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),
  577. CompareIDLookUpElements);
  578. if (!pIDLookUpElement)
  579. {
  580. // bad country ID, but we can't assert here
  581. MYDBG(("Bad country ID in phone book %d\n",pCurAccessEntry->dwCountryID));
  582. continue;
  583. }
  584. else
  585. {
  586. // for a given country ID this is the first phone number
  587. // don't overwrite existing index
  588. if (!pIDLookUpElement->iFirstAE)
  589. {
  590. pIDLookUpElement->iFirstAE = PAEToIdx(pCurAccessEntry);
  591. dwLastCountry = pCurAccessEntry->dwCountryID;
  592. }
  593. }
  594. }
  595. // Check to see if this is the first phone number for a given state
  596. // the code has been changed accordingly
  597. if (pCurAccessEntry->wStateID && (pCurAccessEntry->wStateID != dwLastState))
  598. {
  599. idx = pCurAccessEntry->wStateID - 1;
  600. //
  601. // don't overwrite existing index
  602. //
  603. if ((idx < m_cStates) && !m_rgState[idx].iFirst)
  604. {
  605. m_rgState[idx].dwCountryID = pCurAccessEntry->dwCountryID;
  606. m_rgState[idx].iFirst = PAEToIdx(pCurAccessEntry);
  607. }
  608. dwLastState = pCurAccessEntry->wStateID;
  609. }
  610. pCurAccessEntry++;
  611. m_cPhoneBookEntries++;
  612. } while (TRUE);
  613. MYDBG(("PhoneBook::Init - %lu Entries read",m_cPhoneBookEntries));
  614. if (m_cPhoneBookEntries == 0)
  615. {
  616. //
  617. // Phone book is empty
  618. //
  619. goto InitExit;
  620. }
  621. // Trim the phone book for unused memory
  622. dwAlloc = m_cPhoneBookEntries * sizeof(ACCESSENTRY);
  623. MYDBG(("PhoneBook::Init - Trim ReAlloc = %lu",dwAlloc));
  624. MYDBGASSERT(m_cPhoneBookEntries);
  625. // Realloc
  626. pTempAccessEntry = (PACCESSENTRY)CmRealloc(m_rgPhoneBookEntry, dwAlloc);
  627. MYDBGASSERT(pTempAccessEntry);
  628. if (!pTempAccessEntry)
  629. {
  630. MYDBG(("PhoneBook::Init - Trim ReAlloc of %lu failed",dwAlloc));
  631. goto InitExit;
  632. }
  633. m_rgPhoneBookEntry = pTempAccessEntry;
  634. pTempAccessEntry = NULL;
  635. hr = ERROR_SUCCESS;
  636. // Exit
  637. InitExit:
  638. // If something failed release everything
  639. if (hr != ERROR_SUCCESS)
  640. {
  641. CmFree(m_pLineCountryList);
  642. m_pLineCountryList = NULL;
  643. CmFree(m_rgPhoneBookEntry);
  644. m_rgPhoneBookEntry = NULL;
  645. m_cPhoneBookEntries = 0 ;
  646. CmFree(m_rgIDLookUp);
  647. m_rgIDLookUp=NULL;
  648. CmFree(m_rgNameLookUp);
  649. m_rgNameLookUp=NULL;
  650. CmFree(m_rgState);
  651. m_rgState = NULL;
  652. m_cStates = 0;
  653. }
  654. if (pcCSVFile)
  655. {
  656. pcCSVFile->Close();
  657. delete pcCSVFile;
  658. }
  659. if (pszCmpDir)
  660. {
  661. CmFree(pszCmpDir);
  662. }
  663. return hr;
  664. }
  665. // ############################################################################
  666. HRESULT CPhoneBook::Merge(LPCSTR pszChangeFile)
  667. {
  668. char szTempBuffer[TEMP_BUFFER_LENGTH];
  669. char szTempFileName[MAX_PATH];
  670. CCSVFile *pcCSVFile = NULL;
  671. ACCESSENTRY aeChange;
  672. PIDXLOOKUPELEMENT rgIdxLookUp = NULL;
  673. PIDXLOOKUPELEMENT pCurIdxLookUp;
  674. DWORD dwAllocated;
  675. DWORD dwOriginalSize;
  676. HRESULT hr = ERROR_NOT_ENOUGH_MEMORY;
  677. DWORD dwIdx;
  678. DWORD cch, cchWritten;
  679. HANDLE hFile = INVALID_HANDLE_VALUE;
  680. MYDBG(("CPhoneBook::Merge"));
  681. // We'll grow the phone book on the first add record (this minimizes the number
  682. // of places in the code where we have to grow the phone book) - so, for now,
  683. // just stay with the current size.
  684. dwAllocated = m_cPhoneBookEntries;
  685. // Create index to loaded phone book, sorted by index
  686. rgIdxLookUp = (PIDXLOOKUPELEMENT)CmMalloc(sizeof(IDXLOOKUPELEMENT) * dwAllocated);
  687. MYDBGASSERT(rgIdxLookUp);
  688. if (!rgIdxLookUp)
  689. {
  690. goto MergeExit;
  691. }
  692. for (dwIdx = 0; dwIdx < m_cPhoneBookEntries; dwIdx++)
  693. {
  694. rgIdxLookUp[dwIdx].iAE = PAEToIdx(&m_rgPhoneBookEntry[dwIdx]);
  695. rgIdxLookUp[dwIdx].dwIndex = IdxToPAE(rgIdxLookUp[dwIdx].iAE)->dwIndex;
  696. }
  697. dwOriginalSize = m_cPhoneBookEntries;
  698. CmQSort(rgIdxLookUp,(size_t) dwOriginalSize,sizeof(IDXLOOKUPELEMENT),CompareIdxLookUpElements);
  699. // Load changes to phone book
  700. pcCSVFile = new CCSVFile;
  701. MYDBGASSERT(pcCSVFile);
  702. if (!pcCSVFile)
  703. {
  704. goto MergeExit;
  705. }
  706. if (!pcCSVFile->Open(pszChangeFile))
  707. {
  708. delete pcCSVFile;
  709. pcCSVFile = NULL;
  710. goto MergeExit;
  711. }
  712. do {
  713. // Read a change record
  714. ZeroMemory(&aeChange,sizeof(ACCESSENTRY));
  715. hr = ReadOneLine(&aeChange, pcCSVFile);
  716. if (hr == ERROR_NO_MORE_ITEMS)
  717. {
  718. break; // no more enteries
  719. }
  720. else if (hr != ERROR_SUCCESS)
  721. {
  722. goto MergeExit;
  723. }
  724. hr = ERROR_NOT_ENOUGH_MEMORY;
  725. /* if (!ReadPhoneBookDW(&aeChange.dwIndex,pcCSVFile))
  726. break; // no more enteries
  727. ReadVerifyPhoneBookDW(aeChange.dwCountryID);
  728. ReadVerifyPhoneBookW(aeChange.wStateID);
  729. ReadVerifyPhoneBookSZ(aeChange.szCity,cbCity);
  730. ReadVerifyPhoneBookSZ(aeChange.szAreaCode,cbAreaCode);
  731. // NOTE: 0 is a valid area code and ,, is a valid entry for an area code
  732. if (!FSz2Dw(aeChange.szAreaCode,&aeChange.dwAreaCode))
  733. aeChange.dwAreaCode = NO_AREA_CODE;
  734. ReadVerifyPhoneBookSZ(aeChange.szAccessNumber,cbAccessNumber);
  735. ReadVerifyPhoneBookDW(aeChange.dwConnectSpeedMin);
  736. ReadVerifyPhoneBookDW(aeChange.dwConnectSpeedMax);
  737. ReadVerifyPhoneBookB(aeChange.bFlipFactor);
  738. ReadVerifyPhoneBookDW(aeChange.fType);
  739. ReadVerifyPhoneBookSZ(aeChange.szDataCenter,cbDataCenter);
  740. */
  741. pCurIdxLookUp = (PIDXLOOKUPELEMENT) CmBSearch(&aeChange,
  742. rgIdxLookUp,
  743. (size_t) dwOriginalSize,
  744. sizeof(IDXLOOKUPELEMENT),
  745. CompareIdxLookUpElements);
  746. // Determine if this is a delete, add, or merge record
  747. if (aeChange.szAccessNumber[0] == '0' && aeChange.szAccessNumber[1] == '\0')
  748. {
  749. // This is a delete record
  750. CMASSERTMSG(pCurIdxLookUp,"Attempting to delete a record that does not exist. The change file and phone book versions do not match.");
  751. if (pCurIdxLookUp)
  752. {
  753. CMASSERTMSG(IdxToPAE(pCurIdxLookUp->iAE),"Attempting to delete a record that has already been deleted.");
  754. pCurIdxLookUp->iAE = PAEToIdx(NULL); //Create a dead entry in the look up table
  755. }
  756. }
  757. else if (pCurIdxLookUp)
  758. {
  759. // This is a change record
  760. CMASSERTMSG(IdxToPAE(pCurIdxLookUp->iAE),"Attempting to change a record which has been deleted.");
  761. if (IdxToPAE(pCurIdxLookUp->iAE))
  762. {
  763. CopyMemory(IdxToPAE(pCurIdxLookUp->iAE),&aeChange,sizeof(ACCESSENTRY));
  764. }
  765. }
  766. else
  767. {
  768. // This is an add entry
  769. // Make sure we have enough room
  770. if (m_cPhoneBookEntries >= dwAllocated)
  771. {
  772. // Grow phone book
  773. dwAllocated += CHANGE_BUFFER_SIZE;
  774. DWORD dwNewAlloc = (DWORD) sizeof(ACCESSENTRY) * dwAllocated;
  775. PACCESSENTRY pTempAccessEntry = (PACCESSENTRY)CmRealloc(m_rgPhoneBookEntry, dwNewAlloc);
  776. MYDBGASSERT(pTempAccessEntry);
  777. if (!pTempAccessEntry)
  778. {
  779. MYDBG(("PhoneBook::Merge - Grow ReAlloc of %lu failed",dwNewAlloc));
  780. goto MergeExit;
  781. }
  782. m_rgPhoneBookEntry = pTempAccessEntry;
  783. pTempAccessEntry = NULL;
  784. MYDBG(("Grow phone book to %lu entries",dwAllocated));
  785. // Grow look up index
  786. MYDBGASSERT(rgIdxLookUp);
  787. PIDXLOOKUPELEMENT pTempLookupElement = (PIDXLOOKUPELEMENT)CmRealloc(rgIdxLookUp, sizeof(IDXLOOKUPELEMENT)*dwAllocated);
  788. MYDBGASSERT(pTempLookupElement);
  789. if (!pTempLookupElement)
  790. {
  791. goto MergeExit;
  792. }
  793. rgIdxLookUp = pTempLookupElement;
  794. }
  795. //Add entry to the end of the phonebook and to end of look up index
  796. CopyMemory(&m_rgPhoneBookEntry[m_cPhoneBookEntries],&aeChange,sizeof(ACCESSENTRY));
  797. rgIdxLookUp[m_cPhoneBookEntries].iAE = PAEToIdx(&m_rgPhoneBookEntry[m_cPhoneBookEntries]);
  798. rgIdxLookUp[m_cPhoneBookEntries].dwIndex = IdxToPAE(rgIdxLookUp[m_cPhoneBookEntries].iAE)->dwIndex;
  799. m_cPhoneBookEntries++;
  800. // NOTE: because the entry is added to the end of the list, we can't add
  801. // and delete entries in the same change file.
  802. }
  803. } while (TRUE);
  804. // The CompareIdxLookupElementFileOrder() function needs the iAE member to be
  805. // a PACCESSENTRY, and not an index. So we convert 'em here, and then we'll
  806. // convert 'em back later.
  807. for (dwIdx=0;dwIdx<m_cPhoneBookEntries;dwIdx++) {
  808. rgIdxLookUp[dwIdx].iAE = (LONG_PTR)IdxToPAE(rgIdxLookUp[dwIdx].iAE);
  809. }
  810. // resort the IDXLookUp index to reflect the correct order of entries
  811. // for the phonebook file, including all of the entries to be deleted.
  812. CmQSort(rgIdxLookUp,(size_t) m_cPhoneBookEntries,sizeof(IDXLOOKUPELEMENT),CompareIdxLookUpElementsFileOrder);
  813. // Now we convert 'em back.
  814. for (dwIdx=0;dwIdx<m_cPhoneBookEntries;dwIdx++) {
  815. rgIdxLookUp[dwIdx].iAE = PAEToIdx((PACCESSENTRY) rgIdxLookUp[dwIdx].iAE);
  816. }
  817. // Build a new phonebook file
  818. #if 0
  819. /*
  820. #define TEMP_PHONE_BOOK_PREFIX "PBH"
  821. if (!GetTempPath(TEMP_BUFFER_LENGTH,szTempBuffer))
  822. goto MergeExit;
  823. if (!GetTempFileName(szTempBuffer,TEMP_PHONE_BOOK_PREFIX,0,szTempFileName))
  824. goto MergeExit;
  825. hFile = CreateFile(szTempFileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
  826. FILE_FLAG_WRITE_THROUGH,0);
  827. */
  828. #else
  829. for (dwIdx=0;;dwIdx++)
  830. {
  831. lstrcpy(szTempFileName,m_szPhoneBook);
  832. wsprintf(szTempFileName+lstrlen(szTempFileName),".%03u",dwIdx);
  833. hFile = CreateFile(szTempFileName,GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
  834. if ((hFile != INVALID_HANDLE_VALUE) || (GetLastError() != ERROR_FILE_EXISTS)) {
  835. break;
  836. }
  837. }
  838. #endif
  839. if (hFile == INVALID_HANDLE_VALUE)
  840. {
  841. goto MergeExit;
  842. }
  843. for (dwIdx = 0; dwIdx < m_cPhoneBookEntries; dwIdx++)
  844. {
  845. PACCESSENTRY pAE = IdxToPAE(rgIdxLookUp[dwIdx].iAE);
  846. if (pAE) {
  847. cch = wsprintf(szTempBuffer, "%lu,%lu,%lu,%s,%s,%s,%lu,%lu,%lu,%lu,%s\r\n",
  848. pAE->dwIndex,
  849. pAE->dwCountryID,
  850. (DWORD) pAE->wStateID,
  851. pAE->szCity,
  852. pAE->szAreaCode,
  853. pAE->szAccessNumber,
  854. pAE->dwConnectSpeedMin,
  855. pAE->dwConnectSpeedMax,
  856. (DWORD) pAE->bFlipFactor,
  857. (DWORD) pAE->fType,
  858. pAE->szDataCenter);
  859. if (!WriteFile(hFile,szTempBuffer,cch,&cchWritten,NULL))
  860. {
  861. // something went wrong, get rid of the temporary file
  862. hr = GetLastError();
  863. CloseHandle(hFile);
  864. hFile = INVALID_HANDLE_VALUE;
  865. DeleteFile(szTempFileName);
  866. goto MergeExit;
  867. }
  868. MYDBGASSERT(cch == cchWritten);
  869. }
  870. }
  871. CloseHandle(hFile);
  872. hFile = INVALID_HANDLE_VALUE;
  873. // Move new phone book over old
  874. if (!DeleteFile(m_szPhoneBook))
  875. {
  876. hr = GetLastError();
  877. goto MergeExit;
  878. }
  879. if (!MoveFile(szTempFileName,m_szPhoneBook))
  880. {
  881. hr = GetLastError();
  882. goto MergeExit;
  883. }
  884. // discard the phonebook in memory
  885. CmFree(m_rgPhoneBookEntry);
  886. m_rgPhoneBookEntry = NULL;
  887. m_cPhoneBookEntries = 0;
  888. CmFree(m_pLineCountryList);
  889. CmFree(m_rgIDLookUp);
  890. CmFree(m_rgNameLookUp);
  891. CmFree(m_rgState);
  892. m_pLineCountryList = NULL;
  893. m_rgIDLookUp = NULL;
  894. m_rgNameLookUp = NULL;
  895. m_rgState = NULL;
  896. m_cStates = 0;
  897. lstrcpy(szTempBuffer,m_szINFFile);
  898. m_szINFFile[0] = '\0';
  899. m_szPhoneBook[0] = '\0';
  900. // Reload it (and rebuild look up arrays)
  901. hr = Init(szTempBuffer);
  902. MergeExit:
  903. if (pcCSVFile)
  904. {
  905. pcCSVFile->Close();
  906. delete pcCSVFile;
  907. }
  908. if (hFile != INVALID_HANDLE_VALUE)
  909. {
  910. CloseHandle(hFile);
  911. }
  912. CmFree(rgIdxLookUp);
  913. return hr;
  914. }
  915. // ############################################################################
  916. HRESULT CPhoneBook::ReadOneLine(PACCESSENTRY pAccessEntry, CCSVFile *pcCSVFile)
  917. {
  918. HRESULT hr = ERROR_SUCCESS;
  919. //
  920. // Skip newlines (trailing or leading) and read first DW token
  921. // If either fail, then consider this the end of the file
  922. //
  923. if (!ReadPhoneBookNL(pcCSVFile) || !ReadPhoneBookDW(&pAccessEntry->dwIndex,pcCSVFile))
  924. {
  925. hr = ERROR_NO_MORE_ITEMS; // no more enteries
  926. MYDBG(("CPhoneBook::ReadOneLine - No More items"));
  927. goto ReadExit;
  928. }
  929. ReadVerifyPhoneBookDW(pAccessEntry->dwCountryID);
  930. ReadVerifyPhoneBookW(pAccessEntry->wStateID);
  931. ReadVerifyPhoneBookSZ(pAccessEntry->szCity,cbCity);
  932. ReadVerifyPhoneBookSZ(pAccessEntry->szAreaCode,cbAreaCode);
  933. // NOTE: 0 is a valid area code and ,, is a valid entry for an area code
  934. if (!FSz2Dw(pAccessEntry->szAreaCode,&pAccessEntry->dwAreaCode))
  935. pAccessEntry->dwAreaCode = NO_AREA_CODE;
  936. ReadVerifyPhoneBookSZ(pAccessEntry->szAccessNumber,cbAccessNumber);
  937. ReadVerifyPhoneBookDW(pAccessEntry->dwConnectSpeedMin);
  938. ReadVerifyPhoneBookDW(pAccessEntry->dwConnectSpeedMax);
  939. ReadVerifyPhoneBookB(pAccessEntry->bFlipFactor);
  940. ReadVerifyPhoneBookDW(pAccessEntry->fType);
  941. //
  942. // Attempt to read datacenter, if read fails, find out why before reacting
  943. //
  944. if (!ReadPhoneBookSZ(pAccessEntry->szDataCenter, cbDataCenter + 1, pcCSVFile))
  945. {
  946. //
  947. // If the last read was successful, then we must have some bad sz data
  948. //
  949. if (!pcCSVFile->ReadError())
  950. {
  951. CMASSERTMSG(0,"Invalid STRING in phone book");
  952. goto DataError;
  953. }
  954. }
  955. ReadExit:
  956. return hr;
  957. DataError:
  958. hr = ERROR_INVALID_DATA;
  959. goto ReadExit;
  960. }
  961. // ############################################################################
  962. HRESULT CPhoneBook::GetCanonical (PACCESSENTRY pAE, char *psOut)
  963. {
  964. HRESULT hr = ERROR_SUCCESS;
  965. PIDLOOKUPELEMENT pIDLookUp;
  966. pIDLookUp = (PIDLOOKUPELEMENT)CmBSearch(&pAE->dwCountryID,m_rgIDLookUp,
  967. (size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),CompareIdxLookUpElements);
  968. if (!pIDLookUp)
  969. {
  970. hr = ERROR_INVALID_PARAMETER;
  971. }
  972. else
  973. {
  974. if (!psOut)
  975. {
  976. hr = ERROR_INVALID_PARAMETER;
  977. }
  978. else
  979. {
  980. *psOut = 0;
  981. SzCanonicalFromAE (psOut, pAE, pIDLookUp->pLCE);
  982. }
  983. }
  984. return hr;
  985. }
  986. // ############################################################################
  987. HRESULT CPhoneBook::GetNonCanonical (PACCESSENTRY pAE, char *psOut)
  988. {
  989. HRESULT hr = ERROR_SUCCESS;
  990. PIDLOOKUPELEMENT pIDLookUp;
  991. pIDLookUp = (PIDLOOKUPELEMENT)CmBSearch(&pAE->dwCountryID,m_rgIDLookUp,
  992. (size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),CompareIdxLookUpElements);
  993. if (!pIDLookUp)
  994. {
  995. hr = ERROR_INVALID_PARAMETER;
  996. }
  997. else
  998. {
  999. if (!psOut)
  1000. {
  1001. hr = ERROR_INVALID_PARAMETER;
  1002. }
  1003. else
  1004. {
  1005. *psOut = 0;
  1006. SzNonCanonicalFromAE (psOut, pAE, pIDLookUp->pLCE);
  1007. }
  1008. }
  1009. return hr;
  1010. }
  1011. // ############################################################################
  1012. DllExportH PhoneBookLoad(LPCSTR pszISPCode, DWORD_PTR *pdwPhoneID)
  1013. {
  1014. HRESULT hr = ERROR_NOT_ENOUGH_MEMORY;
  1015. CPhoneBook *pcPhoneBook;
  1016. MYDBG(("CM_PHBK_DllExport - PhoneBookLoad"));
  1017. if (!g_hInst) g_hInst = GetModuleHandleA(NULL);
  1018. // validate parameters
  1019. MYDBGASSERT(pszISPCode && *pszISPCode && pdwPhoneID);
  1020. *pdwPhoneID = NULL;
  1021. // allocate phone book
  1022. pcPhoneBook = new CPhoneBook;
  1023. // initialize phone book
  1024. if (pcPhoneBook)
  1025. hr = pcPhoneBook->Init(pszISPCode);
  1026. // in case of failure
  1027. if (hr && pcPhoneBook)
  1028. {
  1029. delete pcPhoneBook;
  1030. MYDBG(("PhoneBookLoad() - init failed"));
  1031. } else {
  1032. *pdwPhoneID = (DWORD_PTR)pcPhoneBook;
  1033. }
  1034. return hr;
  1035. }
  1036. // ############################################################################
  1037. DllExportH PhoneBookUnload(DWORD_PTR dwPhoneID)
  1038. {
  1039. MYDBG(("CM_PHBK_DllExport - PhoneBookUnload"));
  1040. MYDBGASSERT(dwPhoneID);
  1041. // Release contents
  1042. delete (CPhoneBook*)dwPhoneID;
  1043. return ERROR_SUCCESS;
  1044. }
  1045. // ############################################################################
  1046. DllExportH PhoneBookMergeChanges(DWORD_PTR dwPhoneID, LPCSTR pszChangeFile)
  1047. {
  1048. MYDBG(("CM_PHBK_DllExport - PhoneBookMergeChanges"));
  1049. return ((CPhoneBook*)dwPhoneID)->Merge(pszChangeFile);
  1050. }