/* 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; }