// ############################################################################ // Phone book APIs #include "pch.hpp" #include #include "phbk.h" #include "misc.h" #include "phbkrc.h" #include "suapi.h" #define ReadVerifyPhoneBookDW(x) if (!ReadPhoneBookDW(&(x),pcCSVFile)) \ { AssertSz(0,"Invalid DWORD in phone book"); \ goto ReadError; } #define ReadVerifyPhoneBookW(x) if (!ReadPhoneBookW(&(x),pcCSVFile)) \ { AssertSz(0,"Invalid DWORD in phone book"); \ goto ReadError; } #define ReadVerifyPhoneBookB(x) if (!ReadPhoneBookB(&(x),pcCSVFile)) \ { AssertSz(0,"Invalid DWORD in phone book"); \ goto ReadError; } #define ReadVerifyPhoneBookSZ(x,y) if (!ReadPhoneBookSZ(&x[0],y+sizeof('\0'),pcCSVFile)) \ { AssertSz(0,"Invalid DWORD in phone book"); \ goto ReadError; } #define CHANGE_BUFFER_SIZE 50 #define TEMP_PHONE_BOOK_PREFIX "PBH" #define ERROR_USERBACK 32766 #define ERROR_USERCANCEL 32767 char szTempBuffer[TEMP_BUFFER_LENGTH]; char szTempFileName[MAX_PATH]; #ifdef __cplusplus extern "C" { #endif HWND g_hWndMain; #ifdef __cplusplus } #endif static void GetAbsolutePath( LPTSTR input, LPTSTR output, DWORD chOut) { if(_tcschr(input,_T('%')) == NULL) { _tcsncpy(output, input, chOut); return ; } if(input[0] == _T('%')) { LPTSTR token = _tcstok(input,_T("%")); if(token != NULL) { LPTSTR sztemp; sztemp = getenv( token ); if(sztemp != NULL) { _tcsncpy(output, sztemp, chOut); } token = _tcstok(NULL,_T("\0")); if(token != NULL) { _tcsncat(output, token, chOut - _tcslen(output)); } } } else { LPTSTR token = _tcstok(input,_T("%")); if(token != NULL) { _tcsncpy(output, token, chOut); token = _tcstok(NULL,_T("%")); if(token != NULL) { LPTSTR sztemp; sztemp = getenv( token ); if(sztemp != NULL) { _tcsncat(output, sztemp, chOut - _tcslen(output)); } token = _tcstok(NULL,_T("\0")); if(token != NULL) { _tcsncat(output, token, chOut - _tcslen(output)); } } } } GetAbsolutePath(output, output, chOut); } // ############################################################################ CPhoneBook::CPhoneBook() { HINSTANCE hInst = NULL; LONG lrc; // HANDLE hKey; LONG regStatus; char uszRegKey[]="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\ICWCONN1.EXE"; char uszR[ ]= "Path"; DWORD dwInfoSize ; HKEY hKey; DWORD dwType; DWORD dwSize; CHAR szData[MAX_PATH+1]; CHAR czTemp[256]; m_rgPhoneBookEntry = NULL; m_hPhoneBookEntry = NULL; m_cPhoneBookEntries =0; m_rgLineCountryEntry=NULL; m_rgState=NULL; m_cStates=0; m_rgIDLookUp = NULL; m_rgNameLookUp = NULL; m_pLineCountryList = NULL; ZeroMemory(&m_szINFFile[0],MAX_PATH); ZeroMemory(&m_szINFCode[0],MAX_INFCODE); ZeroMemory(&m_szPhoneBook[0],MAX_PATH); ZeroMemory(&m_szICWDirectoryPath,MAX_PATH); regStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uszRegKey,0,KEY_READ ,&hKey); if (regStatus == ERROR_SUCCESS) { // Get The Path dwInfoSize = MAX_PATH; RegQueryValueEx(hKey,uszR,NULL,0,(LPBYTE) czTemp, &dwInfoSize); GetAbsolutePath(czTemp,m_szICWDirectoryPath, MAX_PATH-1); size_t sLen = strlen(m_szICWDirectoryPath); m_szICWDirectoryPath[sLen-1] = '\0'; } else { MessageBox(NULL,"Error Accessing PAth ","SearchPath",MB_OK); // Error } #if !defined(WIN16) if (VER_PLATFORM_WIN32_NT == DWGetWin32Platform()) { m_bScriptingAvailable = TRUE; } else { // // Verify scripting by checking for smmscrpt.dll in RemoteAccess registry key // if (1111 <= DWGetWin32BuildNumber()) { m_bScriptingAvailable = TRUE; } else { m_bScriptingAvailable = FALSE; hKey = NULL; lrc=RegOpenKey(HKEY_LOCAL_MACHINE,"System\\CurrentControlSet\\Services\\RemoteAccess\\Authentication\\SMM_FILES\\PPP",&hKey); if (ERROR_SUCCESS == lrc) { dwSize = MAX_PATH; lrc = RegQueryValueEx(hKey,"Path",0,&dwType,(LPBYTE)szData,&dwSize); if (ERROR_SUCCESS == lrc) { if (0 == lstrcmpi(szData,"smmscrpt.dll")) m_bScriptingAvailable = TRUE; } } if (hKey) RegCloseKey(hKey); hKey = NULL; } // // Verify that the DLL can be loaded // if (m_bScriptingAvailable) { hInst = LoadLibrary("smmscrpt.dll"); if (hInst) FreeLibrary(hInst); else m_bScriptingAvailable = FALSE; hInst = NULL; } } #endif // WIN16 } // ############################################################################ CPhoneBook::~CPhoneBook() { #ifdef WIN16 if (m_rgPhoneBookEntry) GlobalFree(m_rgPhoneBookEntry); #else if (m_hPhoneBookEntry) GlobalUnlock(m_hPhoneBookEntry); if (m_hPhoneBookEntry) GlobalFree(m_hPhoneBookEntry); #endif if (m_pLineCountryList) GlobalFree(m_pLineCountryList); if (m_rgIDLookUp) GlobalFree(m_rgIDLookUp); if (m_rgNameLookUp) GlobalFree(m_rgNameLookUp); if (m_rgState) GlobalFree(m_rgState); } // ############################################################################ BOOL CPhoneBook::ReadPhoneBookDW(DWORD far *pdw, CCSVFile far *pcCSVFile) { if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH)) return FALSE; return (FSz2Dw(szTempBuffer,pdw)); } // ############################################################################ BOOL CPhoneBook::ReadPhoneBookW(WORD far *pw, CCSVFile far *pcCSVFile) { if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH)) return FALSE; return (FSz2W(szTempBuffer,pw)); } // ############################################################################ BOOL CPhoneBook::ReadPhoneBookB(BYTE far *pb, CCSVFile far *pcCSVFile) { if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH)) return FALSE; return (FSz2B(szTempBuffer,pb)); } // ############################################################################ BOOL CPhoneBook::ReadPhoneBookSZ(LPSTR psz, DWORD dwSize, CCSVFile far *pcCSVFile) { if (!pcCSVFile->ReadToken(psz,dwSize)) return FALSE; return TRUE; } // ############################################################################ BOOL CPhoneBook::FixUpFromRealloc(PACCESSENTRY paeOld, PACCESSENTRY paeNew) { BOOL bRC = FALSE; LONG_PTR lDiff = 0; DWORD idx = 0; // // No starting value or no move, therefore no fix-ups needed // if ((0 == paeOld) || (paeNew == paeOld)) { bRC = TRUE; goto FixUpFromReallocExit; } Assert(paeNew); Assert(((LONG_PTR)paeOld) > 0); // if these address look like negative numbers Assert(((LONG_PTR)paeNew) > 0); // I'm not sure the code would handle them lDiff = (LONG_PTR)paeOld - (LONG_PTR)paeNew; // // fix up STATES // for (idx = 0; idx < m_cStates; idx++) { if (m_rgState[idx].paeFirst) m_rgState[idx].paeFirst = (PACCESSENTRY )((LONG_PTR)m_rgState[idx].paeFirst - lDiff); } // // fix up ID look up array // for (idx = 0; idx < m_pLineCountryList->dwNumCountries ; idx++) { if (m_rgIDLookUp[idx].pFirstAE) m_rgIDLookUp[idx].pFirstAE = (PACCESSENTRY )((LONG_PTR)m_rgIDLookUp[idx].pFirstAE - lDiff); } bRC = TRUE; FixUpFromReallocExit: return bRC; } /* long WINAPI lineGetCountry(unsigned long x,unsigned long y,struct linecountrylist_tag *z) { return 0; } */ // ############################################################################ HRESULT CPhoneBook::Init(LPCSTR pszISPCode) { LPLINECOUNTRYLIST pLineCountryTemp = NULL; HRESULT hr = ERROR_NOT_ENOUGH_MEMORY; DWORD dwLastState = 0; DWORD dwLastCountry = 0; DWORD dwSizeAllocated; PACCESSENTRY pCurAccessEntry; PACCESSENTRY pAETemp; HGLOBAL pTemp; LPLINECOUNTRYENTRY pLCETemp; DWORD idx; LPSTR pszTemp; CCSVFile far *pcCSVFile=NULL; LPSTATE ps,psLast; //faster to use pointers. int iTestSK; // Get TAPI country list m_pLineCountryList = (LPLINECOUNTRYLIST)GlobalAlloc(GPTR,sizeof(LINECOUNTRYLIST)); if (!m_pLineCountryList) goto InitExit; m_pLineCountryList->dwTotalSize = sizeof(LINECOUNTRYLIST); #if defined(WIN16) idx = (DWORD) IETapiGetCountry(0, m_pLineCountryList); #else idx = lineGetCountry(0,0x10003,m_pLineCountryList); #endif if (idx && idx != LINEERR_STRUCTURETOOSMALL) goto InitExit; Assert(m_pLineCountryList->dwNeededSize); pLineCountryTemp = (LPLINECOUNTRYLIST)GlobalAlloc(GPTR, (size_t)m_pLineCountryList->dwNeededSize); if (!pLineCountryTemp) goto InitExit; pLineCountryTemp->dwTotalSize = m_pLineCountryList->dwNeededSize; GlobalFree(m_pLineCountryList); m_pLineCountryList = pLineCountryTemp; pLineCountryTemp = NULL; #if defined(WIN16) if (IETapiGetCountry(0, m_pLineCountryList)) #else if (lineGetCountry(0,0x10003,m_pLineCountryList)) #endif goto InitExit; //#endif // WIN16 // Load Look Up arrays #ifdef DEBUG m_rgIDLookUp = (LPIDLOOKUPELEMENT)GlobalAlloc(GPTR, (int)(sizeof(IDLOOKUPELEMENT)*m_pLineCountryList->dwNumCountries+5)); #else m_rgIDLookUp = (LPIDLOOKUPELEMENT)GlobalAlloc(GPTR, (int)(sizeof(IDLOOKUPELEMENT)*m_pLineCountryList->dwNumCountries)); #endif if (!m_rgIDLookUp) goto InitExit; pLCETemp = (LPLINECOUNTRYENTRY)((DWORD_PTR)m_pLineCountryList + m_pLineCountryList->dwCountryListOffset); for (idx=0;idxdwNumCountries;idx++) { m_rgIDLookUp[idx].dwID = pLCETemp[idx].dwCountryID; m_rgIDLookUp[idx].pLCE = &pLCETemp[idx]; } qsort(m_rgIDLookUp,(int)m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT), CompareIDLookUpElements); m_rgNameLookUp = (LPCNTRYNAMELOOKUPELEMENT)GlobalAlloc(GPTR, (int)(sizeof(CNTRYNAMELOOKUPELEMENT) * m_pLineCountryList->dwNumCountries)); if (!m_rgNameLookUp) goto InitExit; for (idx=0;idxdwNumCountries;idx++) { m_rgNameLookUp[idx].psCountryName = (LPSTR)((LPBYTE)m_pLineCountryList + (DWORD)pLCETemp[idx].dwCountryNameOffset); m_rgNameLookUp[idx].dwNameSize = pLCETemp[idx].dwCountryNameSize; m_rgNameLookUp[idx].pLCE = &pLCETemp[idx]; } qsort(m_rgNameLookUp,(int)m_pLineCountryList->dwNumCountries,sizeof(CNTRYNAMELOOKUPELEMENT), CompareCntryNameLookUpElements); // Load States if (!SearchPath(NULL,STATE_FILENAME,NULL,TEMP_BUFFER_LENGTH,szTempBuffer,&pszTemp)) { if(m_szICWDirectoryPath){ // Try with c:\\ProgramFile\\ICW-INTERNET\\...... if(! SearchPath(m_szICWDirectoryPath, STATE_FILENAME,NULL,TEMP_BUFFER_LENGTH,szTempBuffer,&pszTemp)) { AssertSz(0,"STATE.ICW not found"); hr = ERROR_FILE_NOT_FOUND; goto InitExit; }else { ; // OK Th e file is found iTestSK=0; } } else { AssertSz(0,"STATE.ICW not found"); hr = ERROR_FILE_NOT_FOUND; goto InitExit; } } pcCSVFile = new CCSVFile; if (!pcCSVFile) goto InitExit; if (!pcCSVFile->Open(szTempBuffer)) { AssertSz(0,"Can not open STATE.ICW"); delete pcCSVFile; pcCSVFile = NULL; goto InitExit; } // first token in state file is the number of states if (!pcCSVFile->ReadToken(szTempBuffer,TEMP_BUFFER_LENGTH)) goto InitExit; if (!FSz2Dw(szTempBuffer,&m_cStates)) { AssertSz(0,"STATE.ICW count is invalid"); goto InitExit; } m_rgState = (LPSTATE)GlobalAlloc(GPTR,(int)(sizeof(STATE)*m_cStates)); if (!m_rgState) goto InitExit; for (ps = m_rgState, psLast = &m_rgState[m_cStates - 1]; ps <= psLast;++ps) { pcCSVFile->ReadToken(ps->szStateName,cbStateName); } pcCSVFile->Close(); // Locate ISP's INF file if (!SearchPath(NULL,(LPCTSTR) pszISPCode,INF_SUFFIX,MAX_PATH, m_szINFFile,&pszTemp)) { wsprintf(szTempBuffer,"Can not find:%s%s (%d)",pszISPCode,INF_SUFFIX,GetLastError()); if(m_szICWDirectoryPath) { if(!SearchPath(m_szICWDirectoryPath,(LPCTSTR) pszISPCode,INF_SUFFIX,MAX_PATH, m_szINFFile,&pszTemp)) { AssertSz(0,szTempBuffer); hr = ERROR_FILE_NOT_FOUND; goto InitExit; // }else { iTestSK++; } }else { AssertSz(0,szTempBuffer); hr = ERROR_FILE_NOT_FOUND; goto InitExit; } } //Load Phone Book if (!GetPrivateProfileString(INF_APP_NAME,INF_PHONE_BOOK,INF_DEFAULT, szTempBuffer,TEMP_BUFFER_LENGTH,m_szINFFile)) { AssertSz(0,"PhoneBookFile not specified in INF file"); hr = ERROR_FILE_NOT_FOUND; goto InitExit; } #ifdef DEBUG if (!lstrcmp(szTempBuffer,INF_DEFAULT)) { wsprintf(szTempBuffer, "%s value not found in ISP file", INF_PHONE_BOOK); AssertSz(0,szTempBuffer); } #endif if (!SearchPath(NULL,szTempBuffer,NULL,MAX_PATH,m_szPhoneBook,&pszTemp)) { if(m_szICWDirectoryPath){ if (!SearchPath(m_szICWDirectoryPath,szTempBuffer,NULL,MAX_PATH,m_szPhoneBook,&pszTemp)){ AssertSz(0,"ISP phone book not found"); hr = ERROR_FILE_NOT_FOUND; goto InitExit; }else { ;; // OK file Found iTestSK++; } }else { AssertSz(0,"ISP phone book not found"); hr = ERROR_FILE_NOT_FOUND; goto InitExit; } } if (!pcCSVFile->Open(m_szPhoneBook)) { AssertSz(0,"Can not open phone book"); hr = GetLastError(); goto InitExit; } dwSizeAllocated = 0; do { Assert (dwSizeAllocated >= m_cPhoneBookEntries); // check that sufficient memory is allocated if (m_rgPhoneBookEntry) { if (dwSizeAllocated == m_cPhoneBookEntries) { // // we need more memory // // AssertSz(0,"Out of memory originally allocated for phone book.\r\n"); // goto InitExit; pAETemp = m_rgPhoneBookEntry; #ifdef WIN16 dwSizeAllocated += PHONE_ENTRY_ALLOC_SIZE; pTemp = GlobalReAlloc(m_rgPhoneBookEntry, (int)(dwSizeAllocated * sizeof(ACCESSENTRY)),GHND); if (NULL == pTemp) goto InitExit; else m_rgPhoneBookEntry = (PACCESSENTRY)pTemp; #else // UNLOCK Assert(m_hPhoneBookEntry); if (FALSE == GlobalUnlock(m_hPhoneBookEntry)) { if (NO_ERROR != GetLastError()) goto InitExit; } // REALLOC dwSizeAllocated += PHONE_ENTRY_ALLOC_SIZE; pTemp = GlobalReAlloc(m_hPhoneBookEntry, (int)(dwSizeAllocated * sizeof(ACCESSENTRY)),GHND); if (NULL == pTemp) goto InitExit; else m_hPhoneBookEntry = pTemp; // LOCK m_rgPhoneBookEntry = (PACCESSENTRY)GlobalLock(m_hPhoneBookEntry); if (NULL == m_rgPhoneBookEntry) goto InitExit; #endif FixUpFromRealloc(pAETemp, m_rgPhoneBookEntry); Dprintf("Grow phone book to %d entries\n",dwSizeAllocated); pCurAccessEntry = (PACCESSENTRY)((LONG_PTR)pCurAccessEntry - ((LONG_PTR)pAETemp - (LONG_PTR)(m_rgPhoneBookEntry))); } } else { // // Initialization for the first time through // // ALLOC #ifdef WIN16 m_rgPhoneBookEntry = (PACCESSENTRY)GlobalAlloc(GHND,sizeof(ACCESSENTRY) * PHONE_ENTRY_ALLOC_SIZE); if(NULL == m_rgPhoneBookEntry) goto InitExit; #else m_hPhoneBookEntry = GlobalAlloc(GHND,sizeof(ACCESSENTRY) * PHONE_ENTRY_ALLOC_SIZE); if(NULL == m_hPhoneBookEntry) goto InitExit; // LOCK m_rgPhoneBookEntry = (PACCESSENTRY)GlobalLock(m_hPhoneBookEntry); if(NULL == m_rgPhoneBookEntry) goto InitExit; #endif dwSizeAllocated = 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) { goto InitExit; } hr = ERROR_NOT_ENOUGH_MEMORY; // Check to see if this is the first phone number for a given country if (pCurAccessEntry->dwCountryID != dwLastCountry) { LPIDLOOKUPELEMENT lpIDLookupElement; // NOTE: Not sure about the first parameter here. lpIDLookupElement = (LPIDLOOKUPELEMENT)bsearch(&pCurAccessEntry->dwCountryID, m_rgIDLookUp,(int)m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT), CompareIDLookUpElements); if (!lpIDLookupElement) { // bad country ID, but we can't assert here Dprintf("Bad country ID in phone book %d\n",pCurAccessEntry->dwCountryID); continue; } else { // for a given country ID this is the first phone number lpIDLookupElement->pFirstAE = pCurAccessEntry; dwLastCountry = pCurAccessEntry->dwCountryID; } } // Check to see if this is the first phone number for a given state if (pCurAccessEntry->wStateID && (pCurAccessEntry->wStateID != dwLastState)) { idx = pCurAccessEntry->wStateID - 1; m_rgState[idx].dwCountryID = pCurAccessEntry->dwCountryID; m_rgState[idx].paeFirst = pCurAccessEntry; dwLastState = pCurAccessEntry->wStateID; } pCurAccessEntry++; m_cPhoneBookEntries++; } while (TRUE); // Trim the phone book for unused memory Assert(m_rgPhoneBookEntry && m_cPhoneBookEntries); pAETemp = m_rgPhoneBookEntry; #ifdef WIN16 pTemp = GlobalReAlloc(m_rgPhoneBookEntry,(int)(m_cPhoneBookEntries * sizeof(ACCESSENTRY)),GHND); if (pTemp == NULL) goto InitExit; else m_rgPhoneBookEntry = (PACCESSENTRY)pTemp; #else // UNLOCK Assert(m_hPhoneBookEntry); if (FALSE != GlobalUnlock(m_hPhoneBookEntry)) { if (NO_ERROR != GetLastError()) goto InitExit; } // REALLOC pTemp = GlobalReAlloc(m_hPhoneBookEntry,(int)(m_cPhoneBookEntries * sizeof(ACCESSENTRY)),GHND); if (NULL == pTemp) goto InitExit; else m_hPhoneBookEntry = pTemp; // LOCK m_rgPhoneBookEntry = (PACCESSENTRY)GlobalLock(m_hPhoneBookEntry); if (NULL == m_rgPhoneBookEntry) goto InitExit; #endif FixUpFromRealloc(pAETemp, m_rgPhoneBookEntry); hr = ERROR_SUCCESS; InitExit: // If something failed release everything if (hr != ERROR_SUCCESS) { #ifdef WIN16 GlobalFree(m_rgPhoneBookEntry); #else GlobalUnlock(m_hPhoneBookEntry); GlobalFree(m_hPhoneBookEntry); #endif GlobalFree(m_pLineCountryList); GlobalFree(m_rgIDLookUp); GlobalFree(m_rgNameLookUp); GlobalFree(m_rgState); m_cPhoneBookEntries = 0 ; m_cStates = 0; m_pLineCountryList = NULL; m_rgPhoneBookEntry = NULL; m_hPhoneBookEntry = NULL; m_rgIDLookUp=NULL; m_rgNameLookUp=NULL; m_rgState=NULL; } if (pcCSVFile) { pcCSVFile->Close(); delete pcCSVFile; } return hr; } // ############################################################################ HRESULT CPhoneBook::Merge(LPCSTR pszChangeFile) { CCSVFile far *pcCSVFile; ACCESSENTRY aeChange; LPIDXLOOKUPELEMENT rgIdxLookUp; LPIDXLOOKUPELEMENT pCurIdxLookUp; DWORD dwAllocated; DWORD dwUsed; DWORD dwOriginalSize; HRESULT hr = ERROR_NOT_ENOUGH_MEMORY; DWORD dwIdx; #if !defined(WIN16) HANDLE hTemp; HANDLE hIdxLookUp; #else // Normandy 11746 LPVOID rgTemp; // 16-bit only #endif DWORD cch, cchWritten; HANDLE hFile; // Pad the phonebook for new entries. dwAllocated = m_cPhoneBookEntries + CHANGE_BUFFER_SIZE; #ifdef WIN16 Assert(m_rgPhoneBookEntry); rgTemp = GlobalReAlloc(m_rgPhoneBookEntry, (int)(sizeof(ACCESSENTRY) * dwAllocated),GHND); Assert(rgTemp); if (!rgTemp) goto MergeExit; m_rgPhoneBookEntry = (PACCESSENTRY)rgTemp; #else Assert(m_hPhoneBookEntry); GlobalUnlock(m_hPhoneBookEntry); hTemp = (HANDLE)GlobalReAlloc(m_hPhoneBookEntry, sizeof(ACCESSENTRY) * dwAllocated,GHND); Assert(hTemp); if (!hTemp) goto MergeExit; m_rgPhoneBookEntry = (PACCESSENTRY)GlobalLock(m_hPhoneBookEntry); if (!m_rgPhoneBookEntry) goto MergeExit; #endif // Create index to loaded phone book, sorted by index #ifdef WIN16 rgIdxLookUp = (LPIDXLOOKUPELEMENT)GlobalAlloc(GHND,(int)(sizeof(IDXLOOKUPELEMENT) * dwAllocated)); #else hIdxLookUp = (HANDLE)GlobalAlloc(GHND,sizeof(IDXLOOKUPELEMENT) * dwAllocated); rgIdxLookUp = (LPIDXLOOKUPELEMENT)GlobalLock(hIdxLookUp); #endif Assert(rgIdxLookUp); if (!rgIdxLookUp) goto MergeExit; for (dwIdx = 0; dwIdx < m_cPhoneBookEntries; dwIdx++) { rgIdxLookUp[dwIdx].dwIndex = rgIdxLookUp[dwIdx].pAE->dwIndex; rgIdxLookUp[dwIdx].pAE = &m_rgPhoneBookEntry[dwIdx]; } dwUsed = m_cPhoneBookEntries; dwOriginalSize = m_cPhoneBookEntries; qsort(rgIdxLookUp,(int)dwOriginalSize,sizeof(IDXLOOKUPELEMENT),CompareIdxLookUpElements); // Load changes to phone book pcCSVFile = new CCSVFile; Assert(pcCSVFile); if (!pcCSVFile) goto MergeExit; if (!pcCSVFile->Open(pszChangeFile)) 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; // Determine if this is a delete or add record if (aeChange.szAccessNumber[0] == '0' && aeChange.szAccessNumber[1] == '\0') { // This is a delete record, find matching record // NOTE: we only search the numbers that existed before the change file, // because they are the only ones that are sorted. pCurIdxLookUp = (LPIDXLOOKUPELEMENT)bsearch(&aeChange,rgIdxLookUp,(int)dwOriginalSize, sizeof(IDXLOOKUPELEMENT),CompareIdxLookUpElements); AssertSz(pCurIdxLookUp,"Attempting to delete a record that does not exist. The change file and phone book versions do not match."); if (pCurIdxLookUp) pCurIdxLookUp->pAE = NULL; //Create a dead entry in the look up table m_cPhoneBookEntries--; } else { // This is an add entry m_cPhoneBookEntries++; dwUsed++; // Make sure we have enough room if (m_cPhoneBookEntries > dwAllocated) { // Grow phone book dwAllocated += CHANGE_BUFFER_SIZE; #ifdef WIN16 Assert(m_rgPhoneBookEntry); rgTemp = GlobalReAlloc(m_rgPhoneBookEntry,(int)(sizeof(ACCESSENTRY)*dwAllocated),GHND); Assert(rgTemp); if (!rgTemp) goto MergeExit; m_rgPhoneBookEntry = (PACCESSENTRY)rgTemp; // Grow look up index Assert(rgIdxLookUp); rgTemp = GlobalReAlloc(rgIdxLookUp,(int)(sizeof(IDXLOOKUPELEMENT)*dwAllocated),GHND); Assert(rgTemp); if (!rgTemp) goto MergeExit; rgIdxLookUp = (LPIDXLOOKUPELEMENT)rgTemp; #else Assert(m_hPhoneBookEntry); GlobalUnlock(m_hPhoneBookEntry); hTemp = (HANDLE)GlobalReAlloc(m_hPhoneBookEntry,sizeof(ACCESSENTRY)*dwAllocated,GHND); Assert(hTemp); if (!hTemp) goto MergeExit; m_hPhoneBookEntry = hTemp; m_rgPhoneBookEntry = (PACCESSENTRY)GlobalLock(m_hPhoneBookEntry); Assert(m_rgPhoneBookEntry); if (!m_rgPhoneBookEntry) goto MergeExit; // Grow look up index Assert(hIdxLookUp); GlobalUnlock(hIdxLookUp); hTemp = (HANDLE)GlobalReAlloc(hIdxLookUp,sizeof(IDXLOOKUPELEMENT)*dwAllocated,GHND); Assert(hTemp); if (!hTemp) goto MergeExit; hIdxLookUp = hTemp; rgIdxLookUp = (LPIDXLOOKUPELEMENT)GlobalLock(hIdxLookUp); Assert(rgIdxLookUp); if (!rgIdxLookUp) goto MergeExit; #endif } //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].dwIndex = m_rgPhoneBookEntry[m_cPhoneBookEntries].dwIndex; rgIdxLookUp[m_cPhoneBookEntries].pAE = &m_rgPhoneBookEntry[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); // resort the IDXLookUp index to reflect the correct order of enteries // for the phonebook file, including all of the entries to be deleted. qsort(rgIdxLookUp,(int)dwUsed,sizeof(IDXLOOKUPELEMENT),CompareIdxLookUpElementsFileOrder); // Build a new phonebook file #ifdef WIN16 GetTempFileName(0, TEMP_PHONE_BOOK_PREFIX, 0, szTempFileName); #else if (!GetTempPath(TEMP_BUFFER_LENGTH,szTempBuffer)) goto MergeExit; if (!GetTempFileName(szTempBuffer,TEMP_PHONE_BOOK_PREFIX,0,szTempFileName)) goto MergeExit; #endif hFile = CreateFile(szTempFileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,0); if (hFile == INVALID_HANDLE_VALUE) goto MergeExit; for (dwIdx = 0; dwIdx < m_cPhoneBookEntries; dwIdx++) { cch = wsprintf(szTempBuffer, "%lu,%lu,%lu,%s,%s,%s,%lu,%lu,%lu,%lu,%s\r\n", rgIdxLookUp[dwIdx].pAE->dwIndex, rgIdxLookUp[dwIdx].pAE->dwCountryID, DWORD(rgIdxLookUp[dwIdx].pAE->wStateID), rgIdxLookUp[dwIdx].pAE->szCity, rgIdxLookUp[dwIdx].pAE->szAreaCode, rgIdxLookUp[dwIdx].pAE->szAccessNumber, rgIdxLookUp[dwIdx].pAE->dwConnectSpeedMin, rgIdxLookUp[dwIdx].pAE->dwConnectSpeedMax, DWORD(rgIdxLookUp[dwIdx].pAE->bFlipFactor), DWORD(rgIdxLookUp[dwIdx].pAE->fType), rgIdxLookUp[dwIdx].pAE->szDataCenter); if (!WriteFile(hFile,szTempBuffer,cch,&cchWritten,NULL)) { // something went wrong, get rid of the temporary file CloseHandle(hFile); DeleteFile(szTempFileName); hr = GetLastError(); goto MergeExit; } Assert(cch == cchWritten); } CloseHandle(hFile); hFile = NULL; // Move new phone book over old if (!MoveFileEx(szTempFileName,m_szPhoneBook,MOVEFILE_REPLACE_EXISTING)) { hr = GetLastError(); goto MergeExit; } // discard the phonebook in memory #ifndef WIN16 Assert(m_hPhoneBookEntry); GlobalUnlock(m_hPhoneBookEntry); #endif m_rgPhoneBookEntry = NULL; m_cPhoneBookEntries = 0; GlobalFree(m_pLineCountryList); GlobalFree(m_rgIDLookUp); GlobalFree(m_rgNameLookUp); GlobalFree(m_rgState); m_cStates = 0; lstrcpy(szTempBuffer,m_szINFCode); m_szINFFile[0] = '\0'; m_szPhoneBook[0] = '\0'; m_szINFCode[0] = '\0'; // Reload it (and rebuild look up arrays) hr = Init(szTempBuffer); MergeExit: if (hr != ERROR_SUCCESS) { GlobalFree(rgIdxLookUp); if (pcCSVFile) delete pcCSVFile; CloseHandle(hFile); } return hr; } // ############################################################################ HRESULT CPhoneBook::ReadOneLine(PACCESSENTRY lpAccessEntry, CCSVFile far *pcCSVFile) { HRESULT hr = ERROR_SUCCESS; #if !defined(WIN16) ReadOneLineStart: #endif //WIN16 if (!ReadPhoneBookDW(&lpAccessEntry->dwIndex,pcCSVFile)) { hr = ERROR_NO_MORE_ITEMS; // no more enteries goto ReadExit; } ReadVerifyPhoneBookDW(lpAccessEntry->dwCountryID); ReadVerifyPhoneBookW(lpAccessEntry->wStateID); ReadVerifyPhoneBookSZ(lpAccessEntry->szCity,cbCity); ReadVerifyPhoneBookSZ(lpAccessEntry->szAreaCode,cbAreaCode); // NOTE: 0 is a valid area code and ,, is a valid entry for an area code if (!FSz2Dw(lpAccessEntry->szAreaCode,&lpAccessEntry->dwAreaCode)) lpAccessEntry->dwAreaCode = NO_AREA_CODE; ReadVerifyPhoneBookSZ(lpAccessEntry->szAccessNumber,cbAccessNumber); ReadVerifyPhoneBookDW(lpAccessEntry->dwConnectSpeedMin); ReadVerifyPhoneBookDW(lpAccessEntry->dwConnectSpeedMax); ReadVerifyPhoneBookB(lpAccessEntry->bFlipFactor); ReadVerifyPhoneBookDW(lpAccessEntry->fType); ReadVerifyPhoneBookSZ(lpAccessEntry->szDataCenter,cbDataCenter); #if !defined(WIN16) // // If scripting is not available and the phonebook entry has a dun file other than // icwip.dun, then ignore the entry and read the one after that. // if (!m_bScriptingAvailable) { if (0 != lstrcmpi(lpAccessEntry->szDataCenter,"icwip.dun")) { ZeroMemory(lpAccessEntry,sizeof(ACCESSENTRY)); goto ReadOneLineStart; } } #endif //WIN16 ReadExit: return hr; ReadError: hr = ERROR_INVALID_DATA; goto ReadExit; } // ############################################################################ HRESULT CPhoneBook::Suggest(PSUGGESTINFO pSuggest) { WORD wNumFound = 0; HRESULT hr = ERROR_NOT_ENOUGH_MEMORY; // Validate parameters Assert(pSuggest); Assert(pSuggest->wNumber); if (wNumFound == pSuggest->wNumber) goto SuggestExit; LPIDLOOKUPELEMENT pCurLookUp; PACCESSENTRY lpAccessEntry; //REVIEW: double check this pCurLookUp = (LPIDLOOKUPELEMENT)bsearch(&pSuggest->dwCountryID,m_rgIDLookUp, (int)m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT), CompareIDLookUpElements); // Check for invalid country if (!pCurLookUp) goto SuggestExit; // Check if there are any phone numbers for this country if (!pCurLookUp->pFirstAE) goto SuggestExit; lpAccessEntry = pCurLookUp->pFirstAE; do { // check for the right area code if (lpAccessEntry->dwAreaCode == pSuggest->wAreaCode) { // check for the right type of number if ((lpAccessEntry->fType & pSuggest->bMask) == pSuggest->fType) { pSuggest->rgpAccessEntry[wNumFound] = lpAccessEntry; wNumFound++; } } lpAccessEntry++; } while ((lpAccessEntry <= &m_rgPhoneBookEntry[m_cPhoneBookEntries-1]) && (wNumFound < pSuggest->wNumber) && (lpAccessEntry->dwCountryID == pSuggest->dwCountryID)); // if we couldn't find enough numnbers, try something else // 10/15/96 jmazner ported fixes below from core\client\phbk // Do this only if area code is not 0 - Bug #9349 (VetriV) // if ((pSuggest->wAreaCode != 0) && (wNumFound < pSuggest->wNumber)) // No, there are some places (Finland? ChrisK knows) where 0 is a legit area code -- jmazner if (wNumFound < pSuggest->wNumber) { lpAccessEntry = pCurLookUp->pFirstAE; // Note: we are now only looking for Nationwide phone numbers (state = 0) // 8/13/96 jmazner MOS Normandy #4597 // We want nationwide toll-free numbers to display last, so for this pass, // only consider numbers that are _not_ toll free (fType bit #1 = 0) // Tweak pSuggest->bMask to let through the toll/charge bit pSuggest->bMask |= MASK_TOLLFREE_BIT; // Tweak pSuggest->ftype to be charge pSuggest->fType &= TYPE_SET_TOLL; do { // 8/13/96 jmazner MOS Normandy #4598 // If this entry's area code matches pSuggest->wAreaCode, then we already // have included it in the previous pass, so don't duplicate it again here. if ((lpAccessEntry->fType & pSuggest->bMask) == pSuggest->fType && lpAccessEntry->wStateID == 0 && lpAccessEntry->dwAreaCode != pSuggest->wAreaCode) { pSuggest->rgpAccessEntry[wNumFound] = lpAccessEntry; wNumFound++; } lpAccessEntry++; } while ((lpAccessEntry <= &m_rgPhoneBookEntry[m_cPhoneBookEntries-1]) && (wNumFound < pSuggest->wNumber) && (lpAccessEntry->dwCountryID == pSuggest->dwCountryID) && (lpAccessEntry->wStateID == 0) ); } // 8/13/96 jmazner MOS Normandy #4597 // if we STILL couldn't find enough numnbers, widen the search to include tollfree #s if (wNumFound < pSuggest->wNumber) { lpAccessEntry = pCurLookUp->pFirstAE; // Tweak pSuggest->bMask to let through the toll/charge bit // REDUNDANT? If we made it to this point, we _should_ have done this above... // Better safe than sorry! Assert(pSuggest->bMask & MASK_TOLLFREE_BIT); pSuggest->bMask |= MASK_TOLLFREE_BIT; // Tweak pSuggest->ftype to be tollfree pSuggest->fType |= TYPE_SET_TOLLFREE; do { // 8/13/96 jmazner MOS Normandy #4598 // If this entry's area code matches pSuggest->wAreaCode, then we already // have included it in the first pass, so don't include it here. // Any entry that made it in in the 2nd pass will definitely not make it in here // (because of tollfree bit), so no need to worry about dups from there. if ((lpAccessEntry->fType & pSuggest->bMask) == pSuggest->fType && lpAccessEntry->wStateID == 0 && lpAccessEntry->dwAreaCode != pSuggest->wAreaCode) { pSuggest->rgpAccessEntry[wNumFound] = lpAccessEntry; wNumFound++; } lpAccessEntry++; } while ((lpAccessEntry <= &m_rgPhoneBookEntry[m_cPhoneBookEntries-1]) && (wNumFound < pSuggest->wNumber) && (lpAccessEntry->dwCountryID == pSuggest->dwCountryID) && (lpAccessEntry->wStateID == 0) ); } hr = ERROR_SUCCESS; SuggestExit: pSuggest->wNumber = wNumFound; return hr; } // ############################################################################ HRESULT CPhoneBook::GetCanonical (PACCESSENTRY pAE, LPSTR psOut) { HRESULT hr = ERROR_SUCCESS; LPIDLOOKUPELEMENT pIDLookUp; pIDLookUp = (LPIDLOOKUPELEMENT)bsearch(&pAE->dwCountryID,m_rgIDLookUp, (int)m_pLineCountryList->dwNumCountries,sizeof(IDLOOKUPELEMENT),CompareIdxLookUpElements); if (!pIDLookUp) { hr = ERROR_INVALID_PARAMETER; } else { SzCanonicalFromAE (psOut, pAE, pIDLookUp->pLCE); } return hr; } // ############################################################################ DllExportH PhoneBookLoad(LPCSTR pszISPCode, DWORD_PTR far *pdwPhoneID) { HRESULT hr = ERROR_NOT_ENOUGH_MEMORY; CPhoneBook far *pcPhoneBook; if (!g_hInstDll) g_hInstDll = GetModuleHandle(NULL); // validate parameters Assert(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; } else { *pdwPhoneID = (DWORD_PTR)pcPhoneBook; } #if defined(WIN16) if (!hr) BMP_RegisterClass(g_hInstDll); #endif return hr; } // ############################################################################ DllExportH PhoneBookUnload(DWORD_PTR dwPhoneID) { Assert(dwPhoneID); if (dwPhoneID) { #if defined(WIN16) BMP_DestroyClass(g_hInstDll); #endif // Release contents delete (CPhoneBook far*)dwPhoneID; } return ERROR_SUCCESS; } // ############################################################################ DllExportH PhoneBookMergeChanges(DWORD_PTR dwPhoneID, LPCSTR pszChangeFile) { return ((CPhoneBook far*)dwPhoneID)->Merge(pszChangeFile); } // ############################################################################ DllExportH PhoneBookSuggestNumbers(DWORD_PTR dwPhoneID, PSUGGESTINFO lpSuggestInfo) { HRESULT hr = ERROR_NOT_ENOUGH_MEMORY; // get suggested numbers lpSuggestInfo->rgpAccessEntry = (PACCESSENTRY *)GlobalAlloc(GPTR,sizeof(PACCESSENTRY) * lpSuggestInfo->wNumber); if (lpSuggestInfo->rgpAccessEntry) { hr = ((CPhoneBook far *)dwPhoneID)->Suggest(lpSuggestInfo); } return hr; } // ############################################################################ DllExportH PhoneBookGetCanonical (DWORD_PTR dwPhoneID, PACCESSENTRY pAE, LPSTR psOut) { return ((CPhoneBook far*)dwPhoneID)->GetCanonical(pAE,psOut); } // ############################################################################ DllExportH PhoneBookDisplaySignUpNumbers (DWORD_PTR dwPhoneID, LPSTR far *ppszPhoneNumbers, LPSTR far *ppszDunFiles, WORD far *pwPhoneNumbers, DWORD far *pdwCountry, WORD far *pwRegion, BYTE fType, BYTE bMask, HWND hwndParent, DWORD dwFlags) { INT_PTR hr; AssertSz(ppszPhoneNumbers && pwPhoneNumbers && pdwCountry &&pwRegion,"invalid parameters"); //CAccessNumDlg *pcDlg; CSelectNumDlg far *pcDlg; pcDlg = new CSelectNumDlg; if (!pcDlg) { hr = GetLastError(); goto DisplayExit; } // Initialize information for dialog // pcDlg->m_dwPhoneBook = dwPhoneID; pcDlg->m_dwCountryID = *pdwCountry; pcDlg->m_wRegion = *pwRegion; pcDlg->m_fType = fType; pcDlg->m_bMask = bMask; pcDlg->m_dwFlags = dwFlags; // invoke the dialog // // BUG: NOT THREAD SAFE!! g_hWndMain = hwndParent; hr = DialogBoxParam(g_hInstDll,MAKEINTRESOURCE(IDD_SELECTNUMBER), g_hWndMain,PhbkGenericDlgProc,(LPARAM)pcDlg); g_hWndMain = NULL; if (hr == IDC_CMDNEXT) { *pwRegion = pcDlg->m_wRegion; *pdwCountry = pcDlg->m_dwCountryID; Assert (ppszPhoneNumbers[0] && ppszDunFiles[0]); lstrcpy(ppszPhoneNumbers[0],&pcDlg->m_szPhoneNumber[0]); lstrcpy(ppszDunFiles[0],&pcDlg->m_szDunFile[0]); hr = ERROR_SUCCESS; } else if (hr == IDC_CMDBACK) hr = ERROR_USERBACK; else hr = ERROR_USERCANCEL; // hr == -1; DisplayExit: if (pcDlg) delete pcDlg; return (HRESULT) hr; }