diff options
author | Robert Pösel <robyer@seznam.cz> | 2014-04-23 14:43:51 +0000 |
---|---|---|
committer | Robert Pösel <robyer@seznam.cz> | 2014-04-23 14:43:51 +0000 |
commit | 1babf569634e2f7cee4932cd5ccb20fe125b7a61 (patch) | |
tree | 52de48f405e147e3574d3eec9b9e87d3bed4f9c1 /plugins | |
parent | 373e84ed50b36d871bab20b5b7ba8710a693ec7e (diff) |
TabSRMM: Use consistent "%s is typing..." messages as in chat and scriver
git-svn-id: http://svn.miranda-ng.org/main/trunk@9056 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/TabSRMM/src/generic_msghandlers.cpp | 4110 | ||||
-rw-r--r-- | plugins/TabSRMM/src/mim.cpp | 1344 |
2 files changed, 2727 insertions, 2727 deletions
diff --git a/plugins/TabSRMM/src/generic_msghandlers.cpp b/plugins/TabSRMM/src/generic_msghandlers.cpp index 776cc20cec..fc91c4e0a0 100644 --- a/plugins/TabSRMM/src/generic_msghandlers.cpp +++ b/plugins/TabSRMM/src/generic_msghandlers.cpp @@ -1,2055 +1,2055 @@ -/*
- * Miranda NG: the free IM client for Microsoft* Windows*
- *
- * Copyright (c) 2000-09 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
- *
- * 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"
-
-/**
- * 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"));
- CreateDirectoryTreeT(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)
-{
- if (!IsWindowVisible(dat->hwndTip))
- return;
-
- RECT rc;
- 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(&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;
- SendMessage(dat->hwndTip, TTM_ADDTOOL, 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;
- case TABSRMM_HK_CLOSE_OTHER:
- CloseOtherTabs(GetDlgItem(dat->pContainer->hwnd, IDC_MSGTABS), *dat);
- return 1;
- }
- return 0;
-}
-
-LRESULT TSAPI DM_MsgWindowCmdHandler(HWND hwndDlg, TContainerData *m_pContainer, TWindowData *dat, UINT cmd, WPARAM wParam, LPARAM lParam)
-{
- RECT rc;
- HWND hwndContainer = m_pContainer->hwnd;
- int iSelection;
- HMENU submenu;
-
- switch(cmd) {
- case IDC_FONTBOLD:
- case IDC_FONTITALIC:
- case IDC_FONTUNDERLINE:
- case IDC_FONTSTRIKEOUT:
- if (dat->SendFormat != 0) { // dont use formatting if disabled
- CHARFORMAT2 cf, cfOld;
- 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);
- BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD);
- BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC);
- BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE);
- BOOL isStrikeout = (cfOld.dwEffects & CFM_STRIKEOUT) && (cfOld.dwMask & CFM_STRIKEOUT);
-
- int cmd = LOWORD(wParam);
- 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:
- submenu = GetSubMenu(m_pContainer->hMenuContext, 7);
- {
- CHARFORMAT2 cf;
- ZeroMemory(&cf, sizeof(CHARFORMAT2));
- cf.cbSize = sizeof(CHARFORMAT2);
- cf.dwMask = CFM_COLOR;
-
- 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) {
- cf.crTextColor = M.GetDword(FONTMODULE, "Font16Col", 0);
- for (int 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 (int 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, dat->hContact, 0);
- break;
-
- case IDC_SMILEYBTN:
- if (dat->doSmileys && PluginConfig.g_SmileyAddAvail) {
- MCONTACT hContact = dat->cache->getActiveContact();
- if (CheckValidSmileyPack(dat->cache->getProto(), 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<char *>(dat->cache->getProto());
- 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:
- submenu = GetSubMenu(m_pContainer->hMenuContext, 2);
- MsgWindowUpdateMenu(dat, submenu, MENU_LOGMENU);
-
- GetWindowRect(GetDlgItem(hwndDlg, IDC_TIME), &rc);
-
- iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL);
- return MsgWindowMenuHandler(dat, iSelection, MENU_LOGMENU);
-
- case IDC_PROTOMENU:
- if (dat->hContact) {
- submenu = GetSubMenu(m_pContainer->hMenuContext, 4);
- int iOldGlobalSendFormat = PluginConfig.m_SendFormat;
- 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);
- db_set_b(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;
- db_set_b(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)
- db_unset(dat->hContact, SRMSGMOD_T, "sendformat");
- else if (iNewLocalFormat != iLocalFormat)
- db_set_dw(dat->hContact, SRMSGMOD_T, "sendformat", iNewLocalFormat);
-
- if (PluginConfig.m_SendFormat != iOldGlobalSendFormat)
- db_set_b(0, 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:
- 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:
- db_set_b(dat->hContact, SRMSGMOD_T, "isFavorite", 1);
- AddContactToFavorites(dat->hContact, dat->cache->getNick(), dat->cache->getProto(), dat->szStatus, dat->wStatus, LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 1, PluginConfig.g_hMenuFavorites);
- break;
- case ID_FAVORITES_REMOVECONTACTFROMFAVORITES:
- db_set_b(dat->hContact, SRMSGMOD_T, "isFavorite", 0);
- DeleteMenu(PluginConfig.g_hMenuFavorites, (UINT_PTR)dat->hContact, MF_BYCOMMAND);
- break;
- }
- dat->cache->updateFavorite();
- break;
-
- case IDC_SENDMENU:
- submenu = GetSubMenu(m_pContainer->hMenuContext, 3);
-
- 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();
- EnableMenuItem(submenu, ID_SENDMENU_SENDNUDGE, MF_BYCOMMAND | ((ProtoServiceExists(szFinalProto, PS_SEND_NUDGE) && 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)
- db_set_b(dat->hContact, SRMSGMOD_T, "no_ack", 1);
- else
- db_unset(dat->hContact, SRMSGMOD_T, "no_ack");
- break;
- }
- db_set_b(dat->hContact, SRMSGMOD_T, "no_ack", (BYTE)(dat->sendMode & SMODE_NOACK ? 1 : 0));
- db_set_b(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:
- 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->bIsAutosizingInput) {
- dat->iSplitterSaved = dat->splitterY;
- dat->splitterY = rc.bottom / 2;
- SendMessage(hwndDlg, WM_SIZE, 1, 1);
- }
-
- DBVARIANT dbv = {0};
-
- if (0 == db_get_ts(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);
- db_set_ts(dat->hContact, "UserInfo", "MyNotes", buf);
- SetDlgItemText(hwndDlg, IDC_MESSAGE, _T(""));
-
- if (!dat->bIsAutosizingInput) {
- 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:
- submenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, dat->hContact, 0);
- if (lParam == 0)
- GetWindowRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), &rc);
- else
- GetWindowRect((HWND)lParam, &rc);
-
- iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL);
- if (iSelection)
- CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(iSelection), MPCF_CONTACTMENU), (LPARAM)dat->hContact);
-
- DestroyMenu(submenu);
- 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 = db_get_b(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;
- }
- db_set_b(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, (BYTE)!iCurrentTypingMode);
- }
- break;
-
- default:
- return 0;
- }
- return 1;
-}
-
-static INT_PTR CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- COLORREF url_visited = RGB(128, 0, 128);
- COLORREF url_unvisited = RGB(0, 0, 255);
-
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
- {
- WORD v[4];
- CallService(MS_SYSTEM_GETFILEVERSION, 0, (LPARAM)&v);
-
- TCHAR tStr[80];
- mir_sntprintf(tStr, SIZEOF(tStr), _T("TabSRMM\n%s %d.%d.%d.%d [build %d]"),
- TranslateT("Version"), __MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM, v[3]);
- SetDlgItemText(hwndDlg, IDC_HEADERBAR, tStr);
- }
- SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE));
- SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE));
- return TRUE;
-
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- DestroyWindow(hwndDlg);
- return TRUE;
- case IDC_SUPPORT:
- CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://miranda.or.at/");
- break;
- }
- break;
-
- case WM_CTLCOLOREDIT:
- case WM_CTLCOLORSTATIC:
- SetTextColor((HDC)wParam, RGB(60, 60, 150));
- SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
- return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
- }
- return FALSE;
-}
-
-LRESULT TSAPI DM_ContainerCmdHandler(TContainerData *pContainer, UINT cmd, WPARAM wParam, LPARAM lParam)
-{
- if (!pContainer)
- return 0;
-
- HWND hwndDlg = pContainer->hwnd;
- TWindowData *dat = (TWindowData*)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA);
-
- 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)) {
- db_set_dw(0, SRMSGMOD_T, "splitx", wp.rcNormalPosition.left);
- db_set_dw(0, SRMSGMOD_T, "splity", wp.rcNormalPosition.top);
- db_set_dw(0, SRMSGMOD_T, "splitwidth", wp.rcNormalPosition.right - wp.rcNormalPosition.left);
- db_set_dw(0, SRMSGMOD_T, "splitheight", wp.rcNormalPosition.bottom - wp.rcNormalPosition.top);
- }
- }
- return 0;
-
- case ID_VIEW_INFOPANEL:
- 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:
- 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;
- 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;
-
- dat->inputbg = fIsChat ? M.GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR) : dat->pContainer->theme.inputbg;
- COLORREF colour = fIsChat ? g_Settings.crLogBackground : dat->pContainer->theme.bg;
- COLORREF inputcharcolor;
-
- if (!fIsChat && 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);
-
- CHARFORMAT2A cf2;
- ZeroMemory(&cf2, sizeof(CHARFORMAT2A));
- cf2.cbSize = sizeof(cf2);
-
- if (fIsChat) {
- LOGFONTA lf;
- LoadLogfont(MSGFONTID_MESSAGEAREA, &lf, &inputcharcolor, FONTMODULE);
-
- cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_ITALIC | CFM_BACKCOLOR;
- 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 {
- LOGFONTA lf = dat->pContainer->theme.logFonts[MSGFONTID_MESSAGEAREA];
- inputcharcolor = dat->pContainer->theme.fontColors[MSGFONTID_MESSAGEAREA];
-
- for (int 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);
-
- cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_BOLD | CFM_ITALIC;
- 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) {
- SETTEXTEX stx = {ST_DEFAULT, CP_UTF8};
- SendMessage(hwndEdit, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szStreamOut);
- mir_free(szStreamOut);
- }
-}
-
-/*
-* set the states of defined database action buttons (only if button is a toggle)
-*/
-
-void TSAPI DM_SetDBButtonStates(HWND hwndChild, TWindowData *dat)
-{
- ButtonItem *buttonItem = dat->pContainer->buttonItems;
- MCONTACT 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 (!db_get_s(hFinalContact, szModule, szSetting, &dbv)) {
- result = !strcmp((char *)buttonItem->bValuePush, dbv.pszVal);
- db_free(&dbv);
- }
- } else {
- switch (buttonItem->type) {
- case DBVT_BYTE: {
- BYTE val = db_get_b(hFinalContact, szModule, szSetting, 0);
- result = (val == buttonItem->bValuePush[0]);
- break;
- }
- case DBVT_WORD: {
- WORD val = db_get_w(hFinalContact, szModule, szSetting, 0);
- result = (val == *((WORD *) & buttonItem->bValuePush));
- break;
- }
- case DBVT_DWORD: {
- DWORD val = db_get_dw(hFinalContact, szModule, szSetting, 0);
- result = (val == *((DWORD *) & buttonItem->bValuePush));
- break;
- }
- }
- }
- SendMessage(hWnd, BM_SETCHECK, (WPARAM)result, 0);
- buttonItem = buttonItem->nextItem;
- }
-}
-
-void TSAPI DM_ScrollToBottom(TWindowData *dat, WPARAM wParam, LPARAM lParam)
-{
- if (dat == NULL)
- return;
-
- if (dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED)
- return;
-
- if ( IsIconic(dat->pContainer->hwnd))
- dat->dwFlags |= MWF_DEFERREDSCROLL;
-
- if (dat->hwndIEView) {
- PostMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0);
- return;
- }
- if (dat->hwndHPP) {
- SendMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0);
- return;
- }
-
- 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;
- GetClientRect(hwnd, &rc);
- int 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);
-}
-
-static void LoadKLThread(LPVOID _param)
-{
- DBVARIANT dbv;
- if (!db_get_ts((MCONTACT)_param, SRMSGMOD_T, "locale", &dbv)) {
- HKL hkl = LoadKeyboardLayout(dbv.ptszVal, 0);
- PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SETLOCALE, (WPARAM)_param, (LPARAM)hkl);
- db_free(&dbv);
- }
-}
-
-void TSAPI DM_LoadLocale(TWindowData *dat)
-{
- if (dat == NULL || !PluginConfig.m_AutoLocaleSupport)
- return;
-
- if (dat->dwFlags & MWF_WASBACKGROUNDCREATE)
- return;
-
- DBVARIANT dbv;
- if ( !db_get_ts(dat->hContact, SRMSGMOD_T, "locale", &dbv))
- db_free(&dbv);
- else {
- TCHAR szKLName[KL_NAMELENGTH+1];
- if (!PluginConfig.m_dontUseDefaultKbd) {
- TCHAR szBuf[20];
- GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, szBuf, 20);
- mir_sntprintf(szKLName, KL_NAMELENGTH, _T("0000%s"), szBuf);
- db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName);
- }
- else {
- GetKeyboardLayoutName(szKLName);
- db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName);
- }
- }
-
- mir_forkthread(LoadKLThread, (void*)dat->hContact);
-}
-
-LRESULT TSAPI DM_RecalcPictureSize(TWindowData *dat)
-{
- if (dat) {
- HBITMAP hbm = ((dat->Panel->isActive()) && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown);
- if (hbm) {
- BITMAP bminfo;
- GetObject(hbm, sizeof(bminfo), &bminfo);
- CalcDynamicAvatarSize(dat, &bminfo);
- SendMessage(dat->hwnd, WM_SIZE, 0, 0);
- }
- else dat->pic.cy = dat->pic.cx = 60;
- }
- return 0;
-}
-
-void TSAPI DM_UpdateLastMessage(const TWindowData *dat)
-{
- if (dat == NULL)
- return;
-
- if (dat->pContainer->hwndStatus == 0 || dat->pContainer->hwndActive != dat->hwnd)
- return;
-
- TCHAR szBuf[100];
- if (dat->showTyping) {
- SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]);
- mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("%s is typing a message."), dat->cache->getNick());
- }
- else {
- SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, 0);
-
- if (dat->pContainer->dwFlags & CNT_UINSTATUSBAR)
- mir_sntprintf(szBuf, SIZEOF(szBuf), _T("UID: %s"), dat->cache->getUIN());
- else if (dat->lastMessage) {
- TCHAR date[64], time[64];
- tmi.printTimeStamp(NULL, dat->lastMessage, _T("d"), date, 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, SIZEOF(time), 0);
- mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("Last received: %s at %s"), date, time);
- }
- else szBuf[0] = 0;
- }
-
- SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)szBuf);
-}
-
-/*
-* save current keyboard layout for the given contact
-*/
-
-void TSAPI DM_SaveLocale(TWindowData *dat, WPARAM wParam, LPARAM lParam)
-{
- if (!dat)
- return;
-
- 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);
- db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName);
- GetLocaleID(dat, szKLName);
- UpdateReadChars(dat);
- }
- }
-}
-
-/*
-* 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, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- LRESULT result = mir_callNextSubclass(hwnd, oldWndProc, msg, wParam, lParam);
-
- if (OpenClipboard(hwnd)) {
- HANDLE hClip = GetClipboardData(CF_UNICODETEXT);
- if (hClip) {
- HGLOBAL hgbl;
- TCHAR *tszLocked;
- TCHAR *tszText = (TCHAR*)mir_alloc((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)
- mir_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);
- SendMessage(hwndClist, WM_TIMER, 14, 0);
- HANDLE hItem = (HANDLE)SendMessage(hwndClist, CLM_FINDCONTACT, 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));
-
- 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, FALSE, 0);
- else
- SendMessage(hwndClist, CLM_SETUSEGROUPS, TRUE, 0);
- if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_HIDEEMPTYGROUPS && M.GetByte("CList", "HideEmptyGroups", SETTING_USEGROUPS_DEFAULT))
- SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, TRUE, 0);
- else
- SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, 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, TWindowData *mwdat, WPARAM wParam, LPARAM lParam)
-{
- RECT rc, rc1;
- UINT uID = mwdat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG;
- UINT uIDMsg = mwdat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE;
-
- POINT pt;
- 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;
- }
-
- HWND hwndTab = GetDlgItem(mwdat->pContainer->hwnd, IDC_MSGTABS);
- TCHITTESTINFO hti;
- 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 (dat->hTheme) {
- CloseThemeData(dat->hTheme);
- dat->hTheme = 0;
- }
- if (dat->hThemeIP) {
- CloseThemeData(dat->hThemeIP);
- dat->hThemeIP = 0;
- }
- if (dat->hThemeToolbar) {
- CloseThemeData(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 = OpenThemeData(hwnd, L"EDIT");
-
- 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() ? OpenThemeData(hwnd, L"ButtonStyle") : 0;
- dat->hThemeToolbar = (M.isAero() || (!CSkin::m_skinEnabled && M.isVSThemed())) ? OpenThemeData(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(TWindowData *dat, int mode)
-{
- if (!dat || !dat->hContact)
- return;
-
- DeletePopupsForContact(dat->hContact, PU_REMOVE_ON_TYPE);
-
- const char *szProto = 0;
- MCONTACT hContact = 0;
- 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 (!db_get_b(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
- */
- DWORD typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0);
- if (!(typeCaps & PF4_SUPPORTTYPING))
- return;
-
- DWORD protoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
- if (protoStatus < ID_STATUS_ONLINE)
- return;
-
- /*
- * check visibility/invisibility lists to not "accidentially" send MTN to contacts who
- * should not see them (privacy issue)
- */
- DWORD protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
- if (protoCaps & PF1_VISLIST && db_get_w(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE)
- return;
-
- if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && db_get_w(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 (db_get_b(dat->hContact, "CList", "NotOnList", 0) && !M.GetByte(SRMSGMOD, SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN))
- return;
- // End user check
- dat->nTypeMode = mode;
- CallService(MS_PROTO_SELFISTYPING, 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);
-
- dat->showUIElements = m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1;
-
- 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 {
- if (!fForceOff) {
- dat->showTyping = 2;
- dat->nTypeSecs = 86400;
-
- mir_sntprintf(dat->szStatusBar, 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);
- TWindowData *dat_active = (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, 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, 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->bIsAutosizingInput)
- 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)
- db_set_dw(0, 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;
- DWORD dwTimestamp = 0;
- HWND hwndDlg = dat->hwnd, hwndContainer = m_pContainer->hwnd, hwndTab = GetParent(dat->hwnd);
- HANDLE hDbEvent = (HANDLE)lParam;
-
- DBEVENTINFO dbei = { sizeof(dbei) };
- db_event_get(hDbEvent, &dbei);
- if (dat->hDbEventFirst == NULL)
- dat->hDbEventFirst = hDbEvent;
-
- BOOL bIsStatusChangeEvent = IsStatusEvent(dbei.eventType);
-
- if (dbei.eventType == EVENTTYPE_MESSAGE && (dbei.flags & DBEF_READ))
- return;
-
- if (!DbEventIsShown(dat, &dbei))
- return;
-
- 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) && !bIsStatusChangeEvent) {
- if (PluginConfig.m_DividersUsePopupConfig && PluginConfig.m_UseDividers) {
- if (!MessageWindowOpened(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, hDbEvent, 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 (hDbEvent != dat->hDbEventFirst) {
- HANDLE nextEvent = db_event_next(dat->hContact, hDbEvent);
- 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*)mir_realloc(dat->hQueuedEvents, (dat->iEventQueueSize + 10) * sizeof(HANDLE));
- dat->iEventQueueSize += 10;
- }
- dat->hQueuedEvents[dat->iNextQueuedEvent++] = hDbEvent;
- mir_sntprintf(szBuf, 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) && !bIsStatusChangeEvent) {
- 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, hDbEvent, &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) && !bIsStatusChangeEvent) {
- 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, 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) && !bIsStatusChangeEvent) {
- 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 == NULL || rr == NULL || GetForegroundWindow() != dat->pContainer->hwnd)
- return;
-
- if (!dat->bIsAutosizingInput || dat->iInputAreaHeight == -1)
- return;
-
- 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)
- return;
-
- 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], newcontactname[128];
- DWORD dwOldIdle = dat->idle;
- const char *szActProto = 0;
-
- HWND hwndDlg = dat->hwnd;
- HWND hwndTab = GetParent(hwndDlg);
- HWND hwndContainer = dat->pContainer->hwnd;
- TContainerData* m_pContainer = dat->pContainer;
-
- newcontactname[0] = 0;
- dat->szStatus[0] = 0;
-
- if (dat->iTabID == -1)
- return;
-
- TCITEM item = { 0 };
-
- if (dat->hContact) {
- const TCHAR *szNick = dat->cache->getNick();
-
- if (dat->szProto) {
- szActProto = dat->cache->getProto();
- MCONTACT hActContact = dat->hContact;
-
- bool bHasName = (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();
- _tcsncpy_s(dat->szStatus, SIZEOF(dat->szStatus), pcli->pfnGetStatusModeDescription(dat->szProto == NULL ? ID_STATUS_OFFLINE : dat->wStatus, 0), _TRUNCATE);
-
- if (lParam != 0) {
- if (PluginConfig.m_CutContactNameOnTabs)
- CutContactName(szNick, newcontactname, SIZEOF(newcontactname));
- else
- lstrcpyn(newcontactname, szNick, 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);
-
- TCHAR fulluin[256];
- if (dat->bIsMeta)
- mir_sntprintf(fulluin, 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."),
- bHasName ? dat->cache->getUIN() : TranslateT("No UID"));
- else
- mir_sntprintf(fulluin, SIZEOF(fulluin),
- TranslateT("UID: %s (SHIFT click -> copy to clipboard)\nClick for User's Details\nClick dropdown to change this contact's favorite status."),
- bHasName ? dat->cache->getUIN() : TranslateT("No UID"));
-
- SendMessage(GetDlgItem(hwndDlg, IDC_NAME), BUTTONADDTOOLTIP, (WPARAM)fulluin, BATF_TCHAR);
- }
- }
- else lstrcpyn(newtitle, _T("Message Session"), SIZEOF(newtitle));
-
- if (dat->idle != dwOldIdle || lParam != 0) {
- if (item.mask & TCIF_TEXT) {
- item.pszText = newtitle;
- _tcsncpy(dat->newtitle, newtitle, 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, dat->hContact, 0);
-
- UpdateTrayMenuState(dat, TRUE);
- if (dat->cache->isFavorite())
- AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus,
- LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 0, PluginConfig.g_hMenuFavorites);
-
- if (dat->cache->isRecent())
- AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus,
- LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 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)
- SetParent(dat->hwndFlash, dat->Panel->isActive() ? 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;
-
-static int OnSrmmIconChanged(WPARAM hContact, LPARAM)
-{
- if (hContact == NULL)
- M.BroadcastMessage(DM_STATUSICONCHANGE, 0, 0);
- else {
- HWND hwnd = M.FindWindow(hContact);
- if (hwnd)
- PostMessage(hwnd, DM_STATUSICONCHANGE, 0, 0);
- }
- return 0;
-}
-
-void DrawStatusIcons(TWindowData *dat, HDC hDC, RECT r, int gap)
-{
- HICON hIcon = NULL;
- 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);
-
- int nIcon = 0;
- while (StatusIconData *si = Srmm_GetNthIcon(dat->hContact, nIcon++)) {
- if ( !strcmp(si->szModule, MSG_ICON_MODULE)) {
- if (si->dwId == MSG_ICON_SOUND) {
- 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);
- }
- else if (si->dwId == MSG_ICON_UTN) {
- 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, db_get_b(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);
- }
- else if (si->dwId == MSG_ICON_SESSION) {
- DrawIconEx(hDC, x, y, PluginConfig.g_sideBarIcons[0], cx_icon, cy_icon, 0, NULL, DI_NORMAL);
- }
- }
- else {
- if ((si->flags & MBF_DISABLED) && si->hIconDisabled)
- hIcon = si->hIconDisabled;
- else
- hIcon = si->hIcon;
-
- if ((si->flags & MBF_DISABLED) && si->hIconDisabled == NULL)
- CSkin::DrawDimmedIcon(hDC, x, y, cx_icon, cy_icon, hIcon, 50);
- else
- DrawIconEx(hDC, x, y, hIcon, 16, 16, 0, NULL, DI_NORMAL);
- }
-
- x += cx_icon + gap;
- }
-}
-
-void SI_CheckStatusIconClick(TWindowData *dat, HWND hwndFrom, POINT pt, RECT r, int gap, int code)
-{
- if (dat && (code == NM_CLICK || code == NM_RCLICK)) {
- POINT ptScreen;
- GetCursorPos(&ptScreen);
- if (!PtInRect(&rcLastStatusBarClick, ptScreen))
- return;
- }
-
- UINT iconNum = (pt.x - (r.left + 0)) / (PluginConfig.m_smcxicon + gap), list_icons = 0;
- StatusIconData *si = Srmm_GetNthIcon((dat) ? dat->hContact : 0, iconNum);
- if (si == NULL)
- return;
-
- if ( !strcmp(si->szModule, MSG_ICON_MODULE)) {
- if (si->dwId == MSG_ICON_SOUND && code != NM_RCLICK) {
- if (GetKeyState(VK_SHIFT) & 0x8000) {
- for (TContainerData *p = pFirstContainer; p; p = p->pNext) {
- p->dwFlags = ((dat->pContainer->dwFlags & CNT_NOSOUND) ? p->dwFlags | CNT_NOSOUND : p->dwFlags & ~CNT_NOSOUND);
- InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE);
- }
- }
- else {
- dat->pContainer->dwFlags ^= CNT_NOSOUND;
- InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE);
- }
- }
- else if (si->dwId == MSG_ICON_UTN && code != NM_RCLICK && dat->bType == SESSIONTYPE_IM) {
- SendMessage(dat->pContainer->hwndActive, WM_COMMAND, IDC_SELFTYPING, 0);
- InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE);
- }
- else if (si->dwId == MSG_ICON_SESSION) {
- 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 {
- StatusIconClickData sicd = { sizeof(sicd) };
- GetCursorPos(&sicd.clickLocation);
- sicd.dwId = si->dwId;
- sicd.szModule = si->szModule;
- sicd.flags = (code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0);
- NotifyEventHooks(hHookIconPressedEvt, dat->hContact, (LPARAM)&sicd);
- InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE);
- }
-}
-
-int SI_InitStatusIcons()
-{
- StatusIconData sid = { sizeof(sid) };
- sid.szModule = MSG_ICON_MODULE;
- sid.dwId = MSG_ICON_SOUND; // Sounds
- Srmm_AddIcon(&sid);
-
- sid.dwId = MSG_ICON_UTN;
- Srmm_AddIcon(&sid);
-
- sid.dwId = MSG_ICON_SESSION;
- Srmm_AddIcon(&sid);
-
- HookEvent(ME_MSG_ICONSCHANGED, OnSrmmIconChanged);
-
- hHookIconPressedEvt = CreateHookableEvent(ME_MSG_ICONPRESSED);
- return 0;
-}
-
-int SI_DeinitStatusIcons()
-{
- DestroyHookableEvent(hHookIconPressedEvt);
- return 0;
-}
+/* + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright (c) 2000-09 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 + * + * 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" + +/** + * 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")); + CreateDirectoryTreeT(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) +{ + if (!IsWindowVisible(dat->hwndTip)) + return; + + RECT rc; + 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(&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; + SendMessage(dat->hwndTip, TTM_ADDTOOL, 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; + case TABSRMM_HK_CLOSE_OTHER: + CloseOtherTabs(GetDlgItem(dat->pContainer->hwnd, IDC_MSGTABS), *dat); + return 1; + } + return 0; +} + +LRESULT TSAPI DM_MsgWindowCmdHandler(HWND hwndDlg, TContainerData *m_pContainer, TWindowData *dat, UINT cmd, WPARAM wParam, LPARAM lParam) +{ + RECT rc; + HWND hwndContainer = m_pContainer->hwnd; + int iSelection; + HMENU submenu; + + switch(cmd) { + case IDC_FONTBOLD: + case IDC_FONTITALIC: + case IDC_FONTUNDERLINE: + case IDC_FONTSTRIKEOUT: + if (dat->SendFormat != 0) { // dont use formatting if disabled + CHARFORMAT2 cf, cfOld; + 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); + BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD); + BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC); + BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE); + BOOL isStrikeout = (cfOld.dwEffects & CFM_STRIKEOUT) && (cfOld.dwMask & CFM_STRIKEOUT); + + int cmd = LOWORD(wParam); + 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: + submenu = GetSubMenu(m_pContainer->hMenuContext, 7); + { + CHARFORMAT2 cf; + ZeroMemory(&cf, sizeof(CHARFORMAT2)); + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwMask = CFM_COLOR; + + 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) { + cf.crTextColor = M.GetDword(FONTMODULE, "Font16Col", 0); + for (int 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 (int 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, dat->hContact, 0); + break; + + case IDC_SMILEYBTN: + if (dat->doSmileys && PluginConfig.g_SmileyAddAvail) { + MCONTACT hContact = dat->cache->getActiveContact(); + if (CheckValidSmileyPack(dat->cache->getProto(), 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<char *>(dat->cache->getProto()); + 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: + submenu = GetSubMenu(m_pContainer->hMenuContext, 2); + MsgWindowUpdateMenu(dat, submenu, MENU_LOGMENU); + + GetWindowRect(GetDlgItem(hwndDlg, IDC_TIME), &rc); + + iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); + return MsgWindowMenuHandler(dat, iSelection, MENU_LOGMENU); + + case IDC_PROTOMENU: + if (dat->hContact) { + submenu = GetSubMenu(m_pContainer->hMenuContext, 4); + int iOldGlobalSendFormat = PluginConfig.m_SendFormat; + 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); + db_set_b(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; + db_set_b(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) + db_unset(dat->hContact, SRMSGMOD_T, "sendformat"); + else if (iNewLocalFormat != iLocalFormat) + db_set_dw(dat->hContact, SRMSGMOD_T, "sendformat", iNewLocalFormat); + + if (PluginConfig.m_SendFormat != iOldGlobalSendFormat) + db_set_b(0, 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: + 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: + db_set_b(dat->hContact, SRMSGMOD_T, "isFavorite", 1); + AddContactToFavorites(dat->hContact, dat->cache->getNick(), dat->cache->getProto(), dat->szStatus, dat->wStatus, LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 1, PluginConfig.g_hMenuFavorites); + break; + case ID_FAVORITES_REMOVECONTACTFROMFAVORITES: + db_set_b(dat->hContact, SRMSGMOD_T, "isFavorite", 0); + DeleteMenu(PluginConfig.g_hMenuFavorites, (UINT_PTR)dat->hContact, MF_BYCOMMAND); + break; + } + dat->cache->updateFavorite(); + break; + + case IDC_SENDMENU: + submenu = GetSubMenu(m_pContainer->hMenuContext, 3); + + 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(); + EnableMenuItem(submenu, ID_SENDMENU_SENDNUDGE, MF_BYCOMMAND | ((ProtoServiceExists(szFinalProto, PS_SEND_NUDGE) && 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) + db_set_b(dat->hContact, SRMSGMOD_T, "no_ack", 1); + else + db_unset(dat->hContact, SRMSGMOD_T, "no_ack"); + break; + } + db_set_b(dat->hContact, SRMSGMOD_T, "no_ack", (BYTE)(dat->sendMode & SMODE_NOACK ? 1 : 0)); + db_set_b(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: + 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->bIsAutosizingInput) { + dat->iSplitterSaved = dat->splitterY; + dat->splitterY = rc.bottom / 2; + SendMessage(hwndDlg, WM_SIZE, 1, 1); + } + + DBVARIANT dbv = {0}; + + if (0 == db_get_ts(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); + db_set_ts(dat->hContact, "UserInfo", "MyNotes", buf); + SetDlgItemText(hwndDlg, IDC_MESSAGE, _T("")); + + if (!dat->bIsAutosizingInput) { + 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: + submenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, dat->hContact, 0); + if (lParam == 0) + GetWindowRect(GetDlgItem(hwndDlg, IDC_PROTOCOL), &rc); + else + GetWindowRect((HWND)lParam, &rc); + + iSelection = TrackPopupMenu(submenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); + if (iSelection) + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(iSelection), MPCF_CONTACTMENU), (LPARAM)dat->hContact); + + DestroyMenu(submenu); + 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 = db_get_b(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; + } + db_set_b(dat->hContact, SRMSGMOD, SRMSGSET_TYPING, (BYTE)!iCurrentTypingMode); + } + break; + + default: + return 0; + } + return 1; +} + +static INT_PTR CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + COLORREF url_visited = RGB(128, 0, 128); + COLORREF url_unvisited = RGB(0, 0, 255); + + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + { + WORD v[4]; + CallService(MS_SYSTEM_GETFILEVERSION, 0, (LPARAM)&v); + + TCHAR tStr[80]; + mir_sntprintf(tStr, SIZEOF(tStr), _T("TabSRMM\n%s %d.%d.%d.%d [build %d]"), + TranslateT("Version"), __MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM, v[3]); + SetDlgItemText(hwndDlg, IDC_HEADERBAR, tStr); + } + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_EVENT_MESSAGE)); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + case IDCANCEL: + DestroyWindow(hwndDlg); + return TRUE; + case IDC_SUPPORT: + CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://miranda.or.at/"); + break; + } + break; + + case WM_CTLCOLOREDIT: + case WM_CTLCOLORSTATIC: + SetTextColor((HDC)wParam, RGB(60, 60, 150)); + SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); + } + return FALSE; +} + +LRESULT TSAPI DM_ContainerCmdHandler(TContainerData *pContainer, UINT cmd, WPARAM wParam, LPARAM lParam) +{ + if (!pContainer) + return 0; + + HWND hwndDlg = pContainer->hwnd; + TWindowData *dat = (TWindowData*)GetWindowLongPtr(pContainer->hwndActive, GWLP_USERDATA); + + 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)) { + db_set_dw(0, SRMSGMOD_T, "splitx", wp.rcNormalPosition.left); + db_set_dw(0, SRMSGMOD_T, "splity", wp.rcNormalPosition.top); + db_set_dw(0, SRMSGMOD_T, "splitwidth", wp.rcNormalPosition.right - wp.rcNormalPosition.left); + db_set_dw(0, SRMSGMOD_T, "splitheight", wp.rcNormalPosition.bottom - wp.rcNormalPosition.top); + } + } + return 0; + + case ID_VIEW_INFOPANEL: + 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: + 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; + 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; + + dat->inputbg = fIsChat ? M.GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR) : dat->pContainer->theme.inputbg; + COLORREF colour = fIsChat ? g_Settings.crLogBackground : dat->pContainer->theme.bg; + COLORREF inputcharcolor; + + if (!fIsChat && 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); + + CHARFORMAT2A cf2; + ZeroMemory(&cf2, sizeof(CHARFORMAT2A)); + cf2.cbSize = sizeof(cf2); + + if (fIsChat) { + LOGFONTA lf; + LoadLogfont(MSGFONTID_MESSAGEAREA, &lf, &inputcharcolor, FONTMODULE); + + cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_ITALIC | CFM_BACKCOLOR; + 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 { + LOGFONTA lf = dat->pContainer->theme.logFonts[MSGFONTID_MESSAGEAREA]; + inputcharcolor = dat->pContainer->theme.fontColors[MSGFONTID_MESSAGEAREA]; + + for (int 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); + + cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_BOLD | CFM_ITALIC; + 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) { + SETTEXTEX stx = {ST_DEFAULT, CP_UTF8}; + SendMessage(hwndEdit, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)szStreamOut); + mir_free(szStreamOut); + } +} + +/* +* set the states of defined database action buttons (only if button is a toggle) +*/ + +void TSAPI DM_SetDBButtonStates(HWND hwndChild, TWindowData *dat) +{ + ButtonItem *buttonItem = dat->pContainer->buttonItems; + MCONTACT 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 (!db_get_s(hFinalContact, szModule, szSetting, &dbv)) { + result = !strcmp((char *)buttonItem->bValuePush, dbv.pszVal); + db_free(&dbv); + } + } else { + switch (buttonItem->type) { + case DBVT_BYTE: { + BYTE val = db_get_b(hFinalContact, szModule, szSetting, 0); + result = (val == buttonItem->bValuePush[0]); + break; + } + case DBVT_WORD: { + WORD val = db_get_w(hFinalContact, szModule, szSetting, 0); + result = (val == *((WORD *) & buttonItem->bValuePush)); + break; + } + case DBVT_DWORD: { + DWORD val = db_get_dw(hFinalContact, szModule, szSetting, 0); + result = (val == *((DWORD *) & buttonItem->bValuePush)); + break; + } + } + } + SendMessage(hWnd, BM_SETCHECK, (WPARAM)result, 0); + buttonItem = buttonItem->nextItem; + } +} + +void TSAPI DM_ScrollToBottom(TWindowData *dat, WPARAM wParam, LPARAM lParam) +{ + if (dat == NULL) + return; + + if (dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED) + return; + + if ( IsIconic(dat->pContainer->hwnd)) + dat->dwFlags |= MWF_DEFERREDSCROLL; + + if (dat->hwndIEView) { + PostMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0); + return; + } + if (dat->hwndHPP) { + SendMessage(dat->hwnd, DM_SCROLLIEVIEW, 0, 0); + return; + } + + 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; + GetClientRect(hwnd, &rc); + int 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); +} + +static void LoadKLThread(LPVOID _param) +{ + DBVARIANT dbv; + if (!db_get_ts((MCONTACT)_param, SRMSGMOD_T, "locale", &dbv)) { + HKL hkl = LoadKeyboardLayout(dbv.ptszVal, 0); + PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_SETLOCALE, (WPARAM)_param, (LPARAM)hkl); + db_free(&dbv); + } +} + +void TSAPI DM_LoadLocale(TWindowData *dat) +{ + if (dat == NULL || !PluginConfig.m_AutoLocaleSupport) + return; + + if (dat->dwFlags & MWF_WASBACKGROUNDCREATE) + return; + + DBVARIANT dbv; + if ( !db_get_ts(dat->hContact, SRMSGMOD_T, "locale", &dbv)) + db_free(&dbv); + else { + TCHAR szKLName[KL_NAMELENGTH+1]; + if (!PluginConfig.m_dontUseDefaultKbd) { + TCHAR szBuf[20]; + GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_ILANGUAGE, szBuf, 20); + mir_sntprintf(szKLName, KL_NAMELENGTH, _T("0000%s"), szBuf); + db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName); + } + else { + GetKeyboardLayoutName(szKLName); + db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName); + } + } + + mir_forkthread(LoadKLThread, (void*)dat->hContact); +} + +LRESULT TSAPI DM_RecalcPictureSize(TWindowData *dat) +{ + if (dat) { + HBITMAP hbm = ((dat->Panel->isActive()) && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown); + if (hbm) { + BITMAP bminfo; + GetObject(hbm, sizeof(bminfo), &bminfo); + CalcDynamicAvatarSize(dat, &bminfo); + SendMessage(dat->hwnd, WM_SIZE, 0, 0); + } + else dat->pic.cy = dat->pic.cx = 60; + } + return 0; +} + +void TSAPI DM_UpdateLastMessage(const TWindowData *dat) +{ + if (dat == NULL) + return; + + if (dat->pContainer->hwndStatus == 0 || dat->pContainer->hwndActive != dat->hwnd) + return; + + TCHAR szBuf[100]; + if (dat->showTyping) { + SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); + mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("%s is typing a message..."), dat->cache->getNick()); + } + else { + SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, 0); + + if (dat->pContainer->dwFlags & CNT_UINSTATUSBAR) + mir_sntprintf(szBuf, SIZEOF(szBuf), _T("UID: %s"), dat->cache->getUIN()); + else if (dat->lastMessage) { + TCHAR date[64], time[64]; + tmi.printTimeStamp(NULL, dat->lastMessage, _T("d"), date, 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, SIZEOF(time), 0); + mir_sntprintf(szBuf, SIZEOF(szBuf), TranslateT("Last received: %s at %s"), date, time); + } + else szBuf[0] = 0; + } + + SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)szBuf); +} + +/* +* save current keyboard layout for the given contact +*/ + +void TSAPI DM_SaveLocale(TWindowData *dat, WPARAM wParam, LPARAM lParam) +{ + if (!dat) + return; + + 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); + db_set_ts(dat->hContact, SRMSGMOD_T, "locale", szKLName); + GetLocaleID(dat, szKLName); + UpdateReadChars(dat); + } + } +} + +/* +* 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, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT result = mir_callNextSubclass(hwnd, oldWndProc, msg, wParam, lParam); + + if (OpenClipboard(hwnd)) { + HANDLE hClip = GetClipboardData(CF_UNICODETEXT); + if (hClip) { + HGLOBAL hgbl; + TCHAR *tszLocked; + TCHAR *tszText = (TCHAR*)mir_alloc((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) + mir_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); + SendMessage(hwndClist, WM_TIMER, 14, 0); + HANDLE hItem = (HANDLE)SendMessage(hwndClist, CLM_FINDCONTACT, 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)); + + 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, FALSE, 0); + else + SendMessage(hwndClist, CLM_SETUSEGROUPS, TRUE, 0); + if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_HIDEEMPTYGROUPS && M.GetByte("CList", "HideEmptyGroups", SETTING_USEGROUPS_DEFAULT)) + SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, TRUE, 0); + else + SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, 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, TWindowData *mwdat, WPARAM wParam, LPARAM lParam) +{ + RECT rc, rc1; + UINT uID = mwdat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG; + UINT uIDMsg = mwdat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE; + + POINT pt; + 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; + } + + HWND hwndTab = GetDlgItem(mwdat->pContainer->hwnd, IDC_MSGTABS); + TCHITTESTINFO hti; + 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 (dat->hTheme) { + CloseThemeData(dat->hTheme); + dat->hTheme = 0; + } + if (dat->hThemeIP) { + CloseThemeData(dat->hThemeIP); + dat->hThemeIP = 0; + } + if (dat->hThemeToolbar) { + CloseThemeData(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 = OpenThemeData(hwnd, L"EDIT"); + + 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() ? OpenThemeData(hwnd, L"ButtonStyle") : 0; + dat->hThemeToolbar = (M.isAero() || (!CSkin::m_skinEnabled && M.isVSThemed())) ? OpenThemeData(hwnd, L"REBAR") : 0; + + return 0; +} + +/** + * send out message typing notifications (MTN) when the + * user is typing/editing text in the message input area. + */ +void TSAPI DM_NotifyTyping(TWindowData *dat, int mode) +{ + if (!dat || !dat->hContact) + return; + + DeletePopupsForContact(dat->hContact, PU_REMOVE_ON_TYPE); + + const char *szProto = 0; + MCONTACT hContact = 0; + 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 (!db_get_b(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 + */ + DWORD typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0); + if (!(typeCaps & PF4_SUPPORTTYPING)) + return; + + DWORD protoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0); + if (protoStatus < ID_STATUS_ONLINE) + return; + + /* + * check visibility/invisibility lists to not "accidentially" send MTN to contacts who + * should not see them (privacy issue) + */ + DWORD protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0); + if (protoCaps & PF1_VISLIST && db_get_w(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE) + return; + + if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && db_get_w(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 (db_get_b(dat->hContact, "CList", "NotOnList", 0) && !M.GetByte(SRMSGMOD, SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN)) + return; + // End user check + dat->nTypeMode = mode; + CallService(MS_PROTO_SELFISTYPING, 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); + + dat->showUIElements = m_pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1; + + 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 { + if (!fForceOff) { + dat->showTyping = 2; + dat->nTypeSecs = 86400; + + mir_sntprintf(dat->szStatusBar, 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); + TWindowData *dat_active = (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, 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, 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->bIsAutosizingInput) + 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) + db_set_dw(0, 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; + DWORD dwTimestamp = 0; + HWND hwndDlg = dat->hwnd, hwndContainer = m_pContainer->hwnd, hwndTab = GetParent(dat->hwnd); + HANDLE hDbEvent = (HANDLE)lParam; + + DBEVENTINFO dbei = { sizeof(dbei) }; + db_event_get(hDbEvent, &dbei); + if (dat->hDbEventFirst == NULL) + dat->hDbEventFirst = hDbEvent; + + BOOL bIsStatusChangeEvent = IsStatusEvent(dbei.eventType); + + if (dbei.eventType == EVENTTYPE_MESSAGE && (dbei.flags & DBEF_READ)) + return; + + if (!DbEventIsShown(dat, &dbei)) + return; + + 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) && !bIsStatusChangeEvent) { + if (PluginConfig.m_DividersUsePopupConfig && PluginConfig.m_UseDividers) { + if (!MessageWindowOpened(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, hDbEvent, 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 (hDbEvent != dat->hDbEventFirst) { + HANDLE nextEvent = db_event_next(dat->hContact, hDbEvent); + 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*)mir_realloc(dat->hQueuedEvents, (dat->iEventQueueSize + 10) * sizeof(HANDLE)); + dat->iEventQueueSize += 10; + } + dat->hQueuedEvents[dat->iNextQueuedEvent++] = hDbEvent; + mir_sntprintf(szBuf, 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) && !bIsStatusChangeEvent) { + 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, hDbEvent, &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) && !bIsStatusChangeEvent) { + 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, 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) && !bIsStatusChangeEvent) { + 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 == NULL || rr == NULL || GetForegroundWindow() != dat->pContainer->hwnd) + return; + + if (!dat->bIsAutosizingInput || dat->iInputAreaHeight == -1) + return; + + 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) + return; + + 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], newcontactname[128]; + DWORD dwOldIdle = dat->idle; + const char *szActProto = 0; + + HWND hwndDlg = dat->hwnd; + HWND hwndTab = GetParent(hwndDlg); + HWND hwndContainer = dat->pContainer->hwnd; + TContainerData* m_pContainer = dat->pContainer; + + newcontactname[0] = 0; + dat->szStatus[0] = 0; + + if (dat->iTabID == -1) + return; + + TCITEM item = { 0 }; + + if (dat->hContact) { + const TCHAR *szNick = dat->cache->getNick(); + + if (dat->szProto) { + szActProto = dat->cache->getProto(); + MCONTACT hActContact = dat->hContact; + + bool bHasName = (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(); + _tcsncpy_s(dat->szStatus, SIZEOF(dat->szStatus), pcli->pfnGetStatusModeDescription(dat->szProto == NULL ? ID_STATUS_OFFLINE : dat->wStatus, 0), _TRUNCATE); + + if (lParam != 0) { + if (PluginConfig.m_CutContactNameOnTabs) + CutContactName(szNick, newcontactname, SIZEOF(newcontactname)); + else + lstrcpyn(newcontactname, szNick, 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); + + TCHAR fulluin[256]; + if (dat->bIsMeta) + mir_sntprintf(fulluin, 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."), + bHasName ? dat->cache->getUIN() : TranslateT("No UID")); + else + mir_sntprintf(fulluin, SIZEOF(fulluin), + TranslateT("UID: %s (SHIFT click -> copy to clipboard)\nClick for User's Details\nClick dropdown to change this contact's favorite status."), + bHasName ? dat->cache->getUIN() : TranslateT("No UID")); + + SendMessage(GetDlgItem(hwndDlg, IDC_NAME), BUTTONADDTOOLTIP, (WPARAM)fulluin, BATF_TCHAR); + } + } + else lstrcpyn(newtitle, _T("Message Session"), SIZEOF(newtitle)); + + if (dat->idle != dwOldIdle || lParam != 0) { + if (item.mask & TCIF_TEXT) { + item.pszText = newtitle; + _tcsncpy(dat->newtitle, newtitle, 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, dat->hContact, 0); + + UpdateTrayMenuState(dat, TRUE); + if (dat->cache->isFavorite()) + AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus, + LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 0, PluginConfig.g_hMenuFavorites); + + if (dat->cache->isRecent()) + AddContactToFavorites(dat->hContact, dat->cache->getNick(), szActProto, dat->szStatus, dat->wStatus, + LoadSkinnedProtoIcon(dat->cache->getProto(), dat->cache->getStatus()), 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) + SetParent(dat->hwndFlash, dat->Panel->isActive() ? 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; + +static int OnSrmmIconChanged(WPARAM hContact, LPARAM) +{ + if (hContact == NULL) + M.BroadcastMessage(DM_STATUSICONCHANGE, 0, 0); + else { + HWND hwnd = M.FindWindow(hContact); + if (hwnd) + PostMessage(hwnd, DM_STATUSICONCHANGE, 0, 0); + } + return 0; +} + +void DrawStatusIcons(TWindowData *dat, HDC hDC, RECT r, int gap) +{ + HICON hIcon = NULL; + 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); + + int nIcon = 0; + while (StatusIconData *si = Srmm_GetNthIcon(dat->hContact, nIcon++)) { + if ( !strcmp(si->szModule, MSG_ICON_MODULE)) { + if (si->dwId == MSG_ICON_SOUND) { + 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); + } + else if (si->dwId == MSG_ICON_UTN) { + 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, db_get_b(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); + } + else if (si->dwId == MSG_ICON_SESSION) { + DrawIconEx(hDC, x, y, PluginConfig.g_sideBarIcons[0], cx_icon, cy_icon, 0, NULL, DI_NORMAL); + } + } + else { + if ((si->flags & MBF_DISABLED) && si->hIconDisabled) + hIcon = si->hIconDisabled; + else + hIcon = si->hIcon; + + if ((si->flags & MBF_DISABLED) && si->hIconDisabled == NULL) + CSkin::DrawDimmedIcon(hDC, x, y, cx_icon, cy_icon, hIcon, 50); + else + DrawIconEx(hDC, x, y, hIcon, 16, 16, 0, NULL, DI_NORMAL); + } + + x += cx_icon + gap; + } +} + +void SI_CheckStatusIconClick(TWindowData *dat, HWND hwndFrom, POINT pt, RECT r, int gap, int code) +{ + if (dat && (code == NM_CLICK || code == NM_RCLICK)) { + POINT ptScreen; + GetCursorPos(&ptScreen); + if (!PtInRect(&rcLastStatusBarClick, ptScreen)) + return; + } + + UINT iconNum = (pt.x - (r.left + 0)) / (PluginConfig.m_smcxicon + gap), list_icons = 0; + StatusIconData *si = Srmm_GetNthIcon((dat) ? dat->hContact : 0, iconNum); + if (si == NULL) + return; + + if ( !strcmp(si->szModule, MSG_ICON_MODULE)) { + if (si->dwId == MSG_ICON_SOUND && code != NM_RCLICK) { + if (GetKeyState(VK_SHIFT) & 0x8000) { + for (TContainerData *p = pFirstContainer; p; p = p->pNext) { + p->dwFlags = ((dat->pContainer->dwFlags & CNT_NOSOUND) ? p->dwFlags | CNT_NOSOUND : p->dwFlags & ~CNT_NOSOUND); + InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); + } + } + else { + dat->pContainer->dwFlags ^= CNT_NOSOUND; + InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); + } + } + else if (si->dwId == MSG_ICON_UTN && code != NM_RCLICK && dat->bType == SESSIONTYPE_IM) { + SendMessage(dat->pContainer->hwndActive, WM_COMMAND, IDC_SELFTYPING, 0); + InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); + } + else if (si->dwId == MSG_ICON_SESSION) { + 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 { + StatusIconClickData sicd = { sizeof(sicd) }; + GetCursorPos(&sicd.clickLocation); + sicd.dwId = si->dwId; + sicd.szModule = si->szModule; + sicd.flags = (code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0); + NotifyEventHooks(hHookIconPressedEvt, dat->hContact, (LPARAM)&sicd); + InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); + } +} + +int SI_InitStatusIcons() +{ + StatusIconData sid = { sizeof(sid) }; + sid.szModule = MSG_ICON_MODULE; + sid.dwId = MSG_ICON_SOUND; // Sounds + Srmm_AddIcon(&sid); + + sid.dwId = MSG_ICON_UTN; + Srmm_AddIcon(&sid); + + sid.dwId = MSG_ICON_SESSION; + Srmm_AddIcon(&sid); + + HookEvent(ME_MSG_ICONSCHANGED, OnSrmmIconChanged); + + hHookIconPressedEvt = CreateHookableEvent(ME_MSG_ICONPRESSED); + return 0; +} + +int SI_DeinitStatusIcons() +{ + DestroyHookableEvent(hHookIconPressedEvt); + return 0; +} diff --git a/plugins/TabSRMM/src/mim.cpp b/plugins/TabSRMM/src/mim.cpp index d6a45b2aa1..649ed59f93 100644 --- a/plugins/TabSRMM/src/mim.cpp +++ b/plugins/TabSRMM/src/mim.cpp @@ -1,672 +1,672 @@ -/*
- * Miranda NG: the free IM client for Microsoft* Windows*
- *
- * Copyright (c) 2000-09 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
- *
- * wraps some parts of Miranda API
- * Also, OS dependent stuff (visual styles api etc.)
- *
- */
-
-#include "commonheaders.h"
-
-PDTTE CMimAPI::m_pfnDrawThemeTextEx = 0;
-DEFICA CMimAPI::m_pfnDwmExtendFrameIntoClientArea = 0;
-DICE CMimAPI::m_pfnDwmIsCompositionEnabled = 0;
-DRT CMimAPI::m_pfnDwmRegisterThumbnail = 0;
-BPI CMimAPI::m_pfnBufferedPaintInit = 0;
-BPU CMimAPI::m_pfnBufferedPaintUninit = 0;
-BBP CMimAPI::m_pfnBeginBufferedPaint = 0;
-EBP CMimAPI::m_pfnEndBufferedPaint = 0;
-BBW CMimAPI::m_pfnDwmBlurBehindWindow = 0;
-DGC CMimAPI::m_pfnDwmGetColorizationColor = 0;
-BPSA CMimAPI::m_pfnBufferedPaintSetAlpha = 0;
-DWMIIB CMimAPI::m_pfnDwmInvalidateIconicBitmaps = 0;
-DWMSWA CMimAPI::m_pfnDwmSetWindowAttribute = 0;
-DWMUT CMimAPI::m_pfnDwmUpdateThumbnailProperties = 0;
-DURT CMimAPI::m_pfnDwmUnregisterThumbnail = 0;
-DSIT CMimAPI::m_pfnDwmSetIconicThumbnail = 0;
-DSILP CMimAPI::m_pfnDwmSetIconicLivePreviewBitmap = 0;
-bool CMimAPI::m_shutDown = 0;
-TCHAR CMimAPI::m_userDir[] = _T("\0");
-
-bool CMimAPI::m_haveBufferedPaint = false;
-
-/**
- * Case insensitive _tcsstr
- *
- * @param szString TCHAR *: String to be searched
- * @param szSearchFor
- *TCHAR *: String that should be found in szString
- *
- * @return TCHAR *: found position of szSearchFor in szString. 0 if szSearchFor was not found
- */
-const TCHAR* CMimAPI::StriStr(const TCHAR *szString, const TCHAR *szSearchFor)
-{
- assert(szString != 0 && szSearchFor != 0);
-
- if (!szString || *szString == 0)
- return NULL;
-
- if (!szSearchFor || *szSearchFor == 0)
- return szString;
-
- for (; *szString; ++szString) {
- if (_totupper(*szString) == _totupper(*szSearchFor)) {
- const TCHAR *h, *n;
- for (h = szString, n = szSearchFor; *h && *n; ++h, ++n)
- if (_totupper(*h) != _totupper(*n))
- break;
-
- if (!*n)
- return szString;
- }
- }
- return NULL;
-}
-
-int CMimAPI::pathIsAbsolute(const TCHAR *path) const
-{
- if (!path || !(lstrlen(path) > 2))
- return 0;
- if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
- return 1;
- return 0;
-}
-
-size_t CMimAPI::pathToRelative(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const
-{
- const TCHAR *tszBase = szBase ? szBase : m_szProfilePath;
-
- pOut[0] = 0;
- if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH)
- return 0;
- if (!pathIsAbsolute(pSrc)) {
- mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
- return lstrlen(pOut);
- }
-
- TCHAR szTmp[MAX_PATH];
- mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc);
- if (StriStr(szTmp, tszBase)) {
- if (tszBase[lstrlen(tszBase) - 1] == '\\')
- mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase));
- else {
- mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase) + 1 );
- //pOut[0]='.';
- }
- return(lstrlen(pOut));
- }
-
- mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
- return(lstrlen(pOut));
-}
-
-/**
- * Translate a relativ path to an absolute, using the current profile
- * data directory.
- *
- * @param pSrc TCHAR *: input path + filename (relative)
- * @param pOut TCHAR *: the result
- * @param szBase TCHAR *: (OPTIONAL) base path for the translation. Can be 0 in which case
- * the function will use m_szProfilePath (usually \tabSRMM below %miranda_userdata%
- *
- * @return
- */
-size_t CMimAPI::pathToAbsolute(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const
-{
- const TCHAR *tszBase = szBase ? szBase : m_szProfilePath;
-
- pOut[0] = 0;
- if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH)
- return 0;
- if (pathIsAbsolute(pSrc) && pSrc[0]!='.')
- mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
- else if (pSrc[0]=='.')
- mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc + 1);
- else
- mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc);
-
- return lstrlen(pOut);
-}
-
-/*
- * window list functions
- */
-
-void CMimAPI::BroadcastMessage(UINT msg, WPARAM wParam, LPARAM lParam)
-{
- WindowList_Broadcast(m_hMessageWindowList, msg, wParam, lParam);
-}
-
-void CMimAPI::BroadcastMessageAsync(UINT msg, WPARAM wParam, LPARAM lParam)
-{
- WindowList_BroadcastAsync(m_hMessageWindowList, msg, wParam, lParam);
-}
-
-HWND CMimAPI::FindWindow(MCONTACT h) const
-{
- return WindowList_Find(m_hMessageWindowList, h);
-}
-
-INT_PTR CMimAPI::AddWindow(HWND hWnd, MCONTACT h)
-{
- return WindowList_Add(m_hMessageWindowList, hWnd, h);
-}
-
-INT_PTR CMimAPI::RemoveWindow(HWND hWnd)
-{
- return WindowList_Remove(m_hMessageWindowList, hWnd);
-}
-
-int CMimAPI::FoldersPathChanged(WPARAM wParam, LPARAM lParam)
-{
- return M.foldersPathChanged();
-}
-
-void CMimAPI::configureCustomFolders()
-{
- m_hDataPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Data path"), const_cast<TCHAR *>(getDataPath()));
- m_hSkinsPath = FoldersRegisterCustomPathT(LPGEN("Skins"), LPGEN("TabSRMM"), const_cast<TCHAR *>(getSkinPath()));
- m_hAvatarsPath = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("Saved TabSRMM avatars"), const_cast<TCHAR *>(getSavedAvatarPath()));
- m_hChatLogsPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Group chat logs root"), const_cast<TCHAR *>(getChatLogPath()));
-
- if (m_hDataPath)
- HookEvent(ME_FOLDERS_PATH_CHANGED, CMimAPI::FoldersPathChanged);
-
- foldersPathChanged();
-}
-
-INT_PTR CMimAPI::foldersPathChanged()
-{
- TCHAR szTemp[MAX_PATH + 2] = {'\0'};
-
- if (m_hDataPath) {
- FoldersGetCustomPathT(m_hDataPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getDataPath()));
- mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%s"), szTemp);
-
- FoldersGetCustomPathT(m_hSkinsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getSkinPath()));
- mir_sntprintf(m_szSkinsPath, MAX_PATH - 1, _T("%s"), szTemp);
- Utils::ensureTralingBackslash(m_szSkinsPath);
-
- FoldersGetCustomPathT(m_hAvatarsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getSavedAvatarPath()));
- mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s"), szTemp);
-
- FoldersGetCustomPathT(m_hChatLogsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getChatLogPath()));
- mir_sntprintf(m_szChatLogsPath, MAX_PATH, _T("%s"), szTemp);
- Utils::ensureTralingBackslash(m_szChatLogsPath);
- }
-
- CreateDirectoryTreeT(m_szProfilePath);
- CreateDirectoryTreeT(m_szSkinsPath);
- CreateDirectoryTreeT(m_szSavedAvatarsPath);
-
- Skin->extractSkinsAndLogo(true);
- Skin->setupAeroSkins();
- return 0;
-}
-
-const TCHAR* CMimAPI::getUserDir()
-{
- if (m_userDir[0] == 0) {
- if ( ServiceExists(MS_FOLDERS_REGISTER_PATH))
- lstrcpyn(m_userDir, L"%miranda_userdata%", SIZEOF(m_userDir));
- else
- lstrcpyn(m_userDir, VARST( _T("%miranda_userdata%")), SIZEOF(m_userDir));
-
- Utils::ensureTralingBackslash(m_userDir);
- }
- return m_userDir;
-}
-
-void CMimAPI::InitPaths()
-{
- m_szProfilePath[0] = 0;
- m_szSkinsPath[0] = 0;
- m_szSavedAvatarsPath[0] = 0;
-
- const TCHAR *szUserdataDir = getUserDir();
-
- mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%stabSRMM"), szUserdataDir);
- if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) {
- lstrcpyn(m_szChatLogsPath, _T("%miranda_logpath%"), MAX_PATH);
- lstrcpyn(m_szSkinsPath, _T("%miranda_path%\\Skins\\TabSRMM"), MAX_PATH);
- }
- else {
- lstrcpyn(m_szChatLogsPath, VARST(_T("%miranda_logpath%")), MAX_PATH);
- lstrcpyn(m_szSkinsPath, VARST(_T("%miranda_path%\\Skins\\TabSRMM")), MAX_PATH);
- }
-
- Utils::ensureTralingBackslash(m_szChatLogsPath);
- replaceStrT(g_Settings.pszLogDir, m_szChatLogsPath);
-
- Utils::ensureTralingBackslash(m_szSkinsPath);
-
- mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s\\Saved Contact Pictures"), m_szProfilePath);
-}
-
-bool CMimAPI::getAeroState()
-{
- BOOL result = FALSE;
- m_isAero = m_DwmActive = false;
- if (IsWinVerVistaPlus()) {
- m_DwmActive = (m_pfnDwmIsCompositionEnabled && (m_pfnDwmIsCompositionEnabled(&result) == S_OK) && result) ? true : false;
- m_isAero = (CSkin::m_skinEnabled == false) && GetByte("useAero", 1) && CSkin::m_fAeroSkinsValid && m_DwmActive;
-
- }
- m_isVsThemed = IsThemeActive() != 0;
- return m_isAero;
-}
-
-/**
- * Initialize various Win32 API functions which are not common to all versions of Windows.
- * We have to work with functions pointers here.
- */
-
-void CMimAPI::InitAPI()
-{
- m_hUxTheme = 0;
-
- /*
- * vista+ DWM API
- */
- m_hDwmApi = 0;
- if (IsWinVerVistaPlus()) {
- m_hDwmApi = Utils::loadSystemLibrary(L"\\dwmapi.dll");
- if (m_hDwmApi) {
- m_pfnDwmExtendFrameIntoClientArea = (DEFICA)GetProcAddress(m_hDwmApi,"DwmExtendFrameIntoClientArea");
- m_pfnDwmIsCompositionEnabled = (DICE)GetProcAddress(m_hDwmApi,"DwmIsCompositionEnabled");
- m_pfnDwmRegisterThumbnail = (DRT)GetProcAddress(m_hDwmApi, "DwmRegisterThumbnail");
- m_pfnDwmBlurBehindWindow = (BBW)GetProcAddress(m_hDwmApi, "DwmEnableBlurBehindWindow");
- m_pfnDwmGetColorizationColor = (DGC)GetProcAddress(m_hDwmApi, "DwmGetColorizationColor");
- m_pfnDwmInvalidateIconicBitmaps = (DWMIIB)GetProcAddress(m_hDwmApi, "DwmInvalidateIconicBitmaps");
- m_pfnDwmSetWindowAttribute = (DWMSWA)GetProcAddress(m_hDwmApi, "DwmSetWindowAttribute");
- m_pfnDwmUpdateThumbnailProperties = (DWMUT)GetProcAddress(m_hDwmApi, "DwmUpdateThumbnailProperties");
- m_pfnDwmUnregisterThumbnail = (DURT)GetProcAddress(m_hDwmApi, "DwmUnregisterThumbnail");
- m_pfnDwmSetIconicThumbnail = (DSIT)GetProcAddress(m_hDwmApi, "DwmSetIconicThumbnail");
- m_pfnDwmSetIconicLivePreviewBitmap = (DSILP)GetProcAddress(m_hDwmApi, "DwmSetIconicLivePreviewBitmap");
- }
- /*
- * additional uxtheme APIs (Vista+)
- */
- m_hUxTheme = Utils::loadSystemLibrary(L"\\uxtheme.dll");
- if (m_hUxTheme) {
- m_pfnDrawThemeTextEx = (PDTTE)GetProcAddress(m_hUxTheme, "DrawThemeTextEx");
- m_pfnBeginBufferedPaint = (BBP)GetProcAddress(m_hUxTheme, "BeginBufferedPaint");
- m_pfnEndBufferedPaint = (EBP)GetProcAddress(m_hUxTheme, "EndBufferedPaint");
- m_pfnBufferedPaintInit = (BPI)GetProcAddress(m_hUxTheme, "BufferedPaintInit");
- m_pfnBufferedPaintUninit = (BPU)GetProcAddress(m_hUxTheme, "BufferedPaintUnInit");
- m_pfnBufferedPaintSetAlpha = (BPSA)GetProcAddress(m_hUxTheme, "BufferedPaintSetAlpha");
- m_haveBufferedPaint = (m_pfnBeginBufferedPaint != 0 && m_pfnEndBufferedPaint != 0) ? true : false;
- if (m_haveBufferedPaint)
- m_pfnBufferedPaintInit();
- }
- }
- else m_haveBufferedPaint = false;
-}
-
-/**
- * hook subscriber function for incoming message typing events
- */
-
-int CMimAPI::TypingMessage(WPARAM hContact, LPARAM lParam)
-{
- HWND hwnd = 0;
- int issplit = 1, foundWin = 0, preTyping = 0;
- BOOL fShowOnClist = TRUE;
-
- if (hContact) {
- if ((hwnd = M.FindWindow(hContact)) && M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING))
- preTyping = SendMessage(hwnd, DM_TYPING, 0, lParam);
-
- if (hwnd && IsWindowVisible(hwnd))
- foundWin = MessageWindowOpened(0, (LPARAM)hwnd);
- else
- foundWin = 0;
-
- TContainerData *pContainer = NULL;
- if (hwnd) {
- SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
- if (pContainer == NULL)
- return 0; // should never happen
- }
-
- if ( M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST)) {
- if (!hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGNOWINOPEN, 1))
- fShowOnClist = FALSE;
- if (hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINOPEN, 1))
- fShowOnClist = FALSE;
- }
- else fShowOnClist = FALSE;
-
- if ((!foundWin || !(pContainer->dwFlags & CNT_NOSOUND)) && preTyping != (lParam != 0))
- SkinPlaySound((lParam) ? "TNStart" : "TNStop");
-
- if (M.GetByte(SRMSGMOD, "ShowTypingPopup", 0)) {
- BOOL fShow = FALSE;
- int iMode = M.GetByte("MTN_PopupMode", 0);
-
- switch(iMode) {
- case 0:
- fShow = TRUE;
- break;
- case 1:
- if (!foundWin || !(pContainer && pContainer->hwndActive == hwnd && GetForegroundWindow() == pContainer->hwnd))
- fShow = TRUE;
- break;
- case 2:
- if (hwnd == 0)
- fShow = TRUE;
- else {
- if (PluginConfig.m_HideOnClose) {
- TContainerData *pContainer = 0;
- SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer);
- if (pContainer && pContainer->fHidden)
- fShow = TRUE;
- }
- }
- break;
- }
- if (fShow)
- TN_TypingMessage(hContact, lParam);
- }
-
- if (lParam) {
- TCHAR szTip[256];
- mir_sntprintf(szTip, SIZEOF(szTip), TranslateT("%s is typing a message."), pcli->pfnGetContactDisplayName(hContact, 0));
- if (fShowOnClist && ServiceExists(MS_CLIST_SYSTRAY_NOTIFY) && M.GetByte(SRMSGMOD, "ShowTypingBalloon", 0)) {
- MIRANDASYSTRAYNOTIFY tn;
- tn.szProto = NULL;
- tn.cbSize = sizeof(tn);
- tn.tszInfoTitle = TranslateT("Typing Notification");
- tn.tszInfo = szTip;
- tn.dwInfoFlags = NIIF_INFO | NIIF_INTERN_UNICODE;
- tn.uTimeout = 1000 * 4;
- CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&tn);
- }
- if (fShowOnClist) {
- CLISTEVENT cle = { sizeof(cle) };
- cle.hContact = hContact;
- cle.hDbEvent = (HANDLE)1;
- cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR;
- cle.hIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING];
- cle.pszService = "SRMsg/TypingMessage";
- cle.ptszTooltip = szTip;
- CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1);
- CallServiceSync(MS_CLIST_ADDEVENT, hContact, (LPARAM)&cle);
- }
- }
- }
- return 0;
-}
-
-/**
- * this is the global ack dispatcher. It handles both ACKTYPE_MESSAGE and ACKTYPE_AVATAR events
- * for ACKTYPE_MESSAGE it searches the corresponding send job in the queue and, if found, dispatches
- * it to the owners window
- *
- * ACKTYPE_AVATAR no longer handled here, because we have avs services now.
- */
-
-int CMimAPI::ProtoAck(WPARAM wParam, LPARAM lParam)
-{
- ACKDATA *pAck = (ACKDATA*)lParam;
- if (lParam == 0)
- return 0;
-
- HWND hwndDlg = 0;
- int i=0, iFound = SendQueue::NR_SENDJOBS;
- SendJob *jobs = sendQueue->getJobByIndex(0);
-
- if (pAck->type == ACKTYPE_MESSAGE) {
- MCONTACT hMeta = db_mc_getMeta(pAck->hContact);
- for (int j = 0; j < SendQueue::NR_SENDJOBS; j++) {
- SendJob &p = jobs[j];
- if (pAck->hProcess == p.hSendId && pAck->hContact == p.hOwner) {
- TWindowData *dat = p.hwndOwner ? (TWindowData*)GetWindowLongPtr(p.hwndOwner, GWLP_USERDATA) : NULL;
- if (dat == NULL) {
- sendQueue->ackMessage(NULL, (WPARAM)MAKELONG(j, i), lParam);
- return 0;
- }
- if (dat->hContact == p.hOwner || dat->hContact == hMeta) {
- iFound = j;
- break;
- }
- }
- if (iFound != SendQueue::NR_SENDJOBS) // no mathing entry found in this queue entry.. continue
- break;
- }
- if (iFound == SendQueue::NR_SENDJOBS) // no matching send info found in the queue
- sendLater->processAck(pAck);
- else // try to find the process handle in the list of open send later jobs
- SendMessage(jobs[iFound].hwndOwner, HM_EVENTSENT, (WPARAM)MAKELONG(iFound, i), lParam);
- }
- return 0;
-}
-
-int CMimAPI::PrebuildContactMenu(WPARAM hContact, LPARAM lParam)
-{
- if (hContact == NULL)
- return NULL;
-
- bool bEnabled = false;
- char *szProto = GetContactProto(hContact);
- if (szProto) {
- // leave this menu item hidden for chats
- if ( !db_get_b(hContact, szProto, "ChatRoom", 0 ))
- if ( CallProtoService( szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND)
- bEnabled = true;
- }
-
- Menu_ShowItem(PluginConfig.m_hMenuItem, bEnabled);
- return 0;
-}
-
-/**
- * this handler is called first in the message window chain - it will handle events for which a message window
- * is already open. if not, it will do nothing and the 2nd handler (MessageEventAdded) will perform all
- * the needed actions.
- *
- * this handler POSTs the event to the message window procedure - so it is fast and can exit quickly which will
- * improve the overall responsiveness when receiving messages.
- */
-
-int CMimAPI::DispatchNewEvent(WPARAM hContact, LPARAM lParam)
-{
- if (hContact) {
- HWND h = M.FindWindow(hContact);
- if (h == NULL)
- h = M.FindWindow(hContact = db_event_getContact((HANDLE)lParam));
- if (h)
- PostMessage(h, HM_DBEVENTADDED, hContact, lParam); // was SENDMESSAGE !!! XXX
- }
- return 0;
-}
-
-/**
- * Message event added is called when a new message is added to the database
- * if no session is open for the contact, this function will determine if and how a new message
- * session (tab) must be created.
- *
- * if a session is already created, it just does nothing and DispatchNewEvent() will take care.
- */
-
-int CMimAPI::MessageEventAdded(WPARAM hContact, LPARAM lParam)
-{
- TCHAR szName[CONTAINER_NAMELEN + 1];
-
- HANDLE hDbEvent = (HANDLE)lParam;
- DBEVENTINFO dbei = { sizeof(dbei) };
- db_event_get(hDbEvent, &dbei);
-
- HWND hwnd = M.FindWindow(hContact);
- if (hwnd == NULL)
- hwnd = M.FindWindow(db_event_getContact(hDbEvent));
-
- BOOL isCustomEvent = IsCustomEvent(dbei.eventType);
- BOOL isShownCustomEvent = DbEventIsForMsgWindow(&dbei);
- if (dbei.markedRead() || (isCustomEvent && !isShownCustomEvent))
- return 0;
-
- CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1);
-
- bool bAllowAutoCreate = false;
- bool bAutoPopup = M.GetByte(SRMSGSET_AUTOPOPUP, SRMSGDEFSET_AUTOPOPUP) != 0;
- bool bAutoCreate = M.GetByte("autotabs", 1) != 0;
- bool bAutoContainer = M.GetByte("autocontainer", 1) != 0;
- DWORD dwStatusMask = M.GetDword("autopopupmask", -1);
-
- if (hwnd) {
- TContainerData *pTargetContainer = 0;
- SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pTargetContainer);
- if (pTargetContainer == NULL || !PluginConfig.m_HideOnClose || IsWindowVisible(pTargetContainer->hwnd))
- return 0;
-
- WINDOWPLACEMENT wp = { 0 };
- wp.length = sizeof(wp);
- GetWindowPlacement(pTargetContainer->hwnd, &wp);
- GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN);
-
- if (bAutoPopup || bAutoCreate) {
- if (bAutoPopup) {
- if (wp.showCmd == SW_SHOWMAXIMIZED)
- ShowWindow(pTargetContainer->hwnd, SW_SHOWMAXIMIZED);
- else
- ShowWindow(pTargetContainer->hwnd, SW_SHOWNOACTIVATE);
- return 0;
- }
-
- TContainerData *pContainer = FindContainerByName(szName);
- if (pContainer != NULL) {
- if (bAutoContainer) {
- ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE);
- return 0;
- }
- goto nowindowcreate;
- }
- else if (bAutoContainer) {
- ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE);
- return 0;
- }
- }
- }
- else {
- switch (dbei.eventType) {
- case EVENTTYPE_AUTHREQUEST:
- case EVENTTYPE_ADDED:
- return 0;
-
- case EVENTTYPE_FILE:
- tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0);
- return 0;
- }
- }
-
- // if no window is open, we are not interested in anything else but unread message events
- // new message
- if (!nen_options.iNoSounds)
- SkinPlaySound("AlertMsg");
-
- if (nen_options.iNoAutoPopup)
- goto nowindowcreate;
-
- GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN);
-
- if (dwStatusMask == -1)
- bAllowAutoCreate = true;
- else {
- char *szProto = GetContactProto(hContact);
- if (szProto && !strcmp(szProto, META_PROTO)) {
- MCONTACT hSubconttact = (MCONTACT)CallService(MS_MC_GETMOSTONLINECONTACT, hContact, 0);
- szProto = GetContactProto(hSubconttact);
- }
- if (szProto) {
- DWORD dwStatus = (DWORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0);
- if (dwStatus == 0 || dwStatus <= ID_STATUS_OFFLINE || ((1 << (dwStatus - ID_STATUS_ONLINE)) & dwStatusMask)) // should never happen, but...
- bAllowAutoCreate = true;
- }
- }
-
- if (bAllowAutoCreate && (bAutoPopup || bAutoCreate)) {
- if (bAutoPopup) {
- TContainerData *pContainer = FindContainerByName(szName);
- if (pContainer == NULL)
- pContainer = CreateContainer(szName, FALSE, hContact);
- if (pContainer)
- CreateNewTabForContact(pContainer, hContact, 0, NULL, TRUE, TRUE, FALSE, 0);
- return 0;
- }
-
- bool bActivate = false, bPopup = M.GetByte("cpopup", 0) != 0;
- TContainerData *pContainer = FindContainerByName(szName);
- if (pContainer != NULL) {
- //if ((IsIconic(pContainer->hwnd)) && PluginConfig.haveAutoSwitch())
- // pContainer->dwFlags |= CNT_DEFERREDTABSELECT;
- if (M.GetByte("limittabs", 0) && !wcsncmp(pContainer->szName, L"default", 6)) {
- if ((pContainer = FindMatchingContainer(L"default", hContact)) != NULL) {
- CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent);
- return 0;
- }
- }
- else {
- CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent);
- return 0;
- }
- }
- if (bAutoContainer) {
- if ((pContainer = CreateContainer(szName, CNT_CREATEFLAG_MINIMIZED, hContact)) != NULL) { // 2 means create minimized, don't popup...
- CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent);
- SendMessageW(pContainer->hwnd, WM_SIZE, 0, 0);
- }
- return 0;
- }
- }
-
- /*
- * for tray support, we add the event to the tray menu. otherwise we send it back to
- * the contact list for flashing
- */
-nowindowcreate:
- if (!(dbei.flags & DBEF_READ)) {
- UpdateTrayMenu(0, 0, dbei.szModule, NULL, hContact, 1);
- if (!nen_options.bTraySupport) {
- TCHAR toolTip[256], *contactName;
-
- CLISTEVENT cle = { sizeof(cle) };
- cle.hContact = hContact;
- cle.hDbEvent = hDbEvent;
- cle.flags = CLEF_TCHAR;
- cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
- cle.pszService = "SRMsg/ReadMessage";
- contactName = pcli->pfnGetContactDisplayName(hContact, 0);
- mir_sntprintf(toolTip, SIZEOF(toolTip), TranslateT("Message from %s"), contactName);
- cle.ptszTooltip = toolTip;
- CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle);
- }
- tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0);
- }
- return 0;
-}
-
-CMimAPI M;
-FI_INTERFACE *FIF = 0;
+/* + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright (c) 2000-09 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 + * + * wraps some parts of Miranda API + * Also, OS dependent stuff (visual styles api etc.) + * + */ + +#include "commonheaders.h" + +PDTTE CMimAPI::m_pfnDrawThemeTextEx = 0; +DEFICA CMimAPI::m_pfnDwmExtendFrameIntoClientArea = 0; +DICE CMimAPI::m_pfnDwmIsCompositionEnabled = 0; +DRT CMimAPI::m_pfnDwmRegisterThumbnail = 0; +BPI CMimAPI::m_pfnBufferedPaintInit = 0; +BPU CMimAPI::m_pfnBufferedPaintUninit = 0; +BBP CMimAPI::m_pfnBeginBufferedPaint = 0; +EBP CMimAPI::m_pfnEndBufferedPaint = 0; +BBW CMimAPI::m_pfnDwmBlurBehindWindow = 0; +DGC CMimAPI::m_pfnDwmGetColorizationColor = 0; +BPSA CMimAPI::m_pfnBufferedPaintSetAlpha = 0; +DWMIIB CMimAPI::m_pfnDwmInvalidateIconicBitmaps = 0; +DWMSWA CMimAPI::m_pfnDwmSetWindowAttribute = 0; +DWMUT CMimAPI::m_pfnDwmUpdateThumbnailProperties = 0; +DURT CMimAPI::m_pfnDwmUnregisterThumbnail = 0; +DSIT CMimAPI::m_pfnDwmSetIconicThumbnail = 0; +DSILP CMimAPI::m_pfnDwmSetIconicLivePreviewBitmap = 0; +bool CMimAPI::m_shutDown = 0; +TCHAR CMimAPI::m_userDir[] = _T("\0"); + +bool CMimAPI::m_haveBufferedPaint = false; + +/** + * Case insensitive _tcsstr + * + * @param szString TCHAR *: String to be searched + * @param szSearchFor + *TCHAR *: String that should be found in szString + * + * @return TCHAR *: found position of szSearchFor in szString. 0 if szSearchFor was not found + */ +const TCHAR* CMimAPI::StriStr(const TCHAR *szString, const TCHAR *szSearchFor) +{ + assert(szString != 0 && szSearchFor != 0); + + if (!szString || *szString == 0) + return NULL; + + if (!szSearchFor || *szSearchFor == 0) + return szString; + + for (; *szString; ++szString) { + if (_totupper(*szString) == _totupper(*szSearchFor)) { + const TCHAR *h, *n; + for (h = szString, n = szSearchFor; *h && *n; ++h, ++n) + if (_totupper(*h) != _totupper(*n)) + break; + + if (!*n) + return szString; + } + } + return NULL; +} + +int CMimAPI::pathIsAbsolute(const TCHAR *path) const +{ + if (!path || !(lstrlen(path) > 2)) + return 0; + if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\')) + return 1; + return 0; +} + +size_t CMimAPI::pathToRelative(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const +{ + const TCHAR *tszBase = szBase ? szBase : m_szProfilePath; + + pOut[0] = 0; + if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH) + return 0; + if (!pathIsAbsolute(pSrc)) { + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); + return lstrlen(pOut); + } + + TCHAR szTmp[MAX_PATH]; + mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc); + if (StriStr(szTmp, tszBase)) { + if (tszBase[lstrlen(tszBase) - 1] == '\\') + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase)); + else { + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc + lstrlen(tszBase) + 1 ); + //pOut[0]='.'; + } + return(lstrlen(pOut)); + } + + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); + return(lstrlen(pOut)); +} + +/** + * Translate a relativ path to an absolute, using the current profile + * data directory. + * + * @param pSrc TCHAR *: input path + filename (relative) + * @param pOut TCHAR *: the result + * @param szBase TCHAR *: (OPTIONAL) base path for the translation. Can be 0 in which case + * the function will use m_szProfilePath (usually \tabSRMM below %miranda_userdata% + * + * @return + */ +size_t CMimAPI::pathToAbsolute(const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase) const +{ + const TCHAR *tszBase = szBase ? szBase : m_szProfilePath; + + pOut[0] = 0; + if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH) + return 0; + if (pathIsAbsolute(pSrc) && pSrc[0]!='.') + mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc); + else if (pSrc[0]=='.') + mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc + 1); + else + mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), tszBase, pSrc); + + return lstrlen(pOut); +} + +/* + * window list functions + */ + +void CMimAPI::BroadcastMessage(UINT msg, WPARAM wParam, LPARAM lParam) +{ + WindowList_Broadcast(m_hMessageWindowList, msg, wParam, lParam); +} + +void CMimAPI::BroadcastMessageAsync(UINT msg, WPARAM wParam, LPARAM lParam) +{ + WindowList_BroadcastAsync(m_hMessageWindowList, msg, wParam, lParam); +} + +HWND CMimAPI::FindWindow(MCONTACT h) const +{ + return WindowList_Find(m_hMessageWindowList, h); +} + +INT_PTR CMimAPI::AddWindow(HWND hWnd, MCONTACT h) +{ + return WindowList_Add(m_hMessageWindowList, hWnd, h); +} + +INT_PTR CMimAPI::RemoveWindow(HWND hWnd) +{ + return WindowList_Remove(m_hMessageWindowList, hWnd); +} + +int CMimAPI::FoldersPathChanged(WPARAM wParam, LPARAM lParam) +{ + return M.foldersPathChanged(); +} + +void CMimAPI::configureCustomFolders() +{ + m_hDataPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Data path"), const_cast<TCHAR *>(getDataPath())); + m_hSkinsPath = FoldersRegisterCustomPathT(LPGEN("Skins"), LPGEN("TabSRMM"), const_cast<TCHAR *>(getSkinPath())); + m_hAvatarsPath = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("Saved TabSRMM avatars"), const_cast<TCHAR *>(getSavedAvatarPath())); + m_hChatLogsPath = FoldersRegisterCustomPathT(LPGEN("TabSRMM"), LPGEN("Group chat logs root"), const_cast<TCHAR *>(getChatLogPath())); + + if (m_hDataPath) + HookEvent(ME_FOLDERS_PATH_CHANGED, CMimAPI::FoldersPathChanged); + + foldersPathChanged(); +} + +INT_PTR CMimAPI::foldersPathChanged() +{ + TCHAR szTemp[MAX_PATH + 2] = {'\0'}; + + if (m_hDataPath) { + FoldersGetCustomPathT(m_hDataPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getDataPath())); + mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%s"), szTemp); + + FoldersGetCustomPathT(m_hSkinsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getSkinPath())); + mir_sntprintf(m_szSkinsPath, MAX_PATH - 1, _T("%s"), szTemp); + Utils::ensureTralingBackslash(m_szSkinsPath); + + FoldersGetCustomPathT(m_hAvatarsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getSavedAvatarPath())); + mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s"), szTemp); + + FoldersGetCustomPathT(m_hChatLogsPath, szTemp, MAX_PATH, const_cast<TCHAR *>(getChatLogPath())); + mir_sntprintf(m_szChatLogsPath, MAX_PATH, _T("%s"), szTemp); + Utils::ensureTralingBackslash(m_szChatLogsPath); + } + + CreateDirectoryTreeT(m_szProfilePath); + CreateDirectoryTreeT(m_szSkinsPath); + CreateDirectoryTreeT(m_szSavedAvatarsPath); + + Skin->extractSkinsAndLogo(true); + Skin->setupAeroSkins(); + return 0; +} + +const TCHAR* CMimAPI::getUserDir() +{ + if (m_userDir[0] == 0) { + if ( ServiceExists(MS_FOLDERS_REGISTER_PATH)) + lstrcpyn(m_userDir, L"%miranda_userdata%", SIZEOF(m_userDir)); + else + lstrcpyn(m_userDir, VARST( _T("%miranda_userdata%")), SIZEOF(m_userDir)); + + Utils::ensureTralingBackslash(m_userDir); + } + return m_userDir; +} + +void CMimAPI::InitPaths() +{ + m_szProfilePath[0] = 0; + m_szSkinsPath[0] = 0; + m_szSavedAvatarsPath[0] = 0; + + const TCHAR *szUserdataDir = getUserDir(); + + mir_sntprintf(m_szProfilePath, MAX_PATH, _T("%stabSRMM"), szUserdataDir); + if (ServiceExists(MS_FOLDERS_REGISTER_PATH)) { + lstrcpyn(m_szChatLogsPath, _T("%miranda_logpath%"), MAX_PATH); + lstrcpyn(m_szSkinsPath, _T("%miranda_path%\\Skins\\TabSRMM"), MAX_PATH); + } + else { + lstrcpyn(m_szChatLogsPath, VARST(_T("%miranda_logpath%")), MAX_PATH); + lstrcpyn(m_szSkinsPath, VARST(_T("%miranda_path%\\Skins\\TabSRMM")), MAX_PATH); + } + + Utils::ensureTralingBackslash(m_szChatLogsPath); + replaceStrT(g_Settings.pszLogDir, m_szChatLogsPath); + + Utils::ensureTralingBackslash(m_szSkinsPath); + + mir_sntprintf(m_szSavedAvatarsPath, MAX_PATH, _T("%s\\Saved Contact Pictures"), m_szProfilePath); +} + +bool CMimAPI::getAeroState() +{ + BOOL result = FALSE; + m_isAero = m_DwmActive = false; + if (IsWinVerVistaPlus()) { + m_DwmActive = (m_pfnDwmIsCompositionEnabled && (m_pfnDwmIsCompositionEnabled(&result) == S_OK) && result) ? true : false; + m_isAero = (CSkin::m_skinEnabled == false) && GetByte("useAero", 1) && CSkin::m_fAeroSkinsValid && m_DwmActive; + + } + m_isVsThemed = IsThemeActive() != 0; + return m_isAero; +} + +/** + * Initialize various Win32 API functions which are not common to all versions of Windows. + * We have to work with functions pointers here. + */ + +void CMimAPI::InitAPI() +{ + m_hUxTheme = 0; + + /* + * vista+ DWM API + */ + m_hDwmApi = 0; + if (IsWinVerVistaPlus()) { + m_hDwmApi = Utils::loadSystemLibrary(L"\\dwmapi.dll"); + if (m_hDwmApi) { + m_pfnDwmExtendFrameIntoClientArea = (DEFICA)GetProcAddress(m_hDwmApi,"DwmExtendFrameIntoClientArea"); + m_pfnDwmIsCompositionEnabled = (DICE)GetProcAddress(m_hDwmApi,"DwmIsCompositionEnabled"); + m_pfnDwmRegisterThumbnail = (DRT)GetProcAddress(m_hDwmApi, "DwmRegisterThumbnail"); + m_pfnDwmBlurBehindWindow = (BBW)GetProcAddress(m_hDwmApi, "DwmEnableBlurBehindWindow"); + m_pfnDwmGetColorizationColor = (DGC)GetProcAddress(m_hDwmApi, "DwmGetColorizationColor"); + m_pfnDwmInvalidateIconicBitmaps = (DWMIIB)GetProcAddress(m_hDwmApi, "DwmInvalidateIconicBitmaps"); + m_pfnDwmSetWindowAttribute = (DWMSWA)GetProcAddress(m_hDwmApi, "DwmSetWindowAttribute"); + m_pfnDwmUpdateThumbnailProperties = (DWMUT)GetProcAddress(m_hDwmApi, "DwmUpdateThumbnailProperties"); + m_pfnDwmUnregisterThumbnail = (DURT)GetProcAddress(m_hDwmApi, "DwmUnregisterThumbnail"); + m_pfnDwmSetIconicThumbnail = (DSIT)GetProcAddress(m_hDwmApi, "DwmSetIconicThumbnail"); + m_pfnDwmSetIconicLivePreviewBitmap = (DSILP)GetProcAddress(m_hDwmApi, "DwmSetIconicLivePreviewBitmap"); + } + /* + * additional uxtheme APIs (Vista+) + */ + m_hUxTheme = Utils::loadSystemLibrary(L"\\uxtheme.dll"); + if (m_hUxTheme) { + m_pfnDrawThemeTextEx = (PDTTE)GetProcAddress(m_hUxTheme, "DrawThemeTextEx"); + m_pfnBeginBufferedPaint = (BBP)GetProcAddress(m_hUxTheme, "BeginBufferedPaint"); + m_pfnEndBufferedPaint = (EBP)GetProcAddress(m_hUxTheme, "EndBufferedPaint"); + m_pfnBufferedPaintInit = (BPI)GetProcAddress(m_hUxTheme, "BufferedPaintInit"); + m_pfnBufferedPaintUninit = (BPU)GetProcAddress(m_hUxTheme, "BufferedPaintUnInit"); + m_pfnBufferedPaintSetAlpha = (BPSA)GetProcAddress(m_hUxTheme, "BufferedPaintSetAlpha"); + m_haveBufferedPaint = (m_pfnBeginBufferedPaint != 0 && m_pfnEndBufferedPaint != 0) ? true : false; + if (m_haveBufferedPaint) + m_pfnBufferedPaintInit(); + } + } + else m_haveBufferedPaint = false; +} + +/** + * hook subscriber function for incoming message typing events + */ + +int CMimAPI::TypingMessage(WPARAM hContact, LPARAM lParam) +{ + HWND hwnd = 0; + int issplit = 1, foundWin = 0, preTyping = 0; + BOOL fShowOnClist = TRUE; + + if (hContact) { + if ((hwnd = M.FindWindow(hContact)) && M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING)) + preTyping = SendMessage(hwnd, DM_TYPING, 0, lParam); + + if (hwnd && IsWindowVisible(hwnd)) + foundWin = MessageWindowOpened(0, (LPARAM)hwnd); + else + foundWin = 0; + + TContainerData *pContainer = NULL; + if (hwnd) { + SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer); + if (pContainer == NULL) + return 0; // should never happen + } + + if ( M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST)) { + if (!hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGNOWINOPEN, 1)) + fShowOnClist = FALSE; + if (hwnd && !M.GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINOPEN, 1)) + fShowOnClist = FALSE; + } + else fShowOnClist = FALSE; + + if ((!foundWin || !(pContainer->dwFlags & CNT_NOSOUND)) && preTyping != (lParam != 0)) + SkinPlaySound((lParam) ? "TNStart" : "TNStop"); + + if (M.GetByte(SRMSGMOD, "ShowTypingPopup", 0)) { + BOOL fShow = FALSE; + int iMode = M.GetByte("MTN_PopupMode", 0); + + switch(iMode) { + case 0: + fShow = TRUE; + break; + case 1: + if (!foundWin || !(pContainer && pContainer->hwndActive == hwnd && GetForegroundWindow() == pContainer->hwnd)) + fShow = TRUE; + break; + case 2: + if (hwnd == 0) + fShow = TRUE; + else { + if (PluginConfig.m_HideOnClose) { + TContainerData *pContainer = 0; + SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pContainer); + if (pContainer && pContainer->fHidden) + fShow = TRUE; + } + } + break; + } + if (fShow) + TN_TypingMessage(hContact, lParam); + } + + if (lParam) { + TCHAR szTip[256]; + mir_sntprintf(szTip, SIZEOF(szTip), TranslateT("%s is typing a message"), pcli->pfnGetContactDisplayName(hContact, 0)); + if (fShowOnClist && ServiceExists(MS_CLIST_SYSTRAY_NOTIFY) && M.GetByte(SRMSGMOD, "ShowTypingBalloon", 0)) { + MIRANDASYSTRAYNOTIFY tn; + tn.szProto = NULL; + tn.cbSize = sizeof(tn); + tn.tszInfoTitle = TranslateT("Typing Notification"); + tn.tszInfo = szTip; + tn.dwInfoFlags = NIIF_INFO | NIIF_INTERN_UNICODE; + tn.uTimeout = 1000 * 4; + CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&tn); + } + if (fShowOnClist) { + CLISTEVENT cle = { sizeof(cle) }; + cle.hContact = hContact; + cle.hDbEvent = (HANDLE)1; + cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR; + cle.hIcon = PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]; + cle.pszService = "SRMsg/TypingMessage"; + cle.ptszTooltip = szTip; + CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1); + CallServiceSync(MS_CLIST_ADDEVENT, hContact, (LPARAM)&cle); + } + } + } + return 0; +} + +/** + * this is the global ack dispatcher. It handles both ACKTYPE_MESSAGE and ACKTYPE_AVATAR events + * for ACKTYPE_MESSAGE it searches the corresponding send job in the queue and, if found, dispatches + * it to the owners window + * + * ACKTYPE_AVATAR no longer handled here, because we have avs services now. + */ + +int CMimAPI::ProtoAck(WPARAM wParam, LPARAM lParam) +{ + ACKDATA *pAck = (ACKDATA*)lParam; + if (lParam == 0) + return 0; + + HWND hwndDlg = 0; + int i=0, iFound = SendQueue::NR_SENDJOBS; + SendJob *jobs = sendQueue->getJobByIndex(0); + + if (pAck->type == ACKTYPE_MESSAGE) { + MCONTACT hMeta = db_mc_getMeta(pAck->hContact); + for (int j = 0; j < SendQueue::NR_SENDJOBS; j++) { + SendJob &p = jobs[j]; + if (pAck->hProcess == p.hSendId && pAck->hContact == p.hOwner) { + TWindowData *dat = p.hwndOwner ? (TWindowData*)GetWindowLongPtr(p.hwndOwner, GWLP_USERDATA) : NULL; + if (dat == NULL) { + sendQueue->ackMessage(NULL, (WPARAM)MAKELONG(j, i), lParam); + return 0; + } + if (dat->hContact == p.hOwner || dat->hContact == hMeta) { + iFound = j; + break; + } + } + if (iFound != SendQueue::NR_SENDJOBS) // no mathing entry found in this queue entry.. continue + break; + } + if (iFound == SendQueue::NR_SENDJOBS) // no matching send info found in the queue + sendLater->processAck(pAck); + else // try to find the process handle in the list of open send later jobs + SendMessage(jobs[iFound].hwndOwner, HM_EVENTSENT, (WPARAM)MAKELONG(iFound, i), lParam); + } + return 0; +} + +int CMimAPI::PrebuildContactMenu(WPARAM hContact, LPARAM lParam) +{ + if (hContact == NULL) + return NULL; + + bool bEnabled = false; + char *szProto = GetContactProto(hContact); + if (szProto) { + // leave this menu item hidden for chats + if ( !db_get_b(hContact, szProto, "ChatRoom", 0 )) + if ( CallProtoService( szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND) + bEnabled = true; + } + + Menu_ShowItem(PluginConfig.m_hMenuItem, bEnabled); + return 0; +} + +/** + * this handler is called first in the message window chain - it will handle events for which a message window + * is already open. if not, it will do nothing and the 2nd handler (MessageEventAdded) will perform all + * the needed actions. + * + * this handler POSTs the event to the message window procedure - so it is fast and can exit quickly which will + * improve the overall responsiveness when receiving messages. + */ + +int CMimAPI::DispatchNewEvent(WPARAM hContact, LPARAM lParam) +{ + if (hContact) { + HWND h = M.FindWindow(hContact); + if (h == NULL) + h = M.FindWindow(hContact = db_event_getContact((HANDLE)lParam)); + if (h) + PostMessage(h, HM_DBEVENTADDED, hContact, lParam); // was SENDMESSAGE !!! XXX + } + return 0; +} + +/** + * Message event added is called when a new message is added to the database + * if no session is open for the contact, this function will determine if and how a new message + * session (tab) must be created. + * + * if a session is already created, it just does nothing and DispatchNewEvent() will take care. + */ + +int CMimAPI::MessageEventAdded(WPARAM hContact, LPARAM lParam) +{ + TCHAR szName[CONTAINER_NAMELEN + 1]; + + HANDLE hDbEvent = (HANDLE)lParam; + DBEVENTINFO dbei = { sizeof(dbei) }; + db_event_get(hDbEvent, &dbei); + + HWND hwnd = M.FindWindow(hContact); + if (hwnd == NULL) + hwnd = M.FindWindow(db_event_getContact(hDbEvent)); + + BOOL isCustomEvent = IsCustomEvent(dbei.eventType); + BOOL isShownCustomEvent = DbEventIsForMsgWindow(&dbei); + if (dbei.markedRead() || (isCustomEvent && !isShownCustomEvent)) + return 0; + + CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1); + + bool bAllowAutoCreate = false; + bool bAutoPopup = M.GetByte(SRMSGSET_AUTOPOPUP, SRMSGDEFSET_AUTOPOPUP) != 0; + bool bAutoCreate = M.GetByte("autotabs", 1) != 0; + bool bAutoContainer = M.GetByte("autocontainer", 1) != 0; + DWORD dwStatusMask = M.GetDword("autopopupmask", -1); + + if (hwnd) { + TContainerData *pTargetContainer = 0; + SendMessage(hwnd, DM_QUERYCONTAINER, 0, (LPARAM)&pTargetContainer); + if (pTargetContainer == NULL || !PluginConfig.m_HideOnClose || IsWindowVisible(pTargetContainer->hwnd)) + return 0; + + WINDOWPLACEMENT wp = { 0 }; + wp.length = sizeof(wp); + GetWindowPlacement(pTargetContainer->hwnd, &wp); + GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN); + + if (bAutoPopup || bAutoCreate) { + if (bAutoPopup) { + if (wp.showCmd == SW_SHOWMAXIMIZED) + ShowWindow(pTargetContainer->hwnd, SW_SHOWMAXIMIZED); + else + ShowWindow(pTargetContainer->hwnd, SW_SHOWNOACTIVATE); + return 0; + } + + TContainerData *pContainer = FindContainerByName(szName); + if (pContainer != NULL) { + if (bAutoContainer) { + ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE); + return 0; + } + goto nowindowcreate; + } + else if (bAutoContainer) { + ShowWindow(pTargetContainer->hwnd, SW_SHOWMINNOACTIVE); + return 0; + } + } + } + else { + switch (dbei.eventType) { + case EVENTTYPE_AUTHREQUEST: + case EVENTTYPE_ADDED: + return 0; + + case EVENTTYPE_FILE: + tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0); + return 0; + } + } + + // if no window is open, we are not interested in anything else but unread message events + // new message + if (!nen_options.iNoSounds) + SkinPlaySound("AlertMsg"); + + if (nen_options.iNoAutoPopup) + goto nowindowcreate; + + GetContainerNameForContact(hContact, szName, CONTAINER_NAMELEN); + + if (dwStatusMask == -1) + bAllowAutoCreate = true; + else { + char *szProto = GetContactProto(hContact); + if (szProto && !strcmp(szProto, META_PROTO)) { + MCONTACT hSubconttact = (MCONTACT)CallService(MS_MC_GETMOSTONLINECONTACT, hContact, 0); + szProto = GetContactProto(hSubconttact); + } + if (szProto) { + DWORD dwStatus = (DWORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0); + if (dwStatus == 0 || dwStatus <= ID_STATUS_OFFLINE || ((1 << (dwStatus - ID_STATUS_ONLINE)) & dwStatusMask)) // should never happen, but... + bAllowAutoCreate = true; + } + } + + if (bAllowAutoCreate && (bAutoPopup || bAutoCreate)) { + if (bAutoPopup) { + TContainerData *pContainer = FindContainerByName(szName); + if (pContainer == NULL) + pContainer = CreateContainer(szName, FALSE, hContact); + if (pContainer) + CreateNewTabForContact(pContainer, hContact, 0, NULL, TRUE, TRUE, FALSE, 0); + return 0; + } + + bool bActivate = false, bPopup = M.GetByte("cpopup", 0) != 0; + TContainerData *pContainer = FindContainerByName(szName); + if (pContainer != NULL) { + //if ((IsIconic(pContainer->hwnd)) && PluginConfig.haveAutoSwitch()) + // pContainer->dwFlags |= CNT_DEFERREDTABSELECT; + if (M.GetByte("limittabs", 0) && !wcsncmp(pContainer->szName, L"default", 6)) { + if ((pContainer = FindMatchingContainer(L"default", hContact)) != NULL) { + CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent); + return 0; + } + } + else { + CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent); + return 0; + } + } + if (bAutoContainer) { + if ((pContainer = CreateContainer(szName, CNT_CREATEFLAG_MINIMIZED, hContact)) != NULL) { // 2 means create minimized, don't popup... + CreateNewTabForContact(pContainer, hContact, 0, NULL, bActivate, bPopup, TRUE, hDbEvent); + SendMessageW(pContainer->hwnd, WM_SIZE, 0, 0); + } + return 0; + } + } + + /* + * for tray support, we add the event to the tray menu. otherwise we send it back to + * the contact list for flashing + */ +nowindowcreate: + if (!(dbei.flags & DBEF_READ)) { + UpdateTrayMenu(0, 0, dbei.szModule, NULL, hContact, 1); + if (!nen_options.bTraySupport) { + TCHAR toolTip[256], *contactName; + + CLISTEVENT cle = { sizeof(cle) }; + cle.hContact = hContact; + cle.hDbEvent = hDbEvent; + cle.flags = CLEF_TCHAR; + cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE); + cle.pszService = "SRMsg/ReadMessage"; + contactName = pcli->pfnGetContactDisplayName(hContact, 0); + mir_sntprintf(toolTip, SIZEOF(toolTip), TranslateT("Message from %s"), contactName); + cle.ptszTooltip = toolTip; + CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); + } + tabSRMM_ShowPopup(hContact, hDbEvent, dbei.eventType, 0, 0, 0, dbei.szModule, 0); + } + return 0; +} + +CMimAPI M; +FI_INTERFACE *FIF = 0; |