1316 lines
39 KiB
C++
1316 lines
39 KiB
C++
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// File: phbk.cpp
|
||
|
//
|
||
|
// Module: CMPBK32.DLL
|
||
|
//
|
||
|
// Synopsis: Implementation of CPhoneBook
|
||
|
//
|
||
|
// Copyright (c) 1998-1999 Microsoft Corporation
|
||
|
//
|
||
|
// Author: quintinb created header 08/17/99
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
|
||
|
// ############################################################################
|
||
|
// Phone book APIs
|
||
|
|
||
|
#include "cmmaster.h"
|
||
|
|
||
|
const TCHAR* const c_pszInfDefault = TEXT("INF_DEFAULT");
|
||
|
const TCHAR* const c_pszInfSuffix = TEXT(".CMS");
|
||
|
|
||
|
//#define ReadVerifyPhoneBookDW(x) CMASSERTMSG(ReadPhoneBookDW(&(x),pcCSVFile),"Invalid DWORD in phone book");
|
||
|
#define ReadVerifyPhoneBookDW(x) if (!ReadPhoneBookDW(&(x),pcCSVFile)) \
|
||
|
{ CMASSERTMSG(0,"Invalid DWORD in phone book"); \
|
||
|
goto DataError; }
|
||
|
#define ReadVerifyPhoneBookW(x) if (!ReadPhoneBookW(&(x),pcCSVFile)) \
|
||
|
{ CMASSERTMSG(0,"Invalid WORD in phone book"); \
|
||
|
goto DataError; }
|
||
|
#define ReadVerifyPhoneBookB(x) if (!ReadPhoneBookB(&(x),pcCSVFile)) \
|
||
|
{ CMASSERTMSG(0,"Invalid BYTE in phone book"); \
|
||
|
goto DataError; }
|
||
|
#define ReadVerifyPhoneBookSZ(x,y) if (!ReadPhoneBookSZ(&x[0],y+sizeof('\0'),pcCSVFile)) \
|
||
|
{ CMASSERTMSG(0,"Invalid STRING in phone book"); \
|
||
|
goto DataError; }
|
||
|
#define CHANGE_BUFFER_SIZE 50
|
||
|
|
||
|
#define ERROR_USERBACK 32766
|
||
|
#define ERROR_USERCANCEL 32767
|
||
|
|
||
|
// ############################################################################
|
||
|
void CPhoneBook::EnumNumbersByCountry(DWORD dwCountryID, PPBFS pFilter, CB_PHONEBOOK pfnNumber, DWORD_PTR dwParam)
|
||
|
{
|
||
|
MYDBG(("CPhoneBook::EnumNumbersByCountry"));
|
||
|
|
||
|
PACCESSENTRY pAELast, pAE = NULL;
|
||
|
PIDLOOKUPELEMENT pIDLookUp;
|
||
|
IDLOOKUPELEMENT LookUpTarget;
|
||
|
|
||
|
LookUpTarget.dwID = dwCountryID;
|
||
|
pIDLookUp = NULL;
|
||
|
pIDLookUp = (PIDLOOKUPELEMENT)CmBSearch(&LookUpTarget,m_rgIDLookUp,
|
||
|
(size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),CompareIDLookUpElements);
|
||
|
if (pIDLookUp)
|
||
|
pAE = IdxToPAE(pIDLookUp->iFirstAE);
|
||
|
|
||
|
// Fill the list for whatever AE's we found
|
||
|
//
|
||
|
|
||
|
if (pAE)
|
||
|
{
|
||
|
pAELast = &(m_rgPhoneBookEntry[m_cPhoneBookEntries - 1]);
|
||
|
while (pAELast >= pAE)
|
||
|
{
|
||
|
if (pAE->dwCountryID == dwCountryID && pAE->wStateID == 0) {
|
||
|
if (PhoneBookMatchFilter(pFilter,pAE->fType))
|
||
|
{
|
||
|
pfnNumber((unsigned int) (pAE - m_rgPhoneBookEntry),dwParam);
|
||
|
}
|
||
|
}
|
||
|
pAE++;
|
||
|
}
|
||
|
|
||
|
// Select the first item
|
||
|
//
|
||
|
|
||
|
}
|
||
|
}
|
||
|
// ############################################################################
|
||
|
void CPhoneBook::EnumNumbersByCountry(DWORD dwCountryID, DWORD dwMask, DWORD fType, CB_PHONEBOOK pfnNumber, DWORD_PTR dwParam)
|
||
|
{
|
||
|
MYDBG(("CPhoneBook::EnumNumbersByCountry"));
|
||
|
|
||
|
PhoneBookFilterStruct sFilter = {1,{{dwMask,fType}}};
|
||
|
|
||
|
EnumNumbersByCountry(dwCountryID,&sFilter,pfnNumber,dwParam);
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
BOOL CPhoneBook::FHasPhoneType(PPBFS pFilter)
|
||
|
{
|
||
|
MYDBG(("CPhoneBook::FHasPhoneType"));
|
||
|
|
||
|
PACCESSENTRY pAELast, pAE = NULL;
|
||
|
|
||
|
pAE = &(m_rgPhoneBookEntry[0]); // pAE points to the first phone book entry
|
||
|
|
||
|
//
|
||
|
// Examine each entry until we find a match or exhaust the entries
|
||
|
//
|
||
|
|
||
|
if (pAE)
|
||
|
{
|
||
|
pAELast = &(m_rgPhoneBookEntry[m_cPhoneBookEntries - 1]);
|
||
|
|
||
|
while (pAELast >= pAE)
|
||
|
{
|
||
|
//
|
||
|
// See if this pop passes the specified filter
|
||
|
//
|
||
|
|
||
|
if (PhoneBookMatchFilter(pFilter, pAE->fType))
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
pAE++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
void CPhoneBook::EnumNumbersByRegion(unsigned int nRegion, DWORD dwCountryID, PPBFS pFilter, CB_PHONEBOOK pfnNumber, DWORD_PTR dwParam)
|
||
|
{
|
||
|
MYDBG(("CPhoneBook::EnumNumbersByRegion"));
|
||
|
|
||
|
PACCESSENTRY pAELast, pAE = NULL;
|
||
|
|
||
|
pAE = &m_rgPhoneBookEntry[0]; // pAE points to the first phone book entry
|
||
|
|
||
|
// Fill the list for whatever AE's we found
|
||
|
if (pAE)
|
||
|
{
|
||
|
pAELast = &(m_rgPhoneBookEntry[m_cPhoneBookEntries - 1]);
|
||
|
while (pAELast >= pAE)
|
||
|
{
|
||
|
// choose phone number of the same region OR with region ID = 0(which means ALL regions)
|
||
|
if (pAE->dwCountryID == dwCountryID &&
|
||
|
((pAE->wStateID == nRegion+1) || (pAE->wStateID == 0)))
|
||
|
{
|
||
|
|
||
|
if (PhoneBookMatchFilter(pFilter,pAE->fType))
|
||
|
pfnNumber((unsigned int) (pAE - m_rgPhoneBookEntry), dwParam);
|
||
|
}
|
||
|
pAE++;
|
||
|
}
|
||
|
// Select the first item
|
||
|
//
|
||
|
}
|
||
|
}
|
||
|
// ############################################################################
|
||
|
void CPhoneBook::EnumNumbersByRegion(unsigned int nRegion, DWORD dwCountryID, DWORD dwMask, DWORD fType, CB_PHONEBOOK pfnNumber, DWORD_PTR dwParam)
|
||
|
{
|
||
|
MYDBG(("CPhoneBook::EnumNumbersByRegion"));
|
||
|
|
||
|
PhoneBookFilterStruct sFilter = {1,{{dwMask,fType}}};
|
||
|
|
||
|
EnumNumbersByRegion(nRegion,dwCountryID,&sFilter,pfnNumber,dwParam);
|
||
|
}
|
||
|
// ############################################################################
|
||
|
void CPhoneBook::EnumRegions(DWORD dwCountryID, PPBFS pFilter, CB_PHONEBOOK pfnRegion, DWORD_PTR dwParam)
|
||
|
{
|
||
|
unsigned int idx;
|
||
|
|
||
|
MYDBG(("CPhoneBook::EnumRegions"));
|
||
|
|
||
|
for (idx=0;idx<m_cStates;idx++)
|
||
|
{
|
||
|
PACCESSENTRY pAE = NULL, pAELast = NULL;
|
||
|
|
||
|
pAE = &m_rgPhoneBookEntry[0];
|
||
|
MYDBGASSERT(pAE);
|
||
|
pAELast = &(m_rgPhoneBookEntry[m_cPhoneBookEntries - 1]);
|
||
|
while (pAELast >= pAE)
|
||
|
{
|
||
|
if (pAE->dwCountryID == dwCountryID &&
|
||
|
pAE->wStateID == idx+1)
|
||
|
{
|
||
|
if (PhoneBookMatchFilter(pFilter,pAE->fType))
|
||
|
goto AddRegion;
|
||
|
}
|
||
|
pAE++;
|
||
|
} // while
|
||
|
|
||
|
continue; // start the next 'for' loop
|
||
|
|
||
|
AddRegion:
|
||
|
pfnRegion(idx,dwParam);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// ############################################################################
|
||
|
void CPhoneBook::EnumRegions(DWORD dwCountryID, DWORD dwMask, DWORD fType, CB_PHONEBOOK pfnRegion, DWORD_PTR dwParam)
|
||
|
{
|
||
|
MYDBG(("CPhoneBook::EnumRegions"));
|
||
|
|
||
|
PhoneBookFilterStruct sFilter = {1,{{dwMask,fType}}};
|
||
|
|
||
|
EnumRegions(dwCountryID,&sFilter,pfnRegion,dwParam);
|
||
|
}
|
||
|
// ############################################################################
|
||
|
void CPhoneBook::EnumCountries(PPBFS pFilter, CB_PHONEBOOK pfnCountry, DWORD_PTR dwParam)
|
||
|
{
|
||
|
unsigned int idx;
|
||
|
|
||
|
MYDBG(("CPhoneBook::EnumCountries"));
|
||
|
|
||
|
for (idx=0;idx<m_pLineCountryList->dwNumCountries;idx++)
|
||
|
{
|
||
|
if (FHasPhoneNumbers(m_rgNameLookUp[idx].pLCE->dwCountryID,pFilter))
|
||
|
{
|
||
|
pfnCountry(idx,dwParam);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// ############################################################################
|
||
|
void CPhoneBook::EnumCountries(DWORD dwMask, DWORD fType, CB_PHONEBOOK pfnCountry, DWORD_PTR dwParam)
|
||
|
{
|
||
|
MYDBG(("CPhoneBook::EnumCountries"));
|
||
|
|
||
|
PhoneBookFilterStruct sFilter = {1,{{dwMask,fType}}};
|
||
|
|
||
|
EnumCountries(&sFilter,pfnCountry,dwParam);
|
||
|
}
|
||
|
// ############################################################################
|
||
|
BOOL CPhoneBook::FHasPhoneNumbers(DWORD dwCountryID, PPBFS pFilter)
|
||
|
{
|
||
|
PIDLOOKUPELEMENT pIDLookUp;
|
||
|
IDLOOKUPELEMENT LookUpTarget;
|
||
|
PACCESSENTRY pAE = NULL, pAELast = NULL;
|
||
|
DWORD dwTmpCountryID;
|
||
|
|
||
|
LookUpTarget.dwID = dwCountryID;
|
||
|
|
||
|
pIDLookUp = NULL;
|
||
|
pIDLookUp = (PIDLOOKUPELEMENT)CmBSearch(&LookUpTarget,m_rgIDLookUp,
|
||
|
(size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),CompareIDLookUpElements);
|
||
|
|
||
|
if (!pIDLookUp) return FALSE; // no such country
|
||
|
|
||
|
pAE = IdxToPAE(pIDLookUp->iFirstAE);
|
||
|
if (!pAE) return FALSE; // no phone numbers at all
|
||
|
|
||
|
dwTmpCountryID = pAE->dwCountryID;
|
||
|
|
||
|
pAELast = &(m_rgPhoneBookEntry[m_cPhoneBookEntries - 1]);
|
||
|
while (pAELast >= pAE) {
|
||
|
if (pAE->dwCountryID == dwTmpCountryID)
|
||
|
{
|
||
|
if (PhoneBookMatchFilter(pFilter,pAE->fType)) return TRUE;
|
||
|
}
|
||
|
pAE++;
|
||
|
}
|
||
|
return FALSE; // no phone numbers of the right type
|
||
|
|
||
|
// return ((BOOL)(pIDLookUp->pFirstAE));
|
||
|
}
|
||
|
// ############################################################################
|
||
|
BOOL CPhoneBook::FHasPhoneNumbers(DWORD dwCountryID, DWORD dwMask, DWORD fType)
|
||
|
{
|
||
|
MYDBG(("CPhoneBook::FHasPhoneNumbers"));
|
||
|
|
||
|
PhoneBookFilterStruct sFilter = {1,{{dwMask,fType}}};
|
||
|
|
||
|
return FHasPhoneNumbers(dwCountryID,&sFilter);
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
CPhoneBook::CPhoneBook()
|
||
|
{
|
||
|
m_rgPhoneBookEntry = NULL;
|
||
|
m_cPhoneBookEntries =0;
|
||
|
m_rgLineCountryEntry=NULL;
|
||
|
m_rgState=NULL;
|
||
|
m_cStates=0;
|
||
|
m_rgIDLookUp = NULL;
|
||
|
m_rgNameLookUp = NULL;
|
||
|
m_pLineCountryList = NULL;
|
||
|
|
||
|
MYDBG(("CPhoneBook::CPhoneBook"));
|
||
|
|
||
|
ZeroMemory(&m_szINFFile[0],MAX_PATH);
|
||
|
ZeroMemory(&m_szPhoneBook[0],MAX_PATH);
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
CPhoneBook::~CPhoneBook()
|
||
|
{
|
||
|
MYDBG(("CPhoneBook::~CPhoneBook"));
|
||
|
|
||
|
CmFree(m_rgPhoneBookEntry);
|
||
|
m_rgPhoneBookEntry = NULL;
|
||
|
|
||
|
CmFree(m_pLineCountryList);
|
||
|
m_pLineCountryList = NULL;
|
||
|
|
||
|
CmFree(m_rgIDLookUp);
|
||
|
m_rgIDLookUp = NULL;
|
||
|
|
||
|
CmFree(m_rgNameLookUp);
|
||
|
m_rgNameLookUp = NULL;
|
||
|
|
||
|
CmFree(m_rgState);
|
||
|
m_rgState = NULL;
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
BOOL CPhoneBook::ReadPhoneBookDW(DWORD *pdw, CCSVFile *pcCSVFile)
|
||
|
{
|
||
|
char szTempBuffer[TEMP_BUFFER_LENGTH];
|
||
|
|
||
|
if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
|
||
|
return FALSE;
|
||
|
return (FSz2Dw(szTempBuffer,pdw));
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
BOOL CPhoneBook::ReadPhoneBookW(WORD *pw, CCSVFile *pcCSVFile)
|
||
|
{
|
||
|
char szTempBuffer[TEMP_BUFFER_LENGTH];
|
||
|
|
||
|
if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
|
||
|
return FALSE;
|
||
|
return (FSz2W(szTempBuffer,pw));
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
BOOL CPhoneBook::ReadPhoneBookB(BYTE *pb, CCSVFile *pcCSVFile)
|
||
|
{
|
||
|
char szTempBuffer[TEMP_BUFFER_LENGTH];
|
||
|
|
||
|
if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
|
||
|
return FALSE;
|
||
|
return (FSz2B(szTempBuffer,pb));
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
BOOL CPhoneBook::ReadPhoneBookSZ(LPSTR psz, DWORD dwSize, CCSVFile *pcCSVFile)
|
||
|
{
|
||
|
if (!pcCSVFile->ReadToken(psz,dwSize))
|
||
|
return FALSE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
BOOL CPhoneBook::ReadPhoneBookNL(CCSVFile *pcCSVFile)
|
||
|
{
|
||
|
if (!pcCSVFile->ClearNewLines())
|
||
|
return FALSE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Note: the new fUnicode parameter has been added so that Whistler and newer releases
|
||
|
// take advantage of the Unicode TAPI functions where available, so that MUI works.
|
||
|
//
|
||
|
static LONG PBlineGetCountry(DWORD dwCountryID, DWORD dwAPIVersion, LPLINECOUNTRYLIST lpLineCountryList, BOOL fUnicode)
|
||
|
{
|
||
|
HINSTANCE hInst;
|
||
|
LONG lRes;
|
||
|
|
||
|
// Try to load the TAPI DLL
|
||
|
|
||
|
hInst = LoadLibrary("tapi32");
|
||
|
|
||
|
if (!hInst)
|
||
|
{
|
||
|
return (LINEERR_NOMEM);
|
||
|
}
|
||
|
|
||
|
// Get the proc address for GetCountry
|
||
|
|
||
|
LONG (WINAPI *pfn)(DWORD,DWORD,LPLINECOUNTRYLIST);
|
||
|
pfn = (LONG (WINAPI *)(DWORD,DWORD,LPLINECOUNTRYLIST)) GetProcAddress(hInst, fUnicode ? "lineGetCountryW" : "lineGetCountryA");
|
||
|
|
||
|
if (!pfn)
|
||
|
{
|
||
|
FreeLibrary(hInst);
|
||
|
return (LINEERR_NOMEM);
|
||
|
}
|
||
|
|
||
|
// Get the country list
|
||
|
|
||
|
lRes = pfn(dwCountryID,dwAPIVersion,lpLineCountryList);
|
||
|
|
||
|
FreeLibrary(hInst);
|
||
|
return (lRes);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ############################################################################
|
||
|
HRESULT CPhoneBook::Init(LPCSTR pszISPCode)
|
||
|
{
|
||
|
char szTempBuffer[TEMP_BUFFER_LENGTH];
|
||
|
LPLINECOUNTRYLIST pLineCountryTemp = NULL;
|
||
|
HRESULT hr = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
DWORD dwLastState = 0;
|
||
|
DWORD dwLastCountry = 0;
|
||
|
DWORD dwNumAllocated;
|
||
|
PACCESSENTRY pCurAccessEntry;
|
||
|
LPLINECOUNTRYENTRY pLCETemp;
|
||
|
DWORD idx;
|
||
|
LPTSTR pszTemp;
|
||
|
LPTSTR pszCmpDir = NULL;
|
||
|
CCSVFile *pcCSVFile=NULL;
|
||
|
PSTATE ps,psLast; //faster to use pointers.
|
||
|
DWORD dwAlloc = 0;
|
||
|
PACCESSENTRY pTempAccessEntry = NULL;
|
||
|
|
||
|
MYDBG(("CPhoneBook::Init"));
|
||
|
|
||
|
// Get TAPI country list
|
||
|
m_pLineCountryList = (LPLINECOUNTRYLIST)CmMalloc(sizeof(LINECOUNTRYLIST));
|
||
|
if (!m_pLineCountryList)
|
||
|
{
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
m_pLineCountryList->dwTotalSize = sizeof(LINECOUNTRYLIST);
|
||
|
|
||
|
//
|
||
|
// Note: For Whistler and newer releases, we take advantage of the Unicode TAPI
|
||
|
// functions where available, so that MUI works. Hence the final parameter
|
||
|
// to PBlineGetCountry, and the two different QSorts below.
|
||
|
//
|
||
|
|
||
|
// get ALL country information
|
||
|
idx = PBlineGetCountry(0,0x10003, m_pLineCountryList, OS_NT51);
|
||
|
if (idx && idx != LINEERR_STRUCTURETOOSMALL)
|
||
|
{
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
MYDBGASSERT(m_pLineCountryList->dwNeededSize);
|
||
|
|
||
|
// reallocate memory for country list
|
||
|
pLineCountryTemp = (LPLINECOUNTRYLIST)CmMalloc(m_pLineCountryList->dwNeededSize);
|
||
|
if (!pLineCountryTemp)
|
||
|
{
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
pLineCountryTemp->dwTotalSize = m_pLineCountryList->dwNeededSize;
|
||
|
|
||
|
CmFree(m_pLineCountryList);
|
||
|
|
||
|
m_pLineCountryList = pLineCountryTemp;
|
||
|
pLineCountryTemp = NULL;
|
||
|
|
||
|
if (PBlineGetCountry(0,0x10003, m_pLineCountryList, OS_NT51))
|
||
|
{
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
// Load Look Up arrays
|
||
|
// keyword: country ID,
|
||
|
// keyvalue: pointer to the country entry in m_pLineCountryList
|
||
|
//
|
||
|
#ifdef DEBUG
|
||
|
m_rgIDLookUp = (IDLOOKUPELEMENT*)CmMalloc(sizeof(IDLOOKUPELEMENT)*m_pLineCountryList->dwNumCountries+5);
|
||
|
#else
|
||
|
m_rgIDLookUp = (IDLOOKUPELEMENT*)CmMalloc(sizeof(IDLOOKUPELEMENT)*m_pLineCountryList->dwNumCountries);
|
||
|
#endif
|
||
|
if (!m_rgIDLookUp)
|
||
|
{
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
// pLCETemp points to the first country information entry
|
||
|
pLCETemp = (LPLINECOUNTRYENTRY)((DWORD_PTR) m_pLineCountryList +
|
||
|
m_pLineCountryList->dwCountryListOffset);
|
||
|
|
||
|
for (idx=0;idx<m_pLineCountryList->dwNumCountries;idx++)
|
||
|
{
|
||
|
m_rgIDLookUp[idx].dwID = pLCETemp[idx].dwCountryID;
|
||
|
m_rgIDLookUp[idx].pLCE = &pLCETemp[idx];
|
||
|
}
|
||
|
|
||
|
// sort the country lines
|
||
|
|
||
|
CmQSort(m_rgIDLookUp, (size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),
|
||
|
CompareIDLookUpElements);
|
||
|
|
||
|
|
||
|
// m_rgNameLookUp: look-up list for country name
|
||
|
// keyword: country name
|
||
|
// keyvalue: pointer to the country entry in m_pLineCountryList
|
||
|
|
||
|
m_rgNameLookUp = (CNTRYNAMELOOKUPELEMENT*)CmMalloc(sizeof(CNTRYNAMELOOKUPELEMENT) * m_pLineCountryList->dwNumCountries);
|
||
|
|
||
|
if (!m_rgNameLookUp)
|
||
|
{
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
for (idx=0;idx<m_pLineCountryList->dwNumCountries;idx++)
|
||
|
{
|
||
|
m_rgNameLookUp[idx].psCountryName = (LPSTR)((DWORD_PTR)m_pLineCountryList + (DWORD)pLCETemp[idx].dwCountryNameOffset);
|
||
|
m_rgNameLookUp[idx].dwNameSize = pLCETemp[idx].dwCountryNameSize;
|
||
|
m_rgNameLookUp[idx].pLCE = &pLCETemp[idx];
|
||
|
}
|
||
|
|
||
|
// sort the country names
|
||
|
|
||
|
if (OS_NT51)
|
||
|
{
|
||
|
CmQSort(m_rgNameLookUp,(size_t) m_pLineCountryList->dwNumCountries,sizeof(CNTRYNAMELOOKUPELEMENTW),
|
||
|
CompareCntryNameLookUpElementsW);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CmQSort(m_rgNameLookUp,(size_t) m_pLineCountryList->dwNumCountries,sizeof(CNTRYNAMELOOKUPELEMENT),
|
||
|
CompareCntryNameLookUpElementsA);
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Locate ISP's INF file (aka .CMS)
|
||
|
//
|
||
|
|
||
|
if (!SearchPath(NULL, (LPCTSTR) pszISPCode, c_pszInfSuffix, MAX_PATH, m_szINFFile, &pszTemp))
|
||
|
{
|
||
|
wsprintf(szTempBuffer,"Can not find:%s%s (%d)",pszISPCode,c_pszInfSuffix,GetLastError());
|
||
|
CMASSERTMSG(0,szTempBuffer);
|
||
|
hr = ERROR_FILE_NOT_FOUND;
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
// Load Region file, get region file name
|
||
|
|
||
|
char szStateFile[sizeof(szTempBuffer)/sizeof(szTempBuffer[0])];
|
||
|
|
||
|
GetPrivateProfileString(c_pszCmSectionIsp, c_pszCmEntryIspRegionFile, NULL, szStateFile, sizeof(szStateFile)-1, m_szINFFile);
|
||
|
|
||
|
//
|
||
|
// Can't assume current directory, construct path to PBK directory
|
||
|
//
|
||
|
|
||
|
pszCmpDir = GetBaseDirFromCms(m_szINFFile);
|
||
|
|
||
|
//
|
||
|
// Look for the .PBR file, using CMP dir as base path for search
|
||
|
//
|
||
|
|
||
|
if (!SearchPath(pszCmpDir, szStateFile, NULL, TEMP_BUFFER_LENGTH, szTempBuffer, &pszTemp))
|
||
|
{
|
||
|
// CMASSERTMSG(0,"STATE.ICW not found");
|
||
|
CMASSERTMSG(0,"region file not found");
|
||
|
hr = ERROR_FILE_NOT_FOUND;
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
// open region file
|
||
|
|
||
|
pcCSVFile = new CCSVFile;
|
||
|
if (!pcCSVFile)
|
||
|
{
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
if (!pcCSVFile->Open(szTempBuffer))
|
||
|
{
|
||
|
// CMASSERTMSG(0,"Can not open STATE.ICW");
|
||
|
CMASSERTMSG(0,"Can not open region file");
|
||
|
delete pcCSVFile;
|
||
|
pcCSVFile = NULL;
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
// first token in region file is the number of regions
|
||
|
|
||
|
if (!pcCSVFile->ClearNewLines() || !pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH))
|
||
|
{
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
if (!FSz2Dw(szTempBuffer,&m_cStates))
|
||
|
{
|
||
|
// CMASSERTMSG(0,"STATE.ICW count is invalid");
|
||
|
CMASSERTMSG(0,"region count is invalid");
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
// Now read in all the regions if there are any
|
||
|
|
||
|
if (0 != m_cStates)
|
||
|
{
|
||
|
m_rgState = (PSTATE)CmMalloc(sizeof(STATE)*m_cStates);
|
||
|
|
||
|
if (!m_rgState)
|
||
|
{
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
for (ps = m_rgState, psLast = &m_rgState[m_cStates - 1]; ps <= psLast;++ps)
|
||
|
{
|
||
|
if (pcCSVFile->ClearNewLines())
|
||
|
{
|
||
|
pcCSVFile->ReadToken(ps->szStateName,cbStateName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pcCSVFile->Close();
|
||
|
|
||
|
// load Phone Book Name
|
||
|
|
||
|
if (!GetPrivateProfileString(c_pszCmSectionIsp, c_pszCmEntryIspPbFile,c_pszInfDefault,
|
||
|
szTempBuffer,TEMP_BUFFER_LENGTH,m_szINFFile))
|
||
|
{
|
||
|
CMASSERTMSG(0,"PhoneBookFile not specified in INF file");
|
||
|
hr = ERROR_FILE_NOT_FOUND;
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (!lstrcmp(szTempBuffer,c_pszInfDefault))
|
||
|
{
|
||
|
wsprintf(szTempBuffer, "%s value not found in ISP file", c_pszCmEntryIspPbFile);
|
||
|
CMASSERTMSG(0,szTempBuffer);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Look for the .PBK file, using CMP dir as base path for search
|
||
|
//
|
||
|
|
||
|
if (!SearchPath(pszCmpDir,szTempBuffer,NULL,MAX_PATH,m_szPhoneBook,&pszTemp))
|
||
|
{
|
||
|
CMASSERTMSG(0,"ISP phone book not found");
|
||
|
hr = ERROR_FILE_NOT_FOUND;
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
// read in phone book entries
|
||
|
|
||
|
if (!pcCSVFile->Open(m_szPhoneBook))
|
||
|
{
|
||
|
CMASSERTMSG(0,"Can not open phone book");
|
||
|
hr = GetLastError();
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
dwNumAllocated = 0;
|
||
|
do {
|
||
|
|
||
|
MYDBGASSERT (dwNumAllocated >= m_cPhoneBookEntries);
|
||
|
|
||
|
if (m_rgPhoneBookEntry)
|
||
|
{
|
||
|
// If we already have an array, make sure its big enough
|
||
|
|
||
|
if (dwNumAllocated == m_cPhoneBookEntries)
|
||
|
{
|
||
|
// We're maxed out, allocate some more memory
|
||
|
|
||
|
dwNumAllocated += PHONE_ENTRY_ALLOC_SIZE;
|
||
|
dwAlloc = (DWORD) dwNumAllocated * sizeof(ACCESSENTRY);
|
||
|
MYDBG(("PhoneBook::Init - Grow ReAlloc = %lu",dwAlloc));
|
||
|
|
||
|
// Realloc
|
||
|
|
||
|
pTempAccessEntry = (PACCESSENTRY)CmRealloc(m_rgPhoneBookEntry, dwAlloc);
|
||
|
|
||
|
if (!pTempAccessEntry)
|
||
|
{
|
||
|
MYDBG(("PhoneBook::Init - Grow ReAlloc of %lu failed", dwAlloc));
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
m_rgPhoneBookEntry = pTempAccessEntry;
|
||
|
pTempAccessEntry = NULL;
|
||
|
|
||
|
MYDBG(("Grow phone book to %d entries",dwNumAllocated));
|
||
|
pCurAccessEntry = m_rgPhoneBookEntry + m_cPhoneBookEntries;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Initialization for the first time through
|
||
|
|
||
|
DWORD dwSize = (DWORD) sizeof(ACCESSENTRY);
|
||
|
dwAlloc = (DWORD) dwSize * PHONE_ENTRY_ALLOC_SIZE;
|
||
|
|
||
|
MYDBG(("PhoneBook::Init - sizeof(ACCESSENTRY) = %lu",dwSize));
|
||
|
MYDBG(("PhoneBook::Init - PHONE_ENTRY_ALLOC_SIZE = %d",PHONE_ENTRY_ALLOC_SIZE));
|
||
|
MYDBG(("PhoneBook::Init - Initial Alloc = %lu",dwAlloc));
|
||
|
|
||
|
// Allocate intial array of PHONE_ENTRY_ALLOC_SIZE items
|
||
|
|
||
|
m_rgPhoneBookEntry = (PACCESSENTRY)CmMalloc(dwAlloc);
|
||
|
|
||
|
if (!m_rgPhoneBookEntry)
|
||
|
{
|
||
|
MYDBG(("PhoneBook::Init - Initial Alloc of %lu failed",dwAlloc));
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
dwNumAllocated = PHONE_ENTRY_ALLOC_SIZE;
|
||
|
pCurAccessEntry = m_rgPhoneBookEntry;
|
||
|
}
|
||
|
|
||
|
// Read a line from the phonebook
|
||
|
|
||
|
hr = ReadOneLine(pCurAccessEntry,pcCSVFile);
|
||
|
|
||
|
if (hr == ERROR_NO_MORE_ITEMS)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
else if (hr != ERROR_SUCCESS)
|
||
|
{
|
||
|
MYDBG(("PhoneBook::Init - ReadOneLine failed"));
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
hr = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
|
||
|
// check the first index pointer to prevent it from being overwritten
|
||
|
// by the second appearance that's scattered around somewhere else -- added by byao
|
||
|
|
||
|
if (pCurAccessEntry->dwCountryID != dwLastCountry)
|
||
|
{
|
||
|
PIDLOOKUPELEMENT pIDLookUpElement;
|
||
|
// NOTE: Not sure about the first parameter here.
|
||
|
pIDLookUpElement = (PIDLOOKUPELEMENT)CmBSearch(&pCurAccessEntry->dwCountryID,
|
||
|
m_rgIDLookUp,(size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),
|
||
|
CompareIDLookUpElements);
|
||
|
|
||
|
if (!pIDLookUpElement)
|
||
|
{
|
||
|
// bad country ID, but we can't assert here
|
||
|
MYDBG(("Bad country ID in phone book %d\n",pCurAccessEntry->dwCountryID));
|
||
|
continue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// for a given country ID this is the first phone number
|
||
|
// don't overwrite existing index
|
||
|
|
||
|
if (!pIDLookUpElement->iFirstAE)
|
||
|
{
|
||
|
pIDLookUpElement->iFirstAE = PAEToIdx(pCurAccessEntry);
|
||
|
dwLastCountry = pCurAccessEntry->dwCountryID;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check to see if this is the first phone number for a given state
|
||
|
// the code has been changed accordingly
|
||
|
|
||
|
if (pCurAccessEntry->wStateID && (pCurAccessEntry->wStateID != dwLastState))
|
||
|
{
|
||
|
idx = pCurAccessEntry->wStateID - 1;
|
||
|
//
|
||
|
// don't overwrite existing index
|
||
|
//
|
||
|
if ((idx < m_cStates) && !m_rgState[idx].iFirst)
|
||
|
{
|
||
|
m_rgState[idx].dwCountryID = pCurAccessEntry->dwCountryID;
|
||
|
m_rgState[idx].iFirst = PAEToIdx(pCurAccessEntry);
|
||
|
}
|
||
|
dwLastState = pCurAccessEntry->wStateID;
|
||
|
}
|
||
|
|
||
|
pCurAccessEntry++;
|
||
|
m_cPhoneBookEntries++;
|
||
|
|
||
|
} while (TRUE);
|
||
|
|
||
|
MYDBG(("PhoneBook::Init - %lu Entries read",m_cPhoneBookEntries));
|
||
|
|
||
|
if (m_cPhoneBookEntries == 0)
|
||
|
{
|
||
|
//
|
||
|
// Phone book is empty
|
||
|
//
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
// Trim the phone book for unused memory
|
||
|
|
||
|
dwAlloc = m_cPhoneBookEntries * sizeof(ACCESSENTRY);
|
||
|
|
||
|
MYDBG(("PhoneBook::Init - Trim ReAlloc = %lu",dwAlloc));
|
||
|
|
||
|
MYDBGASSERT(m_cPhoneBookEntries);
|
||
|
|
||
|
// Realloc
|
||
|
|
||
|
pTempAccessEntry = (PACCESSENTRY)CmRealloc(m_rgPhoneBookEntry, dwAlloc);
|
||
|
|
||
|
MYDBGASSERT(pTempAccessEntry);
|
||
|
|
||
|
if (!pTempAccessEntry)
|
||
|
{
|
||
|
MYDBG(("PhoneBook::Init - Trim ReAlloc of %lu failed",dwAlloc));
|
||
|
goto InitExit;
|
||
|
}
|
||
|
|
||
|
m_rgPhoneBookEntry = pTempAccessEntry;
|
||
|
pTempAccessEntry = NULL;
|
||
|
|
||
|
hr = ERROR_SUCCESS;
|
||
|
|
||
|
// Exit
|
||
|
|
||
|
InitExit:
|
||
|
|
||
|
// If something failed release everything
|
||
|
|
||
|
if (hr != ERROR_SUCCESS)
|
||
|
{
|
||
|
CmFree(m_pLineCountryList);
|
||
|
m_pLineCountryList = NULL;
|
||
|
|
||
|
CmFree(m_rgPhoneBookEntry);
|
||
|
|
||
|
m_rgPhoneBookEntry = NULL;
|
||
|
m_cPhoneBookEntries = 0 ;
|
||
|
|
||
|
CmFree(m_rgIDLookUp);
|
||
|
m_rgIDLookUp=NULL;
|
||
|
|
||
|
CmFree(m_rgNameLookUp);
|
||
|
m_rgNameLookUp=NULL;
|
||
|
|
||
|
CmFree(m_rgState);
|
||
|
m_rgState = NULL;
|
||
|
|
||
|
m_cStates = 0;
|
||
|
}
|
||
|
|
||
|
if (pcCSVFile)
|
||
|
{
|
||
|
pcCSVFile->Close();
|
||
|
delete pcCSVFile;
|
||
|
}
|
||
|
|
||
|
if (pszCmpDir)
|
||
|
{
|
||
|
CmFree(pszCmpDir);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
HRESULT CPhoneBook::Merge(LPCSTR pszChangeFile)
|
||
|
{
|
||
|
char szTempBuffer[TEMP_BUFFER_LENGTH];
|
||
|
char szTempFileName[MAX_PATH];
|
||
|
CCSVFile *pcCSVFile = NULL;
|
||
|
ACCESSENTRY aeChange;
|
||
|
PIDXLOOKUPELEMENT rgIdxLookUp = NULL;
|
||
|
PIDXLOOKUPELEMENT pCurIdxLookUp;
|
||
|
DWORD dwAllocated;
|
||
|
DWORD dwOriginalSize;
|
||
|
HRESULT hr = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
DWORD dwIdx;
|
||
|
DWORD cch, cchWritten;
|
||
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||
|
|
||
|
MYDBG(("CPhoneBook::Merge"));
|
||
|
|
||
|
// We'll grow the phone book on the first add record (this minimizes the number
|
||
|
// of places in the code where we have to grow the phone book) - so, for now,
|
||
|
// just stay with the current size.
|
||
|
dwAllocated = m_cPhoneBookEntries;
|
||
|
|
||
|
// Create index to loaded phone book, sorted by index
|
||
|
rgIdxLookUp = (PIDXLOOKUPELEMENT)CmMalloc(sizeof(IDXLOOKUPELEMENT) * dwAllocated);
|
||
|
|
||
|
MYDBGASSERT(rgIdxLookUp);
|
||
|
|
||
|
if (!rgIdxLookUp)
|
||
|
{
|
||
|
goto MergeExit;
|
||
|
}
|
||
|
|
||
|
for (dwIdx = 0; dwIdx < m_cPhoneBookEntries; dwIdx++)
|
||
|
{
|
||
|
rgIdxLookUp[dwIdx].iAE = PAEToIdx(&m_rgPhoneBookEntry[dwIdx]);
|
||
|
rgIdxLookUp[dwIdx].dwIndex = IdxToPAE(rgIdxLookUp[dwIdx].iAE)->dwIndex;
|
||
|
}
|
||
|
dwOriginalSize = m_cPhoneBookEntries;
|
||
|
|
||
|
CmQSort(rgIdxLookUp,(size_t) dwOriginalSize,sizeof(IDXLOOKUPELEMENT),CompareIdxLookUpElements);
|
||
|
|
||
|
// Load changes to phone book
|
||
|
pcCSVFile = new CCSVFile;
|
||
|
MYDBGASSERT(pcCSVFile);
|
||
|
|
||
|
if (!pcCSVFile)
|
||
|
{
|
||
|
goto MergeExit;
|
||
|
}
|
||
|
|
||
|
if (!pcCSVFile->Open(pszChangeFile))
|
||
|
{
|
||
|
delete pcCSVFile;
|
||
|
pcCSVFile = NULL;
|
||
|
goto MergeExit;
|
||
|
}
|
||
|
|
||
|
do {
|
||
|
|
||
|
// Read a change record
|
||
|
ZeroMemory(&aeChange,sizeof(ACCESSENTRY));
|
||
|
hr = ReadOneLine(&aeChange, pcCSVFile);
|
||
|
|
||
|
if (hr == ERROR_NO_MORE_ITEMS)
|
||
|
{
|
||
|
break; // no more enteries
|
||
|
}
|
||
|
else if (hr != ERROR_SUCCESS)
|
||
|
{
|
||
|
goto MergeExit;
|
||
|
}
|
||
|
|
||
|
hr = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
|
||
|
/* if (!ReadPhoneBookDW(&aeChange.dwIndex,pcCSVFile))
|
||
|
break; // no more enteries
|
||
|
ReadVerifyPhoneBookDW(aeChange.dwCountryID);
|
||
|
ReadVerifyPhoneBookW(aeChange.wStateID);
|
||
|
ReadVerifyPhoneBookSZ(aeChange.szCity,cbCity);
|
||
|
ReadVerifyPhoneBookSZ(aeChange.szAreaCode,cbAreaCode);
|
||
|
// NOTE: 0 is a valid area code and ,, is a valid entry for an area code
|
||
|
if (!FSz2Dw(aeChange.szAreaCode,&aeChange.dwAreaCode))
|
||
|
aeChange.dwAreaCode = NO_AREA_CODE;
|
||
|
ReadVerifyPhoneBookSZ(aeChange.szAccessNumber,cbAccessNumber);
|
||
|
ReadVerifyPhoneBookDW(aeChange.dwConnectSpeedMin);
|
||
|
ReadVerifyPhoneBookDW(aeChange.dwConnectSpeedMax);
|
||
|
ReadVerifyPhoneBookB(aeChange.bFlipFactor);
|
||
|
ReadVerifyPhoneBookDW(aeChange.fType);
|
||
|
ReadVerifyPhoneBookSZ(aeChange.szDataCenter,cbDataCenter);
|
||
|
*/
|
||
|
|
||
|
pCurIdxLookUp = (PIDXLOOKUPELEMENT) CmBSearch(&aeChange,
|
||
|
rgIdxLookUp,
|
||
|
(size_t) dwOriginalSize,
|
||
|
sizeof(IDXLOOKUPELEMENT),
|
||
|
CompareIdxLookUpElements);
|
||
|
// Determine if this is a delete, add, or merge record
|
||
|
if (aeChange.szAccessNumber[0] == '0' && aeChange.szAccessNumber[1] == '\0')
|
||
|
{
|
||
|
// This is a delete record
|
||
|
CMASSERTMSG(pCurIdxLookUp,"Attempting to delete a record that does not exist. The change file and phone book versions do not match.");
|
||
|
if (pCurIdxLookUp)
|
||
|
{
|
||
|
CMASSERTMSG(IdxToPAE(pCurIdxLookUp->iAE),"Attempting to delete a record that has already been deleted.");
|
||
|
pCurIdxLookUp->iAE = PAEToIdx(NULL); //Create a dead entry in the look up table
|
||
|
}
|
||
|
}
|
||
|
else if (pCurIdxLookUp)
|
||
|
{
|
||
|
// This is a change record
|
||
|
CMASSERTMSG(IdxToPAE(pCurIdxLookUp->iAE),"Attempting to change a record which has been deleted.");
|
||
|
if (IdxToPAE(pCurIdxLookUp->iAE))
|
||
|
{
|
||
|
CopyMemory(IdxToPAE(pCurIdxLookUp->iAE),&aeChange,sizeof(ACCESSENTRY));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// This is an add entry
|
||
|
// Make sure we have enough room
|
||
|
if (m_cPhoneBookEntries >= dwAllocated)
|
||
|
{
|
||
|
// Grow phone book
|
||
|
|
||
|
dwAllocated += CHANGE_BUFFER_SIZE;
|
||
|
DWORD dwNewAlloc = (DWORD) sizeof(ACCESSENTRY) * dwAllocated;
|
||
|
|
||
|
PACCESSENTRY pTempAccessEntry = (PACCESSENTRY)CmRealloc(m_rgPhoneBookEntry, dwNewAlloc);
|
||
|
MYDBGASSERT(pTempAccessEntry);
|
||
|
|
||
|
if (!pTempAccessEntry)
|
||
|
{
|
||
|
MYDBG(("PhoneBook::Merge - Grow ReAlloc of %lu failed",dwNewAlloc));
|
||
|
goto MergeExit;
|
||
|
}
|
||
|
|
||
|
m_rgPhoneBookEntry = pTempAccessEntry;
|
||
|
|
||
|
pTempAccessEntry = NULL;
|
||
|
|
||
|
MYDBG(("Grow phone book to %lu entries",dwAllocated));
|
||
|
|
||
|
// Grow look up index
|
||
|
MYDBGASSERT(rgIdxLookUp);
|
||
|
|
||
|
PIDXLOOKUPELEMENT pTempLookupElement = (PIDXLOOKUPELEMENT)CmRealloc(rgIdxLookUp, sizeof(IDXLOOKUPELEMENT)*dwAllocated);
|
||
|
|
||
|
MYDBGASSERT(pTempLookupElement);
|
||
|
if (!pTempLookupElement)
|
||
|
{
|
||
|
goto MergeExit;
|
||
|
}
|
||
|
|
||
|
rgIdxLookUp = pTempLookupElement;
|
||
|
}
|
||
|
|
||
|
//Add entry to the end of the phonebook and to end of look up index
|
||
|
CopyMemory(&m_rgPhoneBookEntry[m_cPhoneBookEntries],&aeChange,sizeof(ACCESSENTRY));
|
||
|
rgIdxLookUp[m_cPhoneBookEntries].iAE = PAEToIdx(&m_rgPhoneBookEntry[m_cPhoneBookEntries]);
|
||
|
rgIdxLookUp[m_cPhoneBookEntries].dwIndex = IdxToPAE(rgIdxLookUp[m_cPhoneBookEntries].iAE)->dwIndex;
|
||
|
m_cPhoneBookEntries++;
|
||
|
// NOTE: because the entry is added to the end of the list, we can't add
|
||
|
// and delete entries in the same change file.
|
||
|
}
|
||
|
} while (TRUE);
|
||
|
|
||
|
// The CompareIdxLookupElementFileOrder() function needs the iAE member to be
|
||
|
// a PACCESSENTRY, and not an index. So we convert 'em here, and then we'll
|
||
|
// convert 'em back later.
|
||
|
for (dwIdx=0;dwIdx<m_cPhoneBookEntries;dwIdx++) {
|
||
|
rgIdxLookUp[dwIdx].iAE = (LONG_PTR)IdxToPAE(rgIdxLookUp[dwIdx].iAE);
|
||
|
}
|
||
|
|
||
|
// resort the IDXLookUp index to reflect the correct order of entries
|
||
|
// for the phonebook file, including all of the entries to be deleted.
|
||
|
CmQSort(rgIdxLookUp,(size_t) m_cPhoneBookEntries,sizeof(IDXLOOKUPELEMENT),CompareIdxLookUpElementsFileOrder);
|
||
|
|
||
|
// Now we convert 'em back.
|
||
|
for (dwIdx=0;dwIdx<m_cPhoneBookEntries;dwIdx++) {
|
||
|
rgIdxLookUp[dwIdx].iAE = PAEToIdx((PACCESSENTRY) rgIdxLookUp[dwIdx].iAE);
|
||
|
}
|
||
|
|
||
|
// Build a new phonebook file
|
||
|
#if 0
|
||
|
/*
|
||
|
#define TEMP_PHONE_BOOK_PREFIX "PBH"
|
||
|
|
||
|
if (!GetTempPath(TEMP_BUFFER_LENGTH,szTempBuffer))
|
||
|
goto MergeExit;
|
||
|
if (!GetTempFileName(szTempBuffer,TEMP_PHONE_BOOK_PREFIX,0,szTempFileName))
|
||
|
goto MergeExit;
|
||
|
hFile = CreateFile(szTempFileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
|
||
|
FILE_FLAG_WRITE_THROUGH,0);
|
||
|
*/
|
||
|
#else
|
||
|
for (dwIdx=0;;dwIdx++)
|
||
|
{
|
||
|
lstrcpy(szTempFileName,m_szPhoneBook);
|
||
|
|
||
|
wsprintf(szTempFileName+lstrlen(szTempFileName),".%03u",dwIdx);
|
||
|
hFile = CreateFile(szTempFileName,GENERIC_WRITE,0,NULL,CREATE_NEW,0,0);
|
||
|
if ((hFile != INVALID_HANDLE_VALUE) || (GetLastError() != ERROR_FILE_EXISTS)) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
goto MergeExit;
|
||
|
}
|
||
|
|
||
|
for (dwIdx = 0; dwIdx < m_cPhoneBookEntries; dwIdx++)
|
||
|
{
|
||
|
PACCESSENTRY pAE = IdxToPAE(rgIdxLookUp[dwIdx].iAE);
|
||
|
|
||
|
if (pAE) {
|
||
|
cch = wsprintf(szTempBuffer, "%lu,%lu,%lu,%s,%s,%s,%lu,%lu,%lu,%lu,%s\r\n",
|
||
|
pAE->dwIndex,
|
||
|
pAE->dwCountryID,
|
||
|
(DWORD) pAE->wStateID,
|
||
|
pAE->szCity,
|
||
|
pAE->szAreaCode,
|
||
|
pAE->szAccessNumber,
|
||
|
pAE->dwConnectSpeedMin,
|
||
|
pAE->dwConnectSpeedMax,
|
||
|
(DWORD) pAE->bFlipFactor,
|
||
|
(DWORD) pAE->fType,
|
||
|
pAE->szDataCenter);
|
||
|
|
||
|
if (!WriteFile(hFile,szTempBuffer,cch,&cchWritten,NULL))
|
||
|
{
|
||
|
// something went wrong, get rid of the temporary file
|
||
|
hr = GetLastError();
|
||
|
CloseHandle(hFile);
|
||
|
hFile = INVALID_HANDLE_VALUE;
|
||
|
DeleteFile(szTempFileName);
|
||
|
goto MergeExit;
|
||
|
}
|
||
|
|
||
|
MYDBGASSERT(cch == cchWritten);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CloseHandle(hFile);
|
||
|
hFile = INVALID_HANDLE_VALUE;
|
||
|
|
||
|
// Move new phone book over old
|
||
|
if (!DeleteFile(m_szPhoneBook))
|
||
|
{
|
||
|
hr = GetLastError();
|
||
|
goto MergeExit;
|
||
|
}
|
||
|
if (!MoveFile(szTempFileName,m_szPhoneBook))
|
||
|
{
|
||
|
hr = GetLastError();
|
||
|
goto MergeExit;
|
||
|
}
|
||
|
|
||
|
// discard the phonebook in memory
|
||
|
|
||
|
CmFree(m_rgPhoneBookEntry);
|
||
|
m_rgPhoneBookEntry = NULL;
|
||
|
m_cPhoneBookEntries = 0;
|
||
|
|
||
|
CmFree(m_pLineCountryList);
|
||
|
CmFree(m_rgIDLookUp);
|
||
|
CmFree(m_rgNameLookUp);
|
||
|
CmFree(m_rgState);
|
||
|
|
||
|
m_pLineCountryList = NULL;
|
||
|
m_rgIDLookUp = NULL;
|
||
|
m_rgNameLookUp = NULL;
|
||
|
m_rgState = NULL;
|
||
|
m_cStates = 0;
|
||
|
|
||
|
lstrcpy(szTempBuffer,m_szINFFile);
|
||
|
m_szINFFile[0] = '\0';
|
||
|
m_szPhoneBook[0] = '\0';
|
||
|
|
||
|
// Reload it (and rebuild look up arrays)
|
||
|
hr = Init(szTempBuffer);
|
||
|
|
||
|
MergeExit:
|
||
|
if (pcCSVFile)
|
||
|
{
|
||
|
pcCSVFile->Close();
|
||
|
delete pcCSVFile;
|
||
|
}
|
||
|
if (hFile != INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
CloseHandle(hFile);
|
||
|
}
|
||
|
|
||
|
CmFree(rgIdxLookUp);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
HRESULT CPhoneBook::ReadOneLine(PACCESSENTRY pAccessEntry, CCSVFile *pcCSVFile)
|
||
|
{
|
||
|
HRESULT hr = ERROR_SUCCESS;
|
||
|
|
||
|
//
|
||
|
// Skip newlines (trailing or leading) and read first DW token
|
||
|
// If either fail, then consider this the end of the file
|
||
|
//
|
||
|
|
||
|
if (!ReadPhoneBookNL(pcCSVFile) || !ReadPhoneBookDW(&pAccessEntry->dwIndex,pcCSVFile))
|
||
|
{
|
||
|
hr = ERROR_NO_MORE_ITEMS; // no more enteries
|
||
|
MYDBG(("CPhoneBook::ReadOneLine - No More items"));
|
||
|
goto ReadExit;
|
||
|
}
|
||
|
|
||
|
ReadVerifyPhoneBookDW(pAccessEntry->dwCountryID);
|
||
|
ReadVerifyPhoneBookW(pAccessEntry->wStateID);
|
||
|
ReadVerifyPhoneBookSZ(pAccessEntry->szCity,cbCity);
|
||
|
ReadVerifyPhoneBookSZ(pAccessEntry->szAreaCode,cbAreaCode);
|
||
|
// NOTE: 0 is a valid area code and ,, is a valid entry for an area code
|
||
|
if (!FSz2Dw(pAccessEntry->szAreaCode,&pAccessEntry->dwAreaCode))
|
||
|
pAccessEntry->dwAreaCode = NO_AREA_CODE;
|
||
|
ReadVerifyPhoneBookSZ(pAccessEntry->szAccessNumber,cbAccessNumber);
|
||
|
ReadVerifyPhoneBookDW(pAccessEntry->dwConnectSpeedMin);
|
||
|
ReadVerifyPhoneBookDW(pAccessEntry->dwConnectSpeedMax);
|
||
|
ReadVerifyPhoneBookB(pAccessEntry->bFlipFactor);
|
||
|
ReadVerifyPhoneBookDW(pAccessEntry->fType);
|
||
|
|
||
|
//
|
||
|
// Attempt to read datacenter, if read fails, find out why before reacting
|
||
|
//
|
||
|
|
||
|
if (!ReadPhoneBookSZ(pAccessEntry->szDataCenter, cbDataCenter + 1, pcCSVFile))
|
||
|
{
|
||
|
//
|
||
|
// If the last read was successful, then we must have some bad sz data
|
||
|
//
|
||
|
|
||
|
if (!pcCSVFile->ReadError())
|
||
|
{
|
||
|
CMASSERTMSG(0,"Invalid STRING in phone book");
|
||
|
goto DataError;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ReadExit:
|
||
|
return hr;
|
||
|
DataError:
|
||
|
hr = ERROR_INVALID_DATA;
|
||
|
goto ReadExit;
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
HRESULT CPhoneBook::GetCanonical (PACCESSENTRY pAE, char *psOut)
|
||
|
{
|
||
|
HRESULT hr = ERROR_SUCCESS;
|
||
|
PIDLOOKUPELEMENT pIDLookUp;
|
||
|
|
||
|
pIDLookUp = (PIDLOOKUPELEMENT)CmBSearch(&pAE->dwCountryID,m_rgIDLookUp,
|
||
|
(size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),CompareIdxLookUpElements);
|
||
|
|
||
|
if (!pIDLookUp)
|
||
|
{
|
||
|
hr = ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!psOut)
|
||
|
{
|
||
|
hr = ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*psOut = 0;
|
||
|
SzCanonicalFromAE (psOut, pAE, pIDLookUp->pLCE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
HRESULT CPhoneBook::GetNonCanonical (PACCESSENTRY pAE, char *psOut)
|
||
|
{
|
||
|
HRESULT hr = ERROR_SUCCESS;
|
||
|
PIDLOOKUPELEMENT pIDLookUp;
|
||
|
|
||
|
pIDLookUp = (PIDLOOKUPELEMENT)CmBSearch(&pAE->dwCountryID,m_rgIDLookUp,
|
||
|
(size_t) m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),CompareIdxLookUpElements);
|
||
|
|
||
|
if (!pIDLookUp)
|
||
|
{
|
||
|
hr = ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!psOut)
|
||
|
{
|
||
|
hr = ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*psOut = 0;
|
||
|
SzNonCanonicalFromAE (psOut, pAE, pIDLookUp->pLCE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
DllExportH PhoneBookLoad(LPCSTR pszISPCode, DWORD_PTR *pdwPhoneID)
|
||
|
{
|
||
|
HRESULT hr = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
CPhoneBook *pcPhoneBook;
|
||
|
|
||
|
MYDBG(("CM_PHBK_DllExport - PhoneBookLoad"));
|
||
|
|
||
|
if (!g_hInst) g_hInst = GetModuleHandleA(NULL);
|
||
|
|
||
|
// validate parameters
|
||
|
MYDBGASSERT(pszISPCode && *pszISPCode && pdwPhoneID);
|
||
|
*pdwPhoneID = NULL;
|
||
|
|
||
|
// allocate phone book
|
||
|
pcPhoneBook = new CPhoneBook;
|
||
|
|
||
|
// initialize phone book
|
||
|
if (pcPhoneBook)
|
||
|
hr = pcPhoneBook->Init(pszISPCode);
|
||
|
|
||
|
// in case of failure
|
||
|
if (hr && pcPhoneBook)
|
||
|
{
|
||
|
delete pcPhoneBook;
|
||
|
MYDBG(("PhoneBookLoad() - init failed"));
|
||
|
} else {
|
||
|
*pdwPhoneID = (DWORD_PTR)pcPhoneBook;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
DllExportH PhoneBookUnload(DWORD_PTR dwPhoneID)
|
||
|
{
|
||
|
MYDBG(("CM_PHBK_DllExport - PhoneBookUnload"));
|
||
|
|
||
|
MYDBGASSERT(dwPhoneID);
|
||
|
|
||
|
// Release contents
|
||
|
delete (CPhoneBook*)dwPhoneID;
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
// ############################################################################
|
||
|
DllExportH PhoneBookMergeChanges(DWORD_PTR dwPhoneID, LPCSTR pszChangeFile)
|
||
|
{
|
||
|
MYDBG(("CM_PHBK_DllExport - PhoneBookMergeChanges"));
|
||
|
|
||
|
return ((CPhoneBook*)dwPhoneID)->Merge(pszChangeFile);
|
||
|
}
|
||
|
|