From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/tabsrmm/src/msgdlgutils.cpp | 2555 +++++++++++++++++++++++++++++++++++ 1 file changed, 2555 insertions(+) create mode 100644 plugins/tabsrmm/src/msgdlgutils.cpp (limited to 'plugins/tabsrmm/src/msgdlgutils.cpp') diff --git a/plugins/tabsrmm/src/msgdlgutils.cpp b/plugins/tabsrmm/src/msgdlgutils.cpp new file mode 100644 index 0000000000..caefdcffc3 --- /dev/null +++ b/plugins/tabsrmm/src/msgdlgutils.cpp @@ -0,0 +1,2555 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda IM: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: msgdlgutils.cpp 13650 2011-05-30 11:53:13Z silvercircle@gmail.com $ + * + * Helper functions for the message dialog. + * + */ + +#include "commonheaders.h" +#pragma hdrstop + +//#include "m_MathModule.h" + +extern NEN_OPTIONS nen_options; +extern LOGFONTA logfonts[MSGDLGFONTCOUNT + 2]; +extern COLORREF fontcolors[MSGDLGFONTCOUNT + 2]; +extern TTemplateSet LTR_Active, RTL_Active; + +#ifndef SHVIEW_THUMBNAIL +#define SHVIEW_THUMBNAIL 0x702D +#endif + +#define EVENTTYPE_NICKNAME_CHANGE 9001 +#define EVENTTYPE_STATUSMESSAGE_CHANGE 9002 +#define EVENTTYPE_AVATAR_CHANGE 9003 +#define EVENTTYPE_CONTACTLEFTCHANNEL 9004 +#define EVENTTYPE_WAT_ANSWER 9602 +#define EVENTTYPE_JABBER_CHATSTATES 2000 +#define EVENTTYPE_JABBER_PRESENCE 2001 + +static int g_status_events[] = { + EVENTTYPE_STATUSCHANGE, + EVENTTYPE_CONTACTLEFTCHANNEL, + EVENTTYPE_WAT_ANSWER, + EVENTTYPE_JABBER_CHATSTATES, + EVENTTYPE_JABBER_PRESENCE +}; + +static int g_status_events_size = 0; +#define MAX_REGS(_A_) ( sizeof(_A_) / sizeof(_A_[0]) ) + +BOOL TSAPI IsStatusEvent(int eventType) +{ + int i; + + if (g_status_events_size == 0) + g_status_events_size = MAX_REGS(g_status_events); + + for (i = 0; i < g_status_events_size; i++) { + if (eventType == g_status_events[i]) + return TRUE; + } + return FALSE; +} + +/* + * reorder tabs within a container. fSavePos indicates whether the new position should be saved to the + * contacts db record (if so, the container will try to open the tab at the saved position later) + */ + +void TSAPI RearrangeTab(HWND hwndDlg, const TWindowData *dat, int iMode, BOOL fSavePos) +{ + TCITEM item = {0}; + HWND hwndTab = GetParent(hwndDlg); + int newIndex; + TCHAR oldText[512]; + item.mask = TCIF_IMAGE | TCIF_TEXT | TCIF_PARAM; + item.pszText = oldText; + item.cchTextMax = 500; + + if (dat == NULL || !IsWindow(hwndDlg)) + return; + + TabCtrl_GetItem(hwndTab, dat->iTabID, &item); + newIndex = LOWORD(iMode); + + if (newIndex >= 0 && newIndex <= TabCtrl_GetItemCount(hwndTab)) { + TabCtrl_DeleteItem(hwndTab, dat->iTabID); + item.lParam = (LPARAM)hwndDlg; + TabCtrl_InsertItem(hwndTab, newIndex, &item); + BroadCastContainer(dat->pContainer, DM_REFRESHTABINDEX, 0, 0); + ActivateTabFromHWND(hwndTab, hwndDlg); + if (fSavePos) + M->WriteDword(dat->hContact, SRMSGMOD_T, "tabindex", newIndex * 100); + } +} + +/* + * subclassing for the save as file dialog (needed to set it to thumbnail view on Windows 2000 + * or later + */ + +static BOOL CALLBACK OpenFileSubclass(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_INITDIALOG: { + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)lParam); + break; + } + case WM_NOTIFY: { + OPENFILENAMEA *ofn = (OPENFILENAMEA *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + HWND hwndParent = GetParent(hwnd); + HWND hwndLv = FindWindowEx(hwndParent, NULL, _T("SHELLDLL_DefView"), NULL) ; + + if (hwndLv != NULL && *((DWORD *)(ofn->lCustData))) { + SendMessage(hwndLv, WM_COMMAND, SHVIEW_THUMBNAIL, 0); + *((DWORD *)(ofn->lCustData)) = 0; + } + break; + } + } + return FALSE; +} + +/* + * saves a contact picture to disk + * takes hbm (bitmap handle) and bool isOwnPic (1 == save the picture as your own avatar) + * requires AVS and ADVAIMG services (Miranda 0.7+) + */ + +static void SaveAvatarToFile(TWindowData *dat, HBITMAP hbm, int isOwnPic) +{ + TCHAR szFinalPath[MAX_PATH]; + TCHAR szFinalFilename[MAX_PATH]; + TCHAR szBaseName[MAX_PATH]; + TCHAR szTimestamp[100]; + OPENFILENAME ofn = {0}; + time_t t = time(NULL); + struct tm *lt = localtime(&t); + DWORD setView = 1; + + mir_sntprintf(szTimestamp, 100, _T("%04u %02u %02u_%02u%02u"), lt->tm_year + 1900, lt->tm_mon, lt->tm_mday, lt->tm_hour, lt->tm_min); + + TCHAR *szProto = mir_a2t(dat->cache->getActiveProto()); + + mir_sntprintf(szFinalPath, MAX_PATH, _T("%s\\%s"), M->getSavedAvatarPath(), szProto); + mir_free(szProto); + + if (CreateDirectory(szFinalPath, 0) == 0) { + if (GetLastError() != ERROR_ALREADY_EXISTS) { + MessageBox(0, CTranslator::get(CTranslator::GEN_MSG_SAVE_NODIR), + CTranslator::get(CTranslator::GEN_MSG_SAVE), MB_OK | MB_ICONSTOP); + return; + } + } + if (isOwnPic) + mir_sntprintf(szBaseName, MAX_PATH,_T("My Avatar_%s"), szTimestamp); + else + mir_sntprintf(szBaseName, MAX_PATH, _T("%s_%s"), dat->cache->getNick(), szTimestamp); + + mir_sntprintf(szFinalFilename, MAX_PATH, _T("%s.png"), szBaseName); + ofn.lpstrDefExt = _T("png"); + + /* + * do not allow / or \ or % in the filename + */ + Utils::sanitizeFilename(szFinalFilename); + + TCHAR filter[MAX_PATH]; + mir_sntprintf(filter, SIZEOF(filter), _T("%s%c*.bmp;*.png;*.jpg;*.gif%c%c"), TranslateT("Image files"), 0, 0, 0); + ofn.lpstrFilter = filter; + if (IsWinVer2000Plus()) { + ofn.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLESIZING | OFN_ENABLEHOOK; + ofn.lpfnHook = (LPOFNHOOKPROC)OpenFileSubclass; + ofn.lStructSize = sizeof(ofn); + } else { + ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; + ofn.Flags = OFN_HIDEREADONLY; + } + ofn.hwndOwner = 0; + ofn.lpstrFile = szFinalFilename; + ofn.lpstrInitialDir = szFinalPath; + ofn.nMaxFile = MAX_PATH; + ofn.nMaxFileTitle = MAX_PATH; + ofn.lCustData = (LPARAM) & setView; + if (GetSaveFileName(&ofn)) { + if (PathFileExists(szFinalFilename)) { + if (MessageBox(0, CTranslator::get(CTranslator::GEN_MSG_SAVE_FILE_EXISTS), + CTranslator::get(CTranslator::GEN_MSG_SAVE), MB_YESNO | MB_ICONQUESTION) == IDNO) + return; + } + IMGSRVC_INFO ii; + ii.cbSize = sizeof(ii); + ii.wszName = szFinalFilename; + ii.hbm = hbm; + ii.dwMask = IMGI_HBITMAP; + ii.fif = FIF_UNKNOWN; // get the format from the filename extension. png is default. + CallService(MS_IMG_SAVE, (WPARAM)&ii, IMGL_TCHAR); + } +} + +/* + * flash a tab icon if mode = true, otherwise restore default icon + * store flashing state into bState + */ + +void TSAPI FlashTab(struct TWindowData *dat, HWND hwndTab, int iTabindex, BOOL *bState, BOOL mode, HICON origImage) +{ + TCITEM item; + + ZeroMemory((void *)&item, sizeof(item)); + item.mask = TCIF_IMAGE; + + if (mode) + *bState = !(*bState); + else + dat->hTabIcon = origImage; + item.iImage = 0; + TabCtrl_SetItem(hwndTab, iTabindex, &item); + if(dat->pContainer->dwFlags & CNT_SIDEBAR) + dat->pContainer->SideBar->updateSession(dat); +} + +/* + * calculates avatar layouting, based on splitter position to find the optimal size + * for the avatar w/o disturbing the toolbar too much. + */ + +void TSAPI CalcDynamicAvatarSize(TWindowData *dat, BITMAP *bminfo) +{ + RECT rc; + double aspect = 0, newWidth = 0, picAspect = 0; + double picProjectedWidth = 0; + BOOL bBottomToolBar=dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR; + BOOL bToolBar=dat->pContainer->dwFlags & CNT_HIDETOOLBAR?0:1; + bool fInfoPanel = dat->Panel->isActive(); + int iSplitOffset = dat->fIsAutosizingInput ? 1 : 0; + + if (PluginConfig.g_FlashAvatarAvail) { + FLASHAVATAR fa = {0}; + fa.cProto = dat->szProto; + fa.id = 25367; + fa.hContact = fInfoPanel ? NULL : dat->hContact; + CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0); + if (fa.hWindow) { + bminfo->bmHeight = FAVATAR_HEIGHT; + bminfo->bmWidth = FAVATAR_WIDTH; + } + } + GetClientRect(dat->hwnd, &rc); + + if (dat->dwFlags & MWF_WASBACKGROUNDCREATE || dat->pContainer->dwFlags & CNT_DEFERREDCONFIGURE || dat->pContainer->dwFlags & CNT_CREATE_MINIMIZED || IsIconic(dat->pContainer->hwnd)) + return; // at this stage, the layout is not yet ready... + + if (bminfo->bmWidth == 0 || bminfo->bmHeight == 0) + picAspect = 1.0; + else + picAspect = (double)(bminfo->bmWidth / (double)bminfo->bmHeight); + picProjectedWidth = (double)((dat->dynaSplitter-((bBottomToolBar && bToolBar)? DPISCALEX_S(24):0) + ((dat->showUIElements != 0) ? DPISCALEX_S(28) : DPISCALEX_S(2)))) * picAspect; + + if ((rc.right - (int)picProjectedWidth) > (dat->iButtonBarReallyNeeds) && !PluginConfig.m_AlwaysFullToolbarWidth && bToolBar) + dat->iRealAvatarHeight = dat->dynaSplitter + 3 + (dat->showUIElements ? DPISCALEY_S(28):DPISCALEY_S(2)); + else + dat->iRealAvatarHeight = dat->dynaSplitter + DPISCALEY_S(6) + DPISCALEY_S(iSplitOffset); + + dat->iRealAvatarHeight-=((bBottomToolBar&&bToolBar) ? DPISCALEY_S(22) : 0); + + if (PluginConfig.m_LimitStaticAvatarHeight > 0) + dat->iRealAvatarHeight = min(dat->iRealAvatarHeight, PluginConfig.m_LimitStaticAvatarHeight); + + if (M->GetByte(dat->hContact, "dontscaleavatars", M->GetByte("dontscaleavatars", 0))) + dat->iRealAvatarHeight = min(bminfo->bmHeight, dat->iRealAvatarHeight); + + if (bminfo->bmHeight != 0) + aspect = (double)dat->iRealAvatarHeight / (double)bminfo->bmHeight; + else + aspect = 1; + + newWidth = (double)bminfo->bmWidth * aspect; + if (newWidth > (double)(rc.right) * 0.8) + newWidth = (double)(rc.right) * 0.8; + dat->pic.cy = dat->iRealAvatarHeight + 2; + dat->pic.cx = (int)newWidth + 2; +} + +void TSAPI WriteStatsOnClose(TWindowData *dat) +{ + /* + DBEVENTINFO dbei; + char buffer[450]; + HANDLE hNewEvent; + time_t now = time(NULL); + now = now - dat->stats.started; + + return; + + if (dat->hContact != 0 &&(PluginConfig.m_LogStatusChanges != 0) && dat->dwFlags & MWF_LOG_STATUSCHANGES) { + mir_snprintf(buffer, sizeof(buffer), "Session close - active for: %d:%02d:%02d, Sent: %d (%d), Rcvd: %d (%d)", now / 3600, now / 60, now % 60, dat->stats.iSent, dat->stats.iSentBytes, dat->stats.iReceived, dat->stats.iReceivedBytes); + dbei.cbSize = sizeof(dbei); + dbei.pBlob = (PBYTE) buffer; + dbei.cbBlob = (int)(strlen(buffer)) + 1; + dbei.eventType = EVENTTYPE_STATUSCHANGE; + dbei.flags = DBEF_READ; + dbei.timestamp = time(NULL); + dbei.szModule = dat->szProto; + hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM) dat->hContact, (LPARAM) & dbei); + if (dat->hDbEventFirst == NULL) { + dat->hDbEventFirst = hNewEvent; + SendMessage(dat->hwnd, DM_REMAKELOG, 0, 0); + } + } + */ +} + +int TSAPI MsgWindowUpdateMenu(TWindowData *dat, HMENU submenu, int menuID) +{ + HWND hwndDlg = dat->hwnd; + bool fInfoPanel = dat->Panel->isActive(); + + if (menuID == MENU_TABCONTEXT) { + SESSION_INFO *si = (SESSION_INFO *)dat->si; + int iTabs = TabCtrl_GetItemCount(GetParent(hwndDlg)); + + EnableMenuItem(submenu, ID_TABMENU_ATTACHTOCONTAINER, M->GetByte("useclistgroups", 0) || M->GetByte("singlewinmode", 0) ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(submenu, ID_TABMENU_CLEARSAVEDTABPOSITION, (M->GetDword(dat->hContact, "tabindex", -1) != -1) ? MF_ENABLED : MF_GRAYED); + } else if (menuID == MENU_PICMENU) { + MENUITEMINFO mii = {0}; + TCHAR *szText = NULL; + char avOverride = (char)M->GetByte(dat->hContact, "hideavatar", -1); + HMENU visMenu = GetSubMenu(submenu, 0); + BOOL picValid = fInfoPanel ? (dat->hOwnPic != 0) : (dat->ace && dat->ace->hbmPic && dat->ace->hbmPic != PluginConfig.g_hbmUnknown); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STRING; + + EnableMenuItem(submenu, ID_PICMENU_SAVETHISPICTUREAS, MF_BYCOMMAND | (picValid ? MF_ENABLED : MF_GRAYED)); + + CheckMenuItem(visMenu, ID_VISIBILITY_DEFAULT, MF_BYCOMMAND | (avOverride == -1 ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(visMenu, ID_VISIBILITY_HIDDENFORTHISCONTACT, MF_BYCOMMAND | (avOverride == 0 ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(visMenu, ID_VISIBILITY_VISIBLEFORTHISCONTACT, MF_BYCOMMAND | (avOverride == 1 ? MF_CHECKED : MF_UNCHECKED)); + + CheckMenuItem(submenu, ID_PICMENU_ALWAYSKEEPTHEBUTTONBARATFULLWIDTH, MF_BYCOMMAND | (PluginConfig.m_AlwaysFullToolbarWidth ? MF_CHECKED : MF_UNCHECKED)); + if (!fInfoPanel) { + EnableMenuItem(submenu, ID_PICMENU_SETTINGS, MF_BYCOMMAND | (ServiceExists(MS_AV_GETAVATARBITMAP) ? MF_ENABLED : MF_GRAYED)); + szText = const_cast(CTranslator::get(CTranslator::GEN_AVATAR_SETTINGS)); + EnableMenuItem(submenu, 0, MF_BYPOSITION | MF_ENABLED); + } else { + EnableMenuItem(submenu, 0, MF_BYPOSITION | MF_GRAYED); + EnableMenuItem(submenu, ID_PICMENU_SETTINGS, MF_BYCOMMAND | ((ServiceExists(MS_AV_SETMYAVATAR) && CallService(MS_AV_CANSETMYAVATAR, (WPARAM)(dat->cache->getActiveProto()), 0)) ? MF_ENABLED : MF_GRAYED)); + szText = const_cast(CTranslator::get(CTranslator::GEN_AVATAR_SETOWN)); + } + mii.dwTypeData = szText; + mii.cch = lstrlen(szText) + 1; + SetMenuItemInfo(submenu, ID_PICMENU_SETTINGS, FALSE, &mii); + } else if (menuID == MENU_PANELPICMENU) { + HMENU visMenu = GetSubMenu(submenu, 0); + char avOverride = (char)M->GetByte(dat->hContact, "hideavatar", -1); + + CheckMenuItem(visMenu, ID_VISIBILITY_DEFAULT, MF_BYCOMMAND | (avOverride == -1 ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(visMenu, ID_VISIBILITY_HIDDENFORTHISCONTACT, MF_BYCOMMAND | (avOverride == 0 ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuItem(visMenu, ID_VISIBILITY_VISIBLEFORTHISCONTACT, MF_BYCOMMAND | (avOverride == 1 ? MF_CHECKED : MF_UNCHECKED)); + + EnableMenuItem(submenu, ID_PICMENU_SETTINGS, MF_BYCOMMAND | (ServiceExists(MS_AV_GETAVATARBITMAP) ? MF_ENABLED : MF_GRAYED)); + EnableMenuItem(submenu, ID_PANELPICMENU_SAVETHISPICTUREAS, MF_BYCOMMAND | ((ServiceExists(MS_AV_SAVEBITMAP) && dat->ace && dat->ace->hbmPic && dat->ace->hbmPic != PluginConfig.g_hbmUnknown) ? MF_ENABLED : MF_GRAYED)); + } + return 0; +} + +int TSAPI MsgWindowMenuHandler(TWindowData *dat, int selection, int menuId) +{ + if(dat == 0) + return(0); + + HWND hwndDlg = dat->hwnd; + + if (menuId == MENU_PICMENU || menuId == MENU_PANELPICMENU || menuId == MENU_TABCONTEXT) { + switch (selection) { + case ID_TABMENU_ATTACHTOCONTAINER: + CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_SELECTCONTAINER), hwndDlg, SelectContainerDlgProc, (LPARAM) hwndDlg); + return 1; + case ID_TABMENU_CONTAINEROPTIONS: + if (dat->pContainer->hWndOptions == 0) + CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CONTAINEROPTIONS), hwndDlg, DlgProcContainerOptions, (LPARAM) dat->pContainer); + return 1; + case ID_TABMENU_CLOSECONTAINER: + SendMessage(dat->pContainer->hwnd, WM_CLOSE, 0, 0); + return 1; + case ID_TABMENU_CLOSETAB: + SendMessage(hwndDlg, WM_CLOSE, 1, 0); + return 1; + case ID_TABMENU_SAVETABPOSITION: + M->WriteDword(dat->hContact, SRMSGMOD_T, "tabindex", dat->iTabID * 100); + break; + case ID_TABMENU_CLEARSAVEDTABPOSITION: + DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "tabindex"); + break; + case ID_TABMENU_LEAVECHATROOM: { + if (dat && dat->bType == SESSIONTYPE_CHAT) { + SESSION_INFO *si = (SESSION_INFO *)dat->si; + if ( (si != NULL) && (dat->hContact != NULL) ) { + char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) dat->hContact, 0); + if ( szProto ) + CallProtoService( szProto, PS_LEAVECHAT, (WPARAM)dat->hContact, 0 ); + } + } + return 1; + } + case ID_VISIBILITY_DEFAULT: + case ID_VISIBILITY_HIDDENFORTHISCONTACT: + case ID_VISIBILITY_VISIBLEFORTHISCONTACT: { + BYTE avOverrideMode; + + if (selection == ID_VISIBILITY_DEFAULT) + avOverrideMode = -1; + else if (selection == ID_VISIBILITY_HIDDENFORTHISCONTACT) + avOverrideMode = 0; + else if (selection == ID_VISIBILITY_VISIBLEFORTHISCONTACT) + avOverrideMode = 1; + M->WriteByte(dat->hContact, SRMSGMOD_T, "hideavatar", avOverrideMode); + dat->panelWidth = -1; + ShowPicture(dat, FALSE); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + DM_ScrollToBottom(dat, 0, 1); + return 1; + } + case ID_PICMENU_ALWAYSKEEPTHEBUTTONBARATFULLWIDTH: + PluginConfig.m_AlwaysFullToolbarWidth = !PluginConfig.m_AlwaysFullToolbarWidth; + M->WriteByte(SRMSGMOD_T, "alwaysfulltoolbar", (BYTE)PluginConfig.m_AlwaysFullToolbarWidth); + M->BroadcastMessage(DM_CONFIGURETOOLBAR, 0, 1); + break; + case ID_PICMENU_SAVETHISPICTUREAS: + if (dat->Panel->isActive()) { + if (dat) + SaveAvatarToFile(dat, dat->hOwnPic, 1); + } else { + if (dat && dat->ace) + SaveAvatarToFile(dat, dat->ace->hbmPic, 0); + } + break; + case ID_PANELPICMENU_SAVETHISPICTUREAS: + if (dat && dat->ace) + SaveAvatarToFile(dat, dat->ace->hbmPic, 0); + break; + case ID_PICMENU_SETTINGS: { + if (menuId == MENU_PANELPICMENU) + CallService(MS_AV_CONTACTOPTIONS, (WPARAM)dat->hContact, 0); + else if (menuId == MENU_PICMENU) { + if (dat->Panel->isActive()) { + if (ServiceExists(MS_AV_SETMYAVATAR) && CallService(MS_AV_CANSETMYAVATAR, (WPARAM)(dat->cache->getActiveProto()), 0)) + CallService(MS_AV_SETMYAVATAR, (WPARAM)(dat->cache->getActiveProto()), 0); + } else + CallService(MS_AV_CONTACTOPTIONS, (WPARAM)dat->hContact, 0); + } + } + return 1; + } + } else if (menuId == MENU_LOGMENU) { + int iLocalTime = 0; + int iRtl = (PluginConfig.m_RTLDefault == 0 ? M->GetByte(dat->hContact, "RTL", 0) : M->GetByte(dat->hContact, "RTL", 1)); + int iLogStatus = (PluginConfig.m_LogStatusChanges != 0) && dat->dwFlags & MWF_LOG_STATUSCHANGES; + + DWORD dwOldFlags = dat->dwFlags; + + switch (selection) { + case ID_MESSAGELOGSETTINGS_GLOBAL: { + OPENOPTIONSDIALOG ood = {0}; + + ood.cbSize = sizeof(OPENOPTIONSDIALOG); + ood.pszGroup = NULL; + ood.pszPage = "Message Sessions"; + ood.pszTab = NULL; + M->WriteByte(SRMSGMOD_T, "opage", 3); // force 3th tab to appear + CallService (MS_OPT_OPENOPTIONS, 0, (LPARAM)&ood); + return 1; + } + + case ID_MESSAGELOGSETTINGS_FORTHISCONTACT: + CallService(MS_TABMSG_SETUSERPREFS, (WPARAM)dat->hContact, (LPARAM)0); + return 1; + + default: + break; + } + } + return 0; +} + +/* + * update the status bar field which displays the number of characters in the input area + * and various indicators (caps lock, num lock, insert mode). + */ + +void TSAPI UpdateReadChars(const TWindowData *dat) +{ + + if(dat && (dat->pContainer->hwndStatus && dat->pContainer->hwndActive == dat->hwnd)) { + TCHAR buf[128]; + int len; + TCHAR szIndicators[20]; + BOOL fCaps, fNum; + + szIndicators[0] = 0; + if (dat->bType == SESSIONTYPE_CHAT) + len = GetWindowTextLength(GetDlgItem(dat->hwnd, IDC_CHAT_MESSAGE)); + else { + /* + * retrieve text length in UTF8 bytes, because this is the relevant length for most protocols + */ + GETTEXTLENGTHEX gtxl = {0}; + gtxl.codepage = CP_UTF8; + gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMBYTES; + + len = SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_GETTEXTLENGTHEX, (WPARAM) & gtxl, 0); + } + + fCaps = (GetKeyState(VK_CAPITAL) & 1); + fNum = (GetKeyState(VK_NUMLOCK) & 1); + + if (dat->fInsertMode) + lstrcat(szIndicators, _T("O")); + if (fCaps) + lstrcat(szIndicators, _T("C")); + if (fNum) + lstrcat(szIndicators, _T("N")); + if (dat->fInsertMode || fCaps || fNum) + lstrcat(szIndicators, _T(" | ")); + + mir_sntprintf(buf, safe_sizeof(buf), _T("%s%s %d/%d"), szIndicators, dat->lcID, dat->iOpenJobs, len); + SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 1, (LPARAM) buf); + if(PluginConfig.m_visualMessageSizeIndicator) + InvalidateRect(dat->pContainer->hwndStatus, NULL, FALSE); + } +} + +/* + * update all status bar fields and force a redraw of the status bar. + */ + +void TSAPI UpdateStatusBar(const TWindowData *dat) +{ + if (dat && dat->pContainer->hwndStatus && dat->pContainer->hwndActive == dat->hwnd) { + if (dat->bType == SESSIONTYPE_IM) { + if(dat->szStatusBar[0]) { + SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, (LPARAM)PluginConfig.g_buttonBarIcons[ICON_DEFAULT_TYPING]); + SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)dat->szStatusBar); + } + else { + SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, 0); + DM_UpdateLastMessage(dat); + } + } + else + SendMessage(dat->pContainer->hwndStatus, SB_SETICON, 0, 0); + UpdateReadChars(dat); + InvalidateRect(dat->pContainer->hwndStatus, NULL, TRUE); + SendMessage(dat->pContainer->hwndStatus, WM_USER + 101, 0, (LPARAM)dat); + } +} + +/* + * provide user feedback via icons on tabs. Used to indicate "send in progress" or + * any error state. + * + * NOT used for typing notification feedback as this is handled directly from the + * MTN handler. + */ + +void TSAPI HandleIconFeedback(TWindowData *dat, HICON iIcon) +{ + TCITEM item = {0}; + HICON iOldIcon = dat->hTabIcon; + + if (iIcon == (HICON) - 1) { // restore status image + if (dat->dwFlags & MWF_ERRORSTATE) { + dat->hTabIcon = PluginConfig.g_iconErr; + } else { + dat->hTabIcon = dat->hTabStatusIcon; + } + } else + dat->hTabIcon = iIcon; + item.iImage = 0; + item.mask = TCIF_IMAGE; + if(dat->pContainer->dwFlags & CNT_SIDEBAR) + dat->pContainer->SideBar->updateSession(dat); + else + TabCtrl_SetItem(GetDlgItem(dat->pContainer->hwnd, IDC_MSGTABS), dat->iTabID, &item); +} + +/* + * retrieve the visiblity of the avatar window, depending on the global setting + * and local mode + */ + +int TSAPI GetAvatarVisibility(HWND hwndDlg, struct TWindowData *dat) +{ + BYTE bAvatarMode = dat->pContainer->avatarMode; + BYTE bOwnAvatarMode = dat->pContainer->ownAvatarMode; + char hideOverride = (char)M->GetByte(dat->hContact, "hideavatar", -1); + // infopanel visible, consider own avatar display + + dat->showPic = 0; + + if (dat->Panel->isActive() && bAvatarMode != 3) { + if (bOwnAvatarMode) + dat->showPic = FALSE; + else { + FLASHAVATAR fa = {0}; + if (PluginConfig.g_FlashAvatarAvail) { + fa.cProto = dat->szProto; + fa.id = 25367; + fa.hParentWindow = GetDlgItem(hwndDlg, IDC_CONTACTPIC); + + CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0); + if (fa.hWindow != NULL&&dat->hwndContactPic) { + DestroyWindow(dat->hwndContactPic); + dat->hwndContactPic = NULL; + } + dat->showPic = ((dat->hOwnPic && dat->hOwnPic != PluginConfig.g_hbmUnknown) || (fa.hWindow != NULL)) ? 1 : 0; + } else + dat->showPic = (dat->hOwnPic && dat->hOwnPic != PluginConfig.g_hbmUnknown) ? 1 : 0; + + if (!PluginConfig.g_bDisableAniAvatars && fa.hWindow == NULL && !dat->hwndContactPic) + dat->hwndContactPic =CreateWindowEx(WS_EX_TOPMOST, AVATAR_CONTROL_CLASS, _T(""), WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, GetDlgItem(hwndDlg, IDC_CONTACTPIC), (HMENU)0, NULL, NULL); + + } + switch (bAvatarMode) { + case 2: + dat->showInfoPic = 0; + break; + case 0: + dat->showInfoPic = 1; + case 1: { + FLASHAVATAR fa = {0}; + HBITMAP hbm = ((dat->ace && !(dat->ace->dwFlags & AVS_HIDEONCLIST)) ? dat->ace->hbmPic : 0); + + if(0 == hbm && 0 == bAvatarMode && !PluginConfig.g_bDisableAniAvatars) { + dat->showInfoPic = 0; + break; + } + + if (PluginConfig.g_FlashAvatarAvail) { + fa.cProto = dat->szProto; + fa.id = 25367; + fa.hContact = dat->hContact; + fa.hParentWindow = dat->hwndPanelPicParent; + + CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0); + if (fa.hWindow != NULL && dat->hwndPanelPic) { + DestroyWindow(dat->hwndPanelPic); + dat->hwndPanelPic = NULL; + ShowWindow(dat->hwndPanelPicParent, SW_SHOW); + EnableWindow(dat->hwndPanelPicParent, TRUE); + } + } + if (!PluginConfig.g_bDisableAniAvatars && fa.hWindow == NULL && !dat->hwndPanelPic) { + dat->hwndPanelPic = CreateWindowEx(WS_EX_TOPMOST, AVATAR_CONTROL_CLASS, _T(""), WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, dat->hwndPanelPicParent, (HMENU)7000, NULL, NULL); + if(dat->hwndPanelPic) + SendMessage(dat->hwndPanelPic, AVATAR_SETAEROCOMPATDRAWING, 0, TRUE); + } + if(bAvatarMode != 0) { + if ((hbm && hbm != PluginConfig.g_hbmUnknown) || (fa.hWindow != NULL)) + dat->showInfoPic = 1; + else + dat->showInfoPic = 0; + } + break; + } + } + if (dat->showInfoPic) + dat->showInfoPic = hideOverride == 0 ? 0 : dat->showInfoPic; + else + dat->showInfoPic = hideOverride == 1 ? 1 : dat->showInfoPic; + //Bolshevik: reloads avatars + if (dat->showInfoPic) { + /** panel and contact is shown, reloads contact's avatar -> panel + * user avatar -> bottom picture + */ + SendMessage(dat->hwndPanelPic, AVATAR_SETCONTACT, (WPARAM)0, (LPARAM)dat->hContact); + if (dat->hwndContactPic) + SendMessage(dat->hwndContactPic, AVATAR_SETPROTOCOL, (WPARAM)0, (LPARAM)dat->szProto); + } + else { + //show only user picture(contact is unaccessible) + if (dat->hwndContactPic) + SendMessage(dat->hwndContactPic, AVATAR_SETPROTOCOL, (WPARAM)0, (LPARAM)dat->szProto); + } +//Bolshevik_ + } else { + dat->showInfoPic = 0; + + switch (bAvatarMode) { + case 0: // globally on + dat->showPic = 1; + break; + case 2: // globally OFF + dat->showPic = 0; + break; + case 3: // on, if present + case 1: { + FLASHAVATAR fa = {0}; + HBITMAP hbm = (dat->ace && !(dat->ace->dwFlags & AVS_HIDEONCLIST)) ? dat->ace->hbmPic : 0; + + if (PluginConfig.g_FlashAvatarAvail) { + fa.cProto = dat->szProto; + fa.id = 25367; + fa.hContact = dat->hContact; + fa.hParentWindow = GetDlgItem(hwndDlg, IDC_CONTACTPIC); + + CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0); + + if (fa.hWindow != NULL&&dat->hwndContactPic) { + DestroyWindow(dat->hwndContactPic); + dat->hwndContactPic = NULL; + } + } + if (!PluginConfig.g_bDisableAniAvatars&&fa.hWindow == NULL&&!dat->hwndContactPic) + dat->hwndContactPic =CreateWindowEx(WS_EX_TOPMOST, AVATAR_CONTROL_CLASS, _T(""), WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, GetDlgItem(hwndDlg, IDC_CONTACTPIC), (HMENU)0, NULL, NULL); + + if ((hbm && hbm != PluginConfig.g_hbmUnknown) || (fa.hWindow != NULL)) + dat->showPic = 1; + else + dat->showPic = 0; + break; + } + } + if (dat->showPic) + dat->showPic = hideOverride == 0 ? 0 : dat->showPic; + else + dat->showPic = hideOverride == 1 ? 1 : dat->showPic; + //Bolshevik: reloads avatars + if (dat->showPic) + //shows contact or user picture, depending on panel visibility + if (dat->hwndPanelPic) + SendMessage(dat->hwndContactPic, AVATAR_SETPROTOCOL, (WPARAM)0, (LPARAM)dat->szProto); + if (dat->hwndContactPic) + SendMessage(dat->hwndContactPic, AVATAR_SETCONTACT, (WPARAM)0, (LPARAM)dat->hContact); + + } + return dat->showPic; +} + +/* + * checks, if there is a valid smileypack installed for the given protocol + */ + +int TSAPI CheckValidSmileyPack(const char *szProto, HANDLE hContact) +{ + SMADD_INFO2 smainfo = {0}; + + if (PluginConfig.g_SmileyAddAvail) { + smainfo.cbSize = sizeof(smainfo); + smainfo.Protocolname = const_cast(szProto); + smainfo.hContact = hContact; + CallService(MS_SMILEYADD_GETINFO2, 0, (LPARAM)&smainfo); + if(smainfo.ButtonIcon) + DestroyIcon(smainfo.ButtonIcon); + return smainfo.NumberOfVisibleSmileys; + } else + return 0; +} + +/* + * return value MUST be free()'d by caller. + */ + +TCHAR* TSAPI QuoteText(const TCHAR *text, int charsPerLine, int removeExistingQuotes) +{ + int inChar, outChar, lineChar; + int justDoneLineBreak, bufSize; + TCHAR *strout; + + bufSize = lstrlenW(text) + 23; + strout = (TCHAR*)malloc(bufSize * sizeof(TCHAR)); + inChar = 0; + justDoneLineBreak = 1; + for (outChar = 0, lineChar = 0;text[inChar];) { + if (outChar >= bufSize - 8) { + bufSize += 20; + strout = (TCHAR *)realloc(strout, bufSize * sizeof(TCHAR)); + } + if (justDoneLineBreak && text[inChar] != '\r' && text[inChar] != '\n') { + if (removeExistingQuotes) + if (text[inChar] == '>') { + while (text[++inChar] != '\n'); + inChar++; + continue; + } + strout[outChar++] = '>'; + strout[outChar++] = ' '; + lineChar = 2; + } + if (lineChar == charsPerLine && text[inChar] != '\r' && text[inChar] != '\n') { + int decreasedBy; + for (decreasedBy = 0;lineChar > 10;lineChar--, inChar--, outChar--, decreasedBy++) + if (strout[outChar] == ' ' || strout[outChar] == '\t' || strout[outChar] == '-') break; + if (lineChar <= 10) { + lineChar += decreasedBy; + inChar += decreasedBy; + outChar += decreasedBy; + } else inChar++; + strout[outChar++] = '\r'; + strout[outChar++] = '\n'; + justDoneLineBreak = 1; + continue; + } + strout[outChar++] = text[inChar]; + lineChar++; + if (text[inChar] == '\n' || text[inChar] == '\r') { + if (text[inChar] == '\r' && text[inChar+1] != '\n') + strout[outChar++] = '\n'; + justDoneLineBreak = 1; + lineChar = 0; + } else justDoneLineBreak = 0; + inChar++; + } + strout[outChar++] = '\r'; + strout[outChar++] = '\n'; + strout[outChar] = 0; + return strout; +} + + +void TSAPI AdjustBottomAvatarDisplay(TWindowData *dat) +{ + if(dat) { + bool fInfoPanel = dat->Panel->isActive(); + HBITMAP hbm = (fInfoPanel && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown); + HWND hwndDlg = dat->hwnd; + + 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); + if (fa.hWindow) { + dat->hwndFlash = fa.hWindow; + SetParent(dat->hwndFlash, fInfoPanel ? dat->hwndPanelPicParent : GetDlgItem(dat->hwnd, IDC_CONTACTPIC)); + } + fa.hContact = 0; + fa.hWindow = 0; + if (fInfoPanel) { + fa.hParentWindow = GetDlgItem(hwndDlg, IDC_CONTACTPIC); + CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0); + if (fa.hWindow) { + SetParent(fa.hWindow, GetDlgItem(hwndDlg, IDC_CONTACTPIC)); + ShowWindow(fa.hWindow, SW_SHOW); + } + } else { + CallService(MS_FAVATAR_GETINFO, (WPARAM)&fa, 0); + if (fa.hWindow) + ShowWindow(fa.hWindow, SW_HIDE); + } + } + + if (hbm) { + dat->showPic = GetAvatarVisibility(hwndDlg, dat); + if (dat->dynaSplitter == 0 || dat->splitterY == 0) + LoadSplitter(dat); + dat->dynaSplitter = dat->splitterY - DPISCALEY_S(34); + DM_RecalcPictureSize(dat); + Utils::showDlgControl(hwndDlg, IDC_CONTACTPIC, dat->showPic ? SW_SHOW : SW_HIDE); + InvalidateRect(GetDlgItem(hwndDlg, IDC_CONTACTPIC), NULL, TRUE); + } else { + dat->showPic = GetAvatarVisibility(hwndDlg, dat); + Utils::showDlgControl(hwndDlg, IDC_CONTACTPIC, dat->showPic ? SW_SHOW : SW_HIDE); + dat->pic.cy = dat->pic.cx = DPISCALEY_S(60); + InvalidateRect(GetDlgItem(hwndDlg, IDC_CONTACTPIC), NULL, TRUE); + } + } +} + +void TSAPI ShowPicture(TWindowData *dat, BOOL showNewPic) +{ + DBVARIANT dbv = {0}; + RECT rc; + HWND hwndDlg = dat->hwnd; + + if (!dat->Panel->isActive()) + dat->pic.cy = dat->pic.cx = DPISCALEY_S(60); + + if (showNewPic) { + if (dat->Panel->isActive() && dat->pContainer->avatarMode != 3) { + if (!dat->hwndPanelPic) { + dat->panelWidth = -1; + InvalidateRect(dat->hwnd, NULL, TRUE); + UpdateWindow(dat->hwnd); + SendMessage(dat->hwnd, WM_SIZE, 0, 0); + } + return; + } + AdjustBottomAvatarDisplay(dat); + } else { + dat->showPic = dat->showPic ? 0 : 1; + DBWriteContactSettingByte(dat->hContact, SRMSGMOD_T, "MOD_ShowPic", (BYTE)dat->showPic); + } + GetWindowRect(GetDlgItem(hwndDlg, IDC_CONTACTPIC), &rc); + if (dat->minEditBoxSize.cy + DPISCALEY_S(3)> dat->splitterY) + SendMessage(hwndDlg, DM_SPLITTERMOVED, (WPARAM)rc.bottom - dat->minEditBoxSize.cy, (LPARAM)GetDlgItem(hwndDlg, IDC_SPLITTER)); + if (!showNewPic) + SetDialogToType(hwndDlg); + else + SendMessage(hwndDlg, WM_SIZE, 0, 0); + +} + +void TSAPI FlashOnClist(HWND hwndDlg, struct TWindowData *dat, HANDLE hEvent, DBEVENTINFO *dbei) +{ + CLISTEVENT cle; + + dat->dwTickLastEvent = GetTickCount(); + + if ((GetForegroundWindow() != dat->pContainer->hwnd || dat->pContainer->hwndActive != hwndDlg) && !(dbei->flags & DBEF_SENT) && dbei->eventType == EVENTTYPE_MESSAGE) { + dat->dwUnread++; + UpdateTrayMenu(dat, (WORD)(dat->cache->getActiveStatus()), dat->cache->getActiveProto(), dat->szStatus, dat->hContact, 0L); + if (nen_options.bTraySupport) + return; + } + if (hEvent == 0) + return; + + if (!PluginConfig.m_FlashOnClist) + return; + if ((GetForegroundWindow() != dat->pContainer->hwnd || dat->pContainer->hwndActive != hwndDlg) && !(dbei->flags & DBEF_SENT) && dbei->eventType == EVENTTYPE_MESSAGE && !(dat->dwFlagsEx & MWF_SHOW_FLASHCLIST)) { + ZeroMemory(&cle, sizeof(cle)); + cle.cbSize = sizeof(cle); + cle.hContact = (HANDLE) dat->hContact; + cle.hDbEvent = hEvent; + cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE); + cle.pszService = "SRMsg/ReadMessage"; + CallService(MS_CLIST_ADDEVENT, 0, (LPARAM) & cle); + dat->dwFlagsEx |= MWF_SHOW_FLASHCLIST; + dat->hFlashingEvent = hEvent; + } +} + +/* + * callback function for text streaming + */ + +static DWORD CALLBACK Message_StreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb) +{ + static DWORD dwRead; + char ** ppText = (char **) dwCookie; + + if (*ppText == NULL) { + *ppText = (char *)malloc(cb + 2); + CopyMemory(*ppText, pbBuff, cb); + *pcb = cb; + dwRead = cb; + *(*ppText + cb) = '\0'; + } else { + char *p = (char *)realloc(*ppText, dwRead + cb + 2); + CopyMemory(p + dwRead, pbBuff, cb); + *ppText = p; + *pcb = cb; + dwRead += cb; + *(*ppText + dwRead) = '\0'; + } + return 0; +} + +/* + * retrieve contents of the richedit control by streaming. Used to get the + * typed message before sending it. + * caller must free the returned pointer. + * UNICODE version returns UTF-8 encoded string. + */ + +char* TSAPI Message_GetFromStream(HWND hwndRtf, const TWindowData* dat, DWORD dwPassedFlags) +{ + EDITSTREAM stream; + char *pszText = NULL; + DWORD dwFlags = 0; + + if (hwndRtf == 0 || dat == 0) + return NULL; + + ZeroMemory(&stream, sizeof(stream)); + stream.pfnCallback = Message_StreamCallback; + stream.dwCookie = (DWORD_PTR) & pszText; // pass pointer to pointer + if (dwPassedFlags == 0) + dwFlags = (CP_UTF8 << 16) | (SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE); + else + dwFlags = (CP_UTF8 << 16) | dwPassedFlags; + SendMessage(hwndRtf, EM_STREAMOUT, (WPARAM)dwFlags, (LPARAM) & stream); + + return pszText; // pszText contains the text +} + +/* + * convert rich edit code to bbcode (if wanted). Otherwise, strip all RTF formatting + * tags and return plain text + */ + +BOOL TSAPI DoRtfToTags(TCHAR * pszText, const TWindowData *dat) +{ + TCHAR * p1; + BOOL bJustRemovedRTF = TRUE; + BOOL bTextHasStarted = FALSE; + LOGFONTA lf; + COLORREF color; + static int inColor = 0; + + if (!pszText) + return FALSE; + + /* + * used to filter out attributes which are already set for the default message input area + * font + */ + + lf = dat->pContainer->theme.logFonts[MSGFONTID_MESSAGEAREA]; + color = dat->pContainer->theme.fontColors[MSGFONTID_MESSAGEAREA]; + + // create an index of colors in the module and map them to + // corresponding colors in the RTF color table + + Utils::CreateColorMap(pszText); + // scan the file for rtf commands and remove or parse them + inColor = 0; + p1 = _tcsstr(pszText, _T("\\pard")); + if (p1) { + size_t iRemoveChars; + TCHAR InsertThis[50]; + p1 += 5; + + MoveMemory(pszText, p1, (lstrlen(p1) + 1) * sizeof(TCHAR)); + p1 = pszText; + // iterate through all characters, if rtf control character found then take action + while (*p1 != (TCHAR) '\0') { + _sntprintf(InsertThis, 50, _T("")); + iRemoveChars = 0; + + switch (*p1) { + case (TCHAR) '\\': + if (p1 == _tcsstr(p1, _T("\\cf"))) { // foreground color + TCHAR szTemp[20]; + int iCol = _ttoi(p1 + 3); + int iInd = Utils::RTFColorToIndex(iCol); + bJustRemovedRTF = TRUE; + + _sntprintf(szTemp, 20, _T("%d"), iCol); + iRemoveChars = 3 + lstrlen(szTemp); + if (bTextHasStarted || iCol) + _sntprintf(InsertThis, sizeof(InsertThis) / sizeof(TCHAR), (iInd > 0) ? (inColor ? _T("[/color][color=%s]") : _T("[color=%s]")) : (inColor ? _T("[/color]") : _T("")), Utils::rtf_ctable[iInd - 1].szName); + inColor = iInd > 0 ? 1 : 0; + } else if (p1 == _tcsstr(p1, _T("\\highlight"))) { //background color + TCHAR szTemp[20]; + int iCol = _ttoi(p1 + 10); + bJustRemovedRTF = TRUE; + + _sntprintf(szTemp, 20, _T("%d"), iCol); + iRemoveChars = 10 + lstrlen(szTemp); + } else if (p1 == _tcsstr(p1, _T("\\par"))) { // newline + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 4; + } else if (p1 == _tcsstr(p1, _T("\\line"))) { // soft line break; + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 5; + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("\n")); + } else if (p1 == _tcsstr(p1, _T("\\endash"))) { + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = 7; + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x2013); + } else if (p1 == _tcsstr(p1, _T("\\emdash"))) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x2014); + } else if (p1 == _tcsstr(p1, _T("\\bullet"))) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x2022); + } else if (p1 == _tcsstr(p1, _T("\\ldblquote"))) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 10; + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x201C); + } else if (p1 == _tcsstr(p1, _T("\\rdblquote"))) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 10; + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x201D); + } else if (p1 == _tcsstr(p1, _T("\\lquote"))) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x2018); + } else if (p1 == _tcsstr(p1, _T("\\rquote"))) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x2019); + } else if (p1 == _tcsstr(p1, _T("\\b"))) { //bold + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = (p1[2] != (TCHAR) '0') ? 2 : 3; + if (!(lf.lfWeight == FW_BOLD)) { // only allow bold if the font itself isn't a bold one, otherwise just strip it.. + if (dat->SendFormat) + _sntprintf(InsertThis, safe_sizeof(InsertThis), (p1[2] != (TCHAR) '0') ? _T("[b]") : _T("[/b]")); + } + + } else if (p1 == _tcsstr(p1, _T("\\i"))) { // italics + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = (p1[2] != (TCHAR) '0') ? 2 : 3; + if (!lf.lfItalic) { // same as for bold + if (dat->SendFormat) + _sntprintf(InsertThis, safe_sizeof(InsertThis), (p1[2] != (TCHAR) '0') ? _T("[i]") : _T("[/i]")); + } + + } else if (p1 == _tcsstr(p1, _T("\\strike"))) { // strike-out + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = (p1[7] != (TCHAR) '0') ? 7 : 8; + if (!lf.lfStrikeOut) { // same as for bold + if (dat->SendFormat) + _sntprintf(InsertThis, safe_sizeof(InsertThis), (p1[7] != (TCHAR) '0') ? _T("[s]") : _T("[/s]")); + } + + } else if (p1 == _tcsstr(p1, _T("\\ul"))) { // underlined + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + if (p1[3] == (TCHAR) 'n') + iRemoveChars = 7; + else if (p1[3] == (TCHAR) '0') + iRemoveChars = 4; + else + iRemoveChars = 3; + if (!lf.lfUnderline) { // same as for bold + if (dat->SendFormat) + _sntprintf(InsertThis, safe_sizeof(InsertThis), (p1[3] != (TCHAR) '0' && p1[3] != (TCHAR) 'n') ? _T("[u]") : _T("[/u]")); + } + + } else if (p1 == _tcsstr(p1, _T("\\tab"))) { // tab + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 4; + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), 0x09); + } else if (p1[1] == (TCHAR) '\\' || p1[1] == (TCHAR) '{' || p1[1] == (TCHAR) '}') { // escaped characters + bTextHasStarted = TRUE; + //bJustRemovedRTF = TRUE; + iRemoveChars = 2; + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), p1[1]); + } else if (p1[1] == (TCHAR) '\'') { // special character + bTextHasStarted = TRUE; + bJustRemovedRTF = FALSE; + if (p1[2] != (TCHAR) ' ' && p1[2] != (TCHAR) '\\') { + int iLame = 0; + TCHAR * p3; + TCHAR *stoppedHere; + + if (p1[3] != (TCHAR) ' ' && p1[3] != (TCHAR) '\\') { + _tcsncpy(InsertThis, p1 + 2, 3); + iRemoveChars = 4; + InsertThis[2] = 0; + } else { + _tcsncpy(InsertThis, p1 + 2, 2); + iRemoveChars = 3; + InsertThis[2] = 0; + } + // convert string containing char in hex format to int. + p3 = InsertThis; + iLame = _tcstol(p3, &stoppedHere, 16); + _sntprintf(InsertThis, safe_sizeof(InsertThis), _T("%c"), (TCHAR) iLame); + + } else + iRemoveChars = 2; + } else { // remove unknown RTF command + int j = 1; + bJustRemovedRTF = TRUE; + while (!_tcschr(_T(" !$%()#*\"'"), p1[j]) && p1[j] != (TCHAR) '§' && p1[j] != (TCHAR) '\\' && p1[j] != (TCHAR) '\0') + // while(!_tcschr(_T(" !§$%&()#*"), p1[j]) && p1[j] != (TCHAR)'\\' && p1[j] != (TCHAR)'\0') + j++; + // while(p1[j] != (TCHAR)' ' && p1[j] != (TCHAR)'\\' && p1[j] != (TCHAR)'\0') + // j++; + iRemoveChars = j; + } + break; + + case (TCHAR) '{': // other RTF control characters + case (TCHAR) '}': + iRemoveChars = 1; + break; + + case (TCHAR) ' ': // remove spaces following a RTF command + if (bJustRemovedRTF) + iRemoveChars = 1; + bJustRemovedRTF = FALSE; + bTextHasStarted = TRUE; + break; + + default: // other text that should not be touched + bTextHasStarted = TRUE; + bJustRemovedRTF = FALSE; + + break; + } + + // move the memory and paste in new commands instead of the old RTF + if (lstrlen(InsertThis) || iRemoveChars) { + MoveMemory(p1 + lstrlen(InsertThis), p1 + iRemoveChars, (lstrlen(p1) - iRemoveChars + 1) * sizeof(TCHAR)); + CopyMemory(p1, InsertThis, lstrlen(InsertThis) * sizeof(TCHAR)); + p1 += lstrlen(InsertThis); + } else + p1++; + } + + } else { + return FALSE; + } + return TRUE; +} + +/* + * trims the output from DoRtfToTags(), removes trailing newlines and whitespaces... + */ + +void TSAPI DoTrimMessage(TCHAR *msg) +{ + size_t iLen = lstrlen(msg); + size_t i = iLen; + + while (i && (msg[i-1] == '\r' || msg[i-1] == '\n') || msg[i-1] == ' ') { + i--; + } + if (i < iLen) + msg[i] = '\0'; +} + +/* + * retrieve both buddys and my own UIN for a message session and store them in the message window *dat + * respects metacontacts and uses the current protocol if the contact is a MC + */ + +void TSAPI GetMYUIN(TWindowData *dat) +{ + CONTACTINFO ci; + ZeroMemory((void *)&ci, sizeof(ci)); + + /* + * get my uin + */ + + ci.cbSize = sizeof(ci); + ci.hContact = 0; + ci.szProto = const_cast(dat->cache->getActiveProto()); + ci.dwFlag = CNF_TCHAR | CNF_DISPLAYUID; + + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) { + switch (ci.type) { + case CNFT_ASCIIZ: + mir_sntprintf(dat->myUin, safe_sizeof(dat->myUin), _T("%s"), reinterpret_cast(ci.pszVal)); + mir_free((void *)ci.pszVal); + break; + case CNFT_DWORD: + mir_sntprintf(dat->myUin, safe_sizeof(dat->myUin), _T("%u"), ci.dVal); + break; + default: + dat->myUin[0] = 0; + break; + } + } else + dat->myUin[0] = 0; +} + +static int g_IEViewAvail = -1; +static int g_HPPAvail = -1; + +UINT TSAPI GetIEViewMode(HWND hwndDlg, HANDLE hContact) +{ + int iWantIEView = 0, iWantHPP = 0; + + if (g_IEViewAvail == -1) + g_IEViewAvail = ServiceExists(MS_IEVIEW_WINDOW); + + if (g_HPPAvail == -1) + g_HPPAvail = ServiceExists("History++/ExtGrid/NewWindow"); + + PluginConfig.g_WantIEView = g_IEViewAvail && M->GetByte("default_ieview", 0); + PluginConfig.g_WantHPP = g_HPPAvail && M->GetByte("default_hpp", 0); + + iWantIEView = (PluginConfig.g_WantIEView) || (M->GetByte(hContact, "ieview", 0) == 1 && g_IEViewAvail); + iWantIEView = (M->GetByte(hContact, "ieview", 0) == (BYTE) - 1) ? 0 : iWantIEView; + + iWantHPP = (PluginConfig.g_WantHPP) || (M->GetByte(hContact, "hpplog", 0) == 1 && g_HPPAvail); + iWantHPP = (M->GetByte(hContact, "hpplog", 0) == (BYTE) - 1) ? 0 : iWantHPP; + + return iWantHPP ? WANT_HPP_LOG : (iWantIEView ? WANT_IEVIEW_LOG : 0); +} + +#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER) +static void CheckAndDestroyHPP(struct TWindowData *dat) +{ + if (dat->hwndHPP) { + IEVIEWWINDOW ieWindow; + ieWindow.cbSize = sizeof(IEVIEWWINDOW); + ieWindow.iType = IEW_DESTROY; + ieWindow.hwnd = dat->hwndHPP; + if(dat->oldIEViewProc) { + SetWindowLongPtr(dat->hwndHPP, GWLP_WNDPROC, (LONG_PTR)dat->oldIEViewProc); + dat->oldIEViewProc = 0; + } + CallService(MS_HPP_EG_WINDOW, 0, (LPARAM)&ieWindow); + dat->hwndHPP = 0; + } +} + +void TSAPI CheckAndDestroyIEView(TWindowData *dat) +{ + if (dat->hwndIEView) { + IEVIEWWINDOW ieWindow; + ieWindow.cbSize = sizeof(IEVIEWWINDOW); + ieWindow.iType = IEW_DESTROY; + ieWindow.hwnd = dat->hwndIEView; + if (dat->oldIEViewProc){ + SetWindowLongPtr(dat->hwndIEView, GWLP_WNDPROC, (LONG_PTR)dat->oldIEViewProc); + dat->oldIEViewProc =0; + } + CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow); + dat->oldIEViewProc = 0; + dat->hwndIEView = 0; + } +} +#endif + +void TSAPI SetMessageLog(TWindowData *dat) +{ + HWND hwndDlg = dat->hwnd; + unsigned int iLogMode = GetIEViewMode(hwndDlg, dat->hContact); + + if (iLogMode == WANT_IEVIEW_LOG && dat->hwndIEView == 0) { + IEVIEWWINDOW ieWindow; + + ZeroMemory(&ieWindow, sizeof(ieWindow)); +#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER) + CheckAndDestroyHPP(dat); +#endif + ieWindow.cbSize = sizeof(IEVIEWWINDOW); + ieWindow.iType = IEW_CREATE; + ieWindow.dwFlags = 0; + ieWindow.dwMode = IEWM_TABSRMM; + ieWindow.parent = hwndDlg; + ieWindow.x = 0; + ieWindow.y = 0; + ieWindow.cx = 200; + ieWindow.cy = 200; + CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow); + dat->hwndIEView = ieWindow.hwnd; + Utils::showDlgControl(hwndDlg, IDC_LOG, SW_HIDE); + Utils::enableDlgControl(hwndDlg, IDC_LOG, FALSE); + } else if (iLogMode == WANT_HPP_LOG && dat->hwndHPP == 0) { + IEVIEWWINDOW ieWindow; +#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER) + CheckAndDestroyIEView(dat); +#endif + ieWindow.cbSize = sizeof(IEVIEWWINDOW); + ieWindow.iType = IEW_CREATE; + ieWindow.dwFlags = 0; + ieWindow.dwMode = IEWM_TABSRMM; + ieWindow.parent = hwndDlg; + ieWindow.x = 0; + ieWindow.y = 0; + ieWindow.cx = 10; + ieWindow.cy = 10; + CallService(MS_HPP_EG_WINDOW, 0, (LPARAM)&ieWindow); + dat->hwndHPP = ieWindow.hwnd; + Utils::showDlgControl(hwndDlg, IDC_LOG, SW_HIDE); + Utils::enableDlgControl(hwndDlg, IDC_LOG, FALSE); + } else { +#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER) + if (iLogMode != WANT_IEVIEW_LOG) + CheckAndDestroyIEView(dat); + if (iLogMode != WANT_HPP_LOG) + CheckAndDestroyHPP(dat); + Utils::showDlgControl(hwndDlg, IDC_LOG, SW_SHOW); + Utils::enableDlgControl(hwndDlg, IDC_LOG, TRUE); + dat->hwndIEView = 0; + dat->hwndIWebBrowserControl = 0; + dat->hwndHPP = 0; +#endif + } +} + +#if defined(__FEAT_DEPRECATED_DYNAMICSWITCHLOGVIEWER) +void TSAPI SwitchMessageLog(TWindowData *dat, int iMode) +{ + HWND hwndDlg = dat->hwnd; + + if (iMode) { // switch from rtf to IEview or hpp + SetDlgItemText(hwndDlg, IDC_LOG, _T("")); + Utils::enableDlgControl(hwndDlg, IDC_LOG, FALSE); + Utils::showDlgControl(hwndDlg, IDC_LOG, SW_HIDE); + SetMessageLog(dat); + } else // switch from IEView or hpp to rtf + SetMessageLog(dat); + + SetDialogToType(hwndDlg); + SendMessage(hwndDlg, DM_REMAKELOG, 0, 0); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + + if (dat->hwndIEView) { + if (M->GetByte("subclassIEView", 0)&&dat->oldIEViewProc == 0) { + WNDPROC wndProc = (WNDPROC)SetWindowLongPtr(dat->hwndIEView, GWLP_WNDPROC, (LONG_PTR)IEViewSubclassProc); + dat->oldIEViewProc = wndProc; + } + } else if (dat->hwndHPP) { + if (dat->oldIEViewProc == 0) { + WNDPROC wndProc = (WNDPROC)SetWindowLongPtr(dat->hwndHPP, GWLP_WNDPROC, (LONG_PTR)HPPKFSubclassProc); + dat->oldIEViewProc = wndProc; + } + } +} +#endif + +void TSAPI FindFirstEvent(TWindowData *dat) +{ + int historyMode = (int)M->GetByte(dat->hContact, SRMSGMOD, SRMSGSET_LOADHISTORY, -1); + if (historyMode == -1) + historyMode = (int)M->GetByte(SRMSGMOD, SRMSGSET_LOADHISTORY, SRMSGDEFSET_LOADHISTORY); + + dat->hDbEventFirst = (HANDLE) CallService(MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM) dat->hContact, 0); + + if(dat->bActualHistory) + historyMode = LOADHISTORY_COUNT; + + switch (historyMode) { + case LOADHISTORY_COUNT: { + int i; + HANDLE hPrevEvent; + DBEVENTINFO dbei = { 0}; + dbei.cbSize = sizeof(dbei); + //MAD: ability to load only current session's history + if (dat->bActualHistory) + i = dat->cache->getSessionMsgCount(); + else + i = DBGetContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADCOUNT, SRMSGDEFSET_LOADCOUNT); + // + for (; i > 0; i--) { + if (dat->hDbEventFirst == NULL) + hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0); + else + hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) dat->hDbEventFirst, 0); + if (hPrevEvent == NULL) + break; + dbei.cbBlob = 0; + dat->hDbEventFirst = hPrevEvent; + CallService(MS_DB_EVENT_GET, (WPARAM) dat->hDbEventFirst, (LPARAM) & dbei); + if (!DbEventIsShown(dat, &dbei)) + i++; + } + break; + } + case LOADHISTORY_TIME: { + HANDLE hPrevEvent; + DBEVENTINFO dbei = { 0}; + DWORD firstTime; + + dbei.cbSize = sizeof(dbei); + if (dat->hDbEventFirst == NULL) + dbei.timestamp = time(NULL); + else + CallService(MS_DB_EVENT_GET, (WPARAM) dat->hDbEventFirst, (LPARAM) & dbei); + firstTime = dbei.timestamp - 60 * DBGetContactSettingWord(NULL, SRMSGMOD, SRMSGSET_LOADTIME, SRMSGDEFSET_LOADTIME); + for (;;) { + if (dat->hDbEventFirst == NULL) + hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDLAST, (WPARAM) dat->hContact, 0); + else + hPrevEvent = (HANDLE) CallService(MS_DB_EVENT_FINDPREV, (WPARAM) dat->hDbEventFirst, 0); + if (hPrevEvent == NULL) + break; + dbei.cbBlob = 0; + CallService(MS_DB_EVENT_GET, (WPARAM) hPrevEvent, (LPARAM) & dbei); + if (dbei.timestamp < firstTime) + break; + dat->hDbEventFirst = hPrevEvent; + } + break; + } + default: { + break; + } + } +} + +void TSAPI SaveSplitter(TWindowData *dat) +{ + /* + * group chats save their normal splitter position independently + */ + + if(dat->bType == SESSIONTYPE_CHAT) + return; + +#if defined(__FEAT_EXP_AUTOSPLITTER) + if(dat->fIsAutosizingInput) + return; +#endif + if (dat->splitterY < DPISCALEY_S(MINSPLITTERY) || dat->splitterY < 0) + dat->splitterY = DPISCALEY_S(MINSPLITTERY); + + if (dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE) + M->WriteDword(dat->hContact, SRMSGMOD_T, "splitsplity", dat->splitterY); + else { + if(dat->pContainer->settings->fPrivate) + dat->pContainer->settings->splitterPos = dat->splitterY; + else + M->WriteDword(SRMSGMOD_T, "splitsplity", dat->splitterY); + } +} + +void TSAPI LoadSplitter(TWindowData *dat) +{ +#if defined(__FEAT_EXP_AUTOSPLITTER) + if (dat->fIsAutosizingInput) { + dat->splitterY = GetDefaultMinimumInputHeight(dat); + return; + } +#endif + if (!(dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE)) + if(!dat->pContainer->settings->fPrivate) + dat->splitterY = (int)M->GetDword("splitsplity", (DWORD) 60); + else + dat->splitterY = dat->pContainer->settings->splitterPos; + else + dat->splitterY = (int)M->GetDword(dat->hContact, "splitsplity", M->GetDword("splitsplity", (DWORD) 70)); + + if (dat->splitterY < MINSPLITTERY || dat->splitterY < 0) + dat->splitterY = 150; +} + +void TSAPI PlayIncomingSound(const TWindowData *dat) +{ + int iPlay = Utils::mustPlaySound(dat); + + if (iPlay) { + if (GetForegroundWindow() == dat->pContainer->hwnd && dat->pContainer->hwndActive == dat->hwnd) + SkinPlaySound("RecvMsgActive"); + else + SkinPlaySound("RecvMsgInactive"); + } +} + +/* + * reads send format and configures the toolbar buttons + * if mode == 0, int only configures the buttons and does not change send format + */ + +void TSAPI GetSendFormat(TWindowData *dat, int mode) +{ + UINT controls[5] = {IDC_FONTBOLD, IDC_FONTITALIC, IDC_FONTUNDERLINE,IDC_FONTSTRIKEOUT, IDC_FONTFACE}; + int i; + + if (mode) { + dat->SendFormat = M->GetDword(dat->hContact, "sendformat", PluginConfig.m_SendFormat); + if (dat->SendFormat == -1) // per contact override to disable it.. + dat->SendFormat = 0; + else if (dat->SendFormat == 0) + dat->SendFormat = PluginConfig.m_SendFormat ? 1 : 0; + } + for (i = 0; i < 5; i++) + Utils::enableDlgControl(dat->hwnd, controls[i], dat->SendFormat != 0 ? TRUE : FALSE); + return; +} + +/* + * get user-readable locale information for the currently selected + * keyboard layout. + * + * GetLocaleInfo() should no longer be used on Vista and later + */ + +void TSAPI GetLocaleID(TWindowData *dat, const TCHAR *szKLName) +{ + TCHAR szLI[256], *stopped = NULL; + USHORT langID; + WORD wCtype2[3]; + PARAFORMAT2 pf2; + BOOL fLocaleNotSet; + char szTest[4] = {(char)0xe4, (char)0xf6, (char)0xfc, 0 }; + + szLI[0] = szLI[1] = 0; + + ZeroMemory(&pf2, sizeof(PARAFORMAT2)); + langID = (USHORT)_tcstol(szKLName, &stopped, 16); + dat->lcid = MAKELCID(langID, 0); + /* + * Vista+: read ISO locale names from the registry + */ + if(PluginConfig.m_bIsVista) { + HKEY hKey = 0; + TCHAR szKey[20]; + DWORD dwLID = _tcstoul(szKLName, &stopped, 16); + + mir_sntprintf(szKey, 20, _T("%04.04x"), LOWORD(dwLID)); + if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, _T("MIME\\Database\\Rfc1766"), 0, KEY_READ, &hKey)) { + DWORD dwLength = 255; + if(ERROR_SUCCESS == RegQueryValueEx(hKey, szKey, 0, 0, (unsigned char *)szLI, &dwLength)) { + TCHAR* p; + + szLI[255] = 0; + if((p = _tcschr(szLI, ';')) != 0) + *p = 0; + } + RegCloseKey(hKey); + } + szLI[0] = _totupper(szLI[0]); + szLI[1] = _totupper(szLI[1]); + } + else { + GetLocaleInfo(dat->lcid, LOCALE_SISO639LANGNAME, szLI, 10); + _tcsupr(szLI); + } + fLocaleNotSet = (dat->lcID[0] == 0 && dat->lcID[1] == 0); + mir_sntprintf(dat->lcID, safe_sizeof(dat->lcID), szLI); + GetStringTypeA(dat->lcid, CT_CTYPE2, szTest, 3, wCtype2); + pf2.cbSize = sizeof(pf2); + pf2.dwMask = PFM_RTLPARA; + SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_GETPARAFORMAT, 0, (LPARAM)&pf2); + if (Utils::FindRTLLocale(dat) && fLocaleNotSet) { + if (wCtype2[0] == C2_RIGHTTOLEFT || wCtype2[1] == C2_RIGHTTOLEFT || wCtype2[2] == C2_RIGHTTOLEFT) { + ZeroMemory(&pf2, sizeof(pf2)); + pf2.dwMask = PFM_RTLPARA; + pf2.cbSize = sizeof(pf2); + pf2.wEffects = PFE_RTLPARA; + SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); + } else { + ZeroMemory(&pf2, sizeof(pf2)); + pf2.dwMask = PFM_RTLPARA; + pf2.cbSize = sizeof(pf2); + pf2.wEffects = 0; + SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); + } + SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_SETLANGOPTIONS, 0, (LPARAM) SendDlgItemMessage(dat->hwnd, IDC_MESSAGE, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); + } +} + +void TSAPI LoadContactAvatar(TWindowData *dat) +{ + if(dat) + dat->ace = Utils::loadAvatarFromAVS(dat->hContact); + + if (dat && (!(dat->Panel->isActive()) || dat->pContainer->avatarMode == 3)) { + BITMAP bm; + dat->iRealAvatarHeight = 0; + + if (dat->ace && dat->ace->hbmPic) { + AdjustBottomAvatarDisplay(dat); + GetObject(dat->ace->hbmPic, sizeof(bm), &bm); + CalcDynamicAvatarSize(dat, &bm); + PostMessage(dat->hwnd, WM_SIZE, 0, 0); + } else if (dat->ace == NULL) { + AdjustBottomAvatarDisplay(dat); + GetObject(PluginConfig.g_hbmUnknown, sizeof(bm), &bm); + CalcDynamicAvatarSize(dat, &bm); + PostMessage(dat->hwnd, WM_SIZE, 0, 0); + } + } +} + +void TSAPI LoadOwnAvatar(TWindowData *dat) +{ + AVATARCACHEENTRY *ace = NULL; + + if (ServiceExists(MS_AV_GETMYAVATAR)) + ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)(dat->cache->getActiveProto())); + + if (ace) { + dat->hOwnPic = ace->hbmPic; + dat->ownAce = ace; + } else { + dat->hOwnPic = PluginConfig.g_hbmUnknown; + dat->ownAce = NULL; + } + if (dat->Panel->isActive() && dat->pContainer->avatarMode != 3) { + BITMAP bm; + + dat->iRealAvatarHeight = 0; + AdjustBottomAvatarDisplay(dat); + GetObject(dat->hOwnPic, sizeof(bm), &bm); + CalcDynamicAvatarSize(dat, &bm); + SendMessage(dat->hwnd, WM_SIZE, 0, 0); + } +} + +void TSAPI LoadTimeZone(TWindowData *dat) +{ + if (dat) + dat->hTimeZone = tmi.createByContact ? tmi.createByContact(dat->hContact, TZF_KNOWNONLY) : 0; +} + +/* + * paste contents of the clipboard into the message input area and send it immediately + */ + +void TSAPI HandlePasteAndSend(const TWindowData *dat) +{ + UINT ctrlID = dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE; + + if (!PluginConfig.m_PasteAndSend) { + SendMessage(dat->hwnd, DM_ACTIVATETOOLTIP, ctrlID, (LPARAM)CTranslator::get(CTranslator::GEN_WARNING_PASTEANDSEND_DISABLED)); + return; // feature disabled + } + + SendMessage(GetDlgItem(dat->hwnd, ctrlID), EM_PASTESPECIAL, CF_TEXTT, 0); + if (GetWindowTextLengthA(GetDlgItem(dat->hwnd, ctrlID)) > 0) + SendMessage(dat->hwnd, WM_COMMAND, IDOK, 0); +} + +/* + * draw various elements of the message window, like avatar(s), info panel fields + * and the color formatting menu + */ + +int TSAPI MsgWindowDrawHandler(WPARAM wParam, LPARAM lParam, TWindowData *dat) +{ + LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam; + + if (!dat) + return 0; + + bool fAero = M->isAero(); + HWND hwndDlg = dat->hwnd; + + if (dis->CtlType == ODT_MENU && dis->hwndItem == (HWND)GetSubMenu(PluginConfig.g_hMenuContext, 7)) { + RECT rc = { 0 }; + HBRUSH old, col; + COLORREF clr; + switch (dis->itemID) { + case ID_FONT_RED: + clr = RGB(255, 0, 0); + break; + case ID_FONT_BLUE: + clr = RGB(0, 0, 255); + break; + case ID_FONT_GREEN: + clr = RGB(0, 255, 0); + break; + case ID_FONT_MAGENTA: + clr = RGB(255, 0, 255); + break; + case ID_FONT_YELLOW: + clr = RGB(255, 255, 0); + break; + case ID_FONT_WHITE: + clr = RGB(255, 255, 255); + break; + case ID_FONT_DEFAULTCOLOR: + clr = GetSysColor(COLOR_MENU); + break; + case ID_FONT_CYAN: + clr = RGB(0, 255, 255); + break; + case ID_FONT_BLACK: + clr = RGB(0, 0, 0); + break; + default: + clr = 0; + } + col = (HBRUSH)CreateSolidBrush(clr); + old = (HBRUSH)SelectObject(dis->hDC, col); + rc.left = 2; + rc.top = dis->rcItem.top - 5; + rc.right = 15; + rc.bottom = dis->rcItem.bottom + 4; + Rectangle(dis->hDC, rc.left - 1, rc.top - 1, rc.right + 1, rc.bottom + 1); + FillRect(dis->hDC, &rc, col); + SelectObject(dis->hDC, old); + DeleteObject(col); + return TRUE; + } + else if ((dis->hwndItem == GetDlgItem(hwndDlg, IDC_CONTACTPIC) && (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown) && dat->showPic) || (dis->hwndItem == hwndDlg && dat->Panel->isActive() && (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown))) { + HBRUSH hOldBrush; + BITMAP bminfo; + double dAspect = 0, dNewWidth = 0, dNewHeight = 0; + DWORD iMaxHeight = 0, top, cx, cy; + RECT rc, rcClient, rcFrame; + HDC hdcDraw; + HBITMAP hbmDraw, hbmOld; + BOOL bPanelPic = dis->hwndItem == hwndDlg; + DWORD aceFlags = 0; + HPEN hPenBorder = 0, hPenOld = 0; + HRGN clipRgn = 0; + int iRad = PluginConfig.m_WinVerMajor >= 5 ? 4 : 6; + BOOL flashAvatar = FALSE; + bool fInfoPanel = dat->Panel->isActive(); + + if (PluginConfig.g_FlashAvatarAvail && (!bPanelPic || (bPanelPic && dat->showInfoPic == 1))) { + FLASHAVATAR fa = {0}; + + fa.id = 25367; + fa.cProto = dat->szProto; + if (!bPanelPic && fInfoPanel) { + fa.hParentWindow = GetDlgItem(hwndDlg, IDC_CONTACTPIC); + CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0); + Utils::enableDlgControl(hwndDlg, IDC_CONTACTPIC, fa.hWindow != 0); + } else { + fa.hContact = dat->hContact; + fa.hParentWindow = fInfoPanel ? dat->hwndPanelPicParent : GetDlgItem(hwndDlg, IDC_CONTACTPIC); + CallService(MS_FAVATAR_MAKE, (WPARAM)&fa, 0); + if (fInfoPanel) { + if (fa.hWindow != NULL&&dat->hwndPanelPic) { + DestroyWindow(dat->hwndPanelPic); + dat->hwndPanelPic = NULL; + } + if (!PluginConfig.g_bDisableAniAvatars && fa.hWindow == 0 && dat->hwndPanelPic == 0) { + dat->hwndPanelPic = CreateWindowEx(WS_EX_TOPMOST, AVATAR_CONTROL_CLASS, _T(""), WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, dat->hwndPanelPicParent, (HMENU)7000, NULL, NULL); + SendMessage(dat->hwndPanelPic, AVATAR_SETCONTACT, (WPARAM)0, (LPARAM)dat->hContact); + } + } else { + if (fa.hWindow != NULL && dat->hwndContactPic) { + DestroyWindow(dat->hwndContactPic); + dat->hwndContactPic = NULL; + } + if(!PluginConfig.g_bDisableAniAvatars && fa.hWindow == 0 && dat->hwndContactPic == 0) { + dat->hwndContactPic =CreateWindowEx(WS_EX_TOPMOST, AVATAR_CONTROL_CLASS, _T(""), WS_VISIBLE | WS_CHILD, 1, 1, 1, 1, GetDlgItem(hwndDlg, IDC_CONTACTPIC), (HMENU)0, NULL, NULL); + SendMessage(dat->hwndContactPic, AVATAR_SETCONTACT, (WPARAM)0, (LPARAM)dat->hContact); + } + } + dat->hwndFlash = fa.hWindow; + } + if (fa.hWindow != 0) { + bminfo.bmHeight = FAVATAR_HEIGHT; + bminfo.bmWidth = FAVATAR_WIDTH; + CallService(MS_FAVATAR_SETBKCOLOR, (WPARAM)&fa, (LPARAM)GetSysColor(COLOR_3DFACE)); + flashAvatar = TRUE; + } + } + + if (bPanelPic) { + if (!flashAvatar) { + GetObject(dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown, sizeof(bminfo), &bminfo); + } + if ((dat->ace && dat->showInfoPic && !(dat->ace->dwFlags & AVS_HIDEONCLIST)) || dat->showInfoPic) + aceFlags = dat->ace ? dat->ace->dwFlags : 0; + else { + if (dat->panelWidth) { + dat->panelWidth = -1; + if(!CSkin::m_skinEnabled) + SendMessage(hwndDlg, WM_SIZE, 0, 0); + } + return TRUE; + } + } else { + if (!fInfoPanel || dat->pContainer->avatarMode == 3) { + if (dat->ace) + aceFlags = dat->ace->dwFlags; + } else if (dat->ownAce) + aceFlags = dat->ownAce->dwFlags; + + GetObject((fInfoPanel && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown), sizeof(bminfo), &bminfo); + } + + GetClientRect(hwndDlg, &rc); + if(bPanelPic) { + rcClient = dis->rcItem; + cx = (rcClient.right - rcClient.left); + cy = (rcClient.bottom - rcClient.top) + 1; + } else { + GetClientRect(dis->hwndItem, &rcClient); + cx = rcClient.right; + cy = rcClient.bottom; + } + + if (cx < 5 || cy < 5) + return TRUE; + + if (bPanelPic) { + if (bminfo.bmHeight > bminfo.bmWidth) { + if (bminfo.bmHeight > 0) + dAspect = (double)(cy /*- 2*/) / (double)bminfo.bmHeight; + else + dAspect = 1.0; + dNewWidth = (double)bminfo.bmWidth * dAspect; + dNewHeight = cy;// - 2; + } else { + if (bminfo.bmWidth > 0) + dAspect = (double)(cy /*- 2*/) / (double)bminfo.bmWidth; + else + dAspect = 1.0; + dNewHeight = (double)bminfo.bmHeight * dAspect; + dNewWidth = cy;// - 2; + } + if (dat->panelWidth == -1) { + dat->panelWidth = (int)dNewWidth; + return(0); + } + } else { + + if (bminfo.bmHeight > 0) + dAspect = (double)dat->iRealAvatarHeight / (double)bminfo.bmHeight; + else + dAspect = 1.0; + dNewWidth = (double)bminfo.bmWidth * dAspect; + if (dNewWidth > (double)(rc.right) * 0.8) + dNewWidth = (double)(rc.right) * 0.8; + iMaxHeight = dat->iRealAvatarHeight; + } + + if (flashAvatar) { + SetWindowPos(dat->hwndPanelPicParent, HWND_TOP, rcClient.left, rcClient.top, + (int)dNewWidth, (int)dNewHeight, SWP_SHOWWINDOW | SWP_NOCOPYBITS); + return TRUE; + } + + hdcDraw = CreateCompatibleDC(dis->hDC); + hbmDraw = CreateCompatibleBitmap(dis->hDC, cx, cy); + hbmOld = (HBITMAP)SelectObject(hdcDraw, hbmDraw); + + bool fAero = M->isAero(); + + hOldBrush = (HBRUSH)SelectObject(hdcDraw, fAero ? (HBRUSH)GetStockObject(HOLLOW_BRUSH) : GetSysColorBrush(COLOR_3DFACE)); + rcFrame = rcClient; + + if (!bPanelPic) { + top = (cy - dat->pic.cy) / 2; + RECT rcEdge = {0, top, dat->pic.cx, top + dat->pic.cy}; + if (CSkin::m_skinEnabled) + CSkin::SkinDrawBG(dis->hwndItem, dat->pContainer->hwnd, dat->pContainer, &dis->rcItem, hdcDraw); + else if (PluginConfig.m_fillColor) { + HBRUSH br = CreateSolidBrush(PluginConfig.m_fillColor); + FillRect(hdcDraw, &rcFrame, br); + DeleteObject(br); + } + else { + if(fAero && CSkin::m_pCurrentAeroEffect) { + COLORREF clr = PluginConfig.m_tbBackgroundHigh ? PluginConfig.m_tbBackgroundHigh : + (CSkin::m_pCurrentAeroEffect ? CSkin::m_pCurrentAeroEffect->m_clrToolbar : 0xf0f0f0); + + HBRUSH br = CreateSolidBrush(clr); + FillRect(hdcDraw, &rcFrame, br); + DeleteObject(br); + } + else + FillRect(hdcDraw, &rcFrame, GetSysColorBrush(COLOR_3DFACE)); + } + + hPenBorder = CreatePen(PS_SOLID, 1, CSkin::m_avatarBorderClr); + hPenOld = (HPEN)SelectObject(hdcDraw, hPenBorder); + + if (CSkin::m_bAvatarBorderType == 1) + Rectangle(hdcDraw, rcEdge.left, rcEdge.top, rcEdge.right, rcEdge.bottom); + else if (CSkin::m_bAvatarBorderType == 2) { + clipRgn = CreateRoundRectRgn(rcEdge.left, rcEdge.top, rcEdge.right + 1, rcEdge.bottom + 1, iRad, iRad); + SelectClipRgn(hdcDraw, clipRgn); + } + } + + if ((((fInfoPanel && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown)) && dat->showPic) || bPanelPic) { + HDC hdcMem = CreateCompatibleDC(dis->hDC); + HBITMAP hbmAvatar = bPanelPic ? (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown) : ((fInfoPanel && dat->pContainer->avatarMode != 3) ? dat->hOwnPic : (dat->ace ? dat->ace->hbmPic : PluginConfig.g_hbmUnknown)); + HBITMAP hbmMem = 0; + if (bPanelPic) { + bool bBorder = (CSkin::m_bAvatarBorderType ? true : false); + + LONG height_off = 0; + LONG border_off = bBorder ? 1 : 0; + + ResizeBitmap rb; + rb.size = sizeof(rb); + rb.fit = RESIZEBITMAP_STRETCH; + rb.max_height = (int)(dNewHeight - (bBorder ? 2 : 0)); + rb.max_width = (int)(dNewWidth - (bBorder ? 2 : 0)); + rb.hBmp = hbmAvatar; + + HBITMAP hbmNew = (HBITMAP)CallService("IMG/ResizeBitmap", (WPARAM)&rb, 0); + hbmMem = (HBITMAP)SelectObject(hdcMem, hbmNew); + + rcFrame.left = rcFrame.top = 0; + rcFrame.right = (rcClient.right - rcClient.left); + rcFrame.bottom = (rcClient.bottom - rcClient.top); + + rcFrame.left = rcFrame.right - (LONG)dNewWidth; + rcFrame.bottom = (LONG)dNewHeight; + + height_off = ((cy) - (rb.max_height + (bBorder ? 2 : 0))) / 2; + rcFrame.top += height_off; + rcFrame.bottom += height_off; + + /* + * prepare border drawing (if avatar is rendered by ACC, the parent control will be responsible for + * the border, so skip it here) + */ + if(dat->hwndPanelPic == 0) { + OffsetRect(&rcClient, -2, 0); + if (CSkin::m_bAvatarBorderType == 1) + clipRgn = CreateRectRgn(rcClient.left + rcFrame.left, rcClient.top + rcFrame.top, rcClient.left + rcFrame.right, + rcClient.top + rcFrame.bottom); + else if (CSkin::m_bAvatarBorderType == 2) { + clipRgn = CreateRoundRectRgn(rcClient.left + rcFrame.left, rcClient.top + rcFrame.top, rcClient.left + rcFrame.right + 1, + rcClient.top + rcFrame.bottom + 1, iRad, iRad); + SelectClipRgn(dis->hDC, clipRgn); + } + } + + if(dat->hwndPanelPic) { + /* + * paint avatar using ACC + */ + SendMessage(dat->hwndPanelPic, AVATAR_SETAEROCOMPATDRAWING, 0, fAero ? TRUE : FALSE); + SetWindowPos(dat->hwndPanelPic, HWND_TOP, rcFrame.left + border_off, rcFrame.top + border_off, + rb.max_width, rb.max_height, SWP_SHOWWINDOW | SWP_ASYNCWINDOWPOS | SWP_DEFERERASE | SWP_NOSENDCHANGING); + } + else { + if(CMimAPI::m_MyAlphaBlend) { + CMimAPI::m_MyAlphaBlend(dis->hDC, rcClient.left + rcFrame.left + border_off, rcClient.top + rcFrame.top + border_off, + rb.max_width, rb.max_height, hdcMem, 0, 0, + rb.max_width, rb.max_height, CSkin::m_default_bf); + } + else + CSkin::MY_AlphaBlend(dis->hDC, rcClient.left + rcFrame.left + border_off, rcClient.top + rcFrame.top + border_off, + rb.max_width, rb.max_height, rb.max_width, rb.max_height, hdcMem); + } + SelectObject(hdcMem, hbmMem); + //DeleteObject(hbmMem); + DeleteDC(hdcMem); + if(hbmNew != hbmAvatar) + DeleteObject(hbmNew); + } else { + hbmMem = (HBITMAP)SelectObject(hdcMem, hbmAvatar); + LONG xy_off = 1; //CSkin::m_bAvatarBorderType ? 1 : 0; + LONG width_off = 0; //= CSkin::m_bAvatarBorderType ? 0 : 2; + + SetStretchBltMode(hdcDraw, HALFTONE); + if (aceFlags & AVS_PREMULTIPLIED) + CSkin::MY_AlphaBlend(hdcDraw, xy_off, top + xy_off, (int)dNewWidth + width_off, + iMaxHeight + width_off, bminfo.bmWidth, bminfo.bmHeight, hdcMem); + else + StretchBlt(hdcDraw, xy_off, top + xy_off, (int)dNewWidth + width_off, + iMaxHeight + width_off, hdcMem, 0, 0, bminfo.bmWidth, bminfo.bmHeight, SRCCOPY); + //_DebugTraceA("metrics: %d, %d %d, %d", (int)dNewWidth + width_off, iMaxHeight + width_off, bminfo.bmWidth, bminfo.bmHeight); + SelectObject(hdcMem, hbmMem); + DeleteObject(hbmMem); + DeleteDC(hdcMem); + } + if (clipRgn) { + HBRUSH hbr = CreateSolidBrush(CSkin::m_avatarBorderClr); + if(bPanelPic) + FrameRgn(dis->hDC, clipRgn, hbr, 1, 1); + else + FrameRgn(hdcDraw, clipRgn, hbr, 1, 1); + DeleteObject(hbr); + DeleteObject(clipRgn); + } + } + SelectObject(hdcDraw, hPenOld); + SelectObject(hdcDraw, hOldBrush); + DeleteObject(hPenBorder); + if(!bPanelPic) + BitBlt(dis->hDC, 0, 0, cx, cy, hdcDraw, 0, 0, SRCCOPY); + SelectObject(hdcDraw, hbmOld); + DeleteObject(hbmDraw); + DeleteDC(hdcDraw); + return TRUE; + } else if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_STATICTEXT) || dis->hwndItem == GetDlgItem(hwndDlg, IDC_LOGFROZENTEXT)) { + TCHAR szWindowText[256]; + if (CSkin::m_skinEnabled) { + SetTextColor(dis->hDC, CSkin::m_DefaultFontColor); + CSkin::SkinDrawBG(dis->hwndItem, dat->pContainer->hwnd, dat->pContainer, &dis->rcItem, dis->hDC); + } else { + SetTextColor(dis->hDC, GetSysColor(COLOR_BTNTEXT)); + CSkin::FillBack(dis->hDC, &dis->rcItem); + } + GetWindowText(dis->hwndItem, szWindowText, 255); + szWindowText[255] = 0; + SetBkMode(dis->hDC, TRANSPARENT); + DrawText(dis->hDC, szWindowText, -1, &dis->rcItem, DT_SINGLELINE | DT_VCENTER | DT_NOCLIP | DT_END_ELLIPSIS); + return TRUE; + } else if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_STATICERRORICON)) { + if (CSkin::m_skinEnabled) + CSkin::SkinDrawBG(dis->hwndItem, dat->pContainer->hwnd, dat->pContainer, &dis->rcItem, dis->hDC); + else + CSkin::FillBack(dis->hDC, &dis->rcItem); + DrawIconEx(dis->hDC, (dis->rcItem.right - dis->rcItem.left) / 2 - 8, (dis->rcItem.bottom - dis->rcItem.top) / 2 - 8, + PluginConfig.g_iconErr, 16, 16, 0, 0, DI_NORMAL); + return TRUE; + } + else if (dis->CtlType == ODT_MENU && dat->Panel->isHovered()) { + DrawMenuItem(dis, (HICON)dis->itemData, 0); + return(TRUE); + } + return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam); +} + +void TSAPI LoadThemeDefaults(TContainerData *pContainer) +{ + int i; + char szTemp[40]; + COLORREF colour; + ZeroMemory(&pContainer->theme, sizeof(TLogTheme)); + + pContainer->theme.bg = M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR, GetSysColor(COLOR_WINDOW)); + pContainer->theme.statbg = PluginConfig.crStatus; + pContainer->theme.oldinbg = PluginConfig.crOldIncoming; + pContainer->theme.oldoutbg = PluginConfig.crOldOutgoing; + pContainer->theme.inbg = PluginConfig.crIncoming; + pContainer->theme.outbg = PluginConfig.crOutgoing; + pContainer->theme.hgrid = M->GetDword(FONTMODULE, "hgrid", RGB(224, 224, 224)); + pContainer->theme.left_indent = M->GetDword("IndentAmount", 20) * 15; + pContainer->theme.right_indent = M->GetDword("RightIndent", 20) * 15; + pContainer->theme.inputbg = M->GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR); + + for (i = 1; i <= 5; i++) { + _snprintf(szTemp, 10, "cc%d", i); + colour = M->GetDword(szTemp, RGB(224, 224, 224)); + if (colour == 0) + colour = RGB(1, 1, 1); + pContainer->theme.custom_colors[i - 1] = colour; + } + pContainer->theme.logFonts = logfonts; + pContainer->theme.fontColors = fontcolors; + pContainer->theme.rtfFonts = NULL; + pContainer->ltr_templates = <R_Active; + pContainer->rtl_templates = &RTL_Active; + pContainer->theme.dwFlags = (M->GetDword("mwflags", MWF_LOG_DEFAULT) & MWF_LOG_ALL); + pContainer->theme.isPrivate = false; +} + +void TSAPI LoadOverrideTheme(TContainerData *pContainer) +{ + ZeroMemory(&pContainer->theme, sizeof(TLogTheme)); + + BOOL bReadTemplates = TRUE; //((pContainer->ltr_templates == NULL) || (pContainer->rtl_templates == NULL) || + //(pContainer->logFonts == NULL) || (pContainer->fontColors == NULL)); + + if (lstrlen(pContainer->szAbsThemeFile) > 1) { + if (PathFileExists(pContainer->szAbsThemeFile)) { + if (CheckThemeVersion(pContainer->szAbsThemeFile) == 0) { + LoadThemeDefaults(pContainer); + return; + } + if (pContainer->ltr_templates == NULL) { + pContainer->ltr_templates = (TTemplateSet *)malloc(sizeof(TTemplateSet)); + CopyMemory(pContainer->ltr_templates, <R_Active, sizeof(TTemplateSet)); + } + if (pContainer->rtl_templates == NULL) { + pContainer->rtl_templates = (TTemplateSet *)malloc(sizeof(TTemplateSet)); + CopyMemory(pContainer->rtl_templates, &RTL_Active, sizeof(TTemplateSet)); + } + + pContainer->theme.logFonts = (LOGFONTA *)malloc(sizeof(LOGFONTA) * (MSGDLGFONTCOUNT + 2)); + pContainer->theme.fontColors = (COLORREF *)malloc(sizeof(COLORREF) * (MSGDLGFONTCOUNT + 2)); + pContainer->theme.rtfFonts = (char *)malloc((MSGDLGFONTCOUNT + 2) * RTFCACHELINESIZE); + + ReadThemeFromINI(pContainer->szAbsThemeFile, pContainer, bReadTemplates ? 0 : 1, THEME_READ_ALL); + pContainer->theme.left_indent *= 15; + pContainer->theme.right_indent *= 15; + pContainer->theme.isPrivate = true; + if(CSkin::m_skinEnabled) + pContainer->theme.bg = SkinItems[ID_EXTBKCONTAINER].COLOR; + else + pContainer->theme.bg = PluginConfig.m_fillColor ? PluginConfig.m_fillColor : GetSysColor(COLOR_WINDOW); + return; + } + } + LoadThemeDefaults(pContainer); +} + +void TSAPI ConfigureSmileyButton(TWindowData *dat) +{ + HWND hwndDlg = dat->hwnd; + int nrSmileys = 0; + int showToolbar = dat->pContainer->dwFlags & CNT_HIDETOOLBAR ? 0 : 1; + int iItemID = IDC_SMILEYBTN; + + if (PluginConfig.g_SmileyAddAvail) { + nrSmileys = CheckValidSmileyPack(dat->cache->getActiveProto(), dat->cache->getActiveContact()); + dat->doSmileys = 1; + } + + if (nrSmileys == 0 || dat->hContact == 0) + dat->doSmileys = 0; + + Utils::showDlgControl(hwndDlg, iItemID, (dat->doSmileys && showToolbar) ? SW_SHOW : SW_HIDE); + Utils::enableDlgControl(hwndDlg, iItemID, dat->doSmileys ? TRUE : FALSE); +} + +HICON TSAPI GetXStatusIcon(const TWindowData *dat) +{ + char szServiceName[128]; + BYTE xStatus = dat->cache->getXStatusId(); + + mir_snprintf(szServiceName, 128, "%s/GetXStatusIcon", dat->cache->getActiveProto()); + + if (ServiceExists(szServiceName) && xStatus > 0 && xStatus <= 32) + return (HICON)(CallProtoService(dat->cache->getActiveProto(), "/GetXStatusIcon", xStatus, 0)); + return 0; +} + +LRESULT TSAPI GetSendButtonState(HWND hwnd) +{ + HWND hwndIDok=GetDlgItem(hwnd, IDOK); + + if(hwndIDok) + return(SendMessage(hwndIDok, BUTTONSETASFLATBTN + 15, 0, 0)); + else + return 0; +} + +void TSAPI EnableSendButton(const TWindowData *dat, int iMode) +{ + HWND hwndOK; + SendMessage(GetDlgItem(dat->hwnd, IDOK), BUTTONSETASFLATBTN + 14, iMode, 0); + SendMessage(GetDlgItem(dat->hwnd, IDC_PIC), BUTTONSETASFLATBTN + 14, dat->fEditNotesActive ? TRUE : (!iMode && dat->iOpenJobs == 0) ? TRUE : FALSE, 0); + + hwndOK = GetDlgItem(GetParent(GetParent(dat->hwnd)), IDOK); + + if (IsWindow(hwndOK)) + SendMessage(hwndOK, BUTTONSETASFLATBTN + 14, iMode, 0); +} + +void TSAPI SendNudge(const TWindowData *dat) +{ + char szServiceName[128]; + + mir_snprintf(szServiceName, 128, "%s/SendNudge", dat->cache->getActiveProto()); + if (ServiceExists(szServiceName) && ServiceExists(MS_NUDGE_SEND)) + CallService(MS_NUDGE_SEND, (WPARAM)dat->cache->getActiveContact(), 0); + else + SendMessage(dat->hwnd, DM_ACTIVATETOOLTIP, IDC_MESSAGE, + (LPARAM)CTranslator::get(CTranslator::GEN_WARNING_NUDGE_DISABLED)); +} + +void TSAPI GetClientIcon(TWindowData *dat) +{ + DBVARIANT dbv = {0}; + + if(dat->hClientIcon) + DestroyIcon(dat->hClientIcon); + + dat->hClientIcon = 0; + if (ServiceExists(MS_FP_GETCLIENTICON)) { + if (!DBGetContactSettingString(dat->cache->getActiveContact(), dat->cache->getActiveProto(), "MirVer", &dbv)) { + dat->hClientIcon = (HICON)CallService(MS_FP_GETCLIENTICON, (WPARAM)dbv.pszVal, 1); + DBFreeVariant(&dbv); + } + } +} + +void TSAPI GetMyNick(TWindowData *dat) +{ + CONTACTINFO ci; + + ZeroMemory(&ci, sizeof(ci)); + ci.cbSize = sizeof(ci); + ci.hContact = NULL; + ci.szProto = const_cast(dat->cache->getActiveProto()); + ci.dwFlag = CNF_TCHAR | CNF_NICK; + + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci)) { + if (ci.type == CNFT_ASCIIZ) { + if (lstrlen(reinterpret_cast(ci.pszVal)) < 1 || !_tcscmp(reinterpret_cast(ci.pszVal), + CTranslator::get(CTranslator::GEN_UNKNOWN_CONTACT))) { + mir_sntprintf(dat->szMyNickname, safe_sizeof(dat->szMyNickname), _T("%s"), dat->myUin[0] ? dat->myUin : CTranslator::get(CTranslator::GEN_UNKNOWN_CONTACT)); + if (ci.pszVal) { + mir_free(ci.pszVal); + ci.pszVal = NULL; + } + } else { + _tcsncpy(dat->szMyNickname, reinterpret_cast(ci.pszVal), 110); + dat->szMyNickname[109] = 0; + if (ci.pszVal) { + mir_free(ci.pszVal); + ci.pszVal = NULL; + } + } + } else if (ci.type == CNFT_DWORD) + _ltot(ci.dVal, dat->szMyNickname, 10); + else + _tcsncpy(dat->szMyNickname, _T(""), 110); // that really should *never* happen + } else + _tcsncpy(dat->szMyNickname, _T(""), 110); // same here + if (ci.pszVal) + mir_free(ci.pszVal); +} + +HICON TSAPI MY_GetContactIcon(const TWindowData *dat) +{ + return(LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getActiveStatus())); + //return(LoadSkinnedProtoIcon(dat->cache->getActiveProto(), dat->cache->getStatus())); +} + +static void TSAPI MTH_updatePreview(const TWindowData *dat) +{ + TMathWindowInfo mathWndInfo; + HWND hwndEdit = GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE); + int len = GetWindowTextLengthA(hwndEdit); + RECT windRect; + char * thestr = (char *)malloc(len + 5); + + GetWindowTextA(hwndEdit, thestr, len + 1); + GetWindowRect(dat->pContainer->hwnd, &windRect); + mathWndInfo.top = windRect.top; + mathWndInfo.left = windRect.left; + mathWndInfo.right = windRect.right; + mathWndInfo.bottom = windRect.bottom; + + CallService(MTH_SETFORMULA, 0, (LPARAM) thestr); + CallService(MTH_RESIZE, 0, (LPARAM) &mathWndInfo); + free(thestr); +} + +void TSAPI MTH_updateMathWindow(const TWindowData *dat) +{ + WINDOWPLACEMENT cWinPlace; + + if (!PluginConfig.m_MathModAvail) + return; + + MTH_updatePreview(dat); + CallService(MTH_SHOW, 0, 0); + cWinPlace.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(dat->pContainer->hwnd, &cWinPlace); + return; +} + +/** + * read keyboard state and return the state of the modifier keys + */ +void TSAPI KbdState(TWindowData *dat, BOOL& isShift, BOOL& isControl, BOOL& isAlt) +{ + GetKeyboardState(dat->kstate); + isShift = (dat->kstate[VK_SHIFT] & 0x80); + isControl = (dat->kstate[VK_CONTROL] & 0x80); + isAlt = (dat->kstate[VK_MENU] & 0x80); +} + +/** + * clear the message log + * code needs to distuingish between IM and MUC sessions. + */ +void TSAPI ClearLog(TWindowData *dat) +{ + if(dat && dat->bType == SESSIONTYPE_IM) { + if (dat->hwndIEView || dat->hwndHPP) { + IEVIEWEVENT event; + event.cbSize = sizeof(IEVIEWEVENT); + event.iType = IEE_CLEAR_LOG; + event.dwFlags = (dat->dwFlags & MWF_LOG_RTL) ? IEEF_RTL : 0; + event.hContact = dat->hContact; + if (dat->hwndIEView) { + event.hwnd = dat->hwndIEView; + CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event); + } else { + event.hwnd = dat->hwndHPP; + CallService(MS_HPP_EG_EVENT, 0, (LPARAM)&event); + } + } + SetDlgItemText(dat->hwnd, IDC_LOG, _T("")); + dat->hDbEventFirst = NULL; + } + else if(dat && dat->bType == SESSIONTYPE_CHAT && dat->si) { + SESSION_INFO* si = reinterpret_cast(dat->si); + SESSION_INFO* s = SM_FindSession(si->ptszID, si->pszModule); + if (s) { + SetDlgItemText(dat->hwnd, IDC_CHAT_LOG, _T("")); + LM_RemoveAll(&s->pLog, &s->pLogEnd); + s->iEventCount = 0; + s->LastTime = 0; + si->iEventCount = 0; + si->LastTime = 0; + si->pLog = s->pLog; + si->pLogEnd = s->pLogEnd; + PostMessage(dat->hwnd, WM_MOUSEACTIVATE, 0, 0); + } + } +} + +/** + * calculate the minimum required client height for the given message + * window layout + + * the container will use this in its WM_GETMINMAXINFO handler to set + * minimum tracking height. + */ +void TSAPI DetermineMinHeight(TWindowData* dat) +{ + if(dat) { + RECT rc; + + LONG height = (dat->Panel->isActive() ? dat->Panel->getHeight() + 2 : 0); + if(!(dat->pContainer->dwFlags & CNT_HIDETOOLBAR)) + height += DPISCALEY_S(24); // toolbar + GetClientRect(GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_MESSAGE : IDC_CHAT_MESSAGE), &rc); + height += rc.bottom; // input area + height += 40; // min space for log area and some padding + + dat->pContainer->uChildMinHeight = height; + } +} + +bool TSAPI IsAutoSplitEnabled(const TWindowData* dat) +{ +#if defined(__FEAT_EXP_AUTOSPLITTER) + return((dat && (dat->pContainer->dwFlags & CNT_AUTOSPLITTER) && !(dat->dwFlagsEx & MWF_SHOW_SPLITTEROVERRIDE)) ? true : false); +#else + return(false); +#endif +} + +#if defined(__FEAT_EXP_AUTOSPLITTER) +LONG TSAPI GetDefaultMinimumInputHeight(const TWindowData* dat) +{ + LONG height = MINSPLITTERY; + + if(dat) { + if(dat->bType == SESSIONTYPE_IM) + height = ((dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR) ? DPISCALEY_S(46 + 22) : DPISCALEY_S(46)); + else + height = ((dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR) ? DPISCALEY_S(22 + 46) : DPISCALEY_S(46)) - DPISCALEY_S(23); + + if(CSkin::m_skinEnabled && !SkinItems[ID_EXTBKINPUTAREA].IGNORED) + height += (SkinItems[ID_EXTBKINPUTAREA].MARGIN_BOTTOM + SkinItems[ID_EXTBKINPUTAREA].MARGIN_TOP - 2); + } + return(height); +} +#endif + +static std::vector vTempFilenames; + +/** + * send a pasted bitmap by file transfer. + */ +void TSAPI SendHBitmapAsFile(const TWindowData* dat, HBITMAP hbmp) +{ + const wchar_t* mirandatempdir = L"Miranda"; + const wchar_t* filenametemplate = L"\\clp-%Y%m%d-%H%M%S0.jpg"; + TCHAR filename[MAX_PATH]; + size_t tempdirlen = GetTempPath(MAX_PATH, filename); + bool fSend = true; + + const char* szProto = dat->cache->getActiveProto(); + WORD wMyStatus = (WORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0); + + DWORD protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0); + DWORD typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0); + + /* + * check protocol capabilities, status modes and visibility lists (privacy) + * to determine whether the file can be sent. Throw a warning if any of + * these checks fails. + */ + if(!(protoCaps & PF1_FILESEND)) + fSend = false; + + if((ID_STATUS_OFFLINE == wMyStatus) || (ID_STATUS_OFFLINE == dat->cache->getActiveStatus() && !(typeCaps & PF4_OFFLINEFILES))) + fSend = false; + + if (protoCaps & PF1_VISLIST && DBGetContactSettingWord(dat->cache->getActiveContact(), szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE) + fSend = false; + + if (protoCaps & PF1_INVISLIST && wMyStatus == ID_STATUS_INVISIBLE && DBGetContactSettingWord(dat->cache->getActiveContact(), szProto, "ApparentMode", 0) != ID_STATUS_ONLINE) + fSend = false; + + if(!fSend) { + CWarning::show(CWarning::WARN_SENDFILE, MB_OK|MB_ICONEXCLAMATION|CWarning::CWF_NOALLOWHIDE); + return; + } + if (tempdirlen <=0 || tempdirlen >= MAX_PATH-_tcslen(mirandatempdir)-_tcslen(filenametemplate)-2) // -2 is because %Y takes 4 symbols + filename[0] = 0; // prompt for a new name + else { + _tcscpy(filename+tempdirlen, mirandatempdir); + if ((GetFileAttributes(filename) == INVALID_FILE_ATTRIBUTES || ((GetFileAttributes(filename) & FILE_ATTRIBUTE_DIRECTORY) == 0)) && CreateDirectory(filename, NULL)==0) + filename[0] = 0; + else { + tempdirlen = _tcslen(filename); + + time_t rawtime; + time(&rawtime); + const tm* timeinfo; + timeinfo = _localtime32((__time32_t *)&rawtime); + _tcsftime(filename + tempdirlen, MAX_PATH-tempdirlen, filenametemplate, timeinfo); + size_t firstnumberpos = tempdirlen+14; + size_t lastnumberpos = tempdirlen+20; + while (GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES) { // while it exists + for (size_t pos = lastnumberpos; pos >= firstnumberpos; pos--) + if (filename[pos]++ != '9') + break; + else + if (pos == firstnumberpos) + filename[0] = 0; // all filenames exist => prompt for a new name + else + filename[pos] = '0'; + } + } + } + if (filename[0] == 0) { // prompting to save + OPENFILENAME dlg; + dlg.lStructSize = sizeof(dlg); + dlg.hwndOwner = NULL; //dat->hwnd; + TCHAR filter[MAX_PATH]; + mir_sntprintf(filter, SIZEOF(filter), _T("%s%c*.jpg%c%c"), TranslateT("JPEG-compressed images"), 0, 0, 0); + dlg.lpstrFilter = filter; + dlg.nFilterIndex = 1; + dlg.lpstrFile = filename; + dlg.nMaxFile = MAX_PATH; + dlg.Flags = OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; + dlg.lpstrDefExt = _T("jpg"); + if (!GetSaveFileName(&dlg)) + return; + } + IMGSRVC_INFO ii; + ii.cbSize = sizeof(ii); + ii.hbm = hbmp; + ii.wszName = filename; + ii.dwMask = IMGI_HBITMAP; + ii.fif = FIF_JPEG; + CallService(MS_IMG_SAVE, (WPARAM)&ii, IMGL_TCHAR); + + int fileCount = 1, totalCount = 0; + TCHAR** ppFiles = NULL; + Utils::AddToFileList(&ppFiles, &totalCount, filename); + + wchar_t* _t = mir_tstrdup(filename); + vTempFilenames.push_back(_t); + + CallService(MS_FILE_SENDSPECIFICFILEST, (WPARAM)dat->cache->getActiveContact(), (LPARAM)ppFiles); + + mir_free(ppFiles[0]); + mir_free(ppFiles); +} + +/** + * remove all temporary files created by the "send clipboard as file" feature. + */ +void TSAPI CleanTempFiles() +{ + std::vector::iterator it = vTempFilenames.begin(); + + while(it != vTempFilenames.end()) { + DeleteFileW(*it); + mir_free(*it++); + } +} -- cgit v1.2.3