/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-2009 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "..\..\core\commonheaders.h" #define SUMMARY 0 #define DETAIL 1 #define DM_FINDNEXT (WM_USER+10) #define DM_HREBUILD (WM_USER+11) static INT_PTR CALLBACK DlgProcHistory(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); static INT_PTR CALLBACK DlgProcHistoryFind(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); static HANDLE hWindowList=0; static INT_PTR UserHistoryCommand(WPARAM wParam, LPARAM) { HWND hwnd = WindowList_Find( hWindowList, ( HANDLE )wParam ); if ( hwnd ) { SetForegroundWindow(hwnd); SetFocus(hwnd); return 0; } CreateDialogParam(hMirandaInst, MAKEINTRESOURCE(IDD_HISTORY), NULL, DlgProcHistory, wParam); return 0; } static int HistoryContactDelete(WPARAM wParam, LPARAM) { HWND hwnd = WindowList_Find(hWindowList, (HANDLE)wParam); if ( hwnd != NULL ) DestroyWindow(hwnd); return 0; } int PreShutdownHistoryModule(WPARAM, LPARAM) { if (hWindowList) WindowList_BroadcastAsync(hWindowList, WM_DESTROY, 0, 0); return 0; } int LoadHistoryModule(void) { CLISTMENUITEM mi = { 0 }; mi.cbSize = sizeof(mi); mi.position = 1000090000; mi.flags = CMIF_ICONFROMICOLIB; mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_HISTORY ); mi.pszName = LPGEN("View &History"); mi.pszService = MS_HISTORY_SHOWCONTACTHISTORY; Menu_AddContactMenuItem(&mi); CreateServiceFunction(MS_HISTORY_SHOWCONTACTHISTORY, UserHistoryCommand); hWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); HookEvent(ME_DB_CONTACT_DELETED, HistoryContactDelete); HookEvent(ME_SYSTEM_PRESHUTDOWN, PreShutdownHistoryModule); return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // Fills the events list static void GetMessageDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf ) { TCHAR* msg = DbGetEventTextT( dbei, CP_ACP ); _tcsncpy( buf, msg ? msg : TranslateT("Invalid Message"), cbBuf ); buf[ cbBuf-1 ] = 0; mir_free( msg ); } static void GetUrlDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf ) { int len = dbei->cbBlob; if ( len >= cbBuf ) len = cbBuf-1; #if !defined( _UNICODE ) memcpy( buf, dbei->pBlob, len ); #else MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )dbei->pBlob, len, buf, cbBuf ); #endif buf[ len ] = 0; if ( len < cbBuf-3 ) _tcscat( buf, _T( "\r\n" )); } static void GetFileDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf ) { int len = dbei->cbBlob - sizeof( DWORD ); if ( len >= cbBuf ) len = cbBuf-1; #if !defined( _UNICODE ) memcpy( buf, dbei->pBlob + sizeof( DWORD ), len ); #else MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )dbei->pBlob + sizeof( DWORD ), len, buf, cbBuf ); #endif buf[ len ] = 0; if ( len < cbBuf-3 ) _tcscat( buf, _T( "\r\n" )); } static void GetObjectDescription( DBEVENTINFO *dbei, TCHAR* str, int cbStr ) { switch( dbei->eventType ) { case EVENTTYPE_MESSAGE: GetMessageDescription( dbei, str, cbStr ); break; case EVENTTYPE_URL: GetUrlDescription( dbei, str, cbStr ); break; case EVENTTYPE_FILE: GetFileDescription( dbei, str, cbStr ); break; default: { DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )CallService( MS_DB_EVENT_GETTYPE, ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType ); if ( et && ( et->flags & DETF_HISTORY )) { GetMessageDescription( dbei, str, cbStr ); } else str[ 0 ] = 0; } } } static void GetObjectSummary( DBEVENTINFO *dbei, TCHAR* str, int cbStr ) { TCHAR* pszSrc, *pszTmp = NULL; switch( dbei->eventType ) { case EVENTTYPE_MESSAGE: if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing Message" ); else pszSrc = TranslateT( "Incoming Message" ); break; case EVENTTYPE_URL: if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing URL" ); else pszSrc = TranslateT( "Incoming URL" ); break; case EVENTTYPE_FILE: if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing File" ); else pszSrc = TranslateT( "Incoming File" ); break; default: { DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )CallService( MS_DB_EVENT_GETTYPE, ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType ); if ( et && ( et->flags & DETF_HISTORY )) { pszTmp = mir_a2t( et->descr ); pszSrc = TranslateTS( pszTmp ); break; } else { str[ 0 ] = 0; return; } } } _tcsncpy( str, ( const TCHAR* )pszSrc, cbStr ); str[ cbStr-1 ] = 0; mir_free( pszTmp ); } typedef struct { HANDLE hContact; HWND hwnd; } THistoryThread; static void FillHistoryThread(void* param) { TCHAR str[200], eventText[256], strdatetime[64]; HANDLE hDbEvent; DBEVENTINFO dbei; int newBlobSize, oldBlobSize, i; HWND hwndList; THistoryThread *hInfo = ( THistoryThread* )param; SendDlgItemMessage(hInfo->hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0); i=CallService(MS_DB_EVENT_GETCOUNT, (WPARAM)hInfo->hContact, 0); SendDlgItemMessage(hInfo->hwnd, IDC_LIST, LB_INITSTORAGE, i, i*40); ZeroMemory(&dbei, sizeof(dbei)); dbei.cbSize=sizeof(dbei); oldBlobSize=0; hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hInfo->hContact, 0); hwndList = GetDlgItem(hInfo->hwnd, IDC_LIST); while ( hDbEvent != NULL ) { if ( !IsWindow( hInfo->hwnd )) break; newBlobSize=CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0); if (newBlobSize>oldBlobSize) { dbei.pBlob=(PBYTE)mir_realloc(dbei.pBlob, newBlobSize); oldBlobSize=newBlobSize; } dbei.cbBlob = oldBlobSize; CallService( MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei ); GetObjectSummary(&dbei, str, SIZEOF(str)); if (str[0]) { tmi.printTimeStamp(NULL, dbei.timestamp, _T("d t"), strdatetime, SIZEOF(strdatetime), 0); mir_sntprintf( eventText, SIZEOF(eventText), _T("%s: %s"), strdatetime, str ); i = SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)eventText ); SendMessage(hwndList, LB_SETITEMDATA, i, (LPARAM)hDbEvent); } hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hDbEvent, 0); } mir_free(dbei.pBlob); SendDlgItemMessage(hInfo->hwnd, IDC_LIST, LB_SETCURSEL, 0, 0); SendMessage(hInfo->hwnd, WM_COMMAND, MAKEWPARAM(IDC_LIST, LBN_SELCHANGE), 0); EnableWindow(GetDlgItem(hInfo->hwnd, IDC_LIST), TRUE); mir_free(hInfo); } static int HistoryDlgResizer(HWND, LPARAM, UTILRESIZECONTROL *urc) { switch(urc->wId) { case IDC_LIST: return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; case IDC_EDIT: return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM; case IDC_FIND: case IDC_DELETEHISTORY: return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; case IDOK: return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; } return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; } static INT_PTR CALLBACK DlgProcHistory(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { HANDLE hContact; hContact=(HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); hContact = (HANDLE)lParam; WindowList_Add(hWindowList, hwndDlg, hContact); Utils_RestoreWindowPosition(hwndDlg, hContact, "History", ""); { TCHAR* contactName, str[200]; contactName = cli.pfnGetContactDisplayName( hContact, 0 ); mir_sntprintf(str, SIZEOF(str), TranslateT("History for %s"), contactName); SetWindowText(hwndDlg, str); } Window_SetIcon_IcoLib(hwndDlg, SKINICON_OTHER_HISTORY); SendMessage(hwndDlg, DM_HREBUILD, 0, 0); return TRUE; case DM_HREBUILD: { THistoryThread* hInfo = (THistoryThread*)mir_alloc(sizeof(THistoryThread)); EnableWindow(GetDlgItem(hwndDlg, IDC_LIST), FALSE); hInfo->hContact = hContact; hInfo->hwnd = hwndDlg; forkthread(FillHistoryThread, 0, hInfo); } return TRUE; case WM_DESTROY: Window_FreeIcon_IcoLib(hwndDlg); Utils_SaveWindowPosition(hwndDlg, hContact, "History", ""); WindowList_Remove(hWindowList, hwndDlg); return TRUE; case WM_GETMINMAXINFO: ((MINMAXINFO*)lParam)->ptMinTrackSize.x=300; ((MINMAXINFO*)lParam)->ptMinTrackSize.y=230; case WM_SIZE: { UTILRESIZEDIALOG urd={0}; urd.cbSize=sizeof(urd); urd.hwndDlg=hwndDlg; urd.hInstance=hMirandaInst; urd.lpTemplate=MAKEINTRESOURCEA(IDD_HISTORY); urd.lParam=(LPARAM)NULL; urd.pfnResizer=HistoryDlgResizer; CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); return TRUE; } case WM_COMMAND: switch ( LOWORD( wParam )) { case IDOK: case IDCANCEL: DestroyWindow(hwndDlg); return TRUE; case IDC_FIND: ShowWindow(CreateDialogParam(hMirandaInst, MAKEINTRESOURCE(IDD_HISTORY_FIND), hwndDlg, DlgProcHistoryFind, (LPARAM)hwndDlg), SW_SHOW); return TRUE; case IDC_DELETEHISTORY: { HANDLE hDbevent; int index = SendDlgItemMessage(hwndDlg, IDC_LIST, LB_GETCURSEL, 0, 0); if ( index == LB_ERR ) break; if ( MessageBox(hwndDlg, TranslateT("Are you sure you want to delete this history item?"), TranslateT("Delete History"), MB_YESNO|MB_ICONQUESTION) == IDYES) { hDbevent = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, LB_GETITEMDATA, index, 0); CallService(MS_DB_EVENT_DELETE, (WPARAM)hContact, (LPARAM)hDbevent); SendMessage(hwndDlg, DM_HREBUILD, 0, 0); } return TRUE; } case IDC_LIST: if ( HIWORD(wParam) == LBN_SELCHANGE ) { TCHAR str[8192], *contactName; HANDLE hDbEvent; DBEVENTINFO dbei; int sel; sel=SendDlgItemMessage(hwndDlg, IDC_LIST, LB_GETCURSEL, 0, 0); if (sel == LB_ERR) { EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEHISTORY), FALSE); break; } EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEHISTORY), TRUE); contactName = cli.pfnGetContactDisplayName( hContact, 0 ); hDbEvent=(HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, LB_GETITEMDATA, sel, 0); ZeroMemory(&dbei, sizeof(dbei)); dbei.cbSize=sizeof(dbei); dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0); if ((int)dbei.cbBlob != -1) { dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob); if (CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei) == 0) { GetObjectDescription(&dbei, str, SIZEOF(str)); if ( str[0] ) SetDlgItemText(hwndDlg, IDC_EDIT, str); } mir_free(dbei.pBlob); } } return TRUE; } break; case DM_FINDNEXT: { TCHAR str[1024]; HANDLE hDbEvent, hDbEventStart; DBEVENTINFO dbei; int newBlobSize, oldBlobSize; int index = SendDlgItemMessage(hwndDlg, IDC_LIST, LB_GETCURSEL, 0, 0); if ( index == LB_ERR ) break; hDbEventStart=(HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, LB_GETITEMDATA, index, 0); ZeroMemory(&dbei, sizeof(dbei)); dbei.cbSize=sizeof(dbei); dbei.pBlob=NULL; oldBlobSize=0; for (;;) { hDbEvent = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, LB_GETITEMDATA, ++index, 0); if (hDbEvent == ( HANDLE )LB_ERR) { index = -1; continue; } if (hDbEvent == hDbEventStart) break; newBlobSize=CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0); if (newBlobSize>oldBlobSize) { dbei.pBlob=(PBYTE)mir_realloc(dbei.pBlob, newBlobSize); oldBlobSize=newBlobSize; } dbei.cbBlob=oldBlobSize; CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei); GetObjectDescription(&dbei, str, SIZEOF(str)); if (str[0]) { CharUpperBuff(str, lstrlen(str)); if ( _tcsstr(str, (const TCHAR*)lParam) != NULL) { SendDlgItemMessage(hwndDlg, IDC_LIST, LB_SETCURSEL, index, 0); SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_LIST, LBN_SELCHANGE), 0); break; } } } mir_free(dbei.pBlob); break; } } return FALSE; } static INT_PTR CALLBACK DlgProcHistoryFind(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); return TRUE; case WM_COMMAND: switch ( LOWORD( wParam )) { case IDOK://find Next { TCHAR str[128]; HWND hwndParent = ( HWND )GetWindowLongPtr(hwndDlg, GWLP_USERDATA); GetDlgItemText(hwndDlg, IDC_FINDWHAT, str, SIZEOF(str)); CharUpperBuff(str, lstrlen(str)); SendMessage(hwndParent, DM_FINDNEXT, 0, (LPARAM)str); return TRUE; } case IDCANCEL: DestroyWindow(hwndDlg); return TRUE; } break; } return FALSE; }