From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/srmm/msgdialog.c | 2042 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2042 insertions(+) create mode 100644 plugins/srmm/msgdialog.c (limited to 'plugins/srmm/msgdialog.c') diff --git a/plugins/srmm/msgdialog.c b/plugins/srmm/msgdialog.c new file mode 100644 index 0000000000..1a90a861c6 --- /dev/null +++ b/plugins/srmm/msgdialog.c @@ -0,0 +1,2042 @@ +/* +Copyright 2000-2012 Miranda 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 "commonheaders.h" +#include "statusicon.h" + +#define TIMERID_FLASHWND 1 +#define TIMERID_TYPE 2 +#define TIMEOUT_FLASHWND 900 +#define TIMEOUT_TYPEOFF 10000 //send type off after 10 seconds of inactivity +#define SB_CHAR_WIDTH 45 +#define SB_TIME_WIDTH 60 +#define SB_GRIP_WIDTH 20 // pixels - buffer used to prevent sizegrip from overwriting statusbar icons +#define VALID_AVATAR(x) (x==PA_FORMAT_PNG||x==PA_FORMAT_JPEG||x==PA_FORMAT_ICON||x==PA_FORMAT_BMP||x==PA_FORMAT_GIF) + +extern HCURSOR hCurSplitNS, hCurSplitWE, hCurHyperlinkHand; +extern HANDLE hHookWinEvt, hHookWinPopup; +extern struct CREOleCallback reOleCallback; + +static void UpdateReadChars(HWND hwndDlg, HWND hwndStatus); + +static const UINT infoLineControls[] = { IDC_PROTOCOL, IDC_NAME }; +static const UINT buttonLineControls[] = { IDC_ADD, IDC_USERMENU, IDC_DETAILS, IDC_HISTORY }; +static const UINT sendControls[] = { IDC_MESSAGE }; + +static void NotifyLocalWinEvent(HANDLE hContact, HWND hwnd, unsigned int type) { + MessageWindowEventData mwe = { 0 }; + + if (hContact==NULL || hwnd==NULL) return; + mwe.cbSize = sizeof(mwe); + mwe.hContact = hContact; + mwe.hwndWindow = hwnd; + mwe.szModule = SRMMMOD; + mwe.uType = type; + mwe.uFlags = MSG_WINDOW_UFLAG_MSG_BOTH; + mwe.hwndInput = GetDlgItem(hwnd, IDC_MESSAGE); + mwe.hwndLog = GetDlgItem(hwnd, IDC_LOG); + NotifyEventHooks(hHookWinEvt, 0, (LPARAM)&mwe); +} + +static char *MsgServiceName(HANDLE hContact) +{ +#ifdef _UNICODE + char szServiceName[100]; + char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (szProto == NULL) + return PSS_MESSAGE; + + mir_snprintf(szServiceName, SIZEOF(szServiceName), "%s%sW", szProto, PSS_MESSAGE); + if (ServiceExists(szServiceName)) + return PSS_MESSAGE "W"; +#endif + return PSS_MESSAGE; +} + +static BOOL IsUtfSendAvailable(HANDLE hContact) +{ + char* szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if ( szProto == NULL ) + return FALSE; + + return ( CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_IMSENDUTF ) ? TRUE : FALSE; +} + +static int RTL_Detect(const TCHAR *ptszText) +{ + WORD *infoTypeC2; + int i; + int iLen = (int)_tcslen(ptszText); + + infoTypeC2 = (WORD*)alloca(sizeof(WORD) * (iLen + 2)); + GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE2, ptszText, iLen, infoTypeC2); + + for(i = 0; i < iLen; i++) { + if(infoTypeC2[i] == C2_RIGHTTOLEFT) + return 1; + } + return 0; +} + +HANDLE SendMessageDirect(const TCHAR *szMsg, HANDLE hContact, char *szProto) +{ + int flags = 0; + int bufSize = 0; + char *sendBuffer = NULL; + + if (RTL_Detect(szMsg)) flags |= PREF_RTL; + + if (IsUtfSendAvailable(hContact)) + { + flags |= PREF_UTF; + sendBuffer = mir_utf8encodeT(szMsg); + if (!sendBuffer || !sendBuffer[0]) + { + mir_free(sendBuffer); + return NULL; + } + bufSize = (int)strlen(sendBuffer) + 1; + } + else + { + flags |= PREF_TCHAR; + sendBuffer = mir_t2a(szMsg); + if (!sendBuffer || !sendBuffer[0]) + { + mir_free(sendBuffer); + return NULL; + } + bufSize = (int)strlen(sendBuffer) + 1; +#ifdef _UNICODE + { + size_t bufSizeT = (_tcslen(szMsg) + 1) * sizeof(TCHAR) ; + + sendBuffer = (char*)mir_realloc(sendBuffer, bufSizeT + bufSize); + memcpy((TCHAR*)&sendBuffer[bufSize], szMsg, bufSizeT); + bufSize += (int)bufSizeT; + } +#endif + } + + if (hContact == NULL) + { + mir_free(sendBuffer); + return NULL; + } + + if (sendBuffer) + { + HANDLE hNewEvent, hSendId; + DBEVENTINFO dbei = { 0 }; + dbei.cbSize = sizeof(dbei); + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.flags = DBEF_SENT | (flags & PREF_UTF ? DBEF_UTF : 0) | (flags & PREF_RTL ? DBEF_RTL : 0); + dbei.szModule = szProto; + dbei.timestamp = (DWORD)time(NULL); + dbei.cbBlob = (DWORD)bufSize; + dbei.pBlob = (PBYTE)sendBuffer; + + hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei); + hSendId = (HANDLE) CallContactService(hContact, MsgServiceName(hContact), flags, (LPARAM) sendBuffer); + msgQueue_add(hContact, hSendId, szMsg, hNewEvent); + mir_free(sendBuffer); + + return hNewEvent; + } + return NULL; +} + + +static void AddToFileList(TCHAR ***pppFiles,int *totalCount,const TCHAR* szFilename) +{ + *pppFiles=(TCHAR**)mir_realloc(*pppFiles,(++*totalCount+1)*sizeof(TCHAR*)); + (*pppFiles)[*totalCount] = NULL; + (*pppFiles)[*totalCount-1] = mir_tstrdup( szFilename ); + + if ( GetFileAttributes(szFilename) & FILE_ATTRIBUTE_DIRECTORY ) { + WIN32_FIND_DATA fd; + HANDLE hFind; + TCHAR szPath[MAX_PATH]; + mir_sntprintf(szPath, SIZEOF(szPath), _T("%s\\*"), szFilename); + if (( hFind = FindFirstFile( szPath, &fd )) != INVALID_HANDLE_VALUE ) { + do { + if ( !_tcscmp(fd.cFileName,_T(".")) || !_tcscmp(fd.cFileName,_T(".."))) continue; + mir_sntprintf(szPath, SIZEOF(szPath), _T("%s\\%s"), szFilename, fd.cFileName); + AddToFileList(pppFiles,totalCount,szPath); + } + while( FindNextFile( hFind,&fd )); + FindClose( hFind ); + } } } + +static void ShowMultipleControls(HWND hwndDlg, const UINT * controls, int cControls, int state) +{ + int i; + for (i = 0; i < cControls; i++) + ShowWindow(GetDlgItem(hwndDlg, controls[i]), state); +} + +static void UpdateReadChars(HWND hwndDlg, HWND hwndStatus) +{ + if (hwndStatus && (g_dat->flags & SMF_SHOWREADCHAR)) + { + TCHAR buf[32]; + int len = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)); + + mir_sntprintf(buf, SIZEOF(buf), _T("%d"), len); + SendMessage(hwndStatus, SB_SETTEXT, 1, (LPARAM) buf); + } +} + +static void ShowTime(struct MessageWindowData *dat) +{ + if (dat->hwndStatus && dat->hTimeZone) + { + SYSTEMTIME st; + GetSystemTime(&st); + if (dat->wMinute != st.wMinute) + { + TCHAR buf[32]; + unsigned i = (g_dat->flags & SMF_SHOWREADCHAR) ? 2 : 1; + + tmi.printDateTime(dat->hTimeZone, _T("t"), buf, SIZEOF(buf), 0); + SendMessage(dat->hwndStatus, SB_SETTEXT, i, (LPARAM) buf); + dat->wMinute = st.wMinute; + } + } +} + +static void SetupStatusBar(HWND hwndDlg, struct MessageWindowData *dat) +{ + int icons_width, cx, i = 0, statwidths[4]; + RECT rc; + + icons_width = GetStatusIconsCount(dat->hContact) * (GetSystemMetrics(SM_CXSMICON) + 2) + SB_GRIP_WIDTH; + GetWindowRect(dat->hwndStatus, &rc); + cx = rc.right - rc.left; + + if (dat->hTimeZone) + { + if (g_dat->flags & SMF_SHOWREADCHAR) + statwidths[i++] = cx - SB_TIME_WIDTH - SB_CHAR_WIDTH - icons_width; + statwidths[i++] = cx - SB_TIME_WIDTH - icons_width; + } + else if (g_dat->flags & SMF_SHOWREADCHAR) + statwidths[i++] = cx - SB_CHAR_WIDTH - icons_width; + + statwidths[i++] = cx - icons_width; + statwidths[i++] = -1; + SendMessage(dat->hwndStatus, SB_SETPARTS, i, (LPARAM) statwidths); + + UpdateReadChars(hwndDlg, dat->hwndStatus); + ShowTime(dat); + SendMessage(hwndDlg, DM_STATUSICONCHANGE, 0, 0); +} + +static void SetDialogToType(HWND hwndDlg) +{ + struct MessageWindowData *dat; + + dat = (struct MessageWindowData *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (dat->hContact) + ShowMultipleControls(hwndDlg, infoLineControls, SIZEOF(infoLineControls), (g_dat->flags&SMF_SHOWINFO) ? SW_SHOW : SW_HIDE); + else + ShowMultipleControls(hwndDlg, infoLineControls, SIZEOF(infoLineControls), SW_HIDE); + + if (dat->hContact) { + ShowMultipleControls(hwndDlg, buttonLineControls, SIZEOF(buttonLineControls), (g_dat->flags&SMF_SHOWBTNS) ? SW_SHOW : SW_HIDE); + if (!DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0)) + ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE); + } + else ShowMultipleControls(hwndDlg, buttonLineControls, SIZEOF(buttonLineControls), SW_HIDE); + + ShowMultipleControls(hwndDlg, sendControls, SIZEOF(sendControls), SW_SHOW); + if (!dat->hwndStatus) { + int grip = (GetWindowLongPtr(hwndDlg, GWL_STYLE) & WS_THICKFRAME) ? SBARS_SIZEGRIP : 0; + dat->hwndStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | grip, 0, 0, 0, 0, hwndDlg, NULL, g_hInst, NULL); + SendMessage(dat->hwndStatus, SB_SETMINHEIGHT, GetSystemMetrics(SM_CYSMICON), 0); + } + + ShowWindow(GetDlgItem(hwndDlg, IDCANCEL), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_SPLITTER), SW_SHOW); + ShowWindow(GetDlgItem(hwndDlg, IDOK), (g_dat->flags & SMF_SENDBTN) ? SW_SHOW : SW_HIDE); + EnableWindow(GetDlgItem(hwndDlg, IDOK), GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)) != 0); + if (dat->avatarPic == NULL || !(g_dat->flags & SMF_AVATAR)) + ShowWindow(GetDlgItem(hwndDlg, IDC_AVATAR), SW_HIDE); + SendMessage(hwndDlg, DM_UPDATETITLE, 0, 0); + SendMessage(hwndDlg, WM_SIZE, 0, 0); +} + +struct MsgEditSubclassData +{ + DWORD lastEnterTime; +}; + +static void SetEditorText(HWND hwnd, const TCHAR* txt) +{ + SetWindowText(hwnd, txt); + SendMessage(hwnd, EM_SETSEL, -1, -1); +} + +#define EM_SUBCLASSED (WM_USER+0x101) +#define EM_UNSUBCLASSED (WM_USER+0x102) +#define ENTERCLICKTIME 1000 //max time in ms during which a double-tap on enter will cause a send + +static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + struct MessageWindowData *pdat = (struct MessageWindowData *)GetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA); + struct MsgEditSubclassData *dat = (struct MsgEditSubclassData *) GetWindowLongPtr(hwnd, GWLP_USERDATA); + + switch (msg) { + case WM_DROPFILES: + SendMessage(GetParent(hwnd), WM_DROPFILES, (WPARAM)wParam, (LPARAM)lParam); + break; + + case EM_SUBCLASSED: + dat = (struct MsgEditSubclassData *) mir_alloc(sizeof(struct MsgEditSubclassData)); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) dat); + dat->lastEnterTime = 0; + return 0; + + case WM_CHAR: + if (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY) + break; + + if (wParam == 1 && GetKeyState(VK_CONTROL) & 0x8000) { //ctrl-a + SendMessage(hwnd, EM_SETSEL, 0, -1); + return 0; + } + + if (wParam == 23 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w + SendMessage(GetParent(hwnd), WM_CLOSE, 0, 0); + return 0; + } + break; + + case WM_KEYDOWN: + if (wParam == VK_RETURN) + { + if (!(GetKeyState(VK_SHIFT) & 0x8000) && + ((GetKeyState(VK_CONTROL) & 0x8000) != 0) != ((g_dat->flags & SMF_SENDONENTER) != 0)) + { + PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0); + return 0; + } + if (g_dat->flags & SMF_SENDONDBLENTER) + { + if (dat->lastEnterTime + ENTERCLICKTIME < GetTickCount()) + dat->lastEnterTime = GetTickCount(); + else + { + SendMessage(hwnd, WM_KEYDOWN, VK_BACK, 0); + SendMessage(hwnd, WM_KEYUP, VK_BACK, 0); + PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0); + return 0; + } + } + } + else + dat->lastEnterTime = 0; + + if (((wParam == VK_INSERT && (GetKeyState(VK_SHIFT) & 0x8000)) || (wParam == 'V' && (GetKeyState(VK_CONTROL) & 0x8000))) && + !(GetKeyState(VK_MENU) & 0x8000)) // ctrl-v (paste clean text) + { + SendMessage(hwnd, WM_PASTE, 0, 0); + return 0; + } + + if (wParam == VK_UP && (GetKeyState(VK_CONTROL) & 0x8000) && + ((g_dat->flags & (SMF_AUTOCLOSE | SMF_CTRLSUPPORT)) == SMF_CTRLSUPPORT)) + { + if (pdat->cmdList->realCount) + { + if (pdat->cmdListInd < 0) + { + pdat->cmdListInd = pdat->cmdList->realCount - 1; + SetEditorText(hwnd, tcmdlist_getitem(pdat->cmdList, pdat->cmdListInd)); + } + else if (pdat->cmdListInd > 0) + { + SetEditorText(hwnd, tcmdlist_getitem(pdat->cmdList, --pdat->cmdListInd)); + } + } + EnableWindow(GetDlgItem(GetParent(hwnd), IDOK), GetWindowTextLength(hwnd) != 0); + UpdateReadChars(GetParent(hwnd), pdat->hwndStatus); + return 0; + } + else if (wParam == VK_DOWN && (GetKeyState(VK_CONTROL) & 0x8000) && + ((g_dat->flags & (SMF_AUTOCLOSE | SMF_CTRLSUPPORT)) == SMF_CTRLSUPPORT)) + { + if (pdat->cmdList->realCount && pdat->cmdListInd >= 0) + { + if (pdat->cmdListInd < (pdat->cmdList->realCount - 1)) + { + SetEditorText(hwnd, tcmdlist_getitem(pdat->cmdList, ++pdat->cmdListInd)); + } + else + { + pdat->cmdListInd = -1; + SetEditorText(hwnd, tcmdlist_getitem(pdat->cmdList, pdat->cmdList->realCount - 1)); + } + } + + EnableWindow(GetDlgItem(GetParent(hwnd), IDOK), GetWindowTextLength(hwnd) != 0); + UpdateReadChars(GetParent(hwnd), pdat->hwndStatus); + } + break; + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_MOUSEWHEEL: + case WM_KILLFOCUS: + dat->lastEnterTime = 0; + break; + + case WM_SYSCHAR: + dat->lastEnterTime = 0; + if ((wParam == 's' || wParam == 'S') && GetKeyState(VK_MENU) & 0x8000) + { + PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0); + return 0; + } + break; + + case WM_CONTEXTMENU: + { + HMENU hMenu; + CHARRANGE sel; + static const CHARRANGE all = {0, -1}; + + MessageWindowPopupData mwpd = {0}; + mwpd.cbSize = sizeof(mwpd); + mwpd.uType = MSG_WINDOWPOPUP_SHOWING; + mwpd.uFlags = MSG_WINDOWPOPUP_INPUT; + mwpd.hContact = pdat->hContact; + mwpd.hwnd = hwnd; + + hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT)); + + mwpd.hMenu = GetSubMenu(hMenu, 2); + CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM)mwpd.hMenu, 0); + + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin == sel.cpMax) + { + EnableMenuItem(mwpd.hMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(mwpd.hMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(mwpd.hMenu, IDM_DELETE, MF_BYCOMMAND | MF_GRAYED); + } + if (!SendMessage(hwnd, EM_CANUNDO, 0, 0)) + { + EnableMenuItem(mwpd.hMenu, IDM_UNDO, MF_BYCOMMAND | MF_GRAYED); + } + if (!SendMessage(hwnd, EM_CANREDO, 0, 0)) + { + EnableMenuItem(mwpd.hMenu, IDM_REDO, MF_BYCOMMAND | MF_GRAYED); + } + if (!SendMessage(hwnd, EM_CANPASTE, 0, 0)) + { + if (!IsClipboardFormatAvailable(CF_HDROP)) + EnableMenuItem(mwpd.hMenu, IDM_PASTE, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(mwpd.hMenu, IDM_PASTESEND, MF_BYCOMMAND | MF_GRAYED); + } + if (lParam == 0xFFFFFFFF) + { + SendMessage(hwnd, EM_POSFROMCHAR, (WPARAM)&mwpd.pt, (LPARAM)sel.cpMax); + ClientToScreen(hwnd, &mwpd.pt); + } + else + { + mwpd.pt.x = GET_X_LPARAM(lParam); + mwpd.pt.y = GET_Y_LPARAM(lParam); + } + + + // First notification + NotifyEventHooks(hHookWinPopup, 0, (LPARAM)&mwpd); + + // Someone added items? + if (GetMenuItemCount(mwpd.hMenu) > 0) + { + SetCursor(LoadCursor(NULL, IDC_ARROW)); + mwpd.selection = TrackPopupMenu(mwpd.hMenu, TPM_RETURNCMD, mwpd.pt.x, mwpd.pt.y, 0, hwnd, NULL); + } + + // Second notification + mwpd.uType = MSG_WINDOWPOPUP_SELECTED; + NotifyEventHooks(hHookWinPopup, 0, (LPARAM)&mwpd); + + switch (mwpd.selection) + { + case IDM_UNDO: + SendMessage(hwnd, WM_UNDO, 0, 0); + break; + + case IDM_REDO: + SendMessage(hwnd, EM_REDO, 0, 0); + break; + + case IDM_CUT: + SendMessage(hwnd, WM_CUT, 0, 0); + break; + + case IDM_COPY: + SendMessage(hwnd, WM_COPY, 0, 0); + break; + + case IDM_PASTE: + SendMessage(hwnd, WM_PASTE, 0, 0); + break; + + case IDM_PASTESEND: + SendMessage(hwnd, EM_PASTESPECIAL, CF_TEXT, 0); + PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0); + break; + + case IDM_DELETE: + SendMessage(hwnd, EM_REPLACESEL, TRUE, 0); + break; + + case IDM_SELECTALL: + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&all); + break; + + case IDM_CLEAR: + SetWindowText(hwnd, _T( "" )); + break; + } + DestroyMenu(hMenu); + return 0; + } + + case WM_PASTE: + if (IsClipboardFormatAvailable(CF_HDROP)) + { + if (OpenClipboard(hwnd)) + { + HANDLE hDrop = GetClipboardData(CF_HDROP); + if (hDrop) + SendMessage(hwnd, WM_DROPFILES, (WPARAM)hDrop, 0); + CloseClipboard(); + } + } + else + SendMessage(hwnd, EM_PASTESPECIAL, CF_TEXT, 0); + return 0; + + case EM_UNSUBCLASSED: + mir_free(dat); + return 0; + } + return CallWindowProc(pdat->OldMessageEditProc, hwnd, msg, wParam, lParam); +} + +static LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + struct MessageWindowData *pdat = (struct MessageWindowData *)GetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA); + + switch (msg) { + case WM_NCHITTEST: + return HTCLIENT; + + case WM_SETCURSOR: + { + RECT rc; + GetClientRect(hwnd, &rc); + SetCursor(rc.right > rc.bottom ? hCurSplitNS : hCurSplitWE); + return TRUE; + } + + case WM_LBUTTONDOWN: + SetCapture(hwnd); + return 0; + + case WM_MOUSEMOVE: + if (GetCapture() == hwnd) { + RECT rc; + GetClientRect(hwnd, &rc); + SendMessage(GetParent(hwnd), DM_SPLITTERMOVED, rc.right > rc.bottom ? (short) HIWORD(GetMessagePos()) + rc.bottom / 2 : (short) LOWORD(GetMessagePos()) + rc.right / 2, (LPARAM) hwnd); + } + return 0; + + case WM_LBUTTONUP: + ReleaseCapture(); + return 0; + } + return CallWindowProc(pdat->OldSplitterProc, hwnd, msg, wParam, lParam); +} + +static int MessageDialogResize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL * urc) +{ + struct MessageWindowData *dat = (struct MessageWindowData *) lParam; + + if (!(g_dat->flags&SMF_SHOWINFO) && !(g_dat->flags&SMF_SHOWBTNS)) { + int i; + for (i = 0; i < SIZEOF(buttonLineControls); i++) + if (buttonLineControls[i] == urc->wId) + OffsetRect(&urc->rcItem, 0, -dat->lineHeight); + } + + switch (urc->wId) { + case IDC_NAME: + { + int len; + HWND h; + + h = GetDlgItem(hwndDlg, IDC_NAME); + len = GetWindowTextLength(h); + if (len > 0) { + HDC hdc; + SIZE textSize; + TCHAR buf[256]; + HFONT hFont; + + GetWindowText(h, buf, SIZEOF(buf)); + + hdc = GetDC(h); + hFont = SelectObject(hdc, (HFONT) SendMessage(GetDlgItem(hwndDlg, IDOK), WM_GETFONT, 0, 0)); + GetTextExtentPoint32(hdc, buf, lstrlen(buf), &textSize); + urc->rcItem.right = urc->rcItem.left + textSize.cx + 10; + if ((g_dat->flags&SMF_SHOWBTNS) && urc->rcItem.right > urc->dlgNewSize.cx - dat->nLabelRight) + urc->rcItem.right = urc->dlgNewSize.cx - dat->nLabelRight; + SelectObject(hdc, hFont); + ReleaseDC(h, hdc); + } + } + case IDC_PROTOCOL: + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; + + case IDC_ADD: + case IDC_USERMENU: + case IDC_DETAILS: + case IDC_HISTORY: + return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP; + + case IDC_LOG: + if (!(g_dat->flags&SMF_SHOWINFO) && !(g_dat->flags&SMF_SHOWBTNS)) + urc->rcItem.top -= dat->lineHeight; + urc->rcItem.bottom -= dat->splitterPos - dat->originalSplitterPos; + return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; + + case IDC_SPLITTER: + urc->rcItem.top -= dat->splitterPos - dat->originalSplitterPos; + urc->rcItem.bottom -= dat->splitterPos - dat->originalSplitterPos; + return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; + + case IDC_MESSAGE: + { + if (!(g_dat->flags & SMF_SENDBTN)) + urc->rcItem.right = urc->dlgNewSize.cx - urc->rcItem.left; + if ((g_dat->flags & SMF_AVATAR) && dat->avatarPic) { + urc->rcItem.left = dat->avatarWidth+4; + } + urc->rcItem.top -= dat->splitterPos - dat->originalSplitterPos; + if (!(g_dat->flags & SMF_SENDBTN)) + return RD_ANCHORX_CUSTOM | RD_ANCHORY_BOTTOM; + return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; + } + + case IDCANCEL: + case IDOK: + urc->rcItem.top -= dat->splitterPos - dat->originalSplitterPos; + return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; + + case IDC_AVATAR: + urc->rcItem.top=urc->rcItem.bottom-(dat->avatarHeight + 2); + urc->rcItem.right=urc->rcItem.left+(dat->avatarWidth + 2); + return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; +} + +void ShowAvatar(HWND hwndDlg, struct MessageWindowData *dat) +{ + if (g_dat->flags & SMF_AVATAR) + { + AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)dat->hContact, 0); + if (ace && (INT_PTR)ace != CALLSERVICE_NOTFOUND && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) + dat->avatarPic = ace->hbmPic; + else + dat->avatarPic = NULL; + } + else + dat->avatarPic = NULL; + + SendMessage(hwndDlg, DM_UPDATESIZEBAR, 0, 0); + SendMessage(hwndDlg, DM_AVATARSIZECHANGE, 0, 0); +} + +static void NotifyTyping(struct MessageWindowData *dat, int mode) +{ + DWORD protoStatus; + DWORD protoCaps; + DWORD typeCaps; + + if (!dat->hContact) + return; + // Don't send to protocols who don't support typing + // Don't send to users who are unchecked in the typing notification options + // Don't send to protocols that are offline + // Don't send to users who are not visible and + // Don't send to users who are not on the visible list when you are in invisible mode. + + if (!DBGetContactSettingByte(dat->hContact, SRMMMOD, SRMSGSET_TYPING, DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW))) + return; + + if (!dat->szProto) + return; + + protoStatus = CallProtoService(dat->szProto, PS_GETSTATUS, 0, 0); + protoCaps = CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_1, 0); + typeCaps = CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_4, 0); + + if (!(typeCaps & PF4_SUPPORTTYPING)) + return; + + if (protoStatus < ID_STATUS_ONLINE) + return; + + if (protoCaps & PF1_VISLIST && DBGetContactSettingWord(dat->hContact, dat->szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE) + return; + + if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && DBGetContactSettingWord(dat->hContact, dat->szProto, "ApparentMode", 0) != ID_STATUS_ONLINE) + return; + + if (!(g_dat->flags & SMF_TYPINGUNKNOWN) && DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0)) + return; + + // End user check + dat->nTypeMode = mode; + CallService(MS_PROTO_SELFISTYPING, (WPARAM) dat->hContact, dat->nTypeMode); +} + +void Button_SetIcon_IcoLib(HWND hwndDlg, int itemId, int iconId, const char* tooltip) +{ + HWND hWnd = GetDlgItem( hwndDlg, itemId ); + SendMessage( hWnd, BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadSkinnedIcon( iconId )); + SendMessage( hWnd, BUTTONSETASFLATBTN, 0, 0 ); + SendMessage( hWnd, BUTTONADDTOOLTIP, (WPARAM)tooltip, 0); +} + +void Button_FreeIcon_IcoLib(HWND hwndDlg, int itemId) +{ + HICON hIcon = ( HICON )SendDlgItemMessage(hwndDlg, itemId, BM_SETIMAGE, IMAGE_ICON, 0 ); + CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); +} + +void Window_FreeIcon_IcoLib(HWND hwndDlg) +{ + HICON hIcon = (HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0); + CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); + + hIcon = (HICON)SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, 0); + CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); +} + +INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + struct MessageWindowData *dat; + + dat = (struct MessageWindowData *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + switch (msg) + { + case WM_INITDIALOG: + { + struct NewMessageWindowLParam *newData = (struct NewMessageWindowLParam *) lParam; + TranslateDialogDefault(hwndDlg); + dat = (struct MessageWindowData *) mir_calloc(sizeof(struct MessageWindowData)); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) dat); + + dat->hContact = newData->hContact; + dat->hTimeZone = tmi.createByContact(dat->hContact, TZF_KNOWNONLY); + dat->wMinute = 61; + + NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPENING); + if (newData->szInitialText) + { + int len; +#ifdef _UNICODE + if(newData->isWchar) + SetDlgItemText(hwndDlg, IDC_MESSAGE, (TCHAR *)newData->szInitialText); + else +#endif + SetDlgItemTextA(hwndDlg, IDC_MESSAGE, newData->szInitialText); + len = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)); + PostMessage(GetDlgItem(hwndDlg, IDC_MESSAGE), EM_SETSEL, len, len); + } + + dat->szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) dat->hContact, 0); + RichUtil_SubClass(GetDlgItem(hwndDlg, IDC_LOG)); + RichUtil_SubClass(GetDlgItem(hwndDlg, IDC_MESSAGE)); + + // avatar stuff + dat->limitAvatarH = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_LIMITAVHEIGHT, SRMSGDEFSET_LIMITAVHEIGHT)?DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_AVHEIGHT, SRMSGDEFSET_AVHEIGHT):0; + + if (dat->hContact && dat->szProto != NULL) + dat->wStatus = DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE); + else + dat->wStatus = ID_STATUS_OFFLINE; + dat->wOldStatus = dat->wStatus; + dat->splitterPos = (int) DBGetContactSettingDword(DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SAVEPERCONTACT, SRMSGDEFSET_SAVEPERCONTACT)?dat->hContact:NULL, SRMMMOD, "splitterPos", (DWORD) - 1); + dat->cmdList = li.List_Create(0, 20); + dat->cmdListInd = -1; + dat->nTypeMode = PROTOTYPE_SELFTYPING_OFF; + SetTimer(hwndDlg, TIMERID_TYPE, 1000, NULL); + { + RECT rc, rc2; + GetWindowRect(GetDlgItem(hwndDlg, IDC_USERMENU), &rc); + GetWindowRect(hwndDlg, &rc2); + dat->nLabelRight = rc2.right - rc.left; + } + { + RECT rc; + POINT pt; + GetWindowRect(GetDlgItem(hwndDlg, IDC_SPLITTER), &rc); + pt.y = (rc.top + rc.bottom) / 2; + pt.x = 0; + ScreenToClient(hwndDlg, &pt); + dat->originalSplitterPos = pt.y; + if (dat->splitterPos == -1) + dat->splitterPos = dat->originalSplitterPos;// + 60; + GetWindowRect(GetDlgItem(hwndDlg, IDC_ADD), &rc); + dat->lineHeight = rc.bottom - rc.top + 3; + } + WindowList_Add(g_dat->hMessageWindowList, hwndDlg, dat->hContact); + GetWindowRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &dat->minEditInit); + SendMessage(hwndDlg, DM_UPDATESIZEBAR, 0, 0); + dat->hwndStatus = NULL; + Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, "Add Contact Permanently to List" ); + Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, "View User's Details" ); + Button_SetIcon_IcoLib(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, "View User's History" ); + Button_SetIcon_IcoLib(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, "User Menu" ); + SendDlgItemMessage(hwndDlg, IDC_NAME, BUTTONSETASFLATBTN, 0, 0 ); + + EnableWindow(GetDlgItem(hwndDlg, IDC_PROTOCOL), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_AVATAR), FALSE); + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETOLECALLBACK, 0, (LPARAM) & reOleCallback); + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK | ENM_SCROLL); + /* duh, how come we didnt use this from the start? */ + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_AUTOURLDETECT, (WPARAM) TRUE, 0); + if (dat->hContact && dat->szProto) { + int nMax; + nMax = CallProtoService(dat->szProto, PS_GETCAPS, PFLAG_MAXLENOFMESSAGE, (LPARAM) dat->hContact); + if (nMax) + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_LIMITTEXT, (WPARAM) nMax, 0); + /* get around a lame bug in the Windows template resource code where richedits are limited to 0x7FFF */ + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_LIMITTEXT, (WPARAM) sizeof(TCHAR) * 0x7FFFFFFF, 0); + } + + dat->OldMessageEditProc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWLP_WNDPROC, (LONG_PTR) MessageEditSubclassProc); + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SUBCLASSED, 0, 0); + dat->OldSplitterProc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTER), GWLP_WNDPROC, (LONG_PTR) SplitterSubclassProc); + + if (dat->hContact) + { + int historyMode = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_LOADHISTORY, SRMSGDEFSET_LOADHISTORY); + // This finds the first message to display, it works like shit + dat->hDbEventFirst = (HANDLE) CallService(MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM) dat->hContact, 0); + switch (historyMode) + { + case LOADHISTORY_COUNT: + { + int i; + HANDLE hPrevEvent; + DBEVENTINFO dbei = { 0 }; + dbei.cbSize = sizeof(dbei); + for (i = DBGetContactSettingWord(NULL, SRMMMOD, SRMSGSET_LOADCOUNT, SRMSGDEFSET_LOADCOUNT); i--; ) + { + if (dat->hDbEventFirst == NULL) + hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0); + else + hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) dat->hDbEventFirst, 0); + if (hPrevEvent == NULL) + break; + + dbei.cbBlob = 0; + dat->hDbEventFirst = hPrevEvent; + CallService(MS_DB_EVENT_GET, (WPARAM) hPrevEvent, (LPARAM) &dbei); + if (!DbEventIsShown(&dbei, dat)) + i++; + } + break; + } + case LOADHISTORY_TIME: + { + HANDLE hPrevEvent; + DBEVENTINFO dbei = { 0 }; + DWORD firstTime; + + dbei.cbSize = sizeof(dbei); + if (dat->hDbEventFirst == NULL) + dbei.timestamp = (DWORD)time(NULL); + else + CallService(MS_DB_EVENT_GET, (WPARAM) dat->hDbEventFirst, (LPARAM) & dbei); + firstTime = dbei.timestamp - 60 * DBGetContactSettingWord(NULL, SRMMMOD, SRMSGSET_LOADTIME, SRMSGDEFSET_LOADTIME); + for (;;) + { + if (dat->hDbEventFirst == NULL) + hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0); + else + hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) dat->hDbEventFirst, 0); + if (hPrevEvent == NULL) + break; + dbei.cbBlob = 0; + CallService(MS_DB_EVENT_GET, (WPARAM) hPrevEvent, (LPARAM) & dbei); + if (dbei.timestamp < firstTime) + break; + dat->hDbEventFirst = hPrevEvent; + } + break; + } + } + } + + { + DBEVENTINFO dbei = { 0 }; + HANDLE hdbEvent; + + dbei.cbSize = sizeof(dbei); + hdbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0); + if (hdbEvent) + { + do { + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + CallService(MS_DB_EVENT_GET, (WPARAM) hdbEvent, (LPARAM) & dbei); + if (( dbei.eventType == EVENTTYPE_MESSAGE || DbEventIsForMsgWindow(&dbei) ) && !(dbei.flags & DBEF_SENT)) { + dat->lastMessage = dbei.timestamp; + PostMessage(hwndDlg, DM_UPDATELASTMESSAGE, 0, 0); + break; + } + } + while (hdbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) hdbEvent, 0)); + } + } + + SendMessage(hwndDlg, DM_OPTIONSAPPLIED, 1, 0); + + //restore saved msg if any... + if (dat->hContact) + { + DBVARIANT dbv; + if (!DBGetContactSettingTString(dat->hContact, SRMSGMOD, DBSAVEDMSG, &dbv)) + { + if (dbv.ptszVal[0]) + { + SetDlgItemText(hwndDlg, IDC_MESSAGE, dbv.ptszVal); + EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); + UpdateReadChars(hwndDlg, dat->hwndStatus); + PostMessage(GetDlgItem(hwndDlg, IDC_MESSAGE), EM_SETSEL, -1, -1); + } + DBFreeVariant(&dbv); + } + } + + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETEVENTMASK, 0, ENM_CHANGE); + + { + int flag = newData->noActivate ? RWPF_HIDDEN : 0; + int savePerContact = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SAVEPERCONTACT, SRMSGDEFSET_SAVEPERCONTACT); + if (Utils_RestoreWindowPositionEx(hwndDlg, flag, savePerContact ? dat->hContact : NULL, SRMMMOD, "")) { + if (savePerContact) { + if (Utils_RestoreWindowPositionEx(hwndDlg, flag | RWPF_NOMOVE, NULL, SRMMMOD, "")) + SetWindowPos(hwndDlg, 0, 0, 0, 450, 300, SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW); + } + else + SetWindowPos(hwndDlg, 0, 0, 0, 450, 300, SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW); + } + if (!savePerContact && DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_CASCADE, SRMSGDEFSET_CASCADE)) + WindowList_Broadcast(g_dat->hMessageWindowList, DM_CASCADENEWWINDOW, (WPARAM) hwndDlg, (LPARAM) & dat->windowWasCascaded); + } + if (newData->noActivate) + { + SetWindowPos(hwndDlg, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW); + SetTimer(hwndDlg, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL); + } + else + { + SetWindowPos(hwndDlg, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + SetForegroundWindow(hwndDlg); + SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE)); + } + + SendMessage(hwndDlg, DM_GETAVATAR, 0, 0); + + NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPEN); + return FALSE; + } + + case WM_CONTEXTMENU: + if (dat->hwndStatus && dat->hwndStatus == (HWND) wParam) { + POINT pt, pt2; + HMENU hMenu; + RECT rc; + + GetCursorPos(&pt); + pt2.x = pt.x; pt2.y = pt.y; + ScreenToClient(dat->hwndStatus, &pt); + + // no popup menu for status icons - this is handled via NM_RCLICK notification and the plugins that added the icons + SendMessage(dat->hwndStatus, SB_GETRECT, SendMessage(dat->hwndStatus, SB_GETPARTS, 0, 0) - 1, (LPARAM)&rc); + if (pt.x >= rc.left) break; + + hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) dat->hContact, 0); + + TrackPopupMenu(hMenu, 0, pt2.x, pt2.y, 0, hwndDlg, NULL); + DestroyMenu(hMenu); + } + break; + + // Mod from tabsrmm + case WM_DROPFILES: + if (dat->szProto==NULL) break; + if (!(CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_1,0)&PF1_FILESEND)) break; + if (dat->wStatus==ID_STATUS_OFFLINE) break; + if (dat->hContact!=NULL) { + TCHAR szFilename[MAX_PATH]; + HDROP hDrop = (HDROP)wParam; + int fileCount = DragQueryFile(hDrop,-1,NULL,0), totalCount = 0, i; + TCHAR** ppFiles = NULL; + for ( i=0; i < fileCount; i++ ) { + DragQueryFile(hDrop, i, szFilename, SIZEOF(szFilename)); + AddToFileList(&ppFiles, &totalCount, szFilename); + } + CallServiceSync(MS_FILE_SENDSPECIFICFILEST, (WPARAM)dat->hContact, (LPARAM)ppFiles); + for(i=0;ppFiles[i];i++) mir_free(ppFiles[i]); + mir_free(ppFiles); + } + break; + + case HM_AVATARACK: + ShowAvatar(hwndDlg, dat); + break; + + case DM_AVATARCALCSIZE: + { + BITMAP bminfo; + + if (dat->avatarPic == NULL || !(g_dat->flags&SMF_AVATAR)) + { + dat->avatarWidth=50; + dat->avatarHeight=50; + ShowWindow(GetDlgItem(hwndDlg, IDC_AVATAR), SW_HIDE); + return 0; + } + GetObject(dat->avatarPic, sizeof(bminfo), &bminfo); + dat->avatarWidth=bminfo.bmWidth+2; + dat->avatarHeight=bminfo.bmHeight+2; + if (dat->limitAvatarH&&dat->avatarHeight>dat->limitAvatarH) { + dat->avatarWidth = bminfo.bmWidth * dat->limitAvatarH / bminfo.bmHeight + 2; + dat->avatarHeight = dat->limitAvatarH + 2; + } + ShowWindow(GetDlgItem(hwndDlg, IDC_AVATAR), SW_SHOW); + } + break; + + case DM_UPDATESIZEBAR: + dat->minEditBoxSize.cx = dat->minEditInit.right - dat->minEditInit.left; + dat->minEditBoxSize.cy = dat->minEditInit.bottom - dat->minEditInit.top; + if(g_dat->flags&SMF_AVATAR) { + SendMessage(hwndDlg, DM_AVATARCALCSIZE, 0, 0); + if(dat->avatarPic && dat->minEditBoxSize.cy <= dat->avatarHeight) + dat->minEditBoxSize.cy = dat->avatarHeight; + } + break; + + case DM_AVATARSIZECHANGE: + { + RECT rc; + GetWindowRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &rc); + if (rc.bottom-rc.topminEditBoxSize.cy) { + SendMessage(hwndDlg, DM_SPLITTERMOVED, rc.top-(rc.bottom-rc.top-dat->minEditBoxSize.cy-4), (LPARAM) GetDlgItem(hwndDlg, IDC_SPLITTER)); + } + SendMessage(hwndDlg, WM_SIZE, 0, 0); + } + break; + + case DM_GETAVATAR: + { + PROTO_AVATAR_INFORMATION ai = { sizeof(ai), dat->hContact }; + CallProtoService(dat->szProto, PS_GETAVATARINFO, GAIF_FORCE, (LPARAM)&ai); + + ShowAvatar(hwndDlg, dat); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 1); + } + break; + + case DM_TYPING: + dat->nTypeSecs = (INT_PTR)lParam > 0 ? (int)lParam : 0; + break; + + case DM_UPDATEWINICON: + if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_STATUSICON, SRMSGDEFSET_STATUSICON)) { + WORD wStatus; + + Window_FreeIcon_IcoLib(hwndDlg); + + if (dat->szProto) { + wStatus = DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM) LoadSkinnedProtoIconBig(dat->szProto, wStatus)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM) LoadSkinnedProtoIcon(dat->szProto, wStatus)); + break; + } + } + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM) LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE)); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM) LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); + break; + + case DM_USERNAMETOCLIP: + if (dat->hContact) + { + TCHAR buf[128] = _T(""); + CONTACTINFO ci = {0}; + ci.cbSize = sizeof(ci); + ci.hContact = dat->hContact; + ci.szProto = dat->szProto; + ci.dwFlag = CNF_UNIQUEID | CNF_TCHAR; + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) + { + switch (ci.type) + { + case CNFT_ASCIIZ: + mir_sntprintf(buf, SIZEOF(buf), _T("%s"), ci.pszVal); + mir_free(ci.pszVal); + break; + + case CNFT_DWORD: + mir_sntprintf(buf, SIZEOF(buf), _T("%u"), ci.dVal); + break; + } + } + if (buf[0] && OpenClipboard(hwndDlg)) + { + HGLOBAL hData; + + EmptyClipboard(); + hData = GlobalAlloc(GMEM_MOVEABLE, _tcslen(buf) * sizeof(TCHAR) + 1); + _tcscpy(GlobalLock(hData), buf); + GlobalUnlock(hData); +#ifdef _UNICODE + SetClipboardData(CF_UNICODETEXT, hData); +#else + SetClipboardData(CF_TEXT, hData); +#endif + CloseClipboard(); + } + } + break; + + case DM_UPDATELASTMESSAGE: + if (!dat->hwndStatus || dat->nTypeSecs) + break; + + if (dat->lastMessage) + { + TCHAR date[64], time[64], fmt[128]; + + tmi.printTimeStamp(NULL, dat->lastMessage, _T("d"), date, SIZEOF(date), 0); + tmi.printTimeStamp(NULL, dat->lastMessage, _T("t"), time, SIZEOF(time), 0); + mir_sntprintf(fmt, SIZEOF(fmt), TranslateT("Last message received on %s at %s."), date, time); + SendMessage(dat->hwndStatus, SB_SETTEXT, 0, (LPARAM) fmt); + } + else { + SendMessage(dat->hwndStatus, SB_SETTEXT, 0, (LPARAM) _T("")); + } + SendMessage(dat->hwndStatus, SB_SETICON, 0, (LPARAM) NULL); + break; + + case DM_OPTIONSAPPLIED: + SetDialogToType(hwndDlg); + if (dat->hBkgBrush) + DeleteObject(dat->hBkgBrush); + { + COLORREF colour = DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR); + dat->hBkgBrush = CreateSolidBrush(colour); + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETBKGNDCOLOR, 0, colour); + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETBKGNDCOLOR, 0, colour); + } + { // avatar stuff + dat->avatarPic = NULL; + dat->limitAvatarH = 0; + if (CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_AVATARS) + { + dat->limitAvatarH = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_LIMITAVHEIGHT, SRMSGDEFSET_LIMITAVHEIGHT) ? + DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_AVHEIGHT, SRMSGDEFSET_AVHEIGHT) : 0; + } + if (!wParam) SendMessage(hwndDlg, DM_GETAVATAR, 0, 0); + } + InvalidateRect(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, FALSE); + { + HFONT hFont; + LOGFONT lf; + CHARFORMAT cf = {0}; + hFont = (HFONT) SendDlgItemMessage(hwndDlg, IDC_MESSAGE, WM_GETFONT, 0, 0); + if (hFont != NULL && hFont != (HFONT) SendDlgItemMessage(hwndDlg, IDOK, WM_GETFONT, 0, 0)) + DeleteObject(hFont); + LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, &lf, &cf.crTextColor); + hFont = CreateFontIndirect(&lf); + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, WM_SETFONT, (WPARAM) hFont, MAKELPARAM(TRUE, 0)); + + cf.cbSize = sizeof(CHARFORMAT); + cf.dwMask = CFM_COLOR; + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (WPARAM) &cf); + } + + /* + * configure message history for proper RTL formatting + */ + + { + PARAFORMAT2 pf2; + ZeroMemory((void *)&pf2, sizeof(pf2)); + pf2.cbSize = sizeof(pf2); + + pf2.wEffects = PFE_RTLPARA; + pf2.dwMask = PFM_RTLPARA; + SetDlgItemText(hwndDlg, IDC_LOG, _T("")); + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); + pf2.wEffects = 0; + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETLANGOPTIONS, 0, (LPARAM) SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); + } + SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); + SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); + break; + + case DM_UPDATETITLE: + { + TCHAR newtitle[256], oldtitle[256], *szStatus; + TCHAR *contactName, *pszNewTitleEnd; + DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) wParam; + + pszNewTitleEnd = _T("Message Session"); + if (dat->hContact) + { + if (dat->szProto) + { + TCHAR buf[128] = _T(""); + int statusIcon = DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_STATUSICON, SRMSGDEFSET_STATUSICON); + + dat->wStatus = DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE); + contactName = ( TCHAR* )CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) dat->hContact, GCDNF_TCHAR); + + if (strcmp(dat->szProto, "MetaContacts")) + { + CONTACTINFO ci = {0}; + ci.cbSize = sizeof(ci); + ci.hContact = dat->hContact; + ci.szProto = dat->szProto; + ci.dwFlag = CNF_DISPLAYUID | CNF_TCHAR; + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) { + switch (ci.type) { + case CNFT_ASCIIZ: + mir_sntprintf(buf, SIZEOF(buf), _T("%s"), (TCHAR*)ci.pszVal); + mir_free(ci.pszVal); + break; + case CNFT_DWORD: + mir_sntprintf(buf, SIZEOF(buf), _T("%u"), ci.dVal); + break; + } + } + } + if (buf[0]) + SetDlgItemText(hwndDlg, IDC_NAME, buf); + else + SetDlgItemText(hwndDlg, IDC_NAME, contactName); + + szStatus = (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, dat->szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE), GSMDF_TCHAR); + if (statusIcon) + mir_sntprintf(newtitle, SIZEOF(newtitle), _T("%s - %s"), contactName, TranslateTS(pszNewTitleEnd)); + else + mir_sntprintf(newtitle, SIZEOF(newtitle), _T("%s (%s): %s"), contactName, szStatus, TranslateTS(pszNewTitleEnd)); + + if (!cws || (!strcmp(cws->szModule, dat->szProto) && !strcmp(cws->szSetting, "Status"))) + { + InvalidateRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), NULL, TRUE); + if (statusIcon) + SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); + } + + // log + if ((dat->wStatus != dat->wOldStatus || lParam != 0) && + DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SHOWSTATUSCH, SRMSGDEFSET_SHOWSTATUSCH)) + { + DBEVENTINFO dbei; + TCHAR buffer[200]; + HANDLE hNewEvent; + int iLen; + + TCHAR *szOldStatus = (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM) dat->wOldStatus, GSMDF_TCHAR); + TCHAR *szNewStatus = (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM) dat->wStatus, GSMDF_TCHAR); + + if (dat->wStatus == ID_STATUS_OFFLINE) + { + iLen = mir_sntprintf(buffer, SIZEOF(buffer), TranslateT("signed off (was %s)"), szOldStatus); + SendMessage(hwndDlg, DM_TYPING, 0, 0); + } + else if (dat->wOldStatus == ID_STATUS_OFFLINE) + iLen = mir_sntprintf(buffer, SIZEOF(buffer), TranslateT("signed on (%s)"), szNewStatus); + else + iLen = mir_sntprintf(buffer, SIZEOF(buffer), TranslateT("is now %s (was %s)"), szNewStatus, szOldStatus); + + { + char* blob = ( char* )alloca(1000); +#if defined( _UNICODE ) + int ansiLen = WideCharToMultiByte(CP_ACP, 0, buffer, -1, blob, 1000, 0, 0); + memcpy( blob+ansiLen, buffer, sizeof(TCHAR)*(iLen+1)); + dbei.cbBlob = ansiLen + sizeof(TCHAR)*(iLen+1); +#else + int wLen = MultiByteToWideChar(CP_ACP, 0, buffer, -1, NULL, 0 ); + memcpy( blob, buffer, iLen+1 ); + MultiByteToWideChar(CP_ACP, 0, buffer, -1, (WCHAR*)&blob[iLen+1], wLen+1 ); + dbei.cbBlob = iLen+1 + sizeof(WCHAR)*wLen; +#endif + + dbei.cbSize = sizeof(dbei); + dbei.pBlob = (PBYTE) blob; + dbei.eventType = EVENTTYPE_STATUSCHANGE; + dbei.flags = 0; + dbei.timestamp = (DWORD)time(NULL); + dbei.szModule = dat->szProto; + hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM) dat->hContact, (LPARAM) & dbei); + if (dat->hDbEventFirst == NULL) + { + dat->hDbEventFirst = hNewEvent; + SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); + } + } + } + dat->wOldStatus = dat->wStatus; + } + } + else lstrcpyn(newtitle, pszNewTitleEnd, SIZEOF(newtitle)); + + GetWindowText(hwndDlg, oldtitle, SIZEOF(oldtitle)); + if ( _tcscmp(newtitle, oldtitle )) { //swt() flickers even if the title hasn't actually changed + SetWindowText(hwndDlg, newtitle); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + } + break; + } + + case DM_NEWTIMEZONE: + dat->hTimeZone = tmi.createByContact(dat->hContact, TZF_KNOWNONLY); + dat->wMinute = 61; + SendMessage(hwndDlg, WM_SIZE, 0, 0); + break; + + case DM_GETWINDOWSTATE: + { + UINT state = 0; + + state |= MSG_WINDOW_STATE_EXISTS; + if (IsWindowVisible(hwndDlg)) + state |= MSG_WINDOW_STATE_VISIBLE; + if (GetForegroundWindow()==hwndDlg) + state |= MSG_WINDOW_STATE_FOCUS; + if (IsIconic(hwndDlg)) + state |= MSG_WINDOW_STATE_ICONIC; + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, state); + return TRUE; + + } + + case DM_CASCADENEWWINDOW: + if ((HWND) wParam == hwndDlg) + break; + { + RECT rcThis, rcNew; + GetWindowRect(hwndDlg, &rcThis); + GetWindowRect((HWND) wParam, &rcNew); + if (abs(rcThis.left - rcNew.left) < 3 && abs(rcThis.top - rcNew.top) < 3) { + int offset = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME); + SetWindowPos((HWND) wParam, 0, rcNew.left + offset, rcNew.top + offset, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE); + *(int *) lParam = 1; + } + } + break; + + case WM_ACTIVATE: + if (LOWORD(wParam) != WA_ACTIVE) + break; + + SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE)); + //fall through + + case WM_MOUSEACTIVATE: + if (KillTimer(hwndDlg, TIMERID_FLASHWND)) + FlashWindow(hwndDlg, FALSE); + break; + + case WM_GETMINMAXINFO: + { + MINMAXINFO* mmi = (MINMAXINFO *) lParam; + RECT rcWindow, rcLog; + GetWindowRect(hwndDlg, &rcWindow); + GetWindowRect(GetDlgItem(hwndDlg, IDC_LOG), &rcLog); + mmi->ptMinTrackSize.x = rcWindow.right - rcWindow.left - ((rcLog.right - rcLog.left) - dat->minEditBoxSize.cx); + mmi->ptMinTrackSize.y = rcWindow.bottom - rcWindow.top - ((rcLog.bottom - rcLog.top) - dat->minEditBoxSize.cy); + return 0; + } + + case WM_SIZE: + { + UTILRESIZEDIALOG urd = {0}; + BOOL bottomScroll = TRUE; + + if (IsIconic(hwndDlg)) + break; + + if (dat->hwndStatus) + { + SendMessage(dat->hwndStatus, WM_SIZE, 0, 0); + SetupStatusBar(hwndDlg, dat); + } + + if (GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_STYLE) & WS_VSCROLL) + { + SCROLLINFO si = {0}; + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + GetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &si); + bottomScroll = (si.nPos + (int)si.nPage + 5) >= si.nMax; + } + + urd.cbSize = sizeof(urd); + urd.hInstance = g_hInst; + urd.hwndDlg = hwndDlg; + urd.lParam = (LPARAM) dat; + urd.lpTemplate = MAKEINTRESOURCEA(IDD_MSG); + urd.pfnResizer = MessageDialogResize; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM) & urd); + + // The statusbar sometimes draws over these 2 controls so + // redraw them + if (dat->hwndStatus) + { + RedrawWindow(GetDlgItem(hwndDlg, IDOK), NULL, NULL, RDW_INVALIDATE); + RedrawWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, NULL, RDW_INVALIDATE); + } + if ((g_dat->flags & SMF_AVATAR) && dat->avatarPic) + RedrawWindow(GetDlgItem(hwndDlg, IDC_AVATAR), NULL, NULL, RDW_INVALIDATE); + + if (bottomScroll) + PostMessage(hwndDlg, DM_SCROLLLOGTOBOTTOM, 0, 0); + break; + } + + case DM_SPLITTERMOVED: + { + if ((HWND) lParam == GetDlgItem(hwndDlg, IDC_SPLITTER)) + { + POINT pt; + RECT rc; + RECT rcLog; + int oldSplitterY; + HWND hwndLog = GetDlgItem(hwndDlg, IDC_LOG); + + GetClientRect(hwndDlg, &rc); + GetWindowRect(hwndLog, &rcLog); + + pt.x = 0; + pt.y = wParam; + ScreenToClient(hwndDlg, &pt); + + oldSplitterY = dat->splitterPos; + dat->splitterPos = rc.bottom - pt.y + 23; + GetWindowRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &rc); + if (rc.bottom - rc.top + (dat->splitterPos - oldSplitterY) < dat->minEditBoxSize.cy) + dat->splitterPos = oldSplitterY + dat->minEditBoxSize.cy - (rc.bottom - rc.top); + if (rcLog.bottom - rcLog.top - (dat->splitterPos - oldSplitterY) < dat->minEditBoxSize.cy) + dat->splitterPos = oldSplitterY - dat->minEditBoxSize.cy + (rcLog.bottom - rcLog.top); + + SendMessage(hwndDlg, WM_SIZE, 0, 0); + } + } + break; + + case DM_REMAKELOG: + StreamInEvents(hwndDlg, dat->hDbEventFirst, -1, 0); + break; + + case DM_APPENDTOLOG: //takes wParam=hDbEvent + StreamInEvents(hwndDlg, (HANDLE) wParam, 1, 1); + break; + + case DM_SCROLLLOGTOBOTTOM: + { + HWND hwndLog = GetDlgItem(hwndDlg, IDC_LOG); + if (GetWindowLongPtr(hwndLog, GWL_STYLE) & WS_VSCROLL) + { + SCROLLINFO si = {0}; + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(hwndLog, SB_VERT, &si); + si.fMask = SIF_POS; + si.nPos = si.nMax - si.nPage; + SetScrollInfo(hwndLog, SB_VERT, &si, TRUE); + SendMessage(hwndLog, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); + } + } + break; + + case HM_DBEVENTADDED: + if ((HANDLE) wParam != dat->hContact) + break; + { + DBEVENTINFO dbei = { 0 }; + + dbei.cbSize = sizeof(dbei); + CallService(MS_DB_EVENT_GET, lParam, (LPARAM) & dbei); + if (dat->hDbEventFirst == NULL) + dat->hDbEventFirst = (HANDLE) lParam; + if (DbEventIsShown(&dbei, dat) && !(dbei.flags & DBEF_READ)) + { + if ((dbei.eventType == EVENTTYPE_MESSAGE || DbEventIsForMsgWindow(&dbei)) && !(dbei.flags & DBEF_SENT)) + { + if (GetForegroundWindow() == hwndDlg) + SkinPlaySound("RecvMsgActive"); + else + SkinPlaySound("RecvMsgInactive"); + } + if (( dbei.eventType == EVENTTYPE_MESSAGE || DbEventIsForMsgWindow(&dbei) ) && dat->hwndStatus && !(dbei.flags & DBEF_SENT)) + { + dat->lastMessage = dbei.timestamp; + SendMessage(hwndDlg, DM_UPDATELASTMESSAGE, 0, 0); + } + if ((HANDLE) lParam != dat->hDbEventFirst && (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, lParam, 0) == NULL) + SendMessage(hwndDlg, DM_APPENDTOLOG, lParam, 0); + else + SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); + + if (!(dbei.flags & DBEF_SENT) && dbei.eventType != EVENTTYPE_STATUSCHANGE) + { + if (GetActiveWindow() == hwndDlg && GetForegroundWindow() == hwndDlg) + { + HWND hwndLog = GetDlgItem(hwndDlg, IDC_LOG); + if (GetWindowLongPtr(hwndLog, GWL_STYLE) & WS_VSCROLL) + { + SCROLLINFO si = {0}; + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + GetScrollInfo(hwndLog, SB_VERT, &si); + if ((si.nPos + (int)si.nPage + 5) < si.nMax) + SetTimer(hwndDlg, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL); + } + } + else + SetTimer(hwndDlg, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL); + } + } + } + break; + + case WM_TIMECHANGE: + PostMessage(hwndDlg, DM_NEWTIMEZONE, 0, 0); + PostMessage(hwndDlg, DM_REMAKELOG, 0, 0); + break; + + case WM_TIMER: + if (wParam == TIMERID_FLASHWND) + { + FlashWindow(hwndDlg, TRUE); + if (dat->nFlash > 2 * g_dat->nFlashMax) + { + KillTimer(hwndDlg, TIMERID_FLASHWND); + FlashWindow(hwndDlg, FALSE); + dat->nFlash = 0; + } + dat->nFlash++; + } + else if (wParam == TIMERID_TYPE) + { + ShowTime(dat); + if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - dat->nLastTyping > TIMEOUT_TYPEOFF) + NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF); + + if (dat->showTyping) + { + if (dat->nTypeSecs) + { + dat->nTypeSecs--; + if (GetForegroundWindow() == hwndDlg) + SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); + } + else + { + SendMessage(hwndDlg, DM_UPDATELASTMESSAGE, 0, 0); + if (g_dat->flags & SMF_SHOWTYPINGWIN) + SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); + dat->showTyping = 0; + } + } + else + { + if (dat->nTypeSecs) + { + TCHAR szBuf[256]; + TCHAR* szContactName = (TCHAR*) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) dat->hContact, GCDNF_TCHAR); + HICON hTyping = LoadSkinnedIcon(SKINICON_OTHER_TYPING); + + mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("%s is typing a message..."), szContactName); + dat->nTypeSecs--; + + SendMessage(dat->hwndStatus, SB_SETTEXT, 0, (LPARAM) szBuf); + SendMessage(dat->hwndStatus, SB_SETICON, 0, (LPARAM) hTyping); + if ((g_dat->flags & SMF_SHOWTYPINGWIN) && GetForegroundWindow() != hwndDlg) + { + HICON hIcon = (HICON)SendMessage(hwndDlg, WM_GETICON, ICON_SMALL, 0); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hTyping ); + CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); + } + dat->showTyping = 1; + } + } + } + break; + + case WM_MEASUREITEM: + { + LPMEASUREITEMSTRUCT mis = (LPMEASUREITEMSTRUCT) lParam; + if (mis->CtlType == ODT_MENU) + return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam); + } + break; + + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam; + if (dis->CtlType == ODT_MENU) + return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam); + else if (dis->hwndItem == dat->hwndStatus) + { + DrawStatusIcons(dat->hContact, dis->hDC, dis->rcItem, 2); + return TRUE; + } + else if (dis->CtlID == IDC_PROTOCOL) + { + if (dat->szProto) + { + HICON hIcon; + int dwStatus; + + dwStatus = DBGetContactSettingWord(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE); + hIcon = LoadSkinnedProtoIcon(dat->szProto, dwStatus); + if (hIcon) + { + if (DBGetContactSettingDword(dat->hContact, dat->szProto, "IdleTS", 0)) + { + HIMAGELIST hImageList; + + hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON), IsWinVerXPPlus()? ILC_COLOR32 | ILC_MASK : ILC_COLOR16 | ILC_MASK, 1, 0); + ImageList_AddIcon(hImageList, hIcon); + ImageList_DrawEx(hImageList, 0, dis->hDC, dis->rcItem.left, dis->rcItem.top, 0, 0, CLR_NONE, CLR_NONE, ILD_SELECTED); + ImageList_Destroy(hImageList); + } + else + DrawIconEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL); + CallService(MS_SKIN2_RELEASEICON,(WPARAM)hIcon, 0); + return TRUE; + } + } + } + else if (dis->CtlID == IDC_AVATAR && dat->avatarPic && (g_dat->flags & SMF_AVATAR)) + { + BITMAP bminfo; + HPEN hPen, hOldPen; + + hPen = CreatePen(PS_SOLID, 1, RGB(0,0,0)); + hOldPen = SelectObject(dis->hDC, hPen); + Rectangle(dis->hDC, 0, 0, dat->avatarWidth, dat->avatarHeight); + SelectObject(dis->hDC,hOldPen); + DeleteObject(hPen); + GetObject(dat->avatarPic, sizeof(bminfo), &bminfo); + { + HDC hdcMem = CreateCompatibleDC(dis->hDC); + HBITMAP hbmMem = (HBITMAP)SelectObject(hdcMem, dat->avatarPic); + { + SetStretchBltMode(dis->hDC, HALFTONE); + StretchBlt(dis->hDC, 1, 1, dat->avatarWidth-2, dat->avatarHeight-2, hdcMem, 0, 0, + bminfo.bmWidth, bminfo.bmHeight, SRCCOPY); + } + SelectObject(hdcMem,hbmMem); + DeleteDC(hdcMem); + } + return TRUE; + } + } + break; + + case WM_COMMAND: + if (!lParam && CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM) dat->hContact)) + break; + + switch (LOWORD(wParam)) + { + case IDOK: + if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDOK))) + break; + { + HANDLE hNewEvent; + + int bufSize = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)) + 1; + TCHAR* temp = (TCHAR*)alloca(bufSize * sizeof(TCHAR)); + GetDlgItemText(hwndDlg, IDC_MESSAGE, temp, bufSize); + if (!temp[0]) break; + + hNewEvent = SendMessageDirect(temp, dat->hContact, dat->szProto); + if (hNewEvent) + { + tcmdlist_append(dat->cmdList, temp); + + dat->cmdListInd = -1; + if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON) + NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF); + + EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE)); + + if (dat->hDbEventFirst == NULL) + { + dat->hDbEventFirst = hNewEvent; + SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); + } + + SetDlgItemText(hwndDlg, IDC_MESSAGE, _T("")); + + if (g_dat->flags & SMF_AUTOCLOSE) + DestroyWindow(hwndDlg); + else if (g_dat->flags & SMF_AUTOMIN) + ShowWindow(hwndDlg, SW_MINIMIZE); + } + } + return TRUE; + + case IDCANCEL: + DestroyWindow(hwndDlg); + return TRUE; + + case IDC_USERMENU: + case IDC_NAME: + if (GetKeyState(VK_SHIFT) & 0x8000) // copy user name + SendMessage(hwndDlg, DM_USERNAMETOCLIP, 0, 0); + else { + RECT rc; + HMENU hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) dat->hContact, 0); + GetWindowRect(GetDlgItem(hwndDlg, LOWORD(wParam)), &rc); + TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, hwndDlg, NULL); + DestroyMenu(hMenu); + } + break; + + case IDC_HISTORY: + CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM) dat->hContact, 0); + break; + + case IDC_DETAILS: + CallService(MS_USERINFO_SHOWDIALOG, (WPARAM) dat->hContact, 0); + break; + + case IDC_ADD: + { + ADDCONTACTSTRUCT acs = { 0 }; + + acs.handle = dat->hContact; + acs.handleType = HANDLE_CONTACT; + acs.szProto = 0; + CallService(MS_ADDCONTACT_SHOW, (WPARAM) hwndDlg, (LPARAM) & acs); + } + if (!DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0)) + ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE); + break; + + case IDC_MESSAGE: + if (HIWORD(wParam) == EN_CHANGE) + { + int len = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)); + UpdateReadChars(hwndDlg, dat->hwndStatus); + EnableWindow(GetDlgItem(hwndDlg, IDOK), len != 0); + if (!(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000)) + { + dat->nLastTyping = GetTickCount(); + if (len) + { + if (dat->nTypeMode == PROTOTYPE_SELFTYPING_OFF) + NotifyTyping(dat, PROTOTYPE_SELFTYPING_ON); + } + else if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON) + NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF); + } + } + break; + } + break; + + case WM_NOTIFY: + if (dat && ((LPNMHDR) lParam)->hwndFrom == dat->hwndStatus) + { + if (((LPNMHDR) lParam)->code == NM_CLICK || ((LPNMHDR) lParam)->code == NM_RCLICK) + { + NMMOUSE *nm = (NMMOUSE *) lParam; + RECT rc; + + SendMessage(dat->hwndStatus, SB_GETRECT, SendMessage(dat->hwndStatus, SB_GETPARTS, 0, 0) - 1, (LPARAM)&rc); + if (nm->pt.x >= rc.left) + CheckIconClick(dat->hContact, dat->hwndStatus, nm->pt, rc, 2, ((LPNMHDR) lParam)->code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0); + return TRUE; + } + } + + switch (((LPNMHDR) lParam)->idFrom) + { + case IDC_LOG: + switch (((LPNMHDR) lParam)->code) + { + case EN_MSGFILTER: + switch (((MSGFILTER *) lParam)->msg) + { + case WM_LBUTTONDOWN: + { + HCURSOR hCur = GetCursor(); + if (hCur == LoadCursor(NULL, IDC_SIZENS) || hCur == LoadCursor(NULL, IDC_SIZEWE) + || hCur == LoadCursor(NULL, IDC_SIZENESW) || hCur == LoadCursor(NULL, IDC_SIZENWSE)) + { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + break; + } + case WM_MOUSEMOVE: + { + HCURSOR hCur = GetCursor(); + if (hCur == LoadCursor(NULL, IDC_SIZENS) || hCur == LoadCursor(NULL, IDC_SIZEWE) + || hCur == LoadCursor(NULL, IDC_SIZENESW) || hCur == LoadCursor(NULL, IDC_SIZENWSE)) + SetCursor(LoadCursor(NULL, IDC_ARROW)); + break; + } + case WM_RBUTTONUP: + { + HMENU hMenu, hSubMenu; + POINT pt; + CHARRANGE sel, all = { 0, -1 }; + + hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT)); + hSubMenu = GetSubMenu(hMenu, 0); + CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hSubMenu, 0); + SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXGETSEL, 0, (LPARAM) & sel); + if (sel.cpMin == sel.cpMax) + EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED); + pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam); + pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam); + ClientToScreen(((NMHDR *) lParam)->hwndFrom, &pt); + + switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL)) + { + case IDM_COPY: + SendMessage(((NMHDR *) lParam)->hwndFrom, WM_COPY, 0, 0); + break; + case IDM_COPYALL: + SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & all); + SendMessage(((NMHDR *) lParam)->hwndFrom, WM_COPY, 0, 0); + SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & sel); + break; + case IDM_SELECTALL: + SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & all); + break; + case IDM_CLEAR: + SetDlgItemText(hwndDlg, IDC_LOG, _T("")); + dat->hDbEventFirst = NULL; + break; + } + DestroyMenu(hSubMenu); + DestroyMenu(hMenu); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + } + break; + + case EN_VSCROLL: + if (LOWORD(wParam) == IDC_LOG && GetWindowLongPtr((HWND)lParam, GWL_STYLE) & WS_VSCROLL) + { + SCROLLINFO si = {0}; + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; + GetScrollInfo((HWND)lParam, SB_VERT, &si); + if ((si.nPos + (int)si.nPage + 5) >= si.nMax) + if (KillTimer(hwndDlg, TIMERID_FLASHWND)) + FlashWindow(hwndDlg, FALSE); + } + break; + + case EN_LINK: + switch (((ENLINK *) lParam)->msg) { + case WM_SETCURSOR: + SetCursor(hCurHyperlinkHand); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + { + TEXTRANGE tr; + CHARRANGE sel; + + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXGETSEL, 0, (LPARAM) & sel); + if (sel.cpMin != sel.cpMax) + break; + tr.chrg = ((ENLINK *) lParam)->chrg; + tr.lpstrText = _alloca((tr.chrg.cpMax - tr.chrg.cpMin + 8) * sizeof(TCHAR)); + SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETTEXTRANGE, 0, (LPARAM) & tr); + if (_tcschr(tr.lpstrText, '@') != NULL && _tcschr(tr.lpstrText, ':') == NULL && _tcschr(tr.lpstrText, '/') == NULL) + { + memmove(tr.lpstrText + 7, tr.lpstrText, (tr.chrg.cpMax - tr.chrg.cpMin + 1) * sizeof(TCHAR)); + memcpy(tr.lpstrText, _T("mailto:"), 7 * sizeof(TCHAR)); + } + if (((ENLINK *) lParam)->msg == WM_RBUTTONDOWN) + { + HMENU hMenu, hSubMenu; + POINT pt; + + hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT)); + hSubMenu = GetSubMenu(hMenu, 1); + CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hSubMenu, 0); + pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam); + pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam); + ClientToScreen(((NMHDR *) lParam)->hwndFrom, &pt); + + switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL)) + { + case IDM_OPENLINK: + ShellExecute(NULL, _T("open"), tr.lpstrText, NULL, NULL, SW_SHOW); + break; + + case IDM_COPYLINK: + if (OpenClipboard(hwndDlg)) + { + HGLOBAL hData; + EmptyClipboard(); + hData = GlobalAlloc(GMEM_MOVEABLE, (_tcslen(tr.lpstrText) + 1) * sizeof(TCHAR)); + _tcscpy(GlobalLock(hData), tr.lpstrText); + GlobalUnlock(hData); +#ifdef _UNICODE + SetClipboardData(CF_UNICODETEXT, hData); +#else + SetClipboardData(CF_TEXT, hData); +#endif + CloseClipboard(); + } + break; + } + + DestroyMenu(hMenu); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + else + { + ShellExecute(NULL, _T("open"), tr.lpstrText, NULL, NULL, SW_SHOW); + SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE)); + } + break; + } + } + } + } + break; + + case DM_STATUSICONCHANGE: + SendMessage(dat->hwndStatus, SB_SETTEXT, (WPARAM)(SBT_OWNERDRAW | (SendMessage(dat->hwndStatus, SB_GETPARTS, 0, 0) - 1)), (LPARAM)0); + break; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + + case WM_DESTROY: + if (!dat) return 0; + NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSING); + //save string from the editor + if(dat->hContact) + { + TCHAR* msg; + int len = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)) + 1; + msg = (TCHAR*)alloca(sizeof(TCHAR) * len); + GetDlgItemText(hwndDlg, IDC_MESSAGE, msg, len); + if (msg[0]) + DBWriteContactSettingTString(dat->hContact, SRMSGMOD, DBSAVEDMSG, msg); + else + DBDeleteContactSetting(dat->hContact, SRMSGMOD, DBSAVEDMSG); + } + KillTimer(hwndDlg, TIMERID_TYPE); + if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON) + NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF); + + if (dat->hBkgBrush) + DeleteObject(dat->hBkgBrush); + if (dat->hwndStatus) + DestroyWindow(dat->hwndStatus); + tcmdlist_free(dat->cmdList); + WindowList_Remove(g_dat->hMessageWindowList, hwndDlg); + DBWriteContactSettingDword(DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SAVEPERCONTACT, SRMSGDEFSET_SAVEPERCONTACT)?dat->hContact:NULL, SRMMMOD, "splitterPos", dat->splitterPos); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTER), GWLP_WNDPROC, (LONG_PTR) dat->OldSplitterProc); + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_UNSUBCLASSED, 0, 0); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWLP_WNDPROC, (LONG_PTR) dat->OldMessageEditProc); + { + HFONT hFont; + hFont = (HFONT) SendDlgItemMessage(hwndDlg, IDC_MESSAGE, WM_GETFONT, 0, 0); + if (hFont != NULL && hFont != (HFONT) SendDlgItemMessage(hwndDlg, IDOK, WM_GETFONT, 0, 0)) + DeleteObject(hFont); + } + { + WINDOWPLACEMENT wp = { 0 }; + HANDLE hContact; + + if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SAVEPERCONTACT, SRMSGDEFSET_SAVEPERCONTACT)) + hContact = dat->hContact; + else + hContact = NULL; + wp.length = sizeof(wp); + GetWindowPlacement(hwndDlg, &wp); + if (!dat->windowWasCascaded) + { + DBWriteContactSettingDword(hContact, SRMMMOD, "x", wp.rcNormalPosition.left); + DBWriteContactSettingDword(hContact, SRMMMOD, "y", wp.rcNormalPosition.top); + } + DBWriteContactSettingDword(hContact, SRMMMOD, "width", wp.rcNormalPosition.right - wp.rcNormalPosition.left); + DBWriteContactSettingDword(hContact, SRMMMOD, "height", wp.rcNormalPosition.bottom - wp.rcNormalPosition.top); + } + + NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSE); + if (dat->hContact&&DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_DELTEMP, SRMSGDEFSET_DELTEMP)) + if (DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0)) + CallService(MS_DB_CONTACT_DELETE, (WPARAM)dat->hContact, 0); + + Button_FreeIcon_IcoLib(hwndDlg, IDC_ADD); + Button_FreeIcon_IcoLib(hwndDlg, IDC_DETAILS); + Button_FreeIcon_IcoLib(hwndDlg, IDC_HISTORY); + Button_FreeIcon_IcoLib(hwndDlg, IDC_USERMENU); + Window_FreeIcon_IcoLib(hwndDlg); + mir_free(dat); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + break; + } + return FALSE; +} -- cgit v1.2.3