// File: history.cpp #include "precomp.h" #include "resource.h" #include "dirutil.h" #include "upropdlg.h" #include "history.h" // CCallLogEntry flags: const DWORD CLEF_ACCEPTED = 0x00000001; const DWORD CLEF_REJECTED = 0x00000002; const DWORD CLEF_AUTO_ACCEPTED = 0x00000004; // call was auto-accepted const DWORD CLEF_TIMED_OUT = 0x00000008; // call was rejected due to timeout const DWORD CLEF_SECURE = 0x00000010; // call was secure const DWORD CLEF_NO_CALL = 0x40000000; // No call back information const DWORD CLEF_DELETED = 0x80000000; // Record marked for deletion const WCHAR g_cszwULS[] = L"ULS:"; static const int _rgIdMenu[] = { IDM_DLGCALL_DELETE, 0 }; /* C H I S T O R Y */ /*------------------------------------------------------------------------- %%Function: CHISTORY -------------------------------------------------------------------------*/ CHISTORY::CHISTORY() : CALV(IDS_DLGCALL_HISTORY, II_HISTORY, _rgIdMenu) { DbgMsg(iZONE_OBJECTS, "CHISTORY - Constructed(%08X)", this); RegEntry re(LOG_INCOMING_KEY, HKEY_CURRENT_USER); m_pszFile = PszAlloc(re.GetString(REGVAL_LOG_FILE)); // Make sure file exists and can be read/written m_hFile = OpenLogFile(); SetAvailable(NULL != m_hFile); } CHISTORY::~CHISTORY() { if (NULL != m_hFile) { CloseHandle(m_hFile); } delete m_pszFile; DbgMsg(iZONE_OBJECTS, "CHISTORY - Destroyed(%08X)", this); } int CHISTORY::Compare ( LPARAM param1, LPARAM param2 ) { int ret = 0; LPTSTR pszName1, pszAddress1; LPTSTR pszName2, pszAddress2; LOGHDR logHdr1, logHdr2; if (SUCCEEDED(ReadEntry((DWORD)param1, &logHdr1, &pszName1, &pszAddress1))) { if (SUCCEEDED(ReadEntry((DWORD)param2, &logHdr2, &pszName2, &pszAddress2))) { FILETIME ft1, ft2; SystemTimeToFileTime(&logHdr1.sysTime, &ft1); SystemTimeToFileTime(&logHdr2.sysTime, &ft2); // Sort in reverse order so most recent is at the top ret = -CompareFileTime(&ft1, &ft2); delete pszName2; delete pszAddress2; } delete pszName1; delete pszAddress1; } return(ret); } int CALLBACK CHISTORY::StaticCompare ( LPARAM param1, LPARAM param2, LPARAM pThis ) { return(reinterpret_cast(pThis)->Compare(param1, param2)); } /////////////////////////////////////////////////////////////////////////// // CALV methods /* S H O W I T E M S */ /*------------------------------------------------------------------------- %%Function: ShowItems -------------------------------------------------------------------------*/ VOID CHISTORY::ShowItems(HWND hwnd) { CALV::SetHeader(hwnd, IDS_ADDRESS); TCHAR szReceived[CCHMAXSZ]; if( FLoadString(IDS_RECEIVED, szReceived, CCHMAX(szReceived)) ) { LV_COLUMN lvc; ClearStruct(&lvc); lvc.mask = LVCF_TEXT | LVCF_SUBITEM; lvc.pszText = szReceived; lvc.iSubItem = IDI_MISC1; ListView_InsertColumn(hwnd, IDI_MISC1, &lvc); } if (!FAvailable()) return; LoadFileData(hwnd); ListView_SortItems( hwnd, StaticCompare, (LPARAM) this ); } VOID CHISTORY::ClearItems(void) { CALV::ClearItems(); HWND hWndListView = GetHwnd(); if( IsWindow(hWndListView) ) { ListView_DeleteColumn(hWndListView, IDI_MISC1); } } VOID CHISTORY::OnCommand(WPARAM wParam, LPARAM lParam) { switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDM_DLGCALL_DELETE: CmdDelete(); break; case IDM_DLGCALL_PROPERTIES: CmdProperties(); break; default: CALV::OnCommand(wParam, lParam); break; } } VOID CHISTORY::CmdDelete(void) { int iItem = GetSelection(); if (-1 == iItem) return; LPARAM lParam = LParamFromItem(iItem); if (SUCCEEDED(DeleteEntry((DWORD)lParam))) { DeleteItem(iItem); } } UINT CHISTORY::GetStatusString(DWORD dwCLEF) { if (CLEF_ACCEPTED & dwCLEF) return IDS_HISTORY_ACCEPTED; if (CLEF_TIMED_OUT & dwCLEF) return IDS_HISTORY_NOT_ANSWERED; ASSERT(CLEF_REJECTED & dwCLEF); return IDS_HISTORY_IGNORED; } VOID CHISTORY::CmdProperties(void) { int iItem = GetSelection(); if (-1 == iItem) return; LPTSTR pszName; LPTSTR pszAddress; TCHAR szStatus[CCHMAXSZ]; TCHAR szTime[CCHMAXSZ]; LOGHDR logHdr; PBYTE pbCert = NULL; PCCERT_CONTEXT pCert = NULL; LPARAM lParam = LParamFromItem(iItem); if (SUCCEEDED(ReadEntry((DWORD)lParam, &logHdr, &pszName, &pszAddress))) { if (logHdr.dwCLEF & CLEF_SECURE) // is secure call { ASSERT(logHdr.cbCert); pbCert = new BYTE[logHdr.cbCert]; if (FSetFilePos(lParam+sizeof(logHdr)+logHdr.cbName+logHdr.cbData)) { if (FReadData(pbCert, logHdr.cbCert)) { pCert = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, logHdr.cbCert); if (NULL == pCert) { WARNING_OUT(("Certificate in Call Log is damaged.")); } } } delete []pbCert; } FLoadString(GetStatusString(logHdr.dwCLEF), szStatus, CCHMAX(szStatus)); FmtDateTime(&logHdr.sysTime, szTime, CCHMAX(szTime)); if (NULL == pszAddress) { pszAddress = PszLoadString(IDS_HISTORY_NO_ADDRESS); } UPROPDLGENTRY rgProp[] = { {IDS_UPROP_ADDRESS, pszAddress}, {IDS_UPROP_STATUS, szStatus}, {IDS_UPROP_RECEIVED, szTime}, }; CUserPropertiesDlg dlgUserProp(GetHwnd(), IDI_LARGE); dlgUserProp.DoModal(rgProp, ARRAY_ELEMENTS(rgProp), pszName, pCert); } if ( pCert ) CertFreeCertificateContext ( pCert ); delete pszName; delete pszAddress; } /////////////////////////////////////////////////////////////////////////// /* O P E N L O G F I L E */ /*------------------------------------------------------------------------- %%Function: OpenLogFile Open the log file and return a handle to file. Return NULL if there was a problem. -------------------------------------------------------------------------*/ HANDLE CHISTORY::OpenLogFile(VOID) { HANDLE hFile = CreateFile(m_pszFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { ERROR_OUT(("OpenLogFile: Unable to open call log file")); hFile = NULL; } return hFile; } BOOL CHISTORY::FSetFilePos(DWORD dwOffset) { ASSERT(NULL != m_hFile); return (INVALID_FILE_SIZE != SetFilePointer(m_hFile, dwOffset, NULL, FILE_BEGIN)); } /* L O A D F I L E D A T A */ /*------------------------------------------------------------------------- %%Function: LoadFileData Load the call log data from the file -------------------------------------------------------------------------*/ VOID CHISTORY::LoadFileData(HWND hwnd) { HANDLE hFile = OpenLogFile(); if (NULL == hFile) return; LPTSTR pszName, pszAddress; LOGHDR logHdr; DWORD dwOffset = 0; HRESULT hr = S_OK; while (SUCCEEDED(hr)) { hr = ReadEntry(dwOffset, &logHdr, &pszName, &pszAddress); if (S_OK == hr) { TCHAR szTime[CCHMAXSZ]; FmtDateTime(&logHdr.sysTime, szTime, CCHMAX(szTime)); DlgCallAddItem(hwnd, pszName, pszAddress, II_COMPUTER, dwOffset, 0, szTime); } dwOffset += logHdr.dwSize; delete pszName; pszName = NULL; delete pszAddress; pszAddress = NULL; } CloseHandle(hFile); } /* R E A D E N T R Y */ /*------------------------------------------------------------------------- %%Function: ReadEntry Read the next entry from the file. Return Values: S_OK - data was read successfully S_FALSE - data exists, but was deleted E_FAIL - problem reading file -------------------------------------------------------------------------*/ HRESULT CHISTORY::ReadEntry(DWORD dwOffset, LOGHDR * pLogHdr, LPTSTR * ppszName, LPTSTR * ppszAddress) { ASSERT(NULL != m_hFile); *ppszName = NULL; *ppszAddress = NULL; if (!FSetFilePos(dwOffset)) return E_FAIL; // Read record header if (!FReadData(pLogHdr, sizeof(LOGHDR)) ) return E_FAIL; // Read Name WCHAR szwName[CCHMAXSZ_NAME]; if (!FReadData(szwName, min(pLogHdr->cbName, sizeof(szwName)))) return E_FAIL; *ppszName = PszFromBstr(szwName); if (FReadData(szwName, min(pLogHdr->cbData, sizeof(szwName)))) { LPCWSTR pchw = _StrStrW(szwName, g_cszwULS); if (NULL != pchw) { pchw += CCHMAX(g_cszwULS)-1; // -1 for NULL *ppszAddress = PszFromBstr(pchw); } } return (0 == (pLogHdr->dwCLEF & CLEF_DELETED)) ? S_OK : S_FALSE; } /* R E A D D A T A */ /*------------------------------------------------------------------------- %%Function: FReadData -------------------------------------------------------------------------*/ BOOL CHISTORY::FReadData(PVOID pv, UINT cb) { DWORD cbRead; ASSERT(NULL != m_hFile); ASSERT(NULL != pv); if (0 == cb) return TRUE; if (!ReadFile(m_hFile, pv, cb, &cbRead, NULL)) return FALSE; return (cb == cbRead); } /* D E L E T E E N T R Y */ /*------------------------------------------------------------------------- %%Function: DeleteEntry Delete a single entry. -------------------------------------------------------------------------*/ HRESULT CHISTORY::DeleteEntry(DWORD dwOffset) { // Calculate offset to "CLEF" dwOffset += FIELD_OFFSET(LOGHDR,dwCLEF); if (!FSetFilePos(dwOffset)) return E_FAIL; DWORD dwFlags; if (!FReadData(&dwFlags, sizeof(dwFlags))) return E_FAIL; dwFlags = dwFlags | CLEF_DELETED; if (!FSetFilePos(dwOffset)) return E_FAIL; return WriteData(&dwOffset, &dwFlags, sizeof(dwFlags)); } /* W R I T E D A T A */ /*------------------------------------------------------------------------- %%Function: WriteData Write the data to the file. The file will be automatically opened/close if hFile is NULL. -------------------------------------------------------------------------*/ HRESULT CHISTORY::WriteData(LPDWORD pdwOffset, PVOID pv, DWORD cb) { ASSERT(NULL != m_hFile); ASSERT(0 != cb); ASSERT(NULL != pv); ASSERT(NULL != pdwOffset); ASSERT(INVALID_FILE_SIZE != *pdwOffset); HRESULT hr = E_FAIL; if (FSetFilePos(*pdwOffset)) { DWORD cbWritten; if (WriteFile(m_hFile, pv, cb, &cbWritten, NULL) && (cb == cbWritten)) { *pdwOffset += cbWritten; hr = S_OK; } } return hr; }