/* * astyle --force-indent=tab=4 --brackets=linux --indent-switches * --pad=oper --one-line=keep-blocks --unpad=paren * * Miranda NG: the free IM client for Microsoft* Windows* * * Copyright 2000-2009 Miranda ICQ/IM project, * all portions of this codebase are copyrighted to the people * listed in contributors.txt. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * you should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * part of tabSRMM messaging plugin for Miranda. * * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors * * $Id: generic_msghandlers.cpp 13587 2011-04-12 13:54:26Z george.hazan $ * * these are generic message handlers which are used by the message dialog window procedure. * calling them directly instead of using SendMessage() is faster. * also contains various callback functions for custom buttons */ #include "commonheaders.h" extern RECT rcLastStatusBarClick; /** * Save message log for given session as RTF document */ void TSAPI DM_SaveLogAsRTF(const TWindowData* dat) { TCHAR szFilename[MAX_PATH]; OPENFILENAME ofn = {0}; EDITSTREAM stream = { 0 }; TCHAR szFilter[MAX_PATH]; if (dat && dat->hwndIEView != 0) { IEVIEWEVENT event = {0}; event.cbSize = sizeof(IEVIEWEVENT); event.hwnd = dat->hwndIEView; event.hContact = dat->hContact; event.iType = IEE_SAVE_DOCUMENT; event.dwFlags = 0; event.count = 0; event.codepage = 0; CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event); } else if (dat) { TCHAR szInitialDir[MAX_PATH + 2]; mir_sntprintf(szFilter, SIZEOF(szFilter), _T("%s%c*.rtf%c%c"), TranslateT("Rich Edit file"), 0, 0, 0); mir_sntprintf(szFilename, MAX_PATH, _T("%s.rtf"), dat->cache->getNick()); Utils::sanitizeFilename(szFilename); mir_sntprintf(szInitialDir, MAX_PATH, _T("%s%s\\"), M->getDataPath(), _T("\\Saved message logs")); CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)szInitialDir); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = dat->hwnd; ofn.lpstrFile = szFilename; ofn.lpstrFilter = szFilter; ofn.lpstrInitialDir = szInitialDir; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_HIDEREADONLY; ofn.lpstrDefExt = _T("rtf"); if (GetSaveFileName(&ofn)) { stream.dwCookie = (DWORD_PTR)szFilename; stream.dwError = 0; stream.pfnCallback = Utils::StreamOut; SendDlgItemMessage(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG, EM_STREAMOUT, SF_RTF | SF_USECODEPAGE, (LPARAM) & stream); } } } /** * This is broadcasted by the container to all child windows to check if the * container can be autohidden or -closed. * * wParam is the autohide timeout (in seconds) * lParam points to a BOOL and a session which wants to prevent auto-hiding * the container must set it to FALSE. * * If no session in the container disagrees, the container will be hidden. */ void TSAPI DM_CheckAutoHide(const TWindowData* dat, WPARAM wParam, LPARAM lParam) { if (dat && lParam) { BOOL *fResult = (BOOL *)lParam; if (GetWindowTextLengthA(GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE)) > 0) { *fResult = FALSE; return; // text entered in the input area -> prevent autohide/cose } if (dat->dwUnread) { *fResult = FALSE; return; // unread events, do not hide or close the container } if (((GetTickCount() - dat->dwLastActivity) / 1000) <= wParam) *fResult = FALSE; // time since last activity did not yet reach the threshold. } } /** * checks if the balloon tooltip can be dismissed (usually called by * WM_MOUSEMOVE events */ void TSAPI DM_DismissTip(TWindowData *dat, const POINT& pt) { RECT rc; if (!IsWindowVisible(dat->hwndTip)) return; GetWindowRect(dat->hwndTip, &rc); if (PtInRect(&rc, pt)) return; if (abs(pt.x - dat->ptTipActivation.x) > 5 || abs(pt.y - dat->ptTipActivation.y) > 5) { SendMessage(dat->hwndTip, TTM_TRACKACTIVATE, FALSE, 0); dat->ptTipActivation.x = dat->ptTipActivation.y = 0; } } /** * initialize the balloon tooltip for message window notifications */ void TSAPI DM_InitTip(TWindowData *dat) { dat->hwndTip = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_BALLOON, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, dat->hwnd, NULL, g_hInst, (LPVOID) NULL); ZeroMemory((void*)&dat->ti, sizeof(dat->ti)); dat->ti.cbSize = sizeof(dat->ti); dat->ti.lpszText = PluginConfig.m_szNoStatus; dat->ti.hinst = g_hInst; dat->ti.hwnd = dat->hwnd; dat->ti.uFlags = TTF_TRACK | TTF_IDISHWND | TTF_TRANSPARENT; dat->ti.uId = (UINT_PTR)dat->hwnd; SendMessageA(dat->hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&dat->ti); SetWindowPos(dat->hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); } /** * checks generic hotkeys valid for both IM and MUC sessions * * returns 1 for handled hotkeys, 0 otherwise. */ LRESULT TSAPI DM_GenericHotkeysCheck(MSG *message, TWindowData *dat) { LRESULT mim_hotkey_check = CallService(MS_HOTKEY_CHECK, (WPARAM)message, (LPARAM)(TABSRMM_HK_SECTION_GENERIC)); HWND hwndDlg = dat->hwnd; switch(mim_hotkey_check) { case TABSRMM_HK_PASTEANDSEND: HandlePasteAndSend(dat); return 1; case TABSRMM_HK_HISTORY: SendMessage(hwndDlg, WM_COMMAND, IDC_HISTORY, 0); return 1; case TABSRMM_HK_CONTAINEROPTIONS: if (dat->pContainer->hWndOptions == 0) CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CONTAINEROPTIONS), dat->pContainer->hwnd, DlgProcContainerOptions, (LPARAM)dat->pContainer); return 1; case TABSRMM_HK_SEND: if (!(GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_STYLE) & ES_READONLY)) { PostMessage(hwndDlg, WM_COMMAND, IDOK, 0); return 1; } break; case TABSRMM_HK_TOGGLEINFOPANEL: dat->Panel->setActive(dat->Panel->isActive() ? FALSE : TRUE); dat->Panel->showHide(); return 1; case TABSRMM_HK_EMOTICONS: SendMessage(hwndDlg, WM_COMMAND, IDC_SMILEYBTN, 0); return 1; case TABSRMM_HK_TOGGLETOOLBAR: SendMessage(hwndDlg, WM_COMMAND, IDC_TOGGLETOOLBAR, 0); return 1; case TABSRMM_HK_CLEARLOG: ClearLog(dat); return 1; case TABSRMM_HK_TOGGLESIDEBAR: if (dat->pContainer->SideBar->isActive()) SendMessage(hwndDlg, WM_COMMAND, IDC_TOGGLESIDEBAR, 0); return 1; default: break; } return 0; } LRESULT TSAPI DM_MsgWindowCmdHandler(HWND hwndDlg, TContainerData *m_pContainer, TWindowData *dat, UINT cmd, WPARAM wParam, LPARAM lParam) { HWND hwndContainer = m_pContainer->hwnd; switch(cmd) { case IDC_FONTBOLD: case IDC_FONTITALIC: case IDC_FONTUNDERLINE: case IDC_FONTSTRIKEOUT: { CHARFORMAT2 cf, cfOld; int cmd = LOWORD(wParam); BOOL isBold, isItalic, isUnderline, isStrikeout; if (dat->SendFormat == 0) // dont use formatting if disabled break; ZeroMemory(&cf, sizeof(CHARFORMAT2)); ZeroMemory(&cfOld, sizeof(CHARFORMAT2)); cfOld.cbSize = cf.cbSize = sizeof(CHARFORMAT2); cfOld.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT; SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld); isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD); isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC); isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE); isStrikeout = (cfOld.dwEffects & CFM_STRIKEOUT) && (cfOld.dwMask & CFM_STRIKEOUT); if (cmd == IDC_FONTBOLD && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTBOLD))) break; if (cmd == IDC_FONTITALIC && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTITALIC))) break; if (cmd == IDC_FONTUNDERLINE && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTUNDERLINE))) break; if (cmd == IDC_FONTSTRIKEOUT && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FONTSTRIKEOUT))) break; if (cmd == IDC_FONTBOLD) { cf.dwEffects = isBold ? 0 : CFE_BOLD; cf.dwMask = CFM_BOLD; CheckDlgButton(hwndDlg, IDC_FONTBOLD, !isBold); } else if (cmd == IDC_FONTITALIC) { cf.dwEffects = isItalic ? 0 : CFE_ITALIC; cf.dwMask = CFM_ITALIC; CheckDlgButton(hwndDlg, IDC_FONTITALIC, !isItalic); } else if (cmd == IDC_FONTUNDERLINE) { cf.dwEffects = isUnderline ? 0 : CFE_UNDERLINE; cf.dwMask = CFM_UNDERLINE; CheckDlgButton(hwndDlg, IDC_FONTUNDERLINE, !isUnderline); } else if (cmd == IDC_FONTSTRIKEOUT) { cf.dwEffects = isStrikeout ? 0 : CFM_STRIKEOUT; cf.dwMask = CFM_STRIKEOUT; CheckDlgButton(hwndDlg, IDC_FONTSTRIKEOUT, !isStrikeout); } SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); break; } case IDC_FONTFACE: { HMENU submenu = GetSubMenu(m_pContainer->hMenuContext, 7); RECT rc; int iSelection, i; CHARFORMAT2 cf; ZeroMemory(&cf, sizeof(CHARFORMAT2)); cf.cbSize = sizeof(CHARFORMAT2); cf.dwMask = CFM_COLOR; cf.dwEffects = 0; GetWindowRect(GetDlgItem(hwndDlg, IDC_FONTFACE), &rc); iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); if (iSelection == ID_FONT_CLEARALLFORMATTING) { cf.dwMask = CFM_BOLD | CFM_COLOR | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT; cf.crTextColor = M->GetDword(FONTMODULE, "Font16Col", 0); SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); break; } if (iSelection == ID_FONT_DEFAULTCOLOR) { int i = 0; cf.crTextColor = M->GetDword(FONTMODULE, "Font16Col", 0); for (i=0; i < Utils::rtf_ctable_size; i++) { if (Utils::rtf_ctable[i].clr == cf.crTextColor) cf.crTextColor = RGB(GetRValue(cf.crTextColor), GetGValue(cf.crTextColor), GetBValue(cf.crTextColor) == 0 ? GetBValue(cf.crTextColor) + 1 : GetBValue(cf.crTextColor) - 1); } SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); break; } for (i=0; i < RTF_CTABLE_DEFSIZE; i++) { if (Utils::rtf_ctable[i].menuid == iSelection) { cf.crTextColor = Utils::rtf_ctable[i].clr; SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); } } break; } case IDCANCEL: { ShowWindow(hwndContainer, SW_MINIMIZE); return FALSE; } case IDC_SAVE: SendMessage(hwndDlg, WM_CLOSE, 1, 0); break; case IDC_NAME: { if (GetKeyState(VK_SHIFT) & 0x8000) // copy UIN SendMessage(hwndDlg, DM_UINTOCLIPBOARD, 0, 0); else { CallService(MS_USERINFO_SHOWDIALOG, (WPARAM) (dat->cache->getActiveContact()), 0); } break; } case IDC_HISTORY: CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM) dat->hContact, 0); break; case IDC_SMILEYBTN: if (dat->doSmileys && PluginConfig.g_SmileyAddAvail) { RECT rc; HANDLE hContact = dat->cache->getActiveContact(); if (CheckValidSmileyPack(dat->cache->getActiveProto(), hContact) != 0) { SMADD_SHOWSEL3 smaddInfo = {0}; if (lParam == 0) GetWindowRect(GetDlgItem(hwndDlg, IDC_SMILEYBTN), &rc); else GetWindowRect((HWND)lParam, &rc); smaddInfo.cbSize = sizeof(SMADD_SHOWSEL3); smaddInfo.hwndTarget = GetDlgItem(hwndDlg, IDC_MESSAGE); smaddInfo.targetMessage = EM_REPLACESEL; smaddInfo.targetWParam = TRUE; smaddInfo.Protocolname = const_cast(dat->cache->getActiveProto()); smaddInfo.Direction = 0; smaddInfo.xPosition = rc.left; smaddInfo.yPosition = rc.top + 24; smaddInfo.hwndParent = hwndContainer; smaddInfo.hContact = hContact; CallService(MS_SMILEYADD_SHOWSELECTION, (WPARAM)hwndContainer, (LPARAM) &smaddInfo); } } break; case IDC_TIME: { RECT rc; HMENU submenu = GetSubMenu(m_pContainer->hMenuContext, 2); int iSelection, isHandled; DWORD dwOldFlags = dat->dwFlags; DWORD dwOldEventIsShown = dat->dwFlagsEx; MsgWindowUpdateMenu(dat, submenu, MENU_LOGMENU); GetWindowRect(GetDlgItem(hwndDlg, IDC_TIME), &rc); iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); isHandled = MsgWindowMenuHandler(dat, iSelection, MENU_LOGMENU); return(isHandled); } case IDC_PROTOMENU: { RECT rc; HMENU submenu = GetSubMenu(m_pContainer->hMenuContext, 4); int iSelection; int iOldGlobalSendFormat = PluginConfig.m_SendFormat; if (dat->hContact) { int iLocalFormat = M->GetDword(dat->hContact, "sendformat", 0); int iNewLocalFormat = iLocalFormat; GetWindowRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), &rc); CheckMenuItem(submenu, ID_MODE_GLOBAL, MF_BYCOMMAND | (!(dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE) ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(submenu, ID_MODE_PRIVATE, MF_BYCOMMAND | (dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE ? MF_CHECKED : MF_UNCHECKED)); /* * formatting menu.. */ CheckMenuItem(submenu, ID_GLOBAL_BBCODE, MF_BYCOMMAND | ((PluginConfig.m_SendFormat) ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(submenu, ID_GLOBAL_OFF, MF_BYCOMMAND | ((PluginConfig.m_SendFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(submenu, ID_THISCONTACT_GLOBALSETTING, MF_BYCOMMAND | ((iLocalFormat == SENDFORMAT_NONE) ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(submenu, ID_THISCONTACT_BBCODE, MF_BYCOMMAND | ((iLocalFormat > 0) ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(submenu, ID_THISCONTACT_OFF, MF_BYCOMMAND | ((iLocalFormat == -1) ? MF_CHECKED : MF_UNCHECKED)); iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); switch (iSelection) { case ID_MODE_GLOBAL: dat->dwFlagsEx &= ~(MWF_SHOW_SPLITTEROVERRIDE); M->WriteByte(dat->hContact, SRMSGMOD_T, "splitoverride", 0); LoadSplitter(dat); AdjustBottomAvatarDisplay(dat); DM_RecalcPictureSize(dat); SendMessage(hwndDlg, WM_SIZE, 0, 0); break; case ID_MODE_PRIVATE: dat->dwFlagsEx |= MWF_SHOW_SPLITTEROVERRIDE; M->WriteByte(dat->hContact, SRMSGMOD_T, "splitoverride", 1); LoadSplitter(dat); AdjustBottomAvatarDisplay(dat); DM_RecalcPictureSize(dat); SendMessage(hwndDlg, WM_SIZE, 0, 0); break; case ID_GLOBAL_BBCODE: PluginConfig.m_SendFormat = SENDFORMAT_BBCODE; break; case ID_GLOBAL_OFF: PluginConfig.m_SendFormat = SENDFORMAT_NONE; break; case ID_THISCONTACT_GLOBALSETTING: iNewLocalFormat = 0; break; case ID_THISCONTACT_BBCODE: iNewLocalFormat = SENDFORMAT_BBCODE; break; case ID_THISCONTACT_OFF: iNewLocalFormat = -1; break; } if (iNewLocalFormat == 0) DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "sendformat"); else if (iNewLocalFormat != iLocalFormat) M->WriteDword(dat->hContact, SRMSGMOD_T, "sendformat", iNewLocalFormat); if (PluginConfig.m_SendFormat != iOldGlobalSendFormat) M->WriteByte(SRMSGMOD_T, "sendformat", (BYTE)PluginConfig.m_SendFormat); if (iNewLocalFormat != iLocalFormat || PluginConfig.m_SendFormat != iOldGlobalSendFormat) { dat->SendFormat = M->GetDword(dat->hContact, "sendformat", PluginConfig.m_SendFormat); if (dat->SendFormat == -1) // per contact override to disable it.. dat->SendFormat = 0; M->BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1); } } break; } case IDC_TOGGLETOOLBAR: if (lParam == 1) ApplyContainerSetting(m_pContainer, CNT_NOMENUBAR, m_pContainer->dwFlags & CNT_NOMENUBAR ? 0 : 1, true); else ApplyContainerSetting(m_pContainer, CNT_HIDETOOLBAR, m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1, true); break; case IDC_INFOPANELMENU: { RECT rc; int iSelection; HMENU submenu = GetSubMenu(m_pContainer->hMenuContext, 9); GetWindowRect(GetDlgItem(hwndDlg, IDC_NAME), &rc); EnableMenuItem(submenu, ID_FAVORITES_ADDCONTACTTOFAVORITES, !dat->cache->isFavorite() ? MF_ENABLED : MF_GRAYED); EnableMenuItem(submenu, ID_FAVORITES_REMOVECONTACTFROMFAVORITES, !dat->cache->isFavorite() ? MF_GRAYED : MF_ENABLED); iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); switch(iSelection) { case ID_FAVORITES_ADDCONTACTTOFAVORITES: DBWriteContactSettingByte(dat->hContact, SRMSGMOD_T, "isFavorite", 1); AddContactToFavorites(dat->hContact, dat->cache->getNick(), dat->cache->getActiveProto(), dat->szStatus, dat->wStatus, LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getActiveStatus()), 1, PluginConfig.g_hMenuFavorites); break; case ID_FAVORITES_REMOVECONTACTFROMFAVORITES: DBWriteContactSettingByte(dat->hContact, SRMSGMOD_T, "isFavorite", 0); DeleteMenu(PluginConfig.g_hMenuFavorites, (UINT_PTR)dat->hContact, MF_BYCOMMAND); break; default: break; } dat->cache->updateFavorite(); break; } case IDC_SENDMENU: { RECT rc; HMENU submenu = GetSubMenu(m_pContainer->hMenuContext, 3); int iSelection; GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rc); CheckMenuItem(submenu, ID_SENDMENU_SENDTOMULTIPLEUSERS, MF_BYCOMMAND | (dat->sendMode & SMODE_MULTIPLE ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(submenu, ID_SENDMENU_SENDDEFAULT, MF_BYCOMMAND | (dat->sendMode == 0 ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(submenu, ID_SENDMENU_SENDTOCONTAINER, MF_BYCOMMAND | (dat->sendMode & SMODE_CONTAINER ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(submenu, ID_SENDMENU_FORCEANSISEND, MF_BYCOMMAND | (dat->sendMode & SMODE_FORCEANSI ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(submenu, ID_SENDMENU_SENDLATER, MF_BYCOMMAND | (dat->sendMode & SMODE_SENDLATER ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(submenu, ID_SENDMENU_SENDWITHOUTTIMEOUTS, MF_BYCOMMAND | (dat->sendMode & SMODE_NOACK ? MF_CHECKED : MF_UNCHECKED)); { const char *szFinalProto = dat->cache->getActiveProto(); char szServiceName[128]; mir_snprintf(szServiceName, 128, "%s/SendNudge", szFinalProto); EnableMenuItem(submenu, ID_SENDMENU_SENDNUDGE, MF_BYCOMMAND | ((ServiceExists(szServiceName) && ServiceExists(MS_NUDGE_SEND)) ? MF_ENABLED : MF_GRAYED)); } if (lParam) iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); else iSelection = HIWORD(wParam); switch (iSelection) { case ID_SENDMENU_SENDTOMULTIPLEUSERS: dat->sendMode ^= SMODE_MULTIPLE; if (dat->sendMode & SMODE_MULTIPLE) HWND hwndClist = DM_CreateClist(dat); else { if (IsWindow(GetDlgItem(hwndDlg, IDC_CLIST))) DestroyWindow(GetDlgItem(hwndDlg, IDC_CLIST)); } break; case ID_SENDMENU_SENDNUDGE: SendNudge(dat); break; case ID_SENDMENU_SENDDEFAULT: dat->sendMode = 0; break; case ID_SENDMENU_SENDTOCONTAINER: dat->sendMode ^= SMODE_CONTAINER; RedrawWindow(hwndDlg, 0, 0, RDW_ERASENOW|RDW_UPDATENOW); break; case ID_SENDMENU_FORCEANSISEND: dat->sendMode ^= SMODE_FORCEANSI; break; case ID_SENDMENU_SENDLATER: if (sendLater->isAvail()) dat->sendMode ^= SMODE_SENDLATER; else CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK|MB_ICONINFORMATION, TranslateT("Configuration issue|The unattended send feature is disabled. The \\b1 send later\\b0 and \\b1 send to multiple contacts\\b0 features depend on it.\n\nYou must enable it under \\b1Options->Message Sessions->Advanced tweaks\\b0. Changing this option requires a restart.")); break; case ID_SENDMENU_SENDWITHOUTTIMEOUTS: dat->sendMode ^= SMODE_NOACK; if (dat->sendMode & SMODE_NOACK) M->WriteByte(dat->hContact, SRMSGMOD_T, "no_ack", 1); else DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "no_ack"); break; } M->WriteByte(dat->hContact, SRMSGMOD_T, "no_ack", (BYTE)(dat->sendMode & SMODE_NOACK ? 1 : 0)); M->WriteByte(dat->hContact, SRMSGMOD_T, "forceansi", (BYTE)(dat->sendMode & SMODE_FORCEANSI ? 1 : 0)); SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE); if (dat->sendMode & SMODE_MULTIPLE || dat->sendMode & SMODE_CONTAINER) { SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER| SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS); RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN); } else { if (IsWindow(GetDlgItem(hwndDlg, IDC_CLIST))) DestroyWindow(GetDlgItem(hwndDlg, IDC_CLIST)); SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER| SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS); RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN); } SendMessage(hwndContainer, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc); SendMessage(hwndDlg, WM_SIZE, 0, 0); DM_ScrollToBottom(dat, 1, 1); Utils::showDlgControl(hwndDlg, IDC_MULTISPLITTER, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE); Utils::showDlgControl(hwndDlg, IDC_CLIST, (dat->sendMode & SMODE_MULTIPLE) ? SW_SHOW : SW_HIDE); break; } case IDC_TOGGLESIDEBAR: { SendMessage(m_pContainer->hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0); break; } case IDC_PIC: { RECT rc; GetClientRect(hwndDlg, &rc); dat->fEditNotesActive = !dat->fEditNotesActive; if (dat->fEditNotesActive) { int iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)); if (iLen != 0) { SendMessage(hwndDlg, DM_ACTIVATETOOLTIP, IDC_MESSAGE, (LPARAM)TranslateT("You cannot edit user notes when there are unsent messages")); dat->fEditNotesActive = false; break; } if (!dat->fIsAutosizingInput) { dat->iSplitterSaved = dat->splitterY; dat->splitterY = rc.bottom / 2; SendMessage(hwndDlg, WM_SIZE, 1, 1); } DBVARIANT dbv = {0}; if (0 == M->GetTString(dat->hContact, "UserInfo", "MyNotes", &dbv)) { SetDlgItemText(hwndDlg, IDC_MESSAGE, dbv.ptszVal); mir_free(dbv.ptszVal); } } else { int iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)); TCHAR *buf = (TCHAR *)mir_alloc((iLen + 2) * sizeof(TCHAR)); GetDlgItemText(hwndDlg, IDC_MESSAGE, buf, iLen + 1); M->WriteTString(dat->hContact, "UserInfo", "MyNotes", buf); SetDlgItemText(hwndDlg, IDC_MESSAGE, _T("")); if (!dat->fIsAutosizingInput) { dat->splitterY = dat->iSplitterSaved; SendMessage(hwndDlg, WM_SIZE, 0, 0); DM_ScrollToBottom(dat, 0, 1); } } SetWindowPos(GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 0, 0, 0, 0, SWP_DRAWFRAME|SWP_FRAMECHANGED|SWP_NOZORDER| SWP_NOMOVE|SWP_NOSIZE|SWP_NOCOPYBITS); RedrawWindow(hwndDlg, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME|RDW_UPDATENOW|RDW_ALLCHILDREN); if (dat->fEditNotesActive) CWarning::show(CWarning::WARN_EDITUSERNOTES, MB_OK|MB_ICONINFORMATION); break; } case IDM_CLEAR: ClearLog(dat); break; case IDC_PROTOCOL: { RECT rc; int iSel = 0; HMENU hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) dat->hContact, 0); if (lParam == 0) GetWindowRect(GetDlgItem(hwndDlg, IDC_PROTOCOL/*IDC_NAME*/), &rc); else GetWindowRect((HWND)lParam, &rc); iSel = TrackPopupMenu(hMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); if (iSel) CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(iSel), MPCF_CONTACTMENU), (LPARAM) dat->hContact); DestroyMenu(hMenu); break; } // error control case IDC_CANCELSEND: SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_CANCEL, 0); break; case IDC_RETRY: SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_RETRY, 0); break; case IDC_MSGSENDLATER: SendMessage(hwndDlg, DM_ERRORDECIDED, MSGERROR_SENDLATER, 0); break; case IDC_SELFTYPING: if (dat->hContact) { int iCurrentTypingMode = M->GetByte(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M->GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)); if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && iCurrentTypingMode) { DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF); dat->nTypeMode = PROTOTYPE_SELFTYPING_OFF; } M->WriteByte(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, (BYTE)!iCurrentTypingMode); } break; default: return 0; } return 1; } LRESULT TSAPI DM_ContainerCmdHandler(TContainerData *pContainer, UINT cmd, WPARAM wParam, LPARAM lParam) { if (!pContainer) return 0; HWND hwndDlg = pContainer->hwnd; switch(cmd) { case IDC_CLOSE: SendMessage(hwndDlg, WM_SYSCOMMAND, SC_CLOSE, 0); break; case IDC_MINIMIZE: PostMessage(hwndDlg, WM_SYSCOMMAND, SC_MINIMIZE, 0); break; case IDC_MAXIMIZE: SendMessage(hwndDlg, WM_SYSCOMMAND, IsZoomed(hwndDlg) ? SC_RESTORE : SC_MAXIMIZE, 0); break; case IDOK: SendMessage(pContainer->hwndActive, WM_COMMAND, wParam, lParam); // pass the IDOK command to the active child - fixes the "enter not working break; case ID_FILE_SAVEMESSAGELOGAS: SendMessage(pContainer->hwndActive, DM_SAVEMESSAGELOG, 0, 0); break; case ID_FILE_CLOSEMESSAGESESSION: PostMessage(pContainer->hwndActive, WM_CLOSE, 0, 1); break; case ID_FILE_CLOSE: PostMessage(hwndDlg, WM_CLOSE, 0, 1); break; case ID_VIEW_SHOWSTATUSBAR: ApplyContainerSetting(pContainer, CNT_NOSTATUSBAR, pContainer->dwFlags & CNT_NOSTATUSBAR ? 0 : 1, true); break; case ID_VIEW_VERTICALMAXIMIZE: ApplyContainerSetting(pContainer, CNT_VERTICALMAX, pContainer->dwFlags & CNT_VERTICALMAX ? 0 : 1, false); break; case ID_VIEW_BOTTOMTOOLBAR: ApplyContainerSetting(pContainer, CNT_BOTTOMTOOLBAR, pContainer->dwFlags & CNT_BOTTOMTOOLBAR ? 0 : 1, false); M->BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1); return 0; case ID_VIEW_SHOWTOOLBAR: ApplyContainerSetting(pContainer, CNT_HIDETOOLBAR, pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1, false); M->BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1); return 0; case ID_VIEW_SHOWMENUBAR: ApplyContainerSetting(pContainer, CNT_NOMENUBAR, pContainer->dwFlags & CNT_NOMENUBAR ? 0 : 1, true); break; case ID_VIEW_SHOWTITLEBAR: ApplyContainerSetting(pContainer, CNT_NOTITLE, pContainer->dwFlags & CNT_NOTITLE ? 0 : 1, true); break; case ID_VIEW_TABSATBOTTOM: ApplyContainerSetting(pContainer, CNT_TABSBOTTOM, pContainer->dwFlags & CNT_TABSBOTTOM ? 0 : 1, false); break; case ID_VIEW_SHOWMULTISENDCONTACTLIST: SendMessage(pContainer->hwndActive, WM_COMMAND, MAKEWPARAM(IDC_SENDMENU, ID_SENDMENU_SENDTOMULTIPLEUSERS), 0); break; case ID_VIEW_STAYONTOP: SendMessage(hwndDlg, WM_SYSCOMMAND, IDM_STAYONTOP, 0); break; case ID_CONTAINER_CONTAINEROPTIONS: SendMessage(hwndDlg, WM_SYSCOMMAND, IDM_MOREOPTIONS, 0); break; case ID_EVENTPOPUPS_DISABLEALLEVENTPOPUPS: ApplyContainerSetting(pContainer, (CNT_DONTREPORT | CNT_DONTREPORTUNFOCUSED | CNT_DONTREPORTFOCUSED | CNT_ALWAYSREPORTINACTIVE), 0, false); return 0; case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISMINIMIZED: ApplyContainerSetting(pContainer, CNT_DONTREPORT, pContainer->dwFlags & CNT_DONTREPORT ? 0 : 1, false); return 0; case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISUNFOCUSED: ApplyContainerSetting(pContainer, CNT_DONTREPORTUNFOCUSED, pContainer->dwFlags & CNT_DONTREPORTUNFOCUSED ? 0 : 1, false); return 0; case ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISFOCUSED: ApplyContainerSetting(pContainer, CNT_DONTREPORTFOCUSED, pContainer->dwFlags & CNT_DONTREPORTFOCUSED ? 0 : 1, false); return 0; case ID_EVENTPOPUPS_SHOWPOPUPSFORALLINACTIVESESSIONS: ApplyContainerSetting(pContainer, CNT_ALWAYSREPORTINACTIVE, pContainer->dwFlags & CNT_ALWAYSREPORTINACTIVE ? 0 : 1, false); return 0; case ID_WINDOWFLASHING_DISABLEFLASHING: ApplyContainerSetting(pContainer, CNT_NOFLASH, 1, false); ApplyContainerSetting(pContainer, CNT_FLASHALWAYS, 0, false); return 0; case ID_WINDOWFLASHING_FLASHUNTILFOCUSED: ApplyContainerSetting(pContainer, CNT_NOFLASH, 0, false); ApplyContainerSetting(pContainer, CNT_FLASHALWAYS, 1, false); return 0; case ID_WINDOWFLASHING_USEDEFAULTVALUES: ApplyContainerSetting(pContainer, (CNT_NOFLASH | CNT_FLASHALWAYS), 0, false); return 0; case ID_OPTIONS_SAVECURRENTWINDOWPOSITIONASDEFAULT: { WINDOWPLACEMENT wp = {0}; wp.length = sizeof(wp); if (GetWindowPlacement(hwndDlg, &wp)) { M->WriteDword(SRMSGMOD_T, "splitx", wp.rcNormalPosition.left); M->WriteDword(SRMSGMOD_T, "splity", wp.rcNormalPosition.top); M->WriteDword(SRMSGMOD_T, "splitwidth", wp.rcNormalPosition.right - wp.rcNormalPosition.left); M->WriteDword(SRMSGMOD_T, "splitheight", wp.rcNormalPosition.bottom - wp.rcNormalPosition.top); } return 0; } case ID_VIEW_INFOPANEL: { TWindowData *dat = (TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA); if (dat) { RECT rc; POINT pt; GetWindowRect(pContainer->hwndActive, &rc); pt.x = rc.left + 10; pt.y = rc.top + dat->Panel->getHeight() - 10; dat->Panel->invokeConfigDialog(pt); } return 0; } /* * commands from the message log popup will be routed to the * message log menu handler */ case ID_MESSAGELOGSETTINGS_FORTHISCONTACT: case ID_MESSAGELOGSETTINGS_GLOBAL: { struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA); if (dat) { MsgWindowMenuHandler(dat, (int)LOWORD(wParam), MENU_LOGMENU); return 1; } break; } case ID_HELP_ABOUTTABSRMM: CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_ABOUT), 0, DlgProcAbout, 0); break; default: return 0; // not handled } return 1; // handled } /** * initialize rich edit control (log and edit control) for both MUC and * standard IM session windows. */ void TSAPI DM_InitRichEdit(TWindowData *dat) { char* szStreamOut = NULL; SETTEXTEX stx = {ST_DEFAULT, CP_UTF8}; COLORREF colour; COLORREF inputcharcolor; CHARFORMAT2A cf2; LOGFONTA lf; int i = 0; bool fIsChat = ((dat->bType == SESSIONTYPE_CHAT) ? true : false); HWND hwndLog = GetDlgItem(dat->hwnd, !fIsChat ? IDC_LOG : IDC_CHAT_LOG); HWND hwndEdit= GetDlgItem(dat->hwnd, !fIsChat ? IDC_MESSAGE : IDC_CHAT_MESSAGE); HWND hwndDlg = dat->hwnd; ZeroMemory(&cf2, sizeof(CHARFORMAT2A)); dat->inputbg = fIsChat ? M->GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR) : dat->pContainer->theme.inputbg; colour = fIsChat ? M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR_MUC, SRMSGDEFSET_BKGCOLOUR) : dat->pContainer->theme.bg; if (!fIsChat) { if (GetWindowTextLengthA(hwndEdit) > 0) szStreamOut = Message_GetFromStream(hwndEdit, dat, (CP_UTF8 << 16) | (SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE)); } SendMessage(hwndLog, EM_SETBKGNDCOLOR, 0, colour); SendMessage(hwndEdit, EM_SETBKGNDCOLOR, 0, dat->inputbg); if (fIsChat) LoadLogfont(MSGFONTID_MESSAGEAREA, &lf, &inputcharcolor, FONTMODULE); else { lf = dat->pContainer->theme.logFonts[MSGFONTID_MESSAGEAREA]; inputcharcolor = dat->pContainer->theme.fontColors[MSGFONTID_MESSAGEAREA]; } /* * correct the input area text color to avoid a color from the table of usable bbcode colors */ if (!fIsChat) { for (i=0; i < Utils::rtf_ctable_size; i++) { if (Utils::rtf_ctable[i].clr == inputcharcolor) inputcharcolor = RGB(GetRValue(inputcharcolor), GetGValue(inputcharcolor), GetBValue(inputcharcolor) == 0 ? GetBValue(inputcharcolor) + 1 : GetBValue(inputcharcolor) - 1); } } if (fIsChat) { cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_ITALIC | CFM_BACKCOLOR; cf2.cbSize = sizeof(cf2); cf2.crTextColor = inputcharcolor; cf2.bCharSet = lf.lfCharSet; cf2.crBackColor = dat->inputbg; strncpy(cf2.szFaceName, lf.lfFaceName, LF_FACESIZE); cf2.dwEffects = 0; cf2.wWeight = (WORD)lf.lfWeight; cf2.bPitchAndFamily = lf.lfPitchAndFamily; cf2.yHeight = abs(lf.lfHeight) * 15; SetWindowText(hwndEdit, _T("")); SendMessage(hwndEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); } else { cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_BOLD | CFM_ITALIC; cf2.cbSize = sizeof(cf2); cf2.crTextColor = inputcharcolor; cf2.bCharSet = lf.lfCharSet; strncpy(cf2.szFaceName, lf.lfFaceName, LF_FACESIZE); cf2.dwEffects = ((lf.lfWeight >= FW_BOLD) ? CFE_BOLD : 0) | (lf.lfItalic ? CFE_ITALIC : 0)|(lf.lfUnderline ? CFE_UNDERLINE : 0)|(lf.lfStrikeOut ? CFE_STRIKEOUT : 0); cf2.wWeight = (WORD)lf.lfWeight; cf2.bPitchAndFamily = lf.lfPitchAndFamily; cf2.yHeight = abs(lf.lfHeight) * 15; SendMessageA(hwndEdit, EM_SETCHARFORMAT, 0, (LPARAM)&cf2); } /* * setup the rich edit control(s) * LOG is always set to RTL, because this is needed for proper bidirectional operation later. * The real text direction is then enforced by the streaming code which adds appropiate paragraph * and textflow formatting commands to the */ PARAFORMAT2 pf2; ZeroMemory(&pf2, sizeof(PARAFORMAT2)); pf2.cbSize = sizeof(pf2); pf2.wEffects = PFE_RTLPARA; pf2.dwMask = PFM_RTLPARA; if (Utils::FindRTLLocale(dat)) SendMessage(hwndEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); if (!(dat->dwFlags & MWF_LOG_RTL)) { pf2.wEffects = 0; SendMessage(hwndEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); } SendMessage(hwndEdit, EM_SETLANGOPTIONS, 0, (LPARAM) SendMessage(hwndEdit, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); pf2.wEffects = PFE_RTLPARA; pf2.dwMask |= PFM_OFFSET; if (dat->dwFlags & MWF_INITMODE) { pf2.dwMask |= (PFM_RIGHTINDENT | PFM_OFFSETINDENT); pf2.dxStartIndent = 30; pf2.dxRightIndent = 30; } pf2.dxOffset = dat->pContainer->theme.left_indent + 30; if (!fIsChat) { SetWindowText(hwndLog, _T("")); SendMessage(hwndLog, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); SendMessage(hwndLog, EM_SETLANGOPTIONS, 0, (LPARAM) SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); } /* * set the scrollbars etc to RTL/LTR (only for manual RTL mode) */ if (!fIsChat) { if (dat->dwFlags & MWF_LOG_RTL) { SetWindowLongPtr(hwndEdit, GWL_EXSTYLE, GetWindowLongPtr(hwndEdit, GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR); SetWindowLongPtr(hwndLog, GWL_EXSTYLE, GetWindowLongPtr(hwndLog, GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR); } else { SetWindowLongPtr(hwndEdit, GWL_EXSTYLE, GetWindowLongPtr(hwndEdit, GWL_EXSTYLE) &~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR)); SetWindowLongPtr(hwndLog, GWL_EXSTYLE, GetWindowLongPtr(hwndLog, GWL_EXSTYLE) &~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR)); } SetWindowText(hwndEdit, _T("")); } if (szStreamOut != NULL) { SendMessage(hwndEdit, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szStreamOut); free(szStreamOut); } } /* * action and callback procedures for the stock button objects */ static void BTN_StockAction(ButtonItem *item, HWND hwndDlg, struct TWindowData *dat, HWND hwndBtn) { if (item->dwStockFlags & SBI_HANDLEBYCLIENT && IsWindow(hwndDlg) && dat) SendMessage(hwndDlg, WM_COMMAND, MAKELONG(item->uId, BN_CLICKED), (LPARAM)hwndBtn); else { switch (item->uId) { case IDC_SBAR_CANCEL: PostMessage(hwndDlg, WM_COMMAND, MAKELONG(IDC_SAVE, BN_CLICKED), (LPARAM)hwndBtn); break; case IDC_SBAR_SLIST: SendMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_LBUTTONUP); break; case IDC_SBAR_FAVORITES: { POINT pt; int iSelection; GetCursorPos(&pt); iSelection = TrackPopupMenu(PluginConfig.g_hMenuFavorites, TPM_RETURNCMD, pt.x, pt.y, 0, PluginConfig.g_hwndHotkeyHandler, NULL); HandleMenuEntryFromhContact(iSelection); break; } case IDC_SBAR_RECENT: { POINT pt; int iSelection; GetCursorPos(&pt); iSelection = TrackPopupMenu(PluginConfig.g_hMenuRecent, TPM_RETURNCMD, pt.x, pt.y, 0, PluginConfig.g_hwndHotkeyHandler, NULL); HandleMenuEntryFromhContact(iSelection); break; } case IDC_SBAR_USERPREFS: { HANDLE hContact = 0; SendMessage(hwndDlg, DM_QUERYHCONTACT, 0, (LPARAM)&hContact); if (hContact != 0) CallService(MS_TABMSG_SETUSERPREFS, (WPARAM)hContact, 0); break; } case IDC_SBAR_TOGGLEFORMAT: { if (dat) { if (IsDlgButtonChecked(hwndDlg, IDC_SBAR_TOGGLEFORMAT) == BST_UNCHECKED) { dat->SendFormat = 0; GetSendFormat(dat, 0); } else { dat->SendFormat = SENDFORMAT_BBCODE; GetSendFormat(dat, 0); } } break; } } } } static void BTN_StockCallback(ButtonItem *item, HWND hwndDlg, struct TWindowData *dat, HWND hwndBtn) { } /* * predefined button objects for customizeable buttons */ static struct SIDEBARITEM sbarItems[] = { 0, 0, 0, 0, 0, _T(""), NULL, NULL, _T("") }; int TSAPI BTN_GetStockItem(ButtonItem *item, const TCHAR *szName) { int i = 0; while (sbarItems[i].uId) { if (!_tcsicmp(sbarItems[i].szName, szName)) { item->uId = sbarItems[i].uId; //item->dwFlags |= BUTTON_ISSIDEBAR; //myGlobals.m_SideBarEnabled = TRUE; if (item->dwFlags & BUTTON_ISSIDEBAR) { if (sbarItems[i].dwFlags & SBI_TOP) item->yOff = 0; else if (sbarItems[i].dwFlags & SBI_BOTTOM) item->yOff = -1; } item->dwStockFlags = sbarItems[i].dwFlags; item->dwFlags = sbarItems[i].dwFlags & SBI_TOGGLE ? item->dwFlags | BUTTON_ISTOGGLE : item->dwFlags & ~BUTTON_ISTOGGLE; item->pfnAction = sbarItems[i].pfnAction; item->pfnCallback = sbarItems[i].pfnCallback; lstrcpyn(item->szTip, sbarItems[i].tszTip, 256); item->szTip[255] = 0; if (sbarItems[i].hIcon) { item->normalGlyphMetrics[0] = (LONG_PTR)sbarItems[i].hIcon; item->dwFlags |= BUTTON_NORMALGLYPHISICON; } if (sbarItems[i].hIconPressed) { item->pressedGlyphMetrics[0] = (LONG_PTR)sbarItems[i].hIconPressed; item->dwFlags |= BUTTON_PRESSEDGLYPHISICON; } if (sbarItems[i].hIconHover) { item->hoverGlyphMetrics[0] = (LONG_PTR)sbarItems[i].hIconHover; item->dwFlags |= BUTTON_HOVERGLYPHISICON; } return 1; } i++; } return 0; } /* * set the states of defined database action buttons (only if button is a toggle) */ void TSAPI DM_SetDBButtonStates(HWND hwndChild, struct TWindowData *dat) { ButtonItem *buttonItem = dat->pContainer->buttonItems; HANDLE hContact = dat->hContact, hFinalContact = 0; char *szModule, *szSetting; HWND hwndContainer = dat->pContainer->hwnd;; while (buttonItem) { BOOL result = FALSE; HWND hWnd = GetDlgItem(hwndContainer, buttonItem->uId); if (buttonItem->pfnCallback) buttonItem->pfnCallback(buttonItem, hwndChild, dat, hWnd); if (!(buttonItem->dwFlags & BUTTON_ISTOGGLE && buttonItem->dwFlags & BUTTON_ISDBACTION)) { buttonItem = buttonItem->nextItem; continue; } szModule = buttonItem->szModule; szSetting = buttonItem->szSetting; if (buttonItem->dwFlags & BUTTON_DBACTIONONCONTACT || buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION) { if (hContact == 0) { SendMessage(hWnd, BM_SETCHECK, BST_UNCHECKED, 0); buttonItem = buttonItem->nextItem; continue; } if (buttonItem->dwFlags & BUTTON_ISCONTACTDBACTION) szModule = GetContactProto(hContact); hFinalContact = hContact; } else hFinalContact = 0; if (buttonItem->type == DBVT_ASCIIZ) { DBVARIANT dbv = {0}; if (!DBGetContactSettingString(hFinalContact, szModule, szSetting, &dbv)) { result = !strcmp((char *)buttonItem->bValuePush, dbv.pszVal); DBFreeVariant(&dbv); } } else { switch (buttonItem->type) { case DBVT_BYTE: { BYTE val = M->GetByte(hFinalContact, szModule, szSetting, 0); result = (val == buttonItem->bValuePush[0]); break; } case DBVT_WORD: { WORD val = DBGetContactSettingWord(hFinalContact, szModule, szSetting, 0); result = (val == *((WORD *) & buttonItem->bValuePush)); break; } case DBVT_DWORD: { DWORD val = M->GetDword(hFinalContact, szModule, szSetting, 0); result = (val == *((DWORD *) & buttonItem->bValuePush)); break; } } } SendMessage(hWnd, BM_SETCHECK, (WPARAM)result, 0); buttonItem = buttonItem->nextItem; } } LRESULT TSAPI DM_ScrollToBottom(TWindowData *dat, WPARAM wParam, LPARAM lParam) { if (dat) { if (dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED) return 0; if (IsIconic(dat->pContainer->hwnd)) dat->dwFlags |= MWF_DEFERREDSCROLL; if (dat->hwndIEView) { PostMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0); return 0; } else if (dat->hwndHPP) { SendMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0); return 0; } else { HWND hwnd = GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG); if (lParam) SendMessage(hwnd, WM_SIZE, 0, 0); if (wParam == 1 && lParam == 1) { RECT rc; int len; GetClientRect(hwnd, &rc); len = GetWindowTextLengthA(hwnd); SendMessage(hwnd, EM_SETSEL, len - 1, len - 1); } if (wParam) SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); else PostMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); if (lParam) InvalidateRect(hwnd, NULL, FALSE); } } return 0; } static unsigned __stdcall LoadKLThread(LPVOID vParam) { HANDLE hContact = reinterpret_cast(vParam); DBVARIANT dbv = {0}; LRESULT res = M->GetTString(hContact, SRMSGMOD_T, "locale", &dbv); if (res == 0) { HKL hkl = LoadKeyboardLayout(dbv.ptszVal, 0); PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SETLOCALE, (WPARAM)hContact, (LPARAM)hkl); DBFreeVariant(&dbv); } return 0; } LRESULT TSAPI DM_LoadLocale(TWindowData *dat) { /* * set locale if saved to contact */ if (dat) { if (dat->dwFlags & MWF_WASBACKGROUNDCREATE) return 0; if (PluginConfig.m_AutoLocaleSupport) { DBVARIANT dbv; int res; TCHAR szKLName[KL_NAMELENGTH+1]; UINT flags = KLF_ACTIVATE; res = DBGetContactSettingTString(dat->hContact, SRMSGMOD_T, "locale", &dbv); if (res == 0) { /* dat->hkl = LoadKeyboardLayout(dbv.ptszVal, KLF_REPLACELANG | KLF_NOTELLSHELL); GetLocaleID(dat, dbv.ptszVal); PostMessage(dat->hwnd, DM_SETLOCALE, 0, 0);*/ DBFreeVariant(&dbv); CloseHandle((HANDLE)mir_forkthreadex(LoadKLThread, dat->hContact, NULL)); } else { if (!PluginConfig.m_dontUseDefaultKbd) { TCHAR szBuf[20]; GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, szBuf, 20); mir_sntprintf(szKLName, KL_NAMELENGTH, _T("0000%s"), szBuf); M->WriteTString(dat->hContact, SRMSGMOD_T, "locale", szKLName); } else { GetKeyboardLayoutName(szKLName); M->WriteTString(dat->hContact, SRMSGMOD_T, "locale", szKLName); } /*dat->hkl = LoadKeyboardLayout(szKLName, KLF_NOTELLSHELL | KLF_REPLACELANG); GetLocaleID(dat, szKLName); PostMessage(dat->hwnd, DM_SETLOCALE, 0, 0);*/ CloseHandle((HANDLE)mir_forkthreadex(LoadKLThread, reinterpret_cast(dat->hContact), NULL)); } } } return 0; } LRESULT TSAPI DM_RecalcPictureSize(TWindowData *dat) { BITMAP bminfo; HBITMAP hbm; if (dat) { hbm = ((dat->Panel->isActive()) && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown); if (hbm == 0) { dat->pic.cy = dat->pic.cx = 60; return 0; } GetObject(hbm, sizeof(bminfo), &bminfo); CalcDynamicAvatarSize(dat, &bminfo); SendMessage(dat->hwnd, WM_SIZE, 0, 0); } return 0; } LRESULT TSAPI DM_UpdateLastMessage(const TWindowData *dat) { if (dat) { if (dat->pContainer->hwndStatus == 0) return 0; if (dat->pContainer->hwndActive != dat->hwnd) return 0; if (dat->showTyping) { TCHAR szBuf[80]; mir_sntprintf(szBuf, safe_sizeof(szBuf), TranslateT("%s is typing a message."), dat->cache->getNick()); SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM) szBuf); SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, (LPARAM) PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); return 0; } else SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, 0); if (dat->lastMessage || dat->pContainer->dwFlags & CNT_UINSTATUSBAR) { TCHAR date[64], time[64]; if (!(dat->pContainer->dwFlags & CNT_UINSTATUSBAR)) { tmi.printTimeStamp(NULL, dat->lastMessage, _T("d"), date, safe_sizeof(date), 0); if (dat->pContainer->dwFlags & CNT_UINSTATUSBAR && lstrlen(date) > 6) date[lstrlen(date) - 5] = 0; tmi.printTimeStamp(NULL, dat->lastMessage, _T("t"), time, safe_sizeof(time), 0); } if (dat->pContainer->dwFlags & CNT_UINSTATUSBAR) { TCHAR fmt[100]; mir_sntprintf(fmt, safe_sizeof(fmt), _T("UID: %s"), dat->cache->getUIN()); SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)fmt); } else { TCHAR fmt[100]; mir_sntprintf(fmt, safe_sizeof(fmt), TranslateT("Last received: %s at %s"), date, time); SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM) fmt); } } else SendMessageA(dat->pContainer->hwndStatus, SB_SETTEXTA, 0, (LPARAM) ""); } return 0; } /* * save current keyboard layout for the given contact */ LRESULT TSAPI DM_SaveLocale(TWindowData *dat, WPARAM wParam, LPARAM lParam) { if (dat) { if (PluginConfig.m_AutoLocaleSupport && dat->hContact && dat->pContainer->hwndActive == dat->hwnd) { TCHAR szKLName[KL_NAMELENGTH + 1]; if ((HKL)lParam != dat->hkl) { dat->hkl = (HKL)lParam; ActivateKeyboardLayout(dat->hkl, 0); GetKeyboardLayoutName(szKLName); M->WriteTString(dat->hContact, SRMSGMOD_T, "locale", szKLName); GetLocaleID(dat, szKLName); UpdateReadChars(dat); } } } return 0; } /* * generic handler for the WM_COPY message in message log/chat history richedit control(s). * it filters out the invisible event boundary markers from the text copied to the clipboard. */ LRESULT TSAPI DM_WMCopyHandler(HWND hwnd, WNDPROC oldWndProc, WPARAM wParam, LPARAM lParam) { LRESULT result = CallWindowProc(oldWndProc, hwnd, WM_COPY, wParam, lParam); if (OpenClipboard(hwnd)) { HANDLE hClip = GetClipboardData(CF_UNICODETEXT); if (hClip) { HGLOBAL hgbl; TCHAR *tszLocked; TCHAR *tszText = (TCHAR *)malloc((lstrlen((TCHAR *)hClip) + 2) * sizeof(TCHAR)); lstrcpy(tszText, (TCHAR *)hClip); Utils::FilterEventMarkers(tszText); EmptyClipboard(); hgbl = GlobalAlloc(GMEM_MOVEABLE, (lstrlen(tszText) + 1) * sizeof(TCHAR)); tszLocked = (TCHAR *)GlobalLock(hgbl); lstrcpy(tszLocked, tszText); GlobalUnlock(hgbl); SetClipboardData(CF_UNICODETEXT, hgbl); if (tszText) free(tszText); } CloseClipboard(); } return result; } /* * create embedded contact list control */ HWND TSAPI DM_CreateClist(TWindowData *dat) { if (!sendLater->isAvail()) { CWarning::show(CWarning::WARN_NO_SENDLATER, MB_OK|MB_ICONINFORMATION, TranslateT("Configuration issue|The unattended send feature is disabled. The \\b1 send later\\b0 and \\b1 send to multiple contacts\\b0 features depend on it.\n\nYou must enable it under \\b1Options->Message Sessions->Advanced tweaks\\b0. Changing this option requires a restart.")); dat->sendMode &= ~SMODE_MULTIPLE; return 0; } HWND hwndClist = CreateWindowExA(0, "CListControl", "", WS_TABSTOP | WS_VISIBLE | WS_CHILD | 0x248, 184, 0, 30, 30, dat->hwnd, (HMENU)IDC_CLIST, g_hInst, NULL); //MAD: fix for little bug, when following code didn't work (another hack :)) HANDLE hItem; SendMessage(hwndClist, WM_TIMER, 14, 0); // hItem = (HANDLE) SendMessage(hwndClist, CLM_FINDCONTACT, (WPARAM) dat->hContact, 0); SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) & ~CLS_EX_TRACKSELECT); SetWindowLongPtr(hwndClist, GWL_EXSTYLE, GetWindowLongPtr(hwndClist, GWL_EXSTYLE) | (CLS_EX_NOSMOOTHSCROLLING | CLS_EX_NOTRANSLUCENTSEL)); //MAD: show offline contacts in multi-send if (!PluginConfig.m_AllowOfflineMultisend) SetWindowLongPtr(hwndClist, GWL_STYLE, GetWindowLongPtr(hwndClist, GWL_STYLE) | CLS_HIDEOFFLINE); // if (hItem) SendMessage(hwndClist, CLM_SETCHECKMARK, (WPARAM) hItem, 1); if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_DISABLEGROUPS && !M->GetByte("CList", "UseGroups", SETTING_USEGROUPS_DEFAULT)) SendMessage(hwndClist, CLM_SETUSEGROUPS, (WPARAM) FALSE, 0); else SendMessage(hwndClist, CLM_SETUSEGROUPS, (WPARAM) TRUE, 0); if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_HIDEEMPTYGROUPS && M->GetByte("CList", "HideEmptyGroups", SETTING_USEGROUPS_DEFAULT)) SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, (WPARAM) TRUE, 0); else SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, (WPARAM) FALSE, 0); SendMessage(hwndClist, CLM_FIRST + 106, 0, 1); SendMessage(hwndClist, CLM_AUTOREBUILD, 0, 0); if (hwndClist) RedrawWindow(hwndClist, 0, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW); return hwndClist; } LRESULT TSAPI DM_MouseWheelHandler(HWND hwnd, HWND hwndParent, struct TWindowData *mwdat, WPARAM wParam, LPARAM lParam) { RECT rc, rc1; POINT pt; TCHITTESTINFO hti; HWND hwndTab; UINT uID = mwdat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG; UINT uIDMsg = mwdat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE; GetCursorPos(&pt); GetWindowRect(hwnd, &rc); if (PtInRect(&rc, pt)) return 1; if (mwdat->pContainer->dwFlags & CNT_SIDEBAR) { GetWindowRect(GetDlgItem(mwdat->pContainer->hwnd, IDC_SIDEBARUP), &rc); GetWindowRect(GetDlgItem(mwdat->pContainer->hwnd, IDC_SIDEBARDOWN), &rc1); rc.bottom = rc1.bottom; if (PtInRect(&rc, pt)) { short amount = (short)(HIWORD(wParam)); SendMessage(mwdat->pContainer->hwnd, WM_COMMAND, MAKELONG(amount > 0 ? IDC_SIDEBARUP : IDC_SIDEBARDOWN, 0), (LPARAM)uIDMsg); return 0; } } if (mwdat->bType == SESSIONTYPE_CHAT) { // scroll nick list by just hovering it RECT rcNicklist; GetWindowRect(GetDlgItem(mwdat->hwnd, IDC_LIST), &rcNicklist); if (PtInRect(&rcNicklist, pt)) { SendMessage(GetDlgItem(mwdat->hwnd, IDC_LIST), WM_MOUSEWHEEL, wParam, lParam); return 0; } } if (mwdat->hwndIEView) GetWindowRect(mwdat->hwndIEView, &rc); else if (mwdat->hwndHPP) GetWindowRect(mwdat->hwndHPP, &rc); else GetWindowRect(GetDlgItem(hwndParent, uID), &rc); if (PtInRect(&rc, pt)) { HWND hwnd = (mwdat->hwndIEView || mwdat->hwndHPP) ? mwdat->hwndIWebBrowserControl : GetDlgItem(hwndParent, uID); short wDirection = (short)HIWORD(wParam); if (hwnd == 0) hwnd = WindowFromPoint(pt); if (LOWORD(wParam) & MK_SHIFT || M->GetByte("fastscroll", 0)) { if (wDirection < 0) SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), 0); else if (wDirection > 0) SendMessage(hwnd, WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), 0); } else SendMessage(hwnd, WM_MOUSEWHEEL, wParam, lParam); return 0; } hwndTab = GetDlgItem(mwdat->pContainer->hwnd, IDC_MSGTABS); GetCursorPos(&hti.pt); ScreenToClient(hwndTab, &hti.pt); hti.flags = 0; if (TabCtrl_HitTest(hwndTab, &hti) != -1) { SendMessage(hwndTab, WM_MOUSEWHEEL, wParam, -1); return 0; } return 1; } void TSAPI DM_FreeTheme(TWindowData *dat) { if (dat) { if (CMimAPI::m_pfnCloseThemeData) { if (dat->hTheme) { CMimAPI::m_pfnCloseThemeData(dat->hTheme); dat->hTheme = 0; } if (dat->hThemeIP) { CMimAPI::m_pfnCloseThemeData(dat->hThemeIP); dat->hThemeIP = 0; } if (dat->hThemeToolbar) { CMimAPI::m_pfnCloseThemeData(dat->hThemeToolbar); dat->hThemeToolbar = 0; } } } } LRESULT TSAPI DM_ThemeChanged(TWindowData *dat) { CSkinItem *item_log = &SkinItems[ID_EXTBKHISTORY]; CSkinItem *item_msg = &SkinItems[ID_EXTBKINPUTAREA]; HWND hwnd = dat->hwnd; dat->hTheme = (M->isVSAPIState() && CMimAPI::m_pfnOpenThemeData) ? CMimAPI::m_pfnOpenThemeData(hwnd, L"EDIT") : 0; if (dat->bType == SESSIONTYPE_IM) { if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_log->IGNORED)) SetWindowLongPtr(GetDlgItem(hwnd, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_LOG), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_msg->IGNORED)) SetWindowLongPtr(GetDlgItem(hwnd, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_MESSAGE), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); } else { if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_log->IGNORED)) { SetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_LOG), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); SetWindowLongPtr(GetDlgItem(hwnd, IDC_LIST), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_LIST), GWL_EXSTYLE) & ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); } if (dat->hTheme != 0 || (CSkin::m_skinEnabled && !item_msg->IGNORED)) SetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwnd, IDC_CHAT_MESSAGE), GWL_EXSTYLE) & ~WS_EX_STATICEDGE); } dat->hThemeIP = M->isAero() ? CMimAPI::m_pfnOpenThemeData(hwnd, L"ButtonStyle") : 0; dat->hThemeToolbar = (M->isAero() || (!CSkin::m_skinEnabled && M->isVSThemed())) ? CMimAPI::m_pfnOpenThemeData(hwnd, L"REBAR") : 0; return 0; } /** * send out message typing notifications (MTN) when the * user is typing/editing text in the messgae input area. */ void TSAPI DM_NotifyTyping(struct TWindowData *dat, int mode) { DWORD protoStatus; DWORD protoCaps; DWORD typeCaps; const char* szProto = 0; HANDLE hContact = 0; if (dat && dat->hContact) { DeletePopupsForContact(dat->hContact, PU_REMOVE_ON_TYPE); if (dat->bIsMeta){ szProto = dat->cache->getActiveProto(); hContact = dat->cache->getActiveContact(); } else { szProto = dat->szProto; hContact = dat->hContact; } /* * editing user notes or preparing a message for queued delivery -> don't send MTN */ if (dat->fEditNotesActive || dat->sendMode & SMODE_SENDLATER) return; /* * allow supression of sending out TN for the contact (NOTE: for metacontacts, do NOT use the subcontact handle) */ if (!M->GetByte(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M->GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW))) return; if (!dat->szProto) // should not, but who knows... return; /* * check status and capabilities of the protocol */ protoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0); protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0); typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0); if (!(typeCaps & PF4_SUPPORTTYPING)) return; if (protoStatus < ID_STATUS_ONLINE) return; /* * check visibility/invisibility lists to not "accidentially" send MTN to contacts who * should not see them (privacy issue) */ if (protoCaps & PF1_VISLIST && DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE) return; if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0) != ID_STATUS_ONLINE) return; /* * don't send to contacts which are not permanently added to the contact list, * unless the option to ignore added status is set. */ if (M->GetByte(dat->hContact, "CList", "NotOnList", 0) && !M->GetByte(SRMSGMOD, SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN)) return; // End user check dat->nTypeMode = mode; CallService(MS_PROTO_SELFISTYPING, (WPARAM) hContact, dat->nTypeMode); } } void TSAPI DM_OptionsApplied(TWindowData *dat, WPARAM wParam, LPARAM lParam) { if (dat == 0) return; HWND hwndDlg = dat->hwnd; TContainerData *m_pContainer = dat->pContainer; dat->szMicroLf[0] = 0; if (!(dat->pContainer->theme.isPrivate)) { LoadThemeDefaults(dat->pContainer); dat->dwFlags = dat->pContainer->theme.dwFlags; } LoadLocalFlags(hwndDlg, dat); LoadTimeZone(dat); if (dat->hContact && dat->szProto != NULL && dat->bIsMeta) { DWORD dwForcedContactNum = 0; CallService(MS_MC_GETFORCESTATE, (WPARAM)dat->hContact, (LPARAM)&dwForcedContactNum); M->WriteDword(dat->hContact, SRMSGMOD_T, "tabSRMM_forced", dwForcedContactNum); } dat->showUIElements = m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1; dat->dwFlagsEx = M->GetByte(SRMSGSET_SHOWURLS, SRMSGDEFSET_SHOWURLS) ? MWF_SHOW_URLEVENTS : 0; dat->dwFlagsEx |= M->GetByte(SRMSGSET_SHOWFILES, SRMSGDEFSET_SHOWFILES) ? MWF_SHOW_FILEEVENTS : 0; dat->dwFlagsEx |= M->GetByte(dat->hContact, "splitoverride", 0) ? MWF_SHOW_SPLITTEROVERRIDE : 0; dat->Panel->getVisibility(); // small inner margins (padding) for the text areas SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0)); SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3)); GetSendFormat(dat, 1); SetDialogToType(hwndDlg); SendMessage(hwndDlg, DM_CONFIGURETOOLBAR, 0, 0); DM_InitRichEdit(dat); if (hwndDlg == m_pContainer->hwndActive) SendMessage(m_pContainer->hwnd, WM_SIZE, 0, 0); InvalidateRect(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, FALSE); if (!lParam) SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); ShowWindow(dat->hwndPanelPicParent, PluginConfig.g_bDisableAniAvatars ? SW_HIDE : SW_SHOW); EnableWindow(dat->hwndPanelPicParent, PluginConfig.g_bDisableAniAvatars ? FALSE : TRUE); SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); } void TSAPI DM_Typing(TWindowData *dat, bool fForceOff) { if (dat == 0) return; HWND hwndDlg = dat->hwnd; HWND hwndContainer = dat->pContainer->hwnd; HWND hwndStatus = dat->pContainer->hwndStatus; if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - dat->nLastTyping > TIMEOUT_TYPEOFF) DM_NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF); if (dat->showTyping == 1) { if (dat->nTypeSecs > 0) { dat->nTypeSecs--; if (GetForegroundWindow() == hwndContainer) SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); } else { struct TWindowData *dat_active = NULL; if (!fForceOff) { dat->showTyping = 2; dat->nTypeSecs = 86400; mir_sntprintf(dat->szStatusBar, safe_sizeof(dat->szStatusBar), TranslateT("%s has entered text."), dat->cache->getNick()); if (hwndStatus && dat->pContainer->hwndActive == hwndDlg) SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM) dat->szStatusBar); } SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); HandleIconFeedback(dat, (HICON) - 1); dat_active = (struct TWindowData *)GetWindowLongPtr(dat->pContainer->hwndActive, GWLP_USERDATA); if (dat_active && dat_active->bType == SESSIONTYPE_IM) SendMessage(hwndContainer, DM_UPDATETITLE, 0, 0); else SendMessage(hwndContainer, DM_UPDATETITLE, (WPARAM)dat->pContainer->hwndActive, (LPARAM)1); if (!(dat->pContainer->dwFlags & CNT_NOFLASH) && PluginConfig.m_FlashOnMTN) ReflashContainer(dat->pContainer); } } else if (dat->showTyping == 2) { if (dat->nTypeSecs > 0) dat->nTypeSecs--; else { dat->szStatusBar[0] = 0; dat->showTyping = 0; } UpdateStatusBar(dat); } else { if (dat->nTypeSecs > 0) { mir_sntprintf(dat->szStatusBar, safe_sizeof(dat->szStatusBar), TranslateT("%s is typing a message."), dat->cache->getNick()); dat->nTypeSecs--; if (hwndStatus && dat->pContainer->hwndActive == hwndDlg) { SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM) dat->szStatusBar); SendMessage(hwndStatus, SB_SETICON, 0, (LPARAM) PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); } if (IsIconic(hwndContainer) || GetForegroundWindow() != hwndContainer || GetActiveWindow() != hwndContainer) { SetWindowText(hwndContainer, dat->szStatusBar); dat->pContainer->dwFlags |= CNT_NEED_UPDATETITLE; if (!(dat->pContainer->dwFlags & CNT_NOFLASH) && PluginConfig.m_FlashOnMTN) ReflashContainer(dat->pContainer); } if (dat->pContainer->hwndActive != hwndDlg) { if (dat->mayFlashTab) dat->iFlashIcon = PluginConfig.g_IconTypingEvent; HandleIconFeedback(dat, PluginConfig.g_IconTypingEvent); } else { // active tab may show icon if status bar is disabled if (!hwndStatus) { if (TabCtrl_GetItemCount(GetParent(hwndDlg)) > 1 || !(dat->pContainer->dwFlags & CNT_HIDETABS)) { HandleIconFeedback(dat, PluginConfig.g_IconTypingEvent); } } } if ((GetForegroundWindow() != hwndContainer) || (dat->pContainer->hwndStatus == 0) || (dat->pContainer->hwndActive != hwndDlg)) SendMessage(hwndContainer, DM_SETICON, (WPARAM)dat, (LPARAM) PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); dat->showTyping = 1; } } } /** * sync splitter position for all open sessions. * This cares about private / per container / MUC <> IM splitter syncing and everything. * called from IM and MUC windows via DM_SPLITTERGLOBALEVENT */ int TSAPI DM_SplitterGlobalEvent(TWindowData *dat, WPARAM wParam, LPARAM lParam) { RECT rcWin; short newMessagePos; LONG newPos; TWindowData* srcDat = PluginConfig.lastSPlitterPos.pSrcDat; TContainerData* srcCnt = PluginConfig.lastSPlitterPos.pSrcContainer; bool fCntGlobal = (!dat->pContainer->settings->fPrivate ? true : false); #if defined(__FEAT_EXP_AUTOSPLITTER) if (dat->fIsAutosizingInput) return 0; #endif GetWindowRect(dat->hwnd, &rcWin); if (wParam == 0 && lParam == 0) { if ((dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE) && dat != srcDat) return 0; if (srcDat->bType == dat->bType) newPos = PluginConfig.lastSPlitterPos.pos; else if (srcDat->bType == SESSIONTYPE_IM && dat->bType == SESSIONTYPE_CHAT) newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im; else if (srcDat->bType == SESSIONTYPE_CHAT && dat->bType == SESSIONTYPE_IM) newPos = PluginConfig.lastSPlitterPos.pos + PluginConfig.lastSPlitterPos.off_im; if (dat == srcDat) { if (dat->bType == SESSIONTYPE_IM) { dat->pContainer->settings->splitterPos = dat->splitterY; if (fCntGlobal) { SaveSplitter(dat); if (PluginConfig.lastSPlitterPos.bSync) g_Settings.iSplitterY = dat->splitterY - DPISCALEY_S(23); } } if (dat->bType == SESSIONTYPE_CHAT) { SESSION_INFO *si = dat->si; if (si) { dat->pContainer->settings->splitterPos = si->iSplitterY + DPISCALEY_S(23); if (fCntGlobal) { g_Settings.iSplitterY = si->iSplitterY; if (PluginConfig.lastSPlitterPos.bSync) M->WriteDword(SRMSGMOD_T, "splitsplity", (DWORD)si->iSplitterY + DPISCALEY_S(23)); } } } return 0; } if (!fCntGlobal && dat->pContainer != srcCnt) return 0; if (srcCnt->settings->fPrivate && dat->pContainer != srcCnt) return 0; if (!PluginConfig.lastSPlitterPos.bSync && dat->bType != srcDat->bType) return 0; /* * for inactive sessions, delay the splitter repositioning until they become * active (faster, avoid redraw/resize problems for minimized windows) */ if (IsIconic(dat->pContainer->hwnd) || dat->pContainer->hwndActive != dat->hwnd) { dat->dwFlagsEx |= MWF_EX_DELAYEDSPLITTER; dat->wParam = newPos; dat->lParam = PluginConfig.lastSPlitterPos.lParam; return 0; } } else newPos = wParam; newMessagePos = (short)rcWin.bottom - (short)newPos; if (dat->bType == SESSIONTYPE_IM) { LoadSplitter(dat); AdjustBottomAvatarDisplay(dat); DM_RecalcPictureSize(dat); SendMessage(dat->hwnd, WM_SIZE, 0, 0); DM_ScrollToBottom(dat, 1,1); if (dat != srcDat) CSkin::UpdateToolbarBG(dat); } else { SESSION_INFO *si = dat->si; if (si) { si->iSplitterY = g_Settings.iSplitterY; SendMessage(dat->hwnd, WM_SIZE, 0, 0); } } return 0; } /** * incoming event handler */ void TSAPI DM_EventAdded(TWindowData *dat, WPARAM wParam, LPARAM lParam) { TContainerData *m_pContainer = dat->pContainer; DBEVENTINFO dbei = {0}; DWORD dwTimestamp = 0; BOOL fIsStatusChangeEvent = FALSE, fIsNotifyEvent = FALSE; HWND hwndDlg = dat->hwnd, hwndContainer = m_pContainer->hwnd, hwndTab = GetParent(dat->hwnd); dbei.cbSize = sizeof(dbei); dbei.cbBlob = 0; CallService(MS_DB_EVENT_GET, lParam, (LPARAM) & dbei); if (dat->hDbEventFirst == NULL) dat->hDbEventFirst = (HANDLE) lParam; fIsStatusChangeEvent = IsStatusEvent(dbei.eventType); fIsNotifyEvent = (dbei.eventType == EVENTTYPE_MESSAGE || dbei.eventType == EVENTTYPE_FILE); if (!fIsStatusChangeEvent) { int heFlags = HistoryEvents_GetFlags(dbei.eventType); if (heFlags != -1 && !(heFlags & HISTORYEVENTS_FLAG_DEFAULT) && !(heFlags & HISTORYEVENTS_FLAG_FLASH_MSG_WINDOW)) fIsStatusChangeEvent = TRUE; } if (dbei.eventType == EVENTTYPE_MESSAGE && (dbei.flags & DBEF_READ)) return; if (DbEventIsShown(dat, &dbei)) { if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) { dat->lastMessage = dbei.timestamp; dat->szStatusBar[0] = 0; if (dat->showTyping) { dat->nTypeSecs = 0; DM_Typing(dat, true); dat->showTyping = 0; } HandleIconFeedback(dat, (HICON)-1); if (m_pContainer->hwndStatus) PostMessage(hwndDlg, DM_UPDATELASTMESSAGE, 0, 0); } /* * set the message log divider to mark new (maybe unseen) messages, if the container has * been minimized or in the background. */ if (!(dbei.flags & DBEF_SENT) && !fIsStatusChangeEvent) { if (PluginConfig.m_DividersUsePopupConfig && PluginConfig.m_UseDividers) { if (!MessageWindowOpened((WPARAM)dat->hContact, 0)) SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); } else if (PluginConfig.m_UseDividers) { if ((GetForegroundWindow() != hwndContainer || GetActiveWindow() != hwndContainer)) SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); else { if (m_pContainer->hwndActive != hwndDlg) SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); } } tabSRMM_ShowPopup(wParam, lParam, dbei.eventType, m_pContainer->fHidden ? 0 : 1, m_pContainer, hwndDlg, dat->cache->getActiveProto(), dat); if (IsWindowVisible(m_pContainer->hwnd)) m_pContainer->fHidden = false; } dat->cache->updateStats(TSessionStats::UPDATE_WITH_LAST_RCV, 0); if ((HANDLE) lParam != dat->hDbEventFirst) { HANDLE nextEvent = (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, lParam, 0); if (1 || nextEvent == 0) { if (!(dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED)) SendMessage(hwndDlg, DM_APPENDTOLOG, lParam, 0); else { TCHAR szBuf[100]; if (dat->iNextQueuedEvent >= dat->iEventQueueSize) { dat->hQueuedEvents = (HANDLE *)realloc(dat->hQueuedEvents, (dat->iEventQueueSize + 10) * sizeof(HANDLE)); dat->iEventQueueSize += 10; } dat->hQueuedEvents[dat->iNextQueuedEvent++] = (HANDLE)lParam; mir_sntprintf(szBuf, safe_sizeof(szBuf), TranslateT("Autoscrolling is disabled, %d message(s) queued (press F12 to enable it)"), dat->iNextQueuedEvent); SetDlgItemText(hwndDlg, IDC_LOGFROZENTEXT, szBuf); RedrawWindow(GetDlgItem(hwndDlg, IDC_LOGFROZENTEXT), NULL, NULL, RDW_INVALIDATE); } } else SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); } else SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); // handle tab flashing if ((TabCtrl_GetCurSel(hwndTab) != dat->iTabID) && !(dbei.flags & DBEF_SENT) && !fIsStatusChangeEvent) { switch (dbei.eventType) { case EVENTTYPE_MESSAGE: dat->iFlashIcon = PluginConfig.g_IconMsgEvent; break; case EVENTTYPE_FILE: dat->iFlashIcon = PluginConfig.g_IconFileEvent; break; default: dat->iFlashIcon = PluginConfig.g_IconMsgEvent; break; } SetTimer(hwndDlg, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL); dat->mayFlashTab = TRUE; } /* * try to flash the contact list... */ FlashOnClist(hwndDlg, dat, (HANDLE)lParam, &dbei); /* * autoswitch tab if option is set AND container is minimized (otherwise, we never autoswitch) * never switch for status changes... */ if (!(dbei.flags & DBEF_SENT) && !fIsStatusChangeEvent) { if (PluginConfig.haveAutoSwitch() && m_pContainer->hwndActive != hwndDlg) { if ((IsIconic(hwndContainer) && !IsZoomed(hwndContainer)) || (PluginConfig.m_HideOnClose && !IsWindowVisible(m_pContainer->hwnd))) { int iItem = GetTabIndexFromHWND(GetParent(hwndDlg), hwndDlg); if (iItem >= 0) { TabCtrl_SetCurSel(GetParent(hwndDlg), iItem); ShowWindow(m_pContainer->hwndActive, SW_HIDE); m_pContainer->hwndActive = hwndDlg; SendMessage(hwndContainer, DM_UPDATETITLE, (WPARAM)dat->hContact, 0); m_pContainer->dwFlags |= CNT_DEFERREDTABSELECT; } } } } /* * flash window if it is not focused */ if ((GetActiveWindow() != hwndContainer || GetForegroundWindow() != hwndContainer || dat->pContainer->hwndActive != hwndDlg) && !(dbei.flags & DBEF_SENT) && !fIsStatusChangeEvent) { if (!(m_pContainer->dwFlags & CNT_NOFLASH) && (GetActiveWindow() != hwndContainer || GetForegroundWindow() != hwndContainer)) FlashContainer(m_pContainer, 1, 0); SendMessage(hwndContainer, DM_SETICON, (WPARAM)dat, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); m_pContainer->dwFlags |= CNT_NEED_UPDATETITLE; } /* * play a sound */ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) PostMessage(hwndDlg, DM_PLAYINCOMINGSOUND, 0, 0); if (dat->pWnd) dat->pWnd->Invalidate(); } } void TSAPI DM_HandleAutoSizeRequest(TWindowData *dat, REQRESIZE* rr) { if (dat && rr && GetForegroundWindow() == dat->pContainer->hwnd) { if (dat->fIsAutosizingInput && dat->iInputAreaHeight != -1) { LONG heightLimit = M->GetDword("autoSplitMinLimit", 0); LONG iNewHeight = rr->rc.bottom - rr->rc.top; if (CSkin::m_skinEnabled && !SkinItems[ID_EXTBKINPUTAREA].IGNORED) iNewHeight += (SkinItems[ID_EXTBKINPUTAREA].MARGIN_TOP + SkinItems[ID_EXTBKINPUTAREA].MARGIN_BOTTOM - 2); if (heightLimit && iNewHeight < heightLimit) iNewHeight = heightLimit; if (iNewHeight != dat->iInputAreaHeight) { RECT rc; GetClientRect(dat->hwnd, &rc); LONG cy = rc.bottom - rc.top; LONG panelHeight = (dat->Panel->isActive() ? dat->Panel->getHeight() : 0); if (iNewHeight > (cy - panelHeight) / 2) iNewHeight = (cy - panelHeight) / 2; if (dat->bType == SESSIONTYPE_IM) { dat->dynaSplitter = rc.bottom - (rc.bottom - iNewHeight + DPISCALEY_S(2)); if (dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR) dat->dynaSplitter += DPISCALEY_S(22); dat->splitterY = dat->dynaSplitter + DPISCALEY_S(34); DM_RecalcPictureSize(dat); } else if (dat->si) { dat->si->iSplitterY = (rc.bottom - (rc.bottom - iNewHeight + DPISCALEY_S(3))) + DPISCALEY_S(34); if (!(dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR)) dat->si->iSplitterY -= DPISCALEY_S(22); SendMessage(dat->hwnd, WM_SIZE, 0, 0); } dat->iInputAreaHeight = iNewHeight; CSkin::UpdateToolbarBG(dat); DM_ScrollToBottom(dat, 1, 0); } } } } void TSAPI DM_UpdateTitle(TWindowData *dat, WPARAM wParam, LPARAM lParam) { TCHAR newtitle[128]; TCHAR* pszNewTitleEnd; TCHAR newcontactname[128]; TCITEM item; DWORD dwOldIdle = dat->idle; const char* szActProto = 0; HANDLE hActContact = 0; HWND hwndDlg = dat->hwnd; HWND hwndTab = GetParent(hwndDlg); HWND hwndContainer = dat->pContainer->hwnd; TContainerData* m_pContainer = dat->pContainer; ZeroMemory((void*)newcontactname, sizeof(newcontactname)); dat->szStatus[0] = 0; pszNewTitleEnd = _T("Message Session"); if (dat->iTabID == -1) return; ZeroMemory((void*)&item, sizeof(item)); if (dat->hContact) { int iHasName; TCHAR fulluin[256]; const TCHAR* szNick = dat->cache->getNick(); if (dat->szProto) { szActProto = dat->cache->getActiveProto(); hActContact = dat->hContact; iHasName = (dat->cache->getUIN()[0] != 0); dat->idle = dat->cache->getIdleTS(); dat->dwFlagsEx = dat->idle ? dat->dwFlagsEx | MWF_SHOW_ISIDLE : dat->dwFlagsEx & ~MWF_SHOW_ISIDLE; dat->wStatus = dat->cache->getStatus(); mir_sntprintf(dat->szStatus, safe_sizeof(dat->szStatus), _T("%s"), (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, dat->szProto == NULL ? ID_STATUS_OFFLINE : dat->wStatus, GSMDF_TCHAR)); if (lParam != 0) { if (PluginConfig.m_CutContactNameOnTabs) CutContactName(szNick, newcontactname, safe_sizeof(newcontactname)); else lstrcpyn(newcontactname, szNick, safe_sizeof(newcontactname)); Utils::DoubleAmpersands(newcontactname); if (lstrlen(newcontactname) != 0 && dat->szStatus != NULL) { if (PluginConfig.m_StatusOnTabs) mir_sntprintf(newtitle, 127, _T("%s (%s)"), newcontactname, dat->szStatus); else mir_sntprintf(newtitle, 127, _T("%s"), newcontactname); } else mir_sntprintf(newtitle, 127, _T("%s"), _T("Forward")); item.mask |= TCIF_TEXT; } SendMessage(hwndDlg, DM_UPDATEWINICON, 0, 0); if (dat->bIsMeta) mir_sntprintf(fulluin, safe_sizeof(fulluin), TranslateT("UID: %s (SHIFT click -> copy to clipboard)\nClick for User's Details\nRight click for MetaContact control\nClick dropdown to add or remove user from your favorites."), iHasName ? dat->cache->getUIN() : TranslateT("No UID")); else mir_sntprintf(fulluin, safe_sizeof(fulluin), TranslateT("UID: %s (SHIFT click -> copy to clipboard)\nClick for User's Details\nClick dropdown to change this contact's favorite status."), iHasName ? dat->cache->getUIN() : TranslateT("No UID")); SendMessage(GetDlgItem(hwndDlg, IDC_NAME), BUTTONADDTOOLTIP, /*iHasName ?*/ (WPARAM)fulluin /*: (WPARAM)_T("")*/, 0); } } else lstrcpyn(newtitle, pszNewTitleEnd, safe_sizeof(newtitle)); if (dat->idle != dwOldIdle || lParam != 0) { if (item.mask & TCIF_TEXT) { item.pszText = newtitle; _tcsncpy(dat->newtitle, newtitle, safe_sizeof(dat->newtitle)); dat->newtitle[127] = 0; item.cchTextMax = 127; if (dat->pWnd) dat->pWnd->updateTitle(dat->cache->getNick()); } if (dat->iTabID >= 0) { TabCtrl_SetItem(hwndTab, dat->iTabID, &item); if (m_pContainer->dwFlags & CNT_SIDEBAR) m_pContainer->SideBar->updateSession(dat); } if (m_pContainer->hwndActive == hwndDlg && lParam) SendMessage(hwndContainer, DM_UPDATETITLE, (WPARAM)dat->hContact, 0); UpdateTrayMenuState(dat, TRUE); if (dat->cache->isFavorite()) AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus, LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getActiveStatus()), 0, PluginConfig.g_hMenuFavorites); if (dat->cache->isRecent()) { AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus, LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getActiveStatus()), 0, PluginConfig.g_hMenuRecent); } dat->Panel->Invalidate(); if (dat->pWnd) dat->pWnd->Invalidate(); if (PluginConfig.g_FlashAvatarAvail) { FLASHAVATAR fa = {0}; fa.hContact = dat->hContact; fa.hWindow = 0; fa.id = 25367; fa.cProto = dat->szProto; CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0); dat->hwndFlash = fa.hWindow; if (dat->hwndFlash) { bool isInfoPanel = dat->Panel->isActive(); SetParent(dat->hwndFlash, isInfoPanel ? dat->hwndPanelPicParent : GetDlgItem(hwndDlg, IDC_CONTACTPIC)); } } } // care about MetaContacts and update the statusbar icon with the currently "most online" contact... if (dat->bIsMeta) { PostMessage(hwndDlg, DM_UPDATEMETACONTACTINFO, 0, 0); PostMessage(hwndDlg, DM_OWNNICKCHANGED, 0, 0); if (m_pContainer->dwFlags & CNT_UINSTATUSBAR) DM_UpdateLastMessage(dat); } } /* * status icon stuff (by sje, used for indicating encryption status in the status bar * this is now part of the message window api */ static HANDLE hHookIconPressedEvt; TStatusBarIconNode *status_icon_list = 0; int status_icon_list_size = 0; static INT_PTR SI_AddStatusIcon(WPARAM wParam, LPARAM lParam) { StatusIconData *sid = (StatusIconData *)lParam; TStatusBarIconNode *siln = (TStatusBarIconNode *)mir_alloc(sizeof(TStatusBarIconNode)); siln->sid.cbSize = sid->cbSize; siln->sid.szModule = mir_strdup(sid->szModule); siln->sid.dwId = sid->dwId; siln->sid.hIcon = sid->hIcon; siln->sid.hIconDisabled = sid->hIconDisabled; siln->sid.flags = sid->flags; siln->sid.szTooltip = mir_strdup(sid->szTooltip); siln->next = status_icon_list; status_icon_list = siln; status_icon_list_size++; M->BroadcastMessage(DM_STATUSICONCHANGE, 0, 0); return 0; } static INT_PTR SI_RemoveStatusIcon(WPARAM wParam, LPARAM lParam) { StatusIconData *sid = (StatusIconData *)lParam; TStatusBarIconNode *current = status_icon_list, *prev = 0; while (current) { if (strcmp(current->sid.szModule, sid->szModule) == 0 && current->sid.dwId == sid->dwId) { if (prev) prev->next = current->next; else status_icon_list = current->next; status_icon_list_size--; mir_free(current->sid.szModule); DestroyIcon(current->sid.hIcon); if (current->sid.hIconDisabled) DestroyIcon(current->sid.hIconDisabled); mir_free(current->sid.szTooltip); mir_free(current); M->BroadcastMessage(DM_STATUSICONCHANGE, 0, 0); return 0; } prev = current; current = current->next; } return 1; } static void SI_RemoveAllStatusIcons(void) { TStatusBarIconNode *current; while (status_icon_list) { current = status_icon_list; status_icon_list = status_icon_list->next; status_icon_list_size--; mir_free(current->sid.szModule); DestroyIcon(current->sid.hIcon); if (current->sid.hIconDisabled) DestroyIcon(current->sid.hIconDisabled); if (current->sid.szTooltip) mir_free(current->sid.szTooltip); mir_free(current); } M->BroadcastMessage(DM_STATUSICONCHANGE, 0, 0); } static INT_PTR SI_ModifyStatusIcon(WPARAM wParam, LPARAM lParam) { StatusIconData *sid = (StatusIconData *)lParam; if ( !sid || !sid->szModule) return 1; TStatusBarIconNode *current = status_icon_list; HANDLE hContact = (HANDLE)wParam; while (current) { if ( strcmp(current->sid.szModule, sid->szModule) == 0 && current->sid.dwId == sid->dwId) { if (!hContact) { current->sid.flags = sid->flags; if (sid->hIcon) { DestroyIcon(current->sid.hIcon); current->sid.hIcon = sid->hIcon; } if (sid->hIconDisabled) { DestroyIcon(current->sid.hIconDisabled); current->sid.hIconDisabled = sid->hIconDisabled; } if (sid->szTooltip) replaceStr(current->sid.szTooltip, sid->szTooltip); M->BroadcastMessage(DM_STATUSICONCHANGE, 0, 0); } else { char buff[256]; HWND hwnd; if ( !(sid->flags & MBF_OWNERSTATE)) { sprintf(buff, "SRMMStatusIconFlags%d", (int)sid->dwId); M->WriteByte(hContact, sid->szModule, buff, (BYTE)sid->flags); } if ((hwnd = M->FindWindow(hContact))) { if (sid->flags & MBF_OWNERSTATE) { TStatusBarIconNode *siln = NULL; TWindowData *dat = (TWindowData*) GetWindowLongPtr(hwnd, GWLP_USERDATA); TStatusBarIconNode *psi = dat->pSINod; while (psi) { if (strcmp(psi->sid.szModule, sid->szModule) == 0 && psi->sid.dwId == sid->dwId) { siln = psi; break; } psi = psi->next; } if (!siln) { siln = (TStatusBarIconNode *)mir_alloc(sizeof(TStatusBarIconNode)); siln->sid.szModule = mir_strdup(sid->szModule); siln->sid.dwId = sid->dwId; siln->sid.hIcon = sid->hIcon; siln->sid.hIconDisabled = sid->hIconDisabled; siln->sid.flags = sid->flags; if (sid->szTooltip) siln->sid.szTooltip = mir_strdup(sid->szTooltip); else siln->sid.szTooltip = 0; siln->next = dat->pSINod; dat->pSINod = siln; } else { siln->sid.hIcon = sid->hIcon; siln->sid.hIconDisabled = sid->hIconDisabled; siln->sid.flags = sid->flags; if (siln->sid.szTooltip) mir_free(siln->sid.szTooltip); if (sid->szTooltip) siln->sid.szTooltip = mir_strdup(sid->szTooltip); else siln->sid.szTooltip = 0; } } PostMessage(hwnd, DM_STATUSICONCHANGE, 0, 0); } } return 0; } current = current->next; } return 1; } void DrawStatusIcons(struct TWindowData *dat, HDC hDC, RECT r, int gap) { TStatusBarIconNode* current = status_icon_list; HICON hIcon = NULL; char buff[256]; int flags; int x = r.left; LONG cx_icon = PluginConfig.m_smcxicon; LONG cy_icon = PluginConfig.m_smcyicon; LONG y = (r.top + r.bottom - cx_icon) >> 1; SetBkMode(hDC, TRANSPARENT); while (current) { if (current->sid.flags&MBF_OWNERSTATE) { TStatusBarIconNode *currentSIN = dat->pSINod; flags = current->sid.flags; hIcon = current->sid.hIcon; while (currentSIN) { if (strcmp(currentSIN->sid.szModule, current->sid.szModule) == 0 && currentSIN->sid.dwId == current->sid.dwId) { flags = currentSIN->sid.flags; hIcon = currentSIN->sid.hIcon; break; } currentSIN = currentSIN->next; } } else { sprintf(buff, "SRMMStatusIconFlags%d", (int)current->sid.dwId); flags = M->GetByte(dat->hContact, current->sid.szModule, buff, current->sid.flags); } if (!(flags & MBF_HIDDEN)) { if (!(flags&MBF_OWNERSTATE) && (flags & MBF_DISABLED) && current->sid.hIconDisabled) hIcon = current->sid.hIconDisabled; else if (!(flags&MBF_OWNERSTATE)) hIcon = current->sid.hIcon; if (flags & MBF_DISABLED && current->sid.hIconDisabled == (HICON)0) CSkin::DrawDimmedIcon(hDC, x, y, cx_icon, cy_icon, hIcon, 50); else DrawIconEx(hDC, x, y, hIcon, 16, 16, 0, NULL, DI_NORMAL); x += 16 + gap; } current = current->next; } DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_SOUNDS], cx_icon, cy_icon, 0, NULL, DI_NORMAL); DrawIconEx(hDC, x, y, dat->pContainer->dwFlags & CNT_NOSOUND ? PluginConfig.g_iconOverlayDisabled : PluginConfig.g_iconOverlayEnabled, cx_icon, cy_icon, 0, NULL, DI_NORMAL); x += (cx_icon + gap); if (dat->bType == SESSIONTYPE_IM) { DrawIconEx(hDC, x, y, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], cx_icon, cy_icon, 0, NULL, DI_NORMAL); DrawIconEx(hDC, x, y, M->GetByte(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, M->GetByte(SRMSGMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)) ? PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled, cx_icon, cy_icon, 0, NULL, DI_NORMAL); } else CSkin::DrawDimmedIcon(hDC, x, y, cx_icon, cy_icon, PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING], 50); x += (cx_icon + gap); DrawIconEx(hDC, x, y, PluginConfig.g_sideBarIcons[0], cx_icon, cy_icon, 0, NULL, DI_NORMAL); } void SI_CheckStatusIconClick(struct TWindowData *dat, HWND hwndFrom, POINT pt, RECT r, int gap, int code) { StatusIconClickData sicd; TStatusBarIconNode *current = status_icon_list; TStatusBarIconNode *clicked = NULL; UINT iconNum = (pt.x - (r.left + 0)) / (PluginConfig.m_smcxicon + gap); UINT list_icons = 0; char buff[100]; DWORD flags; if (dat && (code == NM_CLICK || code == NM_RCLICK)) { POINT ptScreen; GetCursorPos(&ptScreen); if (!PtInRect(&rcLastStatusBarClick, ptScreen)) return; } while (current && dat) { if (current->sid.flags & MBF_OWNERSTATE) { TStatusBarIconNode *currentSIN = dat->pSINod; flags = current->sid.flags; while (currentSIN) { if (strcmp(currentSIN->sid.szModule, current->sid.szModule) == 0 && currentSIN->sid.dwId == current->sid.dwId) { flags = currentSIN->sid.flags; break; } currentSIN = currentSIN->next; } } else { sprintf(buff, "SRMMStatusIconFlags%d", (int)current->sid.dwId); flags = M->GetByte(dat->hContact, current->sid.szModule, buff, current->sid.flags); } if ( !(flags & MBF_HIDDEN)) { if (list_icons++ == iconNum) clicked = current; } current = current->next; } if ((int)iconNum == list_icons && code != NM_RCLICK) { if (GetKeyState(VK_SHIFT) & 0x8000) { struct TContainerData *piContainer = pFirstContainer; while (piContainer) { piContainer->dwFlags = ((dat->pContainer->dwFlags & CNT_NOSOUND) ? piContainer->dwFlags | CNT_NOSOUND : piContainer->dwFlags & ~CNT_NOSOUND); InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); piContainer = piContainer->pNextContainer; } } else { dat->pContainer->dwFlags ^= CNT_NOSOUND; InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); } } else if ((int)iconNum == list_icons + 1 && code != NM_RCLICK && dat->bType == SESSIONTYPE_IM) { SendMessage(dat->pContainer->hwndActive, WM_COMMAND, IDC_SELFTYPING, 0); InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); } else if ((int)iconNum == list_icons + 2) { if (code == NM_CLICK) PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_LBUTTONUP); else if (code == NM_RCLICK) PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_TRAYICONNOTIFY, 101, WM_RBUTTONUP); } else if (clicked) { sicd.cbSize = sizeof(StatusIconClickData); GetCursorPos(&sicd.clickLocation); sicd.dwId = clicked->sid.dwId; sicd.szModule = clicked->sid.szModule; sicd.flags = (code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0); NotifyEventHooks(hHookIconPressedEvt, (WPARAM)dat->hContact, (LPARAM)&sicd); InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); } } int SI_InitStatusIcons() { CreateServiceFunction(MS_MSG_ADDICON, SI_AddStatusIcon); CreateServiceFunction(MS_MSG_REMOVEICON, SI_RemoveStatusIcon); CreateServiceFunction(MS_MSG_MODIFYICON, SI_ModifyStatusIcon); hHookIconPressedEvt = CreateHookableEvent(ME_MSG_ICONPRESSED); return 0; } int SI_DeinitStatusIcons() { DestroyHookableEvent(hHookIconPressedEvt); SI_RemoveAllStatusIcons(); return 0; } int SI_GetStatusIconsCount() { return status_icon_list_size; }