From 50feaa0ffc1b2e120eb6b22b2970f5bc2f7dc7a4 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Sun, 14 Oct 2012 13:35:25 +0000 Subject: TabSRMM: folders restructurization git-svn-id: http://svn.miranda-ng.org/main/trunk@1923 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/TabSRMM/src/ImageDataObject.cpp | 2 +- plugins/TabSRMM/src/chat/chat.h | 369 ++ plugins/TabSRMM/src/chat/chat_resource.h | 161 + plugins/TabSRMM/src/chat/chatprototypes.h | 174 + plugins/TabSRMM/src/chat/clist.cpp | 325 ++ plugins/TabSRMM/src/chat/colorchooser.cpp | 281 ++ plugins/TabSRMM/src/chat/log.cpp | 1340 +++++++ plugins/TabSRMM/src/chat/main.cpp | 142 + plugins/TabSRMM/src/chat/manager.cpp | 1544 +++++++++ plugins/TabSRMM/src/chat/message.cpp | 341 ++ plugins/TabSRMM/src/chat/muchighlight.cpp | 427 +++ plugins/TabSRMM/src/chat/muchighlight.h | 94 + plugins/TabSRMM/src/chat/options.cpp | 1493 ++++++++ plugins/TabSRMM/src/chat/services.cpp | 882 +++++ plugins/TabSRMM/src/chat/tools.cpp | 1353 ++++++++ plugins/TabSRMM/src/chat/window.cpp | 3833 +++++++++++++++++++++ plugins/TabSRMM/src/commonheaders.h | 52 +- plugins/TabSRMM/src/include/ImageDataObject.h | 136 + plugins/TabSRMM/src/include/buttonbar.h | 54 + plugins/TabSRMM/src/include/contactcache.h | 167 + plugins/TabSRMM/src/include/controls.h | 136 + plugins/TabSRMM/src/include/functions.h | 199 ++ plugins/TabSRMM/src/include/generic_msghandlers.h | 67 + plugins/TabSRMM/src/include/globals.h | 245 ++ plugins/TabSRMM/src/include/infopanel.h | 220 ++ plugins/TabSRMM/src/include/m_cln_skinedit.h | 147 + plugins/TabSRMM/src/include/mim.h | 301 ++ plugins/TabSRMM/src/include/msgdlgutils.h | 103 + plugins/TabSRMM/src/include/msgs.h | 1062 ++++++ plugins/TabSRMM/src/include/nen.h | 169 + plugins/TabSRMM/src/include/resource.h | 796 +++++ plugins/TabSRMM/src/include/sendlater.h | 155 + plugins/TabSRMM/src/include/sendqueue.h | 123 + plugins/TabSRMM/src/include/sidebar.h | 239 ++ plugins/TabSRMM/src/include/taskbar.h | 197 ++ plugins/TabSRMM/src/include/templates.h | 50 + plugins/TabSRMM/src/include/themes.h | 415 +++ plugins/TabSRMM/src/include/translator.h | 63 + plugins/TabSRMM/src/include/typingnotify.h | 76 + plugins/TabSRMM/src/include/utils.h | 268 ++ plugins/TabSRMM/src/include/version.h | 15 + plugins/TabSRMM/src/modplus.cpp | 276 ++ plugins/TabSRMM/src/msgoptions_plus.cpp | 189 + 43 files changed, 18654 insertions(+), 27 deletions(-) create mode 100644 plugins/TabSRMM/src/chat/chat.h create mode 100644 plugins/TabSRMM/src/chat/chat_resource.h create mode 100644 plugins/TabSRMM/src/chat/chatprototypes.h create mode 100644 plugins/TabSRMM/src/chat/clist.cpp create mode 100644 plugins/TabSRMM/src/chat/colorchooser.cpp create mode 100644 plugins/TabSRMM/src/chat/log.cpp create mode 100644 plugins/TabSRMM/src/chat/main.cpp create mode 100644 plugins/TabSRMM/src/chat/manager.cpp create mode 100644 plugins/TabSRMM/src/chat/message.cpp create mode 100644 plugins/TabSRMM/src/chat/muchighlight.cpp create mode 100644 plugins/TabSRMM/src/chat/muchighlight.h create mode 100644 plugins/TabSRMM/src/chat/options.cpp create mode 100644 plugins/TabSRMM/src/chat/services.cpp create mode 100644 plugins/TabSRMM/src/chat/tools.cpp create mode 100644 plugins/TabSRMM/src/chat/window.cpp create mode 100644 plugins/TabSRMM/src/include/ImageDataObject.h create mode 100644 plugins/TabSRMM/src/include/buttonbar.h create mode 100644 plugins/TabSRMM/src/include/contactcache.h create mode 100644 plugins/TabSRMM/src/include/controls.h create mode 100644 plugins/TabSRMM/src/include/functions.h create mode 100644 plugins/TabSRMM/src/include/generic_msghandlers.h create mode 100644 plugins/TabSRMM/src/include/globals.h create mode 100644 plugins/TabSRMM/src/include/infopanel.h create mode 100644 plugins/TabSRMM/src/include/m_cln_skinedit.h create mode 100644 plugins/TabSRMM/src/include/mim.h create mode 100644 plugins/TabSRMM/src/include/msgdlgutils.h create mode 100644 plugins/TabSRMM/src/include/msgs.h create mode 100644 plugins/TabSRMM/src/include/nen.h create mode 100644 plugins/TabSRMM/src/include/resource.h create mode 100644 plugins/TabSRMM/src/include/sendlater.h create mode 100644 plugins/TabSRMM/src/include/sendqueue.h create mode 100644 plugins/TabSRMM/src/include/sidebar.h create mode 100644 plugins/TabSRMM/src/include/taskbar.h create mode 100644 plugins/TabSRMM/src/include/templates.h create mode 100644 plugins/TabSRMM/src/include/themes.h create mode 100644 plugins/TabSRMM/src/include/translator.h create mode 100644 plugins/TabSRMM/src/include/typingnotify.h create mode 100644 plugins/TabSRMM/src/include/utils.h create mode 100644 plugins/TabSRMM/src/include/version.h create mode 100644 plugins/TabSRMM/src/modplus.cpp create mode 100644 plugins/TabSRMM/src/msgoptions_plus.cpp (limited to 'plugins/TabSRMM/src') diff --git a/plugins/TabSRMM/src/ImageDataObject.cpp b/plugins/TabSRMM/src/ImageDataObject.cpp index 90fb804622..65e8e8d4dd 100644 --- a/plugins/TabSRMM/src/ImageDataObject.cpp +++ b/plugins/TabSRMM/src/ImageDataObject.cpp @@ -35,7 +35,7 @@ */ #include "commonheaders.h" -#include "../include/ImageDataObject.h" +#include "include\ImageDataObject.h" extern void ReleaseRichEditOle(IRichEditOle *ole) { diff --git a/plugins/TabSRMM/src/chat/chat.h b/plugins/TabSRMM/src/chat/chat.h new file mode 100644 index 0000000000..97224cef53 --- /dev/null +++ b/plugins/TabSRMM/src/chat/chat.h @@ -0,0 +1,369 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * This code is based on and still contains large parts of the the + * original chat module for Miranda NG, written and copyrighted + * by Joergen Persson in 2005. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: chat.h 12272 2010-08-04 08:24:08Z silvercircle $ + * + */ + +#ifndef _CHAT_H_ +#define _CHAT_H_ + +#pragma warning( disable : 4786 ) // limitation in MSVC's debugger. +#pragma warning( disable : 4996 ) // limitation in MSVC's debugger. + +#define WIN32_LEAN_AND_MEAN + +#include "m_stdhdr.h" + +//defines +#define OPTIONS_FONTCOUNT 20 +#define GC_UPDATETITLE (WM_USER+100) +#define GC_CLOSEWINDOW (WM_USER+103) +#define GC_GETITEMDATA (WM_USER+104) +#define GC_SETITEMDATA (WM_USER+105) +#define GC_UPDATESTATUSBAR (WM_USER+106) +#define GC_SETVISIBILITY (WM_USER+107) +#define GC_SETWNDPROPS (WM_USER+108) +#define GC_REDRAWLOG (WM_USER+109) +#define GC_FIREHOOK (WM_USER+110) +#define GC_FILTERFIX (WM_USER+111) +#define GC_CHANGEFILTERFLAG (WM_USER+112) +#define GC_SHOWFILTERMENU (WM_USER+113) +//#define GC_NICKLISTCLEAR (WM_USER+117) +#define GC_REDRAWWINDOW (WM_USER+118) +#define GC_SHOWCOLORCHOOSER (WM_USER+119) +#define GC_ADDLOG (WM_USER+120) +#define GC_ACKMESSAGE (WM_USER+121) +//#define GC_ADDUSER (WM_USER+122) +//#define GC_REMOVEUSER (WM_USER+123) +//#define GC_NICKCHANGE (WM_USER+124) +#define GC_UPDATENICKLIST (WM_USER+125) +//#define GC_MODECHANGE (WM_USER+126) +#define GC_SCROLLTOBOTTOM (WM_USER+129) +#define GC_SESSIONNAMECHANGE (WM_USER+131) +#define GC_SETMESSAGEHIGHLIGHT (WM_USER+139) +#define GC_REDRAWLOG2 (WM_USER+140) +#define GC_REDRAWLOG3 (WM_USER+141) + +#define EM_ACTIVATE (WM_USER+202) + +#define GC_EVENT_HIGHLIGHT 0x1000 +#define STATE_TALK 0x0001 + +#define ICON_ACTION 0 +#define ICON_ADDSTATUS 1 +#define ICON_HIGHLIGHT 2 +#define ICON_INFO 3 +#define ICON_JOIN 4 +#define ICON_KICK 5 +#define ICON_MESSAGE 6 +#define ICON_MESSAGEOUT 7 +#define ICON_NICK 8 +#define ICON_NOTICE 9 +#define ICON_PART 10 +#define ICON_QUIT 11 +#define ICON_REMSTATUS 12 +#define ICON_TOPIC 13 + +#define ICON_STATUS1 14 +#define ICON_STATUS2 15 +#define ICON_STATUS3 16 +#define ICON_STATUS4 17 +#define ICON_STATUS0 18 +#define ICON_STATUS5 19 + +// special service for tweaking performance +#define MS_GC_GETEVENTPTR "GChat/GetNewEventPtr" +typedef INT_PTR (*GETEVENTFUNC)(WPARAM wParam, LPARAM lParam); +typedef struct { + GETEVENTFUNC pfnAddEvent; +}GCPTRS; + +class CMUCHighlight; + +//structs + +typedef struct MODULE_INFO_TYPE +{ + char* pszModule; + TCHAR* ptszModDispName; + char* pszHeader; + BOOL bBold; + BOOL bUnderline; + BOOL bItalics; + BOOL bColor; + BOOL bBkgColor; + BOOL bChanMgr; + BOOL bAckMsg; + int nColorCount; + COLORREF* crColors; + /* + HICON hOnlineIcon; + HICON hOfflineIcon; + HICON hOnlineTalkIcon; + HICON hOfflineTalkIcon; + int OnlineIconIndex; + int OfflineIconIndex; + */ + int iMaxText; + DWORD idleTimeStamp; + DWORD lastIdleCheck; + TCHAR tszIdleMsg[60]; + CMUCHighlight* Highlight; + struct MODULE_INFO_TYPE *next; +} + MODULEINFO; + +typedef struct COMMAND_INFO_TYPE +{ + char* lpCommand; + struct COMMAND_INFO_TYPE *last, *next; +} + COMMAND_INFO; + +typedef struct +{ + LOGFONT lf; + COLORREF color; +} + FONTINFO; + +typedef struct LOG_INFO_TYPE +{ + TCHAR* ptszText; + TCHAR* ptszNick; + TCHAR* ptszUID; + TCHAR* ptszStatus; + TCHAR* ptszUserInfo; + BOOL bIsMe; + BOOL bIsHighlighted; + time_t time; + int iType; + DWORD dwFlags; + struct LOG_INFO_TYPE *next; + struct LOG_INFO_TYPE *prev; +} + LOGINFO; + +typedef struct STATUSINFO_TYPE +{ + TCHAR* pszGroup; + HICON hIcon; + WORD Status; + struct STATUSINFO_TYPE *next; +} + STATUSINFO; + +typedef struct USERINFO_TYPE +{ + TCHAR* pszNick; + TCHAR* pszUID; + WORD Status; + int iStatusEx; + WORD ContactStatus; + struct USERINFO_TYPE *next; +} + USERINFO; + +typedef struct SESSIONINFO_TYPE +{ + HWND hWnd; + + BOOL bFGSet; + BOOL bBGSet; + BOOL bFilterEnabled; + BOOL bNicklistEnabled; + BOOL bInitDone; + + char* pszModule; + TCHAR* ptszID; + TCHAR* ptszName; + TCHAR* ptszStatusbarText; + TCHAR* ptszTopic; + TCHAR pszLogFileName[MAX_PATH + 50]; + + char* pszID; // ugly fix for returning static ANSI strings in GC_INFO + char* pszName; // just to fix a bug quickly, should die after porting IRC to Unicode + + int iType; + int iFG; + int iBG; + int iSplitterY; + int iSplitterX; + int iLogFilterFlags; + int iLogPopupFlags; + int iLogTrayFlags; + int iDiskLogFlags; + int nUsersInNicklist; + int iEventCount; + int iStatusCount; + + WORD wStatus; + WORD wState; + WORD wCommandsNum; + DWORD dwItemData; + DWORD dwFlags; + HANDLE hContact; + HWND hwndFilter; + time_t LastTime; + TCHAR szSearch[255]; + int iSearchItem; + CMUCHighlight* Highlight; + COMMAND_INFO* lpCommands; + COMMAND_INFO* lpCurrentCommand; + LOGINFO* pLog; + LOGINFO* pLogEnd; + USERINFO* pUsers; + USERINFO* pMe; + STATUSINFO* pStatuses; + TContainerData *pContainer; + TWindowData *dat; + int wasTrimmed; + SESSIONINFO_TYPE* next; +} SESSION_INFO; + +typedef struct +{ + char* buffer; + int bufferOffset, bufferLen; + HWND hwnd; + LOGINFO* lin; + BOOL bStripFormat; + BOOL bRedraw; + SESSION_INFO* si; + int crCount; + TWindowData* dat; +} + LOGSTREAMDATA; + +struct TMUCSettings { + HICON hIconOverlay; + BOOL ShowTime; + BOOL ShowTimeIfChanged; + BOOL LoggingEnabled; + BOOL FlashWindow; + BOOL FlashWindowHightlight; + BOOL OpenInDefault; + BOOL HighlightEnabled; + BOOL LogIndentEnabled; + BOOL StripFormat; + BOOL BBCodeInPopups; + BOOL TrayIconInactiveOnly; + BOOL AddColonToAutoComplete; + BOOL LogLimitNames; + BOOL TimeStampEventColour; + DWORD dwIconFlags; + int LogTextIndent; + long LoggingLimit; + int iEventLimit; + int iEventLimitThreshold; + int iPopupStyle; + int iPopupTimeout; + int iSplitterX; + int iSplitterY; + TCHAR* pszTimeStamp; + TCHAR* pszTimeStampLog; + TCHAR* pszIncomingNick; + TCHAR* pszOutgoingNick; + TCHAR pszLogDir[MAX_PATH + 20]; + LONG iNickListFontHeight; + HFONT UserListFont, UserListHeadingsFont; + HFONT NameFont; + COLORREF crUserListColor; + COLORREF crUserListBGColor; + COLORREF crUserListHeadingsColor; + COLORREF crPUTextColour; + COLORREF crPUBkgColour; + BYTE ClassicIndicators; + //MAD + BYTE LogClassicIndicators; + BYTE AlternativeSorting; + BYTE AnnoyingHighlight; + BYTE CreateWindowOnHighlight; + //MAD_ + BYTE LogSymbols; + BYTE ClickableNicks; + BYTE ColorizeNicks; + BYTE ColorizeNicksInLog; + BYTE ScaleIcons; + BYTE UseDividers; + BYTE DividersUsePopupConfig; + BYTE MathMod; + COLORREF nickColors[8]; + HBRUSH SelectionBGBrush; + BOOL DoubleClick4Privat; + BOOL ShowContactStatus; + BOOL ContactStatusFirst; + HANDLE hGroup; + CMUCHighlight* Highlight; +}; + +struct FLASH_PARAMS { + HANDLE hContact; + const char* sound; + int iEvent; + HICON hNotifyIcon; + BOOL bActiveTab, bHighlight, bInactive, bMustFlash, bMustAutoswitch; + HWND hWnd; +}; + +extern TMUCSettings g_Settings; + +typedef struct{ + MODULEINFO* pModule; + int xPosition; + int yPosition; + HWND hWndTarget; + BOOL bForeground; + SESSION_INFO* si; +} COLORCHOOSER; + +#pragma comment(lib,"comctl32.lib") + +////////////////////////////////////////////////////////////////////////////////// + +#include "chatprototypes.h" +#include "chat_resource.h" + +#define mir_tstrdup mir_wstrdup + +TCHAR* a2t(const char* str); +char* t2a(const TCHAR* str, DWORD codepage); +TCHAR* a2tf(const TCHAR* str, int flags, DWORD cp = 0); +TCHAR* replaceStr(TCHAR** dest, const TCHAR* src); +char* replaceStrA(char** dest, const char* src); + +extern char *szChatIconString; + +#define DEFLOGFILENAME _T("%miranda_logpath%\\%proto%\\%userid%.log") + +#endif diff --git a/plugins/TabSRMM/src/chat/chat_resource.h b/plugins/TabSRMM/src/chat/chat_resource.h new file mode 100644 index 0000000000..07a9bb8ba4 --- /dev/null +++ b/plugins/TabSRMM/src/chat/chat_resource.h @@ -0,0 +1,161 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by chat.rc +// +#define IDR_MENU 151 +#define IDD_CHANNEL 401 +#define IDD_OPTIONS1 402 +#define IDD_OPTIONS2 403 +#define IDD_FILTER 404 +#define IDD_OPTIONSPOPUP 405 +#define IDD_COLORCHOOSER 406 +#define IDD_OPTIONS3 407 +#define IDD_OPTIONS4 408 +#define IDD_ADDHIGHLIGHT 409 +#define IDC_CHAT_LOG 1005 +#define IDC_SPLITTERX 1006 +#define IDC_SMILEY 1007 +#define IDC_SPLITTERY 1008 +#define IDC_CHAT_MESSAGE 1009 +#define IDC_FILTER 1013 +#define IDC_CHANMGR 1014 +#define IDC_SHOWNICKLIST 1015 +#define IDC_BKGCOLOR 1019 +#define IDC_CHECKBOXES 1021 +#define IDC_NICKROW2 1023 +#define IDC_NICKROW 1024 +#define IDC_LOGLIMIT 1024 +#define IDC_CHAT_CLOSE 1025 +#define IDC_CHAT_SPIN1 1028 +#define IDC_CHAT_SPIN2 1029 +#define IDC_CHAT_SPIN3 1030 +#define IDC_CHAT_SPIN4 1031 +#define IDC_PANELNICK 1032 +#define IDC_PANELUIN 1033 +#define IDC_INSTAMP 1041 +#define IDC_OUTSTAMP 1043 +#define IDC_TIMESTAMP 1046 +#define IDC_FONTCHOOSE 1047 +#define IDC_LOGDIRECTORY 1048 +#define IDC_LIMIT 1050 +#define IDC_LOGTIMESTAMP 1051 +#define IDC_GROUP 1057 +#define IDC_CHAT_RADIO1 1061 +#define IDC_RADIO2 1062 +#define IDC_RADIO3 1063 +#define IDC_TEXT 1064 +#define IDC_BKG 1065 +#define IDC_TIMEOUT 1067 +#define IDC_TEXTO 1069 +#define IDC_LOGGING 1069 +#define IDC_COLORTEXT 1070 +#define IDC_TEXTO2 1070 +#define IDC_TEXTO3 1071 +#define IDC_LIST 1072 +#define IDC_TEXTO4 1072 +#define IDC_STATIC_ADD 1077 +#define IDC_STATIC_ULIST 1078 +#define IDC_STATIC_OTHER 1079 +#define IDC_STATIC_MESSAGE 1081 +#define IDC_STATIC110 1082 +#define IDC_STATIC112 1085 +#define IDC_TRAYONLYFORINACTIVE 1086 +#define IDC_NOPOPUPSFORCLOSEDWINDOWS 1087 +#define IDC_LOGICONTYPE 1088 +#define IDC_HIGHLIGHTNICKENABLE 1089 +#define IDC_HIGHLIGHTNICKUID 1090 +#define IDC_HIGHLIGHTNICKPATTERN 1091 +#define IDC_HIGHLIGHTTEXTENABLE 1092 +#define IDC_COMBO1 1092 +#define IDC_ADDHIGHLIGHTNAME 1092 +#define IDC_HIGHLIGHTTEXTPATTERN 1093 +#define IDC_ADDHIGHLIGHTTITLE 1093 +#define IDC_ADDHIGHLIGHTEXPLAIN 1094 +#define IDC_HIGHLIGHTNICKUID2 1094 +#define IDC_HIGHLIGHTME 1094 +#define IDC_ADDHIGHLIGHTEDITLIST 1095 +#define IDC_MUC_OPENLOGBASEDIR 1096 +#define IDC_CHAT_BOLD 1106 +#define IDC_ITALICS 1107 +#define IDC_CHAT_UNDERLINE 1108 +#define IDC_COLOR 1110 +#define IDC_CHAT_HISTORY 1111 +#define IDC_1 1200 +#define IDC_2 1201 +#define IDC_3 1202 +#define IDC_4 1203 +#define IDC_5 1204 +#define IDC_6 1205 +#define IDC_7 1206 +#define IDC_8 1207 +#define IDC_9 1208 +#define IDC_10 1209 +#define IDC_11 1210 +#define IDC_PANELSPLITTER 1216 +#define IDC_CHAT_TOGGLESIDEBAR 1277 +#define IDC_P1 1300 +#define IDC_P2 1301 +#define IDC_P3 1302 +#define IDC_P4 1303 +#define IDC_P5 1304 +#define IDC_P6 1305 +#define IDC_P7 1306 +#define IDC_P8 1307 +#define IDC_P9 1308 +#define IDC_P10 1309 +#define IDC_P11 1310 +#define IDC_P12 1311 +#define IDC_T1 1400 +#define IDC_T2 1401 +#define IDC_T3 1402 +#define IDC_T4 1403 +#define IDC_T5 1404 +#define IDC_T6 1405 +#define IDC_T7 1406 +#define IDC_T8 1407 +#define IDC_T9 1408 +#define IDC_T10 1409 +#define IDC_T11 1410 +#define IDC_T12 1411 +#define IDC_L1 1500 +#define IDC_L2 1501 +#define IDC_L3 1502 +#define IDC_L4 1503 +#define IDC_L5 1504 +#define IDC_L6 1505 +#define IDC_L7 1506 +#define IDC_L8 1507 +#define IDC_L9 1508 +#define IDC_L10 1509 +#define IDC_L11 1510 +#define IDC_WHITERECT 1600 +#define ID_MESS 40001 +#define ID_NEW 40002 +#define ID_CURR 40003 +#define ID_COPY 40004 +#define ID_COPYALL 40006 +#define ID_CLEARLOG 40009 +#define ID_MESSAGE_UNDO 40013 +#define ID_MESSAGE_COPY 40014 +#define ID_MESSAGE_CUT 40015 +#define ID_MESSAGE_CLEAR 40017 +#define ID_MESSAGE_SELECTALL 40018 +#define ID_MESSAGE_REDO 40019 +#define ID_MESSAGE_PASTE 40020 +#define ID_CLOSE 40022 +#define ID_CLOSEOTHER 40023 +#define ID_LOCKPOSITION 40024 +#define ID_SEARCH_GOOGLE 40027 +#define ID_SEARCH_WIKIPEDIA 40028 +#define ID_WIKIPEDIA_ 40029 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 163 +#define _APS_NEXT_COMMAND_VALUE 40030 +#define _APS_NEXT_CONTROL_VALUE 1097 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/TabSRMM/src/chat/chatprototypes.h b/plugins/TabSRMM/src/chat/chatprototypes.h new file mode 100644 index 0000000000..c304b38cec --- /dev/null +++ b/plugins/TabSRMM/src/chat/chatprototypes.h @@ -0,0 +1,174 @@ +/* +Chat module plugin for Miranda NG + +Copyright (C) 2003-2009 Joergen Persson and others + +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. + +$Id: chatprototypes.h 13184 2010-12-07 14:16:58Z silvercircle $ + +*/ + +void LoadIcons(void); +void LoadLogIcons(void); +void FreeIcons(void); +void UpgradeCheck(void); + +//colorchooser.c +INT_PTR CALLBACK DlgProcColorToolWindow(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +//log.c +void Log_StreamInEvent(HWND hwndDlg, LOGINFO* lin, SESSION_INFO* si, BOOL bRedraw, BOOL bPhaseTwo); +void LoadMsgLogBitmaps(void); +void FreeMsgLogBitmaps(void); +TCHAR* GetChatLogsFilename(SESSION_INFO *si, time_t tTime); +TCHAR* MakeTimeStamp(TCHAR* pszStamp, time_t time); +char* Log_CreateRtfHeader(MODULEINFO * mi); + +//window.c +INT_PTR CALLBACK RoomWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); +int GetTextPixelSize( TCHAR* pszText, HFONT hFont, BOOL bWidth); + +//options.c +enum { FONTSECTION_AUTO, FONTSECTION_CHAT, FONTSECTION_IM, FONTSECTION_IP }; +int OptionsInit(void); +int OptionsUnInit(void); +void LoadMsgDlgFont(int section, int i, LOGFONT * lf, COLORREF * colour, char* szMod ); +void LoadGlobalSettings(void); +void AddIcons(void); +HICON LoadIconEx(int iIndex, char * pszIcoLibName, int iX, int iY); + +//services.c +void HookEvents(void); +void UnhookEvents(void); +int CreateServiceFunctions(void); +void DestroyServiceFunctions(void); +void DestroyHookableEvents(void); +void CreateHookableEvents(void); +void TabsInit(void); +int ModulesLoaded(WPARAM wParam,LPARAM lParam); +int SmileyOptionsChanged(WPARAM wParam,LPARAM lParam); +int PreShutdown(WPARAM wParam,LPARAM lParam); +int IconsChanged(WPARAM wParam,LPARAM lParam); +void ShowRoom(SESSION_INFO* si, WPARAM wp, BOOL bSetForeground); +INT_PTR Service_AddEvent(WPARAM wParam, LPARAM lParam); +int Service_ItemData(WPARAM wParam, LPARAM lParam); +int Service_SetSBText(WPARAM wParam, LPARAM lParam); +int Service_SetVisibility(WPARAM wParam, LPARAM lParam); +INT_PTR Service_GetCount(WPARAM wParam,LPARAM lParam); + +HWND CreateNewRoom(TContainerData *pContainer, SESSION_INFO *si, BOOL bActivateTab, BOOL bPopupContainer, BOOL bWantPopup); + +//manager.c +void SetActiveSession(const TCHAR* pszID, const char* pszModule); +void SetActiveSessionEx(SESSION_INFO* si); +SESSION_INFO* GetActiveSession(void); +SESSION_INFO* SM_AddSession(const TCHAR* pszID, const char* pszModule); +int SM_RemoveSession(const TCHAR* pszID, const char* pszModule, bool removeContact); +SESSION_INFO* SM_FindSession(const TCHAR* pszID, const char* pszModule); +USERINFO* SM_AddUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus); +SESSION_INFO* SM_FindSessionAutoComplete(const char* pszModule, SESSION_INFO* currSession, SESSION_INFO* prevSession, const TCHAR* pszOriginal, const TCHAR* pszCurrent); +BOOL SM_ChangeUID(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszNewUID); +BOOL SM_ChangeNick(const TCHAR* pszID, const char* pszModule, GCEVENT * gce); +BOOL SM_RemoveUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID); +BOOL SM_SetOffline(const TCHAR* pszID, const char* pszModule); +HICON SM_GetStatusIcon(SESSION_INFO* si, USERINFO* ui, char* szIndicator); +BOOL SM_SetStatus(const TCHAR* pszID, const char* pszModule, int wStatus); +BOOL SM_SetStatusEx(const TCHAR* pszID, const char* pszModule, const TCHAR* pszText, int flags ); +BOOL SM_SendUserMessage(const TCHAR* pszID, const char* pszModule, const TCHAR* pszText); +STATUSINFO* SM_AddStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszStatus); +BOOL SM_AddEventToAllMatchingUID(GCEVENT * gce, BOOL bisHighLight = FALSE); +BOOL SM_AddEvent(const TCHAR* pszID, const char* pszModule, GCEVENT * gce, BOOL bIsHighlighted); +LRESULT SM_SendMessage(const TCHAR* pszID, const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam); +BOOL SM_PostMessage(const TCHAR* pszID, const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam); +BOOL SM_BroadcastMessage(const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam, BOOL bAsync); +BOOL SM_RemoveAll (void); +BOOL SM_GiveStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszStatus); +BOOL SM_SetContactStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, WORD pszStatus); +BOOL SM_TakeStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszStatus); +BOOL SM_MoveUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID); +void SM_AddCommand(const TCHAR* pszID, const char* pszModule, const char* lpNewCommand); +char* SM_GetPrevCommand(const TCHAR* pszID, const char* pszModule); +char* SM_GetNextCommand(const TCHAR* pszID, const char* pszModule); +int SM_GetCount(const char* pszModule); +SESSION_INFO* SM_FindSessionByHWND(HWND h); +SESSION_INFO* SM_FindSessionByHCONTACT(HANDLE h); +SESSION_INFO* SM_FindSessionByIndex(const char* pszModule, int iItem); +char* SM_GetUsers(SESSION_INFO* si); +USERINFO* SM_GetUserFromIndex(const TCHAR* pszID, const char* pszModule, int index); +BOOL SM_ReconfigureFilters(); +BOOL SM_InvalidateLogDirectories(); +MODULEINFO* MM_AddModule(const char* pszModule); +MODULEINFO* MM_FindModule(const char* pszModule); +void MM_FixColors(); +void MM_FontsChanged(void); +void MM_IconsChanged(void); +BOOL MM_RemoveAll (void); +BOOL TabM_AddTab(const TCHAR* pszID, const char* pszModule); +BOOL TabM_RemoveAll (void); +STATUSINFO* TM_AddStatus(STATUSINFO** ppStatusList, const TCHAR* pszStatus, int* iCount); +STATUSINFO* TM_FindStatus(STATUSINFO* pStatusList, const TCHAR* pszStatus); +WORD TM_StringToWord(STATUSINFO* pStatusList, const TCHAR* pszStatus); +TCHAR* TM_WordToString(STATUSINFO* pStatusList, WORD Status); +BOOL TM_RemoveAll (STATUSINFO** pStatusList); +BOOL UM_SetStatusEx(USERINFO* pUserList,const TCHAR* pszText, int onlyMe ); +USERINFO* UM_AddUser(STATUSINFO* pStatusList, USERINFO** pUserList, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus); +USERINFO* UM_SortUser(USERINFO** ppUserList, const TCHAR* pszUID); +USERINFO* UM_FindUser(USERINFO* pUserList, const TCHAR* pszUID); +USERINFO* UM_FindUserFromIndex(USERINFO* pUserList, int index); +USERINFO* UM_GiveStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status); +USERINFO* UM_SetContactStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status); +USERINFO* UM_TakeStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status); +TCHAR* UM_FindUserAutoComplete(USERINFO* pUserList, const TCHAR* pszOriginal, const TCHAR* pszCurrent); +BOOL UM_RemoveUser(USERINFO** pUserList, const TCHAR* pszUID); +BOOL UM_RemoveAll (USERINFO** ppUserList); +LOGINFO* LM_AddEvent(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd); +BOOL LM_TrimLog(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd, int iCount); +BOOL LM_RemoveAll (LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd); + +//clist.c +HANDLE CList_AddRoom(const char* pszModule, const TCHAR* pszRoom, const TCHAR* pszDisplayName, int iType); +BOOL CList_SetOffline(HANDLE hContact, BOOL bHide); +BOOL CList_SetAllOffline(BOOL bHide, const char *pszModule); +int CList_RoomDoubleclicked(WPARAM wParam,LPARAM lParam); +INT_PTR CList_EventDoubleclicked(WPARAM wParam,LPARAM lParam); +INT_PTR CList_JoinChat(WPARAM wParam, LPARAM lParam); +INT_PTR CList_LeaveChat(WPARAM wParam, LPARAM lParam); +int CList_PrebuildContactMenu(WPARAM wParam, LPARAM lParam); +INT_PTR CList_PrebuildContactMenuSvc(WPARAM wParam, LPARAM lParam); +void CList_CreateGroup(TCHAR* group); +BOOL CList_AddEvent(HANDLE hContact, HICON Icon, HANDLE event, int type, const TCHAR* fmt, ... ) ; +HANDLE CList_FindRoom (const char* pszModule, const TCHAR* pszRoom) ; +int WCCmp(TCHAR* wild, TCHAR*string); + +//tools.c +TCHAR* RemoveFormatting(const TCHAR* pszText, bool fLower = false, bool fStripCR = false, TCHAR* buf = 0, const size_t len = 0); +BOOL DoSoundsFlashPopupTrayStuff(SESSION_INFO* si, GCEVENT * gce, BOOL bHighlight, int bManyFix); +int Chat_GetColorIndex(const char* pszModule, COLORREF cr); +void CheckColorsInModule(const char* pszModule); +TCHAR* my_strstri(const TCHAR* s1, const TCHAR* s2) ; +int GetRichTextLength(HWND hwnd); +BOOL IsHighlighted(SESSION_INFO* si, const TCHAR* pszText); +UINT CreateGCMenu(HWND hwndDlg, HMENU *hMenu, int iIndex, POINT pt, SESSION_INFO* si, TCHAR* pszUID, TCHAR* pszWordText); +void DestroyGCMenu(HMENU *hMenu, int iIndex); +BOOL DoEventHookAsync(HWND hwnd, const TCHAR* pszID, const char* pszModule, int iType, TCHAR* pszUID, TCHAR* pszText, DWORD dwItem); +BOOL DoEventHook(const TCHAR* pszID, const char* pszModule, int iType, const TCHAR* pszUID, const TCHAR* pszText, DWORD dwItem); +BOOL IsEventSupported(int eventType); +BOOL LogToFile(SESSION_INFO* si, GCEVENT * gce); +void Chat_SetFilters(SESSION_INFO *si); +void TSAPI DoFlashAndSoundWorker(FLASH_PARAMS* p); +// message.c +char* Chat_Message_GetFromStream(HWND hwndDlg, SESSION_INFO* si); +TCHAR* Chat_DoRtfToTags( char* pszRtfText, SESSION_INFO* si); diff --git a/plugins/TabSRMM/src/chat/clist.cpp b/plugins/TabSRMM/src/chat/clist.cpp new file mode 100644 index 0000000000..8e095e1585 --- /dev/null +++ b/plugins/TabSRMM/src/chat/clist.cpp @@ -0,0 +1,325 @@ +/* +astyle --force-indent=tab=4 --brackets=linux --indent-switches + --pad=oper --one-line=keep-blocks --unpad=paren + +Chat module plugin for Miranda NG + +Copyright (C) 2003 Jörgen Persson + +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. + +Group chat module: contact list support functions. Add chat rooms as +contacts and handle default action for such contacts. + +This code was taken in almost unmodified from from the chat.dll +plugin, originally written by Jörgen Persson + +$Id: clist.c 10402 2009-07-24 00:35:21Z silvercircle $ + +*/ + +/* + * handles interaction of the group chat implementation with the contact list plugin + */ + +#include "..\commonheaders.h" + +char *szChatIconString = "chaticon"; + +extern HANDLE hJoinMenuItem, hLeaveMenuItem; + +static HANDLE Clist_GroupExists(TCHAR *tszGroup) +{ + unsigned int i = 0; + TCHAR* _t = 0; + char str[10]; + INT_PTR result = 0; + DBVARIANT dbv = {0}; + int match; + + do { + _itoa(i, str, 10); + result = M->GetTString(0, "CListGroups", str, &dbv); + if (!result) { + match = (!_tcscmp(tszGroup, &dbv.ptszVal[1]) && (lstrlen(tszGroup) == lstrlen(&dbv.ptszVal[1]))); + DBFreeVariant(&dbv); + if (match) + return((HANDLE)(i + 1)); + } + i++; + } + while(result == 0); + return 0; +} + +HANDLE CList_AddRoom(const char* pszModule, const TCHAR* pszRoom, const TCHAR* pszDisplayName, int iType) +{ + HANDLE hContact = CList_FindRoom(pszModule, pszRoom); + DBVARIANT dbv; + TCHAR pszGroup[50]; + + *pszGroup = '\0'; + if (!M->GetTString(NULL, "Chat", "AddToGroup", &dbv)) { + if (lstrlen(dbv.ptszVal) > 0) + lstrcpyn(pszGroup, dbv.ptszVal, 50); + DBFreeVariant(&dbv); + } else + lstrcpyn(pszGroup, _T("Chat rooms"), 50); + + if (pszGroup[0]) + CList_CreateGroup(pszGroup); + + if (hContact) + return hContact; + + // here we create a new one since no one is to be found + + if ((hContact = (HANDLE) CallService(MS_DB_CONTACT_ADD, 0, 0)) == NULL) + return NULL; + + CallService(MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM) pszModule); + if (pszGroup && lstrlen(pszGroup) > 0) + CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)hContact, (LPARAM)g_Settings.hGroup); + else + DBDeleteContactSetting(hContact, "CList", "Group"); + + M->WriteTString(hContact, pszModule, "Nick", pszDisplayName); + M->WriteTString(hContact, pszModule, "ChatRoomID", pszRoom); + M->WriteByte(hContact, pszModule, "ChatRoom", (BYTE)iType); + DBWriteContactSettingWord(hContact, pszModule, "Status", ID_STATUS_OFFLINE); + return hContact; +} + +BOOL CList_SetOffline(HANDLE hContact, BOOL bHide) +{ + if (hContact) { + char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + int i = M->GetByte(hContact, szProto, "ChatRoom", 0); + DBWriteContactSettingWord(hContact, szProto, "ApparentMode", (LPARAM) 0); + DBWriteContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE); + return TRUE; + } + return FALSE; +} + +BOOL CList_SetAllOffline(BOOL bHide, const char *pszModule) +{ + HANDLE hContact; + char* szProto; + + hContact = db_find_first(); + while (hContact) { + szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (MM_FindModule(szProto)) { + if (!pszModule || (pszModule && !strcmp(pszModule, szProto))) { + int i = M->GetByte(hContact, szProto, "ChatRoom", 0); + if (i != 0) { + DBWriteContactSettingWord(hContact, szProto, "ApparentMode", (LPARAM)(WORD) 0); + DBWriteContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE); + } + } + } + + hContact = db_find_next(hContact); + } + return TRUE; +} + +int CList_RoomDoubleclicked(WPARAM wParam, LPARAM lParam) +{ + DBVARIANT dbv; + char *szProto; + BOOL bRedrawFlag = FALSE; + bool fCreate = false; + + HANDLE hContact = (HANDLE)wParam; + if (!hContact) + return 0; + + szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (MM_FindModule(szProto)) { + if (M->GetByte(hContact, szProto, "ChatRoom", 0) == 0) + return 0; + + if (!M->GetTString(hContact, szProto, "ChatRoomID", &dbv)) { + SESSION_INFO* si = SM_FindSession(dbv.ptszVal, szProto); + if (si) { + // is the "toggle visibility option set, so we need to close the window? + if (si->hWnd != NULL + && M->GetByte("Chat", "ToggleVisibility", 0) == 1 + && !CallService(MS_CLIST_GETEVENT, (WPARAM)hContact, 0) + && IsWindowVisible(si->hWnd) + && !IsIconic(si->pContainer->hwnd)) { + PostMessage(si->hWnd, GC_CLOSEWINDOW, 0, 0); + DBFreeVariant(&dbv); + return 1; + } + else + fCreate = true; + + ShowRoom(si, WINDOW_VISIBLE, TRUE); + if (lParam && fCreate) { + SendMessage(si->hWnd, DM_ACTIVATEME, 0, 0); + if (si->dat) + SetForegroundWindow(si->dat->pContainer->hwnd); + } + } + DBFreeVariant(&dbv); + return 1; + } + } + + return 0; +} + +INT_PTR CList_EventDoubleclicked(WPARAM wParam, LPARAM lParam) +{ + return CList_RoomDoubleclicked((WPARAM)((CLISTEVENT*)lParam)->hContact, (LPARAM) 0); +} + +INT_PTR CList_JoinChat(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + if ( hContact ) { + char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if ( szProto ) { + if ( DBGetContactSettingWord( hContact, szProto, "Status", 0 ) == ID_STATUS_OFFLINE ) + CallProtoService( szProto, PS_JOINCHAT, wParam, lParam ); + else + CList_RoomDoubleclicked( wParam, 0 ); + } } + + return 0; +} + +INT_PTR CList_LeaveChat(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + if ( hContact ) { + char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if ( szProto ) + CallProtoService( szProto, PS_LEAVECHAT, wParam, lParam ); + } + return 0; +} + +int CList_PrebuildContactMenu(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + if ( hContact ) { + char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + + CLISTMENUITEM clmi = {0}; + clmi.cbSize = sizeof(CLISTMENUITEM); + clmi.flags = CMIM_FLAGS | CMIF_DEFAULT | CMIF_HIDDEN; + + if ( szProto ) { + // display this menu item only for chats + if ( M->GetByte(hContact, szProto, "ChatRoom", 0 )) { + // still hide it for offline protos + if ( CallProtoService( szProto, PS_GETSTATUS, 0, 0 ) != ID_STATUS_OFFLINE ) { + clmi.flags &= ~CMIF_HIDDEN; + clmi.flags |= CMIM_NAME; + + if ( DBGetContactSettingWord( hContact, szProto, "Status", 0 ) == ID_STATUS_OFFLINE ) + clmi.pszName = ( char* )LPGEN("Join chat"); + else + clmi.pszName = ( char* )LPGEN("Open chat window"); + } } } + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hJoinMenuItem, ( LPARAM )&clmi ); + + clmi.flags &= ~(CMIM_NAME | CMIF_DEFAULT); + clmi.flags |= CMIF_NOTOFFLINE; + CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hLeaveMenuItem, ( LPARAM )&clmi ); + } + return 0; +} + +INT_PTR CList_PrebuildContactMenuSvc(WPARAM wParam, LPARAM lParam) +{ + return CList_PrebuildContactMenu(wParam, lParam); +} + + +void CList_CreateGroup(TCHAR* group) +{ + if (!group) + return; + + g_Settings.hGroup = Clist_GroupExists(group); + + if (g_Settings.hGroup == 0) { + g_Settings.hGroup = (HANDLE)CallService(MS_CLIST_GROUPCREATE, 0, (LPARAM)group); + + if (g_Settings.hGroup) { + CallService(MS_CLUI_GROUPADDED, (WPARAM)g_Settings.hGroup, 0); + CallService(MS_CLIST_GROUPSETEXPANDED, (WPARAM)g_Settings.hGroup, 1); + } + } +} + +BOOL CList_AddEvent(HANDLE hContact, HICON Icon, HANDLE event, int type, const TCHAR* fmt, ...) +{ + CLISTEVENT cle; + va_list marker; + TCHAR* szBuf = (TCHAR*)alloca(4096 * sizeof(TCHAR)); + + if (!fmt || lstrlen(fmt) < 1 || lstrlen(fmt) > 2000) + return FALSE; + + va_start(marker, fmt); + _vstprintf(szBuf, fmt, marker); + va_end(marker); + + cle.cbSize = sizeof(cle); + cle.hContact = (HANDLE)hContact; + cle.hDbEvent = (HANDLE)event; + cle.flags = type + CLEF_TCHAR; + cle.hIcon = Icon; + cle.pszService = "GChat/DblClickEvent" ; + cle.ptszTooltip = TranslateTS(szBuf); + if (type) { + if (!CallService(MS_CLIST_GETEVENT, (WPARAM)hContact, (LPARAM)0)) + CallService(MS_CLIST_ADDEVENT, (WPARAM) hContact, (LPARAM) &cle); + } else { + if (CallService(MS_CLIST_GETEVENT, (WPARAM)hContact, (LPARAM)0)) + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)hContact, (LPARAM)"chaticon"); + CallService(MS_CLIST_ADDEVENT, (WPARAM) hContact, (LPARAM) &cle); + } + return TRUE; +} + +HANDLE CList_FindRoom(const char* pszModule, const TCHAR* pszRoom) +{ + HANDLE hContact = db_find_first(); + while (hContact) { + char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (szProto && !lstrcmpiA(szProto, pszModule)) { + if (M->GetByte(hContact, szProto, "ChatRoom", 0) != 0) { + DBVARIANT dbv; + if (!M->GetTString(hContact, szProto, "ChatRoomID", &dbv)) { + if (!lstrcmpi(dbv.ptszVal, pszRoom)) { + DBFreeVariant(&dbv); + return hContact; + } + DBFreeVariant(&dbv); + } + } + } + + hContact = db_find_next(hContact); + } + return 0; +} diff --git a/plugins/TabSRMM/src/chat/colorchooser.cpp b/plugins/TabSRMM/src/chat/colorchooser.cpp new file mode 100644 index 0000000000..72366db24b --- /dev/null +++ b/plugins/TabSRMM/src/chat/colorchooser.cpp @@ -0,0 +1,281 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * This code is based on and still contains large parts of the the + * original chat module for Miranda NG, written and copyrighted + * by Joergen Persson in 2005. + * + * $Id: colorchooser.cpp 10670 2009-09-11 03:28:50Z silvercircle $ + * + * Color chooser for group chats + * + */ + +#include "..\commonheaders.h" +#include + +static int CalculateCoordinatesToButton(COLORCHOOSER * pCC, POINT pt) +{ + int iSquareRoot = (int)sqrt(static_cast(pCC->pModule->nColorCount)); + int nCols = iSquareRoot * iSquareRoot < pCC->pModule->nColorCount ? iSquareRoot + 1 : iSquareRoot; + + int col = pt.x / 25; + int row = (pt.y - 20) / 20; + int pos = nCols * row + col; + + if (pt.y < 20 && pos >= pCC->pModule->nColorCount) + pos = -1; + + return pos; +} + +static RECT CalculateButtonToCoordinates(COLORCHOOSER * pCC, int buttonPosition) +{ + RECT pt; + int iSquareRoot = (int)sqrt(static_cast(pCC->pModule->nColorCount)); + int nCols = iSquareRoot * iSquareRoot < pCC->pModule->nColorCount ? iSquareRoot + 1 : iSquareRoot; + + int row = buttonPosition / nCols; + int col = buttonPosition % nCols; + + pt.left = col * 25 + 1; + pt.top = row * 20 + 20; + pt.right = pt.left + 25 - 1; + pt.bottom = pt.top + 20; + + return pt; +} + +INT_PTR CALLBACK DlgProcColorToolWindow(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static COLORCHOOSER* pCC = NULL; + static int iCurrentHotTrack; + static BOOL bChoosing; + static int iRows; + static int iColumns; + static HWND hPreviousActiveWindow; + + switch (msg) { + case WM_INITDIALOG: { + RECT rc; + int iSquareRoot; + int width ; + int height; + + TranslateDialogDefault(hwndDlg); + pCC = (COLORCHOOSER*) lParam; + + iCurrentHotTrack = -2; + bChoosing = FALSE; + + iSquareRoot = (int)sqrt(static_cast(pCC->pModule->nColorCount)); + + iColumns = iSquareRoot * iSquareRoot == pCC->pModule->nColorCount ? iSquareRoot : iSquareRoot + 1; + iRows = iSquareRoot; + + rc.top = rc.left = 100; + rc.right = 100 + iColumns * 25 + 1; + rc.bottom = iRows * 20 + 100 + 20; + + AdjustWindowRectEx(&rc, GetWindowLongPtr(hwndDlg, GWL_STYLE), FALSE, GetWindowLongPtr(hwndDlg, GWL_EXSTYLE)); + + width = rc.right - rc.left; + height = rc.bottom - rc.top; + + pCC->yPosition -= height; + + + SetDlgItemText(hwndDlg, IDC_COLORTEXT, pCC->bForeground ? TranslateT("Text color") : + TranslateT("Background color")); + SetWindowPos(GetDlgItem(hwndDlg, IDC_COLORTEXT), NULL, 0, 0, width, 20, 0); + SetWindowPos(hwndDlg, NULL, pCC->xPosition, pCC->yPosition, width, height, SWP_SHOWWINDOW); + } + break; + + case WM_CTLCOLOREDIT: + case WM_CTLCOLORSTATIC: + if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_COLORTEXT)) { + SetTextColor((HDC)wParam, RGB(60, 60, 150)); + SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + if (iCurrentHotTrack >= 0) + PostMessage(hwndDlg, WM_LBUTTONUP, 0, 0); + break; + case IDCANCEL: + DestroyWindow(hwndDlg); + break; + } + break; + + case WM_LBUTTONUP: + if (iCurrentHotTrack >= 0 && iCurrentHotTrack < pCC->pModule->nColorCount && pCC->hWndTarget != NULL) { + HWND hWindow; + CHARFORMAT2 cf; + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwMask = 0; + cf.dwEffects = 0; + hWindow = GetParent(pCC->hWndTarget); + + if (pCC->bForeground) { + pCC->si->bFGSet = TRUE; + pCC->si->iFG = iCurrentHotTrack; + if (IsDlgButtonChecked(hWindow, IDC_COLOR)) { + cf.dwMask = CFM_COLOR; + cf.crTextColor = pCC->pModule->crColors[iCurrentHotTrack]; + SendMessage(pCC->hWndTarget, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } else { + pCC->si->bBGSet = TRUE; + pCC->si->iBG = iCurrentHotTrack; + if (IsDlgButtonChecked(hWindow, IDC_BKGCOLOR)) { + cf.dwMask = CFM_BACKCOLOR; + cf.crBackColor = pCC->pModule->crColors[iCurrentHotTrack]; + SendMessage(pCC->hWndTarget, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } + } + PostMessage(hwndDlg, WM_CLOSE, 0, 0); + break; + + case WM_ACTIVATE: + if (wParam == WA_INACTIVE) + PostMessage(hwndDlg, WM_CLOSE, 0, 0); + else if ((wParam == WA_ACTIVE) || (wParam == WA_CLICKACTIVE)) + hPreviousActiveWindow = (HWND)lParam; + break; + + case WM_MOUSEMOVE: { + HDC hdc = GetDC(hwndDlg); + POINT pt; + RECT rect; + int but; + + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + + if (iCurrentHotTrack == -2) + return 0; // prevent focussing when not drawn yet! + + but = CalculateCoordinatesToButton(pCC, pt); + + // weird stuff + if (but != iCurrentHotTrack) { + if (iCurrentHotTrack >= 0) { + rect = CalculateButtonToCoordinates(pCC, iCurrentHotTrack); + DrawFocusRect(hdc, &rect); + iCurrentHotTrack = -1; + } + iCurrentHotTrack = but; + + if (iCurrentHotTrack >= 0) { + rect = CalculateButtonToCoordinates(pCC, iCurrentHotTrack); + DrawFocusRect(hdc, &rect); + } + } + ReleaseDC(hwndDlg, hdc); + } + break; + + case WM_PAINT: { + PAINTSTRUCT ps; + HDC hdc; + RECT rc; + int i = 0; + int iThisRow = 1; + int iThisColumn = 0; + + GetClientRect(hwndDlg, &rc); + + rc.top += 20; + + hdc = BeginPaint(hwndDlg, &ps); + + // fill background + FillRect(hdc, &rc, GetSysColorBrush(COLOR_WINDOW)); + + for (i; i < pCC->pModule->nColorCount; i++) { + HBRUSH hbr; + + // decide place to draw the color block in the window + iThisColumn ++; + if (iThisColumn > iColumns) { + iThisColumn = 1; + iThisRow++; + } + + if (pCC->bForeground && pCC->si->bFGSet && pCC->si->iFG == i || + !pCC->bForeground && pCC->si->bBGSet && pCC->si->iBG == i) { + rc.top = (iThisRow - 1) * 20 + 1 + 20 ; + rc.left = (iThisColumn - 1) * 25 + 1 + 1 ; + rc.bottom = iThisRow * 20 - 1 + 20 ; + rc.right = iThisColumn * 25 - 1 ; + + DrawEdge(hdc, &rc, EDGE_RAISED, BF_TOP | BF_LEFT | BF_RIGHT | BF_BOTTOM); + } + + rc.top = (iThisRow - 1) * 20 + 3 + 20 ; + rc.left = (iThisColumn - 1) * 25 + 3 + 1 ; + rc.bottom = iThisRow * 20 - 3 + 20 ; + rc.right = iThisColumn * 25 - 3 ; + + FillRect(hdc, &rc, CSkin::m_BrushBack); + + hbr = CreateSolidBrush(pCC->pModule->crColors[i]); + + rc.top = (iThisRow - 1) * 20 + 4 + 20; + rc.left = (iThisColumn - 1) * 25 + 4 + 1; + rc.bottom = iThisRow * 20 - 4 + 20; + rc.right = iThisColumn * 25 - 4; + + FillRect(hdc, &rc, hbr); + DeleteObject(hbr); + } + + EndPaint(hwndDlg, &ps); + iCurrentHotTrack = -1; + } + break; + + case WM_CLOSE: + SetFocus(pCC->hWndTarget); + DestroyWindow(hwndDlg); + break; + + case WM_DESTROY: + mir_free(pCC); + return TRUE; + } + + return FALSE; +} diff --git a/plugins/TabSRMM/src/chat/log.cpp b/plugins/TabSRMM/src/chat/log.cpp new file mode 100644 index 0000000000..bdadea5bf5 --- /dev/null +++ b/plugins/TabSRMM/src/chat/log.cpp @@ -0,0 +1,1340 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * This code is based on and still contains large parts of the the + * original chat module for Miranda NG, written and copyrighted + * by Joergen Persson in 2005. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: log.cpp 13614 2011-04-22 13:16:21Z borkra $ + * + * Implements the richedit-based message history display for the group + * chat window. + * + */ + +#include "..\commonheaders.h" +#include +#include +#include + +/* + * The code for streaming the text is to a large extent copied from + * the srmm module and then modified to fit the chat module. + */ + +extern FONTINFO aFonts[OPTIONS_FONTCOUNT]; +extern HICON hIcons[30]; + +static PBYTE pLogIconBmpBits[14]; +static int logIconBmpSize[ SIZEOF(pLogIconBmpBits)]; + +static int logPixelSY = 0; +static int logPixelSX = 0; +static char *szDivider = "\\strike----------------------------------------------------------------------------\\strike0"; +static char CHAT_rtfFontsGlobal[OPTIONS_FONTCOUNT + 2][RTFCACHELINESIZE]; +static char *CHAT_rtffonts = 0; + +/* + * ieview MUC support - mostly from scriver + */ + +/* +static char* u2a( const wchar_t* src, int codepage ) { + int cbLen = WideCharToMultiByte( codepage, 0, src, -1, NULL, 0, NULL, NULL ); + char* result = ( char* )mir_alloc( cbLen+1 ); + if ( result == NULL ) + return NULL; + + WideCharToMultiByte( codepage, 0, src, -1, result, cbLen, NULL, NULL ); + result[ cbLen ] = 0; + return result; +} + +static char* t2acp( const TCHAR* src, int codepage ) { + return u2a( src, codepage ); +} + +static TCHAR *a2tcp(const char *text, int cp) { + if ( text != NULL ) { + int cbLen = MultiByteToWideChar( cp, 0, text, -1, NULL, 0 ); + TCHAR* result = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( cbLen+1 )); + if ( result == NULL ) + return NULL; + MultiByteToWideChar(cp, 0, text, -1, result, cbLen); + return result; + } + return NULL; +} + +static int Log_AppendIEView(LOGSTREAMDATA* streamData, BOOL simpleMode, TCHAR **buffer, int *cbBufferEnd, int *cbBufferAlloced, const TCHAR *fmt, ...) +{ + va_list va; + int lineLen, textCharsCount=0; + TCHAR* line = (TCHAR*)alloca( 8001 * sizeof(TCHAR)); + TCHAR* d; + MODULEINFO *mi = MM_FindModule(streamData->si->pszModule); + + va_start(va, fmt); + lineLen = _vsntprintf( line, 8000, fmt, va); + if (lineLen < 0) + return 0; + line[lineLen] = 0; + va_end(va); + lineLen = lineLen*9 + 8; + if (*cbBufferEnd + lineLen > *cbBufferAlloced) { + cbBufferAlloced[0] += (lineLen + 1024 - lineLen % 1024); + *buffer = (TCHAR *) mir_realloc(*buffer, *cbBufferAlloced * sizeof(TCHAR)); + } + + d = *buffer + *cbBufferEnd; + + for (; *line; line++, textCharsCount++) { + if (*line == '%' && !simpleMode ) { + TCHAR szTemp[200]; + + szTemp[0] = '\0'; + switch ( *++line ) { + case '\0': + case '%': + *d++ = '%'; + break; + + case 'c': + case 'f': + if (!g_Settings.StripFormat && !streamData->bStripFormat) { + if ( line[1] != '\0' && line[2] != '\0') { + TCHAR szTemp3[3], c = *line; + int col; + szTemp3[0] = line[1]; + szTemp3[1] = line[2]; + szTemp3[2] = '\0'; + col = _ttoi(szTemp3); + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%%c#%02X%02X%02X"), c, GetRValue(mi->crColors[col]), GetGValue(mi->crColors[col]), GetBValue(mi->crColors[col])); + } + } + line += 2; + break; + case 'C': + case 'F': + if ( !g_Settings.StripFormat && !streamData->bStripFormat) { + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%%c"), *line ); + } + break; + case 'b': + case 'u': + case 'i': + case 'B': + case 'U': + case 'I': + case 'r': + if ( !streamData->bStripFormat ) { + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%%%c"), *line ); + } + break; + } + + if ( szTemp[0] ) { + size_t iLen = lstrlen(szTemp); + memcpy( d, szTemp, iLen * sizeof(TCHAR)); + d += iLen; + } + } + else if (*line == '%') { + *d++ = '%'; + *d++ = (char) *line; + } + else { + *d++ = (TCHAR) *line; + } + } + *d = '\0'; + *cbBufferEnd = (int) (d - *buffer); + return textCharsCount; +} + +static void AddEventTextToBufferIEView(TCHAR **buffer, int *bufferEnd, int *bufferAlloced, LOGSTREAMDATA *streamData) +{ + if (streamData->lin->ptszText) + Log_AppendIEView(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T(": %s"), streamData->lin->ptszText); +} + +static void AddEventToBufferIEView(TCHAR **buffer, int *bufferEnd, int *bufferAlloced, LOGSTREAMDATA *streamData, TCHAR *pszNick) +{ + + if ( streamData && streamData->lin ) { + switch ( streamData->lin->iType ) { + case GC_EVENT_MESSAGE: + if ( streamData->lin->ptszText ) { + TCHAR *ptszTemp = NULL; + TCHAR *ptszText = streamData->lin->ptszText; + if (streamData->dat->codePage != CP_ACP) { + char *aText = t2acp(streamData->lin->ptszText, CP_ACP); + ptszText = ptszTemp = a2tcp(aText, streamData->dat->codePage); + mir_free(aText); + } + Log_AppendIEView( streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), ptszText ); + mir_free(ptszTemp); + } + break; + case GC_EVENT_ACTION: + if ( pszNick && streamData->lin->ptszText) { + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, _T("%s "), streamData->lin->ptszNick); + Log_AppendIEView(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), streamData->lin->ptszText); + } + break; + case GC_EVENT_JOIN: + if (pszNick) { + if (!streamData->lin->bIsMe) + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s has joined"), pszNick); + else + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("You have joined %s"), streamData->si->ptszName); + } + break; + case GC_EVENT_PART: + if (pszNick) + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s has left"), pszNick); + AddEventTextToBufferIEView(buffer, bufferEnd, bufferAlloced, streamData); + break; + case GC_EVENT_QUIT: + if (pszNick) + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s has disconnected"), pszNick); + AddEventTextToBufferIEView(buffer, bufferEnd, bufferAlloced, streamData); + break; + case GC_EVENT_NICK: + if (pszNick && streamData->lin->ptszText) { + if (!streamData->lin->bIsMe) + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s is now known as %s"), pszNick, streamData->lin->ptszText); + else + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("You are now known as %s"), streamData->lin->ptszText); + } + break; + case GC_EVENT_KICK: + if (pszNick && streamData->lin->ptszStatus) + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s kicked %s"), streamData->lin->ptszStatus, streamData->lin->ptszNick); + AddEventTextToBufferIEView(buffer, bufferEnd, bufferAlloced, streamData); + break; + case GC_EVENT_NOTICE: + if (pszNick && streamData->lin->ptszText) { + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("Notice from %s"), pszNick ); + AddEventTextToBufferIEView(buffer, bufferEnd, bufferAlloced, streamData); + } + break; + case GC_EVENT_TOPIC: + if (streamData->lin->ptszText) + Log_AppendIEView(streamData, FALSE, buffer, bufferEnd, bufferAlloced, TranslateT("The topic is \'%s%s\'"), streamData->lin->ptszText, _T("%r")); + if (pszNick) + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, + streamData->lin->ptszUserInfo ? TranslateT(" (set by %s on %s)"): TranslateT(" (set by %s)"), + pszNick, streamData->lin->ptszUserInfo); + break; + case GC_EVENT_INFORMATION: + if (streamData->lin->ptszText) + Log_AppendIEView(streamData, FALSE, buffer, bufferEnd, bufferAlloced, (streamData->lin->bIsMe) ? _T("--> %s") : _T("%s"), streamData->lin->ptszText); + break; + case GC_EVENT_ADDSTATUS: + if (pszNick && streamData->lin->ptszText && streamData->lin->ptszStatus) + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s enables \'%s\' status for %s"), streamData->lin->ptszText, streamData->lin->ptszStatus, streamData->lin->ptszNick); + break; + case GC_EVENT_REMOVESTATUS: + if (pszNick && streamData->lin->ptszText && streamData->lin->ptszStatus) + Log_AppendIEView(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s disables \'%s\' status for %s"), streamData->lin->ptszText , streamData->lin->ptszStatus, streamData->lin->ptszNick); + break; + } + } +} + +static void LogEventIEView(LOGSTREAMDATA *streamData, TCHAR *ptszNick) +{ + TCHAR *buffer = NULL; + int bufferEnd = 0; + int bufferAlloced = 0; + IEVIEWEVENTDATA ied; + IEVIEWEVENT event; + ZeroMemory(&event, sizeof(event)); + event.cbSize = sizeof(event); + event.dwFlags = 0; + event.hwnd = streamData->dat->hwndIEView ? streamData->dat->hwndIEView : streamData->dat->hwndHPP; + event.hContact = streamData->dat->hContact; + event.codepage = streamData->dat->codePage; + event.pszProto = streamData->si->pszModule; + event.iType = IEE_LOG_MEM_EVENTS; + event.eventData = &ied; + event.count = 1; + + ZeroMemory(&ied, sizeof(ied)); + AddEventToBufferIEView(&buffer, &bufferEnd, &bufferAlloced, streamData, ptszNick); + ied.ptszNick = ptszNick; + ied.ptszText = buffer; + ied.time = streamData->lin->time; + ied.bIsMe = streamData->lin->bIsMe; + + switch ( streamData->lin->iType ) { + case GC_EVENT_MESSAGE: + ied.iType = IEED_GC_EVENT_MESSAGE; + ied.dwData = IEEDD_GC_SHOW_NICK; + break; + case GC_EVENT_ACTION: + ied.iType = IEED_GC_EVENT_ACTION; + break; + case GC_EVENT_JOIN: + ied.iType = IEED_GC_EVENT_JOIN; + break; + case GC_EVENT_PART: + ied.iType = IEED_GC_EVENT_PART; + break; + case GC_EVENT_QUIT: + ied.iType = IEED_GC_EVENT_QUIT; + break; + case GC_EVENT_NICK: + ied.iType = IEED_GC_EVENT_NICK; + break; + case GC_EVENT_KICK: + ied.iType = IEED_GC_EVENT_KICK; + break; + case GC_EVENT_NOTICE: + ied.iType = IEED_GC_EVENT_NOTICE; + break; + case GC_EVENT_TOPIC: + ied.iType = IEED_GC_EVENT_TOPIC; + break; + case GC_EVENT_INFORMATION: + ied.iType = IEED_GC_EVENT_INFORMATION; + break; + case GC_EVENT_ADDSTATUS: + ied.iType = IEED_GC_EVENT_ADDSTATUS; + break; + case GC_EVENT_REMOVESTATUS: + ied.iType = IEED_GC_EVENT_REMOVESTATUS; + break; + } + ied.dwData |= g_Settings.ShowTime ? IEEDD_GC_SHOW_TIME : 0; + ied.dwData |= IEEDD_GC_SHOW_ICON; + ied.dwFlags = IEEDF_UNICODE_TEXT | IEEDF_UNICODE_NICK | IEEDF_UNICODE_TEXT2; + ied.next = NULL; + CallService(streamData->dat->hwndIEView ? MS_IEVIEW_EVENT : MS_HPP_EG_EVENT, 0, (LPARAM)&event); + mir_free(buffer); +} + +*/ + +static int EventToIndex(LOGINFO * lin) +{ + switch (lin->iType) { + case GC_EVENT_MESSAGE: + if (lin->bIsMe) + return 10; + else + return 9; + + case GC_EVENT_JOIN: + return 3; + case GC_EVENT_PART: + return 4; + case GC_EVENT_QUIT: + return 5; + case GC_EVENT_NICK: + return 7; + case GC_EVENT_KICK: + return 6; + case GC_EVENT_NOTICE: + return 8; + case GC_EVENT_TOPIC: + return 11; + case GC_EVENT_INFORMATION: + return 12; + case GC_EVENT_ADDSTATUS: + return 13; + case GC_EVENT_REMOVESTATUS: + return 14; + case GC_EVENT_ACTION: + return 15; + } + return 0; +} + +static BYTE EventToSymbol(LOGINFO *lin) +{ + switch (lin->iType) { + case GC_EVENT_MESSAGE: + return (lin->bIsMe) ? 0x37 : 0x38; + case GC_EVENT_JOIN: + return 0x34; + case GC_EVENT_PART: + return 0x33; + case GC_EVENT_QUIT: + return 0x39; + case GC_EVENT_NICK: + return 0x71; + case GC_EVENT_KICK: + return 0x72; + case GC_EVENT_NOTICE: + return 0x28; + case GC_EVENT_INFORMATION: + return 0x69; + case GC_EVENT_ADDSTATUS: + return 0x35; + case GC_EVENT_REMOVESTATUS: + return 0x36; + case GC_EVENT_ACTION: + return 0x60; + } + return 0x73; +} + +static int EventToIcon(LOGINFO * lin) +{ + switch (lin->iType) { + case GC_EVENT_MESSAGE: + if (lin->bIsMe) + return ICON_MESSAGEOUT; + else + return ICON_MESSAGE; + + case GC_EVENT_JOIN: + return ICON_JOIN; + case GC_EVENT_PART: + return ICON_PART; + case GC_EVENT_QUIT: + return ICON_QUIT; + case GC_EVENT_NICK: + return ICON_NICK; + case GC_EVENT_KICK: + return ICON_KICK; + case GC_EVENT_NOTICE: + return ICON_NOTICE; + case GC_EVENT_TOPIC: + return ICON_TOPIC; + case GC_EVENT_INFORMATION: + return ICON_INFO; + case GC_EVENT_ADDSTATUS: + return ICON_ADDSTATUS; + case GC_EVENT_REMOVESTATUS: + return ICON_REMSTATUS; + case GC_EVENT_ACTION: + return ICON_ACTION; + } + return 0; +} + +/* replace pattern `ptrn' with the string `rplc' in string `src' points to */ +static TCHAR * _tcsrplc(TCHAR **src, const TCHAR *ptrn, const TCHAR *rplc) +{ + size_t lSrc, lPtrn, lRplc; + TCHAR *tszFound, *tszTail; + + lSrc = lstrlen(*src); + lPtrn = lstrlen(ptrn); + lRplc = lstrlen(rplc); + if (lPtrn && lSrc && lSrc >= lPtrn && (tszFound = _tcsstr(*src, ptrn)) != NULL) { + if (lRplc > lPtrn) + *src = (TCHAR *) realloc((void *) * src, + sizeof(TCHAR) * (lSrc + lRplc - lPtrn + 1)); + if (tszTail = (TCHAR *) malloc(sizeof(TCHAR) * + (lSrc - (tszFound - *src) - lPtrn + 1))) { + /* save tail */ + _tcscpy(tszTail, tszFound + lPtrn); + /* write replacement string */ + _tcscpy(tszFound, rplc); + /* write tail */ + _tcscpy(tszFound + lRplc, tszTail); + free((void *) tszTail); + } + } + return *src; +} + +/* + * replace pattern `ptrn' with the string `rplc' in string `src', + * `src' is supposed to be `n' character long (or no checking is done if n < 0). + * This function is useful for statically allocated buffers + */ +static TCHAR * _tcsnrplc(TCHAR *src, size_t n, const TCHAR *ptrn, const TCHAR *rplc) +{ + size_t lSrc, lPtrn, lRplc; + TCHAR *tszFound, *tszTail; + + lSrc = lstrlen(src); + lPtrn = lstrlen(ptrn); + lRplc = lstrlen(rplc); + if (lPtrn && lSrc && lSrc >= lPtrn && /* lengths are ok */ + (tszFound = _tcsstr(src, ptrn)) != NULL && /* pattern was found in string */ + (n < 0 || lSrc - lPtrn + lRplc < n) && /* there is enough room in the string */ + (tszTail = (TCHAR *) malloc(sizeof(TCHAR) * + (lSrc - (tszFound - src) - lPtrn + 1))) != NULL) { + /* save tail */ + _tcscpy(tszTail, tszFound + lPtrn); + /* write replacement string */ + _tcscpy(tszFound, rplc); + /* write tail */ + _tcscpy(tszFound + lRplc, tszTail); + free((void *) tszTail); + } + return src; +} + +static char *Log_SetStyle(int style, int fontindex) +{ + if (style < OPTIONS_FONTCOUNT) + return CHAT_rtffonts + (style * RTFCACHELINESIZE); + + return ""; +} + +static void Log_Append(char **buffer, int *cbBufferEnd, int *cbBufferAlloced, const char *fmt, ...) +{ + va_list va; + int charsDone = 0; + + va_start(va, fmt); + for (;;) { + charsDone = mir_vsnprintf(*buffer + *cbBufferEnd, *cbBufferAlloced - *cbBufferEnd, fmt, va); + if (charsDone >= 0) + break; + *cbBufferAlloced += 4096; + *buffer = (char *) mir_realloc(*buffer, *cbBufferAlloced); + } + va_end(va); + *cbBufferEnd += charsDone; +} + +static int Log_AppendRTF(LOGSTREAMDATA* streamData, BOOL simpleMode, char **buffer, int *cbBufferEnd, int *cbBufferAlloced, const TCHAR *fmt, ...) +{ + va_list va; + int lineLen, textCharsCount = 0; + TCHAR* line = (TCHAR*)alloca(8001 * sizeof(TCHAR)); + char* d; + + va_start(va, fmt); + lineLen = _vsntprintf(line, 8000, fmt, va); + if (lineLen < 0) lineLen = 8000; + line[lineLen] = 0; + va_end(va); + + lineLen = lineLen * 20 + 8; + if (*cbBufferEnd + lineLen > *cbBufferAlloced) { + cbBufferAlloced[0] += (lineLen + 1024 - lineLen % 1024); + if ((d = (char *) mir_realloc(*buffer, *cbBufferAlloced)) == 0) + return 0; + *buffer = d; + } + + d = *buffer + *cbBufferEnd; + + for (; *line; line++, textCharsCount++) { + if (*line == '\r' && line[1] == '\n') { + CopyMemory(d, "\\par ", 5); + line++; + d += 5; + } else if (*line == '\n') { + CopyMemory(d, "\\line ", 6); + d += 6; + } else if (*line == '%' && !simpleMode) { + char szTemp[200]; + + szTemp[0] = '\0'; + switch (*++line) { + case '\0': + case '%': + *d++ = '%'; + break; + + case 'c': + case 'f': + if (g_Settings.StripFormat || streamData->bStripFormat) + line += 2; + + else if (line[1] != '\0' && line[2] != '\0') { + TCHAR szTemp3[3], c = *line; + int col; + szTemp3[0] = line[1]; + szTemp3[1] = line[2]; + szTemp3[2] = '\0'; + line += 2; + + col = _ttoi(szTemp3); + col += (OPTIONS_FONTCOUNT + 1); + mir_snprintf(szTemp, SIZEOF(szTemp), (c == 'c') ? "\\cf%u " : "\\highlight%u ", col); + } + break; + case 'C': + case 'F': + if (!g_Settings.StripFormat && !streamData->bStripFormat) { + int j = streamData->lin->bIsHighlighted ? 16 : EventToIndex(streamData->lin); + if (*line == 'C') + mir_snprintf(szTemp, SIZEOF(szTemp), "\\cf%u ", j + 1); + else + mir_snprintf(szTemp, SIZEOF(szTemp), "\\highlight0 "); + } + break; + case 'b': + case 'u': + case 'i': + if (!streamData->bStripFormat) + mir_snprintf(szTemp, SIZEOF(szTemp), (*line == 'u') ? "\\%cl " : "\\%c ", *line); + break; + + case 'B': + case 'U': + case 'I': + if (!streamData->bStripFormat) { + mir_snprintf(szTemp, SIZEOF(szTemp), (*line == 'U') ? "\\%cl0 " : "\\%c0 ", *line); + CharLowerA(szTemp); + } + break; + + case 'r': + if (!streamData->bStripFormat) { + int index = EventToIndex(streamData->lin); + mir_snprintf(szTemp, SIZEOF(szTemp), "%s ", Log_SetStyle(index, index)); + } + break; + } + + if (szTemp[0]) { + int iLen = lstrlenA(szTemp); + memcpy(d, szTemp, iLen); + d += iLen; + } + } else if (*line == '\t' && !streamData->bStripFormat) { + CopyMemory(d, "\\tab ", 5); + d += 5; + } else if ((*line == '\\' || *line == '{' || *line == '}') && !streamData->bStripFormat) { + *d++ = '\\'; + *d++ = (char) * line; + } else if (*line > 0 && *line < 128) { + *d++ = (char) * line; + } + else d += sprintf(d, "\\u%u ?", (WORD) * line); + } + + *cbBufferEnd = (int)(d - *buffer); + return textCharsCount; +} + +static void AddEventToBuffer(char **buffer, int *bufferEnd, int *bufferAlloced, LOGSTREAMDATA *streamData) +{ + TCHAR szTemp[512], szTemp2[512]; + TCHAR* pszNick = NULL; + + if (streamData == NULL) + return; + + if (streamData->lin == NULL) + return; + + if (streamData->lin->ptszNick) { + if (g_Settings.LogLimitNames && lstrlen(streamData->lin->ptszNick) > 20) { + lstrcpyn(szTemp, streamData->lin->ptszNick, 20); + lstrcpyn(szTemp + 20, _T("..."), 4); + } else lstrcpyn(szTemp, streamData->lin->ptszNick, 511); + + if (g_Settings.ClickableNicks) + mir_sntprintf(szTemp2, SIZEOF(szTemp2), _T("~~++#%s#++~~"), szTemp); + else + _tcscpy(szTemp2, szTemp); + + if (streamData->lin->ptszUserInfo && streamData->lin->iType != GC_EVENT_TOPIC) + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s (%s)"), szTemp2, streamData->lin->ptszUserInfo); + else + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s"), szTemp2); + pszNick = szTemp; + } + + switch (streamData->lin->iType) { + case GC_EVENT_MESSAGE: + if (streamData->lin->ptszText) + Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), streamData->lin->ptszText); + break; + case GC_EVENT_ACTION: + if (streamData->lin->ptszNick && streamData->lin->ptszText) { + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, _T("%s "), streamData->lin->ptszNick); + Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), streamData->lin->ptszText); + } + break; + case GC_EVENT_JOIN: + if (pszNick) { + if (!streamData->lin->bIsMe) + /* replace nick of a newcomer with a link */ + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s has joined"), pszNick); + else + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("You have joined %s"), streamData->si->ptszName); + } + break; + case GC_EVENT_PART: + if (pszNick) + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s has left"), pszNick); + if (streamData->lin->ptszText) + Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T(": %s"), streamData->lin->ptszText); + break; + case GC_EVENT_QUIT: + if (pszNick) + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s has disconnected"), pszNick); + if (streamData->lin->ptszText) + Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T(": %s"), streamData->lin->ptszText); + break; + case GC_EVENT_NICK: + if (pszNick && streamData->lin->ptszText) { + if (!streamData->lin->bIsMe) + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s is now known as %s"), pszNick, streamData->lin->ptszText); + else + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("You are now known as %s"), streamData->lin->ptszText); + } + break; + case GC_EVENT_KICK: + if (pszNick && streamData->lin->ptszStatus) + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, + TranslateT("%s kicked %s"), streamData->lin->ptszStatus, pszNick); + + if (streamData->lin->ptszText) + Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T(": %s"), streamData->lin->ptszText); + break; + case GC_EVENT_NOTICE: + if (pszNick && streamData->lin->ptszText) { + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("Notice from %s: "), pszNick); + Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), streamData->lin->ptszText); + } + break; + case GC_EVENT_TOPIC: + if (streamData->lin->ptszText) + Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, TranslateT("The topic is \'%s%s\'"), streamData->lin->ptszText, _T("%r")); + if (pszNick) + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, + (streamData->lin->ptszUserInfo) ? TranslateT(" (set by %s on %s)") : + TranslateT(" (set by %s)"), + pszNick, streamData->lin->ptszUserInfo); + break; + case GC_EVENT_INFORMATION: + if (streamData->lin->ptszText) + Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, (streamData->lin->bIsMe) ? _T("--> %s") : _T("%s"), streamData->lin->ptszText); + break; + case GC_EVENT_ADDSTATUS: + if (pszNick && streamData->lin->ptszText && streamData->lin->ptszStatus) + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, + TranslateT("%s enables \'%s\' status for %s"), + streamData->lin->ptszText, streamData->lin->ptszStatus, pszNick); + break; + case GC_EVENT_REMOVESTATUS: + if (pszNick && streamData->lin->ptszText && streamData->lin->ptszStatus) { + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, + TranslateT("%s disables \'%s\' status for %s"), + streamData->lin->ptszText , streamData->lin->ptszStatus, pszNick); + } + break; + } +} + +TCHAR* MakeTimeStamp(TCHAR* pszStamp, time_t time) +{ + static TCHAR szTime[30]; + _tcsftime(szTime, 29, pszStamp, localtime(&time)); + return szTime; +} + +static char* Log_CreateRTF(LOGSTREAMDATA *streamData) +{ + char *buffer, *header; + int bufferAlloced, bufferEnd, i, me = 0; + LOGINFO * lin = streamData->lin; + MODULEINFO *mi = MM_FindModule(streamData->si->pszModule); + + // guesstimate amount of memory for the RTF + bufferEnd = 0; + bufferAlloced = streamData->bRedraw ? 2048 * (streamData->si->iEventCount + 2) : 2048; + buffer = (char *) mir_alloc(bufferAlloced); + buffer[0] = '\0'; + + // ### RTF HEADER + + if (0 == mi->pszHeader) + mi->pszHeader = Log_CreateRtfHeader(mi); + + header = mi->pszHeader; + streamData->crCount = mi->nColorCount; + + if (header) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, header); + + + // ### RTF BODY (one iteration per event that should be streamed in) + while (lin) { + // filter + if (streamData->si->iType != GCW_CHATROOM || !streamData->si->bFilterEnabled || (streamData->si->iLogFilterFlags&lin->iType) != 0) { + if (lin->next != NULL) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\par "); + + if (streamData->dat->dwFlags & MWF_DIVIDERWANTED || lin->dwFlags & MWF_DIVIDERWANTED) { + static char szStyle_div[128] = "\0"; + if (szStyle_div[0] == 0) + mir_snprintf(szStyle_div, 128, "\\f%u\\cf%u\\ul0\\b%d\\i%d\\fs%u", 17, 18, 0, 0, 5); + + lin->dwFlags |= MWF_DIVIDERWANTED; + if (lin->prev || !streamData->bRedraw) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\qc\\sl-1\\highlight%d %s ---------------------------------------------------------------------------------------\\par ", 18, szStyle_div); + streamData->dat->dwFlags &= ~MWF_DIVIDERWANTED; + } + // create new line, and set font and color + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\ql\\sl0%s ", Log_SetStyle(0, 0)); + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\v~-+%d+-~\\v0 ", lin); + + // Insert icon + if (g_Settings.LogSymbols) // use symbols + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s %c", Log_SetStyle(17, 17), EventToSymbol(lin)); + else if (g_Settings.dwIconFlags) { + int iIndex = lin->bIsHighlighted ? ICON_HIGHLIGHT : EventToIcon(lin); + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\f0\\fs14"); + while (bufferAlloced - bufferEnd < (logIconBmpSize[0] + 20)) + bufferAlloced += 4096; + buffer = (char *) mir_realloc(buffer, bufferAlloced); + CopyMemory(buffer + bufferEnd, pLogIconBmpBits[iIndex], logIconBmpSize[iIndex]); + bufferEnd += logIconBmpSize[iIndex]; + } + + if (g_Settings.TimeStampEventColour) { + // colored timestamps + static char szStyle[256]; + int iii; + if (lin->ptszNick && lin->iType == GC_EVENT_MESSAGE) { + iii = lin->bIsHighlighted ? 16 : (lin->bIsMe ? 2 : 1); + mir_snprintf(szStyle, SIZEOF(szStyle), "\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\ul%d\\fs%u", iii + 1, aFonts[0].lf.lfWeight >= FW_BOLD ? 1 : 0,aFonts[0].lf.lfItalic,aFonts[0].lf.lfUnderline, 2 * abs(aFonts[0].lf.lfHeight) * 74 / logPixelSY); + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s ", szStyle); + } else { + iii = lin->bIsHighlighted ? 16 : EventToIndex(lin); + mir_snprintf(szStyle, SIZEOF(szStyle), "\\f0\\cf%u\\ul0\\highlight0\\b%d\\i%d\\ul%d\\fs%u", iii + 1, aFonts[0].lf.lfWeight >= FW_BOLD ? 1 : 0, aFonts[0].lf.lfItalic,aFonts[0].lf.lfUnderline ,2 * abs(aFonts[0].lf.lfHeight) * 74 / logPixelSY); + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s ", szStyle); + } + } else + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s ", Log_SetStyle(0, 0)); + // insert a TAB if necessary to put the timestamp in the right position + if (g_Settings.dwIconFlags) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\tab "); + + //insert timestamp + if (g_Settings.ShowTime) { + TCHAR szTimeStamp[30], szOldTimeStamp[30]; + + lstrcpyn(szTimeStamp, MakeTimeStamp(g_Settings.pszTimeStamp, lin->time), 30); + lstrcpyn(szOldTimeStamp, MakeTimeStamp(g_Settings.pszTimeStamp, streamData->si->LastTime), 30); + if (!g_Settings.ShowTimeIfChanged || streamData->si->LastTime == 0 || lstrcmp(szTimeStamp, szOldTimeStamp)) { + streamData->si->LastTime = lin->time; + Log_AppendRTF(streamData, TRUE, &buffer, &bufferEnd, &bufferAlloced, _T("%s"), szTimeStamp); + } + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\tab "); + } + + // Insert the nick + if (lin->ptszNick && lin->iType == GC_EVENT_MESSAGE) { + TCHAR pszTemp[300], *p1; + STATUSINFO *ti; + char pszIndicator[3] = "\0\0"; + int crNickIndex = 0; + //mad + if (g_Settings.LogClassicIndicators/*g_Settings.ClassicIndicators */||g_Settings.ColorizeNicksInLog) { + USERINFO *ui = streamData->si->pUsers; + while (ui) { + if (!lstrcmp(ui->pszNick, lin->ptszNick)) { + ti = TM_FindStatus(streamData->si->pStatuses, TM_WordToString(streamData->si->pStatuses, ui->Status)); + if (ti && (int)ti->hIcon < streamData->si->iStatusCount) { + int id = streamData->si->iStatusCount - (int)ti->hIcon - 1; + switch (id) { + case 1: + pszIndicator[0] = '+'; + crNickIndex = 2; + break; + case 2: + pszIndicator[0] = '%'; + crNickIndex = 1; + break; + case 3: + pszIndicator[0] = '@'; + crNickIndex = 0; + break; + case 4: + pszIndicator[0] = '!'; + crNickIndex = 3; + break; + case 5: + pszIndicator[0] = '*'; + crNickIndex = 4; + break; + default: + pszIndicator[0] = 0; + } + } + break; + } + ui = ui->next; + } + } + + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s ", Log_SetStyle(lin->bIsMe ? 2 : 1, lin->bIsMe ? 2 : 1)); + //MAD + if (g_Settings.LogClassicIndicators /*g_Settings.ClassicIndicators*/) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s", pszIndicator); + + lstrcpyn(pszTemp, lin->bIsMe ? g_Settings.pszOutgoingNick : g_Settings.pszIncomingNick, 299); + p1 = _tcsstr(pszTemp, _T("%n")); + if (p1) + p1[1] = 's'; + + if (!lin->bIsMe) { + if (g_Settings.ClickableNicks) { + _tcsnrplc(pszTemp, 300, _T("%s"), _T("~~++#%s#++~~")); + pszTemp[299] = 0; + } + //Log_Append(&buffer, &bufferEnd, &bufferAlloced, "~~++#"); + if (g_Settings.ColorizeNicksInLog && pszIndicator[0]) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\cf%u ", OPTIONS_FONTCOUNT + streamData->crCount + crNickIndex + 1); + } + + Log_AppendRTF(streamData, TRUE, &buffer, &bufferEnd, &bufferAlloced, pszTemp, lin->ptszNick); + Log_Append(&buffer, &bufferEnd, &bufferAlloced, " "); + } + + // Insert the message + { + i = lin->bIsHighlighted ? 16 : EventToIndex(lin); + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "%s ", Log_SetStyle(i, i)); + streamData->lin = lin; + AddEventToBuffer(&buffer, &bufferEnd, &bufferAlloced, streamData); + } + } + lin = lin->prev; + } + + // ### RTF END + if (streamData->bRedraw) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\par}"); + else + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "}"); + return buffer; +} + +static DWORD CALLBACK Log_StreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb) +{ + LOGSTREAMDATA *lstrdat = (LOGSTREAMDATA *) dwCookie; + + if (lstrdat) { + // create the RTF + if (lstrdat->buffer == NULL) { + lstrdat->bufferOffset = 0; + lstrdat->buffer = Log_CreateRTF(lstrdat); + lstrdat->bufferLen = lstrlenA(lstrdat->buffer); + } + + // give the RTF to the RE control + *pcb = min(cb, lstrdat->bufferLen - lstrdat->bufferOffset); + CopyMemory(pbBuff, lstrdat->buffer + lstrdat->bufferOffset, *pcb); + lstrdat->bufferOffset += *pcb; + + // free stuff if the streaming operation is complete + if (lstrdat->bufferOffset == lstrdat->bufferLen) { + mir_free(lstrdat->buffer); + lstrdat->buffer = NULL; + } + } + + return 0; +} + +void Log_StreamInEvent(HWND hwndDlg, LOGINFO* lin, SESSION_INFO* si, BOOL bRedraw, BOOL bPhaseTwo) +{ + EDITSTREAM stream; + LOGSTREAMDATA streamData; + CHARRANGE oldsel, sel, newsel; + POINT point = {0}; + SCROLLINFO scroll; + WPARAM wp; + HWND hwndRich; + TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + if (hwndDlg == 0 || lin == 0 || si == 0 || dat == 0) + return; + + hwndRich = GetDlgItem(hwndDlg, IDC_CHAT_LOG); + ZeroMemory(&streamData, sizeof(LOGSTREAMDATA)); + streamData.hwnd = hwndRich; + streamData.si = si; + streamData.lin = lin; + streamData.bStripFormat = FALSE; + streamData.dat = dat; + + // bPhaseTwo = bRedraw && bPhaseTwo; + + if (bRedraw || si->iType != GCW_CHATROOM || !si->bFilterEnabled || (si->iLogFilterFlags&lin->iType) != 0) { + BOOL bFlag = FALSE, fDoReplace; + + ZeroMemory(&stream, sizeof(stream)); + stream.pfnCallback = Log_StreamCallback; + stream.dwCookie = (DWORD_PTR) & streamData; + scroll.cbSize = sizeof(SCROLLINFO); + scroll.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; + GetScrollInfo(GetDlgItem(hwndDlg, IDC_CHAT_LOG), SB_VERT, &scroll); + SendMessage(hwndRich, EM_GETSCROLLPOS, 0, (LPARAM) &point); + + // do not scroll to bottom if there is a selection + SendMessage(hwndRich, EM_EXGETSEL, 0, (LPARAM) &oldsel); + if (oldsel.cpMax != oldsel.cpMin) + SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0); + + //set the insertion point at the bottom + sel.cpMin = sel.cpMax = GetRichTextLength(hwndRich); + SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) & sel); + + // fix for the indent... must be a M$ bug + if (sel.cpMax == 0) + bRedraw = TRUE; + + // should the event(s) be appended to the current log + wp = bRedraw ? SF_RTF : SFF_SELECTION | SF_RTF; + + //get the number of pixels per logical inch + if (bRedraw) { + HDC hdc; + hdc = GetDC(NULL); + logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY); + logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX); + ReleaseDC(NULL, hdc); + SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0); + bFlag = TRUE; + // SetCursor(LoadCursor(NULL, IDC_ARROW)); + } + + // stream in the event(s) + streamData.lin = lin; + streamData.bRedraw = bRedraw; + SendMessage(hwndRich, EM_STREAMIN, wp, (LPARAM) & stream); + + + //SendMessage(hwndRich, EM_EXGETSEL, (WPARAM)0, (LPARAM)&newsel); + /* + * for new added events, only replace in message or action events. + * no need to replace smileys or math formulas elsewhere + */ + + fDoReplace = (bRedraw || (lin->ptszText + && (lin->iType == GC_EVENT_MESSAGE || lin->iType == GC_EVENT_ACTION))); + + + /* + * use mathmod to replace formulas + */ + if (g_Settings.MathMod && fDoReplace) { + TMathRicheditInfo mathReplaceInfo; + CHARRANGE mathNewSel; + mathNewSel.cpMin = sel.cpMin; + + if (mathNewSel.cpMin < 0) + mathNewSel.cpMin = 0; + + mathNewSel.cpMax = -1; + + mathReplaceInfo.hwndRichEditControl = hwndRich; + + if (!bRedraw) + mathReplaceInfo.sel = &mathNewSel; + else + mathReplaceInfo.sel = 0; + + mathReplaceInfo.disableredraw = TRUE; + CallService(MATH_RTF_REPLACE_FORMULAE, 0, (LPARAM)&mathReplaceInfo); + bFlag = TRUE; + } + + /* + * replace marked nicknames with hyperlinks to make the nicks + * clickable + */ + + if (g_Settings.ClickableNicks) { + CHARFORMAT2 cf2; + FINDTEXTEX fi, fi2; + + ZeroMemory(&cf2, sizeof(CHARFORMAT2)); + fi2.lpstrText = _T("#++~~"); + fi.chrg.cpMin = bRedraw ? 0 : sel.cpMin; + fi.chrg.cpMax = -1; + fi.lpstrText = _T("~~++#"); + cf2.cbSize = sizeof(cf2); + + while (SendMessage(hwndRich, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) > -1) { + fi2.chrg.cpMin = fi.chrgText.cpMin; + fi2.chrg.cpMax = -1; + + if (SendMessage(hwndRich, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi2) > -1) { + + SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&fi.chrgText); + SendMessage(hwndRich, EM_REPLACESEL, TRUE, (LPARAM)_T("")); + fi2.chrgText.cpMin -= fi.chrgText.cpMax - fi.chrgText.cpMin; + fi2.chrgText.cpMax -= fi.chrgText.cpMax - fi.chrgText.cpMin; + SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&fi2.chrgText); + SendMessage(hwndRich, EM_REPLACESEL, TRUE, (LPARAM)_T("")); + fi2.chrgText.cpMax = fi2.chrgText.cpMin; + + fi2.chrgText.cpMin = fi.chrgText.cpMin; + SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM)&fi2.chrgText); + cf2.dwMask = CFM_PROTECTED; + cf2.dwEffects = CFE_PROTECTED; + SendMessage(hwndRich, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2); + } + fi.chrg.cpMin = fi.chrgText.cpMax; + } + SendMessage(hwndRich, EM_SETSEL, -1, -1); + } + + + /* + * run smileyadd + */ + if (PluginConfig.g_SmileyAddAvail && fDoReplace) { + SMADD_RICHEDIT3 sm = {0}; + + newsel.cpMax = -1; + newsel.cpMin = sel.cpMin; + if (newsel.cpMin < 0) + newsel.cpMin = 0; + ZeroMemory(&sm, sizeof(sm)); + sm.cbSize = sizeof(sm); + sm.hwndRichEditControl = hwndRich; + sm.Protocolname = si->pszModule; + sm.rangeToReplace = bRedraw ? NULL : &newsel; + sm.disableRedraw = TRUE; + sm.hContact = si->hContact; + CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm); + } + + /* + * trim the message log to the number of most recent events + * this uses hidden marks in the rich text to find the events which should be deleted + */ + + + if (si->wasTrimmed) { + TCHAR szPattern[50]; + FINDTEXTEX fi; + + mir_sntprintf(szPattern, SIZEOF(szPattern), _T("~-+%d+-~"), si->pLogEnd); + fi.lpstrText = szPattern; + fi.chrg.cpMin = 0; + fi.chrg.cpMax = -1; + if (SendMessage(hwndRich, EM_FINDTEXTEX, FR_DOWN, (LPARAM)&fi) != 0) { + CHARRANGE sel; + sel.cpMin = 0; + sel.cpMax = 20; + SendMessage(hwndRich, EM_SETSEL, 0, fi.chrgText.cpMax + 1); + SendMessage(hwndRich, EM_REPLACESEL, TRUE, (LPARAM)_T("")); + } + si->wasTrimmed = FALSE; + } + + // scroll log to bottom if the log was previously scrolled to bottom, else restore old position + if ((bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50)) + SendMessage(GetParent(hwndRich), GC_SCROLLTOBOTTOM, 0, 0); + else + SendMessage(hwndRich, EM_SETSCROLLPOS, 0, (LPARAM) &point); + + // do we need to restore the selection + if (oldsel.cpMax != oldsel.cpMin) { + SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) & oldsel); + SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0); + InvalidateRect(hwndRich, NULL, TRUE); + } + + // need to invalidate the window + if (bFlag) { + sel.cpMin = sel.cpMax = GetRichTextLength(hwndRich); + SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) & sel); + SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0); + InvalidateRect(hwndRich, NULL, TRUE); + } + } +} + +char * Log_CreateRtfHeader(MODULEINFO * mi) +{ + char *buffer; + int bufferAlloced, bufferEnd, i = 0; + + // guesstimate amount of memory for the RTF header + bufferEnd = 0; + bufferAlloced = 4096; + buffer = (char *) mir_realloc(mi->pszHeader, bufferAlloced); + buffer[0] = '\0'; + + + //get the number of pixels per logical inch + if (logPixelSY == 0) { + HDC hdc; + hdc = GetDC(NULL); + logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY); + logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX); + ReleaseDC(NULL, hdc); + } + + // ### RTF HEADER + + // font table + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "{\\rtf1\\ansi\\deff0{\\fonttbl"); + for (i=0; i < OPTIONS_FONTCOUNT ; i++) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "{\\f%u\\fnil\\fcharset%u" TCHAR_STR_PARAM ";}", i, aFonts[i].lf.lfCharSet, aFonts[i].lf.lfFaceName); + + // colour table + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "}{\\colortbl ;"); + + for (i=0; i < OPTIONS_FONTCOUNT; i++) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(aFonts[i].color), GetGValue(aFonts[i].color), GetBValue(aFonts[i].color)); + + for (i=0; i < mi->nColorCount; i++) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(mi->crColors[i]), GetGValue(mi->crColors[i]), GetBValue(mi->crColors[i])); + + for (i=0; i < 5; i++) + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(g_Settings.nickColors[i]), GetGValue(g_Settings.nickColors[i]), GetBValue(g_Settings.nickColors[i])); + + // new paragraph + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "}\\pard\\sl%d", 1000); + + // set tabs and indents + { + int iIndent = 0; + + if (g_Settings.LogSymbols) { + TCHAR szString[2]; + LOGFONT lf; + HFONT hFont; + int iText; + + szString[1] = 0; + szString[0] = 0x28; + LoadMsgDlgFont(FONTSECTION_CHAT, 17, &lf, NULL, CHAT_FONTMODULE); + hFont = CreateFontIndirect(&lf); + iText = GetTextPixelSize(szString, hFont, TRUE) + 3; + DeleteObject(hFont); + iIndent += (iText * 1440) / logPixelSX; + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\tx%u", iIndent); + } else if (g_Settings.dwIconFlags) { + iIndent += ((g_Settings.ScaleIcons ? 14 : 20) * 1440) / logPixelSX; + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\tx%u", iIndent); + } + if (g_Settings.ShowTime) { + int iSize = (g_Settings.LogTextIndent * 1440) / logPixelSX; + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\tx%u", iIndent + iSize); + if (g_Settings.LogIndentEnabled) + iIndent += iSize; + } + Log_Append(&buffer, &bufferEnd, &bufferAlloced, "\\fi-%u\\li%u", iIndent, iIndent); + } + return buffer; +} + +#define RTFPICTHEADERMAXSIZE 78 +void LoadMsgLogBitmaps(void) +{ + HICON hIcon; + HBITMAP hBmp, hoBmp; + HDC hdc, hdcMem; + BITMAPINFOHEADER bih = { 0 }; + int widthBytes, i; + RECT rc; + HBRUSH hBkgBrush; + int rtfHeaderSize; + PBYTE pBmpBits; + int iIconSize; + int sizeX = 0, sizeY = 0; + + if (hIcons[0]) + Utils::getIconSize(hIcons[0], sizeX, sizeY); + else + sizeX = 16; + + if (sizeX >= 12) + iIconSize = g_Settings.ScaleIcons ? 12 : 16; + else + iIconSize = sizeX; + + hBkgBrush = CreateSolidBrush(M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR_MUC, SRMSGDEFSET_BKGCOLOUR)); + bih.biSize = sizeof(bih); + bih.biBitCount = 24; + bih.biCompression = BI_RGB; + bih.biHeight = iIconSize; + bih.biPlanes = 1; + bih.biWidth = iIconSize; + widthBytes = ((bih.biWidth * bih.biBitCount + 31) >> 5) * 4; + rc.top = rc.left = 0; + rc.right = iIconSize; + rc.bottom = iIconSize; + hdc = GetDC(NULL); + hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight); + hdcMem = CreateCompatibleDC(hdc); + pBmpBits = (PBYTE) mir_alloc(widthBytes * bih.biHeight); + for (i=0; i < SIZEOF(pLogIconBmpBits); i++) { + hIcon = hIcons[i]; + pLogIconBmpBits[i] = (PBYTE) mir_alloc(RTFPICTHEADERMAXSIZE + (bih.biSize + widthBytes * bih.biHeight) * 2); + rtfHeaderSize = sprintf((char *)pLogIconBmpBits[i], "{\\pict\\dibitmap0\\wbmbitspixel%u\\wbmplanes1\\wbmwidthbytes%u\\picw%u\\pich%u ", bih.biBitCount, widthBytes, bih.biWidth, bih.biHeight); + hoBmp = (HBITMAP) SelectObject(hdcMem, hBmp); + FillRect(hdcMem, &rc, hBkgBrush); + DrawIconEx(hdcMem, 0, 1, hIcon, iIconSize, iIconSize, 0, NULL, DI_NORMAL); + + SelectObject(hdcMem, hoBmp); + GetDIBits(hdc, hBmp, 0, bih.biHeight, pBmpBits, (BITMAPINFO *) & bih, DIB_RGB_COLORS); + { + int n; + for (n = 0; n < sizeof(BITMAPINFOHEADER); n++) + sprintf((char *)pLogIconBmpBits[i] + rtfHeaderSize + n * 2, "%02X", ((PBYTE) & bih)[n]); + for (n = 0; n < widthBytes * bih.biHeight; n += 4) + sprintf((char *)pLogIconBmpBits[i] + rtfHeaderSize + (bih.biSize + n) * 2, "%02X%02X%02X%02X", pBmpBits[n], pBmpBits[n + 1], pBmpBits[n + 2], pBmpBits[n + 3]); + } + logIconBmpSize[i] = rtfHeaderSize + (bih.biSize + widthBytes * bih.biHeight) * 2 + 1; + pLogIconBmpBits[i][logIconBmpSize[i] - 1] = '}'; + } + mir_free(pBmpBits); + DeleteDC(hdcMem); + DeleteObject(hBmp); + ReleaseDC(NULL, hdc); + DeleteObject(hBkgBrush); + + /* cache RTF font headers */ + + //get the number of pixels per logical inch + if (logPixelSY == 0) { + HDC hdc; + hdc = GetDC(NULL); + logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY); + logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX); + ReleaseDC(NULL, hdc); + } + + for (i=0; i < OPTIONS_FONTCOUNT; i++) + mir_snprintf(CHAT_rtfFontsGlobal[i], RTFCACHELINESIZE, "\\f%u\\cf%u\\ul0\\highlight0\\b%d\\i%d\\ul%d\\fs%u", i, i + 1, aFonts[i].lf.lfWeight >= FW_BOLD ? 1 : 0, aFonts[i].lf.lfItalic,aFonts[i].lf.lfUnderline ,2 * abs(aFonts[i].lf.lfHeight) * 74 / logPixelSY); + CHAT_rtffonts = &(CHAT_rtfFontsGlobal[0][0]); +} + +void FreeMsgLogBitmaps(void) +{ + int i; + for (i=0; i < SIZEOF(pLogIconBmpBits); i++) + mir_free(pLogIconBmpBits[i]); +} diff --git a/plugins/TabSRMM/src/chat/main.cpp b/plugins/TabSRMM/src/chat/main.cpp new file mode 100644 index 0000000000..56489a2fc9 --- /dev/null +++ b/plugins/TabSRMM/src/chat/main.cpp @@ -0,0 +1,142 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * This code is based on and still contains large parts of the the + * original chat module for Miranda NG, written and copyrighted + * by Joergen Persson in 2005. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: main.cpp 13132 2010-11-17 03:47:44Z silvercircle $ + * + * chat module exports and functions to load/unload the plugin. + * + */ + +#include "..\commonheaders.h" + +HANDLE g_hWindowList; +HMENU g_hMenu = NULL; + +FONTINFO aFonts[OPTIONS_FONTCOUNT]; +HICON hIcons[30]; +HBRUSH hListBkgBrush = NULL; + +TMUCSettings g_Settings; + +TCHAR *pszActiveWndID = 0; +char *pszActiveWndModule = 0; + +/* + * load the group chat module + */ + +int Chat_Load() +{ + if (M->GetByte("forceDisableMUC", 0)) { + PluginConfig.m_chat_enabled = false; + return 0; + } + g_hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENU)); + if (CreateServiceFunctions()) { + HookEvents(); + CreateHookableEvents(); + OptionsInit(); + } + return 0; +} + +/* + * unload the module. final cleanup + */ + +int Chat_Unload(void) +{ + if (!PluginConfig.m_chat_enabled) + return 0; + + DBWriteContactSettingWord(NULL, "Chat", "SplitterX", (WORD)g_Settings.iSplitterX); + DBWriteContactSettingWord(NULL, "Chat", "splitY", (WORD)g_Settings.iSplitterY); + + CList_SetAllOffline(TRUE, NULL); + + mir_free(pszActiveWndID); + mir_free(pszActiveWndModule); + + DestroyMenu(g_hMenu); + DestroyServiceFunctions(); + DestroyHookableEvents(); + FreeIcons(); + OptionsUnInit(); + UnhookEvents(); + return 0; +} + +void LoadLogIcons(void) +{ + ZeroMemory(hIcons, sizeof(HICON) * (ICON_STATUS5 - ICON_ACTION)); + hIcons[ICON_ACTION] = LoadIconEx(IDI_ACTION, "log_action", 16, 16); + hIcons[ICON_ADDSTATUS] = LoadIconEx(IDI_ADDSTATUS, "log_addstatus", 16, 16); + hIcons[ICON_HIGHLIGHT] = LoadIconEx(IDI_HIGHLIGHT, "log_highlight", 16, 16); + hIcons[ICON_INFO] = LoadIconEx(IDI_INFO, "log_info", 16, 16); + hIcons[ICON_JOIN] = LoadIconEx(IDI_JOIN, "log_join", 16, 16); + hIcons[ICON_KICK] = LoadIconEx(IDI_KICK, "log_kick", 16, 16); + hIcons[ICON_MESSAGE] = LoadIconEx(IDI_MESSAGE, "log_message_in", 16, 16); + hIcons[ICON_MESSAGEOUT] = LoadIconEx(IDI_MESSAGEOUT, "log_message_out", 16, 16); + hIcons[ICON_NICK] = LoadIconEx(IDI_NICK, "log_nick", 16, 16); + hIcons[ICON_NOTICE] = LoadIconEx(IDI_NOTICE, "log_notice", 16, 16); + hIcons[ICON_PART] = LoadIconEx(IDI_PART, "log_part", 16, 16); + hIcons[ICON_QUIT] = LoadIconEx(IDI_QUIT, "log_quit", 16, 16); + hIcons[ICON_REMSTATUS] = LoadIconEx(IDI_REMSTATUS, "log_removestatus", 16, 16); + hIcons[ICON_TOPIC] = LoadIconEx(IDI_TOPIC, "log_topic", 16, 16); + hIcons[ICON_STATUS1] = LoadIconEx(IDI_STATUS1, "status1", 16, 16); + hIcons[ICON_STATUS2] = LoadIconEx(IDI_STATUS2, "status2", 16, 16); + hIcons[ICON_STATUS3] = LoadIconEx(IDI_STATUS3, "status3", 16, 16); + hIcons[ICON_STATUS4] = LoadIconEx(IDI_STATUS4, "status4", 16, 16); + hIcons[ICON_STATUS0] = LoadIconEx(IDI_STATUS0, "status0", 16, 16); + hIcons[ICON_STATUS5] = LoadIconEx(IDI_STATUS5, "status5", 16, 16); + + return; +} + +void LoadIcons(void) +{ + int i; + + for (i=0; i < 20; i++) + hIcons[i] = NULL; + + LoadLogIcons(); + g_Settings.hIconOverlay = LoadIconEx(IDI_OVERLAY, "overlay", 16, 16); + LoadMsgLogBitmaps(); + return ; +} + +void FreeIcons(void) +{ + FreeMsgLogBitmaps(); + return; +} diff --git a/plugins/TabSRMM/src/chat/manager.cpp b/plugins/TabSRMM/src/chat/manager.cpp new file mode 100644 index 0000000000..0dfa59a470 --- /dev/null +++ b/plugins/TabSRMM/src/chat/manager.cpp @@ -0,0 +1,1544 @@ +/* +astyle --force-indent=tab=4 --brackets=linux --indent-switches + --pad=oper --one-line=keep-blocks --unpad=paren + +Chat module plugin for Miranda NG + +Copyright (C) 2003 Jörgen Persson + +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. + +$Id: manager.cpp 14208 2012-03-26 13:56:42Z silvercircle $ +*/ + +#include "..\commonheaders.h" + +extern TCHAR *pszActiveWndID ; +extern char *pszActiveWndModule ; +extern HICON hIcons[30]; + +#define WINDOWS_COMMANDS_MAX 30 +#define STATUSICONCOUNT 6 + +SESSION_INFO *m_WndList = 0; +MODULEINFO *m_ModList = 0; + +extern CRITICAL_SECTION cs; + +void SetActiveSession(const TCHAR* pszID, const char* pszModule) +{ + SESSION_INFO* si = SM_FindSession(pszID, pszModule); + if (si) + SetActiveSessionEx(si); +} + +void SetActiveSessionEx(SESSION_INFO* si) +{ + if (si) { + replaceStr(&pszActiveWndID, si->ptszID); + replaceStrA(&pszActiveWndModule, si->pszModule); + } +} + +SESSION_INFO* GetActiveSession(void) +{ + SESSION_INFO* si = SM_FindSession(pszActiveWndID, pszActiveWndModule); + if (si) + return si; + + return m_WndList; +} + +//--------------------------------------------------- +// Session Manager functions +// +// Keeps track of all sessions and its windows +//--------------------------------------------------- + +SESSION_INFO* SM_AddSession(const TCHAR* pszID, const char* pszModule) +{ + if (!pszID || !pszModule) + return NULL; + + if (!SM_FindSession(pszID, pszModule)) { + SESSION_INFO*node = (SESSION_INFO*) mir_alloc(sizeof(SESSION_INFO)); + ZeroMemory(node, sizeof(SESSION_INFO)); + node->ptszID = mir_tstrdup(pszID); + node->pszModule = mir_strdup(pszModule); + + MODULEINFO *mi = MM_FindModule(pszModule); + + if (mi) { + mi->idleTimeStamp = time(0); + SM_BroadcastMessage(pszModule, GC_UPDATESTATUSBAR, 0, 1, TRUE); + } + + if (m_WndList == NULL) { // list is empty + m_WndList = node; + node->next = NULL; + } else { + node->next = m_WndList; + m_WndList = node; + } + node->Highlight = g_Settings.Highlight; + return node; + } + return NULL; +} + +int SM_RemoveSession(const TCHAR* pszID, const char* pszModule, bool removeContact) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID && pTemp->iType != GCW_SERVER || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { // match + COMMAND_INFO *pCurComm; + DWORD dw = pTemp->dwItemData; + + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_EVENT_CONTROL + WM_USER + 500, SESSION_TERMINATE, 0); + + DoEventHook(pTemp->ptszID, pTemp->pszModule, GC_SESSION_TERMINATE, NULL, NULL, (DWORD)pTemp->dwItemData); + + if (pLast == NULL) + m_WndList = pTemp->next; + else + pLast->next = pTemp->next; + + UM_RemoveAll(&pTemp->pUsers); + TM_RemoveAll(&pTemp->pStatuses); + LM_RemoveAll(&pTemp->pLog, &pTemp->pLogEnd); + pTemp->iStatusCount = 0; + pTemp->nUsersInNicklist = 0; + + if (pTemp->hContact) { + CList_SetOffline(pTemp->hContact, pTemp->iType == GCW_CHATROOM ? TRUE : FALSE); + //if (pTemp->iType != GCW_SERVER) + //DBWriteContactSettingByte(pTemp->hContact, "CList", "Hidden", 1); + } + DBWriteContactSettingString(pTemp->hContact, pTemp->pszModule , "Topic", ""); + DBWriteContactSettingString(pTemp->hContact, pTemp->pszModule, "StatusBar", ""); + DBDeleteContactSetting(pTemp->hContact, "CList", "StatusMsg"); + + if (removeContact) + CallService(MS_DB_CONTACT_DELETE, (WPARAM)pTemp->hContact, 0); + + mir_free(pTemp->pszModule); + mir_free(pTemp->ptszID); + mir_free(pTemp->ptszName); + mir_free(pTemp->ptszStatusbarText); + mir_free(pTemp->ptszTopic); + mir_free(pTemp->pszID); + mir_free(pTemp->pszName); + + // delete commands + pCurComm = pTemp->lpCommands; + while (pCurComm != NULL) { + COMMAND_INFO *pNext = pCurComm->next; + mir_free(pCurComm->lpCommand); + mir_free(pCurComm); + pCurComm = pNext; + } + + mir_free(pTemp); + if (pszID) + return (int)dw; + if (pLast) + pTemp = pLast->next; + else + pTemp = m_WndList; + } else { + pLast = pTemp; + pTemp = pTemp->next; + } + } + return FALSE; +} + +SESSION_INFO* SM_FindSession(const TCHAR* pszID, const char* pszModule) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) + return pTemp; + + pLast = pTemp; + pTemp = pTemp->next; + } + return NULL; +} + +BOOL SM_SetOffline(const TCHAR* pszID, const char* pszModule) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + UM_RemoveAll(&pTemp->pUsers); + pTemp->nUsersInNicklist = 0; + if (pTemp->iType != GCW_SERVER) + pTemp->bInitDone = FALSE; + + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +BOOL SM_SetStatusEx(const TCHAR* pszID, const char* pszModule, const TCHAR* pszText, int flags) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + UM_SetStatusEx(pTemp->pUsers, pszText, flags); + if (pTemp->hWnd) + RedrawWindow(GetDlgItem(pTemp->hWnd, IDC_LIST), NULL, NULL, RDW_INVALIDATE); + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +HICON SM_GetStatusIcon(SESSION_INFO* si, USERINFO* ui, char *szIndicator) +{ + STATUSINFO * ti; + if (!ui || !si) + return NULL; + + *szIndicator = 0; + + ti = TM_FindStatus(si->pStatuses, TM_WordToString(si->pStatuses, ui->Status)); + if (ti) { + if ((INT_PTR)ti->hIcon < STATUSICONCOUNT) { + int id = si->iStatusCount - (int)ti->hIcon - 1; + if (id == 0) { + *szIndicator = 0; + return hIcons[ICON_STATUS0]; + } + if (id == 1) { + *szIndicator = '+'; + return hIcons[ICON_STATUS1]; + } + if (id == 2) { + *szIndicator = '%'; + return hIcons[ICON_STATUS2]; + } + if (id == 3) { + *szIndicator = '@'; + return hIcons[ICON_STATUS3]; + } + if (id == 4) { + *szIndicator = '!'; + return hIcons[ICON_STATUS4]; + } + if (id == 5) { + *szIndicator = '*'; + return hIcons[ICON_STATUS5]; + } + } else + return ti->hIcon; + } + return hIcons[ICON_STATUS0]; +} + +BOOL SM_AddEventToAllMatchingUID(GCEVENT * gce, BOOL bIsHighLight) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + int bManyFix = 0; + + while (pTemp != NULL) { + if (!lstrcmpiA(pTemp->pszModule, gce->pDest->pszModule)) { + if (UM_FindUser(pTemp->pUsers, gce->ptszUID)) { + if (pTemp->bInitDone) { + if (SM_AddEvent(pTemp->ptszID, pTemp->pszModule, gce, FALSE) && pTemp->hWnd && pTemp->bInitDone) { + SendMessage(pTemp->hWnd, GC_ADDLOG, 0, 0); + } else if (pTemp->hWnd && pTemp->bInitDone) { + SendMessage(pTemp->hWnd, GC_REDRAWLOG2, 0, 0); + } + DoSoundsFlashPopupTrayStuff(pTemp, gce, bIsHighLight, bManyFix); + bManyFix ++; + if ((gce->dwFlags & GCEF_ADDTOLOG) && g_Settings.LoggingEnabled) + LogToFile(pTemp, gce); + } + } + } + + pLast = pTemp; + pTemp = pTemp->next; + } + + return 0; +} + +BOOL SM_AddEvent(const TCHAR* pszID, const char* pszModule, GCEVENT * gce, BOOL bIsHighlighted) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return TRUE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + LOGINFO * li = LM_AddEvent(&pTemp->pLog, &pTemp->pLogEnd); + pTemp->iEventCount += 1; + + li->iType = gce->pDest->iType; + li->ptszNick = mir_tstrdup(gce->ptszNick); + li->ptszText = mir_tstrdup(gce->ptszText); + li->ptszStatus = mir_tstrdup(gce->ptszStatus); + li->ptszUserInfo = mir_tstrdup(gce->ptszUserInfo); + + li->bIsMe = gce->bIsMe; + li->time = gce->time; + li->bIsHighlighted = bIsHighlighted; + + if (g_Settings.iEventLimit > 0 && pTemp->iEventCount > g_Settings.iEventLimit + g_Settings.iEventLimitThreshold) { + LM_TrimLog(&pTemp->pLog, &pTemp->pLogEnd, pTemp->iEventCount - g_Settings.iEventLimit); + pTemp->wasTrimmed = TRUE; + pTemp->iEventCount = g_Settings.iEventLimit; + } + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +USERINFO * SM_AddUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO * p = UM_AddUser(pTemp->pStatuses, &pTemp->pUsers, pszUID, pszNick, wStatus); + pTemp->nUsersInNicklist++; + return p; + } + pLast = pTemp; + pTemp = pTemp->next; + } + + return 0; +} + +BOOL SM_MoveUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID) +{ + SESSION_INFO* pTemp = m_WndList; + + if (!pszID || !pszModule || !pszUID) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + UM_SortUser(&pTemp->pUsers, pszUID); + return TRUE; + } + pTemp = pTemp->next; + } + + return FALSE; +} + +BOOL SM_RemoveUser(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszModule || !pszUID) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + DWORD dw; + USERINFO * ui = UM_FindUser(pTemp->pUsers, pszUID); + if (ui) { + pTemp->nUsersInNicklist--; + + dw = UM_RemoveUser(&pTemp->pUsers, pszUID); + + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0); + + if (pszID) + return TRUE; + } + } + + pLast = pTemp; + pTemp = pTemp->next; + } + + return 0; +} + +USERINFO * SM_GetUserFromIndex(const TCHAR* pszID, const char* pszModule, int index) +{ + SESSION_INFO* pTemp = m_WndList; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) + return UM_FindUserFromIndex(pTemp->pUsers, index); + pTemp = pTemp->next; + } + + return NULL; +} + + +STATUSINFO * SM_AddStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszStatus) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + STATUSINFO* ti = TM_AddStatus(&pTemp->pStatuses, pszStatus, &pTemp->iStatusCount); + if (ti) + pTemp->iStatusCount++; + return ti; + } + pLast = pTemp; + pTemp = pTemp->next; + } + + return 0; +} + +BOOL SM_GiveStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszStatus) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO * ui = UM_GiveStatus(pTemp->pUsers, pszUID, TM_StringToWord(pTemp->pStatuses, pszStatus)); + if (ui) { + SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID); + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0); + } + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + + return FALSE; +} + +BOOL SM_SetContactStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, WORD wStatus) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO * ui = UM_SetContactStatus(pTemp->pUsers, pszUID, wStatus); + if (ui) { + SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID); + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0); + } + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + + return FALSE; +} + +BOOL SM_TakeStatus(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszStatus) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO* ui = UM_TakeStatus(pTemp->pUsers, pszUID, TM_StringToWord(pTemp->pStatuses, pszStatus)); + if (ui) { + SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID); + if (pTemp->hWnd) + SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0); + } + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + + return FALSE; +} +LRESULT SM_SendMessage(const TCHAR* pszID, const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + while (pTemp && pszModule) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + if (pTemp->hWnd) { + LRESULT i = SendMessage(pTemp->hWnd, msg, wParam, lParam); + if (pszID) + return i; + } + if (pszID) + return 0; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +BOOL SM_PostMessage(const TCHAR* pszID, const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszID || !pszModule) + return 0; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->ptszID, pszID) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + if (pTemp->hWnd) + return PostMessage(pTemp->hWnd, msg, wParam, lParam); + + return FALSE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return FALSE; +} + +BOOL SM_BroadcastMessage(const char* pszModule, UINT msg, WPARAM wParam, LPARAM lParam, BOOL bAsync) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + while (pTemp != NULL) { + if (!pszModule || !lstrcmpiA(pTemp->pszModule, pszModule)) { + if (pTemp->hWnd) { + if (bAsync) + PostMessage(pTemp->hWnd, msg, wParam, lParam); + else + SendMessage(pTemp->hWnd, msg, wParam, lParam); + } + + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +BOOL SM_ReconfigureFilters() +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + while (pTemp != NULL) { + Chat_SetFilters(pTemp); + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +BOOL SM_InvalidateLogDirectories() +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + EnterCriticalSection(&cs); + + while (pTemp != NULL) { + pTemp->pszLogFileName[0] = 0; + pLast = pTemp; + pTemp = pTemp->next; + } + + LeaveCriticalSection(&cs); + return TRUE; +} + +BOOL SM_SetStatus(const TCHAR* pszID, const char* pszModule, int wStatus) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + pTemp->wStatus = wStatus; + + if (pTemp->hContact) { + if (pTemp->iType != GCW_SERVER && wStatus != ID_STATUS_OFFLINE) + DBDeleteContactSetting(pTemp->hContact, "CList", "Hidden"); + + DBWriteContactSettingWord(pTemp->hContact, pTemp->pszModule, "Status", (WORD)wStatus); + } + + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +BOOL SM_SendUserMessage(const TCHAR* pszID, const char* pszModule, const TCHAR* pszText) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszModule || !pszText) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + if (pTemp->iType == GCW_CHATROOM) + DoEventHook(pTemp->ptszID, pTemp->pszModule, GC_USER_MESSAGE, NULL, pszText, (LPARAM)NULL); + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +BOOL SM_ChangeUID(const TCHAR* pszID, const char* pszModule, const TCHAR* pszUID, const TCHAR* pszNewUID) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO* ui = UM_FindUser(pTemp->pUsers, pszUID); + if (ui) + replaceStr(&ui->pszUID, pszNewUID); + + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +BOOL SM_ChangeNick(const TCHAR* pszID, const char* pszModule, GCEVENT * gce) +{ + SESSION_INFO* pTemp = m_WndList, *pLast = NULL; + + if (!pszModule) + return FALSE; + + while (pTemp != NULL) { + if ((!pszID || !lstrcmpi(pTemp->ptszID, pszID)) && !lstrcmpiA(pTemp->pszModule, pszModule)) { + USERINFO* ui = UM_FindUser(pTemp->pUsers, gce->ptszUID); + if (ui) { + replaceStr(&ui->pszNick, gce->ptszText); + SM_MoveUser(pTemp->ptszID, pTemp->pszModule, ui->pszUID); + if (pTemp->hWnd) { + SendMessage(pTemp->hWnd, GC_UPDATENICKLIST, 0, 0); + if (pTemp->dat) + GetMyNick(pTemp->dat); + SendMessage(pTemp->hWnd, GC_UPDATESTATUSBAR, 0, 0); + } + } + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} +BOOL SM_RemoveAll(void) +{ + while (m_WndList) { + SESSION_INFO*pLast = m_WndList->next; + + if (m_WndList->hWnd) + SendMessage(m_WndList->hWnd, GC_EVENT_CONTROL + WM_USER + 500, SESSION_TERMINATE, 0); + DoEventHook(m_WndList->ptszID, m_WndList->pszModule, GC_SESSION_TERMINATE, NULL, NULL, (DWORD)m_WndList->dwItemData); + if (m_WndList->hContact) + CList_SetOffline(m_WndList->hContact, m_WndList->iType == GCW_CHATROOM ? TRUE : FALSE); + DBWriteContactSettingString(m_WndList->hContact, m_WndList->pszModule , "Topic", ""); + DBDeleteContactSetting(m_WndList->hContact, "CList", "StatusMsg"); + DBWriteContactSettingString(m_WndList->hContact, m_WndList->pszModule, "StatusBar", ""); + + UM_RemoveAll(&m_WndList->pUsers); + TM_RemoveAll(&m_WndList->pStatuses); + LM_RemoveAll(&m_WndList->pLog, &m_WndList->pLogEnd); + m_WndList->iStatusCount = 0; + m_WndList->nUsersInNicklist = 0; + + mir_free(m_WndList->pszModule); + mir_free(m_WndList->ptszID); + mir_free(m_WndList->ptszName); + mir_free(m_WndList->ptszStatusbarText); + mir_free(m_WndList->ptszTopic); + + while (m_WndList->lpCommands != NULL) { + COMMAND_INFO *pNext = m_WndList->lpCommands->next; + mir_free(m_WndList->lpCommands->lpCommand); + mir_free(m_WndList->lpCommands); + m_WndList->lpCommands = pNext; + } + + mir_free(m_WndList); + m_WndList = pLast; + } + m_WndList = NULL; + return TRUE; +} + +void SM_AddCommand(const TCHAR* pszID, const char* pszModule, const char* lpNewCommand) +{ + SESSION_INFO* pTemp = m_WndList; + while (pTemp != NULL) { + if (lstrcmpi(pTemp->ptszID, pszID) == 0 && lstrcmpiA(pTemp->pszModule, pszModule) == 0) { // match + COMMAND_INFO *node = (COMMAND_INFO *)mir_alloc(sizeof(COMMAND_INFO)); + node->lpCommand = mir_strdup(lpNewCommand); + node->last = NULL; // always added at beginning! + // new commands are added at start + if (pTemp->lpCommands == NULL) { + node->next = NULL; + pTemp->lpCommands = node; + } else { + node->next = pTemp->lpCommands; + pTemp->lpCommands->last = node; // hmm, weird + pTemp->lpCommands = node; + } + pTemp->lpCurrentCommand = NULL; // current command + pTemp->wCommandsNum++; + + if (pTemp->wCommandsNum > WINDOWS_COMMANDS_MAX) { + COMMAND_INFO *pCurComm = pTemp->lpCommands; + COMMAND_INFO *pLast; + while (pCurComm->next != NULL) { + pCurComm = pCurComm->next; + } + pLast = pCurComm->last; + mir_free(pCurComm->lpCommand); + mir_free(pCurComm); + pLast->next = NULL; + // done + pTemp->wCommandsNum--; + } + } + pTemp = pTemp->next; + } +} + +char* SM_GetPrevCommand(const TCHAR* pszID, const char* pszModule) // get previous command. returns NULL if previous command does not exist. current command remains as it was. +{ + SESSION_INFO* pTemp = m_WndList; + while (pTemp != NULL) { + if (lstrcmpi(pTemp->ptszID, pszID) == 0 && lstrcmpiA(pTemp->pszModule, pszModule) == 0) { // match + COMMAND_INFO *pPrevCmd = NULL; + if (pTemp->lpCurrentCommand != NULL) { + if (pTemp->lpCurrentCommand->next != NULL) // not NULL + pPrevCmd = pTemp->lpCurrentCommand->next; // next command (newest at beginning) + else + pPrevCmd = pTemp->lpCurrentCommand; + } else pPrevCmd = pTemp->lpCommands; + + pTemp->lpCurrentCommand = pPrevCmd; // make it the new command + return(((pPrevCmd) ? (pPrevCmd->lpCommand) : (NULL))); + } + pTemp = pTemp->next; + } + return(NULL); +} + +char* SM_GetNextCommand(const TCHAR* pszID, const char* pszModule) // get next command. returns NULL if next command does not exist. current command becomes NULL (a prev command after this one will get you the last command) +{ + SESSION_INFO* pTemp = m_WndList; + while (pTemp != NULL) { + if (lstrcmpi(pTemp->ptszID, pszID) == 0 && lstrcmpiA(pTemp->pszModule, pszModule) == 0) { // match + COMMAND_INFO *pNextCmd = NULL; + if (pTemp->lpCurrentCommand != NULL) + pNextCmd = pTemp->lpCurrentCommand->last; // last command (newest at beginning) + + pTemp->lpCurrentCommand = pNextCmd; // make it the new command + return(((pNextCmd) ? (pNextCmd->lpCommand) : (NULL))); + } + pTemp = pTemp->next; + } + return(NULL); +} + +int SM_GetCount(const char* pszModule) +{ + SESSION_INFO* pTemp = m_WndList; + int count = 0; + + while (pTemp != NULL) { + if (!lstrcmpiA(pszModule, pTemp->pszModule)) + count++; + + pTemp = pTemp->next; + } + return count; +} + +SESSION_INFO* SM_FindSessionByHWND(HWND hWnd) +{ + SESSION_INFO *pTemp = m_WndList; + + while (pTemp) { + if (pTemp->hWnd == hWnd) + return pTemp; + pTemp = pTemp->next; + } + return NULL; +} + +SESSION_INFO * SM_FindSessionByHCONTACT(HANDLE h) +{ + SESSION_INFO *pTemp = m_WndList; + + while (pTemp) { + if (pTemp->hContact == h) + return pTemp; + pTemp = pTemp->next; + } + return NULL; +} + +SESSION_INFO* SM_FindSessionByIndex(const char* pszModule, int iItem) +{ + SESSION_INFO* pTemp = m_WndList; + int count = 0; + while (pTemp != NULL) { + if (!lstrcmpiA(pszModule, pTemp->pszModule)) { + if (iItem == count) + return pTemp; + else + count++; + } + + pTemp = pTemp->next; + } + return NULL; + +} + +SESSION_INFO* SM_FindSessionAutoComplete(const char* pszModule, SESSION_INFO* currSession, SESSION_INFO* prevSession, const TCHAR* pszOriginal, const TCHAR* pszCurrent) +{ + SESSION_INFO* pResult = NULL; + if (prevSession == NULL && my_strstri(currSession->ptszName, pszOriginal) == currSession->ptszName) { + pResult = currSession; + } else { + TCHAR* pszName = NULL; + SESSION_INFO* pTemp = m_WndList; + if (currSession == prevSession) { + pszCurrent = pszOriginal; + } + while (pTemp != NULL) { + if (pTemp != currSession && !lstrcmpiA(pszModule, pTemp->pszModule)) { + if (my_strstri(pTemp->ptszName, pszOriginal) == pTemp->ptszName) { + if (prevSession != pTemp && lstrcmpi(pTemp->ptszName, pszCurrent) > 0 && (!pszName || lstrcmpi(pTemp->ptszName, pszName) < 0)) { + pResult = pTemp; + pszName = pTemp->ptszName; + } + } + } + pTemp = pTemp->next; + } + } + return pResult; + +} + +char* SM_GetUsers(SESSION_INFO* si) +{ + SESSION_INFO* pTemp = m_WndList; + USERINFO* utemp; + int count = 0; + char* p = NULL; + int alloced = 0; + + if (si == NULL) + return NULL; + + while (pTemp != NULL) { + if (si == pTemp) { + if ((utemp = pTemp->pUsers) == NULL) + return NULL; + + break; + } + pTemp = pTemp->next; + } + + do { + int pLen = lstrlenA(p), nameLen = lstrlen(utemp->pszUID); + if (pLen + nameLen + 2 > alloced) + p = (char *)mir_realloc(p, alloced += 4096); + WideCharToMultiByte(CP_ACP, 0, utemp->pszUID, -1, p + pLen, nameLen + 1, 0, 0); + lstrcpyA(p + pLen + nameLen, " "); + utemp = utemp->next; + } while (utemp != NULL); + return p; +} + + + + + + +//--------------------------------------------------- +// Module Manager functions +// +// Necessary to keep track of all modules +// that has registered with the plugin +//--------------------------------------------------- + +MODULEINFO* MM_AddModule(const char* pszModule) +{ + if (!pszModule) + return NULL; + if (!MM_FindModule(pszModule)) { + MODULEINFO *node = (MODULEINFO*) mir_alloc(sizeof(MODULEINFO)); + ZeroMemory(node, sizeof(MODULEINFO)); + + node->pszModule = (char*)mir_alloc(lstrlenA(pszModule) + 1); + lstrcpyA(node->pszModule, pszModule); + node->idleTimeStamp = time(0); + if (m_ModList == NULL) { // list is empty + m_ModList = node; + node->next = NULL; + } else { + node->next = m_ModList; + m_ModList = node; + } + return node; + } + return FALSE; +} + +/* +void MM_IconsChanged(void) +{ + MODULEINFO *pTemp = m_ModList, *pLast = NULL; + while (pTemp != NULL) { + if (pTemp->hOfflineIcon) + DestroyIcon(pTemp->hOfflineIcon); + if (pTemp->hOnlineIcon) + DestroyIcon(pTemp->hOnlineIcon); + if (pTemp->hOnlineTalkIcon) + DestroyIcon(pTemp->hOnlineTalkIcon); + if (pTemp->hOfflineTalkIcon) + DestroyIcon(pTemp->hOfflineTalkIcon); + + pTemp->hOfflineIcon = ImageList_GetIcon(hIconsList, pTemp->OfflineIconIndex, ILD_TRANSPARENT); + pTemp->hOnlineIcon = ImageList_GetIcon(hIconsList, pTemp->OnlineIconIndex, ILD_TRANSPARENT); + + pTemp->hOnlineTalkIcon = ImageList_GetIcon(hIconsList, pTemp->OnlineIconIndex, ILD_TRANSPARENT|INDEXTOOVERLAYMASK(1)); + ImageList_ReplaceIcon(hIconsList, pTemp->OnlineIconIndex+1, pTemp->hOnlineTalkIcon); + + pTemp->hOfflineTalkIcon = ImageList_GetIcon(hIconsList, pTemp->OfflineIconIndex, ILD_TRANSPARENT|INDEXTOOVERLAYMASK(1)); + ImageList_ReplaceIcon(hIconsList, pTemp->OfflineIconIndex+1, pTemp->hOfflineTalkIcon); + + pLast = pTemp; + pTemp = pTemp->next; + } + return; +} +*/ + +void MM_FontsChanged(void) +{ + MODULEINFO *pTemp = m_ModList; + while (pTemp != NULL) { + pTemp->pszHeader = Log_CreateRtfHeader(pTemp); + pTemp = pTemp->next; + } + return; +} +MODULEINFO* MM_FindModule(const char* pszModule) +{ + MODULEINFO *pTemp = m_ModList, *pLast = NULL; + + if (!pszModule) + return NULL; + + while (pTemp != NULL) { + if (lstrcmpiA(pTemp->pszModule, pszModule) == 0) + return pTemp; + + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +// stupid thing.. +void MM_FixColors() +{ + MODULEINFO *pTemp = m_ModList; + + while (pTemp != NULL) { + CheckColorsInModule(pTemp->pszModule); + pTemp = pTemp->next; + } + return; +} + +BOOL MM_RemoveAll(void) +{ + while (m_ModList != NULL) { + MODULEINFO *pLast = m_ModList->next; + mir_free(m_ModList->pszModule); + mir_free(m_ModList->ptszModDispName); + if (m_ModList->pszHeader) + mir_free(m_ModList->pszHeader); + mir_free(m_ModList->crColors); + + mir_free(m_ModList); + m_ModList = pLast; + } + m_ModList = NULL; + return TRUE; +} + +//--------------------------------------------------- +// Status manager functions +// +// Necessary to keep track of what user statuses +// per window nicklist that is available +//--------------------------------------------------- + +STATUSINFO * TM_AddStatus(STATUSINFO** ppStatusList, const TCHAR* pszStatus, int* iCount) +{ + if (!ppStatusList || !pszStatus) + return NULL; + + if (!TM_FindStatus(*ppStatusList, pszStatus)) { + STATUSINFO *node = (STATUSINFO*) mir_alloc(sizeof(STATUSINFO)); + ZeroMemory(node, sizeof(STATUSINFO)); + replaceStr(&node->pszGroup, pszStatus); + node->hIcon = (HICON)(*iCount); + while ((int)node->hIcon > STATUSICONCOUNT - 1) + node->hIcon--; + + if (*ppStatusList == NULL) { // list is empty + node->Status = 1; + *ppStatusList = node; + node->next = NULL; + } else { + node->Status = ppStatusList[0]->Status * 2; + node->next = *ppStatusList; + *ppStatusList = node; + } + return node; + + } + return FALSE; +} + +STATUSINFO * TM_FindStatus(STATUSINFO* pStatusList, const TCHAR* pszStatus) +{ + STATUSINFO *pTemp = pStatusList, *pLast = NULL; + + if (!pStatusList || !pszStatus) + return NULL; + + while (pTemp != NULL) { + if (lstrcmpi(pTemp->pszGroup, pszStatus) == 0) + return pTemp; + + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +WORD TM_StringToWord(STATUSINFO* pStatusList, const TCHAR* pszStatus) +{ + STATUSINFO *pTemp = pStatusList, *pLast = NULL; + + if (!pStatusList || !pszStatus) + return 0; + + while (pTemp != NULL) { + if (lstrcmpi(pTemp->pszGroup, pszStatus) == 0) + return pTemp->Status; + + if (pTemp->next == NULL) + return pStatusList->Status; + + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +TCHAR* TM_WordToString(STATUSINFO* pStatusList, WORD Status) +{ + STATUSINFO *pTemp = pStatusList, *pLast = NULL; + + if (!pStatusList) + return NULL; + + while (pTemp != NULL) { + if (pTemp->Status&Status) { + Status -= pTemp->Status; + if (Status == 0) + return pTemp->pszGroup; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +BOOL TM_RemoveAll(STATUSINFO** ppStatusList) +{ + + if (!ppStatusList) + return FALSE; + + while (*ppStatusList != NULL) { + STATUSINFO *pLast = ppStatusList[0]->next; + mir_free(ppStatusList[0]->pszGroup); + if ((int)ppStatusList[0]->hIcon > 10) + DestroyIcon(ppStatusList[0]->hIcon); + mir_free(*ppStatusList); + *ppStatusList = pLast; + } + *ppStatusList = NULL; + return TRUE; +} + +//--------------------------------------------------- +// User manager functions +// +// Necessary to keep track of the users +// in a window nicklist +//--------------------------------------------------- + +//MAD: alternative sorting by Nullbie +static int sttCompareNicknames(const TCHAR *s1, const TCHAR *s2) +{ + // skip rubbish + while (*s1 && !_istalpha(*s1)) ++s1; + while (*s2 && !_istalpha(*s2)) ++s2; + + // are there ~0veRy^kEwL_n1kz? + if (!*s1 && !*s2) return 0; + if (!*s1 && *s2) return +1; + if (*s1 && !*s2) return -1; + + // compare tails + return lstrcmpi(s1, s2); +} +// + +static int UM_CompareItem(USERINFO * u1, const TCHAR* pszNick, WORD wStatus) +{ + int i; + + WORD dw1 = u1->Status; + WORD dw2 = wStatus; + + for (i=0; i < 8; i++) { + if ((dw1 & 1) && !(dw2 & 1)) + return -1; + if ((dw2 & 1) && !(dw1 & 1)) + return 1; + if ((dw1 & 1) && (dw2 & 1)) + // + { + if (g_Settings.AlternativeSorting) + return sttCompareNicknames(u1->pszNick, pszNick); + else + return lstrcmp(u1->pszNick, pszNick); + }// + dw1 = dw1 >> 1; + dw2 = dw2 >> 1; + } + if (g_Settings.AlternativeSorting) + // + return sttCompareNicknames(u1->pszNick, pszNick); + else + return lstrcmp(u1->pszNick, pszNick); + // +} + +USERINFO * UM_SortUser(USERINFO** ppUserList, const TCHAR* pszUID) +{ + USERINFO * pTemp = *ppUserList, *pLast = NULL; + USERINFO * node = NULL; + + if (!pTemp || !pszUID) + return NULL; + + while (pTemp && lstrcmpi(pTemp->pszUID, pszUID)) { + pLast = pTemp; + pTemp = pTemp->next; + } + + if (pTemp) { + node = pTemp; + if (pLast) + pLast->next = pTemp->next; + else + *ppUserList = pTemp->next; + pTemp = *ppUserList; + + pLast = NULL; + + while (pTemp && UM_CompareItem(pTemp, node->pszNick, node->Status) <= 0) { + pLast = pTemp; + pTemp = pTemp->next; + } + + if (*ppUserList == NULL) { // list is empty + *ppUserList = node; + node->next = NULL; + } else { + if (pLast) { + node->next = pTemp; + pLast->next = node; + } else { + node->next = *ppUserList; + *ppUserList = node; + } + } + + return node; + } + return NULL; +} + +USERINFO* UM_AddUser(STATUSINFO* pStatusList, USERINFO** ppUserList, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus) +{ + USERINFO * pTemp = *ppUserList, *pLast = NULL; + + if (!pStatusList || !ppUserList || !ppUserList) + return NULL; + + while (pTemp && UM_CompareItem(pTemp, pszNick, wStatus) <= 0) { + pLast = pTemp; + pTemp = pTemp->next; + } + + // if (!UM_FindUser(*ppUserList, pszUI, wStatus) + { + USERINFO *node = (USERINFO*) mir_alloc(sizeof(USERINFO)); + ZeroMemory(node, sizeof(USERINFO)); + replaceStr(&node->pszUID, pszUID); + + if (*ppUserList == NULL) { // list is empty + *ppUserList = node; + node->next = NULL; + } else { + if (pLast) { + node->next = pTemp; + pLast->next = node; + } else { + node->next = *ppUserList; + *ppUserList = node; + } + } + + return node; + } + return NULL; +} + +USERINFO* UM_FindUser(USERINFO* pUserList, const TCHAR* pszUID) +{ + USERINFO *pTemp = pUserList, *pLast = NULL; + + if (!pUserList || !pszUID) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->pszUID, pszUID)) + return pTemp; + + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +USERINFO* UM_FindUserFromIndex(USERINFO* pUserList, int index) +{ + int i = 0; + USERINFO *pTemp = pUserList; + + if (!pUserList) + return NULL; + + while (pTemp != NULL) { + if (i == index) { + return pTemp; + } + pTemp = pTemp->next; + i++; + } + return NULL; +} + +USERINFO* UM_GiveStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status) +{ + USERINFO *pTemp = pUserList, *pLast = NULL; + + if (!pUserList || !pszUID) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->pszUID, pszUID)) { + pTemp->Status |= status; + return pTemp; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +USERINFO* UM_SetContactStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status) +{ + USERINFO *pTemp = pUserList, *pLast = NULL; + + if (!pUserList || !pszUID) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->pszUID, pszUID)) { + pTemp->ContactStatus = status; + return pTemp; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +BOOL UM_SetStatusEx(USERINFO* pUserList, const TCHAR* pszText, int flags) +{ + USERINFO *pTemp = pUserList, *pLast = NULL; + int bOnlyMe = (flags & GC_SSE_ONLYLISTED) != 0, bSetStatus = (flags & GC_SSE_ONLINE) != 0; + char cDelimiter = (flags & GC_SSE_TABDELIMITED) ? '\t' : ' '; + + while (pTemp != NULL) { + if (!bOnlyMe) + pTemp->iStatusEx = 0; + + if (pszText != NULL) { + TCHAR* s = (TCHAR *)_tcsstr(pszText, pTemp->pszUID); + if (s) { + pTemp->iStatusEx = 0; + if (s == pszText || s[-1] == cDelimiter) { + int len = lstrlen(pTemp->pszUID); + if (s[len] == cDelimiter || s[len] == '\0') + pTemp->iStatusEx = (!bOnlyMe || bSetStatus) ? 1 : 0; + } + } + } + + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +USERINFO* UM_TakeStatus(USERINFO* pUserList, const TCHAR* pszUID, WORD status) +{ + USERINFO *pTemp = pUserList, *pLast = NULL; + + if (!pUserList || !pszUID) + return NULL; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->pszUID, pszUID)) { + pTemp->Status &= ~status; + return pTemp; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return 0; +} + +TCHAR* UM_FindUserAutoComplete(USERINFO* pUserList, const TCHAR* pszOriginal, const TCHAR* pszCurrent) +{ + TCHAR* pszName = NULL; + USERINFO *pTemp = pUserList; + + if (!pUserList || !pszOriginal || !pszCurrent) + return NULL; + + while (pTemp != NULL) { + if (my_strstri(pTemp->pszNick, pszOriginal) == pTemp->pszNick) + if (lstrcmpi(pTemp->pszNick, pszCurrent) > 0 && (!pszName || lstrcmpi(pTemp->pszNick, pszName) < 0)) + pszName = pTemp->pszNick; + + pTemp = pTemp->next; + } + return pszName; +} + +BOOL UM_RemoveUser(USERINFO** ppUserList, const TCHAR* pszUID) +{ + USERINFO *pTemp = *ppUserList, *pLast = NULL; + + if (!ppUserList || !pszUID) + return FALSE; + + while (pTemp != NULL) { + if (!lstrcmpi(pTemp->pszUID, pszUID)) { + if (pLast == NULL) + *ppUserList = pTemp->next; + else + pLast->next = pTemp->next; + mir_free(pTemp->pszNick); + mir_free(pTemp->pszUID); + mir_free(pTemp); + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return FALSE; +} + +BOOL UM_RemoveAll(USERINFO** ppUserList) +{ + if (!ppUserList) + return FALSE; + + while (*ppUserList != NULL) { + USERINFO *pLast = ppUserList[0]->next; + mir_free(ppUserList[0]->pszUID); + mir_free(ppUserList[0]->pszNick); + mir_free(*ppUserList); + *ppUserList = pLast; + } + *ppUserList = NULL; + return TRUE; +} + +//--------------------------------------------------- +// Log manager functions +// +// Necessary to keep track of events +// in a window log +//--------------------------------------------------- + +LOGINFO * LM_AddEvent(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd) +{ + + LOGINFO *node = NULL; + + if (!ppLogListStart || !ppLogListEnd) + return NULL; + + node = (LOGINFO*) mir_alloc(sizeof(LOGINFO)); + ZeroMemory(node, sizeof(LOGINFO)); + + + if (*ppLogListStart == NULL) { // list is empty + *ppLogListStart = node; + *ppLogListEnd = node; + node->next = NULL; + node->prev = NULL; + } else { + ppLogListStart[0]->prev = node; + node->next = *ppLogListStart; + *ppLogListStart = node; + ppLogListStart[0]->prev = NULL; + } + + return node; +} + +BOOL LM_TrimLog(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd, int iCount) +{ + LOGINFO *pTemp = *ppLogListEnd; + while (pTemp != NULL && iCount > 0) { + *ppLogListEnd = pTemp->prev; + if (*ppLogListEnd == NULL) + *ppLogListStart = NULL; + + mir_free(pTemp->ptszNick); + mir_free(pTemp->ptszUserInfo); + mir_free(pTemp->ptszText); + mir_free(pTemp->ptszStatus); + mir_free(pTemp); + pTemp = *ppLogListEnd; + iCount--; + } + ppLogListEnd[0]->next = NULL; + + return TRUE; +} + +BOOL LM_RemoveAll(LOGINFO** ppLogListStart, LOGINFO** ppLogListEnd) +{ + while (*ppLogListStart != NULL) { + LOGINFO *pLast = ppLogListStart[0]->next; + mir_free(ppLogListStart[0]->ptszText); + mir_free(ppLogListStart[0]->ptszNick); + mir_free(ppLogListStart[0]->ptszStatus); + mir_free(ppLogListStart[0]->ptszUserInfo); + mir_free(*ppLogListStart); + *ppLogListStart = pLast; + } + *ppLogListStart = NULL; + *ppLogListEnd = NULL; + return TRUE; +} diff --git a/plugins/TabSRMM/src/chat/message.cpp b/plugins/TabSRMM/src/chat/message.cpp new file mode 100644 index 0000000000..71fbba7276 --- /dev/null +++ b/plugins/TabSRMM/src/chat/message.cpp @@ -0,0 +1,341 @@ +/* +astyle --force-indent=tab=4 --brackets=linux --indent-switches + --pad=oper --one-line=keep-blocks --unpad=paren + +Chat module plugin for Miranda NG + +Copyright (C) 2003 Jörgen Persson + +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. + +$Id: message.c 10402 2009-07-24 00:35:21Z silvercircle $ +*/ + +#include "..\commonheaders.h" +#include + +static int RTFColorToIndex(int *pIndex, int iCol, SESSION_INFO* si) +{ + int i; + MODULEINFO * pMod = MM_FindModule(si->pszModule); + + for (i=0; i < pMod->nColorCount ; i++) + if (pIndex[i] == iCol) + return i; + + return -1; +} + +static void CreateColorMap(char* Text, int *pIndex, SESSION_INFO* si) +{ + char *p1, *p2, *pEnd; + int iIndex = 1; + + static const char* lpszFmt = "\\red%[^ \x5b\\]\\green%[^ \x5b\\]\\blue%[^ \x5b;];"; + char szRed[10], szGreen[10], szBlue[10]; + + p1 = strstr(Text, "\\colortbl"); + if (!p1) + return; + + pEnd = strchr(p1, '}'); + p2 = strstr(p1, "\\red"); + + while (p2 && p2 < pEnd) { + if (sscanf(p2, lpszFmt, &szRed, &szGreen, &szBlue) > 0) { + int i; + MODULEINFO * pMod = MM_FindModule(si->pszModule); + for (i=0; i < pMod->nColorCount ; i ++) + if (pMod->crColors[i] == RGB(atoi(szRed), atoi(szGreen), atoi(szBlue))) + pIndex[i] = iIndex; + } + iIndex++; + p1 = p2; + p1 ++; + p2 = strstr(p1, "\\red"); + } +} + +static int ReadInteger(const char* p, int* result) +{ + char temp[10]; + int i = 0; + while (isdigit(*p) && i < 9) + temp[i++] = *p++; + temp[i] = 0; + + if (result != NULL) + *result = atoi(temp); + + return i; +} + +TCHAR* Chat_DoRtfToTags(char* pszText, SESSION_INFO* si) +{ + char *p1; + int* pIndex; + int i, iRemoveChars, cp = CP_ACP; + char InsertThis[50]; + BOOL bJustRemovedRTF = TRUE; + BOOL bTextHasStarted = FALSE; + TCHAR *ptszResult; //, *d; + int iUcMode = 0; + + if (!pszText) + return FALSE; + + // create an index of colors in the module and map them to + // corresponding colors in the RTF color table + pIndex = (int *)mir_alloc(sizeof(int) * MM_FindModule(si->pszModule)->nColorCount); + for (i=0; i < MM_FindModule(si->pszModule)->nColorCount ; i++) + pIndex[i] = -1; + + CreateColorMap(pszText, pIndex, si); + + // scan the file for rtf commands and remove or parse them + p1 = strstr(pszText, "\\pard"); + if (p1 == NULL) { + mir_free(pIndex); + return FALSE; + } + + p1 += 5; + + MoveMemory(pszText, p1, lstrlenA(p1) + 1); + p1 = pszText; + + // iterate through all characters, if rtf control character found then take action + while (*p1 != '\0') { + InsertThis[0] = 0; + iRemoveChars = 0; + + switch (*p1) { + case '\\': + if (!memcmp(p1, "\\cf", 3)) { // foreground color + int iCol, iInd; + iRemoveChars = 3 + ReadInteger(p1 + 3, &iCol); + iInd = RTFColorToIndex(pIndex, iCol, si); + bJustRemovedRTF = TRUE; + + if (bTextHasStarted || iInd >= 0) + mir_snprintf(InsertThis, SIZEOF(InsertThis), (iInd >= 0) ? "%%c%02u" : "%%C", iInd); + } else if (!memcmp(p1, "\\highlight", 10)) { //background color + int iCol, iInd; + iRemoveChars = 10 + ReadInteger(p1 + 10, &iCol); + iInd = RTFColorToIndex(pIndex, iCol, si); + bJustRemovedRTF = TRUE; + + if (bTextHasStarted || iInd >= 0) + mir_snprintf(InsertThis, SIZEOF(InsertThis), (iInd >= 0) ? "%%f%02u" : "%%F", iInd); + } else if (!memcmp(p1, "\\lang", 5)) { // language id + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = 5 + ReadInteger(p1 + 5, NULL); + } else if (!memcmp(p1, "\\par", 4)) { // newline + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = 4; + strcpy(InsertThis, "\n"); + } else if (!memcmp(p1, "\\endash", 7)) { + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = 7; + strcpy(InsertThis, "\xE2\x80\x93"); + } else if (!memcmp(p1, "\\emdash", 7)) { + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = 7; + strcpy(InsertThis, "\xE2\x80\x94"); + } else if (!memcmp(p1, "\\bullet", 7)) { + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = 7; + strcpy(InsertThis, "\xE2\x80\xA2"); + } else if (!memcmp(p1, "\\line", 5)) { // newline + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = 5; + strcpy(InsertThis, "\n"); + } else if (!memcmp(p1, "\\b", 2)) { //bold + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = (p1[2] != '0') ? 2 : 3; + strcpy(InsertThis, (p1[2] != '0') ? "%b" : "%B"); + } else if (!memcmp(p1, "\\i", 2)) { // italics + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = (p1[2] != '0') ? 2 : 3; + strcpy(InsertThis, (p1[2] != '0') ? "%i" : "%I"); + } else if (!memcmp(p1, "\\uc", 3)) { // number of Unicode chars + bTextHasStarted = bJustRemovedRTF = TRUE; + iUcMode = p1[3] - '0'; + iRemoveChars = 4; + } else if (!memcmp(p1, "\\ul", 3)) { // underlined + bTextHasStarted = bJustRemovedRTF = TRUE; + if (p1[3] == 'n') + iRemoveChars = 7; + else if (p1[3] == '0') + iRemoveChars = 4; + else + iRemoveChars = 3; + mir_snprintf(InsertThis, SIZEOF(InsertThis), (p1[3] != '0' && p1[3] != 'n') ? "%%u" : "%%U"); + } else if (p1[1] == 'f' && isdigit(p1[2])) { // unicode char + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = 2 + ReadInteger(p1 + 2, NULL); + } else if (p1[1] == '\\' || p1[1] == '{' || p1[1] == '}') { // escaped characters + bTextHasStarted = TRUE; + bJustRemovedRTF = FALSE; + iRemoveChars = 2; + mir_snprintf(InsertThis, SIZEOF(InsertThis), "%c", p1[1]); + } else if (p1[1] == '~') { // non-breaking space + bTextHasStarted = TRUE; + bJustRemovedRTF = FALSE; + iRemoveChars = 2; + strcpy(InsertThis, "\xC2\xA0"); + } + + + else if (!memcmp(p1, "\\tab",4)) { // tab + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 4; + strcpy(InsertThis, "\x09"); + } + else if (!memcmp(p1, "\\ldblquote",10)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 10; + strcpy(InsertThis, "\xe2\x80\x9c"); + } + else if (!memcmp(p1, "\\rdblquote",10)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 10; + strcpy(InsertThis, "\xe2\x80\x9d"); + } + else if (!memcmp(p1, "\\lquote",7)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; + strcpy(InsertThis, "\xE2\x80\x98"); + } + else if (!memcmp(p1, "\\rquote",7)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; + strcpy(InsertThis, "\xE2\x80\x99"); + } + + else if (p1[1] == '\'') { // special character + char tmp[4], *p3 = tmp; + bTextHasStarted = TRUE; + bJustRemovedRTF = FALSE; + if (p1[2] != ' ' && p1[2] != '\\') { + *p3++ = p1[2]; + iRemoveChars = 3; + if (p1[3] != ' ' && p1[3] != '\\') { + *p3++ = p1[3]; + iRemoveChars++; + } + *p3 = 0; + sscanf(tmp, "%x", InsertThis); + + InsertThis[1] = 0; + } else iRemoveChars = 2; + } else if (bJustRemovedRTF) { // remove unknown RTF command + int j = 1; + bJustRemovedRTF = TRUE; + while (p1[j] != ' ' && p1[j] != '\\' && p1[j] != '\0') + j++; + iRemoveChars = j; + } + break; + + case '{': // other RTF control characters + case '}': + iRemoveChars = 1; + break; + + case '\r': case '\n': + bTextHasStarted = TRUE; + bJustRemovedRTF = FALSE; + iRemoveChars = 1; + break; + + case '%': // escape chat -> protocol control character + bTextHasStarted = TRUE; + bJustRemovedRTF = FALSE; + iRemoveChars = 1; + strcpy(InsertThis, "%%"); + break; + case ' ': // 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 (InsertThis[0] || iRemoveChars) { + MoveMemory(p1 + lstrlenA(InsertThis) , p1 + iRemoveChars, lstrlenA(p1) - iRemoveChars + 1); + CopyMemory(p1, InsertThis, lstrlenA(InsertThis)); + p1 += lstrlenA(InsertThis); + } else p1++; + } + + mir_free(pIndex); + ptszResult = mir_utf8decodeW(pszText); + return ptszResult; +} + +static DWORD CALLBACK Chat_Message_StreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb) +{ + static DWORD dwRead; + char ** ppText = (char **) dwCookie; + + if (*ppText == NULL) { + *ppText = (char *)mir_alloc(cb + 1); + memcpy(*ppText, pbBuff, cb); + (*ppText)[cb] = 0; + *pcb = cb; + dwRead = cb; + } else { + char *p = (char *)mir_alloc(dwRead + cb + 1); + memcpy(p, *ppText, dwRead); + memcpy(p + dwRead, pbBuff, cb); + p[dwRead + cb] = 0; + mir_free(*ppText); + *ppText = p; + *pcb = cb; + dwRead += cb; + } + return 0; +} + +char* Chat_Message_GetFromStream(HWND hwndDlg, SESSION_INFO* si) +{ + EDITSTREAM stream; + char* pszText = NULL; + DWORD dwFlags; + + if (hwndDlg == 0 || si == 0) + return NULL; + + ZeroMemory(&stream, sizeof(stream)); + stream.pfnCallback = Chat_Message_StreamCallback; + stream.dwCookie = (DWORD_PTR) & pszText; // pass pointer to pointer + + dwFlags = SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE | (CP_UTF8 << 16); + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), EM_STREAMOUT, dwFlags, (LPARAM) & stream); + return pszText; // pszText contains the text +} diff --git a/plugins/TabSRMM/src/chat/muchighlight.cpp b/plugins/TabSRMM/src/chat/muchighlight.cpp new file mode 100644 index 0000000000..7b05b5b81b --- /dev/null +++ b/plugins/TabSRMM/src/chat/muchighlight.cpp @@ -0,0 +1,427 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: muchighlight.cpp 13184 2010-12-07 14:16:58Z silvercircle $ + * + * highlighter class for multi user chats + * + */ + +#include "..\commonheaders.h" + +//#define __HLT_PERFSTATS 0 + +void CMUCHighlight::cleanup() +{ + if (m_NickPatternString) + mir_free(m_NickPatternString); + if (m_TextPatternString) + mir_free(m_TextPatternString); + + m_TextPatternString = m_NickPatternString = 0; + + if (m_NickPatterns) + mir_free(m_NickPatterns); + if (m_TextPatterns) + mir_free(m_TextPatterns); + + m_iNickPatterns = m_iTextPatterns = 0; + m_NickPatterns = m_TextPatterns = 0; +} + +void CMUCHighlight::init() +{ + DBVARIANT dbv = {0}; + + if (m_fInitialized) + cleanup(); // clean up first, if we were already initialized + + m_fInitialized = true; + + if (0 == M->GetTString(0, "Chat", "HighlightWords", &dbv)) { + m_TextPatternString = dbv.ptszVal; + _wsetlocale(LC_ALL, L""); + wcslwr(m_TextPatternString); + } + + if (0 == M->GetTString(0, "Chat", "HighlightNames", &dbv)) + m_NickPatternString = dbv.ptszVal; + + m_dwFlags = M->GetByte("Chat", "HighlightEnabled", MATCH_TEXT); + m_fHighlightMe = (M->GetByte("Chat", "HighlightMe", 1) ? true : false); + + __try { + tokenize(m_TextPatternString, m_TextPatterns, m_iTextPatterns); + tokenize(m_NickPatternString, m_NickPatterns, m_iNickPatterns); + } + __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"MUC_HLT_TOKENIZER", false)) { + m_Valid = false; + } +} + +void CMUCHighlight::tokenize(TCHAR *tszString, TCHAR**& patterns, UINT& nr) +{ + if (tszString == 0) + return; + + TCHAR *p = tszString; + + if (*p == 0) + return; + + nr = 0; + + if (*p != ' ') + nr++; + + while(*p) { + if (*p == ' ') { + p++; + while(*p && _istspace(*p)) + p++; + if (*p) + nr++; + } + p++; + } + patterns = (TCHAR **)mir_alloc(nr * sizeof(TCHAR *)); + + p = tszString; + nr = 0; + + if (*p != ' ') + patterns[nr++] = p; + + while(*p) { + if (*p == ' ') { + *p++ = 0; + while(*p && _istspace(*p)) + p++; + if (*p) + patterns[nr++] = p; + } + p++; + } +} + +int CMUCHighlight::match(const GCEVENT *pgce, const SESSION_INFO *psi, DWORD dwFlags) +{ + int result = 0, nResult = 0; + + if (pgce == 0 || m_Valid == false) + return 0; + + __try { + if ((m_dwFlags & MATCH_TEXT) && (dwFlags & MATCH_TEXT) && (m_fHighlightMe || m_iTextPatterns > 0) && psi != 0) { + #ifdef __HLT_PERFSTATS + int words = 0; + M->startTimer(); + #endif + TCHAR *tszCleaned = ::RemoveFormatting(pgce->ptszText, true, true); + TCHAR *p = tszCleaned; + TCHAR *p1; + UINT i = 0; + + TCHAR *tszMe = ((psi && psi->pMe) ? mir_tstrdup(psi->pMe->pszNick) : 0); + if (tszMe) { + _wsetlocale(LC_ALL, L""); + wcslwr(tszMe); + } + + if (m_fHighlightMe && tszMe) { + result = wcsstr(p, tszMe) ? MATCH_TEXT : 0; + if (0 == m_iTextPatterns) + goto skip_textpatterns; + } + while(p && !result) { + while(*p && (*p == ' ' || *p == ',' || *p == '.' || *p == ':' || *p == ';' || *p == '?' || *p == '!')) + p++; + + if (*p) { + p1 = p; + while(*p1 && *p1 != ' ' && *p1 != ',' && *p1 != '.' && *p1 != ':' && *p1 != ';' && *p1 != '?' && *p1 != '!') + p1++; + + if (*p1) + *p1 = 0; + else + p1 = 0; + + for (i=0; i < m_iTextPatterns && !result; i++) + result = wildmatch(m_TextPatterns[i], p) ? MATCH_TEXT : 0; + + if (p1) { + *p1 = ' '; + p = p1 + 1; + } + else + p = 0; + #ifdef __HLT_PERFSTATS + words++; + #endif + } + else + break; + } +skip_textpatterns: + + #ifdef __HLT_PERFSTATS + M->stopTimer(0); + if (psi && psi->dat) { + mir_sntprintf(psi->dat->szStatusBar, 100, _T("PERF text match: %d ticks = %f msec (%d words, %d patterns)"), (int)M->getTicks(), M->getMsec(), words, m_iTextPatterns); + if (psi->dat->pContainer->hwndStatus) + ::SendMessage(psi->dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)psi->dat->szStatusBar); + } + #endif + if (tszMe) + mir_free(tszMe); + } + + /* + * optinally, match the nickname against the list of nicks to highlight + */ + if ((m_dwFlags & MATCH_NICKNAME) && (dwFlags & MATCH_NICKNAME) && pgce->ptszNick && m_iNickPatterns > 0) { + for (UINT i = 0; i < m_iNickPatterns && !nResult; i++) { + if (pgce->ptszNick) + nResult = wildmatch(m_NickPatterns[i], pgce->ptszNick) ? MATCH_NICKNAME : 0; + if ((m_dwFlags & MATCH_UIN) && pgce->ptszUserInfo) + nResult = wildmatch(m_NickPatterns[i], pgce->ptszUserInfo) ? MATCH_NICKNAME : 0; + } + } + + return(result | nResult); + } + __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"MUC_HIGHLIGHT_EXCEPTION", false)) { + m_Valid = false; + return 0; + } + return 0; +} + +int CMUCHighlight::wildmatch(const TCHAR *pattern, const TCHAR *tszString) { + + const TCHAR *cp = 0, *mp = 0; + + while ((*tszString) && (*pattern != '*')) { + if ((*pattern != *tszString) && (*pattern != '?')) { + return 0; + } + pattern++; + tszString++; + } + + while (*tszString) { + if (*pattern == '*') { + if (!*++pattern) + return 1; + mp = pattern; + cp = tszString + 1; + } + else if ((*pattern == *tszString) || (*pattern == '?')) { + pattern++; + tszString++; + } + else { + pattern = mp; + tszString = cp++; + } + } + + while (*pattern == '*') + pattern++; + + return(!*pattern); +} + +/** + * Dialog procedure to handle global highlight settings + * + * @param Standard Windows dialog procedure parameters + */ + +INT_PTR CALLBACK CMUCHighlight::dlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) { + case WM_INITDIALOG: { + DBVARIANT dbv = {0}; + + TranslateDialogDefault(hwndDlg); + + if (0 == M->GetTString(0, "Chat", "HighlightWords", &dbv)) { + ::SetDlgItemTextW(hwndDlg, IDC_HIGHLIGHTTEXTPATTERN, dbv.ptszVal); + ::DBFreeVariant(&dbv); + } + + if (0 == M->GetTString(0, "Chat", "HighlightNames", &dbv)) { + ::SetDlgItemTextW(hwndDlg, IDC_HIGHLIGHTNICKPATTERN, dbv.ptszVal); + ::DBFreeVariant(&dbv); + } + + DWORD dwFlags = M->GetByte("Chat", "HighlightEnabled", MATCH_TEXT); + + ::CheckDlgButton(hwndDlg, IDC_HIGHLIGHTNICKENABLE, dwFlags & MATCH_NICKNAME ? BST_CHECKED : BST_UNCHECKED); + ::CheckDlgButton(hwndDlg, IDC_HIGHLIGHTNICKUID, dwFlags & MATCH_UIN ? BST_CHECKED : BST_UNCHECKED); + ::CheckDlgButton(hwndDlg, IDC_HIGHLIGHTTEXTENABLE, dwFlags & MATCH_TEXT ? BST_CHECKED : BST_UNCHECKED); + ::CheckDlgButton(hwndDlg, IDC_HIGHLIGHTME, M->GetByte("Chat", "HighlightMe", 1) ? BST_CHECKED : BST_UNCHECKED); + + ::SendMessageW(hwndDlg, WM_USER + 100, 0, 0); + return(TRUE); + } + + case WM_USER + 100: + Utils::enableDlgControl(hwndDlg, IDC_HIGHLIGHTTEXTPATTERN, + ::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTTEXTENABLE) ? TRUE : FALSE); + + Utils::enableDlgControl(hwndDlg, IDC_HIGHLIGHTNICKPATTERN, + ::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTNICKENABLE) ? TRUE : FALSE); + + Utils::enableDlgControl(hwndDlg, IDC_HIGHLIGHTNICKUID, + ::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTNICKENABLE) ? TRUE : FALSE); + + Utils::enableDlgControl(hwndDlg, IDC_HIGHLIGHTME, + ::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTTEXTENABLE) ? TRUE : FALSE); + return(FALSE); + + case WM_COMMAND: + if ((LOWORD(wParam) == IDC_HIGHLIGHTNICKPATTERN + || LOWORD(wParam) == IDC_HIGHLIGHTTEXTPATTERN) + && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != ::GetFocus())) + return 0; + + ::SendMessage(hwndDlg, WM_USER + 100, 0, 0); + if (lParam != (LPARAM)NULL) + ::SendMessage(::GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->idFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: { + wchar_t* szBuf = 0; + int iLen = ::GetWindowTextLengthW(::GetDlgItem(hwndDlg, IDC_HIGHLIGHTNICKPATTERN)); + + if (iLen) { + szBuf = reinterpret_cast(mir_alloc((iLen + 2) * sizeof(wchar_t))); + ::GetDlgItemTextW(hwndDlg, IDC_HIGHLIGHTNICKPATTERN, szBuf, iLen + 1); + M->WriteTString(0, "Chat", "HighlightNames",szBuf); + } + + iLen = ::GetWindowTextLengthW(::GetDlgItem(hwndDlg, IDC_HIGHLIGHTTEXTPATTERN)); + if (iLen) { + szBuf = reinterpret_cast(mir_realloc(szBuf, sizeof(wchar_t) * (iLen + 2))); + ::GetDlgItemTextW(hwndDlg, IDC_HIGHLIGHTTEXTPATTERN, szBuf, iLen + 1); + M->WriteTString(0, "Chat", "HighlightWords", szBuf); + } + else + M->WriteTString(0, "Chat", "HighlightWords", L""); + + mir_free(szBuf); + BYTE dwFlags = (::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTNICKENABLE) ? MATCH_NICKNAME : 0) | + (::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTTEXTENABLE) ? MATCH_TEXT : 0); + + if (dwFlags & MATCH_NICKNAME) + dwFlags |= (::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTNICKUID) ? MATCH_UIN : 0); + + M->WriteByte("Chat", "HighlightEnabled", dwFlags); + M->WriteByte("Chat", "HighlightMe", ::IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHTME) ? 1 : 0); + g_Settings.Highlight->init(); + } + return TRUE; + } + default: + break; + } + break; + } + return(FALSE); +} + +/** + * dialog procedure for the small "add user to highlight list" dialog box + * TODO: finish it + */ +INT_PTR CALLBACK CMUCHighlight::dlgProcAdd(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + UINT uCmd = ::GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch(msg) { + case WM_INITDIALOG: { + HFONT hFont = (HFONT)::SendDlgItemMessage(hwndDlg, IDC_ADDHIGHLIGHTTITLE, WM_GETFONT, 0, 0); + LOGFONTW lf = {0}; + + THighLightEdit *the = reinterpret_cast(lParam); + ::SetWindowLongPtr(hwndDlg, GWLP_USERDATA, the->uCmd); + + ::GetObject(hFont, sizeof(lf), &lf); + lf.lfWeight = FW_BOLD; + lf.lfHeight = (int)(lf.lfHeight * 1.2); + hFont = ::CreateFontIndirectW(&lf); + + ::SendDlgItemMessage(hwndDlg, IDC_ADDHIGHLIGHTTITLE, WM_SETFONT, (WPARAM)hFont, FALSE); + if (the->uCmd == THighLightEdit::CMD_ADD) { + Utils::showDlgControl(hwndDlg, IDC_ADDHIGHLIGHTEDITLIST, SW_HIDE); + ::SetDlgItemTextW(hwndDlg, IDC_ADDHIGHLIGHTTITLE, TranslateT("Add user to highlight list")); + ::SendDlgItemMessageW(hwndDlg, IDC_ADDHIGHLIGHTNAME, CB_INSERTSTRING, -1, (LPARAM)the->ui->pszNick); + ::SendDlgItemMessageW(hwndDlg, IDC_ADDHIGHLIGHTNAME, CB_INSERTSTRING, -1, (LPARAM)the->ui->pszUID); + ::SendDlgItemMessageW(hwndDlg, IDC_ADDHIGHLIGHTNAME, CB_SETCURSEL, 1, 0); + } else { + Utils::showDlgControl(hwndDlg, IDC_ADDHIGHLIGHTNAME, SW_HIDE); + Utils::showDlgControl(hwndDlg, IDC_ADDHIGHLIGHTEXPLAIN, SW_HIDE); + ::SetDlgItemTextW(hwndDlg, IDC_ADDHIGHLIGHTTITLE, TranslateT("Edit user highlight list")); + } + break; + } + + case WM_CTLCOLOREDIT: + case WM_CTLCOLORSTATIC: + { + HWND hwndChild = (HWND)lParam; + UINT id = ::GetDlgCtrlID(hwndChild); + + if (hwndChild == ::GetDlgItem(hwndDlg, IDC_ADDHIGHLIGHTTITLE)) + ::SetTextColor((HDC)wParam, RGB(60, 60, 150)); + ::SetBkColor((HDC)wParam, ::GetSysColor(COLOR_WINDOW)); + return (INT_PTR)::GetSysColorBrush(COLOR_WINDOW); + } + + case WM_COMMAND: { + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + ::DestroyWindow(hwndDlg); + break; + } + + case WM_DESTROY: { + HFONT hFont = (HFONT)::SendDlgItemMessage(hwndDlg, IDC_ADDHIGHLIGHTTITLE, WM_GETFONT, 0, 0); + ::DeleteObject(hFont); + break; + } + } + return(FALSE); +} + diff --git a/plugins/TabSRMM/src/chat/muchighlight.h b/plugins/TabSRMM/src/chat/muchighlight.h new file mode 100644 index 0000000000..e6e403a040 --- /dev/null +++ b/plugins/TabSRMM/src/chat/muchighlight.h @@ -0,0 +1,94 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: muchighlight.h 12299 2010-08-10 02:39:36Z silvercircle $ + * + * highlighter class for multi user chats + * + */ + +class CMUCHighlight { + +public: + + enum { + MATCH_TEXT = 1, + MATCH_NICKNAME = 2, + MATCH_UIN = 4, + }; + + CMUCHighlight() + { + m_fInitialized = false; + m_TextPatternString = m_NickPatternString = 0; + m_NickPatterns = m_TextPatterns = 0; + m_iNickPatterns = m_iTextPatterns = 0; + m_dwFlags = 0; + m_Valid = true; + init(); + } + + ~CMUCHighlight() + { + cleanup(); + } + + void init (); + void cleanup (); + int match (const GCEVENT *pgce, const SESSION_INFO *psi, + DWORD dwFlags = MATCH_NICKNAME); + + static INT_PTR CALLBACK dlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); // option page dlg proc + static INT_PTR CALLBACK dlgProcAdd (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); // for the "add to" dialog +private: + void tokenize(TCHAR *tszString, TCHAR**& patterns, UINT& nr); + int wildmatch (const TCHAR *pattern, const TCHAR *tszString); + DWORD m_dwFlags; + bool m_fInitialized; + TCHAR** m_NickPatterns; + TCHAR** m_TextPatterns; + UINT m_iNickPatterns; + UINT m_iTextPatterns; + TCHAR* m_NickPatternString; + TCHAR* m_TextPatternString; + bool m_Valid; + bool m_fHighlightMe; +}; + +struct THighLightEdit +{ + enum { + CMD_ADD = 1, + CMD_EDIT = 2 + }; + + UINT uCmd; + SESSION_INFO *si; + USERINFO *ui; +}; + diff --git a/plugins/TabSRMM/src/chat/options.cpp b/plugins/TabSRMM/src/chat/options.cpp new file mode 100644 index 0000000000..9d2fec8b48 --- /dev/null +++ b/plugins/TabSRMM/src/chat/options.cpp @@ -0,0 +1,1493 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * This code is based on and still contains large parts of the the + * original chat module for Miranda NG, written and copyrighted + * by Joergen Persson in 2005. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: options.cpp 13412 2011-03-08 19:13:11Z george.hazan $ + * + * group chat options and generic font handling + * + */ + +#include "..\commonheaders.h" +#undef Translate + +#define TranslateA(s) ((char*)CallService(MS_LANGPACK_TRANSLATESTRING,0,(LPARAM)(s))) +#include +#include + +extern HBRUSH hListBkgBrush; +extern HICON hIcons[30]; +extern FONTINFO aFonts[OPTIONS_FONTCOUNT]; +extern HMODULE g_hIconDLL; + +extern HIMAGELIST CreateStateImageList(); + +HANDLE g_hOptions = NULL; + + +#define FONTF_BOLD 1 +#define FONTF_ITALIC 2 + +struct FontOptionsList { + TCHAR* szDescr; + COLORREF defColour; + TCHAR* szDefFace; + BYTE defCharset, defStyle; + char defSize; + COLORREF colour; + TCHAR szFace[LF_FACESIZE]; + BYTE charset, style; + char size; +}; + +struct ColorOptionsList { + int order; + TCHAR* tszGroup; + TCHAR* tszName; + char* szSetting; + COLORREF def; +}; + +/* + * note: bits 24-31 in default color indicates that color is a system color index + * (GetSysColor(default_color & 0x00ffffff)), not a rgb value. + */ +static ColorOptionsList _clrs[] = { + 0, LPGENT("TabSRMM/Group Chats"), LPGENT("Group chat log background"), SRMSGSET_BKGCOLOUR_MUC, SRMSGDEFSET_BKGCOLOUR, + 1, LPGENT("TabSRMM"), LPGENT("Input area background"), "inputbg", SRMSGDEFSET_BKGCOLOUR, + 2, LPGENT("TabSRMM"), LPGENT("Log background"), SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR, + 0, LPGENT("TabSRMM/Single Messaging"), LPGENT("Outgoing background"), "outbg", SRMSGDEFSET_BKGOUTCOLOUR, + 1, LPGENT("TabSRMM/Single Messaging"), LPGENT("Incoming background"), "inbg", SRMSGDEFSET_BKGINCOLOUR, + 2, LPGENT("TabSRMM/Single Messaging"), LPGENT("Status background"), "statbg", SRMSGDEFSET_BKGCOLOUR, + 3, LPGENT("TabSRMM/Single Messaging"), LPGENT("Incoming background(old)"), "oldinbg", SRMSGDEFSET_BKGINCOLOUR, + 4, LPGENT("TabSRMM/Single Messaging"), LPGENT("Outgoing background(old)"), "oldoutbg", SRMSGDEFSET_BKGOUTCOLOUR, + 5, LPGENT("TabSRMM/Single Messaging"), LPGENT("Horizontal Grid Lines"), "hgrid", RGB(224, 224, 224), + 0, LPGENT("TabSRMM/Info Panel"), LPGENT("Panel background low"), "ipfieldsbg", 0x62caff, + 1, LPGENT("TabSRMM/Info Panel"), LPGENT("Panel background high"), "ipfieldsbgHigh", 0xf0f0f0, + 0, LPGENT("TabSRMM/Common colors"), LPGENT("Toolbar background high"), "tbBgHigh", 0, + 1, LPGENT("TabSRMM/Common colors"), LPGENT("Toolbar background low"), "tbBgLow", 0, + 2, LPGENT("TabSRMM/Common colors"), LPGENT("Window fill color"), "fillColor", 0, + 3, LPGENT("TabSRMM/Common colors"), LPGENT("Text area borders"), "cRichBorders", 0, + 4, LPGENT("TabSRMM/Common colors"), LPGENT("Aero glow effect"), "aeroGlow", RGB(40, 40, 255), + 4, LPGENT("TabSRMM/Common colors"), LPGENT("Generic text color (only when fill color is set)"), "genericTxtClr", 0xff000000 | COLOR_BTNTEXT, +}; + +static ColorOptionsList _tabclrs[] = { + 0, LPGENT("TabSRMM/Tabs"), LPGENT("Normal text"), "tab_txt_normal", 0xff000000 | COLOR_BTNTEXT, + 1, LPGENT("TabSRMM/Tabs"), LPGENT("Active text"), "tab_txt_active", 0xff000000 | COLOR_BTNTEXT, + 2, LPGENT("TabSRMM/Tabs"), LPGENT("Hovered text"), "tab_txt_hottrack", 0xff000000 | COLOR_HOTLIGHT, + 3, LPGENT("TabSRMM/Tabs"), LPGENT("Unread text"), "tab_txt_unread", 0xff000000 | COLOR_HOTLIGHT, + + 4, LPGENT("TabSRMM/Tabs"), LPGENT("Normal background"), "tab_bg_normal", 0xff000000 | COLOR_3DFACE, + 5, LPGENT("TabSRMM/Tabs"), LPGENT("Active background"), "tab_bg_active", 0xff000000 | COLOR_3DFACE, + 6, LPGENT("TabSRMM/Tabs"), LPGENT("Hovered background"), "tab_bg_hottrack", 0xff000000 | COLOR_3DFACE, + 7, LPGENT("TabSRMM/Tabs"), LPGENT("Unread background"), "tab_bg_unread", 0xff000000 | COLOR_3DFACE +}; + +extern LOGFONT lfDefault; + +//remember to put these in the Translate( ) template file too +static FontOptionsList CHAT_fontOptionsList[] = { + {LPGENT("Timestamp"), RGB(50, 50, 240), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Others nicknames"), RGB(0, 0, 192), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12}, + {LPGENT("Your nickname"), RGB(0, 0, 192), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12}, + {LPGENT("User has joined"), RGB(90, 160, 90), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("User has left"), RGB(160, 160, 90), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("User has disconnected"), RGB(160, 90, 90), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("User kicked ..."), RGB(100, 100, 100), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("User is now known as ..."), RGB(90, 90, 160), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Notice from user"), RGB(160, 130, 60), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Incoming message"), RGB(90, 90, 90), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Outgoing message"), RGB(90, 90, 90), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("The topic is ..."), RGB(70, 70, 160), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Information messages"), RGB(130, 130, 195), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("User enables status for ..."), RGB(70, 150, 70), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("User disables status for ..."), RGB(150, 70, 70), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Action message"), RGB(160, 90, 160), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Highlighted message"), RGB(180, 150, 80), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Chat log symbols (Webdings)"), RGB(170, 170, 170), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("User list members (Online)"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("User list members (away)"), RGB(170, 170, 170), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, +}; + +const int msgDlgFontCount = SIZEOF(CHAT_fontOptionsList); + +static FontOptionsList IM_fontOptionsList[] = { + {LPGENT(">> Outgoing messages"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT(">> Outgoing misc events"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("<< Incoming messages"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("<< Incoming misc events"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT(">> Outgoing name"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12}, + {LPGENT(">> Outgoing timestamp"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12}, + {LPGENT("<< Incoming name"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12}, + {LPGENT("<< Incoming timestamp"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12}, + {LPGENT(">> Outgoing messages (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT(">> Outgoing misc events (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("<< Incoming messages (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("<< Incoming misc events (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT(">> Outgoing name (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12}, + {LPGENT(">> Outgoing timestamp (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12}, + {LPGENT("<< Incoming name (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12}, + {LPGENT("<< Incoming timestamp (old)"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, FONTF_BOLD, -12}, + {LPGENT("* Message Input Area"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("* Status changes"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("* Dividers"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("* Error and warning Messages"), RGB(50, 50, 50), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("* Symbols (incoming)"), RGB(50, 50, 50), _T("Webdings"), SYMBOL_CHARSET, 0, -12}, + {LPGENT("* Symbols (outgoing)"), RGB(50, 50, 50), _T("Webdings"), SYMBOL_CHARSET, 0, -12}, +}; + +static FontOptionsList IP_fontOptionsList[] = { + {LPGENT("Nickname"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("UIN"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Status"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Protocol"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Contacts local time"), RGB(0, 0, 0), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, + {LPGENT("Window caption (skinned mode)"), RGB(255, 255, 255), lfDefault.lfFaceName, DEFAULT_CHARSET, 0, -12}, +}; + +static FontOptionsList *fontOptionsList = IM_fontOptionsList; +static int fontCount = MSGDLGFONTCOUNT; + +struct branch_t { + TCHAR* szDescr; + char* szDBName; + int iMode; + BYTE bDefault; + HTREEITEM hItem; +}; +static struct branch_t branch1[] = { + {LPGENT("Open new chat rooms in the default container"), "DefaultContainer", 0, 1, NULL}, + {LPGENT("Flash window when someone speaks"), "FlashWindow", 0, 0, NULL}, + {LPGENT("Flash window when a word is highlighted"), "FlashWindowHighlight", 0, 1, NULL}, +//TODO Fix for 3.0 !!! + +#if !defined(__DELAYED_FOR_3_1) + {LPGENT("Create tabs or windows for highlight events"), "CreateWindowOnHighlight", 0,0, NULL}, + {LPGENT("Activate chat window on highlight"), "AnnoyingHighlight", 0,0, NULL}, +#endif + + {LPGENT("Show list of users in the chat room"), "ShowNicklist", 0, 1, NULL}, + {LPGENT("Colorize nicknames in member list"), "ColorizeNicks", 0, 1, NULL}, + {LPGENT("Show button menus when right clicking the buttons"), "RightClickFilter", 0, 1, NULL}, + {LPGENT("Show topic as status message on the contact list"), "TopicOnClist", 0, 1, NULL}, + {LPGENT("Do not pop up the window when joining a chat room"), "PopupOnJoin", 0, 0, NULL}, + {LPGENT("Hide or show the window by double click in the contact list"), "ToggleVisibility", 0, 0, NULL}, + {LPGENT("Sync splitter position with standard IM sessions"), "SyncSplitter", 0, 0, NULL}, + {LPGENT("Show contact's status modes if supported by the protocol"), "ShowContactStatus", 0, 1, NULL}, + {LPGENT("Display contact's status icon before user role icon"), "ContactStatusFirst", 0, 0, NULL}, + //MAD: simple customization improvement + {LPGENT("Use IRC style status indicators in the user list"), "ClassicIndicators", 0, 0, NULL}, + {LPGENT("Use alternative sorting method in member list"), "AlternativeSorting", 0, 1, NULL}, + +}; +static struct branch_t branch2[] = { + {LPGENT("Prefix all events with a timestamp"), "ShowTimeStamp", 0, 1, NULL}, + {LPGENT("Timestamp only when event time differs"), "ShowTimeStampIfChanged", 0, 0, NULL}, + {LPGENT("Timestamp has same color as the event"), "TimeStampEventColour", 0, 0, NULL}, + {LPGENT("Indent the second line of a message"), "LogIndentEnabled", 0, 1, NULL}, + {LPGENT("Limit user names in the message log to 20 characters"), "LogLimitNames", 0, 1, NULL}, + {LPGENT("Add a colon (:) to auto-completed user names"), "AddColonToAutoComplete", 0, 1, NULL}, + {LPGENT("Start private conversation on doubleclick in nick list (insert nick if unchecked)"), "DoubleClick4Privat", 0, 0, NULL}, + {LPGENT("Strip colors from messages in the log"), "StripFormatting", 0, 0, NULL}, + {LPGENT("Enable the \'event filter\' for new rooms"), "FilterEnabled", 0, 0, NULL}, +//MAD: simple customization improvement + {LPGENT("Use IRC style status indicators in the log"), "LogClassicIndicators", 0,0, NULL}, +// + {LPGENT("Allow clickable user names in the message log"), "ClickableNicks", 0, 1, NULL}, + {LPGENT("Colorize user names in message log"), "ColorizeNicksInLog", 0, 1, NULL}, + {LPGENT("Scale down icons to 10x10 pixels in the chat log"), "ScaleIcons", 0, 1, NULL}, + {LPGENT("Place a separator in the log after a window lost its foreground status"), "UseDividers", 0, 1, NULL}, + {LPGENT("Only place a separator when an incoming event is announced with a popup"), "DividersUsePopupConfig", 0, 1, NULL}, + {LPGENT("Support the math module plugin"), "MathModSupport", 0, 0, NULL} +}; + +static HWND hPathTip = 0; + +void LoadMsgDlgFont(int section, int i, LOGFONT *lf, COLORREF* colour, char *szMod) +{ + char str[32]; + int style; + DBVARIANT dbv; + int j = (i >= 100 ? i - 100 : i); + + struct FontOptionsList *fol = fontOptionsList; + switch (section) + { + case FONTSECTION_CHAT: fol = CHAT_fontOptionsList; break; + case FONTSECTION_IM: fol = IM_fontOptionsList; break; + case FONTSECTION_IP: fol = IP_fontOptionsList; break; + } + + if (colour) { + wsprintfA(str, "Font%dCol", i); + *colour = M->GetDword(szMod, str, fol[j].defColour); + } + if (lf) { + wsprintfA(str, "Font%dSize", i); + lf->lfHeight = (char) M->GetByte(szMod, str, fol[j].defSize); + lf->lfWidth = 0; + lf->lfEscapement = 0; + lf->lfOrientation = 0; + wsprintfA(str, "Font%dSty", i); + style = M->GetByte(szMod, str, fol[j].defStyle); + if (i == MSGFONTID_MESSAGEAREA && section == FONTSECTION_IM && M->GetByte(0, SRMSGMOD_T, "inputFontFix", 1) == 1) { + lf->lfWeight = FW_NORMAL; + lf->lfItalic = 0; + lf->lfUnderline = 0; + lf->lfStrikeOut = 0; + } + else { + lf->lfWeight = style & FONTF_BOLD ? FW_BOLD : FW_NORMAL; + lf->lfItalic = style & FONTF_ITALIC ? 1 : 0; + lf->lfUnderline = style & FONTF_UNDERLINE ? 1 : 0; + lf->lfStrikeOut = style & FONTF_STRIKEOUT ? 1 : 0; + } + wsprintfA(str, "Font%dSet", i); + lf->lfCharSet = M->GetByte(szMod, str, fol[j].defCharset); + lf->lfOutPrecision = OUT_DEFAULT_PRECIS; + lf->lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf->lfQuality = DEFAULT_QUALITY; + lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + wsprintfA(str, "Font%d", i); + if ((i == 17 && !strcmp(szMod, CHAT_FONTMODULE)) || ((i == 20 || i == 21) && !strcmp(szMod, FONTMODULE))) { + lf->lfCharSet = SYMBOL_CHARSET; + lstrcpyn(lf->lfFaceName, _T("Webdings"), SIZEOF(lf->lfFaceName)); + } else { + if (M->GetTString(NULL, szMod, str, &dbv)) { + lstrcpy(lf->lfFaceName, fol[j].szDefFace); + } else { + lstrcpyn(lf->lfFaceName, dbv.ptszVal, SIZEOF(lf->lfFaceName)); + DBFreeVariant(&dbv); + } + } + } +} + +static HTREEITEM InsertBranch(HWND hwndTree, TCHAR* pszDescr, BOOL bExpanded) +{ + TVINSERTSTRUCT tvis; + + tvis.hParent = NULL; + tvis.hInsertAfter = TVI_LAST; + tvis.item.mask = TVIF_TEXT | TVIF_STATE; + tvis.item.pszText = TranslateTS(pszDescr); + tvis.item.stateMask = (bExpanded ? TVIS_STATEIMAGEMASK | TVIS_EXPANDED : TVIS_STATEIMAGEMASK) | TVIS_BOLD; + tvis.item.state = (bExpanded ? INDEXTOSTATEIMAGEMASK(0) | TVIS_EXPANDED : INDEXTOSTATEIMAGEMASK(0)) | TVIS_BOLD; + return TreeView_InsertItem(hwndTree, &tvis); +} + +static void FillBranch(HWND hwndTree, HTREEITEM hParent, struct branch_t *branch, int nValues, DWORD defaultval) +{ + TVINSERTSTRUCT tvis; + int i; + int iState; + + if (hParent == 0) + return; + + tvis.hParent = hParent; + tvis.hInsertAfter = TVI_LAST; + tvis.item.mask = TVIF_TEXT | TVIF_STATE; + for (i=0;i < nValues;i++) { + tvis.item.pszText = TranslateTS(branch[i].szDescr); + tvis.item.stateMask = TVIS_STATEIMAGEMASK; + if (branch[i].iMode) + iState = ((M->GetDword("Chat", branch[i].szDBName, defaultval) & branch[i].iMode) & branch[i].iMode) != 0 ? 3 : 2; + else + iState = M->GetByte("Chat", branch[i].szDBName, branch[i].bDefault) != 0 ? 3 : 2; + tvis.item.state = INDEXTOSTATEIMAGEMASK(iState); + branch[i].hItem = TreeView_InsertItem(hwndTree, &tvis); + } +} + +static void SaveBranch(HWND hwndTree, struct branch_t *branch, int nValues) +{ + TVITEM tvi; + BYTE bChecked; + int i; + int iState = 0; + + tvi.mask = TVIF_HANDLE | TVIF_STATE; + for (i=0;i < nValues;i++) { + tvi.hItem = branch[i].hItem; + TreeView_GetItem(hwndTree, &tvi); + bChecked = ((tvi.state & TVIS_STATEIMAGEMASK) >> 12 == 2) ? 0 : 1; + if (branch[i].iMode) { + if (bChecked) + iState |= branch[i].iMode; + if (iState & GC_EVENT_ADDSTATUS) + iState |= GC_EVENT_REMOVESTATUS; + M->WriteDword("Chat", branch[i].szDBName, (DWORD)iState); + } else M->WriteByte("Chat", branch[i].szDBName, bChecked); + } +} + +static void CheckHeading(HWND hwndTree, HTREEITEM hHeading) +{ + BOOL bChecked = TRUE; + TVITEM tvi; + + if (hHeading == 0) + return; + + tvi.mask = TVIF_HANDLE | TVIF_STATE; + tvi.hItem = TreeView_GetNextItem(hwndTree, hHeading, TVGN_CHILD); + while (tvi.hItem && bChecked) { + if (tvi.hItem != branch1[0].hItem && tvi.hItem != branch1[1].hItem) { + TreeView_GetItem(hwndTree, &tvi); + if (((tvi.state&TVIS_STATEIMAGEMASK) >> 12 == 2)) + bChecked = FALSE; + } + tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem); + } + tvi.stateMask = TVIS_STATEIMAGEMASK; + tvi.state = INDEXTOSTATEIMAGEMASK(1); //bChecked ? 3 : 2); + tvi.hItem = hHeading; + TreeView_SetItem(hwndTree, &tvi); +} + +static void CheckBranches(HWND hwndTree, HTREEITEM hHeading) +{ + BOOL bChecked = TRUE; + TVITEM tvi; + + if (hHeading == 0) + return; + + tvi.mask = TVIF_HANDLE | TVIF_STATE; + tvi.hItem = hHeading; + TreeView_GetItem(hwndTree, &tvi); + if (((tvi.state&TVIS_STATEIMAGEMASK) >> 12 == 3)||((tvi.state & TVIS_STATEIMAGEMASK) >> 12 == 1)) + bChecked = FALSE; + + tvi.stateMask = TVIS_STATEIMAGEMASK; + tvi.state = INDEXTOSTATEIMAGEMASK(bChecked ? 2 : 1); + TreeView_SetItem(hwndTree, &tvi); + tvi.hItem = TreeView_GetNextItem(hwndTree, hHeading, TVGN_CHILD); + while (tvi.hItem) { + tvi.state = INDEXTOSTATEIMAGEMASK(bChecked ? 3:2); + if (tvi.hItem != branch1[0].hItem && tvi.hItem != branch1[1].hItem) + TreeView_SetItem(hwndTree, &tvi); + tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem); + } +} + +static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) +{ + char szDir[MAX_PATH]; + switch (uMsg) { + case BFFM_INITIALIZED: { + const TCHAR *szData = M->getUserDir(); + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szData); + break; + } + case BFFM_SELCHANGED: + if (SHGetPathFromIDListA((LPITEMIDLIST) lp , szDir)) + SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)szDir); + break; + } + return 0; +} + +static void LoadLogFonts(void) +{ + int i; + + for (i=0; i < OPTIONS_FONTCOUNT; i++) + LoadMsgDlgFont(FONTSECTION_CHAT, i, &aFonts[i].lf, &aFonts[i].color, CHAT_FONTMODULE); +} + +struct { char *szDesc; char *szName; int id; UINT size;} static _icons[] = +{ + { LPGEN("Window Icon"), "chat_window", IDI_CHANMGR, 16 }, + { LPGEN("Icon overlay"), "chat_overlay", IDI_OVERLAY, 16 }, + + { LPGEN("Status 1 (10x10)"), "chat_status0", IDI_STATUS0, 16 }, + { LPGEN("Status 2 (10x10)"), "chat_status1", IDI_STATUS1, 16 }, + { LPGEN("Status 3 (10x10)"), "chat_status2", IDI_STATUS2, 16 }, + { LPGEN("Status 4 (10x10)"), "chat_status3", IDI_STATUS3, 16 }, + { LPGEN("Status 5 (10x10)"), "chat_status4", IDI_STATUS4, 16 }, + { LPGEN("Status 6 (10x10)"), "chat_status5", IDI_STATUS5, 16 }, +}; + +struct { char *szDesc; char *szName; int id; UINT size;} static _logicons[] = +{ + { LPGEN("Message in (10x10)"), "chat_log_message_in", IDI_MESSAGE, 16 }, + { LPGEN("Message out (10x10)"), "chat_log_message_out", IDI_MESSAGEOUT, 16 }, + { LPGEN("Action (10x10)"), "chat_log_action", IDI_ACTION, 16 }, + { LPGEN("Add Status (10x10)"), "chat_log_addstatus", IDI_ADDSTATUS, 16 }, + { LPGEN("Remove Status (10x10)"), "chat_log_removestatus", IDI_REMSTATUS, 16 }, + { LPGEN("Join (10x10)"), "chat_log_join", IDI_JOIN, 16 }, + { LPGEN("Leave (10x10)"), "chat_log_part", IDI_PART, 16 }, + { LPGEN("Quit (10x10)"), "chat_log_quit", IDI_QUIT, 16 }, + { LPGEN("Kick (10x10)"), "chat_log_kick", IDI_KICK, 16 }, + { LPGEN("Notice (10x10)"), "chat_log_notice", IDI_NOTICE, 16 }, + { LPGEN("Nickchange (10x10)"), "chat_log_nick", IDI_NICK, 16 }, + { LPGEN("Topic (10x10)"), "chat_log_topic", IDI_TOPIC, 16 }, + { LPGEN("Highlight (10x10)"), "chat_log_highlight", IDI_HIGHLIGHT, 16 }, + { LPGEN("Information (10x10)"), "chat_log_info", IDI_INFO, 16 } +}; + +// add icons to the skinning module +void Chat_AddIcons(void) +{ + int i; + TCHAR szFile[MAX_PATH]; + GetModuleFileName(g_hIconDLL, szFile, SIZEOF(szFile)); + + // 16x16 icons + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.pszSection = "TabSRMM/Group chat windows"; + sid.ptszDefaultFile = szFile; + sid.flags = SIDF_PATH_TCHAR; + + for (i=0; i < SIZEOF(_icons); i++) { + sid.cx = sid.cy = _icons[i].size; + sid.pszDescription = _icons[i].szDesc; + sid.pszName = _icons[i].szName; + sid.iDefaultIndex = -_icons[i].id; + Skin_AddIcon(&sid); + } + + sid.pszSection = "TabSRMM/Group chat log"; + for (i=0; i < SIZEOF(_logicons); i++) { + sid.cx = sid.cy = _logicons[i].size; + sid.pszDescription = _logicons[i].szDesc; + sid.pszName = _logicons[i].szName; + sid.iDefaultIndex = -_logicons[i].id; + Skin_AddIcon(&sid); + } +} + +/* + * get icon by name from the core icon library service + */ + +HICON LoadIconEx(int iIndex, char * pszIcoLibName, int iX, int iY) +{ + char szTemp[256]; + mir_snprintf(szTemp, sizeof(szTemp), "chat_%s", pszIcoLibName); + return (HICON) CallService(MS_SKIN2_GETICON, 0, (LPARAM)szTemp); +} + +static void InitSetting(TCHAR** ppPointer, char* pszSetting, TCHAR* pszDefault) +{ + DBVARIANT dbv; + if (!M->GetTString(NULL, "Chat", pszSetting, &dbv)) { + replaceStr(ppPointer, dbv.ptszVal); + DBFreeVariant(&dbv); + } else + replaceStr(ppPointer, pszDefault); +} + +#define OPT_FIXHEADINGS (WM_USER+1) + +static UINT _o1controls[] = {IDC_CHECKBOXES, IDC_GROUP, IDC_STATIC_ADD, 0}; + +HWND CreateToolTip(HWND hwndParent, LPTSTR ptszText, LPTSTR ptszTitle) +{ + TOOLINFO ti = { 0 }; + HWND hwndTT; + hwndTT = CreateWindowEx(WS_EX_TOPMOST, + TOOLTIPS_CLASS, NULL, + WS_POPUP | TTS_NOPREFIX, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + hwndParent, NULL, g_hInst, NULL); + + SetWindowPos(hwndTT, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + + ti.cbSize = sizeof(TOOLINFO); + ti.uFlags = TTF_SUBCLASS | TTF_CENTERTIP; + ti.hwnd = hwndParent; + ti.hinst = g_hInst; + ti.lpszText = ptszText; + GetClientRect (hwndParent, &ti.rect); + ti.rect.left =- 85; + + SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); + SendMessage(hwndTT, TTM_SETTITLE, 1, (LPARAM)ptszTitle); + return hwndTT; +} + +INT_PTR CALLBACK DlgProcOptions1(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static HTREEITEM hListHeading1 = 0; + static HTREEITEM hListHeading2 = 0; + + switch (uMsg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + if (PluginConfig.m_chat_enabled) { + HIMAGELIST himlOptions; + + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHECKBOXES), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHECKBOXES), GWL_STYLE) | TVS_NOHSCROLL | TVS_CHECKBOXES); + + himlOptions = (HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_CHECKBOXES, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)CreateStateImageList()); + ImageList_Destroy(himlOptions); + + hListHeading1 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), TranslateT("Appearance and functionality of chat room windows"), TRUE); + hListHeading2 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), TranslateT("Appearance of the message log"), TRUE); + + FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading1, branch1, SIZEOF(branch1), 0x0000); + FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading2, branch2, SIZEOF(branch2), 0x0000); + + { + TCHAR* pszGroup = NULL; + InitSetting(&pszGroup, "AddToGroup", _T("Chat rooms")); + SetWindowText(GetDlgItem(hwndDlg, IDC_GROUP), pszGroup); + mir_free(pszGroup); + Utils::showDlgControl(hwndDlg, IDC_STATIC_MESSAGE, SW_HIDE); + } + } else { + int i = 0; + + while (_o1controls[i]) + Utils::showDlgControl(hwndDlg, _o1controls[i++], SW_HIDE); + } + break; + + case WM_COMMAND: + if ((LOWORD(wParam) == IDC_GROUP) + && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return 0; + + if (lParam != (LPARAM)NULL) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + + case WM_NOTIFY: { + switch (((LPNMHDR)lParam)->idFrom) { + case IDC_CHECKBOXES: + if (((LPNMHDR)lParam)->code == NM_CLICK || (((LPNMHDR)lParam)->code == TVN_KEYDOWN && ((LPNMTVKEYDOWN)lParam)->wVKey == VK_SPACE)) { + TVHITTESTINFO hti; + hti.pt.x = (short)LOWORD(GetMessagePos()); + hti.pt.y = (short)HIWORD(GetMessagePos()); + ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt); + if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti) || ((LPNMHDR)lParam)->code == TVN_KEYDOWN) { + if (((LPNMHDR)lParam)->code == TVN_KEYDOWN) + hti.flags |= TVHT_ONITEMSTATEICON; + if (hti.flags&TVHT_ONITEMSTATEICON) { + TVITEM tvi = {0}; + + tvi.mask = TVIF_HANDLE | TVIF_STATE; + tvi.stateMask = TVIS_STATEIMAGEMASK | TVIS_BOLD; + + if (((LPNMHDR)lParam)->code == TVN_KEYDOWN) + tvi.hItem = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom); + else + tvi.hItem = (HTREEITEM)hti.hItem; + + TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom, &tvi); + + if (tvi.state & TVIS_BOLD && hti.flags & TVHT_ONITEMSTATEICON) { + tvi.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_BOLD; + SendDlgItemMessageA(hwndDlg, IDC_CHECKBOXES, TVM_SETITEMA, 0, (LPARAM)&tvi); + } else if (hti.flags&TVHT_ONITEMSTATEICON) { + if (((tvi.state & TVIS_STATEIMAGEMASK) >> 12) == 3) { + tvi.state = INDEXTOSTATEIMAGEMASK(1); + SendDlgItemMessageA(hwndDlg, IDC_CHECKBOXES, TVM_SETITEMA, 0, (LPARAM)&tvi); + } + } + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + } + + break; + + case 0: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: { + if (PluginConfig.m_chat_enabled) { + int iLen; + TCHAR *pszText = NULL; + BYTE b; + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_GROUP)); + if (iLen > 0) { + pszText = (TCHAR *)realloc(pszText, (iLen + 2) * sizeof(TCHAR)); + GetDlgItemText(hwndDlg, IDC_GROUP, pszText, iLen + 1); + M->WriteTString(NULL, "Chat", "AddToGroup", pszText); + } else + M->WriteTString(NULL, "Chat", "AddToGroup", _T("")); + + g_Settings.hGroup = 0; + + if (pszText) + free(pszText); + + b = M->GetByte("Chat", "Tabs", 1); + SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch1, sizeof(branch1) / sizeof(branch1[0])); + SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch2, sizeof(branch2) / sizeof(branch2[0])); + + LoadGlobalSettings(); + MM_FontsChanged(); + FreeMsgLogBitmaps(); + LoadMsgLogBitmaps(); + SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE); + SM_ReconfigureFilters(); + } + } + return TRUE; + } + } + } + break; + case WM_DESTROY: { + BYTE b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading1, TVIS_EXPANDED) & TVIS_EXPANDED ? 1 : 0; + M->WriteByte("Chat", "Branch1Exp", b); + b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading2, TVIS_EXPANDED) & TVIS_EXPANDED ? 1 : 0; + M->WriteByte("Chat", "Branch2Exp", b); + } + break; + + default: + break; + } + return FALSE; +} + +static TCHAR* chatcolorsnames[] ={ +// LPGENT("Your nickname"), + LPGENT("Channel operators"), + LPGENT("Half operators"), + LPGENT("Voiced"), +// LPGENT("Others nicknames"), + LPGENT("Extended mode 1"), + LPGENT("Extended mode 2"), + LPGENT("Selection background"), + LPGENT("Selected text"), + LPGENT("Incremental search highlight") + }; + +void RegisterFontServiceFonts() { + int i; + char szTemp[100]; + LOGFONT lf; + FontIDT fid = {0}; + ColourIDT cid = {0}; + + fid.cbSize = sizeof(FontIDT); + cid.cbSize = sizeof(ColourIDT); + + strncpy(fid.dbSettingsGroup, FONTMODULE, SIZEOF(fid.dbSettingsGroup)); + + for (i=0; i < SIZEOF(IM_fontOptionsList); i++) { + fid.flags = FIDF_DEFAULTVALID|FIDF_ALLOWEFFECTS; + LoadMsgDlgFont(FONTSECTION_IM, i , &lf, &fontOptionsList[i].colour, FONTMODULE); + mir_snprintf(szTemp, SIZEOF(szTemp), "Font%d", i); + strncpy(fid.prefix, szTemp, SIZEOF(fid.prefix)); + fid.order = i; + _tcsncpy(fid.name, fontOptionsList[i].szDescr, SIZEOF(fid.name)); + fid.deffontsettings.colour = fontOptionsList[i].colour; + fid.deffontsettings.size = (char) lf.lfHeight; + fid.deffontsettings.style = (lf.lfWeight >= FW_BOLD ? FONTF_BOLD : 0) | (lf.lfItalic ? FONTF_ITALIC : 0); + fid.deffontsettings.charset = lf.lfCharSet; + fid.flags = fid.flags & ~FIDF_CLASSMASK | (fid.deffontsettings.style&FONTF_BOLD ? FIDF_CLASSHEADER : FIDF_CLASSGENERAL); + _tcsncpy(fid.deffontsettings.szFace, lf.lfFaceName, LF_FACESIZE); + _tcsncpy(fid.backgroundGroup, _T("TabSRMM/Single Messaging"), SIZEOF(fid.backgroundGroup)); + _tcsncpy(fid.group, _T("TabSRMM/Single Messaging"), SIZEOF(fid.group)); + switch (i) { + case MSGFONTID_MYMSG: + case 1: + case MSGFONTID_MYNAME: + case MSGFONTID_MYTIME: + case 21: + _tcsncpy(fid.backgroundName, _T("Outgoing background"), SIZEOF(fid.backgroundName)); + break; + case 8: + case 9: + case 12: + case 13: + _tcsncpy(fid.backgroundName, _T("Outgoing background(old)"), SIZEOF(fid.backgroundName)); + break; + case 10: + case 11: + case 14: + case 15: + _tcsncpy(fid.backgroundName, _T("Incoming background(old)"), SIZEOF(fid.backgroundName)); + break; + case MSGFONTID_MESSAGEAREA: + _tcsncpy(fid.group, _T("TabSRMM"), SIZEOF(fid.group)); + _tcsncpy(fid.backgroundGroup, _T("TabSRMM"), SIZEOF(fid.backgroundGroup)); + _tcsncpy(fid.backgroundName, _T("Input area background"), SIZEOF(fid.backgroundName)); + fid.flags |= FIDF_DISABLESTYLES; + fid.flags &= ~FIDF_ALLOWEFFECTS; + break; + case 17: + _tcsncpy(fid.backgroundName, _T("Status background"), SIZEOF(fid.backgroundName)); + break; + case 18: + _tcsncpy(fid.backgroundGroup, _T("TabSRMM"), SIZEOF(fid.backgroundGroup)); + _tcsncpy(fid.backgroundName, _T("Log background"), SIZEOF(fid.backgroundName)); + break; + case 19: + _tcsncpy(fid.backgroundName, _T(""), SIZEOF(fid.backgroundName)); + break; + default: + _tcsncpy(fid.backgroundName, _T("Incoming background"), SIZEOF(fid.backgroundName)); + break; + } + FontRegisterT(&fid); + } + + fontOptionsList = IP_fontOptionsList; + fid.flags = FIDF_DEFAULTVALID|FIDF_ALLOWEFFECTS; + //fid.flags|=FIDF_SAVEPOINTSIZE; + _tcsncpy(fid.group, _T("TabSRMM/Info Panel"), SIZEOF(fid.group)); + _tcsncpy(fid.backgroundGroup, _T("TabSRMM/Info Panel"), SIZEOF(fid.backgroundGroup)); + _tcsncpy(fid.backgroundName, _T("Fields background"), SIZEOF(fid.backgroundName)); + for (i =0; i < IPFONTCOUNT; i++) { + LoadMsgDlgFont(FONTSECTION_IP, i + 100 , &lf, &fontOptionsList[i].colour, FONTMODULE); + mir_snprintf(szTemp, SIZEOF(szTemp), "Font%d", i + 100); + strncpy(fid.prefix, szTemp, SIZEOF(fid.prefix)); + fid.order = i + 100 ; + _tcsncpy(fid.name, fontOptionsList[i].szDescr, SIZEOF(fid.name)); + fid.deffontsettings.colour = fontOptionsList[i].colour; + fid.deffontsettings.size = (char) lf.lfHeight; + fid.deffontsettings.style = (lf.lfWeight >= FW_BOLD ? FONTF_BOLD : 0) | (lf.lfItalic ? FONTF_ITALIC : 0); + fid.deffontsettings.charset = lf.lfCharSet; + fid.flags = fid.flags & ~FIDF_CLASSMASK | (fid.deffontsettings.style&FONTF_BOLD ? FIDF_CLASSHEADER : FIDF_CLASSGENERAL); + fid.deffontsettings.charset = lf.lfCharSet; + _tcsncpy(fid.deffontsettings.szFace, lf.lfFaceName, LF_FACESIZE); + if (i==IPFONTCOUNT-1){ + _tcsncpy(fid.backgroundGroup, _T(""), SIZEOF(fid.backgroundGroup)); + _tcsncpy(fid.backgroundName, _T(""), SIZEOF(fid.backgroundName)); + _tcsncpy(fid.group, _T("TabSRMM"), SIZEOF(fid.group)); + } + FontRegisterT(&fid); + } + + fontOptionsList = CHAT_fontOptionsList; + fid.flags = FIDF_DEFAULTVALID|FIDF_ALLOWEFFECTS; + fid.flags&=~FIDF_SAVEPOINTSIZE; + _tcsncpy(fid.group, _T("TabSRMM/Group Chats"), SIZEOF(fid.group)); + strncpy(fid.dbSettingsGroup, CHAT_FONTMODULE, SIZEOF(fid.dbSettingsGroup)); + for (i=0; i < msgDlgFontCount; i++) { + LoadMsgDlgFont(FONTSECTION_CHAT, i , &lf, &fontOptionsList[i].colour, CHAT_FONTMODULE); + mir_snprintf(szTemp, SIZEOF(szTemp), "Font%d", i); + strncpy(fid.prefix, szTemp, SIZEOF(fid.prefix)); + fid.order = i; + _tcsncpy(fid.name, fontOptionsList[i].szDescr, SIZEOF(fid.name)); + fid.deffontsettings.colour = fontOptionsList[i].colour; + fid.deffontsettings.size = (char) lf.lfHeight; + fid.deffontsettings.style = (lf.lfWeight >= FW_BOLD ? FONTF_BOLD : 0) | (lf.lfItalic ? FONTF_ITALIC : 0); + fid.flags = fid.flags & ~FIDF_CLASSMASK | (fid.deffontsettings.style&FONTF_BOLD ? FIDF_CLASSHEADER : FIDF_CLASSGENERAL); + fid.deffontsettings.charset = lf.lfCharSet; + _tcsncpy(fid.deffontsettings.szFace, lf.lfFaceName, LF_FACESIZE); + _tcsncpy(fid.backgroundGroup, _T("TabSRMM/Group Chats"), SIZEOF(fid.backgroundGroup)); + _tcsncpy(fid.backgroundName, _T("Group chat log background"), SIZEOF(fid.backgroundName)); + if (i == 18 || i == 19) + _tcsncpy(fid.backgroundName, _T("Userlist background"), SIZEOF(fid.backgroundName)); + FontRegisterT(&fid); + } + + _tcsncpy(cid.group, _T("TabSRMM/Group Chats"), SIZEOF(cid.group)); + strncpy(cid.dbSettingsGroup, "Chat", SIZEOF(cid.dbSettingsGroup)); + for (i=0; i <= 7; i++) { + mir_snprintf(szTemp, SIZEOF(szTemp), "NickColor%d", i); + _tcsncpy(cid.name, chatcolorsnames[i], SIZEOF(cid.name)); + cid.order=i+1; + strncpy(cid.setting, szTemp, SIZEOF(cid.setting)); + switch (i) { + case 5: + cid.defcolour = GetSysColor(COLOR_HIGHLIGHT); + break; + case 6: + cid.defcolour = GetSysColor(COLOR_HIGHLIGHTTEXT); + break; + default: + cid.defcolour =RGB(0, 0, 0); + break; + } + ColourRegisterT(&cid); + } + cid.order=8; + _tcsncpy(cid.name, _T("Userlist background"), SIZEOF(cid.name)); + strncpy(cid.setting, "ColorNicklistBG", SIZEOF(cid.setting)); + cid.defcolour = SRMSGDEFSET_BKGCOLOUR; + ColourRegisterT(&cid); + + /* + * static colors (info panel, tool bar background etc...) + */ + strncpy(fid.dbSettingsGroup, FONTMODULE, SIZEOF(fid.dbSettingsGroup)); + strncpy(cid.dbSettingsGroup, FONTMODULE, SIZEOF(fid.dbSettingsGroup)); + + for (i=0; i < (sizeof(_clrs) / sizeof(_clrs[0])); i++) { + cid.order = _clrs[i].order; + _tcsncpy(cid.group, _clrs[i].tszGroup, SIZEOF(fid.group)); + _tcsncpy(cid.name, _clrs[i].tszName, SIZEOF(cid.name)); + strncpy(cid.setting, _clrs[i].szSetting, SIZEOF(cid.setting)); + if (_clrs[i].def & 0xff000000) + cid.defcolour = GetSysColor(_clrs[i].def & 0x000000ff); + else + cid.defcolour = _clrs[i].def; + ColourRegisterT(&cid); + } + + strncpy(cid.dbSettingsGroup, SRMSGMOD_T, SIZEOF(fid.dbSettingsGroup)); + + /* + * text and background colors for tabs + */ + for (i=0; i < (sizeof(_tabclrs) / sizeof(_tabclrs[0])); i++) { + cid.order = _tabclrs[i].order; + _tcsncpy(cid.group, _tabclrs[i].tszGroup, SIZEOF(fid.group)); + _tcsncpy(cid.name, _tabclrs[i].tszName, SIZEOF(cid.name)); + strncpy(cid.setting, _tabclrs[i].szSetting, SIZEOF(cid.setting)); + if (_tabclrs[i].def & 0xff000000) + cid.defcolour = GetSysColor(_tabclrs[i].def & 0x000000ff); + else + cid.defcolour = _tabclrs[i].def; + + ColourRegisterT(&cid); + } +} + +int FontServiceFontsChanged(WPARAM wParam, LPARAM lParam) +{ + if (PluginConfig.m_chat_enabled) { + LOGFONT lf; + HFONT hFont; + int iText; + + LoadLogFonts(); + FreeMsgLogBitmaps(); + LoadMsgLogBitmaps(); + + LoadMsgDlgFont(FONTSECTION_CHAT, 0, &lf, NULL, CHAT_FONTMODULE); + hFont = CreateFontIndirect(&lf); + iText = GetTextPixelSize(MakeTimeStamp(g_Settings.pszTimeStamp, time(NULL)), hFont, TRUE); + DeleteObject(hFont); + g_Settings.LogTextIndent = iText; + g_Settings.LogTextIndent = g_Settings.LogTextIndent * 12 / 10; + g_Settings.LogIndentEnabled = (M->GetByte("Chat", "LogIndentEnabled", 1) != 0) ? TRUE : FALSE; + + LoadGlobalSettings(); + MM_FontsChanged(); + MM_FixColors(); + SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE); + } + + PluginConfig.reloadSettings(); + CSkin::initAeroEffect(); + CacheMsgLogIcons(); + CacheLogFonts(); + FreeTabConfig(); + ReloadTabConfig(); + Skin->setupAeroSkins(); + M->BroadcastMessage(DM_OPTIONSAPPLIED, 1, 0); + return 0; +} + + +static UINT _o2chatcontrols[] = { IDC_CHAT_SPIN2, IDC_LIMIT, IDC_CHAT_SPIN4, IDC_LOGTIMESTAMP, IDC_TIMESTAMP, + IDC_OUTSTAMP, IDC_FONTCHOOSE, IDC_LOGGING, IDC_LOGDIRECTORY, IDC_INSTAMP, IDC_CHAT_SPIN2, IDC_CHAT_SPIN3, IDC_NICKROW2, IDC_LOGLIMIT, + IDC_STATIC110, IDC_STATIC112, 0}; + +static UINT _o3chatcontrols[] = {0}; + +INT_PTR CALLBACK DlgProcOptions2(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) { + case WM_INITDIALOG: { + + TranslateDialogDefault(hwndDlg); + + if (PluginConfig.m_chat_enabled) { + + SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN2, UDM_SETRANGE, 0, MAKELONG(5000, 0)); + SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN2, UDM_SETPOS, 0, MAKELONG(DBGetContactSettingWord(NULL, "Chat", "LogLimit", 100), 0)); + SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN3, UDM_SETRANGE, 0, MAKELONG(255, 10)); + SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN3, UDM_SETPOS, 0, MAKELONG(M->GetByte("Chat", "NicklistRowDist", 12), 0)); + SetDlgItemText(hwndDlg, IDC_LOGTIMESTAMP, g_Settings.pszTimeStampLog); + SetDlgItemText(hwndDlg, IDC_TIMESTAMP, g_Settings.pszTimeStamp); + SetDlgItemText(hwndDlg, IDC_OUTSTAMP, g_Settings.pszOutgoingNick); + SetDlgItemText(hwndDlg, IDC_INSTAMP, g_Settings.pszIncomingNick); + CheckDlgButton(hwndDlg, IDC_LOGGING, g_Settings.LoggingEnabled); + SetDlgItemText(hwndDlg, IDC_LOGDIRECTORY, g_Settings.pszLogDir); + Utils::enableDlgControl(hwndDlg, IDC_LOGDIRECTORY, g_Settings.LoggingEnabled ? TRUE : FALSE); + Utils::enableDlgControl(hwndDlg, IDC_FONTCHOOSE, g_Settings.LoggingEnabled ? TRUE : FALSE); + SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN4, UDM_SETRANGE, 0, MAKELONG(10000, 0)); + SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN4, UDM_SETPOS, 0, MAKELONG(DBGetContactSettingWord(NULL, "Chat", "LoggingLimit", 100), 0)); + Utils::enableDlgControl(hwndDlg, IDC_LIMIT, g_Settings.LoggingEnabled ? TRUE : FALSE); + + if (ServiceExists(MS_UTILS_REPLACEVARS)) { + TCHAR tszTooltipText[2048]; + + mir_sntprintf(tszTooltipText, SIZEOF(tszTooltipText), + _T("%s - %s\n%s - %s\n%s - %s\n\n") + _T("%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n\n") + _T("%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s"), + // contact vars + _T("%nick%"), TranslateT("nick of current contact (if defined)"), + _T("%proto%"), TranslateT("protocol name of current contact (if defined). Account name is used when protocol supports multiaccounts"), + _T("%userid%"), TranslateT("UserID of current contact (if defined). It is like UIN Number for ICQ, JID for Jabber, etc."), + // global vars + _T("%miranda_path%"), TranslateT("path to root miranda folder"), + _T("%miranda_profile%"), TranslateT("path to current miranda profile"), + _T("%miranda_profilename%"), TranslateT("name of current miranda profile (filename, without extension)"), + _T("%miranda_userdata%"), TranslateT("will return parsed string %miranda_profile%\\Profiles\\%miranda_profilename%"), + _T("%appdata%"), TranslateT("same as environment variable %APPDATA% for currently logged-on Windows user"), + _T("%username%"), TranslateT("username for currently logged-on Windows user"), + _T("%mydocuments%"), TranslateT("\"My Documents\" folder for currently logged-on Windows user"), + _T("%desktop%"), TranslateT("\"Desktop\" folder for currently logged-on Windows user"), + _T("%xxxxxxx%"), TranslateT("any environment variable defined in current Windows session (like %systemroot%, %allusersprofile%, etc.)"), + // date/time vars + _T("%d%"), TranslateT("day of month, 1-31"), + _T("%dd%"), TranslateT("day of month, 01-31"), + _T("%m%"), TranslateT("month number, 1-12"), + _T("%mm%"), TranslateT("month number, 01-12"), + _T("%mon%"), TranslateT("abbreviated month name"), + _T("%month%"), TranslateT("full month name"), + _T("%yy%"), TranslateT("year without century, 01-99"), + _T("%yyyy%"), TranslateT("year with century, 1901-9999"), + _T("%wday%"), TranslateT("abbreviated weekday name"), + _T("%weekday%"), TranslateT("full weekday name")); + hPathTip = CreateToolTip(GetDlgItem(hwndDlg, IDC_LOGDIRECTORY), tszTooltipText, TranslateT("Variables")); + } + + } else { + int i = 0; + + while (_o2chatcontrols[i]) + Utils::enableDlgControl(hwndDlg, _o2chatcontrols[i++], FALSE); + } + if (hPathTip) + SetTimer(hwndDlg, 0, 3000, NULL); + break; + } + case WM_COMMAND: + if ((LOWORD(wParam) == IDC_INSTAMP + || LOWORD(wParam) == IDC_OUTSTAMP + || LOWORD(wParam) == IDC_TIMESTAMP + || LOWORD(wParam) == IDC_LOGLIMIT + || LOWORD(wParam) == IDC_NICKROW2 + || LOWORD(wParam) == IDC_LOGDIRECTORY + || LOWORD(wParam) == IDC_LIMIT + || LOWORD(wParam) == IDC_LOGTIMESTAMP) + && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return 0; + + switch (LOWORD(wParam)) { + /* + * open the base directory for MUC logs, using a standard file selector + * dialog. Simply allows the user to view what log files are there + * and possibly delete archived logs. + */ + case IDC_MUC_OPENLOGBASEDIR: { + OPENFILENAME ofn = {0}; + SESSION_INFO si = {0}; + TCHAR tszReturnName[MAX_PATH]; + TCHAR tszInitialDir[_MAX_DRIVE + _MAX_PATH + 10]; + TCHAR tszTemp[MAX_PATH + 20], *p = 0, *p1 = 0; + + mir_sntprintf(tszTemp, MAX_PATH + 20, _T("%s"), g_Settings.pszLogDir); + + p = tszTemp; + while(*p && (*p == '\\' || *p == '.')) + p++; + + if (*p) { + if ((p1 = _tcschr(p, '\\'))) + *p1 = 0; + } + + mir_sntprintf(tszInitialDir, MAX_PATH, _T("%s%s"), M->getChatLogPath(), p); + if (PathFileExists(tszInitialDir)) + ofn.lpstrInitialDir = tszInitialDir; + else { + mir_sntprintf(tszInitialDir, MAX_PATH, _T("%s"), M->getChatLogPath()); + ofn.lpstrInitialDir = tszInitialDir; + } + + tszReturnName[0] = 0; + mir_sntprintf(tszTemp, SIZEOF(tszTemp), _T("%s%c*.*%c%c"), TranslateT("All Files"), 0, 0, 0); + + ofn.lpstrFilter = tszTemp; + ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; + ofn.hwndOwner = 0; + ofn.lpstrFile = tszReturnName; + ofn.nMaxFile = MAX_PATH; + ofn.nMaxFileTitle = MAX_PATH; + ofn.Flags = OFN_HIDEREADONLY | OFN_DONTADDTORECENT; + ofn.lpstrDefExt = _T("log"); + GetOpenFileName(&ofn); + break; + } + + case IDC_FONTCHOOSE: { + TCHAR tszDirectory[MAX_PATH]; + LPITEMIDLIST idList; + LPMALLOC psMalloc; + BROWSEINFO bi = {0}; + + if (SUCCEEDED(CoGetMalloc(1, &psMalloc))) { + TCHAR tszTemp[MAX_PATH]; + bi.hwndOwner = hwndDlg; + bi.pszDisplayName = tszDirectory; + bi.lpszTitle = TranslateT("Select Folder"); + bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_RETURNONLYFSDIRS; + bi.lpfn = BrowseCallbackProc; + bi.lParam = (LPARAM)tszDirectory; + + + idList = SHBrowseForFolder(&bi); + if (idList) { + const TCHAR *szUserDir = M->getUserDir(); + SHGetPathFromIDList(idList, tszDirectory); + lstrcat(tszDirectory, _T("\\")); + M->pathToRelative(tszDirectory, tszTemp, const_cast(szUserDir)); + SetWindowText(GetDlgItem(hwndDlg, IDC_LOGDIRECTORY), lstrlen(tszTemp) > 1 ? tszTemp : DEFLOGFILENAME); + } + psMalloc->Free(idList); + psMalloc->Release(); + } + break; + } + + case IDC_LOGGING: + if (PluginConfig.m_chat_enabled) { + Utils::enableDlgControl(hwndDlg, IDC_LOGDIRECTORY, IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE); + Utils::enableDlgControl(hwndDlg, IDC_FONTCHOOSE, IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE); + Utils::enableDlgControl(hwndDlg, IDC_LIMIT, IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE); + } + break; + } + + if (lParam != (LPARAM)NULL) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == 0 && ((LPNMHDR)lParam)->code == PSN_APPLY) { + int iLen; + TCHAR *p2 = NULL; + char *pszText = NULL; + TCHAR *ptszPath = NULL; + + if (PluginConfig.m_chat_enabled) { + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOGDIRECTORY)); + if (iLen > 0) { + TCHAR *pszText1 = (TCHAR *)malloc(iLen*sizeof(TCHAR) + 2); + GetDlgItemText(hwndDlg, IDC_LOGDIRECTORY, pszText1, iLen + 1); + M->WriteTString(NULL, "Chat", "LogDirectory", pszText1); + free(pszText1); + g_Settings.LoggingEnabled = IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE; + M->WriteByte("Chat", "LoggingEnabled", (BYTE)g_Settings.LoggingEnabled); + } else { + DBDeleteContactSetting(NULL, "Chat", "LogDirectory"); + M->WriteByte("Chat", "LoggingEnabled", 0); + } + SM_InvalidateLogDirectories(); + + iLen = SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN4, UDM_GETPOS, 0, 0); + DBWriteContactSettingWord(NULL, "Chat", "LoggingLimit", (WORD)iLen); + + iLen = SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN3, UDM_GETPOS, 0, 0); + if (iLen > 0) + M->WriteByte("Chat", "NicklistRowDist", (BYTE)iLen); + else + DBDeleteContactSetting(NULL, "Chat", "NicklistRowDist"); + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOGTIMESTAMP)); + if (iLen > 0) { + pszText = (char *)realloc(pszText, iLen + 1); + GetDlgItemTextA(hwndDlg, IDC_LOGTIMESTAMP, pszText, iLen + 1); + DBWriteContactSettingString(NULL, "Chat", "LogTimestamp", pszText); + } else DBDeleteContactSetting(NULL, "Chat", "LogTimestamp"); + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_TIMESTAMP)); + if (iLen > 0) { + pszText = (char *)realloc(pszText, iLen + 1); + GetDlgItemTextA(hwndDlg, IDC_TIMESTAMP, pszText, iLen + 1); + DBWriteContactSettingString(NULL, "Chat", "HeaderTime", pszText); + } else DBDeleteContactSetting(NULL, "Chat", "HeaderTime"); + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_INSTAMP)); + if (iLen > 0) { + pszText = (char *)realloc(pszText, iLen + 1); + GetDlgItemTextA(hwndDlg, IDC_INSTAMP, pszText, iLen + 1); + DBWriteContactSettingString(NULL, "Chat", "HeaderIncoming", pszText); + } else DBDeleteContactSetting(NULL, "Chat", "HeaderIncoming"); + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_OUTSTAMP)); + if (iLen > 0) { + pszText = (char *)realloc(pszText, iLen + 1); + GetDlgItemTextA(hwndDlg, IDC_OUTSTAMP, pszText, iLen + 1); + DBWriteContactSettingString(NULL, "Chat", "HeaderOutgoing", pszText); + } else DBDeleteContactSetting(NULL, "Chat", "HeaderOutgoing"); + + iLen = SendDlgItemMessage(hwndDlg, IDC_CHAT_SPIN2, UDM_GETPOS, 0, 0); + DBWriteContactSettingWord(NULL, "Chat", "LogLimit", (WORD)iLen); + } + + + if (pszText != NULL) + free(pszText); + if (hListBkgBrush) + DeleteObject(hListBkgBrush); + hListBkgBrush = CreateSolidBrush(M->GetDword("Chat", "ColorNicklistBG", SRMSGDEFSET_BKGCOLOUR)); + + + if (PluginConfig.m_chat_enabled) { + LOGFONT lf; + HFONT hFont; + int iText; + + LoadLogFonts(); + FreeMsgLogBitmaps(); + LoadMsgLogBitmaps(); + + LoadMsgDlgFont(FONTSECTION_CHAT, 0, &lf, NULL, CHAT_FONTMODULE); + hFont = CreateFontIndirect(&lf); + iText = GetTextPixelSize(MakeTimeStamp(g_Settings.pszTimeStamp, time(NULL)), hFont, TRUE); + DeleteObject(hFont); + g_Settings.LogTextIndent = iText; + g_Settings.LogTextIndent = g_Settings.LogTextIndent * 12 / 10; + g_Settings.LogIndentEnabled = (M->GetByte("Chat", "LogIndentEnabled", 1) != 0) ? TRUE : FALSE; + + LoadGlobalSettings(); + MM_FontsChanged(); + MM_FixColors(); + SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE); + } + + PluginConfig.reloadSettings(); + CacheMsgLogIcons(); + CacheLogFonts(); + return TRUE; + } + break; + case WM_TIMER: + if (IsWindow(hPathTip)) + KillTimer(hPathTip, 4); // It will prevent tooltip autoclosing + break; + case WM_DESTROY: + if (hPathTip) + { + KillTimer(hwndDlg, 0); + DestroyWindow(hPathTip); + hPathTip = 0; + } + break; + } + return FALSE; +} + +#define NR_GC_EVENTS 12 + +static UINT _eventorder[] = { GC_EVENT_ACTION, + GC_EVENT_MESSAGE, + GC_EVENT_NICK, + GC_EVENT_JOIN, + GC_EVENT_PART, + GC_EVENT_TOPIC, + GC_EVENT_ADDSTATUS, + GC_EVENT_INFORMATION, + GC_EVENT_QUIT, + GC_EVENT_KICK, + GC_EVENT_NOTICE, + GC_EVENT_HIGHLIGHT, + 0 +}; + +#define GC_EVENT_ALL (GC_EVENT_ACTION | GC_EVENT_MESSAGE | GC_EVENT_NICK | GC_EVENT_JOIN | \ + GC_EVENT_PART | GC_EVENT_TOPIC | GC_EVENT_ADDSTATUS | GC_EVENT_INFORMATION | GC_EVENT_QUIT | \ + GC_EVENT_KICK | GC_EVENT_NOTICE) + +/** + * Dialog procedure for group chat options tab #3 (event filter configuration) + * + * @return + */ +INT_PTR CALLBACK DlgProcOptions3(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) { + case WM_INITDIALOG: { + + TranslateDialogDefault(hwndDlg); + + if (PluginConfig.m_chat_enabled) { + DWORD dwFilterFlags = M->GetDword("Chat", "FilterFlags", GC_EVENT_ALL); + DWORD dwTrayFlags = M->GetDword("Chat", "TrayIconFlags", GC_EVENT_ALL); + DWORD dwPopupFlags = M->GetDword("Chat", "PopupFlags", GC_EVENT_ALL); + DWORD dwLogFlags = M->GetDword("Chat", "DiskLogFlags", GC_EVENT_ALL); + + for (int i = 0; _eventorder[i]; i++) { + if (_eventorder[i] != GC_EVENT_HIGHLIGHT) { + CheckDlgButton(hwndDlg, IDC_1 + i, dwFilterFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_L1 + i, dwLogFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED); + } + CheckDlgButton(hwndDlg, IDC_P1 + i, dwPopupFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_T1 + i, dwTrayFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED); + } + SendDlgItemMessage(hwndDlg, IDC_LOGICONTYPE, CB_ADDSTRING, -1, (LPARAM)TranslateT("No markers")); + SendDlgItemMessage(hwndDlg, IDC_LOGICONTYPE, CB_ADDSTRING, -1, (LPARAM)TranslateT("Show as icons")); + SendDlgItemMessage(hwndDlg, IDC_LOGICONTYPE, CB_ADDSTRING, -1, (LPARAM)TranslateT("Show as text symbols")); + + SendDlgItemMessage(hwndDlg, IDC_LOGICONTYPE, CB_SETCURSEL, (g_Settings.LogSymbols ? 2 : (g_Settings.dwIconFlags ? 1 : 0)), 0); + + CheckDlgButton(hwndDlg, IDC_NOPOPUPSFORCLOSEDWINDOWS, M->GetByte("Chat", "SkipWhenNoWindow", 0) ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_TRAYONLYFORINACTIVE, M->GetByte("Chat", "TrayIconInactiveOnly", 0) ? BST_CHECKED : BST_UNCHECKED); + } + break; + } + case WM_COMMAND: + if (lParam != (LPARAM)NULL) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->idFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: { + DWORD dwFilterFlags = 0, dwTrayFlags = 0, + dwPopupFlags = 0, dwLogFlags = 0; + + for (int i = 0; _eventorder[i]; i++) { + if (_eventorder[i] != GC_EVENT_HIGHLIGHT) { + dwFilterFlags |= (IsDlgButtonChecked(hwndDlg, IDC_1 + i) ? _eventorder[i] : 0); + dwLogFlags |= (IsDlgButtonChecked(hwndDlg, IDC_L1 + i) ? _eventorder[i] : 0); + } + dwPopupFlags |= (IsDlgButtonChecked(hwndDlg, IDC_P1 + i) ? _eventorder[i] : 0); + dwTrayFlags |= (IsDlgButtonChecked(hwndDlg, IDC_T1 + i) ? _eventorder[i] : 0); + } + M->WriteDword("Chat", "FilterFlags", dwFilterFlags); + M->WriteDword("Chat", "PopupFlags", dwPopupFlags); + M->WriteDword("Chat", "TrayIconFlags", dwTrayFlags); + M->WriteDword("Chat", "DiskLogFlags", dwLogFlags); + + LRESULT lr = SendDlgItemMessage(hwndDlg, IDC_LOGICONTYPE, CB_GETCURSEL, 0, 0); + + M->WriteDword("Chat", "IconFlags", lr == 1 ? 1 : 0); + M->WriteByte("Chat", "LogSymbols", lr == 2 ? 1 : 0); + + M->WriteByte("Chat", "SkipWhenNoWindow", IsDlgButtonChecked(hwndDlg, IDC_NOPOPUPSFORCLOSEDWINDOWS) ? 1 : 0); + M->WriteByte("Chat", "TrayIconInactiveOnly", IsDlgButtonChecked(hwndDlg, IDC_TRAYONLYFORINACTIVE) ? 1 : 0); + LoadGlobalSettings(); + MM_FontsChanged(); + SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE); + SM_ReconfigureFilters(); + break; + } + return TRUE; + } + } + break; + + case WM_DESTROY: + break; + + } + return FALSE; +} + +void LoadGlobalSettings(void) +{ + LOGFONT lf; + int i; + char szBuf[40]; + + g_Settings.LogLimitNames = M->GetByte("Chat", "LogLimitNames", 1); + g_Settings.ShowTime = M->GetByte("Chat", "ShowTimeStamp", 1); + g_Settings.ShowTimeIfChanged = (BOOL)M->GetByte("Chat", "ShowTimeStampIfChanged", 0); + g_Settings.TimeStampEventColour = (BOOL)M->GetByte("Chat", "TimeStampEventColour", 0); + g_Settings.iEventLimit = DBGetContactSettingWord(NULL, "Chat", "LogLimit", 100); + g_Settings.iEventLimitThreshold = DBGetContactSettingWord(NULL, "Chat", "LogLimitThreshold", 20); + g_Settings.dwIconFlags = M->GetDword("Chat", "IconFlags", 0x0000); + g_Settings.LoggingLimit = (size_t)DBGetContactSettingWord(NULL, "Chat", "LoggingLimit", 100); + g_Settings.LoggingEnabled = (BOOL)M->GetByte("Chat", "LoggingEnabled", 0); + g_Settings.OpenInDefault = (BOOL)M->GetByte("Chat", "DefaultContainer", 1); + g_Settings.FlashWindow = (BOOL)M->GetByte("Chat", "FlashWindow", 0); + g_Settings.FlashWindowHightlight = (BOOL)M->GetByte("Chat", "FlashWindowHighlight", 0); + g_Settings.HighlightEnabled = (BOOL)M->GetByte("Chat", "HighlightEnabled", 1); + g_Settings.crUserListColor = (BOOL)M->GetDword(CHAT_FONTMODULE, "Font18Col", RGB(0, 0, 0)); + g_Settings.crUserListBGColor = (BOOL)M->GetDword("Chat", "ColorNicklistBG", SRMSGDEFSET_BKGCOLOUR); + g_Settings.crUserListHeadingsColor = (BOOL)M->GetDword(CHAT_FONTMODULE, "Font19Col", RGB(170, 170, 170)); + g_Settings.StripFormat = (BOOL)M->GetByte("Chat", "StripFormatting", 0); + g_Settings.TrayIconInactiveOnly = (BOOL)M->GetByte("Chat", "TrayIconInactiveOnly", 1); + g_Settings.BBCodeInPopups = (BOOL)M->GetByte("Chat", "BBCodeInPopups", 0); + g_Settings.AddColonToAutoComplete = (BOOL)M->GetByte("Chat", "AddColonToAutoComplete", 1); + g_Settings.iPopupStyle = M->GetByte("Chat", "PopupStyle", 1); + g_Settings.iPopupTimeout = DBGetContactSettingWord(NULL, "Chat", "PopupTimeout", 3); + g_Settings.crPUBkgColour = M->GetDword("Chat", "PopupColorBG", GetSysColor(COLOR_WINDOW)); + g_Settings.crPUTextColour = M->GetDword("Chat", "PopupColorText", 0); + g_Settings.ClassicIndicators = M->GetByte("Chat", "ClassicIndicators", 0); + //MAD + g_Settings.LogClassicIndicators = M->GetByte("Chat", "LogClassicIndicators", 0); + g_Settings.AlternativeSorting = M->GetByte("Chat", "AlternativeSorting", 1); + g_Settings.AnnoyingHighlight = M->GetByte("Chat", "AnnoyingHighlight", 0); + g_Settings.CreateWindowOnHighlight = M->GetByte("Chat", "CreateWindowOnHighlight", 1); + //MAD_ + g_Settings.LogSymbols = M->GetByte("Chat", "LogSymbols", 1); + g_Settings.ClickableNicks = M->GetByte("Chat", "ClickableNicks", 1); + g_Settings.ColorizeNicks = M->GetByte("Chat", "ColorizeNicks", 1); + g_Settings.ColorizeNicksInLog = M->GetByte("Chat", "ColorizeNicksInLog", 1); + g_Settings.ScaleIcons = M->GetByte("Chat", "ScaleIcons", 1); + g_Settings.UseDividers = M->GetByte("Chat", "UseDividers", 1); + g_Settings.DividersUsePopupConfig = M->GetByte("Chat", "DividersUsePopupConfig", 1); + g_Settings.MathMod = ServiceExists(MATH_RTF_REPLACE_FORMULAE) && M->GetByte("Chat", "MathModSupport", 0); + + g_Settings.DoubleClick4Privat = (BOOL)M->GetByte("Chat", "DoubleClick4Privat", 0); + g_Settings.ShowContactStatus = M->GetByte("Chat", "ShowContactStatus", 1); + g_Settings.ContactStatusFirst = M->GetByte("Chat", "ContactStatusFirst", 0); + + + if (hListBkgBrush) + DeleteObject(hListBkgBrush); + hListBkgBrush = CreateSolidBrush(M->GetDword("Chat", "ColorNicklistBG", SRMSGDEFSET_BKGCOLOUR)); + + InitSetting(&g_Settings.pszTimeStamp, "HeaderTime", _T("[%H:%M]")); + InitSetting(&g_Settings.pszTimeStampLog, "LogTimestamp", _T("[%d %b %y %H:%M]")); + InitSetting(&g_Settings.pszIncomingNick, "HeaderIncoming", _T("%n:")); + InitSetting(&g_Settings.pszOutgoingNick, "HeaderOutgoing", _T("%n:")); + + DBVARIANT dbv; + + if (!M->GetTString(NULL, "Chat", "LogDirectory", &dbv)) { + lstrcpyn(g_Settings.pszLogDir, dbv.ptszVal, MAX_PATH); + DBFreeVariant(&dbv); + } else + lstrcpyn(g_Settings.pszLogDir, DEFLOGFILENAME, MAX_PATH); + + g_Settings.pszLogDir[MAX_PATH - 1] = 0; + + g_Settings.LogIndentEnabled = (M->GetByte("Chat", "LogIndentEnabled", 1) != 0) ? TRUE : FALSE; + + + // nicklist + + if (g_Settings.UserListFont) { + DeleteObject(g_Settings.UserListFont); + DeleteObject(g_Settings.UserListHeadingsFont); + } + + LoadMsgDlgFont(FONTSECTION_CHAT, 18, &lf, NULL, CHAT_FONTMODULE); + g_Settings.UserListFont = CreateFontIndirect(&lf); + + LoadMsgDlgFont(FONTSECTION_CHAT, 19, &lf, NULL, CHAT_FONTMODULE); + g_Settings.UserListHeadingsFont = CreateFontIndirect(&lf); + + int ih; + int ih2; + + ih = GetTextPixelSize(_T("AQGglo"), g_Settings.UserListFont, FALSE); + ih2 = GetTextPixelSize(_T("AQGglo"), g_Settings.UserListHeadingsFont, FALSE); + g_Settings.iNickListFontHeight = max(M->GetByte("Chat", "NicklistRowDist", 12), (ih > ih2 ? ih : ih2)); + + for (i=0; i < 7; i++) { + mir_snprintf(szBuf, 20, "NickColor%d", i); + g_Settings.nickColors[i] = M->GetDword("Chat", szBuf, g_Settings.crUserListColor); + } + g_Settings.nickColors[5] = M->GetDword("Chat", "NickColor5", GetSysColor(COLOR_HIGHLIGHT)); + g_Settings.nickColors[6] = M->GetDword("Chat", "NickColor6", GetSysColor(COLOR_HIGHLIGHTTEXT)); + if (g_Settings.SelectionBGBrush) + DeleteObject(g_Settings.SelectionBGBrush); + g_Settings.SelectionBGBrush = CreateSolidBrush(g_Settings.nickColors[5]); +} + +static void FreeGlobalSettings(void) +{ + mir_free(g_Settings.pszTimeStamp); + mir_free(g_Settings.pszTimeStampLog); + mir_free(g_Settings.pszIncomingNick); + mir_free(g_Settings.pszOutgoingNick); + if (g_Settings.UserListFont) { + DeleteObject(g_Settings.UserListFont); + DeleteObject(g_Settings.UserListHeadingsFont); + } + if (g_Settings.SelectionBGBrush) + DeleteObject(g_Settings.SelectionBGBrush); + + delete g_Settings.Highlight; +} + +int OptionsInit(void) +{ + LOGFONT lf; + HFONT hFont; + int iText; + + LoadLogFonts(); + LoadMsgDlgFont(FONTSECTION_CHAT, 17, &lf, NULL, CHAT_FONTMODULE); + lstrcpy(lf.lfFaceName, _T("MS Shell Dlg")); + lf.lfUnderline = lf.lfItalic = lf.lfStrikeOut = 0; + lf.lfHeight = -17; + lf.lfWeight = FW_BOLD; + ZeroMemory(&g_Settings, sizeof(TMUCSettings)); + g_Settings.NameFont = CreateFontIndirect(&lf); + g_Settings.iSplitterX = DBGetContactSettingWord(NULL, "Chat", "SplitterX", 105); + if (g_Settings.iSplitterX <= 50) + g_Settings.iSplitterX = 105; + g_Settings.iSplitterY = DBGetContactSettingWord(NULL, "Chat", "splitY", 50); + if (g_Settings.iSplitterY <= 20) + g_Settings.iSplitterY = 50; + g_Settings.hGroup = 0; + LoadGlobalSettings(); + g_Settings.Highlight = new CMUCHighlight(); + + SkinAddNewSoundEx("ChatMessage", LPGEN("Group chats"), LPGEN("Incoming message")); + SkinAddNewSoundEx("ChatSent", LPGEN("Group chats"), LPGEN("Outgoing message")); + SkinAddNewSoundEx("ChatHighlight", LPGEN("Group chats"), LPGEN("Message is highlighted")); + SkinAddNewSoundEx("ChatAction", LPGEN("Group chats"), LPGEN("User has performed an action")); + SkinAddNewSoundEx("ChatJoin", LPGEN("Group chats"), LPGEN("User has joined")); + SkinAddNewSoundEx("ChatPart", LPGEN("Group chats"), LPGEN("User has left")); + SkinAddNewSoundEx("ChatKick", LPGEN("Group chats"), LPGEN("User has kicked some other user")); + SkinAddNewSoundEx("ChatMode", LPGEN("Group chats"), LPGEN("User's status was changed")); + SkinAddNewSoundEx("ChatNick", LPGEN("Group chats"), LPGEN("User has changed name")); + SkinAddNewSoundEx("ChatNotice", LPGEN("Group chats"), LPGEN("User has sent a notice")); + SkinAddNewSoundEx("ChatQuit", LPGEN("Group chats"), LPGEN("User has disconnected")); + SkinAddNewSoundEx("ChatTopic", LPGEN("Group chats"), LPGEN("The topic has been changed")); + + LoadMsgDlgFont(FONTSECTION_CHAT, 0, &lf, NULL, CHAT_FONTMODULE); + hFont = CreateFontIndirect(&lf); + iText = GetTextPixelSize(MakeTimeStamp(g_Settings.pszTimeStamp, time(NULL)), hFont, TRUE); + DeleteObject(hFont); + g_Settings.LogTextIndent = iText; + g_Settings.LogTextIndent = g_Settings.LogTextIndent * 12 / 10; + return 0; +} + + +int OptionsUnInit(void) +{ + FreeGlobalSettings(); + UnhookEvent(g_hOptions); + DeleteObject(hListBkgBrush); + DeleteObject(g_Settings.NameFont); + return 0; +} diff --git a/plugins/TabSRMM/src/chat/services.cpp b/plugins/TabSRMM/src/chat/services.cpp new file mode 100644 index 0000000000..edd9f25d79 --- /dev/null +++ b/plugins/TabSRMM/src/chat/services.cpp @@ -0,0 +1,882 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * This code is based on and still contains large parts of the the + * original chat module for Miranda NG, written and copyrighted + * by Joergen Persson in 2005. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: services.cpp 13046 2010-10-28 10:02:50Z silvercircle $ + * + * This implements the services that form the group chat API + * + */ + +#include "..\commonheaders.h" + +// defs +extern HICON hIcons[30]; + +CRITICAL_SECTION cs; + +HANDLE hSendEvent; +HANDLE hBuildMenuEvent; +HANDLE hJoinMenuItem, hLeaveMenuItem; +HANDLE g_hHookPrebuildMenu; + +static HANDLE + hServiceRegister = NULL, + hServiceNewChat = NULL, + hServiceAddEvent = NULL, + hServiceGetAddEventPtr = NULL, + hServiceGetInfo = NULL, + hServiceGetCount = NULL, + hEventPrebuildMenu = NULL, + hEventDoubleclicked = NULL, + hEventJoinChat = NULL, + hEventLeaveChat = NULL; + +int Chat_ModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + if (!PluginConfig.m_chat_enabled) + return 0; + + char * mods[3] = {"Chat", CHAT_FONTMODULE}; + CallService("DBEditorpp/RegisterModule", (WPARAM)mods, (LPARAM)2); + + LoadIcons(); + + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.position = -2000090001; + mi.flags = CMIF_DEFAULT | CMIF_ICONFROMICOLIB; + mi.icolibItem = LoadSkinnedIconHandle( SKINICON_CHAT_JOIN ); + mi.pszName = LPGEN("&Join"); + mi.pszService = "GChat/JoinChat"; + hJoinMenuItem = Menu_AddContactMenuItem(&mi); + + mi.position = -2000090000; + mi.flags = CMIF_NOTOFFLINE | CMIF_ICONFROMICOLIB; + mi.icolibItem = LoadSkinnedIconHandle( SKINICON_CHAT_LEAVE ); + mi.pszName = LPGEN("&Leave"); + mi.pszService = "GChat/LeaveChat"; + hLeaveMenuItem = Menu_AddContactMenuItem(&mi); + + CList_SetAllOffline(TRUE, NULL); + + g_Settings.MathMod = ServiceExists(MATH_RTF_REPLACE_FORMULAE) && M->GetByte("Chat", "MathModSupport", 0); + return 0; +} + +int Chat_PreShutdown() +{ + SM_RemoveAll(); + MM_RemoveAll(); + return 0; +} + +int Chat_IconsChanged(WPARAM wParam, LPARAM lParam) +{ + FreeMsgLogBitmaps(); + + LoadLogIcons(); + LoadMsgLogBitmaps(); + //MM_IconsChanged(); + SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, FALSE); + return 0; +} + +INT_PTR Service_GetCount(WPARAM wParam, LPARAM lParam) +{ + int i; + + if (!lParam) + return -1; + + EnterCriticalSection(&cs); + + i = SM_GetCount((char *)lParam); + + LeaveCriticalSection(&cs); + return i; +} + +INT_PTR Service_GetInfo(WPARAM wParam, LPARAM lParam) +{ + GC_INFO * gci = (GC_INFO *) lParam; + SESSION_INFO* si = NULL; + + if (!gci || !gci->pszModule) + return 1; + + EnterCriticalSection(&cs); + + if (gci->Flags&BYINDEX) + si = SM_FindSessionByIndex(gci->pszModule, gci->iItem); + else + si = SM_FindSession(gci->pszID, gci->pszModule); + + if (si) { + if (gci->Flags & DATA) gci->dwItemData = si->dwItemData; + if (gci->Flags & HCONTACT) gci->hContact = si->hContact; + if (gci->Flags & TYPE) gci->iType = si->iType; + if (gci->Flags & COUNT) gci->iCount = si->nUsersInNicklist; + if (gci->Flags & USERS) gci->pszUsers = SM_GetUsers(si); + + if (si->dwFlags & GC_UNICODE) { + if (gci->Flags & ID) gci->pszID = si->ptszID; + if (gci->Flags & NAME) gci->pszName = si->ptszName; + } + else { + if (gci->Flags & ID) gci->pszID = (TCHAR*)si->pszID; + if (gci->Flags & NAME) gci->pszName = (TCHAR*)si->pszName; + } + LeaveCriticalSection(&cs); + return 0; + } + + LeaveCriticalSection(&cs); + return 1; +} + +INT_PTR Service_Register(WPARAM wParam, LPARAM lParam) +{ + GCREGISTER *gcr = (GCREGISTER *)lParam; + MODULEINFO * mi = NULL; + if (gcr == NULL) + return GC_REGISTER_ERROR; + + if (gcr->cbSize != sizeof(GCREGISTER)) + return GC_REGISTER_WRONGVER; + + EnterCriticalSection(&cs); + + mi = MM_AddModule(gcr->pszModule); + if (mi) { + mi->ptszModDispName = a2tf( gcr->ptszModuleDispName, gcr->dwFlags); + mi->bBold = gcr->dwFlags & GC_BOLD; + mi->bUnderline = gcr->dwFlags & GC_UNDERLINE ; + mi->bItalics = gcr->dwFlags & GC_ITALICS ; + mi->bColor = gcr->dwFlags & GC_COLOR ; + mi->bBkgColor = gcr->dwFlags & GC_BKGCOLOR ; + mi->bAckMsg = gcr->dwFlags & GC_ACKMSG ; + mi->bChanMgr = gcr->dwFlags & GC_CHANMGR ; + mi->iMaxText = gcr->iMaxText; + mi->nColorCount = gcr->nColors; + if (gcr->nColors > 0) { + mi->crColors = (COLORREF *)mir_alloc(sizeof(COLORREF) * gcr->nColors); + memcpy(mi->crColors, gcr->pColors, sizeof(COLORREF) * gcr->nColors); + } + mi->pszHeader = 0; + + CheckColorsInModule((char*)gcr->pszModule); + CList_SetAllOffline(TRUE, gcr->pszModule); + + LeaveCriticalSection(&cs); + return 0; + } + + LeaveCriticalSection(&cs); + return GC_REGISTER_ERROR; +} + +INT_PTR Service_NewChat(WPARAM wParam, LPARAM lParam) +{ + MODULEINFO* mi; + GCSESSION *gcw = (GCSESSION *)lParam; + if (gcw == NULL) + return GC_NEWSESSION_ERROR; + + if (gcw->cbSize != sizeof(GCSESSION)) + return GC_NEWSESSION_WRONGVER; + + EnterCriticalSection(&cs); + + if ((mi = MM_FindModule(gcw->pszModule)) != NULL) { + TCHAR* ptszID = a2tf(gcw->ptszID, gcw->dwFlags); + SESSION_INFO* si = SM_AddSession(ptszID, gcw->pszModule); + + // create a new session and set the defaults + if (si != NULL) { + TCHAR szTemp[256]; + + si->dwItemData = gcw->dwItemData; + if (gcw->iType != GCW_SERVER) + si->wStatus = ID_STATUS_ONLINE; + si->iType = gcw->iType; + si->dwFlags = gcw->dwFlags; + si->ptszName = a2tf(gcw->ptszName, gcw->dwFlags); + si->ptszStatusbarText = a2tf(gcw->ptszStatusbarText, gcw->dwFlags); + si->iSplitterX = g_Settings.iSplitterX; + si->bFilterEnabled = M->GetByte(si->hContact, "Chat", "FilterEnabled", M->GetByte("Chat", "FilterEnabled", 0)); + si->bNicklistEnabled = M->GetByte("Chat", "ShowNicklist", 1); + if (!(gcw->dwFlags & GC_UNICODE)) { + si->pszID = mir_strdup(gcw->pszID); + si->pszName = mir_strdup(gcw->pszName); + } + + if (mi->bColor) { + si->iFG = 4; + si->bFGSet = TRUE; + } + if (mi->bBkgColor) { + si->iBG = 2; + si->bBGSet = TRUE; + } + if (si->iType == GCW_SERVER) + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("Server: %s"), si->ptszName); + else + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s"), si->ptszName); + si->hContact = CList_AddRoom(gcw->pszModule, ptszID, szTemp, si->iType); + DBWriteContactSettingString(si->hContact, si->pszModule , "Topic", ""); + DBDeleteContactSetting(si->hContact, "CList", "StatusMsg"); + if (si->ptszStatusbarText) + M->WriteTString(si->hContact, si->pszModule, "StatusBar", si->ptszStatusbarText); + else + DBWriteContactSettingString(si->hContact, si->pszModule, "StatusBar", ""); + if (si->hContact) + Chat_SetFilters(si); + } + else { + SESSION_INFO* si2 = SM_FindSession(ptszID, gcw->pszModule); + if (si2) { + + UM_RemoveAll(&si2->pUsers); + TM_RemoveAll(&si2->pStatuses); + + si2->iStatusCount = 0; + si2->nUsersInNicklist = 0; + + if (si2->hContact) + Chat_SetFilters(si2); + if (si2->hWnd) + RedrawWindow(GetDlgItem(si2->hWnd, IDC_LIST), NULL, NULL, RDW_INVALIDATE); + } + } + + LeaveCriticalSection(&cs); + mir_free(ptszID); + return 0; + } + + LeaveCriticalSection(&cs); + return GC_NEWSESSION_ERROR; +} + +static int DoControl(GCEVENT * gce, WPARAM wp) +{ + SESSION_INFO* si; + + switch(gce->pDest->iType) { + case GC_EVENT_CONTROL: + switch (wp) { + case WINDOW_HIDDEN: + si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + si->bInitDone = TRUE; + SetActiveSession(si->ptszID, si->pszModule); + if (si->hWnd) + ShowRoom(si, wp, FALSE); + } + return 0; + + case WINDOW_MINIMIZE: + case WINDOW_MAXIMIZE: + case WINDOW_VISIBLE: + case SESSION_INITDONE: + si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + si->bInitDone = TRUE; + if (wp != SESSION_INITDONE || M->GetByte("Chat", "PopupOnJoin", 0) == 0) + ShowRoom(si, wp, TRUE); + return 0; + } + break; + + case SESSION_OFFLINE: + SM_SetOffline(gce->pDest->ptszID, gce->pDest->pszModule); + // fall through + + case SESSION_ONLINE: + SM_SetStatus(gce->pDest->ptszID, gce->pDest->pszModule, wp == SESSION_ONLINE ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE); + break; + + case WINDOW_CLEARLOG: + si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + LM_RemoveAll(&si->pLog, &si->pLogEnd); + si->iEventCount = 0; + si->LastTime = 0; + } + break; + + case SESSION_TERMINATE: + return SM_RemoveSession(gce->pDest->ptszID, gce->pDest->pszModule, (gce->dwFlags & GCEF_REMOVECONTACT) != 0); + } + SM_SendMessage(gce->pDest->ptszID, gce->pDest->pszModule, GC_EVENT_CONTROL + WM_USER + 500, wp, 0); + break; + + case GC_EVENT_CHUID: + if (gce->pszText) + SM_ChangeUID(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszNick, gce->ptszText); + break; + + case GC_EVENT_CHANGESESSIONAME: + if (gce->pszText) { + si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + replaceStr(&si->ptszName, gce->ptszText); + if (si->hWnd) + SendMessage(si->hWnd, GC_UPDATETITLE, 0, 0); + } + } + break; + + case GC_EVENT_SETITEMDATA: + si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) + si->dwItemData = gce->dwItemData; + break; + + case GC_EVENT_GETITEMDATA: + si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + gce->dwItemData = si->dwItemData; + return si->dwItemData; + } + return 0; + + case GC_EVENT_SETSBTEXT: + si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + replaceStr(&si->ptszStatusbarText, gce->ptszText); + if (si->ptszStatusbarText) + M->WriteTString(si->hContact, si->pszModule, "StatusBar", si->ptszStatusbarText); + else + DBWriteContactSettingString(si->hContact, si->pszModule, "StatusBar", ""); + if (si->hWnd) + SendMessage(si->hWnd, GC_UPDATESTATUSBAR, 0, 0); + } + break; + + case GC_EVENT_ACK: + SM_SendMessage(gce->pDest->ptszID, gce->pDest->pszModule, GC_ACKMESSAGE, 0, 0); + break; + + case GC_EVENT_SENDMESSAGE: + if (gce->pszText) + SM_SendUserMessage(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszText); + break; + + case GC_EVENT_SETSTATUSEX: + SM_SetStatusEx(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszText, gce->dwItemData); + break; + + default: + return 1; + } + return 0; +} + +static void AddUser(GCEVENT * gce) +{ + SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + WORD status = TM_StringToWord(si->pStatuses, gce->ptszStatus); + USERINFO * ui = SM_AddUser(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID, gce->ptszNick, status); + if (ui) { + ui->pszNick = mir_tstrdup(gce->ptszNick); + + if (gce->bIsMe) + si->pMe = ui; + + ui->Status = status; + ui->Status |= si->pStatuses->Status; + + if (si->hWnd) { + SendMessage(si->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0); + if (si->dat) + GetMyNick(si->dat); + } + } + } +} + +HWND CreateNewRoom(TContainerData *pContainer, SESSION_INFO *si, BOOL bActivateTab, BOOL bPopupContainer, BOOL bWantPopup) +{ + HANDLE hContact = si->hContact; + if (M->FindWindow(hContact) != 0) + return 0; + + if (hContact != 0 && M->GetByte("limittabs", 0) && !_tcsncmp(pContainer->szName, _T("default"), 6)) { + if ((pContainer = FindMatchingContainer(_T("default"), hContact)) == NULL) { + TCHAR szName[CONTAINER_NAMELEN + 1]; + + _sntprintf(szName, CONTAINER_NAMELEN, _T("default")); + pContainer = CreateContainer(szName, CNT_CREATEFLAG_CLONED, hContact); + } + } + + TNewWindowData newData = { 0 }; + newData.hContact = hContact; + newData.isWchar = 0; + newData.szInitialText = NULL; + memset(&newData.item, 0, sizeof(newData.item)); + + TCHAR *contactName = (TCHAR *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) newData.hContact, GCDNF_TCHAR); + + /* + * cut nickname if larger than x chars... + */ + + TCHAR newcontactname[128]; + if ( lstrlen(contactName) > 0) { + if (M->GetByte("cuttitle", 0)) + CutContactName(contactName, newcontactname, safe_sizeof(newcontactname)); + else { + lstrcpyn(newcontactname, contactName, safe_sizeof(newcontactname)); + newcontactname[127] = 0; + } + } + else lstrcpyn(newcontactname, _T("_U_"), SIZEOF(newcontactname)); + + char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) newData.hContact, 0); + WORD wStatus = szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord((HANDLE) newData.hContact, szProto, "Status", ID_STATUS_OFFLINE); + char *szStatus = (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord((HANDLE)newData.hContact, szProto, "Status", ID_STATUS_OFFLINE), 0); + + newData.item.pszText = newcontactname; + newData.item.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; + newData.item.iImage = 0; + + HWND hwndTab = GetDlgItem(pContainer->hwnd, 1159); + + // hide the active tab + if (pContainer->hwndActive && bActivateTab) + ShowWindow(pContainer->hwndActive, SW_HIDE); + + { + int iTabIndex_wanted = M->GetDword(hContact, "tabindex", pContainer->iChilds * 100); + int iCount = TabCtrl_GetItemCount(hwndTab); + TCITEM item = {0}; + HWND hwnd; + struct TWindowData *dat; + int relPos; + int i; + + pContainer->iTabIndex = iCount; + if (iCount > 0) { + for (i = iCount - 1; i >= 0; i--) { + item.mask = TCIF_PARAM; + TabCtrl_GetItem(hwndTab, i, &item); + hwnd = (HWND)item.lParam; + dat = (struct TWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (dat) { + relPos = M->GetDword(dat->hContact, "tabindex", i * 100); + if (iTabIndex_wanted <= relPos) + pContainer->iTabIndex = i; + } + } + } + } + + int newItem = TabCtrl_InsertItem(hwndTab, pContainer->iTabIndex, &newData.item); + SendMessage(hwndTab, EM_REFRESHWITHOUTCLIP, 0, 0); + if (bActivateTab) + TabCtrl_SetCurSel(hwndTab, newItem); + newData.iTabID = newItem; + newData.iTabImage = newData.item.iImage; + newData.pContainer = pContainer; + newData.iActivate = (int) bActivateTab; + pContainer->iChilds++; + newData.bWantPopup = bWantPopup; + newData.hdbEvent = (HANDLE)si; + HWND hwndNew = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CHANNEL), GetDlgItem(pContainer->hwnd, 1159), RoomWndProc, (LPARAM) & newData); + if (pContainer->dwFlags & CNT_SIDEBAR) { + TWindowData *dat = (TWindowData *)GetWindowLongPtr(hwndNew, GWLP_USERDATA); + if (dat) + pContainer->SideBar->addSession(dat, pContainer->iTabIndex); + } + SendMessage(pContainer->hwnd, WM_SIZE, 0, 0); + // if the container is minimized, then pop it up... + if (IsIconic(pContainer->hwnd)) { + if (bPopupContainer) { + SendMessage(pContainer->hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); + SetFocus(pContainer->hwndActive); + } + else { + if (pContainer->dwFlags & CNT_NOFLASH) + SendMessage(pContainer->hwnd, DM_SETICON, 0, (LPARAM)LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); + else + FlashContainer(pContainer, 1, 0); + } + } + if (bActivateTab) { + if (PluginConfig.m_HideOnClose && !IsWindowVisible(pContainer->hwnd)) { + WINDOWPLACEMENT wp={0}; + wp.length = sizeof(wp); + GetWindowPlacement(pContainer->hwnd, &wp); + + BroadCastContainer(pContainer, DM_CHECKSIZE, 0, 0); // make sure all tabs will re-check layout on activation + if (wp.showCmd == SW_SHOWMAXIMIZED) + ShowWindow(pContainer->hwnd, SW_SHOWMAXIMIZED); + else { + if (bPopupContainer) + ShowWindow(pContainer->hwnd, SW_SHOWNORMAL); + else + ShowWindow(pContainer->hwnd, SW_SHOWMINNOACTIVE); + } + SendMessage(pContainer->hwndActive, WM_SIZE, 0, 0); + SetFocus(hwndNew); + } + else { + SetFocus(hwndNew); + RedrawWindow(pContainer->hwnd, NULL, NULL, RDW_INVALIDATE); + UpdateWindow(pContainer->hwnd); + if (GetForegroundWindow() != pContainer->hwnd && bPopupContainer == TRUE) + SetForegroundWindow(pContainer->hwnd); + } + } + + if (PluginConfig.m_bIsWin7 && PluginConfig.m_useAeroPeek && CSkin::m_skinEnabled && !M->GetByte("forceAeroPeek", 0)) + CWarning::show(CWarning::WARN_AEROPEEK_SKIN, MB_ICONWARNING|MB_OK); + return hwndNew; // return handle of the new dialog +} + +void ShowRoom(SESSION_INFO* si, WPARAM wp, BOOL bSetForeground) +{ + if (!si) + return; + + if (si->hWnd != NULL) { + ActivateExistingTab(si->pContainer, si->hWnd); + return; + } + + TCHAR szName[CONTAINER_NAMELEN + 2]; + TContainerData *pContainer = si->pContainer; + + szName[0] = 0; + if (pContainer == NULL) { + GetContainerNameForContact(si->hContact, szName, CONTAINER_NAMELEN); + if (!g_Settings.OpenInDefault && !_tcscmp(szName, _T("default"))) + _tcsncpy(szName, _T("Chat Rooms"), CONTAINER_NAMELEN); + szName[CONTAINER_NAMELEN] = 0; + pContainer = FindContainerByName(szName); + } + if (pContainer == NULL) + pContainer = CreateContainer(szName, FALSE, si->hContact); + si->hWnd = CreateNewRoom(pContainer, si, TRUE, TRUE, FALSE); +} + +INT_PTR Service_AddEvent(WPARAM wParam, LPARAM lParam) +{ + GCEVENT *gce = (GCEVENT*)lParam; + GCDEST *gcd = NULL; + GCEVENT save_gce; + GCDEST save_gcd; + TCHAR* pWnd = NULL; + char* pMod = NULL; + BOOL bIsHighlighted = FALSE; + BOOL bRemoveFlag = FALSE; + int iRetVal = GC_EVENT_ERROR; + SESSION_INFO *si = NULL; + BOOL fFreeText = FALSE; + + if (CMimAPI::m_shutDown) + return 0; + + if (gce == NULL) + return GC_EVENT_ERROR; + + gcd = gce->pDest; + if (gcd == NULL) + return GC_EVENT_ERROR; + + if (gce->cbSize != sizeof(GCEVENT)) + return GC_EVENT_WRONGVER; + + if (!IsEventSupported(gcd->iType)) + return GC_EVENT_ERROR; + + if (!(gce->dwFlags & GC_UNICODE)) { + save_gce = *gce; + save_gcd = *gce->pDest; + gce->pDest->ptszID = a2tf(gce->pDest->ptszID, gce->dwFlags); + gce->ptszUID = a2tf(gce->ptszUID, gce->dwFlags); + gce->ptszNick = a2tf(gce->ptszNick, gce->dwFlags); + gce->ptszStatus = a2tf(gce->ptszStatus, gce->dwFlags); + if (gcd->iType != GC_EVENT_MESSAGE && gcd->iType != GC_EVENT_ACTION) { + gce->ptszText = a2tf(gce->ptszText, gce->dwFlags); + fFreeText = TRUE; + } + gce->ptszUserInfo = a2tf(gce->ptszUserInfo, gce->dwFlags); + } + + EnterCriticalSection(&cs); + + // Do different things according to type of event + switch (gcd->iType) { + case GC_EVENT_ADDGROUP: + { + STATUSINFO* si = SM_AddStatus(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszStatus); + if (si && gce->dwItemData) + si->hIcon = CopyIcon((HICON)gce->dwItemData); + } + iRetVal = 0; + goto LBL_Exit; + + case GC_EVENT_CHUID: + case GC_EVENT_CHANGESESSIONAME: + case GC_EVENT_SETITEMDATA: + case GC_EVENT_GETITEMDATA: + case GC_EVENT_CONTROL: + case GC_EVENT_SETSBTEXT: + case GC_EVENT_ACK: + case GC_EVENT_SENDMESSAGE : + case GC_EVENT_SETSTATUSEX : + iRetVal = DoControl(gce, wParam); + goto LBL_Exit; + + case GC_EVENT_SETCONTACTSTATUS: + iRetVal = SM_SetContactStatus(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID, (WORD)gce->dwItemData); + goto LBL_Exit; + + case GC_EVENT_TOPIC: + si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + if (gce->pszText) { + replaceStr(&si->ptszTopic, RemoveFormatting(gce->ptszText)); + M->WriteTString(si->hContact, si->pszModule , "Topic", /*RemoveFormatting*/(si->ptszTopic)); + if (M->GetByte("Chat", "TopicOnClist", 1)) + M->WriteTString(si->hContact, "CList" , "StatusMsg", /*RemoveFormatting*/(si->ptszTopic)); + if (si->hWnd) + SendMessage(si->hWnd, DM_INVALIDATEPANEL, 0, 0); + } + } + break; + + case GC_EVENT_ADDSTATUS: + SM_GiveStatus(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID, gce->ptszStatus); + if (!gce->bIsMe) + bIsHighlighted = g_Settings.Highlight->match(gce, 0, CMUCHighlight::MATCH_NICKNAME); + break; + + case GC_EVENT_REMOVESTATUS: + SM_TakeStatus(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID, gce->ptszStatus); + if (!gce->bIsMe) + bIsHighlighted = g_Settings.Highlight->match(gce, 0, CMUCHighlight::MATCH_NICKNAME); + break; + + case GC_EVENT_MESSAGE: + case GC_EVENT_ACTION: + si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (!(gce->dwFlags & GC_UNICODE)) { + fFreeText = TRUE; + if (si) + gce->ptszText = a2tf(gce->ptszText, gce->dwFlags, M->GetDword(si->hContact, "ANSIcodepage", 0)); + else + gce->ptszText = a2tf(gce->ptszText, gce->dwFlags); + } + if (!gce->bIsMe && gce->pDest->pszID && gce->pszText && si) + bIsHighlighted = si->Highlight->match(gce, si, CMUCHighlight::MATCH_TEXT | CMUCHighlight::MATCH_NICKNAME); + break; + + case GC_EVENT_NICK: + SM_ChangeNick(gce->pDest->ptszID, gce->pDest->pszModule, gce); + if (!gce->bIsMe) + bIsHighlighted = g_Settings.Highlight->match(gce, 0, CMUCHighlight::MATCH_NICKNAME); + break; + + case GC_EVENT_JOIN: + AddUser(gce); + if (!gce->bIsMe) + bIsHighlighted = g_Settings.Highlight->match(gce, 0, CMUCHighlight::MATCH_NICKNAME); + break; + + case GC_EVENT_PART: + case GC_EVENT_QUIT: + case GC_EVENT_KICK: + bRemoveFlag = TRUE; + if (!gce->bIsMe) + bIsHighlighted = g_Settings.Highlight->match(gce, 0, CMUCHighlight::MATCH_NICKNAME); + break; + } + + // Decide which window (log) should have the event + if (gcd->pszID) { + pWnd = gcd->ptszID; + pMod = gcd->pszModule; + } + else if ( gcd->iType == GC_EVENT_NOTICE || gcd->iType == GC_EVENT_INFORMATION ) { + SESSION_INFO* si = GetActiveSession(); + if (si && !lstrcmpA(si->pszModule, gcd->pszModule)) { + pWnd = si->ptszID; + pMod = si->pszModule; + } + else { + iRetVal = 0; + goto LBL_Exit; + } + } + else { + // Send the event to all windows with a user pszUID. Used for broadcasting QUIT etc + SM_AddEventToAllMatchingUID(gce, bIsHighlighted); + if (!bRemoveFlag) { + iRetVal = 0; + goto LBL_Exit; + } } + + // add to log + if (pWnd) { + if (si == NULL) + si = SM_FindSession(pWnd, pMod); + + // fix for IRC's old stuyle mode notifications. Should not affect any other protocol + if ((gce->pDest->iType == GC_EVENT_ADDSTATUS || gce->pDest->iType == GC_EVENT_REMOVESTATUS) && !(gce->dwFlags & GCEF_ADDTOLOG)) { + iRetVal = 0; + goto LBL_Exit; + } + + if (gce && gce->pDest->iType == GC_EVENT_JOIN && gce->time == 0) { + iRetVal = 0; + goto LBL_Exit; + } + + if (si && (si->bInitDone || gce->pDest->iType == GC_EVENT_TOPIC || (gce->pDest->iType == GC_EVENT_JOIN && gce->bIsMe))) { + if (SM_AddEvent(pWnd, pMod, gce, bIsHighlighted) && si->hWnd) { + SendMessage(si->hWnd, GC_ADDLOG, 0, 0); + } + else if (si->hWnd) { + SendMessage(si->hWnd, GC_REDRAWLOG2, 0, 0); + } + DoSoundsFlashPopupTrayStuff(si, gce, bIsHighlighted, 0); + if ((gce->dwFlags & GCEF_ADDTOLOG) && g_Settings.LoggingEnabled) + LogToFile(si, gce); + } + + if (!bRemoveFlag) { + iRetVal = 0; + goto LBL_Exit; + } } + + if (bRemoveFlag) + iRetVal = (SM_RemoveUser(gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID) == 0) ? 1 : 0; + +LBL_Exit: + LeaveCriticalSection(&cs); + + if (!(gce->dwFlags & GC_UNICODE)) { + if (fFreeText) + mir_free((void*)gce->ptszText); + mir_free((void*)gce->ptszNick); + mir_free((void*)gce->ptszUID); + mir_free((void*)gce->ptszStatus); + mir_free((void*)gce->ptszUserInfo); + mir_free((void*)gce->pDest->ptszID); + *gce = save_gce; + *gce->pDest = save_gcd; + } + return iRetVal; +} + +static INT_PTR Service_GetAddEventPtr(WPARAM wParam, LPARAM lParam) +{ + GCPTRS * gp = (GCPTRS *) lParam; + + EnterCriticalSection(&cs); + + gp->pfnAddEvent = Service_AddEvent; + LeaveCriticalSection(&cs); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Service creation + +void HookEvents(void) +{ + InitializeCriticalSection(&cs); + g_hHookPrebuildMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, CList_PrebuildContactMenu); // MIRANDAHOOK should return INT_PTR too +} + +void UnhookEvents(void) +{ + UnhookEvent(g_hHookPrebuildMenu); + DeleteCriticalSection(&cs); +} + +int CreateServiceFunctions(void) +{ + PluginConfig.m_chat_enabled = false; + + if (ServiceExists(MS_GC_REGISTER)) { + LRESULT result = CWarning::show(CWarning::WARN_CHAT_ENABLED, CWarning::CWF_NOALLOWHIDE | MB_YESNOCANCEL | MB_ICONQUESTION); + if (result == IDYES) + M->WriteByte("PluginDisable", "chat.dll", 1); + return 0; + } + PluginConfig.m_chat_enabled = true; + + hServiceRegister = CreateServiceFunction(MS_GC_REGISTER, Service_Register); + hServiceNewChat = CreateServiceFunction(MS_GC_NEWSESSION, Service_NewChat); + hServiceAddEvent = CreateServiceFunction(MS_GC_EVENT, Service_AddEvent); + hServiceGetAddEventPtr = CreateServiceFunction(MS_GC_GETEVENTPTR, Service_GetAddEventPtr); + hServiceGetInfo = CreateServiceFunction(MS_GC_GETINFO, Service_GetInfo); + hServiceGetCount = CreateServiceFunction(MS_GC_GETSESSIONCOUNT, Service_GetCount); + + hEventDoubleclicked = CreateServiceFunction("GChat/DblClickEvent", CList_EventDoubleclicked); + hEventPrebuildMenu = CreateServiceFunction("GChat/PrebuildMenuEvent", CList_PrebuildContactMenuSvc); + hEventJoinChat = CreateServiceFunction("GChat/JoinChat", CList_JoinChat); + hEventLeaveChat = CreateServiceFunction("GChat/LeaveChat", CList_LeaveChat); + return 1; +} + +void DestroyServiceFunctions(void) +{ + DestroyServiceFunction(hServiceRegister); + DestroyServiceFunction(hServiceNewChat); + DestroyServiceFunction(hServiceAddEvent); + DestroyServiceFunction(hServiceGetAddEventPtr); + DestroyServiceFunction(hServiceGetInfo); + DestroyServiceFunction(hServiceGetCount); + DestroyServiceFunction(hEventDoubleclicked); + DestroyServiceFunction(hEventPrebuildMenu); + DestroyServiceFunction(hEventJoinChat); + DestroyServiceFunction(hEventLeaveChat); +} + +void CreateHookableEvents(void) +{ + hSendEvent = CreateHookableEvent(ME_GC_EVENT); + hBuildMenuEvent = CreateHookableEvent(ME_GC_BUILDMENU); +} + +void DestroyHookableEvents(void) +{ + DestroyHookableEvent(hSendEvent); + DestroyHookableEvent(hBuildMenuEvent); +} diff --git a/plugins/TabSRMM/src/chat/tools.cpp b/plugins/TabSRMM/src/chat/tools.cpp new file mode 100644 index 0000000000..7662aaf722 --- /dev/null +++ b/plugins/TabSRMM/src/chat/tools.cpp @@ -0,0 +1,1353 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * This code is based on and still contains large parts of the the + * original chat module for Miranda NG, written and copyrighted + * by Joergen Persson in 2005. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: tools.cpp 13650 2011-05-30 11:53:13Z silvercircle@gmail.com $ + * + * Helper functions for the group chat module. + * + */ + +#include "..\commonheaders.h" + +// externs +extern HICON hIcons[30]; +extern FONTINFO aFonts[OPTIONS_FONTCOUNT]; +extern HMENU g_hMenu; +extern HANDLE hBuildMenuEvent ; +extern HANDLE hSendEvent; + +int GetRichTextLength(HWND hwnd) +{ + GETTEXTLENGTHEX gtl; + + gtl.flags = GTL_PRECISE; + gtl.codepage = CP_ACP ; + return (int) SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>l, 0); +} + +/** + * @param pszWord string to strip of any IRC-style + * formatting + * @param fToLower convert to lowercase + * @param fStripCR strip cr/lf sequences (only for highlighter, defaults to false) + * @param buf caller-provided buffer, use a static one + * when the caller does not provide a + * buffer + * caller provided buffer is NEEDED to make + * this thread-safe. + * + * @return TCHAR* the stripped string + */ +TCHAR* RemoveFormatting(const TCHAR* pszWord, bool fToLower, bool fStripCR, TCHAR* buf, const size_t len) +{ + static TCHAR _szTemp[20000]; + TCHAR* szTemp = 0; + size_t _buflen = 0; + + if (0 == buf) { + szTemp = _szTemp; + _buflen = 20000; + } else { + szTemp = buf; + _buflen = len; + szTemp[len - 1] = 0; + } + + size_t i = 0; + size_t j = 0; + + if (pszWord == 0) + return NULL; + + size_t wordlen = lstrlen(pszWord); + + while (j < _buflen && i <= wordlen) { + if (pszWord[i] == '%') { + switch (pszWord[i+1]) { + case '%': + szTemp[j] = '%'; + j++; + i++; + i++; + break; + case 'b': + case 'u': + case 'i': + case 'B': + case 'U': + case 'I': + case 'r': + case 'C': + case 'F': + i++; + i++; + break; + + case 'c': + case 'f': + i += 4; + break; + + default: + szTemp[j] = pszWord[i]; + j++; + i++; + break; + } + } else { + if (fStripCR) { + if (0x0a == pszWord[i] || 0x0c == pszWord[i]) { + szTemp[j++] = ' '; + i++; + continue; + } + } + szTemp[j] = pszWord[i]; + j++; + i++; + } + } + if (fToLower) { + _wsetlocale(LC_ALL, L""); + wcslwr(szTemp); + } + return(szTemp); +} + +static void __stdcall ShowRoomFromPopup(void * pi) +{ + SESSION_INFO* si = (SESSION_INFO*) pi; + ShowRoom(si, WINDOW_VISIBLE, TRUE); +} + +static void TSAPI Chat_OpenPopup(SESSION_INFO* si, HWND hwndPopup) +{ + CallFunctionAsync(ShowRoomFromPopup, si); + PUDeletePopUp(hwndPopup); +} + +static void TSAPI Chat_DismissPopup(const SESSION_INFO* si, HWND hwndPopup) +{ + if (si->hContact) + if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->hContact, (LPARAM)0)) + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->hContact, (LPARAM)szChatIconString); + + if (si->hWnd && KillTimer(si->hWnd, TIMERID_FLASHWND)) + FlashWindow(si->hWnd, FALSE); + + PUDeletePopUp(hwndPopup); +} + +static INT_PTR CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_COMMAND: + if (HIWORD(wParam) == STN_CLICKED) { + SESSION_INFO* si = (SESSION_INFO*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, (LPARAM)0);; + + if (si) { + if (nen_options.maskActL & MASK_OPEN) + Chat_OpenPopup(si, hWnd); + else + Chat_DismissPopup(si, hWnd); + } + return TRUE; + } + break; + case WM_CONTEXTMENU: { + SESSION_INFO* si = (SESSION_INFO*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, (LPARAM)0); + + if (si && si->hContact) { + if (nen_options.maskActR & MASK_OPEN) + Chat_OpenPopup(si, hWnd); + else + Chat_DismissPopup(si, hWnd); + } + } + break; + } + return DefWindowProc(hWnd, message, wParam, lParam); +} + +static int ShowPopup(HANDLE hContact, SESSION_INFO* si, HICON hIcon, char* pszProtoName, TCHAR* pszRoomName, COLORREF crBkg, const TCHAR* fmt, ...) +{ + POPUPDATAT_V2 pd = {0}; + va_list marker; + static TCHAR szBuf[4*1024]; + + if (!fmt || lstrlen(fmt) == 0 || lstrlen(fmt) > 2000) + return 0; + + va_start(marker, fmt); + _vstprintf(szBuf, fmt, marker); + va_end(marker); + + pd.lchContact = hContact; + + if (hIcon) + pd.lchIcon = hIcon ; + else + pd.lchIcon = LoadIconEx(IDI_CHANMGR, "window", 0, 0); + + mir_sntprintf(pd.lptzContactName, MAX_CONTACTNAME - 1, _T(TCHAR_STR_PARAM) _T(" - %s"), + pszProtoName, CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)); + lstrcpyn(pd.lptzText, TranslateTS(szBuf), MAX_SECONDLINE - 1); + pd.iSeconds = g_Settings.iPopupTimeout; + + if (g_Settings.iPopupStyle == 2) { + pd.colorBack = 0; + pd.colorText = 0; + } else if (g_Settings.iPopupStyle == 3) { + pd.colorBack = g_Settings.crPUBkgColour; + pd.colorText = g_Settings.crPUTextColour; + } else { + pd.colorBack = M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR_MUC, SRMSGDEFSET_BKGCOLOUR); + pd.colorText = crBkg; + } + + pd.PluginWindowProc = (WNDPROC)PopupDlgProc; + pd.PluginData = si; + return PUAddPopUpT(&pd); +} + +static BOOL DoTrayIcon(SESSION_INFO* si, GCEVENT * gce) +{ + int iEvent = gce->pDest->iType; + + if (si && (iEvent & si->iLogTrayFlags)) { + switch (iEvent) { + case GC_EVENT_MESSAGE | GC_EVENT_HIGHLIGHT : + case GC_EVENT_ACTION | GC_EVENT_HIGHLIGHT : + CList_AddEvent(si->hContact, PluginConfig.g_IconMsgEvent, szChatIconString, 0, + TranslateT("%s wants your attention in %s"), gce->ptszNick, si->ptszName); + break; + case GC_EVENT_MESSAGE : + CList_AddEvent(si->hContact, hIcons[ICON_MESSAGE], szChatIconString, CLEF_ONLYAFEW, + TranslateT("%s speaks in %s"), gce->ptszNick, si->ptszName); + break; + case GC_EVENT_ACTION: + CList_AddEvent(si->hContact, hIcons[ICON_ACTION], szChatIconString, CLEF_ONLYAFEW, + TranslateT("%s speaks in %s"), gce->ptszNick, si->ptszName); + break; + case GC_EVENT_JOIN: + CList_AddEvent(si->hContact, hIcons[ICON_JOIN], szChatIconString, CLEF_ONLYAFEW, + TranslateT("%s has joined %s"), gce->ptszNick, si->ptszName); + break; + case GC_EVENT_PART: + CList_AddEvent(si->hContact, hIcons[ICON_PART], szChatIconString, CLEF_ONLYAFEW, + TranslateT("%s has left %s"), gce->ptszNick, si->ptszName); + break; + case GC_EVENT_QUIT: + CList_AddEvent(si->hContact, hIcons[ICON_QUIT], szChatIconString, CLEF_ONLYAFEW, + TranslateT("%s has disconnected"), gce->ptszNick); + break; + case GC_EVENT_NICK: + CList_AddEvent(si->hContact, hIcons[ICON_NICK], szChatIconString, CLEF_ONLYAFEW, + TranslateT("%s is now known as %s"), gce->ptszNick, gce->pszText); + break; + case GC_EVENT_KICK: + CList_AddEvent(si->hContact, hIcons[ICON_KICK], szChatIconString, CLEF_ONLYAFEW, + TranslateT("%s kicked %s from %s"), gce->pszStatus, gce->ptszNick, si->ptszName); + break; + case GC_EVENT_NOTICE: + CList_AddEvent(si->hContact, hIcons[ICON_NOTICE], szChatIconString, CLEF_ONLYAFEW, + TranslateT("Notice from %s"), gce->ptszNick); + break; + case GC_EVENT_TOPIC: + CList_AddEvent(si->hContact, hIcons[ICON_TOPIC], szChatIconString, CLEF_ONLYAFEW, + TranslateT("Topic change in %s"), si->ptszName); + break; + case GC_EVENT_INFORMATION: + CList_AddEvent(si->hContact, hIcons[ICON_INFO], szChatIconString, CLEF_ONLYAFEW, + TranslateT("Information in %s"), si->ptszName); + break; + case GC_EVENT_ADDSTATUS: + CList_AddEvent(si->hContact, hIcons[ICON_ADDSTATUS], szChatIconString, CLEF_ONLYAFEW, + TranslateT("%s enables \'%s\' status for %s in %s"), gce->pszText, gce->pszStatus, gce->ptszNick, si->ptszName); + break; + case GC_EVENT_REMOVESTATUS: + CList_AddEvent(si->hContact, hIcons[ICON_REMSTATUS], szChatIconString, CLEF_ONLYAFEW, + TranslateT("%s disables \'%s\' status for %s in %s"), gce->pszText, gce->pszStatus, gce->ptszNick, si->ptszName); + break; + } + } + return TRUE; +} + +static BOOL DoPopup(SESSION_INFO* si, GCEVENT* gce, struct TWindowData* dat) +{ + int iEvent = gce->pDest->iType; + struct TContainerData *pContainer = dat ? dat->pContainer : NULL; + char *szProto = dat ? dat->szProto : si->pszModule; + + TCHAR *bbStart, *bbEnd; + if (g_Settings.BBCodeInPopups) + { + bbStart = _T("[b]"); + bbEnd = _T("[/b]"); + } else + { + bbStart = bbEnd = _T(""); + } + + if (si && (iEvent & si->iLogPopupFlags)) { + + if (nen_options.iMUCDisable) // no popups at all. Period + return 0; + /* + * check the status mode against the status mask + */ + + if (nen_options.dwStatusMask != -1) { + DWORD dwStatus = 0; + if (szProto != NULL) { + dwStatus = (DWORD)CallProtoService(szProto, PS_GETSTATUS, 0, 0); + if (!(dwStatus == 0 || dwStatus <= ID_STATUS_OFFLINE || ((1 << (dwStatus - ID_STATUS_ONLINE)) & nen_options.dwStatusMask))) // should never happen, but... + return 0; + } + } + if (dat && pContainer != 0) { // message window is open, need to check the container config if we want to see a popup nonetheless + if (nen_options.bWindowCheck) { // no popups at all for open windows... no exceptions + if (!PluginConfig.m_HideOnClose) + return 0; + if (pContainer->fHidden) + goto passed; + return 0; + } + if (pContainer->dwFlags & CNT_DONTREPORT && IsIconic(pContainer->hwnd)) // in tray counts as "minimised" + goto passed; + if (pContainer->dwFlags & CNT_DONTREPORTUNFOCUSED) { + if (!IsIconic(pContainer->hwnd) && GetForegroundWindow() != pContainer->hwnd && GetActiveWindow() != pContainer->hwnd) + goto passed; + } + if (pContainer->dwFlags & CNT_ALWAYSREPORTINACTIVE) { + if (pContainer->dwFlags & CNT_DONTREPORTFOCUSED) + goto passed; + + if (pContainer->hwndActive == si->hWnd) + return 0; + + goto passed; + } + return 0; + } +passed: + int iNewEvent = iEvent; + COLORREF clr = 0; + + if ((iNewEvent & GC_EVENT_HIGHLIGHT)) { + clr = aFonts[16].color; + iNewEvent &= ~GC_EVENT_HIGHLIGHT; + } + switch (iNewEvent) { + case GC_EVENT_MESSAGE : + ShowPopup(si->hContact, si, hIcons[ICON_MESSAGE], si->pszModule, si->ptszName, clr ? clr : aFonts[9].color, + TranslateT("%s%s says:%s %s"), bbStart, gce->ptszNick, bbEnd, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_ACTION: + ShowPopup(si->hContact, si, hIcons[ICON_ACTION], si->pszModule, si->ptszName, clr ? clr : aFonts[15].color, _T("%s %s"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_JOIN: + ShowPopup(si->hContact, si, hIcons[ICON_JOIN], si->pszModule, si->ptszName, clr ? clr : aFonts[3].color, + TranslateT("%s has joined"), gce->ptszNick); + break; + case GC_EVENT_PART: + if (!gce->pszText) + ShowPopup(si->hContact, si, hIcons[ICON_PART], si->pszModule, si->ptszName, clr ? clr : aFonts[4].color, + TranslateT("%s has left"), gce->ptszNick); + else + ShowPopup(si->hContact, si, hIcons[ICON_PART], si->pszModule, si->ptszName, clr ? clr : aFonts[4].color, + TranslateT("%s has left (%s)"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_QUIT: + if (!gce->pszText) + ShowPopup(si->hContact, si, hIcons[ICON_QUIT], si->pszModule, si->ptszName, clr ? clr : aFonts[5].color, + TranslateT("%s has disconnected"), gce->ptszNick); + else + ShowPopup(si->hContact, si, hIcons[ICON_QUIT], si->pszModule, si->ptszName, clr ? clr : aFonts[5].color, + TranslateT("%s has disconnected (%s)"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_NICK: + ShowPopup(si->hContact, si, hIcons[ICON_NICK], si->pszModule, si->ptszName, clr ? clr : aFonts[7].color, + TranslateT("%s is now known as %s"), gce->ptszNick, gce->ptszText); + break; + case GC_EVENT_KICK: + if (!gce->pszText) + ShowPopup(si->hContact, si, hIcons[ICON_KICK], si->pszModule, si->ptszName, clr ? clr : aFonts[6].color, + TranslateT("%s kicked %s"), (char *)gce->pszStatus, gce->ptszNick); + else + ShowPopup(si->hContact, si, hIcons[ICON_KICK], si->pszModule, si->ptszName, clr ? clr : aFonts[6].color, + TranslateT("%s kicked %s (%s)"), (char *)gce->pszStatus, gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_NOTICE: + ShowPopup(si->hContact, si, hIcons[ICON_NOTICE], si->pszModule, si->ptszName, clr ? clr : aFonts[8].color, + TranslateT("Notice from %s: %s"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_TOPIC: + if (!gce->ptszNick) + ShowPopup(si->hContact, si, hIcons[ICON_TOPIC], si->pszModule, si->ptszName, clr ? clr : aFonts[11].color, + TranslateT("The topic is \'%s\'"), RemoveFormatting(gce->ptszText)); + else + ShowPopup(si->hContact, si, hIcons[ICON_TOPIC], si->pszModule, si->ptszName, clr ? clr : aFonts[11].color, + TranslateT("The topic is \'%s\' (set by %s)"), RemoveFormatting(gce->ptszText), gce->ptszNick); + break; + case GC_EVENT_INFORMATION: + ShowPopup(si->hContact, si, hIcons[ICON_INFO], si->pszModule, si->ptszName, clr ? clr : aFonts[12].color, _T("%s"), RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_ADDSTATUS: + ShowPopup(si->hContact, si, hIcons[ICON_ADDSTATUS], si->pszModule, si->ptszName, clr ? clr : aFonts[13].color, + TranslateT("%s enables \'%s\' status for %s"), gce->ptszText, (char *)gce->pszStatus, gce->ptszNick); + break; + case GC_EVENT_REMOVESTATUS: + ShowPopup(si->hContact, si, hIcons[ICON_REMSTATUS], si->pszModule, si->ptszName, clr ? clr : aFonts[14].color, + TranslateT("%s disables \'%s\' status for %s"), gce->ptszText, (char *)gce->pszStatus, gce->ptszNick); + break; + } + } + + return TRUE; +} + +void TSAPI DoFlashAndSoundWorker(FLASH_PARAMS* p) +{ + SESSION_INFO* si = SM_FindSessionByHCONTACT(p->hContact); + TWindowData* dat = 0; + + if (si == 0) + return; + + if (si->hWnd) { + dat = si->dat; + if (dat) { + p->bInactive = dat->pContainer->hwnd != GetForegroundWindow(); + p->bActiveTab = (dat->pContainer->hwndActive == si->hWnd); + } + if (p->sound && Utils::mustPlaySound(si->dat)) + SkinPlaySound(p->sound); + } + else if (p->sound) + SkinPlaySound(p->sound); + + if (dat) { + HWND hwndTab = GetParent(si->hWnd); + BOOL bForcedIcon = (p->hNotifyIcon == hIcons[ICON_HIGHLIGHT] || p->hNotifyIcon == hIcons[ICON_MESSAGE]); + + if ((p->iEvent & si->iLogTrayFlags) || bForcedIcon) { + if (!p->bActiveTab) { + if (p->hNotifyIcon == hIcons[ICON_HIGHLIGHT]) + dat->iFlashIcon = p->hNotifyIcon; + else { + if (dat->iFlashIcon != hIcons[ICON_HIGHLIGHT] && dat->iFlashIcon != hIcons[ICON_MESSAGE]) + dat->iFlashIcon = p->hNotifyIcon; + } + dat->mayFlashTab = TRUE; + SetTimer(si->hWnd, TIMERID_FLASHWND, TIMEOUT_FLASHWND, NULL); + } + } + if (dat->pWnd) { + dat->pWnd->updateIcon(p->hNotifyIcon); + dat->pWnd->setOverlayIcon(p->hNotifyIcon, true); + } + + // autoswitch tab.. + if (p->bMustAutoswitch) { + if ((IsIconic(dat->pContainer->hwnd)) && !IsZoomed(dat->pContainer->hwnd) && PluginConfig.haveAutoSwitch() && dat->pContainer->hwndActive != si->hWnd) { + int iItem = GetTabIndexFromHWND(hwndTab, si->hWnd); + if (iItem >= 0) { + TabCtrl_SetCurSel(hwndTab, iItem); + ShowWindow(dat->pContainer->hwndActive, SW_HIDE); + dat->pContainer->hwndActive = si->hWnd; + SendMessage(dat->pContainer->hwnd, DM_UPDATETITLE, (WPARAM)dat->hContact, 0); + dat->pContainer->dwFlags |= CNT_DEFERREDTABSELECT; + } + } + } + + /* + * flash window if it is not focused + */ + if (p->bMustFlash && p->bInactive) + if (!(dat->pContainer->dwFlags & CNT_NOFLASH)) + FlashContainer(dat->pContainer, 1, 0); + + if (p->hNotifyIcon && p->bInactive && ((p->iEvent & si->iLogTrayFlags) || bForcedIcon)) { + HICON hIcon; + + if (p->bMustFlash) + dat->hTabIcon = p->hNotifyIcon; + else if (dat->iFlashIcon) { + TCITEM item = {0}; + + dat->hTabIcon = dat->iFlashIcon; + item.mask = TCIF_IMAGE; + item.iImage = 0; + TabCtrl_SetItem(GetParent(si->hWnd), dat->iTabID, &item); + } + hIcon = (HICON)SendMessage(dat->pContainer->hwnd, WM_GETICON, ICON_BIG, 0); + if (p->hNotifyIcon == hIcons[ICON_HIGHLIGHT] || (hIcon != hIcons[ICON_MESSAGE] && hIcon != hIcons[ICON_HIGHLIGHT])) { + SendMessage(dat->pContainer->hwnd, DM_SETICON, (WPARAM)dat, (LPARAM)p->hNotifyIcon); + dat->pContainer->dwFlags |= CNT_NEED_UPDATETITLE; + } + } + + if (p->bMustFlash && p->bInactive) + UpdateTrayMenu(dat, si->wStatus, si->pszModule, dat ? dat->szStatus : NULL, si->hContact, p->bHighlight ? 1 : 1); + } + + free(p); +} + +BOOL DoSoundsFlashPopupTrayStuff(SESSION_INFO* si, GCEVENT * gce, BOOL bHighlight, int bManyFix) +{ + FLASH_PARAMS* params; + struct TWindowData *dat = 0; + bool fFlagUnread = false; + WPARAM wParamForHighLight = 0; + + if (gce == 0 || si == 0 || gce->bIsMe || si->iType == GCW_SERVER) + return FALSE; + + params = (FLASH_PARAMS*)calloc(1, sizeof(FLASH_PARAMS)); + params->hContact = si->hContact; + params->bInactive = TRUE; + if (si->hWnd && si->dat) { + dat = si->dat; + if ((si->hWnd == si->dat->pContainer->hwndActive) && GetForegroundWindow() == si->dat->pContainer->hwnd) + params->bInactive = FALSE; + } + params->bActiveTab = params->bMustFlash = params->bMustAutoswitch = FALSE; + + params->iEvent = gce->pDest->iType; + + if (bHighlight) { + gce->pDest->iType |= GC_EVENT_HIGHLIGHT; + params->sound = "ChatHighlight"; + if (M->GetByte(si->hContact, "CList", "Hidden", 0) != 0) + DBDeleteContactSetting(si->hContact, "CList", "Hidden"); + if (params->bInactive) { + fFlagUnread = true; + DoTrayIcon(si, gce); + } + + /* TODO fix for 3.0 final !!! */ +#if !defined(__DELAYED_FOR_3_1) + if (g_Settings.CreateWindowOnHighlight && 0 == dat) + wParamForHighLight = 1; + + if (dat && g_Settings.AnnoyingHighlight && params->bInactive && dat->pContainer->hwnd != GetForegroundWindow()) { + wParamForHighLight = 2; + params->hWnd = dat->hwnd; + } +#endif + if (dat || !nen_options.iMUCDisable) + DoPopup(si, gce, dat); + if (params->bInactive && si && si->hWnd) + SendMessage(si->hWnd, GC_SETMESSAGEHIGHLIGHT, 0, (LPARAM) si); + if (g_Settings.FlashWindowHightlight && params->bInactive) + params->bMustFlash = TRUE; + params->bMustAutoswitch = TRUE; + params->hNotifyIcon = hIcons[ICON_HIGHLIGHT]; + } else { + // do blinking icons in tray + if (params->bInactive || !g_Settings.TrayIconInactiveOnly) { + DoTrayIcon(si, gce); + if (params->iEvent == GC_EVENT_MESSAGE) + fFlagUnread = true; + } + // stupid thing to not create multiple popups for a QUIT event for instance + if (bManyFix == 0) { + // do popups + if (dat || !nen_options.iMUCDisable) + DoPopup(si, gce, dat); + + // do sounds and flashing + switch (params->iEvent) { + case GC_EVENT_JOIN: + params->sound = "ChatJoin"; + if (params->bInactive) + params->hNotifyIcon = hIcons[ICON_JOIN]; + break; + case GC_EVENT_PART: + params->sound = "ChatPart"; + if (params->bInactive) + params->hNotifyIcon = hIcons[ICON_PART]; + break; + case GC_EVENT_QUIT: + params->sound = "ChatQuit"; + if (params->bInactive) + params->hNotifyIcon = hIcons[ICON_QUIT]; + break; + case GC_EVENT_ADDSTATUS: + case GC_EVENT_REMOVESTATUS: + params->sound = "ChatMode"; + if (params->bInactive) + params->hNotifyIcon = hIcons[params->iEvent == GC_EVENT_ADDSTATUS ? ICON_ADDSTATUS : ICON_REMSTATUS]; + break; + case GC_EVENT_KICK: + params->sound = "ChatKick"; + if (params->bInactive) + params->hNotifyIcon = hIcons[ICON_KICK]; + break; + case GC_EVENT_MESSAGE: + params->sound = "ChatMessage"; + if (params->bInactive && !(si->wState&STATE_TALK)) { + si->wState |= STATE_TALK; + DBWriteContactSettingWord(si->hContact, si->pszModule, "ApparentMode", (LPARAM)(WORD) 40071); + } + break; + case GC_EVENT_ACTION: + params->sound = "ChatAction"; + if (params->bInactive) + params->hNotifyIcon = hIcons[ICON_ACTION]; + break; + case GC_EVENT_NICK: + params->sound = "ChatNick"; + if (params->bInactive) + params->hNotifyIcon = hIcons[ICON_NICK]; + break; + case GC_EVENT_NOTICE: + params->sound = "ChatNotice"; + if (params->bInactive) + params->hNotifyIcon = hIcons[ICON_NOTICE]; + break; + case GC_EVENT_TOPIC: + params->sound = "ChatTopic"; + if (params->bInactive) + params->hNotifyIcon = hIcons[ICON_TOPIC]; + break; + } + } else { + switch (params->iEvent) { + case GC_EVENT_JOIN: + params->hNotifyIcon = hIcons[ICON_JOIN]; + break; + case GC_EVENT_PART: + params->hNotifyIcon = hIcons[ICON_PART]; + break; + case GC_EVENT_QUIT: + params->hNotifyIcon = hIcons[ICON_QUIT]; + break; + case GC_EVENT_KICK: + params->hNotifyIcon = hIcons[ICON_KICK]; + break; + case GC_EVENT_ACTION: + params->hNotifyIcon = hIcons[ICON_ACTION]; + break; + case GC_EVENT_NICK: + params->hNotifyIcon = hIcons[ICON_NICK]; + break; + case GC_EVENT_NOTICE: + params->hNotifyIcon = hIcons[ICON_NOTICE]; + break; + case GC_EVENT_TOPIC: + params->hNotifyIcon = hIcons[ICON_TOPIC]; + break; + case GC_EVENT_ADDSTATUS: + params->hNotifyIcon = hIcons[ICON_ADDSTATUS]; + break; + case GC_EVENT_REMOVESTATUS: + params->hNotifyIcon = hIcons[ICON_REMSTATUS]; + break; + } + } + + if (params->iEvent == GC_EVENT_MESSAGE) { + params->bMustAutoswitch = TRUE; + if (g_Settings.FlashWindow) + params->bMustFlash = TRUE; + params->hNotifyIcon = hIcons[ICON_MESSAGE]; + } + } + if (dat && fFlagUnread) { + dat->dwUnread++; + if (dat->pWnd) + dat->pWnd->Invalidate(); + } + PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_MUCFLASHWORKER, wParamForHighLight, (LPARAM)params); + return TRUE; +} + +int Chat_GetColorIndex(const char* pszModule, COLORREF cr) +{ + MODULEINFO * pMod = MM_FindModule(pszModule); + int i = 0; + + if (!pMod || pMod->nColorCount == 0) + return -1; + + for (i=0; i < pMod->nColorCount; i++) + if (pMod->crColors[i] == cr) + return i; + + return -1; +} + +// obscure function that is used to make sure that any of the colors +// passed by the protocol is used as fore- or background color +// in the messagebox. THis is to vvercome limitations in the richedit +// that I do not know currently how to fix + +void CheckColorsInModule(const char* pszModule) +{ + MODULEINFO * pMod = MM_FindModule(pszModule); + int i = 0; + COLORREF crFG; + COLORREF crBG = (COLORREF)M->GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR); + + LoadLogfont(MSGFONTID_MESSAGEAREA, NULL, &crFG, FONTMODULE); + + if (!pMod) + return; + + for (i=0; i < pMod->nColorCount; i++) { + if (pMod->crColors[i] == crFG || pMod->crColors[i] == crBG) { + if (pMod->crColors[i] == RGB(255, 255, 255)) + pMod->crColors[i]--; + else + pMod->crColors[i]++; + } + } +} + +TCHAR* my_strstri(const TCHAR* s1, const TCHAR* s2) +{ + int i, j, k; + + _tsetlocale(LC_ALL, _T("")); + for (i=0;s1[i];i++) + for (j = i, k = 0; _totlower(s1[j]) == _totlower(s2[k]);j++, k++) + if (!s2[k+1]) + return (TCHAR*)(s1 + i); + + return NULL; +} + +/* + * log the event to the log file + * allows selective logging of wanted events + */ +BOOL LogToFile(SESSION_INFO* si, GCEVENT * gce) +{ + MODULEINFO * mi = NULL; + TCHAR szBuffer[4096]; + TCHAR szLine[4096]; + TCHAR szTime[100]; + FILE *hFile = NULL; + TCHAR tszFolder[MAX_PATH]; + TCHAR p = '\0'; + BOOL bFileJustCreated = TRUE; + + if (!si || !gce) + return FALSE; + + mi = MM_FindModule(si->pszModule); + if (!mi) + return FALSE; + + /* + * check whether we have to log this event + */ + if (!(gce->pDest->iType & si->iDiskLogFlags)) + return FALSE; + + szBuffer[0] = '\0'; + + GetChatLogsFilename(si, gce->time); + bFileJustCreated = !PathFileExists(si->pszLogFileName); + _tcscpy(tszFolder, si->pszLogFileName); + PathRemoveFileSpec(tszFolder); + if (!PathIsDirectory(tszFolder)) + CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)tszFolder); + + lstrcpyn(szTime, MakeTimeStamp(g_Settings.pszTimeStampLog, gce->time), 99); + + hFile = _tfopen(si->pszLogFileName, _T("ab+")); + if (hFile) { + TCHAR szTemp[512], szTemp2[512]; + TCHAR* pszNick = NULL; + if (bFileJustCreated) + fputws((const wchar_t*)"\377\376", hFile); //UTF-16 LE BOM == FF FE + if (gce->ptszNick) { + if (g_Settings.LogLimitNames && lstrlen(gce->ptszNick) > 20) { + lstrcpyn(szTemp2, gce->ptszNick, 20); + lstrcpyn(szTemp2 + 20, _T("..."), 4); + } else lstrcpyn(szTemp2, gce->ptszNick, 511); + + if (gce->pszUserInfo) + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s (%s)"), szTemp2, gce->pszUserInfo); + else + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s"), szTemp2); + pszNick = szTemp; + } + switch (gce->pDest->iType) { + case GC_EVENT_MESSAGE: + case GC_EVENT_MESSAGE | GC_EVENT_HIGHLIGHT: + p = '*'; + mir_sntprintf(szBuffer, SIZEOF(szBuffer), _T("%s: %s"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_ACTION: + case GC_EVENT_ACTION | GC_EVENT_HIGHLIGHT: + p = '*'; + mir_sntprintf(szBuffer, SIZEOF(szBuffer), _T("%s %s"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_JOIN: + p = '>'; + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s has joined"), (char *)pszNick); + break; + case GC_EVENT_PART: + p = '<'; + if (!gce->pszText) + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s has left"), (char *)pszNick); + else + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s has left (%s)"), (char *)pszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_QUIT: + p = '<'; + if (!gce->pszText) + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s has disconnected"), (char *)pszNick); + else + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s has disconnected (%s)"), (char *)pszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_NICK: + p = '^'; + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s is now known as %s"), gce->ptszNick, gce->ptszText); + break; + case GC_EVENT_KICK: + p = '~'; + if (!gce->pszText) + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s kicked %s"), (char *)gce->pszStatus, gce->ptszNick); + else + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s kicked %s (%s)"), (char *)gce->pszStatus, gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_NOTICE: + p = 'o'; + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("Notice from %s: %s"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_TOPIC: + p = '#'; + if (!gce->pszNick) + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("The topic is \'%s\'"), RemoveFormatting(gce->ptszText)); + else + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("The topic is \'%s\' (set by %s)"), RemoveFormatting(gce->ptszText), gce->ptszNick); + break; + case GC_EVENT_INFORMATION: + p = '!'; + mir_sntprintf(szBuffer, SIZEOF(szBuffer), _T("%s"), RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_ADDSTATUS: + p = '+'; + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s enables \'%s\' status for %s"), gce->ptszText, (char *)gce->pszStatus, gce->ptszNick); + break; + case GC_EVENT_REMOVESTATUS: + p = '-'; + mir_sntprintf(szBuffer, SIZEOF(szBuffer), TranslateT("%s disables \'%s\' status for %s"), gce->ptszText, (char *)gce->pszStatus, gce->ptszNick); + break; + } + /* + * formatting strings don't need to be translatable - changing them via language pack would + * only screw up the log format. + */ + if (p) + mir_sntprintf(szLine, SIZEOF(szLine), _T("%s %c %s\r\n"), szTime, p, szBuffer); + else + mir_sntprintf(szLine, SIZEOF(szLine), _T("%s %s\r\n"), szTime, szBuffer); + + if (szLine[0]) { + _fputts(szLine, hFile); + + if (g_Settings.LoggingLimit > 0) { + long dwSize; + long trimlimit; + + fseek(hFile, 0, SEEK_END); + dwSize = ftell(hFile); + rewind(hFile); + + trimlimit = g_Settings.LoggingLimit * 1024; + if (dwSize > trimlimit) { + TCHAR tszDrive[_MAX_DRIVE]; + TCHAR tszDir[_MAX_DIR]; + TCHAR tszName[_MAX_FNAME]; + TCHAR tszExt[_MAX_EXT]; + TCHAR tszNewName[_MAX_DRIVE + _MAX_DIR + _MAX_FNAME + _MAX_EXT + 20]; + TCHAR tszNewPath[_MAX_DRIVE + _MAX_DIR + _MAX_FNAME + _MAX_EXT + 20]; + TCHAR tszTimestamp[20]; + time_t now = time(0); + + _tcsftime(tszTimestamp, 20, _T("%Y%m%d-%H%M%S"), _localtime32((__time32_t *)&now)); + tszTimestamp[19] = 0; + /* + * max size reached, rotate the log + * move old logs to /archived sub folder just inside the log root folder. + * add a time stamp to the file name. + */ + _tsplitpath(si->pszLogFileName, tszDrive, tszDir, tszName, tszExt); + + mir_sntprintf(tszNewPath, _MAX_DRIVE + _MAX_DIR + _MAX_FNAME + _MAX_EXT + 20, _T("%s%sarchived\\"), + tszDrive, tszDir); + + CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)tszNewPath); + mir_sntprintf(tszNewName, _MAX_DRIVE + _MAX_DIR + _MAX_FNAME + _MAX_EXT + 20, _T("%s%s-%s%s"), tszNewPath, tszName, tszTimestamp, tszExt); + fclose(hFile); + hFile = 0; + if (!PathFileExists(tszNewName)) + CopyFile(si->pszLogFileName, tszNewName, TRUE); + DeleteFile(si->pszLogFileName); + } + } + } + + if (hFile) + fclose(hFile); + hFile = NULL; + return TRUE; + } + return FALSE; +} + +UINT CreateGCMenu(HWND hwndDlg, HMENU *hMenu, int iIndex, POINT pt, SESSION_INFO* si, TCHAR* pszUID, TCHAR* pszWordText) +{ + GCMENUITEMS gcmi = {0}; + int i; + HMENU hSubMenu = 0; + DWORD codepage = M->GetDword(si->hContact, "ANSIcodepage", 0); + int pos; + + *hMenu = GetSubMenu(g_hMenu, iIndex); + TranslateMenu(*hMenu); + gcmi.pszID = si->ptszID; + gcmi.pszModule = si->pszModule; + gcmi.pszUID = pszUID; + + if (iIndex == 1) { + int i = GetRichTextLength(GetDlgItem(hwndDlg, IDC_CHAT_LOG)); + + EnableMenuItem(*hMenu, ID_CLEARLOG, MF_ENABLED); + EnableMenuItem(*hMenu, ID_COPYALL, MF_ENABLED); + ModifyMenu(*hMenu, 4, MF_GRAYED | MF_BYPOSITION, 4, NULL); + if (!i) { + EnableMenuItem(*hMenu, ID_COPYALL, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(*hMenu, ID_CLEARLOG, MF_BYCOMMAND | MF_GRAYED); + if (pszWordText && pszWordText[0]) + ModifyMenu(*hMenu, 4, MF_ENABLED | MF_BYPOSITION, 4, NULL); + } + + if (pszWordText && pszWordText[0]) { + TCHAR szMenuText[4096]; + mir_sntprintf(szMenuText, 4096, TranslateT("Look up \'%s\':"), pszWordText); + ModifyMenu(*hMenu, 4, MF_STRING | MF_BYPOSITION, 4, szMenuText); + } else ModifyMenu(*hMenu, 4, MF_STRING | MF_GRAYED | MF_BYPOSITION, 4, TranslateT("No word to look up")); + gcmi.Type = MENU_ON_LOG; + } else if (iIndex == 0) { + TCHAR szTemp[30], szTemp2[30]; + lstrcpyn(szTemp, TranslateT("&Message"), 24); + if (pszUID) + mir_sntprintf(szTemp2, SIZEOF(szTemp2), _T("%s %s"), szTemp, pszUID); + else + lstrcpyn(szTemp2, szTemp, 24); + + if (lstrlen(szTemp2) > 22) + lstrcpyn(szTemp2 + 22, _T("..."), 4); + ModifyMenu(*hMenu, ID_MESS, MF_STRING | MF_BYCOMMAND, ID_MESS, szTemp2); + gcmi.Type = MENU_ON_NICKLIST; + } + + NotifyEventHooks(hBuildMenuEvent, 0, (WPARAM)&gcmi); + + if (gcmi.nItems > 0) + AppendMenu(*hMenu, MF_SEPARATOR, 0, 0); + + for (i=0; i < gcmi.nItems; i++) { + TCHAR* ptszDescr = a2tf(gcmi.Item[i].pszDesc, si->dwFlags); + TCHAR* ptszText = TranslateTS(ptszDescr); + DWORD dwState = gcmi.Item[i].bDisabled ? MF_GRAYED : 0; + + if (gcmi.Item[i].uType == MENU_NEWPOPUP) { + hSubMenu = CreateMenu(); + AppendMenu(*hMenu, dwState | MF_POPUP, (UINT_PTR)hSubMenu, ptszText); + } + else if (gcmi.Item[i].uType == MENU_POPUPHMENU) + AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_POPUP, gcmi.Item[i].dwID, ptszText); + else if (gcmi.Item[i].uType == MENU_POPUPITEM) + AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_STRING, gcmi.Item[i].dwID, ptszText); + else if (gcmi.Item[i].uType == MENU_POPUPCHECK) + AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_CHECKED | MF_STRING, gcmi.Item[i].dwID, ptszText); + else if (gcmi.Item[i].uType == MENU_POPUPSEPARATOR) + AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, MF_SEPARATOR, 0, ptszText); + else if (gcmi.Item[i].uType == MENU_SEPARATOR) + AppendMenu(*hMenu, MF_SEPARATOR, 0, ptszText); + else if (gcmi.Item[i].uType == MENU_HMENU) + AppendMenu(*hMenu, dwState | MF_POPUP, gcmi.Item[i].dwID, ptszText); + else if (gcmi.Item[i].uType == MENU_ITEM) + AppendMenu(*hMenu, dwState | MF_STRING, gcmi.Item[i].dwID, ptszText); + else if (gcmi.Item[i].uType == MENU_CHECK) + AppendMenu(*hMenu, dwState | MF_CHECKED | MF_STRING, gcmi.Item[i].dwID, ptszText); + + mir_free(ptszDescr); + } + +#if !defined(__DELAYED_FOR_3_1) + if (iIndex == 0) { + AppendMenu(*hMenu, MF_SEPARATOR, 0, 0); + pos = GetMenuItemCount(*hMenu); + InsertMenu(*hMenu, pos, MF_BYPOSITION, (UINT_PTR)20020, TranslateT("Highlight User...")); + InsertMenu(*hMenu, pos, MF_BYPOSITION, (UINT_PTR)20021, TranslateT("Edit Highlight List...")); + } +#endif + if (iIndex == 1 && si->iType != GCW_SERVER && !(si->dwFlags & GC_UNICODE)) { + AppendMenu(*hMenu, MF_SEPARATOR, 0, 0); + InsertMenu(PluginConfig.g_hMenuEncoding, 1, MF_BYPOSITION | MF_STRING, (UINT_PTR)CP_UTF8, TranslateT("UTF-8")); + pos = GetMenuItemCount(*hMenu); + InsertMenu(*hMenu, pos, MF_BYPOSITION | MF_POPUP, (UINT_PTR) PluginConfig.g_hMenuEncoding, TranslateT("Character Encoding")); + for (i=0; i < GetMenuItemCount(PluginConfig.g_hMenuEncoding); i++) + CheckMenuItem(PluginConfig.g_hMenuEncoding, i, MF_BYPOSITION | MF_UNCHECKED); + if (codepage == CP_ACP) + CheckMenuItem(PluginConfig.g_hMenuEncoding, 0, MF_BYPOSITION | MF_CHECKED); + else + CheckMenuItem(PluginConfig.g_hMenuEncoding, codepage, MF_BYCOMMAND | MF_CHECKED); + + } + + return TrackPopupMenu(*hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL); +} + +void DestroyGCMenu(HMENU *hMenu, int iIndex) +{ + MENUITEMINFO mi; + mi.cbSize = sizeof(mi); + mi.fMask = MIIM_SUBMENU; + while (GetMenuItemInfo(*hMenu, iIndex, TRUE, &mi)) { + if (mi.hSubMenu != NULL) + DestroyMenu(mi.hSubMenu); + RemoveMenu(*hMenu, iIndex, MF_BYPOSITION); + } +} + +BOOL DoEventHookAsync(HWND hwnd, const TCHAR* pszID, const char* pszModule, int iType, TCHAR* pszUID, TCHAR* pszText, DWORD dwItem) +{ + SESSION_INFO* si; + GCHOOK* gch = (GCHOOK*)mir_alloc(sizeof(GCHOOK)); + GCDEST* gcd = (GCDEST*)mir_alloc(sizeof(GCDEST)); + + memset(gch, 0, sizeof(GCHOOK)); + memset(gcd, 0, sizeof(GCDEST)); + + replaceStrA(&gcd->pszModule, pszModule); + if ((si = SM_FindSession(pszID, pszModule)) == NULL) + return FALSE; + + if (!(si->dwFlags & GC_UNICODE)) { + DWORD dwCP = M->GetDword(si->hContact, "ANSIcodepage", 0); + gcd->pszID = t2a(pszID, 0); + gch->pszUID = t2a(pszUID, 0); + gch->pszText = t2a(pszText, dwCP); + } else { + replaceStr(&gcd->ptszID, pszID); + replaceStr(&gch->ptszUID, pszUID); + replaceStr(&gch->ptszText, pszText); + } + gcd->iType = iType; + gch->dwData = dwItem; + gch->pDest = gcd; + PostMessage(hwnd, GC_FIREHOOK, 0, (LPARAM) gch); + return TRUE; +} + +BOOL DoEventHook(const TCHAR* pszID, const char* pszModule, int iType, const TCHAR* pszUID, const TCHAR* pszText, DWORD dwItem) +{ + SESSION_INFO* si; + GCHOOK gch = {0}; + GCDEST gcd = {0}; + + gcd.pszModule = (char*)pszModule; + if ((si = SM_FindSession(pszID, pszModule)) == NULL) + return FALSE; + + if (!(si->dwFlags & GC_UNICODE)) { + DWORD dwCP = M->GetDword(si->hContact, "ANSIcodepage", 0); + gcd.pszID = t2a(pszID, 0); + gch.pszUID = t2a(pszUID, 0); + gch.pszText = t2a(pszText, dwCP); + } else { + gcd.ptszID = mir_tstrdup(pszID); + gch.ptszUID = mir_tstrdup(pszUID); + gch.ptszText = mir_tstrdup(pszText); + } + gcd.iType = iType; + gch.dwData = dwItem; + gch.pDest = &gcd; + NotifyEventHooks(hSendEvent, 0, (WPARAM)&gch); + + mir_free(gcd.pszID); + mir_free(gch.ptszUID); + mir_free(gch.ptszText); + return TRUE; +} + +BOOL IsEventSupported(int eventType) +{ + switch (eventType) { + // Supported events + case GC_EVENT_JOIN: + case GC_EVENT_PART: + case GC_EVENT_QUIT: + case GC_EVENT_KICK: + case GC_EVENT_NICK: + case GC_EVENT_NOTICE: + case GC_EVENT_MESSAGE: + case GC_EVENT_TOPIC: + case GC_EVENT_INFORMATION: + case GC_EVENT_ACTION: + case GC_EVENT_ADDSTATUS: + case GC_EVENT_REMOVESTATUS: + case GC_EVENT_CHUID: + case GC_EVENT_CHANGESESSIONAME: + case GC_EVENT_ADDGROUP: + case GC_EVENT_SETITEMDATA: + case GC_EVENT_GETITEMDATA: + case GC_EVENT_SETSBTEXT: + case GC_EVENT_ACK: + case GC_EVENT_SENDMESSAGE: + case GC_EVENT_SETSTATUSEX: + case GC_EVENT_CONTROL: + case GC_EVENT_SETCONTACTSTATUS: + return TRUE; + } + + // Other events + return FALSE; +} + +TCHAR* a2tf(const TCHAR* str, int flags, DWORD cp) +{ + if (str == NULL) + return NULL; + + if (flags & GC_UNICODE) + return mir_tstrdup(str); + else { + int cbLen; + TCHAR *result; + + if (cp == CP_UTF8) + return(mir_utf8decodeW((char *)str)); + + if (cp == 0) + cp = PluginConfig.m_LangPackCP; // CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 ); + cbLen = MultiByteToWideChar(cp, 0, (char*)str, -1, 0, 0); + result = (TCHAR*)mir_alloc(sizeof(TCHAR) * (cbLen + 1)); + if (result == NULL) + return NULL; + + MultiByteToWideChar(cp, 0, (char*)str, -1, result, cbLen); + result[ cbLen ] = 0; + return result; + } +} + +static char* u2a(const wchar_t* src, DWORD cp) +{ + int cbLen; + char *result; + + if (cp == 0) + cp = PluginConfig.m_LangPackCP; + else if (cp == CP_UTF8) + return(mir_utf8encodeT(src)); + + cbLen = WideCharToMultiByte(cp, 0, src, -1, NULL, 0, NULL, NULL); + result = (char*)mir_alloc(cbLen + 1); + if (result == NULL) + return NULL; + + WideCharToMultiByte(cp, 0, src, -1, result, cbLen, NULL, NULL); + result[ cbLen ] = 0; + return result; +} + +char* t2a(const TCHAR* src, DWORD cp) +{ + return u2a(src, cp); +} + +TCHAR* replaceStr(TCHAR** dest, const TCHAR* src) +{ + mir_free(*dest); + *dest = mir_tstrdup(src); + return *dest; +} + +char* replaceStrA(char** dest, const char* src) +{ + mir_free(*dest); + *dest = mir_strdup(src); + return *dest; +} + +/* + * set all filters and notification config for a session + * uses per channel mask + filterbits, default config as backup + */ + +void Chat_SetFilters(SESSION_INFO *si) +{ + DWORD dwFlags_default = 0, dwMask = 0, dwFlags_local = 0; + int i; + + if (si == NULL) + return; + + dwFlags_default = M->GetDword("Chat", "FilterFlags", 0x03E0); + dwFlags_local = M->GetDword(si->hContact, "Chat", "FilterFlags", 0x03E0); + dwMask = M->GetDword(si->hContact, "Chat", "FilterMask", 0); + + si->iLogFilterFlags = dwFlags_default; + for (i=0; i < 32; i++) { + if (dwMask & (1 << i)) + si->iLogFilterFlags = (dwFlags_local & (1 << i) ? si->iLogFilterFlags | (1 << i) : si->iLogFilterFlags & ~(1 << i)); + } + + dwFlags_default = M->GetDword("Chat", "PopupFlags", 0x03E0); + dwFlags_local = M->GetDword(si->hContact, "Chat", "PopupFlags", 0x03E0); + dwMask = M->GetDword(si->hContact, "Chat", "PopupMask", 0); + + si->iLogPopupFlags = dwFlags_default; + for (i=0; i < 32; i++) { + if (dwMask & (1 << i)) + si->iLogPopupFlags = (dwFlags_local & (1 << i) ? si->iLogPopupFlags | (1 << i) : si->iLogPopupFlags & ~(1 << i)); + } + + dwFlags_default = M->GetDword("Chat", "TrayIconFlags", 0x03E0); + dwFlags_local = M->GetDword(si->hContact, "Chat", "TrayIconFlags", 0x03E0); + dwMask = M->GetDword(si->hContact, "Chat", "TrayIconMask", 0); + + si->iLogTrayFlags = dwFlags_default; + for (i=0; i < 32; i++) { + if (dwMask & (1 << i)) + si->iLogTrayFlags = (dwFlags_local & (1 << i) ? si->iLogTrayFlags | (1 << i) : si->iLogTrayFlags & ~(1 << i)); + } + + dwFlags_default = M->GetDword("Chat", "DiskLogFlags", 0xFFFF); + si->iDiskLogFlags = dwFlags_default; + + + if (si->iLogFilterFlags == 0) + si->bFilterEnabled = 0; +} + +static TCHAR tszOldTimeStamp[30] = _T("\0"); + +TCHAR* GetChatLogsFilename(SESSION_INFO *si, time_t tTime) +{ + REPLACEVARSARRAY rva[11]; + REPLACEVARSDATA dat = {0}; + TCHAR *p = 0, *tszParsedName = 0; + int i; + bool fReparse = false; + + if (!tTime) + time(&tTime); + + /* + * check whether relevant parts of the timestamp have changed and + * we have to reparse the filename + */ + + TCHAR *tszNow = MakeTimeStamp(_T("%a%d%m%Y"), tTime); + + if (_tcscmp(tszOldTimeStamp, tszNow)) { + _tcsncpy(tszOldTimeStamp, tszNow, 30); + tszOldTimeStamp[29] = 0; + fReparse = true; + } + + if (fReparse || 0 == si->pszLogFileName[0]) { + rva[0].lptzKey = _T("d"); + rva[0].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%#d"), tTime)); + // day 01-31 + rva[1].lptzKey = _T("dd"); + rva[1].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%d"), tTime)); + // month 1-12 + rva[2].lptzKey = _T("m"); + rva[2].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%#m"), tTime)); + // month 01-12 + rva[3].lptzKey = _T("mm"); + rva[3].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%m"), tTime)); + // month text short + rva[4].lptzKey = _T("mon"); + rva[4].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%b"), tTime)); + // month text + rva[5].lptzKey = _T("month"); + rva[5].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%B"), tTime)); + // year 01-99 + rva[6].lptzKey = _T("yy"); + rva[6].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%y"), tTime)); + // year 1901-9999 + rva[7].lptzKey = _T("yyyy"); + rva[7].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%Y"), tTime)); + // weekday short + rva[8].lptzKey = _T("wday"); + rva[8].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%a"), tTime)); + // weekday + rva[9].lptzKey = _T("weekday"); + rva[9].lptzValue = mir_tstrdup(MakeTimeStamp(_T("%A"), tTime)); + // end of array + rva[10].lptzKey = NULL; + rva[10].lptzValue = NULL; + + if (g_Settings.pszLogDir[lstrlen(g_Settings.pszLogDir)-1] == '\\') + _tcscat(g_Settings.pszLogDir, _T("%userid%.log")); + + dat.cbSize = sizeof(dat); + dat.dwFlags = RVF_TCHAR; + dat.hContact = si->hContact; + dat.variables = rva; + tszParsedName = (TCHAR*) CallService(MS_UTILS_REPLACEVARS, (WPARAM)g_Settings.pszLogDir, (LPARAM)&dat); + + if (!M->pathIsAbsolute(tszParsedName)) + mir_sntprintf(si->pszLogFileName, MAX_PATH, _T("%s%s"), M->getChatLogPath(), tszParsedName); + else + mir_sntprintf(si->pszLogFileName, MAX_PATH, _T("%s"), tszParsedName); + + mir_free(tszParsedName); + + for (i=0; i < SIZEOF(rva);i++) + mir_free(rva[i].lptzValue); + + for (p = si->pszLogFileName + 2; *p; ++p) { + if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || *p == '<' || *p == '>' || *p == '|' ) + *p = _T('_'); + } + } + + return si->pszLogFileName; +} diff --git a/plugins/TabSRMM/src/chat/window.cpp b/plugins/TabSRMM/src/chat/window.cpp new file mode 100644 index 0000000000..77ee85f9b9 --- /dev/null +++ b/plugins/TabSRMM/src/chat/window.cpp @@ -0,0 +1,3833 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * This code is based on and still contains large parts of the the + * original chat module for Miranda NG, written and copyrighted + * by Joergen Persson in 2005. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: window.cpp 13631 2011-04-24 08:44:57Z silvercircle $ + * + * This implements the group chat dialog window + * + */ + +#include "..\commonheaders.h" + +#include + +//#include "../m_MathModule.h" + +// externs... +extern LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +extern HRESULT(WINAPI *MyCloseThemeData)(HANDLE); +extern REOLECallback *mREOLECallback; + +int g_cLinesPerPage=0; +int g_iWheelCarryover=0; +// + +extern HBRUSH hListBkgBrush; +extern HANDLE hSendEvent; +extern HICON hIcons[30]; +extern HMENU g_hMenu; +extern WNDPROC OldSplitterProc; + +static WNDPROC OldMessageProc; +static WNDPROC OldNicklistProc; +static WNDPROC OldFilterButtonProc; +static WNDPROC OldLogProc; +static HKL hkl = NULL; +static HCURSOR hCurHyperlinkHand; + +typedef struct +{ + time_t lastEnterTime; + TCHAR* szSearchQuery; + TCHAR* szSearchResult; + SESSION_INFO *lastSession; + TCHAR szTabSave[20]; + BOOL iSavedSpaces; +} MESSAGESUBDATA; + +static const CLSID IID_ITextDocument= { 0x8CC497C0,0xA1DF,0x11CE, { 0x80,0x98, 0x00,0xAA, 0x00,0x47,0xBE,0x5D} }; +extern WNDPROC OldIEViewProc; + +static void Chat_SetMessageLog(TWindowData *dat) +{ + unsigned int iLogMode = M->GetByte("Chat", "useIEView", 0); + + if (iLogMode == WANT_IEVIEW_LOG && dat->hwndIEView == 0) { + IEVIEWWINDOW ieWindow; + IEVIEWEVENT iee; + + //CheckAndDestroyHPP(dat); + ZeroMemory(&ieWindow, sizeof(ieWindow)); + ZeroMemory(&iee, sizeof(iee)); + ieWindow.cbSize = sizeof(ieWindow); + ieWindow.iType = IEW_CREATE; + ieWindow.dwFlags = 0; + ieWindow.dwMode = IEWM_TABSRMM; + ieWindow.parent = dat->hwnd; + ieWindow.x = 0; + ieWindow.y = 0; + ieWindow.cx = 200; + ieWindow.cy = 300; + CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow); + dat->hwndIEView = ieWindow.hwnd; + ZeroMemory(&iee, sizeof(iee)); + iee.cbSize = sizeof(iee); + iee.iType = IEE_CLEAR_LOG; + iee.hwnd = dat->hwndIEView; + iee.hContact = dat->hContact; + iee.codepage = dat->codePage; + + SESSION_INFO *si = (SESSION_INFO *)dat->si; + + iee.pszProto = si->pszModule; + CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&iee); + + Utils::showDlgControl(dat->hwnd, IDC_CHAT_LOG, SW_HIDE); + Utils::enableDlgControl(dat->hwnd, IDC_CHAT_LOG, FALSE); + } else if (iLogMode == WANT_HPP_LOG && dat->hwndHPP == 0) { + IEVIEWWINDOW ieWindow; + + ZeroMemory(&ieWindow, sizeof(ieWindow)); + //CheckAndDestroyIEView(dat); + ieWindow.cbSize = sizeof(IEVIEWWINDOW); + ieWindow.iType = IEW_CREATE; + ieWindow.dwFlags = 0; + ieWindow.dwMode = IEWM_MUCC; + ieWindow.parent = dat->hwnd; + 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(dat->hwnd, IDC_CHAT_LOG, SW_HIDE); + Utils::enableDlgControl(dat->hwnd, IDC_CHAT_LOG, FALSE); + } else { + if (iLogMode != WANT_IEVIEW_LOG) + CheckAndDestroyIEView(dat); + Utils::showDlgControl(dat->hwnd, IDC_CHAT_LOG, SW_SHOW); + Utils::enableDlgControl(dat->hwnd, IDC_CHAT_LOG, TRUE); + dat->hwndIEView = 0; + dat->hwndIWebBrowserControl = 0; + dat->hwndHPP = 0; + } +} + + +/* + * checking if theres's protected text at the point + * emulates EN_LINK WM_NOTIFY to parent to process links + */ +static BOOL CheckCustomLink(HWND hwndDlg, POINT* ptClient, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL bUrlNeeded) +{ + long res = 0, cnt = 0; + long cpMin = 0, cpMax = 0; + POINT ptEnd = {0}; + IRichEditOle* RichEditOle = NULL; + ITextDocument* TextDocument = NULL; + ITextRange* TextRange = NULL; + ITextFont* TextFont = NULL; + BOOL bIsCustomLink = FALSE; + + POINT pt = *ptClient; + ClientToScreen(hwndDlg, &pt); + + do { + if (!SendMessage(hwndDlg, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle)) break; + if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) break; + if (TextDocument->RangeFromPoint(pt.x, pt.y, &TextRange) != S_OK) break; + + TextRange->GetStart(&cpMin); + cpMax = cpMin+1; + TextRange->SetEnd(cpMax); + + if (TextRange->GetFont(&TextFont) != S_OK) + break; + + TextFont->GetProtected(&res); + if (res != tomTrue) + break; + + TextRange->GetPoint(tomEnd+TA_BOTTOM+TA_RIGHT, &ptEnd.x, &ptEnd.y); + if (pt.x > ptEnd.x || pt.y > ptEnd.y) + break; + + if (bUrlNeeded) { + TextRange->GetStoryLength(&cnt); + for (; cpMin > 0; cpMin--) { + res = tomTrue; + TextRange->SetIndex(tomCharacter, cpMin+1, tomTrue); + TextFont->GetProtected(&res); + if (res != tomTrue) { cpMin++; break; } + } + for (cpMax--; cpMax < cnt; cpMax++) { + res = tomTrue; + TextRange->SetIndex(tomCharacter, cpMax+1, tomTrue); + TextFont->GetProtected(&res); + if (res != tomTrue) + break; + } + } + + bIsCustomLink = (cpMin < cpMax); + } while(FALSE); + + if (TextFont) TextFont->Release(); + if (TextRange) TextRange->Release(); + if (TextDocument) TextDocument->Release(); + if (RichEditOle) RichEditOle->Release(); + + if (bIsCustomLink) { + ENLINK enlink = {0}; + enlink.nmhdr.hwndFrom = hwndDlg; + enlink.nmhdr.idFrom = IDC_CHAT_LOG; + enlink.nmhdr.code = EN_LINK; + enlink.msg = uMsg; + enlink.wParam = wParam; + enlink.lParam = lParam; + enlink.chrg.cpMin = cpMin; + enlink.chrg.cpMax = cpMax; + SendMessage(GetParent(hwndDlg), WM_NOTIFY, (WPARAM)IDC_CHAT_LOG, (LPARAM)&enlink); + } + return bIsCustomLink; +} + +static BOOL IsStringValidLink(TCHAR* pszText) +{ + TCHAR *p = pszText; + + if (pszText == NULL) + return FALSE; + if (lstrlen(pszText) < 5) + return FALSE; + + while (*p) { + if (*p == (TCHAR)'"') + return FALSE; + p++; + } + if (_totlower(pszText[0]) == 'w' && _totlower(pszText[1]) == 'w' && _totlower(pszText[2]) == 'w' && pszText[3] == '.' && _istalnum(pszText[4])) + return TRUE; + + return(_tcsstr(pszText, _T("://")) == NULL ? FALSE : TRUE); +} + +/* + * called whenever a group chat tab becomes active (either by switching tabs or activating a + * container window + */ + +static void Chat_UpdateWindowState(TWindowData *dat, UINT msg) +{ + if (dat == NULL) + return; + + HWND hwndDlg = dat->hwnd; + HWND hwndTab = GetParent(hwndDlg); + SESSION_INFO *si = (SESSION_INFO *)dat->si; + + if (msg == WM_ACTIVATE) { + if (dat->pContainer->dwFlags & CNT_TRANSPARENCY && CMimAPI::m_pSetLayeredWindowAttributes != NULL) { + DWORD trans = LOWORD(dat->pContainer->settings->dwTransparency); + CMimAPI::m_pSetLayeredWindowAttributes(dat->pContainer->hwnd, CSkin::m_ContainerColorKey, (BYTE)trans, (dat->pContainer->dwFlags & CNT_TRANSPARENCY ? LWA_ALPHA : 0)); + } + } + + if (si->hwndFilter) { + POINT pt; + RECT rcFilter; + + GetCursorPos(&pt); + GetWindowRect(si->hwndFilter, &rcFilter); + if (!PtInRect(&rcFilter, pt)) { + SendMessage(si->hwndFilter, WM_CLOSE, 1, 1); + si->hwndFilter = 0; + } + } + +#if defined(__FEAT_EXP_AUTOSPLITTER) + if (dat->fIsAutosizingInput && dat->iInputAreaHeight == -1) { + dat->iInputAreaHeight = 0; + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_REQUESTRESIZE, 0, 0); + } +#endif + dat->Panel->dismissConfig(); + dat->dwUnread = 0; + if (dat->pWnd) { + dat->pWnd->activateTab(); + dat->pWnd->setOverlayIcon(0, true); + } + + if (dat->pContainer->hwndSaved == hwndDlg || dat->bWasDeleted) + return; + + dat->pContainer->hwndSaved = hwndDlg; + + SetActiveSession(si->ptszID, si->pszModule); + dat->hTabIcon = dat->hTabStatusIcon; + + if (dat->iTabID >= 0) { + if (DBGetContactSettingWord(si->hContact, si->pszModule , "ApparentMode", 0) != 0) + DBWriteContactSettingWord(si->hContact, si->pszModule , "ApparentMode", (LPARAM) 0); + if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->hContact, (LPARAM)0)) + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->hContact, (LPARAM)szChatIconString); + + SendMessage(hwndDlg, GC_UPDATETITLE, 0, 1); + dat->dwTickLastEvent = 0; + dat->dwFlags &= ~MWF_DIVIDERSET; + if (KillTimer(hwndDlg, TIMERID_FLASHWND) || dat->iFlashIcon) { + FlashTab(dat, hwndTab, dat->iTabID, &dat->bTabFlash, FALSE, dat->hTabIcon); + dat->mayFlashTab = FALSE; + dat->iFlashIcon = 0; + } + if (dat->pContainer->dwFlashingStarted != 0) { + FlashContainer(dat->pContainer, 0, 0); + dat->pContainer->dwFlashingStarted = 0; + } + dat->pContainer->dwFlags &= ~CNT_NEED_UPDATETITLE; + + if (dat->dwFlags & MWF_NEEDCHECKSIZE) + PostMessage(hwndDlg, DM_SAVESIZE, 0, 0); + + if (PluginConfig.m_AutoLocaleSupport) { + if (dat->hkl == 0) + DM_LoadLocale(dat); + else + SendMessage(hwndDlg, DM_SETLOCALE, 0, 0); + } + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + dat->dwLastActivity = GetTickCount(); + dat->pContainer->dwLastActivity = dat->dwLastActivity; + dat->pContainer->MenuBar->configureMenu(); + UpdateTrayMenuState(dat, FALSE); + DM_SetDBButtonStates(hwndDlg, dat); + + if (g_Settings.MathMod) { + CallService(MTH_Set_ToolboxEditHwnd, 0, (LPARAM)GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + MTH_updateMathWindow(dat); + } + + if (dat->dwFlagsEx & MWF_EX_DELAYEDSPLITTER) { + dat->dwFlagsEx &= ~MWF_EX_DELAYEDSPLITTER; + ShowWindow(dat->pContainer->hwnd, SW_RESTORE); + PostMessage(hwndDlg, DM_SPLITTERGLOBALEVENT, dat->wParam, dat->lParam); + PostMessage(hwndDlg, WM_SIZE, 0, 0); + dat->wParam = dat->lParam = 0; + } + /* + if (dat->hwndIEView) { + RECT rcRTF; + POINT pt; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_LOG), &rcRTF); + rcRTF.left += 20; + rcRTF.top += 20; + pt.x = rcRTF.left; + pt.y = rcRTF.top; + if (dat->hwndIEView) { + if (M->GetByte("subclassIEView", 0) && dat->oldIEViewProc == 0) { + WNDPROC wndProc = (WNDPROC)SetWindowLongPtr(dat->hwndIEView, GWLP_WNDPROC, (LONG_PTR)IEViewSubclassProc); + if (OldIEViewProc == 0) + OldIEViewProc = wndProc; + dat->oldIEViewProc = wndProc; + } + } + dat->hwndIWebBrowserControl = WindowFromPoint(pt); + } + */ + } + if (M->isAero()) + InvalidateRect(hwndTab, NULL, FALSE); + if (dat->pContainer->dwFlags & CNT_SIDEBAR) + dat->pContainer->SideBar->setActiveItem(dat); + BB_SetButtonsPos(dat); + + if (dat->pWnd) + dat->pWnd->Invalidate(); +} + +/* + * initialize button bar, set all the icons and ensure proper button state + */ + +static void InitButtons(HWND hwndDlg, SESSION_INFO* si) +{ + BOOL isFlat = M->GetByte("tbflat", 1); + BOOL isThemed = PluginConfig.m_bIsXP; + MODULEINFO *pInfo = si ? MM_FindModule(si->pszModule) : NULL; + BOOL bFilterEnabled = si ? si->bFilterEnabled : FALSE; + + int i = 0; + + if (pInfo) { + Utils::enableDlgControl(hwndDlg, IDC_CHAT_BOLD, pInfo->bBold); + Utils::enableDlgControl(hwndDlg, IDC_ITALICS, pInfo->bItalics); + Utils::enableDlgControl(hwndDlg, IDC_CHAT_UNDERLINE, pInfo->bUnderline); + Utils::enableDlgControl(hwndDlg, IDC_COLOR, pInfo->bColor); + Utils::enableDlgControl(hwndDlg, IDC_BKGCOLOR, pInfo->bBkgColor); + if (si->iType == GCW_CHATROOM) + Utils::enableDlgControl(hwndDlg, IDC_CHANMGR, pInfo->bChanMgr); + } +} + +static void Chat_ResizeIeView(const TWindowData *dat) +{ + RECT rcRichEdit; + POINT pt; + IEVIEWWINDOW ieWindow; + int iMode = dat->hwndIEView ? 1 : 2; + HWND hwndDlg = dat->hwnd; + + ZeroMemory(&ieWindow, sizeof(ieWindow)); + GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_LOG), &rcRichEdit); + pt.x = rcRichEdit.left; + pt.y = rcRichEdit.top; + ScreenToClient(hwndDlg, &pt); + ieWindow.cbSize = sizeof(IEVIEWWINDOW); + ieWindow.iType = IEW_SETPOS; + ieWindow.parent = hwndDlg; + ieWindow.hwnd = iMode == 1 ? dat->hwndIEView : dat->hwndHPP; + ieWindow.x = pt.x; + ieWindow.y = pt.y; + ieWindow.cx = rcRichEdit.right - rcRichEdit.left; + ieWindow.cy = rcRichEdit.bottom - rcRichEdit.top; + if (ieWindow.cx != 0 && ieWindow.cy != 0) { + CallService(iMode == 1 ? MS_IEVIEW_WINDOW : MS_HPP_EG_WINDOW, 0, (LPARAM)&ieWindow); + } +} + +/* + * resizer callback for the group chat session window. Called from Mirandas dialog + * resizing service + */ + +static int RoomWndResize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL *urc) +{ + RECT rc, rcTabs; + SESSION_INFO* si = (SESSION_INFO*)lParam; + struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + int TabHeight; + BOOL bToolbar = !(dat->pContainer->dwFlags & CNT_HIDETOOLBAR); + BOOL bBottomToolbar = dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR ? 1 : 0; + int panelHeight = dat->Panel->getHeight() + 1; + + BOOL bNick = si->iType != GCW_SERVER && si->bNicklistEnabled; + int i = 0; + static int msgBottom = 0, msgTop = 0; + bool fInfoPanel = dat->Panel->isActive(); + + rc.bottom = rc.top = rc.left = rc.right = 0; + + GetClientRect(hwndDlg, &rcTabs); + TabHeight = rcTabs.bottom - rcTabs.top; + + if (dat->fIsAutosizingInput) + Utils::showDlgControl(hwndDlg, IDC_SPLITTERY, SW_HIDE); + + if (si->iType != GCW_SERVER) { + Utils::showDlgControl(hwndDlg, IDC_LIST, si->bNicklistEnabled ? SW_SHOW : SW_HIDE); + Utils::showDlgControl(hwndDlg, IDC_SPLITTERX, si->bNicklistEnabled ? SW_SHOW : SW_HIDE); + + Utils::enableDlgControl(hwndDlg, IDC_SHOWNICKLIST, TRUE); + Utils::enableDlgControl(hwndDlg, IDC_FILTER, TRUE); + if (si->iType == GCW_CHATROOM) { + MODULEINFO* tmp = MM_FindModule(si->pszModule); + if (tmp) + Utils::enableDlgControl(hwndDlg, IDC_CHANMGR, tmp->bChanMgr); + } + } else { + Utils::showDlgControl(hwndDlg, IDC_LIST, SW_HIDE); + Utils::showDlgControl(hwndDlg, IDC_SPLITTERX, SW_HIDE); + } + + if (si->iType == GCW_SERVER) { + Utils::enableDlgControl(hwndDlg, IDC_SHOWNICKLIST, FALSE); + Utils::enableDlgControl(hwndDlg, IDC_FILTER, FALSE); + Utils::enableDlgControl(hwndDlg, IDC_CHANMGR, FALSE); + } + //ShowWindow(GetDlgItem(hwndDlg, IDC_CHAT_TOGGLESIDEBAR), dat->pContainer->dwFlags & CNT_SIDEBAR ? SW_SHOW : SW_HIDE); + + switch (urc->wId) { + case IDC_PANELSPLITTER: + urc->rcItem.bottom = panelHeight; + urc->rcItem.top = panelHeight - 2; + return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; + case IDC_CHAT_LOG: + urc->rcItem.top = 0; + urc->rcItem.left = 0; + urc->rcItem.right = bNick ? urc->dlgNewSize.cx - si->iSplitterX : urc->dlgNewSize.cx; + urc->rcItem.bottom = (bToolbar&&!bBottomToolbar) ? (urc->dlgNewSize.cy - si->iSplitterY - (PluginConfig.g_DPIscaleY > 1.0 ? DPISCALEY_S(24) : DPISCALEY_S(23))) : (urc->dlgNewSize.cy - si->iSplitterY - DPISCALEY_S(2)); + if (fInfoPanel) + urc->rcItem.top += panelHeight; + if (CSkin::m_skinEnabled) { + CSkinItem *item = &SkinItems[ID_EXTBKHISTORY]; + if (!item->IGNORED) { + urc->rcItem.left += item->MARGIN_LEFT; + urc->rcItem.right -= item->MARGIN_RIGHT; + urc->rcItem.top += item->MARGIN_TOP; + urc->rcItem.bottom -= item->MARGIN_BOTTOM; + } + } + return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM; + + case IDC_LIST: + urc->rcItem.top = 0; + urc->rcItem.right = urc->dlgNewSize.cx ; + urc->rcItem.left = urc->dlgNewSize.cx - si->iSplitterX + 2; + urc->rcItem.bottom = (bToolbar&&!bBottomToolbar) ? (urc->dlgNewSize.cy - si->iSplitterY - DPISCALEY_S(23)) : (urc->dlgNewSize.cy - si->iSplitterY - DPISCALEY_S(2)); + if (fInfoPanel) + urc->rcItem.top += panelHeight; + if (CSkin::m_skinEnabled) { + CSkinItem *item = &SkinItems[ID_EXTBKUSERLIST]; + if (!item->IGNORED) { + urc->rcItem.left += item->MARGIN_LEFT; + urc->rcItem.right -= item->MARGIN_RIGHT; + urc->rcItem.top += item->MARGIN_TOP; + urc->rcItem.bottom -= item->MARGIN_BOTTOM; + } + } + return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM; + + case IDC_SPLITTERX: + urc->rcItem.right = urc->dlgNewSize.cx - si->iSplitterX + 2; + urc->rcItem.left = urc->dlgNewSize.cx - si->iSplitterX; + urc->rcItem.bottom = (bToolbar&&!bBottomToolbar) ? (urc->dlgNewSize.cy - si->iSplitterY - DPISCALEY_S(23)) : (urc->dlgNewSize.cy - si->iSplitterY - DPISCALEY_S(2)); + urc->rcItem.top = 0; + if (fInfoPanel) + urc->rcItem.top += panelHeight; + return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM; + + case IDC_SPLITTERY: + urc->rcItem.right = urc->dlgNewSize.cx; + urc->rcItem.top = (bToolbar&&!bBottomToolbar) ? urc->dlgNewSize.cy - si->iSplitterY : urc->dlgNewSize.cy - si->iSplitterY; + urc->rcItem.bottom = (bToolbar&&!bBottomToolbar) ? (urc->dlgNewSize.cy - si->iSplitterY + DPISCALEY_S(2)) : (urc->dlgNewSize.cy - si->iSplitterY + DPISCALEY_S(2)); + urc->rcItem.left = 0; + urc->rcItem.bottom++; + urc->rcItem.top++; + return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM; + + case IDC_CHAT_MESSAGE: + urc->rcItem.right = urc->dlgNewSize.cx ; + urc->rcItem.top = urc->dlgNewSize.cy - si->iSplitterY + 3; + urc->rcItem.bottom = urc->dlgNewSize.cy; // - 1 ; + msgBottom = urc->rcItem.bottom; + + if (dat->fIsAutosizingInput) + urc->rcItem.top -= DPISCALEY_S(1); + + msgTop = urc->rcItem.top; + if (bBottomToolbar&&bToolbar) + urc->rcItem.bottom -= DPISCALEY_S(22); + if (CSkin::m_skinEnabled) { + CSkinItem *item = &SkinItems[ID_EXTBKINPUTAREA]; + if (!item->IGNORED) { + urc->rcItem.left += item->MARGIN_LEFT; + urc->rcItem.right -= item->MARGIN_RIGHT; + urc->rcItem.top += item->MARGIN_TOP; + urc->rcItem.bottom -= item->MARGIN_BOTTOM; + } + } + return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; +} + + +/* + * subclassing for the message input control (a richedit text control) + */ + +static LRESULT CALLBACK MessageSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + MESSAGESUBDATA *dat; + SESSION_INFO* Parentsi; + struct TWindowData *mwdat; + HWND hwndParent = GetParent(hwnd); + + mwdat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA); + Parentsi = (SESSION_INFO *)mwdat->si; + + dat = (MESSAGESUBDATA *) GetWindowLongPtr(hwnd, GWLP_USERDATA); + + if (mwdat->fkeyProcessed && (msg == WM_KEYUP)) { + GetKeyboardState(mwdat->kstate); + if (mwdat->kstate[VK_CONTROL] & 0x80 || mwdat->kstate[VK_SHIFT] & 0x80) + return 0; + else { + mwdat->fkeyProcessed = false; + return 0; + } + } + switch (msg) { + case WM_NCCALCSIZE: + return(CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKINPUTAREA, msg, wParam, lParam, OldMessageProc)); + + case WM_NCPAINT: + return(CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKINPUTAREA, msg, wParam, lParam, OldMessageProc)); + + case EM_SUBCLASSED: + dat = (MESSAGESUBDATA *) mir_calloc(sizeof(MESSAGESUBDATA)); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) dat); + return 0; + + case WM_CONTEXTMENU: + { + MODULEINFO* mi = MM_FindModule(Parentsi->pszModule); + HMENU hMenu, hSubMenu; + CHARRANGE sel, all = { 0, -1}; + int iSelection; + int iPrivateBG = M->GetByte(mwdat->hContact, "private_bg", 0); + MessageWindowPopupData mwpd; + POINT pt; + int idFrom = IDC_CHAT_MESSAGE; + + GetCursorPos(&pt); + hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT)); + hSubMenu = GetSubMenu(hMenu, 2); + RemoveMenu(hSubMenu, 9, MF_BYPOSITION); + RemoveMenu(hSubMenu, 8, MF_BYPOSITION); + RemoveMenu(hSubMenu, 4, MF_BYPOSITION); + EnableMenuItem(hSubMenu, IDM_PASTEFORMATTED, MF_BYCOMMAND | ((mi && mi->bBold) ? MF_ENABLED : MF_GRAYED)); + TranslateMenu(hSubMenu); + + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) & sel); + if (sel.cpMin == sel.cpMax) { + EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED); + if (idFrom == IDC_CHAT_MESSAGE) + EnableMenuItem(hSubMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED); + } + mwpd.cbSize = sizeof(mwpd); + mwpd.uType = MSG_WINDOWPOPUP_SHOWING; + mwpd.uFlags = (idFrom == IDC_LOG ? MSG_WINDOWPOPUP_LOG : MSG_WINDOWPOPUP_INPUT); + mwpd.hContact = mwdat->hContact; + mwpd.hwnd = hwnd; + mwpd.hMenu = hSubMenu; + mwpd.selection = 0; + mwpd.pt = pt; + NotifyEventHooks(PluginConfig.m_event_MsgPopup, 0, (LPARAM)&mwpd); + + iSelection = TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, GetParent(hwnd), NULL); + + mwpd.selection = iSelection; + mwpd.uType = MSG_WINDOWPOPUP_SELECTED; + NotifyEventHooks(PluginConfig.m_event_MsgPopup, 0, (LPARAM)&mwpd); + + switch (iSelection) { + case IDM_COPY: + SendMessage(hwnd, WM_COPY, 0, 0); + break; + case IDM_CUT: + SendMessage(hwnd, WM_CUT, 0, 0); + break; + case IDM_PASTE: + case IDM_PASTEFORMATTED: + if (idFrom == IDC_CHAT_MESSAGE) + SendMessage(hwnd, EM_PASTESPECIAL, (iSelection == IDM_PASTE) ? CF_TEXTT : 0, 0); + break; + case IDM_COPYALL: + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & all); + SendMessage(hwnd, WM_COPY, 0, 0); + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & sel); + break; + case IDM_SELECTALL: + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & all); + break; + } + DestroyMenu(hMenu); + } + return TRUE; + + case WM_MOUSEWHEEL: + if ( DM_MouseWheelHandler(hwnd, hwndParent, mwdat, wParam, lParam) == 0) + return 0; + + dat->lastEnterTime = 0; + break; + + case WM_SYSKEYUP: + if (wParam == VK_MENU) { + ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_CHAT_MESSAGE); + return 0; + } + break; + + case WM_SYSKEYDOWN: + mwdat->fkeyProcessed = false; + if (ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_CHAT_MESSAGE)) { + mwdat->fkeyProcessed = true; + return 0; + } + break; + + case WM_SYSCHAR: + if (mwdat->fkeyProcessed) { + mwdat->fkeyProcessed = false; // preceeding key event has been processed by miranda hotkey service + return 0; + } + + if ((wParam >= '0' && wParam <= '9') && (GetKeyState(VK_MENU) & 0x8000)) { // ALT-1 -> ALT-0 direct tab selection + BYTE bChar = (BYTE)wParam; + int iIndex; + + if (bChar == '0') + iIndex = 10; + else + iIndex = bChar - (BYTE)'0'; + SendMessage(mwdat->pContainer->hwnd, DM_SELECTTAB, DM_SELECT_BY_INDEX, (LPARAM)iIndex); + return 0; + } + break; + + case WM_CHAR: + { + BOOL isShift, isAlt, isCtrl; + KbdState(mwdat, isShift, isCtrl, isAlt); + + //MAD: sound on typing.. + if (PluginConfig.g_bSoundOnTyping && !isAlt &&!isCtrl&&!(mwdat->pContainer->dwFlags&CNT_NOSOUND)&&wParam!=VK_ESCAPE&&!(wParam==VK_TAB&&PluginConfig.m_AllowTab)) + SkinPlaySound("SoundOnTyping"); + //MAD + + if (wParam == 0x0d && isCtrl && PluginConfig.m_MathModAvail) { + TCHAR toInsert[100]; + BYTE keyState[256]; + size_t i; + size_t iLen = lstrlen(PluginConfig.m_MathModStartDelimiter); + ZeroMemory(keyState, 256); + _tcsncpy(toInsert, PluginConfig.m_MathModStartDelimiter, 30); + _tcsncat(toInsert, PluginConfig.m_MathModStartDelimiter, 30); + SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM)toInsert); + SetKeyboardState(keyState); + for (i=0; i < iLen; i++) + SendMessage(hwnd, WM_KEYDOWN, mwdat->dwFlags & MWF_LOG_RTL ? VK_RIGHT : VK_LEFT, 0); + return 0; + } + if (isCtrl && !isAlt && !isShift) { + MODULEINFO* mi = MM_FindModule(Parentsi->pszModule); + + switch(wParam) { + case 0x09: // ctrl-i (italics) + if (mi && mi->bItalics) { + CheckDlgButton(hwndParent, IDC_ITALICS, IsDlgButtonChecked(hwndParent, IDC_ITALICS) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED); + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_ITALICS, 0), 0); + } + return 0; + case 0x02: // ctrl-b (bold) + if (mi && mi->bBold) { + CheckDlgButton(hwndParent, IDC_CHAT_BOLD, IsDlgButtonChecked(hwndParent, IDC_CHAT_BOLD) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED); + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CHAT_BOLD, 0), 0); + } + return 0; + case 0x20: // ctrl-space clear formatting + if (mi && mi->bBold && mi->bItalics && mi->bUnderline) { + CheckDlgButton(hwndParent, IDC_BKGCOLOR, BST_UNCHECKED); + CheckDlgButton(hwndParent, IDC_COLOR, BST_UNCHECKED); + CheckDlgButton(hwndParent, IDC_CHAT_BOLD, BST_UNCHECKED); + CheckDlgButton(hwndParent, IDC_CHAT_UNDERLINE, BST_UNCHECKED); + CheckDlgButton(hwndParent, IDC_ITALICS, BST_UNCHECKED); + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_BKGCOLOR, 0), 0); + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_COLOR, 0), 0); + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CHAT_BOLD, 0), 0); + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CHAT_UNDERLINE, 0), 0); + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_ITALICS, 0), 0); + } + return 0; + case 0x0c: // ctrl-l background color + if (mi && mi->bBkgColor) { + CheckDlgButton(hwndParent, IDC_BKGCOLOR, IsDlgButtonChecked(hwndParent, IDC_BKGCOLOR) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED); + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_BKGCOLOR, 0), 0); + } + return 0; + case 0x15: // ctrl-u underlined + if (mi && mi->bUnderline) { + CheckDlgButton(hwndParent, IDC_CHAT_UNDERLINE, IsDlgButtonChecked(hwndParent, IDC_CHAT_UNDERLINE) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED); + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CHAT_UNDERLINE, 0), 0); + } + return 0; // ctrl-k color + case 0x0b: + if (mi && mi->bColor) { + CheckDlgButton(hwndParent, IDC_COLOR, IsDlgButtonChecked(hwndParent, IDC_COLOR) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED); + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_COLOR, 0), 0); + } + return 0; + case 0x17: + PostMessage(hwndParent, WM_CLOSE, 0, 1); + return 0; + default: + break; + } + } + } + break; + + case WM_KEYDOWN: + { + static size_t start, end; + BOOL isShift, isCtrl, isAlt; + KbdState(mwdat, isShift, isCtrl, isAlt); + + //MAD: sound on typing.. + if (PluginConfig.g_bSoundOnTyping&&!isAlt&&wParam == VK_DELETE) + SkinPlaySound("SoundOnTyping"); + // + if (wParam == VK_INSERT && !isShift && !isCtrl && !isAlt) { + mwdat->fInsertMode = !mwdat->fInsertMode; + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd); + } + if (wParam == VK_CAPITAL || wParam == VK_NUMLOCK) + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd); + + if (isCtrl && isAlt && !isShift) { + switch (wParam) { + case VK_UP: + case VK_DOWN: + case VK_PRIOR: + case VK_NEXT: + case VK_HOME: + case VK_END: { + WPARAM wp = 0; + + if (wParam == VK_UP) + wp = MAKEWPARAM(SB_LINEUP, 0); + else if (wParam == VK_PRIOR) + wp = MAKEWPARAM(SB_PAGEUP, 0); + else if (wParam == VK_NEXT) + wp = MAKEWPARAM(SB_PAGEDOWN, 0); + else if (wParam == VK_HOME) + wp = MAKEWPARAM(SB_TOP, 0); + else if (wParam == VK_END) { + DM_ScrollToBottom(mwdat, 0, 0); + return 0; + } else if (wParam == VK_DOWN) + wp = MAKEWPARAM(SB_LINEDOWN, 0); + + SendMessage(GetDlgItem(hwndParent, IDC_CHAT_LOG), WM_VSCROLL, wp, 0); + return 0; + } + } + } + + if (wParam == VK_RETURN) { + if (isShift) { + if (PluginConfig.m_SendOnShiftEnter) { + PostMessage(hwndParent, WM_COMMAND, IDOK, 0); + return 0; + } else + break; + } + if ((isCtrl && !isShift) ^(0 != PluginConfig.m_SendOnEnter)) { + PostMessage(hwndParent, WM_COMMAND, IDOK, 0); + return 0; + } + if (PluginConfig.m_SendOnEnter || PluginConfig.m_SendOnDblEnter) { + if (isCtrl) + break; + else { + if (PluginConfig.m_SendOnDblEnter) { + if (dat->lastEnterTime + 2 < time(NULL)) { + dat->lastEnterTime = time(NULL); + break; + } else { + SendMessage(hwnd, WM_KEYDOWN, VK_BACK, 0); + SendMessage(hwnd, WM_KEYUP, VK_BACK, 0); + PostMessage(hwndParent, WM_COMMAND, IDOK, 0); + return 0; + } + } + PostMessage(hwndParent, WM_COMMAND, IDOK, 0); + return 0; + } + } else + break; + } else + dat->lastEnterTime = 0; + + if ((wParam == VK_NEXT && isCtrl && !isShift) || (wParam == VK_TAB && isCtrl && !isShift)) { // CTRL-TAB (switch tab/window) + SendMessage(mwdat->pContainer->hwnd, DM_SELECTTAB, DM_SELECT_NEXT, 0); + return TRUE; + } + + if ((wParam == VK_PRIOR && isCtrl && !isShift) || (wParam == VK_TAB && isCtrl && isShift)) { // CTRL_SHIFT-TAB (switch tab/window) + SendMessage(mwdat->pContainer->hwnd, DM_SELECTTAB, DM_SELECT_PREV, 0); + return TRUE; + } + if (wParam == VK_TAB && !isCtrl && !isShift) { //tab-autocomplete + int iLen, end, topicStart; + BOOL isTopic = FALSE; + BOOL isRoom = FALSE; + wchar_t* pszText = NULL; + GETTEXTEX gt = {0}; + LRESULT lResult = (LRESULT)SendMessage(hwnd, EM_GETSEL, (WPARAM)NULL, (LPARAM)NULL); + bool fCompleted = false; + + SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + start = LOWORD(lResult); + end = HIWORD(lResult); + SendMessage(hwnd, EM_SETSEL, end, end); + + gt.codepage = 1200; + gt.flags = GTL_DEFAULT | GTL_PRECISE; + + iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)>, (LPARAM)0); + if (iLen > 0) { + wchar_t* pszName = NULL; + pszText = reinterpret_cast(Utils::safeMirCalloc((iLen + 10) * sizeof(wchar_t))); + gt.flags = GT_DEFAULT; + gt.cb = (iLen + 9) * sizeof(wchar_t); + + SendMessage(hwnd, EM_GETTEXTEX, (WPARAM)>, (LPARAM)pszText); + + if (start > 1 && pszText[start-1] == ' ' && pszText[start-2] == ':') + start--; + + while( start > 0 && pszText[start-1] != ' ' && pszText[start-1] != 13 && pszText[start-1] != VK_TAB) + start--; + + while (end < iLen && pszText[end] != ' ' && pszText[end] != 13 && pszText[end-1] != VK_TAB) + end ++; + + if (pszText[start] == '#') + isRoom = TRUE; + else { + topicStart = (int)start; + while ( topicStart >0 && (pszText[topicStart-1] == ' ' || pszText[topicStart-1] == 13 || pszText[topicStart-1] == VK_TAB)) + topicStart--; + if (topicStart > 5 && _tcsstr(&pszText[topicStart-6], _T("/topic")) == &pszText[topicStart-6]) + isTopic = TRUE; + } + if (dat->szSearchQuery == NULL) { + size_t len = (end - start) + 1; + dat->szSearchQuery = reinterpret_cast(Utils::safeMirAlloc(sizeof(wchar_t) * len)); + wcsncpy( dat->szSearchQuery, pszText + start, len); + dat->szSearchQuery[len - 1] = 0; + dat->szSearchResult = mir_tstrdup(dat->szSearchQuery); + dat->lastSession = NULL; + } + if (isTopic) { + pszName = Parentsi->ptszTopic; + } else if (isRoom) { + dat->lastSession = SM_FindSessionAutoComplete(Parentsi->pszModule, Parentsi, dat->lastSession, dat->szSearchQuery, dat->szSearchResult); + if (dat->lastSession != NULL) + pszName = dat->lastSession->ptszName; + } else + pszName = UM_FindUserAutoComplete(Parentsi->pUsers, dat->szSearchQuery, dat->szSearchResult); + + mir_free(pszText); + pszText = NULL; + mir_free(dat->szSearchResult); + dat->szSearchResult = 0; + if (pszName == 0) { + if ((int)end != (int)start) { + SendMessage(hwnd, EM_SETSEL, start, end); + SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) dat->szSearchQuery); + } + mir_free(dat->szSearchQuery); + dat->szSearchQuery = NULL; + } else { + pszText = 0; + dat->szSearchResult = mir_tstrdup(pszName); + if ((int)end != (int)start) { + if (!isRoom && !isTopic && g_Settings.AddColonToAutoComplete && start == 0) { + pszText = reinterpret_cast(Utils::safeMirAlloc((wcslen(pszName) + 4) * sizeof(wchar_t))); + wcscpy(pszText, pszName); + wcscat(pszText, L": "); + pszName = pszText; + } + SendMessage(hwnd, EM_SETSEL, start, end); + SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM)pszName); + } + if (pszText) + mir_free(pszText); + fCompleted = true; + } + } + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); + if (!fCompleted && !PluginConfig.m_AllowTab) { + if ((GetSendButtonState(mwdat->hwnd) != PBS_DISABLED)) + SetFocus(GetDlgItem(mwdat->hwnd, IDOK)); + else + SetFocus(GetDlgItem(mwdat->hwnd, IDC_CHAT_LOG)); + } + return 0; + } else if (wParam != VK_RIGHT && wParam != VK_LEFT) { + mir_free(dat->szSearchQuery); + dat->szSearchQuery = NULL; + mir_free(dat->szSearchResult); + dat->szSearchResult = NULL; + } + + if (wParam == VK_F4 && isCtrl && !isAlt) { // ctrl-F4 (close tab) + SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(IDC_CHAT_CLOSE, BN_CLICKED), 0); + return 0; + } + + if (wParam == VK_NEXT || wParam == VK_PRIOR) { + HWND htemp = hwndParent; + SendDlgItemMessage(htemp, IDC_CHAT_LOG, msg, wParam, lParam); + dat->lastEnterTime = 0; + return 0; + } + + if (wParam == VK_UP && isCtrl && !isAlt) { + int iLen; + GETTEXTLENGTHEX gtl = {0}; + SETTEXTEX ste; + LOGFONTA lf; + char* lpPrevCmd = SM_GetPrevCommand(Parentsi->ptszID, Parentsi->pszModule); + + SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + + LoadLogfont(MSGFONTID_MESSAGEAREA, &lf, NULL, FONTMODULE); + ste.flags = ST_DEFAULT; + ste.codepage = CP_ACP; + if (lpPrevCmd) + SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpPrevCmd); + else + SetWindowText(hwnd, _T("")); + + gtl.flags = GTL_PRECISE; + gtl.codepage = CP_ACP; + iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM) & gtl, (LPARAM)NULL); + SendMessage(hwnd, EM_SCROLLCARET, 0, 0); + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); + SendMessage(hwnd, EM_SETSEL, iLen, iLen); + dat->lastEnterTime = 0; + return 0; + } + + if (wParam == VK_DOWN && isCtrl && !isAlt) { + int iLen; + GETTEXTLENGTHEX gtl = {0}; + SETTEXTEX ste; + + char* lpPrevCmd = SM_GetNextCommand(Parentsi->ptszID, Parentsi->pszModule); + SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + + ste.flags = ST_DEFAULT; + ste.codepage = CP_ACP; + if (lpPrevCmd) + SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM) lpPrevCmd); + else + SetWindowText(hwnd, _T("")); + + gtl.flags = GTL_PRECISE; + gtl.codepage = CP_ACP; + iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM) & gtl, (LPARAM)NULL); + SendMessage(hwnd, EM_SCROLLCARET, 0, 0); + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); + SendMessage(hwnd, EM_SETSEL, iLen, iLen); + dat->lastEnterTime = 0; + return 0; + } + if (wParam == VK_RETURN) + break; + //fall through + } + + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_KILLFOCUS: + dat->lastEnterTime = 0; + break; + + case WM_KEYUP: + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + { + CHARFORMAT2 cf; + UINT u = 0; + UINT u2 = 0; + COLORREF cr; + MODULEINFO* mi = MM_FindModule(Parentsi->pszModule); + + LoadLogfont(MSGFONTID_MESSAGEAREA, NULL, &cr, FONTMODULE); + + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_BACKCOLOR | CFM_COLOR | CFM_UNDERLINETYPE; + cf.dwEffects = 0; + SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + + if (mi && mi->bColor) { + int index = Chat_GetColorIndex(Parentsi->pszModule, cf.crTextColor); + u = IsDlgButtonChecked(GetParent(hwnd), IDC_COLOR); + + if (index >= 0) { + Parentsi->bFGSet = TRUE; + Parentsi->iFG = index; + } + + if (u == BST_UNCHECKED && cf.crTextColor != cr) + CheckDlgButton(hwndParent, IDC_COLOR, BST_CHECKED); + else if (u == BST_CHECKED && cf.crTextColor == cr) + CheckDlgButton(hwndParent, IDC_COLOR, BST_UNCHECKED); + } + + if (mi && mi->bBkgColor) { + int index = Chat_GetColorIndex(Parentsi->pszModule, cf.crBackColor); + COLORREF crB = (COLORREF)M->GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR); + u = IsDlgButtonChecked(hwndParent, IDC_BKGCOLOR); + + if (index >= 0) { + Parentsi->bBGSet = TRUE; + Parentsi->iBG = index; + } + + if (u == BST_UNCHECKED && cf.crBackColor != crB) + CheckDlgButton(hwndParent, IDC_BKGCOLOR, BST_CHECKED); + else if (u == BST_CHECKED && cf.crBackColor == crB) + CheckDlgButton(hwndParent, IDC_BKGCOLOR, BST_UNCHECKED); + } + + if (mi && mi->bBold) { + u = IsDlgButtonChecked(hwndParent, IDC_CHAT_BOLD); + u2 = cf.dwEffects; + u2 &= CFE_BOLD; + if (u == BST_UNCHECKED && u2) + CheckDlgButton(hwndParent, IDC_CHAT_BOLD, BST_CHECKED); + else if (u == BST_CHECKED && u2 == 0) + CheckDlgButton(hwndParent, IDC_CHAT_BOLD, BST_UNCHECKED); + } + + if (mi && mi->bItalics) { + u = IsDlgButtonChecked(hwndParent, IDC_ITALICS); + u2 = cf.dwEffects; + u2 &= CFE_ITALIC; + if (u == BST_UNCHECKED && u2) + CheckDlgButton(hwndParent, IDC_ITALICS, BST_CHECKED); + else if (u == BST_CHECKED && u2 == 0) + CheckDlgButton(hwndParent, IDC_ITALICS, BST_UNCHECKED); + } + + if (mi && mi->bUnderline) { + u = IsDlgButtonChecked(hwndParent, IDC_CHAT_UNDERLINE); + if (cf.dwEffects & CFE_UNDERLINE && (cf.bUnderlineType & CFU_UNDERLINE || cf.bUnderlineType & CFU_UNDERLINEWORD)) { + if (u == BST_UNCHECKED ) + CheckDlgButton(hwndParent, IDC_CHAT_UNDERLINE, BST_CHECKED); + } + else { + if (u == BST_CHECKED) + CheckDlgButton(hwndParent, IDC_CHAT_UNDERLINE, BST_UNCHECKED); + } + } + } + break; + + case WM_INPUTLANGCHANGE: + if (PluginConfig.m_AutoLocaleSupport && GetFocus() == hwnd && mwdat->pContainer->hwndActive == hwndParent && GetForegroundWindow() == mwdat->pContainer->hwnd && GetActiveWindow() == mwdat->pContainer->hwnd) { + DM_SaveLocale(mwdat, wParam, lParam); + SendMessage(hwnd, EM_SETLANGOPTIONS, 0, (LPARAM) SendMessage(hwnd, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD); + return 1; + } + break; + + case WM_ERASEBKGND: + return CSkin::m_skinEnabled ? 0 : 1; + + case EM_UNSUBCLASSED: + mir_free(dat); + return 0; + } + + return CallWindowProc(OldMessageProc, hwnd, msg, wParam, lParam); +} + + +/* +* subclassing for the message filter dialog (set and configure event filters for the current +* session +*/ + +static UINT _eventorder[] = { GC_EVENT_ACTION, + GC_EVENT_MESSAGE, + GC_EVENT_NICK, + GC_EVENT_JOIN, + GC_EVENT_PART, + GC_EVENT_TOPIC, + GC_EVENT_ADDSTATUS, + GC_EVENT_INFORMATION, + GC_EVENT_QUIT, + GC_EVENT_KICK, + GC_EVENT_NOTICE, + 0 +}; + +static INT_PTR CALLBACK FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + SESSION_INFO * si = (SESSION_INFO *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + switch (uMsg) { + case WM_INITDIALOG: { + + si = (SESSION_INFO *)lParam; + DWORD dwMask = M->GetDword(si->hContact, "Chat", "FilterMask", 0); + DWORD dwFlags = M->GetDword(si->hContact, "Chat", "FilterFlags", 0); + + DWORD dwPopupMask = M->GetDword(si->hContact, "Chat", "PopupMask", 0); + DWORD dwPopupFlags = M->GetDword(si->hContact, "Chat", "PopupFlags", 0); + + DWORD dwTrayMask = M->GetDword(si->hContact, "Chat", "TrayIconMask", 0); + DWORD dwTrayFlags = M->GetDword(si->hContact, "Chat", "TrayIconFlags", 0); + + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)si); + + for (int i = 0; _eventorder[i]; i++) { + CheckDlgButton(hwndDlg, IDC_1 + i, dwMask & _eventorder[i] ? (dwFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE); + CheckDlgButton(hwndDlg, IDC_P1 + i, dwPopupMask & _eventorder[i] ? (dwPopupFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE); + CheckDlgButton(hwndDlg, IDC_T1 + i, dwTrayMask & _eventorder[i] ? (dwTrayFlags & _eventorder[i] ? BST_CHECKED : BST_UNCHECKED) : BST_INDETERMINATE); + } + return(FALSE); + } + 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); + + case WM_CLOSE: + if (wParam == 1 && lParam == 1) { + int iFlags = 0, i; + UINT result; + DWORD dwMask = 0, dwFlags = 0; + + for (i=0; _eventorder[i]; i++) { + result = IsDlgButtonChecked(hwndDlg, IDC_1 + i); + dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0); + iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0); + } + + if (iFlags&GC_EVENT_ADDSTATUS) + iFlags |= GC_EVENT_REMOVESTATUS; + + if (si) { + if (dwMask == 0) { + DBDeleteContactSetting(si->hContact, "Chat", "FilterFlags"); + DBDeleteContactSetting(si->hContact, "Chat", "FilterMask"); + } else { + M->WriteDword(si->hContact, "Chat", "FilterFlags", iFlags); + M->WriteDword(si->hContact, "Chat", "FilterMask", dwMask); + } + } + + dwMask = iFlags = 0; + + for (i=0; _eventorder[i]; i++) { + result = IsDlgButtonChecked(hwndDlg, IDC_P1 + i); + dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0); + iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0); + } + + if (iFlags&GC_EVENT_ADDSTATUS) + iFlags |= GC_EVENT_REMOVESTATUS; + + if (si) { + if (dwMask == 0) { + DBDeleteContactSetting(si->hContact, "Chat", "PopupFlags"); + DBDeleteContactSetting(si->hContact, "Chat", "PopupMask"); + } else { + M->WriteDword(si->hContact, "Chat", "PopupFlags", iFlags); + M->WriteDword(si->hContact, "Chat", "PopupMask", dwMask); + } + } + + dwMask = iFlags = 0; + + for (i=0; _eventorder[i]; i++) { + result = IsDlgButtonChecked(hwndDlg, IDC_T1 + i); + dwMask |= (result != BST_INDETERMINATE ? _eventorder[i] : 0); + iFlags |= (result == BST_CHECKED ? _eventorder[i] : 0); + } + if (iFlags&GC_EVENT_ADDSTATUS) + iFlags |= GC_EVENT_REMOVESTATUS; + + if (si) { + if (dwMask == 0) { + DBDeleteContactSetting(si->hContact, "Chat", "TrayIconFlags"); + DBDeleteContactSetting(si->hContact, "Chat", "TrayIconMask"); + } else { + M->WriteDword(si->hContact, "Chat", "TrayIconFlags", iFlags); + M->WriteDword(si->hContact, "Chat", "TrayIconMask", dwMask); + } + Chat_SetFilters(si); + SendMessage(si->hWnd, GC_CHANGEFILTERFLAG, 0, (LPARAM)iFlags); + if (si->bFilterEnabled) + SendMessage(si->hWnd, GC_REDRAWLOG, 0, 0); + } + } + DestroyWindow(hwndDlg); + break; + case WM_DESTROY: + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + break; + } + return(FALSE); +} + +/** + * subclass for some tool bar buttons which must perform special actions + * on right click. + */ +static LRESULT CALLBACK ButtonSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND hwndParent = GetParent(hwnd); + + switch (msg) { + case WM_RBUTTONUP: { + HWND hFilter = GetDlgItem(hwndParent, IDC_FILTER); + HWND hColor = GetDlgItem(hwndParent, IDC_COLOR); + HWND hBGColor = GetDlgItem(hwndParent, IDC_BKGCOLOR); + + if (M->GetByte("Chat", "RightClickFilter", 0) != 0) { + if (hFilter == hwnd) + SendMessage(hwndParent, GC_SHOWFILTERMENU, 0, 0); + if (hColor == hwnd) + SendMessage(hwndParent, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_COLOR); + if (hBGColor == hwnd) + SendMessage(hwndParent, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_BKGCOLOR); + } + } + break; + } + + return CallWindowProc(OldFilterButtonProc, hwnd, msg, wParam, lParam); +} + + +/* + * subclassing for the message history display (rich edit control in which the chat history appears) + */ + +static LRESULT CALLBACK LogSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND hwndParent = GetParent(hwnd); + struct TWindowData *mwdat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA); + + switch (msg) { + case WM_NCCALCSIZE: + return(CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, OldLogProc)); + + case WM_NCPAINT: + return(CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKHISTORY, msg, wParam, lParam, OldLogProc)); + + case WM_COPY: + return(DM_WMCopyHandler(hwnd, OldLogProc, wParam, lParam)); + + case WM_SETCURSOR: + if (g_Settings.ClickableNicks && (LOWORD(lParam) == HTCLIENT)) { + POINT pt; + GetCursorPos(&pt); + ScreenToClient(hwnd,&pt); + if (CheckCustomLink(hwnd, &pt, msg, wParam, lParam, FALSE)) return TRUE; + } + break; + + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + if (g_Settings.ClickableNicks) { + POINT pt={LOWORD(lParam), HIWORD(lParam)}; + CheckCustomLink(hwnd, &pt, msg, wParam, lParam, TRUE); + } + break; + + case WM_LBUTTONUP: + { + CHARRANGE sel; + if (g_Settings.ClickableNicks) { + POINT pt={LOWORD(lParam), HIWORD(lParam)}; + CheckCustomLink(hwnd, &pt, msg, wParam, lParam, TRUE); + } + if (true || M->GetByte("autocopy", 0)) { + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) &sel); + if (sel.cpMin != sel.cpMax) { + SendMessage(hwnd, WM_COPY, 0, 0); + sel.cpMin = sel.cpMax ; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & sel); + SetFocus(GetDlgItem(hwndParent, IDC_CHAT_MESSAGE)); + } + } + } + break; + + case WM_KEYDOWN: + if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window) + PostMessage(hwndParent, WM_CLOSE, 0, 1); + return TRUE; + } + break; + + case WM_SYSKEYUP: + if (wParam == VK_MENU) { + ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_CHAT_LOG); + return 0; + } + break; + + case WM_SYSKEYDOWN: + mwdat->fkeyProcessed = false; + if (ProcessHotkeysByMsgFilter(hwnd, msg, wParam, lParam, IDC_CHAT_LOG)) { + mwdat->fkeyProcessed = true; + return 0; + } + break; + + case WM_SYSCHAR: { + if (mwdat->fkeyProcessed) { + mwdat->fkeyProcessed = false; + return 0; + } + break; + } + + case WM_ACTIVATE: { + if (LOWORD(wParam) == WA_INACTIVE) { + CHARRANGE sel; + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) &sel); + if (sel.cpMin != sel.cpMax) { + sel.cpMin = sel.cpMax ; + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & sel); + } + } + } + break; + + case WM_CHAR: + SetFocus(GetDlgItem(hwndParent, IDC_CHAT_MESSAGE)); + SendMessage(GetDlgItem(hwndParent, IDC_CHAT_MESSAGE), WM_CHAR, wParam, lParam); + break; + } + + return CallWindowProc(OldLogProc, hwnd, msg, wParam, lParam); +} + + +/* + * process mouse - hovering for the nickname list. fires events so the protocol can + * show the userinfo - tooltip. + */ + +static void ProcessNickListHovering(HWND hwnd, int hoveredItem, POINT * pt, SESSION_INFO * parentdat) +{ + static int currentHovered = -1; + static HWND hwndToolTip = NULL; + static HWND oldParent = NULL; + TOOLINFO ti = {0}; + RECT clientRect; + BOOL bNewTip = FALSE; + USERINFO *ui1 = NULL; + + if (hoveredItem == currentHovered) return; + currentHovered = hoveredItem; + + if (oldParent != hwnd && hwndToolTip) { + SendMessage(hwndToolTip, TTM_DELTOOL, 0, 0); + DestroyWindow(hwndToolTip); + hwndToolTip = NULL; + } + if (hoveredItem == -1) { + + SendMessage(hwndToolTip, TTM_ACTIVATE, 0, 0); + + } else { + + if (!hwndToolTip) { + hwndToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL, + WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + hwnd, NULL, g_hInst, NULL); + bNewTip = TRUE; + } + + GetClientRect(hwnd, &clientRect); + ti.cbSize = sizeof(TOOLINFO); + ti.uFlags = TTF_SUBCLASS; + ti.hinst = g_hInst; + ti.hwnd = hwnd; + ti.uId = 1; + ti.rect = clientRect; + + ti.lpszText = NULL; + + ui1 = SM_GetUserFromIndex(parentdat->ptszID, parentdat->pszModule, currentHovered); + if (ui1) { + char serviceName[256]; + _snprintf(serviceName, SIZEOF(serviceName), "%s"MS_GC_PROTO_GETTOOLTIPTEXT, parentdat->pszModule); + if (ServiceExists(serviceName)) + ti.lpszText = (TCHAR*)CallService(serviceName, (WPARAM)parentdat->ptszID, (LPARAM)ui1->pszUID); + else { + TCHAR ptszBuf[ 1024 ]; + mir_sntprintf( ptszBuf, SIZEOF(ptszBuf), _T("%s: %s\r\n%s: %s\r\n%s: %s"), + TranslateT("Nick name"), ui1->pszNick, + TranslateT("Unique Id"), ui1->pszUID, + TranslateT("Status"), TM_WordToString( parentdat->pStatuses, ui1->Status )); + ti.lpszText = mir_tstrdup( ptszBuf ); + } + } + + SendMessage(hwndToolTip, bNewTip ? TTM_ADDTOOL : TTM_UPDATETIPTEXT, 0, (LPARAM) &ti); + SendMessage(hwndToolTip, TTM_ACTIVATE, (ti.lpszText != NULL) , 0); + SendMessage(hwndToolTip, TTM_SETMAXTIPWIDTH, 0 , 400); + if (ti.lpszText) + mir_free(ti.lpszText); + } +} + +/* + * subclassing for the nickname list control. It is an ownerdrawn listbox + */ + +static LRESULT CALLBACK NicklistSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND hwndParent = GetParent(hwnd); + struct TWindowData *mwdat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA); + + static BOOL isToolTip = NULL; + static int currentHovered = -1; + + switch (msg) { + //MAD: attemp to fix weird bug, when combobox with hidden vscroll + //can't be scrolled with mouse-wheel. + case WM_NCCALCSIZE: { + if (CSkin::m_DisableScrollbars) { + RECT lpRect; + LONG itemHeight; + + GetClientRect (hwnd, &lpRect); + itemHeight = SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0); + g_cLinesPerPage = (lpRect.bottom - lpRect.top) /itemHeight ; + } + return(CSkin::NcCalcRichEditFrame(hwnd, mwdat, ID_EXTBKUSERLIST, msg, wParam, lParam, OldNicklistProc)); + } + // + case WM_NCPAINT: + return(CSkin::DrawRichEditFrame(hwnd, mwdat, ID_EXTBKUSERLIST, msg, wParam, lParam, OldNicklistProc)); + + case WM_ERASEBKGND: { + HDC dc = (HDC)wParam; + struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA); + SESSION_INFO *parentdat = (SESSION_INFO *)dat->si; + if (dc) { + int height, index, items = 0; + + index = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0); + if (index == LB_ERR || parentdat->nUsersInNicklist <= 0) + return 0; + + items = parentdat->nUsersInNicklist - index; + height = SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0); + + if (height != LB_ERR) { + RECT rc = {0}; + GetClientRect(hwnd, &rc); + + if (rc.bottom - rc.top > items * height) { + rc.top = items * height; + FillRect(dc, &rc, hListBkgBrush); + } + } + } + } + return 1; + + //MAD + case WM_MOUSEWHEEL: { + if (CSkin::m_DisableScrollbars) { + UINT uScroll; + int dLines; + short zDelta=(short)HIWORD(wParam); + if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uScroll, 0)) + uScroll = 3; /* default value */ + + if (uScroll == WHEEL_PAGESCROLL) + uScroll = g_cLinesPerPage; + if (uScroll == 0) + return 0; + + zDelta += g_iWheelCarryover; /* Accumulate wheel motion */ + + dLines = zDelta * (int)uScroll / WHEEL_DELTA; + + + //Record the unused portion as the next carryover. + g_iWheelCarryover = zDelta - dLines * WHEEL_DELTA / (int)uScroll; + + + // scrolling. + while (abs(dLines)) { + if (dLines > 0) { + SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); + dLines--; + } else { + SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); + dLines++; + } + } + return 0; + } + break; + } +//MAD_ + case WM_KEYDOWN: + if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window) + PostMessage(hwndParent, WM_CLOSE, 0, 1); + return TRUE; + } + if (wParam == VK_ESCAPE || wParam == VK_UP || wParam == VK_DOWN || wParam == VK_NEXT || + wParam == VK_PRIOR || wParam == VK_TAB || wParam == VK_HOME || wParam == VK_END) { + if (mwdat && mwdat->si) { + SESSION_INFO *si = (SESSION_INFO *)mwdat->si; + si->szSearch[0] = 0; + si->iSearchItem = -1; + } + } + break; + + case WM_SETFOCUS: + case WM_KILLFOCUS: + if (mwdat && mwdat->si) { // set/kill focus invalidates incremental search status + SESSION_INFO *si = (SESSION_INFO *)mwdat->si; + si->szSearch[0] = 0; + si->iSearchItem = -1; + } + break; + + case WM_CHAR: + case WM_UNICHAR: { + /* + * simple incremental search for the user (nick) - list control + * typing esc or movement keys will clear the current search string + */ + + if (mwdat && mwdat->si) { + SESSION_INFO *si = (SESSION_INFO *)mwdat->si; + if (wParam == 27 && si->szSearch[0]) { // escape - reset everything + si->szSearch[0] = 0; + si->iSearchItem = -1; + break; + } else if (wParam == '\b' && si->szSearch[0]) // backspace + si->szSearch[lstrlen(si->szSearch) - 1] = '\0'; + else if (wParam < ' ') + break; + else { + TCHAR szNew[2]; + szNew[0] = (TCHAR) wParam; + szNew[1] = '\0'; + if (lstrlen(si->szSearch) >= SIZEOF(si->szSearch) - 2) { + MessageBeep(MB_OK); + break; + } + _tcscat(si->szSearch, szNew); + } + if (si->szSearch[0]) { + int iItems = SendMessage(hwnd, LB_GETCOUNT, 0, 0); + int i; + USERINFO *ui; + + /* + * iterate over the (sorted) list of nicknames and search for the + * string we have + */ + + for (i=0; i < iItems; i++) { + ui = UM_FindUserFromIndex(si->pUsers, i); + if (ui) { + if (!_tcsnicmp(ui->pszNick, si->szSearch, lstrlen(si->szSearch))) { + SendMessage(hwnd, LB_SETSEL, FALSE, -1); + SendMessage(hwnd, LB_SETSEL, TRUE, i); + si->iSearchItem = i; + InvalidateRect(hwnd, NULL, FALSE); + return 0; + } + } + } + if (i == iItems) { + MessageBeep(MB_OK); + si->szSearch[lstrlen(si->szSearch) - 1] = '\0'; + return 0; + } + } + } + break; + } + + case WM_RBUTTONDOWN: { + int iCounts = SendMessage(hwnd, LB_GETSELCOUNT, 0, 0); + + if (iCounts != LB_ERR && iCounts > 1) + return 0; + SendMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam); + break; + } + + case WM_RBUTTONUP: + SendMessage(hwnd, WM_LBUTTONUP, wParam, lParam); + break; + + case WM_MEASUREITEM: { + MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *) lParam; + if (mis->CtlType == ODT_MENU) + return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam); + return FALSE; + } + + case WM_DRAWITEM: { + DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *) lParam; + if (dis->CtlType == ODT_MENU) + return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam); + return FALSE; + } + case WM_CONTEXTMENU: { + TVHITTESTINFO hti; + int item; + int height; + USERINFO * ui; + struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA); + SESSION_INFO *parentdat = (SESSION_INFO *)dat->si; + + + hti.pt.x = (short) LOWORD(lParam); + hti.pt.y = (short) HIWORD(lParam); + if (hti.pt.x == -1 && hti.pt.y == -1) { + int index = SendMessage(hwnd, LB_GETCURSEL, 0, 0); + int top = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0); + height = SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0); + hti.pt.x = 4; + hti.pt.y = (index - top) * height + 1; + } else + ScreenToClient(hwnd, &hti.pt); + + item = (DWORD)(SendMessage(hwnd, LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y))); + if ( HIWORD( item ) == 1 ) + item = (DWORD)(-1); + else + item &= 0xFFFF; + + ui = SM_GetUserFromIndex(parentdat->ptszID, parentdat->pszModule, item); + // ui = (USERINFO *)SendMessage(GetDlgItem(hwndParent, IDC_LIST), LB_GETITEMDATA, item, 0); + if (ui) { + HMENU hMenu = 0; + UINT uID; + USERINFO uinew; + + memcpy(&uinew, ui, sizeof(USERINFO)); + if (hti.pt.x == -1 && hti.pt.y == -1) + hti.pt.y += height - 4; + ClientToScreen(hwnd, &hti.pt); + uID = CreateGCMenu(hwnd, &hMenu, 0, hti.pt, parentdat, uinew.pszUID, NULL); + + switch (uID) { + case 0: + break; + + case 20020: { // add to highlight... + RECT rc, rcWnd; + THighLightEdit the = {THighLightEdit::CMD_ADD, parentdat, ui}; + + if (parentdat && ui) { + HWND hwnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_ADDHIGHLIGHT), parentdat->dat->pContainer->hwnd, CMUCHighlight::dlgProcAdd, (LPARAM)&the); + TranslateDialogDefault(hwnd); + GetClientRect(parentdat->pContainer->hwnd, &rcWnd); + GetWindowRect(hwnd, &rc); + + SetWindowPos(hwnd, HWND_TOP, (rcWnd.right - (rc.right - rc.left)) / 2, (rcWnd.bottom - (rc.bottom - rc.top)) / 2 , 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); + } + break; + } + + case ID_MESS: + DoEventHookAsync(GetParent(hwnd), parentdat->ptszID, parentdat->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, (LPARAM)NULL); + break; + + default: { + int iCount = SendMessage(hwnd, LB_GETCOUNT, 0, 0); + + if (iCount != LB_ERR) { + int iSelectedItems = SendMessage(hwnd, LB_GETSELCOUNT, 0, 0); + + if (iSelectedItems != LB_ERR) { + int *pItems = (int *)malloc(sizeof(int) * (iSelectedItems + 1)); + + if (pItems) { + if (SendMessage(hwnd, LB_GETSELITEMS, (WPARAM)iSelectedItems, (LPARAM)pItems) != LB_ERR) { + USERINFO *ui1 = NULL; + int i; + + for (i=0; i < iSelectedItems; i++) { + ui1 = SM_GetUserFromIndex(parentdat->ptszID, parentdat->pszModule, pItems[i]); + if (ui1) + DoEventHookAsync(hwndParent, parentdat->ptszID, parentdat->pszModule, GC_USER_NICKLISTMENU, ui1->pszUID, NULL, (LPARAM)uID); + } + } + free(pItems); + } + } + } + //DoEventHookAsync(hwndParent, parentdat->ptszID, parentdat->pszModule, GC_USER_NICKLISTMENU, ui->pszUID, NULL, (LPARAM)uID); + break; + } + } + DestroyGCMenu(&hMenu, 1); + return TRUE; + } + } + break; + + case WM_MOUSEMOVE: { + POINT pt; + RECT clientRect; + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + GetClientRect(hwnd, &clientRect); + if (PtInRect(&clientRect, pt)) { + //hit test item under mouse + struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA); + SESSION_INFO *parentdat = (SESSION_INFO *)dat->si; + + DWORD nItemUnderMouse = (DWORD)SendMessage(hwnd, LB_ITEMFROMPOINT, 0, lParam); + if (HIWORD(nItemUnderMouse) == 1) + nItemUnderMouse = (DWORD)(-1); + else + nItemUnderMouse &= 0xFFFF; + + if (M->GetByte("adv_TipperTooltip", 1) && ServiceExists("mToolTip/HideTip")) { + if ((int)nItemUnderMouse == currentHovered) break; + currentHovered = (int)nItemUnderMouse; + + KillTimer(hwnd, 1); + + if (isToolTip) { + CallService("mToolTip/HideTip", 0, 0); + isToolTip = FALSE; + } + + if (nItemUnderMouse != -1) + SetTimer(hwnd, 1, 450, 0); + } + else ProcessNickListHovering(hwnd, (int)nItemUnderMouse, &pt, parentdat); + } + else + { + if (M->GetByte("adv_TipperTooltip", 1) && ServiceExists("mToolTip/HideTip")) { + KillTimer(hwnd, 1); + if (isToolTip) { + CallService("mToolTip/HideTip", 0, 0); + isToolTip = FALSE; + } + } + else ProcessNickListHovering(hwnd, -1, &pt, NULL); + } + } + break; + + case WM_TIMER: + { + CLCINFOTIP ti = {0}; + USERINFO *ui1 = NULL; + TCHAR ptszBuf[1024]; + char serviceName[256]; + POINT pt; + + struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndParent, GWLP_USERDATA); + SESSION_INFO * parentdat = dat->si; + + GetCursorPos(&pt); + ScreenToClient(hwnd, &pt); + + DWORD nItemUnderMouse = (DWORD)SendMessage(GetDlgItem(dat->hwnd, IDC_LIST), LB_ITEMFROMPOINT, 0, MAKELPARAM(pt.x, pt.y)); + if (HIWORD(nItemUnderMouse) == 1) + nItemUnderMouse = (DWORD)(-1); + else + nItemUnderMouse &= 0xFFFF; + if (((int)nItemUnderMouse != currentHovered) || (nItemUnderMouse == -1)) { + KillTimer(hwnd, 1); + break; + } + + ui1 = SM_GetUserFromIndex(parentdat->ptszID, parentdat->pszModule, currentHovered); + + if (ui1) { + ti.cbSize = sizeof(ti); + mir_snprintf(serviceName, SIZEOF(serviceName), "%s"MS_GC_PROTO_GETTOOLTIPTEXT, parentdat->pszModule); + + if (ServiceExists(serviceName)) + mir_sntprintf(ptszBuf, SIZEOF(ptszBuf), _T("%s"), (TCHAR*)CallService(serviceName, (WPARAM)parentdat->ptszID, (LPARAM)ui1->pszUID)); + else + mir_sntprintf(ptszBuf, SIZEOF(ptszBuf), _T("%s:\t%s\n%s:\t%s\n%s:\t%s"), + TranslateT("Nick"), ui1->pszNick, + TranslateT("Unique id"), ui1->pszUID, + TranslateT("Status"), TM_WordToString(parentdat->pStatuses, ui1->Status)); + + if (ptszBuf != NULL) + if (CallService("mToolTip/ShowTipW", (WPARAM)mir_tstrdup(ptszBuf), (LPARAM)&ti)) + isToolTip = TRUE; + } + KillTimer(hwnd, 1); + } + break; + } + return CallWindowProc(OldNicklistProc, hwnd, msg, wParam, lParam); +} + +/* + * calculate the required rectangle for a string using the given font. This is more + * precise than using GetTextExtentPoint...() + */ + +int GetTextPixelSize(TCHAR* pszText, HFONT hFont, BOOL bWidth) +{ + HDC hdc; + HFONT hOldFont; + RECT rc = {0}; + int i; + + if (!pszText || !hFont) + return 0; + + hdc = GetDC(NULL); + hOldFont = (HFONT)SelectObject(hdc, hFont); + i = DrawText(hdc, pszText , -1, &rc, DT_CALCRECT); + SelectObject(hdc, hOldFont); + ReleaseDC(NULL, hdc); + return bWidth ? rc.right - rc.left : rc.bottom - rc.top; +} + +static void __cdecl phase2(void * lParam) +{ + SESSION_INFO* si = (SESSION_INFO*) lParam; + Sleep(30); + if (si && si->hWnd) + PostMessage(si->hWnd, GC_REDRAWLOG3, 0, 0); +} + + +/* + * the actual group chat session window procedure. Handles the entire chat session window + * which is usually a (tabbed) child of a container class window. + */ + +INT_PTR CALLBACK RoomWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + SESSION_INFO * si = NULL; + HWND hwndTab = GetParent(hwndDlg); + struct TWindowData *dat = (struct TWindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (dat) + si = (SESSION_INFO *)dat->si; + + if (dat == NULL && (uMsg == WM_ACTIVATE || uMsg == WM_SETFOCUS)) + return 0; + + switch (uMsg) { + case WM_INITDIALOG: { + int mask; + struct TNewWindowData *newData = (struct TNewWindowData *) lParam; + struct TWindowData *dat; + SESSION_INFO *psi = (SESSION_INFO*)newData->hdbEvent; + RECT rc; + + dat = (struct TWindowData *)malloc(sizeof(struct TWindowData)); + ZeroMemory(dat, sizeof(struct TWindowData)); + si = psi; + dat->si = psi; + dat->hContact = psi->hContact; + dat->szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)psi->hContact, 0); + dat->bType = SESSIONTYPE_CHAT; + dat->Panel = new CInfoPanel(dat); + + dat->cache = CContactCache::getContactCache(dat->hContact); + dat->cache->updateState(); + dat->cache->updateUIN(); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); + newData->item.lParam = (LPARAM) hwndDlg; + TabCtrl_SetItem(hwndTab, newData->iTabID, &newData->item); + dat->iTabID = newData->iTabID; + dat->pContainer = newData->pContainer; + psi->pContainer = newData->pContainer; + dat->hwnd = hwndDlg; + psi->hWnd = hwndDlg; + psi->dat = dat; + dat->fIsAutosizingInput = IsAutoSplitEnabled(dat); + dat->fLimitedUpdate = false; + dat->iInputAreaHeight = -1; + if (!dat->pContainer->settings->fPrivate) + psi->iSplitterY = g_Settings.iSplitterY; + else { + if (M->GetByte("Chat", "SyncSplitter", 0)) + psi->iSplitterY = dat->pContainer->settings->splitterPos - DPISCALEY_S(23); + else + psi->iSplitterY = g_Settings.iSplitterY; + } +#if defined(__FEAT_EXP_AUTOSPLITTER) + if (dat->fIsAutosizingInput) + psi->iSplitterY = GetDefaultMinimumInputHeight(dat); +#endif + dat->pWnd = 0; + CProxyWindow::add(dat); + + dat->fInsertMode = FALSE; + + dat->codePage = M->GetDword(dat->hContact, "ANSIcodepage", CP_ACP); + dat->Panel->getVisibility(); + dat->Panel->Configure(); + M->AddWindow(hwndDlg, dat->hContact); + BroadCastContainer(dat->pContainer, DM_REFRESHTABINDEX, 0, 0); + + SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETOLECALLBACK, 0, (LPARAM) mREOLECallback); + + BB_InitDlgButtons(dat); + DM_InitTip(dat); + + SendMessage(GetDlgItem(hwndDlg,IDC_COLOR), BUTTONSETASPUSHBTN, TRUE, 0); + + OldSplitterProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTERX), GWLP_WNDPROC, (LONG_PTR)SplitterSubclassProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTERY), GWLP_WNDPROC, (LONG_PTR)SplitterSubclassProc); + OldNicklistProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LIST), GWLP_WNDPROC, (LONG_PTR)NicklistSubclassProc); + OldLogProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHAT_LOG), GWLP_WNDPROC, (LONG_PTR)LogSubclassProc); + OldFilterButtonProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_WNDPROC, (LONG_PTR)ButtonSubclassProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_COLOR), GWLP_WNDPROC, (LONG_PTR)ButtonSubclassProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_BKGCOLOR), GWLP_WNDPROC, (LONG_PTR)ButtonSubclassProc); + OldMessageProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), GWLP_WNDPROC, (LONG_PTR)MessageSubclassProc); + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SUBCLASSED, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_AUTOURLDETECT, 1, 0); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PANELSPLITTER), GWLP_WNDPROC, (LONG_PTR) SplitterSubclassProc); + TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPENING, 0); + + mask = (int)SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_GETEVENTMASK, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETEVENTMASK, 0, mask | ENM_LINK | ENM_MOUSEEVENTS | ENM_KEYEVENTS); + +#if defined(__FEAT_EXP_AUTOSPLITTER) + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETEVENTMASK, 0, ENM_REQUESTRESIZE | ENM_MOUSEEVENTS | ENM_SCROLL | ENM_KEYEVENTS | ENM_CHANGE); +#else + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_SCROLL | ENM_KEYEVENTS | ENM_CHANGE); +#endif + + SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_LIMITTEXT, (WPARAM)0x7FFFFFFF, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3)); + SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(3, 3)); + dat->Panel->loadHeight(); + Utils::enableDlgControl(hwndDlg, IDC_SMILEYBTN, TRUE); + + if (PluginConfig.g_hMenuTrayUnread != 0 && dat->hContact != 0 && dat->szProto != NULL) + UpdateTrayMenu(0, dat->wStatus, dat->szProto, dat->szStatus, dat->hContact, FALSE); + + DM_ThemeChanged(dat); + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_HIDESELECTION, TRUE, 0); + + CreateWindowEx(0, _T("TSButtonClass"), _T(""), WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0, 0, 6, DPISCALEY_S(20), + hwndDlg, (HMENU)IDC_CHAT_TOGGLESIDEBAR, g_hInst, NULL); + + GetMYUIN(dat); + GetMyNick(dat); + SendDlgItemMessage(hwndDlg, IDC_CHAT_TOGGLESIDEBAR, BUTTONSETASTHEMEDBTN, PluginConfig.m_bIsXP, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_TOGGLESIDEBAR, BUTTONSETCONTAINER, (LPARAM)dat->pContainer, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_TOGGLESIDEBAR, BUTTONSETASFLATBTN, FALSE, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_TOGGLESIDEBAR, BUTTONSETASTOOLBARBUTTON, TRUE, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_TOGGLESIDEBAR, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Expand or collapse the side bar"), 1); + + dat->hwndIEView = dat->hwndHPP = 0; + + //Chat_SetMessageLog(dat); + + SendMessage(hwndDlg, GC_SETWNDPROPS, 0, 0); + SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0); + SendMessage(hwndDlg, GC_UPDATETITLE, 0, 1); + SendMessage(dat->pContainer->hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc); + SetWindowPos(hwndDlg, HWND_TOP, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), 0); + ShowWindow(hwndDlg, SW_SHOW); + PostMessage(hwndDlg, GC_UPDATENICKLIST, 0, 0); + dat->pContainer->hwndActive = hwndDlg; + BB_SetButtonsPos(dat); + TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPEN, 0); + } + break; + + case WM_SETFOCUS: + if (CMimAPI::m_shutDown) + break; + + Chat_UpdateWindowState(dat, WM_SETFOCUS); + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + return 1; + + case WM_TIMECHANGE: + PostMessage(hwndDlg, GC_REDRAWLOG, 0, 0); + break; + + case DM_LOADBUTTONBARICONS: { + BB_UpdateIcons(hwndDlg, dat); + return 0; + } + + case GC_SETWNDPROPS: { + //HICON hIcon; + COLORREF colour = M->GetDword(FONTMODULE, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR); + InitButtons(hwndDlg, si); + ConfigureSmileyButton(dat); + SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETBKGNDCOLOR, 0, colour); + + DM_InitRichEdit(dat); + SendDlgItemMessage(hwndDlg, IDOK, BUTTONSETASNORMAL, TRUE, 0); + { + SendMessage(GetDlgItem(hwndDlg, IDC_LIST), LB_SETITEMHEIGHT, 0, (LPARAM)g_Settings.iNickListFontHeight); + InvalidateRect(GetDlgItem(hwndDlg, IDC_LIST), NULL, TRUE); + } + SendDlgItemMessage(hwndDlg, IDC_FILTER, BUTTONSETOVERLAYICON, + (LPARAM)(si->bFilterEnabled ? PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled), 0); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + SendMessage(hwndDlg, GC_REDRAWLOG2, 0, 0); + } + break; + + case DM_UPDATETITLE: + return(SendMessage(hwndDlg, GC_UPDATETITLE, wParam, lParam)); + + case GC_UPDATETITLE: { + TCHAR szTemp [100]; + HICON hIcon; + BOOL fNoCopy = TRUE; + const TCHAR* szNick = dat->cache->getNick(); + + if (dat->bWasDeleted) + return 0; + + dat->wStatus = si->wStatus; + + if (lstrlen(szNick) > 0) { + if (M->GetByte("cuttitle", 0)) + CutContactName(szNick, dat->newtitle, safe_sizeof(dat->newtitle)); + else { + lstrcpyn(dat->newtitle, szNick, safe_sizeof(dat->newtitle)); + dat->newtitle[129] = 0; + } + } + + switch (si->iType) { + case GCW_CHATROOM: + hIcon = dat->wStatus <= ID_STATUS_OFFLINE ? LoadSkinnedProtoIcon(si->pszModule, ID_STATUS_OFFLINE) : LoadSkinnedProtoIcon(si->pszModule, dat->wStatus); + fNoCopy = FALSE; + mir_sntprintf(szTemp, SIZEOF(szTemp), + (si->nUsersInNicklist == 1) ? TranslateT("%s: Chat Room (%u user%s)") : + TranslateT("%s: Chat Room (%u users%s)"), + si->ptszName, si->nUsersInNicklist, si->bFilterEnabled ? TranslateT(", event filter active") : _T("")); + break; + case GCW_PRIVMESS: + mir_sntprintf(szTemp, SIZEOF(szTemp), + (si->nUsersInNicklist == 1) ? TranslateT("%s: Message Session") : + TranslateT("%s: Message Session (%u users)"), si->ptszName, si->nUsersInNicklist); + break; + case GCW_SERVER: + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s: Server"), si->ptszName); + hIcon = LoadIconEx(IDI_CHANMGR, "window", 16, 16); + break; + } + + if (dat->pWnd) { + dat->pWnd->updateTitle(dat->newtitle); + dat->pWnd->updateIcon(hIcon); + } + dat->hTabStatusIcon = hIcon; + + if (lParam) + dat->hTabIcon = dat->hTabStatusIcon; + + if (dat->cache->getStatus() != dat->cache->getOldStatus()) { + TCITEM item; + + ZeroMemory(&item, sizeof(item)); + item.mask = TCIF_TEXT; + + lstrcpyn(dat->szStatus, (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)dat->wStatus, GSMDF_TCHAR), 50); + dat->szStatus[49] = 0; + item.pszText = dat->newtitle; + item.cchTextMax = 120; + TabCtrl_SetItem(hwndTab, dat->iTabID, &item); + } + SetWindowText(hwndDlg, szTemp); + if (dat->pContainer->hwndActive == hwndDlg) { + SendMessage(dat->pContainer->hwnd, DM_UPDATETITLE, (WPARAM)hwndDlg, 1); + SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0); + } + } + break; + + case GC_UPDATESTATUSBAR: + if (dat->bWasDeleted) + return 0; + + if (dat->pContainer->hwndActive != hwndDlg || dat->pContainer->hwndStatus == 0 || CMimAPI::m_shutDown || dat->szStatusBar[0]) + break; + if (si->pszModule != NULL) { + TCHAR szFinalStatusBarText[512]; + MODULEINFO* mi=NULL; + int x = 12; + + //Mad: strange rare crash here... + mi = MM_FindModule(si->pszModule); + if (!mi) + break; + + if (!mi->ptszModDispName) + break; + + x += GetTextPixelSize(mi->ptszModDispName, (HFONT)SendMessage(dat->pContainer->hwndStatus, WM_GETFONT, 0, 0), TRUE); + x += GetSystemMetrics(SM_CXSMICON); + + if (dat->Panel->isActive()) { + time_t now = time(0); + DWORD diff = (now - mi->idleTimeStamp) / 60; + + if ((diff >= 1 && diff != mi->lastIdleCheck) || lParam) { + mi->lastIdleCheck = diff; + if (diff == 0) + mi->tszIdleMsg[0] = 0; + else if (diff > 59) { + DWORD hours = diff / 60; + DWORD minutes = diff % 60; + mir_sntprintf(mi->tszIdleMsg, 60, TranslateT(", %d %s, %d %s idle"), hours, hours > 1 ? + TranslateT("hours") : TranslateT("hour"), + minutes, minutes > 1 ? TranslateT("minutes") : TranslateT("minute")); + } + else + mir_sntprintf(mi->tszIdleMsg, 60, TranslateT(", %d %s idle"), + diff, diff > 1 ? TranslateT("minutes") : TranslateT("minute")); + } + mir_sntprintf(szFinalStatusBarText, SIZEOF(szFinalStatusBarText), TranslateT("%s on %s%s"), dat->szMyNickname, mi->ptszModDispName, mi->tszIdleMsg); + } else { + if (si->ptszStatusbarText) + mir_sntprintf(szFinalStatusBarText, SIZEOF(szFinalStatusBarText), _T("%s %s"), mi->ptszModDispName, si->ptszStatusbarText); + else { + lstrcpyn(szFinalStatusBarText, mi->ptszModDispName, SIZEOF(szFinalStatusBarText)); + szFinalStatusBarText[511] = 0; + } + } + SendMessage(dat->pContainer->hwndStatus, SB_SETTEXT, 0, (LPARAM)szFinalStatusBarText); + UpdateStatusBar(dat); + dat->Panel->Invalidate(); + if (dat->pWnd) + dat->pWnd->Invalidate(); + return TRUE; + } + break; + + case WM_SIZE: { + UTILRESIZEDIALOG urd; + RECT rc; + int panelHeight = dat->Panel->getHeight() + 1; + LONG cx; + + if (dat->ipFieldHeight == 0) + dat->ipFieldHeight = CInfoPanel::m_ipConfig.height1; + + if (wParam == SIZE_MAXIMIZED) + PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0); + + if (IsIconic(hwndDlg)) break; + ZeroMemory(&urd, sizeof(urd)); + urd.cbSize = sizeof(urd); + urd.hInstance = g_hInst; + urd.hwndDlg = hwndDlg; + urd.lParam = (LPARAM)si; + urd.lpTemplate = MAKEINTRESOURCEA(IDD_CHANNEL); + urd.pfnResizer = RoomWndResize; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); + //mad + BB_SetButtonsPos(dat); + + GetClientRect(hwndDlg, &rc); + cx = rc.right; + + rc.left = panelHeight <= CInfoPanel::LEFT_OFFSET_LOGO ? panelHeight : CInfoPanel::LEFT_OFFSET_LOGO; + rc.right = cx; + rc.top = 1; + rc.bottom = (panelHeight > CInfoPanel::DEGRADE_THRESHOLD ? rc.top + dat->ipFieldHeight - 2 : panelHeight - 1); + dat->rcNick = rc; + + rc.left = panelHeight <= CInfoPanel::LEFT_OFFSET_LOGO ? panelHeight : CInfoPanel::LEFT_OFFSET_LOGO; + rc.right = cx; + rc.bottom = panelHeight - 2; + rc.top = dat->rcNick.bottom + 1; + dat->rcUIN = rc; + + if (dat->hwndIEView || dat->hwndHPP) + Chat_ResizeIeView(dat); + DetermineMinHeight(dat); + } + break; + + case GC_REDRAWWINDOW: + InvalidateRect(hwndDlg, NULL, TRUE); + break; + + case GC_REDRAWLOG: + si->LastTime = 0; + if (si->pLog) { + LOGINFO * pLog = si->pLog; + if (si->iEventCount > 60) { + int index = 0; + while (index < 59) { + if (pLog->next == NULL) + break; + pLog = pLog->next; + if (si->iType != GCW_CHATROOM || !si->bFilterEnabled || (si->iLogFilterFlags&pLog->iType) != 0) + index++; + } + Log_StreamInEvent(hwndDlg, pLog, si, TRUE, FALSE); + mir_forkthread(phase2, si); + } else Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE, FALSE); + } else SendMessage(hwndDlg, GC_EVENT_CONTROL + WM_USER + 500, WINDOW_CLEARLOG, 0); + break; + + case GC_REDRAWLOG2: + si->LastTime = 0; + if (si->pLog) + Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE, FALSE); + break; + + case GC_REDRAWLOG3: + si->LastTime = 0; + if (si->pLog) + Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE, TRUE); + break; + + case GC_ADDLOG: { + BOOL fInactive = (GetForegroundWindow() != dat->pContainer->hwnd || GetActiveWindow() != dat->pContainer->hwnd); + + if (g_Settings.UseDividers && g_Settings.DividersUsePopupConfig) { + if (!MessageWindowOpened(0, (LPARAM)hwndDlg)) + SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); + } else if (g_Settings.UseDividers) { + if (fInactive) + SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); + else { + if (dat->pContainer->hwndActive != hwndDlg) + SendMessage(hwndDlg, DM_ADDDIVIDER, 0, 0); + } + } + + if (si->pLogEnd) + Log_StreamInEvent(hwndDlg, si->pLog, si, FALSE, FALSE); + else + SendMessage(hwndDlg, GC_EVENT_CONTROL + WM_USER + 500, WINDOW_CLEARLOG, 0); + break; + } + + case GC_ACKMESSAGE: + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETREADONLY, FALSE, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, WM_SETTEXT, 0, (LPARAM)_T("")); + return TRUE; + + case WM_CTLCOLORLISTBOX: + SetBkColor((HDC) wParam, g_Settings.crUserListBGColor); + return (INT_PTR) hListBkgBrush; + + case WM_MEASUREITEM: { + MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *) lParam; + + if (mis->CtlType == ODT_MENU) { + if (dat->Panel->isHovered()) { + mis->itemHeight = 0; + mis->itemWidth = 6; + return(TRUE); + } + return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam); + } + else + mis->itemHeight = g_Settings.iNickListFontHeight; + return TRUE; + } + + case WM_DRAWITEM: { + DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *) lParam; + + if (dis->CtlType == ODT_MENU) { + if (dat->Panel->isHovered()) { + DrawMenuItem(dis, (HICON)dis->itemData, 0); + return(TRUE); + } + return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam); + } + else { + if (dis->CtlID == IDC_LIST) { + HFONT hFont, hOldFont; + HICON hIcon; + int offset, x_offset = 0; + int height; + int index = dis->itemID; + USERINFO * ui = UM_FindUserFromIndex(si->pUsers, index); + char szIndicator = 0; + + if (ui) { + height = dis->rcItem.bottom - dis->rcItem.top; + + if (height&1) + height++; + if (height == 10) + offset = 0; + else + offset = height / 2; + hIcon = SM_GetStatusIcon(si, ui, &szIndicator); + hFont = (ui->iStatusEx == 0) ? g_Settings.UserListFont : g_Settings.UserListHeadingsFont; + hOldFont = (HFONT) SelectObject(dis->hDC, hFont); + SetBkMode(dis->hDC, TRANSPARENT); + + if (dis->itemState & ODS_SELECTED) { + FillRect(dis->hDC, &dis->rcItem, g_Settings.SelectionBGBrush); + SetTextColor(dis->hDC, g_Settings.nickColors[6]); + } else { + FillRect(dis->hDC, &dis->rcItem, hListBkgBrush); + if (g_Settings.ColorizeNicks && szIndicator != 0) { + COLORREF clr; + + switch (szIndicator) { + case '@': + clr = g_Settings.nickColors[0]; + break; + case '%': + clr = g_Settings.nickColors[1]; + break; + case '+': + clr = g_Settings.nickColors[2]; + break; + case '!': + clr = g_Settings.nickColors[3]; + break; + case '*': + clr = g_Settings.nickColors[4]; + break; + } + SetTextColor(dis->hDC, clr); + } else SetTextColor(dis->hDC, ui->iStatusEx == 0 ? g_Settings.crUserListColor : g_Settings.crUserListHeadingsColor); + } + x_offset = 2; + + if (g_Settings.ShowContactStatus && g_Settings.ContactStatusFirst && ui->ContactStatus) { + HICON hIcon = LoadSkinnedProtoIcon(si->pszModule, ui->ContactStatus); + DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 8, hIcon, 16, 16, 0, NULL, DI_NORMAL); + CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); + x_offset += 18; + } + + if (g_Settings.ClassicIndicators) { + char szTemp[3]; + SIZE szUmode; + + szTemp[1] = 0; + szTemp[0] = szIndicator; + if (szTemp[0]) { + GetTextExtentPoint32A(dis->hDC, szTemp, 1, &szUmode); + TextOutA(dis->hDC, x_offset, dis->rcItem.top, szTemp, 1); + x_offset += szUmode.cx + 2; + } else x_offset += 8; + } else { + DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 5, hIcon, 10, 10, 0, NULL, DI_NORMAL); + x_offset += 12; + } + + if (g_Settings.ShowContactStatus && !g_Settings.ContactStatusFirst && ui->ContactStatus) { + HICON hIcon = LoadSkinnedProtoIcon(si->pszModule, ui->ContactStatus); + DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 8, hIcon, 16, 16, 0, NULL, DI_NORMAL); + CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); + x_offset += 18; + } + + { + SIZE sz; + + if (si->iSearchItem != -1 && si->iSearchItem == index && si->szSearch[0]) { + COLORREF clr_orig = GetTextColor(dis->hDC); + GetTextExtentPoint32(dis->hDC, ui->pszNick, lstrlen(si->szSearch), &sz); + SetTextColor(dis->hDC, RGB(250, 250, 0)); + TextOut(dis->hDC, x_offset, (dis->rcItem.top + dis->rcItem.bottom - sz.cy) / 2, ui->pszNick, lstrlen(si->szSearch)); + SetTextColor(dis->hDC, clr_orig); + x_offset += sz.cx; + TextOut(dis->hDC, x_offset, (dis->rcItem.top + dis->rcItem.bottom - sz.cy) / 2, ui->pszNick + lstrlen(si->szSearch), lstrlen(ui->pszNick) - lstrlen(si->szSearch)); + } else { + GetTextExtentPoint32(dis->hDC, ui->pszNick, lstrlen(ui->pszNick), &sz); + TextOut(dis->hDC, x_offset, (dis->rcItem.top + dis->rcItem.bottom - sz.cy) / 2, ui->pszNick, lstrlen(ui->pszNick)); + SelectObject(dis->hDC, hOldFont); + } + } + } + return TRUE; + } + } + } + break; + case WM_CONTEXTMENU:{ + //mad + DWORD idFrom=GetDlgCtrlID((HWND)wParam); + if (idFrom>=MIN_CBUTTONID&&idFrom<=MAX_CBUTTONID) + BB_CustomButtonClick(dat,idFrom,(HWND) wParam,1); + }break; + // + case GC_UPDATENICKLIST: { + int i = SendMessage(GetDlgItem(hwndDlg, IDC_LIST), LB_GETTOPINDEX, 0, 0); + SendMessage(GetDlgItem(hwndDlg, IDC_LIST), LB_SETCOUNT, si->nUsersInNicklist, 0); + SendMessage(GetDlgItem(hwndDlg, IDC_LIST), LB_SETTOPINDEX, i, 0); + SendMessage(hwndDlg, GC_UPDATETITLE, 0, 0); + } + break; + + case GC_EVENT_CONTROL + WM_USER + 500: { + switch (wParam) { + case SESSION_OFFLINE: + SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0); + SendMessage(si->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0); + return TRUE; + + case SESSION_ONLINE: + SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0); + return TRUE; + + case WINDOW_HIDDEN: + SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 1); + return TRUE; + + case WINDOW_CLEARLOG: + SetDlgItemText(hwndDlg, IDC_CHAT_LOG, _T("")); + return TRUE; + + case SESSION_TERMINATE: + if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->hContact, (LPARAM)0)) + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->hContact, (LPARAM)szChatIconString); + + si->wState &= ~STATE_TALK; + dat->bWasDeleted = 1; + DBWriteContactSettingWord(si->hContact, si->pszModule , "ApparentMode", (LPARAM) 0); + SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, lParam == 2 ? lParam : 1); + return TRUE; + + case WINDOW_MINIMIZE: + ShowWindow(hwndDlg, SW_MINIMIZE); + goto LABEL_SHOWWINDOW; + + case WINDOW_MAXIMIZE: + ShowWindow(hwndDlg, SW_MAXIMIZE); + goto LABEL_SHOWWINDOW; + + case SESSION_INITDONE: + if (M->GetByte("Chat", "PopupOnJoin", 0) != 0) + return TRUE; + // fall through + case WINDOW_VISIBLE: + if (IsIconic(hwndDlg)) + ShowWindow(hwndDlg, SW_NORMAL); +LABEL_SHOWWINDOW: + SendMessage(hwndDlg, WM_SIZE, 0, 0); + SendMessage(hwndDlg, GC_REDRAWLOG, 0, 0); + SendMessage(hwndDlg, GC_UPDATENICKLIST, 0, 0); + SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0); + ShowWindow(hwndDlg, SW_SHOW); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + SetForegroundWindow(hwndDlg); + return TRUE; + } + } + break; + + case DM_SPLITTERMOVED: { + POINT pt; + RECT rc; + RECT rcLog; + BOOL bFormat = TRUE; //IsWindowVisible(GetDlgItem(hwndDlg,IDC_SMILEY)); + + static int x = 0; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_LOG), &rcLog); + if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SPLITTERX)) { + int oldSplitterX; + GetClientRect(hwndDlg, &rc); + pt.x = wParam; + pt.y = 0; + ScreenToClient(hwndDlg, &pt); + + oldSplitterX = si->iSplitterX; + si->iSplitterX = rc.right - pt.x + 1; + if (si->iSplitterX < 35) + si->iSplitterX = 35; + if (si->iSplitterX > rc.right - rc.left - 35) + si->iSplitterX = rc.right - rc.left - 35; + g_Settings.iSplitterX = si->iSplitterX; + SendMessage(dat->hwnd, WM_SIZE, 0, 0); + } else if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SPLITTERY) || lParam == -1) { + int oldSplitterY; + GetClientRect(hwndDlg, &rc); + rc.top += (dat->Panel->isActive() ? dat->Panel->getHeight() + 40 : 30); + pt.x = 0; + pt.y = wParam; + ScreenToClient(hwndDlg, &pt); + + oldSplitterY = si->iSplitterY; + si->iSplitterY = bFormat ? rc.bottom - pt.y + DPISCALEY_S(1) : rc.bottom - pt.y + DPISCALEY_S(20); + if (si->iSplitterY < DPISCALEY_S(23)) + si->iSplitterY = DPISCALEY_S(23); + if (si->iSplitterY > rc.bottom - rc.top - DPISCALEY_S(40)) + si->iSplitterY = rc.bottom - rc.top - DPISCALEY_S(40); + g_Settings.iSplitterY = si->iSplitterY; + CSkin::UpdateToolbarBG(dat, RDW_ALLCHILDREN); + SendMessage(dat->hwnd, WM_SIZE, 0, 0); + } else if ((HWND) lParam == GetDlgItem(hwndDlg, IDC_PANELSPLITTER)) { + RECT rc; + POINT pt; + pt.x = 0; + pt.y = wParam; + ScreenToClient(hwndDlg, &pt); + GetClientRect(GetDlgItem(hwndDlg, IDC_CHAT_LOG), &rc); + if ((pt.y + 2 >= MIN_PANELHEIGHT + 2) && (pt.y + 2 < 100) && (pt.y + 2 < rc.bottom - 30)) + dat->Panel->setHeight(pt.y + 2); + dat->panelWidth = -1; + RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE); + if (M->isAero()) + InvalidateRect(GetParent(hwndDlg), NULL, FALSE); + SendMessage(hwndDlg, WM_SIZE, DM_SPLITTERMOVED, 0); + break; + } + } + break; + + case GC_FIREHOOK: + if (lParam) { + GCHOOK* gch = (GCHOOK *) lParam; + NotifyEventHooks(hSendEvent, 0, (WPARAM)gch); + if (gch->pDest) { + mir_free(gch->pDest->pszID); + mir_free(gch->pDest->pszModule); + mir_free(gch->pDest); + } + mir_free(gch->ptszText); + mir_free(gch->ptszUID); + mir_free(gch); + } + break; + + case GC_CHANGEFILTERFLAG: + if (si->iLogFilterFlags == 0 && si->bFilterEnabled) + SendMessage(hwndDlg, WM_COMMAND, IDC_FILTER, 0); + break; + + case GC_SHOWFILTERMENU: { + RECT rcFilter, rcLog; + POINT pt; + + si->hwndFilter = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER), dat->pContainer->hwnd, FilterWndProc, (LPARAM)si); + TranslateDialogDefault(si->hwndFilter); + + GetClientRect(si->hwndFilter, &rcFilter); + GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_LOG), &rcLog); + pt.x = rcLog.right; + pt.y = rcLog.bottom; + ScreenToClient(dat->pContainer->hwnd, &pt); + + SetWindowPos(si->hwndFilter, HWND_TOP, pt.x - rcFilter.right, pt.y - rcFilter.bottom, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); + } + break; + + case DM_SPLITTERGLOBALEVENT: { + DM_SplitterGlobalEvent(dat, wParam, lParam); + return 0; + } + + case GC_SHOWCOLORCHOOSER: { + HWND ColorWindow; + RECT rc; + BOOL bFG = lParam == IDC_COLOR ? TRUE : FALSE; + COLORCHOOSER *pCC = (COLORCHOOSER *)mir_alloc(sizeof(COLORCHOOSER)); + + GetWindowRect(GetDlgItem(hwndDlg, bFG ? IDC_COLOR : IDC_BKGCOLOR), &rc); + pCC->hWndTarget = GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE); + pCC->pModule = MM_FindModule(si->pszModule); + pCC->xPosition = rc.left + 3; + pCC->yPosition = IsWindowVisible(GetDlgItem(hwndDlg, IDC_COLOR)) ? rc.top - 1 : rc.top + 20; + pCC->bForeground = bFG; + pCC->si = si; + + ColorWindow = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_COLORCHOOSER), hwndDlg, DlgProcColorToolWindow, (LPARAM) pCC); + } + break; + + case GC_SCROLLTOBOTTOM: { + return(DM_ScrollToBottom(dat, wParam, lParam)); + } + + case WM_TIMER: + if (wParam == TIMERID_FLASHWND) + if (dat->mayFlashTab) + FlashTab(dat, hwndTab, dat->iTabID, &dat->bTabFlash, TRUE, dat->hTabIcon); + break; + + case WM_ACTIVATE: + if (LOWORD(wParam) != WA_ACTIVE) { + dat->pContainer->hwndSaved = 0; + break; + } + + //fall through + case WM_MOUSEACTIVATE: + Chat_UpdateWindowState(dat, WM_ACTIVATE); + return 1; + + case WM_NOTIFY: { + LPNMHDR pNmhdr = (LPNMHDR)lParam; + switch (pNmhdr->code) { + case EN_MSGFILTER: { + UINT msg = ((MSGFILTER *) lParam)->msg; + WPARAM wp = ((MSGFILTER *) lParam)->wParam; + LPARAM lp = ((MSGFILTER *) lParam)->lParam; + + BOOL isShift, isCtrl, isMenu; + KbdState(dat, isShift, isCtrl, isMenu); + + MSG message; + message.hwnd = hwndDlg; + message.message = msg; + message.lParam = lp; + message.wParam = wp; + + if (msg == WM_SYSKEYUP) { + if (wp == VK_MENU) { + if (!dat->fkeyProcessed && !(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000) && !(lp & (1 << 24))) + dat->pContainer->MenuBar->autoShow(); + } + return(_dlgReturn(hwndDlg, 0)); + } + + if (msg == WM_MOUSEMOVE) { + POINT pt; + GetCursorPos(&pt); + DM_DismissTip(dat, pt); + dat->Panel->trackMouse(pt); + break; + } + if (msg == WM_KEYDOWN) { + if ((wp == VK_INSERT && isShift && !isCtrl && !isMenu) || (wp == 'V' && !isShift && !isMenu && isCtrl)) { + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), EM_PASTESPECIAL, CF_TEXTT, 0); + ((MSGFILTER *) lParam)->msg = WM_NULL; + ((MSGFILTER *) lParam)->wParam = 0; + ((MSGFILTER *) lParam)->lParam = 0; + return(_dlgReturn(hwndDlg, 1)); + } + } + + if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN) + dat->pContainer->MenuBar->Cancel(); + + if ((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) && !(GetKeyState(VK_RMENU) & 0x8000)) { + + if (DM_GenericHotkeysCheck(&message, dat)) { + dat->fkeyProcessed = true; + return(_dlgReturn(hwndDlg, 1)); + } + + LRESULT mim_hotkey_check = CallService(MS_HOTKEY_CHECK, (WPARAM)&message, (LPARAM)(TABSRMM_HK_SECTION_GC)); + if (mim_hotkey_check) + dat->fkeyProcessed = true; + switch(mim_hotkey_check) { // nothing (yet) FIXME + case TABSRMM_HK_CHANNELMGR: + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_CHANMGR, BN_CLICKED), 0); + return(_dlgReturn(hwndDlg, 1)); + case TABSRMM_HK_FILTERTOGGLE: + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_FILTER, BN_CLICKED), 0); + InvalidateRect(GetDlgItem(hwndDlg, IDC_FILTER), NULL, TRUE); + return(_dlgReturn(hwndDlg, 1)); + case TABSRMM_HK_LISTTOGGLE: + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_SHOWNICKLIST, BN_CLICKED), 0); + return(_dlgReturn(hwndDlg, 1)); + case TABSRMM_HK_MUC_SHOWSERVER: + if (si->iType != GCW_SERVER) + DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, L"/servershow", (LPARAM)NULL); + return(_dlgReturn(hwndDlg, 1)); + default: + break; + } + } + + if (msg == WM_KEYDOWN && wp == VK_TAB) { + if (((NMHDR *)lParam)->idFrom == IDC_CHAT_LOG) { + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + return(_dlgReturn(hwndDlg, 1)); + } + } + + if (pNmhdr->idFrom == IDC_CHAT_LOG && ((MSGFILTER *) lParam)->msg == WM_RBUTTONUP) { + CHARRANGE sel, all = { 0, -1 }; + POINT pt; + UINT uID = 0; + HMENU hMenu = 0; + TCHAR pszWord[4096]; + int pos; + + pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam); + pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam); + ClientToScreen(pNmhdr->hwndFrom, &pt); + + { // fixing stuff for searches + long iCharIndex, iLineIndex, iChars, start, end, iRes; + POINTL ptl; + + pszWord[0] = '\0'; + ptl.x = (LONG)pt.x; + ptl.y = (LONG)pt.y; + ScreenToClient(GetDlgItem(hwndDlg, IDC_CHAT_LOG), (LPPOINT)&ptl); + iCharIndex = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_CHARFROMPOS, 0, (LPARAM) & ptl); + if (iCharIndex < 0) + break; + iLineIndex = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_EXLINEFROMCHAR, 0, (LPARAM)iCharIndex); + iChars = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_LINEINDEX, (WPARAM)iLineIndex, 0); + start = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_FINDWORDBREAK, WB_LEFT, iCharIndex);//-iChars; + end = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_FINDWORDBREAK, WB_RIGHT, iCharIndex);//-iChars; + + if (end - start > 0) { + TEXTRANGE tr; + CHARRANGE cr; + static char szTrimString[] = ":;,.!?\'\"><()[]- \r\n"; + ZeroMemory(&tr, sizeof(TEXTRANGE)); + + cr.cpMin = start; + cr.cpMax = end; + tr.chrg = cr; + tr.lpstrText = (TCHAR *)pszWord; + iRes = SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_GETTEXTRANGE, 0, (LPARAM) & tr); + + if (iRes > 0) { + int iLen = lstrlen(pszWord) - 1; + while (iLen >= 0 && strchr(szTrimString, pszWord[iLen])) { + pszWord[iLen] = '\0'; + iLen--; + } + } + } + } + + uID = CreateGCMenu(hwndDlg, &hMenu, 1, pt, si, NULL, pszWord); + + if ((uID > 800 && uID < 1400) || uID == CP_UTF8 || uID == 20866) { + dat->codePage = uID; + M->WriteDword(dat->hContact, SRMSGMOD_T, "ANSIcodepage", dat->codePage); + } else if (uID == 500) { + dat->codePage = CP_ACP; + DBDeleteContactSetting(dat->hContact, SRMSGMOD_T, "ANSIcodepage"); + } else { + switch (uID) { + case 0: + PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0); + break; + + case ID_COPYALL: + SendMessage(pNmhdr->hwndFrom, EM_EXGETSEL, 0, (LPARAM) & sel); + SendMessage(pNmhdr->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & all); + SendMessage(pNmhdr->hwndFrom, WM_COPY, 0, 0); + SendMessage(pNmhdr->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & sel); + PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0); + break; + + case ID_CLEARLOG: + ClearLog(dat); + break; + + case ID_SEARCH_GOOGLE: { + TCHAR szURL[4096]; + if (pszWord[0]) { + mir_sntprintf(szURL, SIZEOF(szURL), _T("http://www.google.com/search?q=%s"), pszWord); + CallService(MS_UTILS_OPENURL, OUF_NEWWINDOW|OUF_TCHAR, (LPARAM) szURL); + } + PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0); + } + break; + + case ID_SEARCH_WIKIPEDIA: { + TCHAR szURL[4096]; + if (pszWord[0]) { + mir_sntprintf(szURL, SIZEOF(szURL), _T("http://en.wikipedia.org/wiki/%s"), pszWord); + CallService(MS_UTILS_OPENURL, OUF_NEWWINDOW|OUF_TCHAR, (LPARAM) szURL); + } + PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0); + } + break; + + default: + PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0); + DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_LOGMENU, NULL, NULL, (LPARAM)uID); + break; + } + } + if (si->iType != GCW_SERVER && !(si->dwFlags & GC_UNICODE)) { + pos = GetMenuItemCount(hMenu); + RemoveMenu(hMenu, pos - 1, MF_BYPOSITION); + RemoveMenu(PluginConfig.g_hMenuEncoding, 1, MF_BYPOSITION); + } + DestroyGCMenu(&hMenu, 5); + } + break; + } + + case EN_REQUESTRESIZE: { + if (pNmhdr->idFrom == IDC_CHAT_MESSAGE) { + REQRESIZE *rr = (REQRESIZE *)lParam; + DM_HandleAutoSizeRequest(dat, rr); + } + break; + } + + case EN_LINK: + if (pNmhdr->idFrom == IDC_CHAT_LOG) { + switch (((ENLINK *) lParam)->msg) { + case WM_SETCURSOR: + + if (g_Settings.ClickableNicks) { + if (!hCurHyperlinkHand) + hCurHyperlinkHand = LoadCursor(NULL, IDC_HAND); + if (hCurHyperlinkHand != GetCursor()) + SetCursor(hCurHyperlinkHand); + return TRUE; + } + break; + + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: { + TEXTRANGE tr; + CHARRANGE sel; + BOOL isLink = FALSE; + UINT msg = ((ENLINK *) lParam)->msg; + + dat->pContainer->MenuBar->Cancel(); + + tr.lpstrText = NULL; + SendMessage(pNmhdr->hwndFrom, EM_EXGETSEL, 0, (LPARAM) & sel); + if (sel.cpMin != sel.cpMax) + break; + tr.chrg = ((ENLINK *) lParam)->chrg; + tr.lpstrText = (TCHAR *)mir_alloc(sizeof(TCHAR) * (tr.chrg.cpMax - tr.chrg.cpMin + 2)); + SendMessage(pNmhdr->hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM) & tr); + + isLink = IsStringValidLink(tr.lpstrText); + + if (isLink) { + if (((ENLINK *) lParam)->msg == WM_RBUTTONDOWN) { + HMENU hSubMenu; + POINT pt; + + hSubMenu = GetSubMenu(g_hMenu, 2); + TranslateMenu(hSubMenu); + pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam); + pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam); + ClientToScreen(((NMHDR *) lParam)->hwndFrom, &pt); + switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL)) { + case ID_NEW: + CallService(MS_UTILS_OPENURL, OUF_NEWWINDOW|OUF_TCHAR, (LPARAM) tr.lpstrText); + break; + case ID_CURR: + CallService(MS_UTILS_OPENURL, OUF_TCHAR, (LPARAM) tr.lpstrText); + break; + case ID_COPY: { + if (!OpenClipboard(hwndDlg)) + break; + EmptyClipboard(); + HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(TCHAR) * (lstrlen(tr.lpstrText) + 1)); + lstrcpy((TCHAR*)GlobalLock(hData), tr.lpstrText); + GlobalUnlock(hData); + SetClipboardData(CF_UNICODETEXT, hData); + } + CloseClipboard(); + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + break; + } + mir_free(tr.lpstrText); + return TRUE; + } else if (((ENLINK *) lParam)->msg == WM_LBUTTONUP) { + CallService(MS_UTILS_OPENURL, OUF_NEWWINDOW|OUF_TCHAR, (LPARAM) tr.lpstrText); + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + mir_free(tr.lpstrText); + return TRUE; + } + } else if (g_Settings.ClickableNicks) { // clicked a nick name + CHARRANGE chr; + TEXTRANGE tr2; + TCHAR tszAplTmpl[] = _T("%s:"), + *tszAppeal, *tszTmp; + size_t st; + + if (msg == WM_RBUTTONDOWN) { + USERINFO *ui = si->pUsers; + HMENU hMenu = 0; + USERINFO uiNew; + while (ui) { + if (!lstrcmp(ui->pszNick, tr.lpstrText)) { + POINT pt; + UINT uID; + + pt.x = (short) LOWORD(((ENLINK *) lParam)->lParam); + pt.y = (short) HIWORD(((ENLINK *) lParam)->lParam); + ClientToScreen(((NMHDR *) lParam)->hwndFrom, &pt); + CopyMemory(&uiNew, ui, sizeof(USERINFO)); + uID = CreateGCMenu(hwndDlg, &hMenu, 0, pt, si, uiNew.pszUID, NULL); + switch (uID) { + case 0: + break; + + case ID_MESS: + DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, (LPARAM)NULL); + break; + + default: + DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_NICKLISTMENU, ui->pszUID, NULL, (LPARAM)uID); + break; + } + DestroyGCMenu(&hMenu, 1); + return TRUE; + } + ui = ui->next; + } + return TRUE; + } + else if (msg == WM_LBUTTONUP) { + USERINFO *ui = si->pUsers; + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_EXGETSEL, 0, (LPARAM) &chr); + tszTmp = tszAppeal = (TCHAR *) malloc((lstrlen(tr.lpstrText) + lstrlen(tszAplTmpl) + 3) * sizeof(TCHAR)); + tr2.lpstrText = (LPTSTR) malloc(sizeof(TCHAR) * 2); + if (chr.cpMin) { + /* prepend nick with space if needed */ + tr2.chrg.cpMin = chr.cpMin - 1; + tr2.chrg.cpMax = chr.cpMin; + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_GETTEXTRANGE, 0, (LPARAM) &tr2); + if (! _istspace(*tr2.lpstrText)) + *tszTmp++ = _T(' '); + _tcscpy(tszTmp, tr.lpstrText); + } + else + /* in the beginning of the message window */ + _stprintf(tszAppeal, tszAplTmpl, tr.lpstrText); + st = lstrlen(tszAppeal); + if (chr.cpMax != -1) { + tr2.chrg.cpMin = chr.cpMax; + tr2.chrg.cpMax = chr.cpMax + 1; + /* if there is no space after selection, + or there is nothing after selection at all... */ + if (! SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_GETTEXTRANGE, 0, (LPARAM) &tr2) || ! _istspace(*tr2.lpstrText)) { + tszAppeal[st++] = _T(' '); + tszAppeal[st++] = _T('\0'); + } + } + else { + tszAppeal[st++] = _T(' '); + tszAppeal[st++] = _T('\0'); + } + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_REPLACESEL, FALSE, (LPARAM)tszAppeal); + free((void *) tr2.lpstrText); + free((void *) tszAppeal); + } + } + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + mir_free(tr.lpstrText); + return TRUE; + } + } + return TRUE; + } + return TRUE; + } + } + break; + + case WM_LBUTTONDOWN: { + POINT tmp; //+ Protogenes + POINTS cur; //+ Protogenes + GetCursorPos(&tmp); //+ Protogenes + if (!dat->Panel->isHovered()) { + cur.x = (SHORT)tmp.x; //+ Protogenes + cur.y = (SHORT)tmp.y; //+ Protogenes + SendMessage(dat->pContainer->hwnd, WM_NCLBUTTONDOWN, HTCAPTION, *((LPARAM*)(&cur))); //+ Protogenes + } + break; + } + + case WM_LBUTTONUP: { + POINT tmp; //+ Protogenes + POINTS cur; //+ Protogenes + GetCursorPos(&tmp); //+ Protogenes + if (dat->Panel->isHovered()) + dat->Panel->handleClick(tmp); + else { + cur.x = (SHORT)tmp.x; //+ Protogenes + cur.y = (SHORT)tmp.y; //+ Protogenes + SendMessage(dat->pContainer->hwnd, WM_NCLBUTTONUP, HTCAPTION, *((LPARAM*)(&cur))); //+ Protogenes + } + break; + } + + case WM_MOUSEMOVE: { + POINT pt; + GetCursorPos(&pt); + DM_DismissTip(dat, pt); + dat->Panel->trackMouse(pt); + break; + } + case WM_APPCOMMAND: { + DWORD cmd = GET_APPCOMMAND_LPARAM(lParam); + if (cmd == APPCOMMAND_BROWSER_BACKWARD || cmd == APPCOMMAND_BROWSER_FORWARD) { + SendMessage(dat->pContainer->hwnd, DM_SELECTTAB, cmd == APPCOMMAND_BROWSER_BACKWARD ? DM_SELECT_PREV : DM_SELECT_NEXT, 0); + return 1; + } + } + break; + + case WM_COMMAND: + //mad + if (LOWORD(wParam)>=MIN_CBUTTONID&&LOWORD(wParam)<=MAX_CBUTTONID){ + BB_CustomButtonClick(dat,LOWORD(wParam) ,GetDlgItem(hwndDlg,LOWORD(wParam)),0); + break; + } + // + switch (LOWORD(wParam)) { + case IDC_LIST: + if (HIWORD(wParam) == LBN_DBLCLK) { + TVHITTESTINFO hti; + int item; + USERINFO * ui; + + hti.pt.x = (short)LOWORD(GetMessagePos()); + hti.pt.y = (short)HIWORD(GetMessagePos()); + ScreenToClient(GetDlgItem(hwndDlg, IDC_LIST), &hti.pt); + + item = LOWORD(SendMessage(GetDlgItem(hwndDlg, IDC_LIST), LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y))); + ui = UM_FindUserFromIndex(si->pUsers, item); + //ui = SM_GetUserFromIndex(si->pszID, si->pszModule, item); + if (ui) { + if (g_Settings.DoubleClick4Privat ? GetKeyState(VK_SHIFT) & 0x8000 : !(GetKeyState(VK_SHIFT) & 0x8000)) { + LRESULT lResult = (LRESULT)SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), EM_GETSEL, (WPARAM)NULL, (LPARAM)NULL); + int start = LOWORD(lResult); + TCHAR* pszName = (TCHAR*)alloca(sizeof(TCHAR) * (lstrlen(ui->pszUID) + 3)); + if (start == 0) + mir_sntprintf(pszName, lstrlen(ui->pszUID) + 3, _T("%s: "), ui->pszUID); + else + mir_sntprintf(pszName, lstrlen(ui->pszUID) + 2, _T("%s "), ui->pszUID); + + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), EM_REPLACESEL, FALSE, (LPARAM) pszName); + PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0); + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + } else DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, (LPARAM)NULL); + } + + return TRUE; + } else if (HIWORD(wParam) == LBN_KILLFOCUS) + RedrawWindow(GetDlgItem(hwndDlg, IDC_LIST), NULL, NULL, RDW_INVALIDATE); + break; + + case IDC_CHAT_TOGGLESIDEBAR: + SendMessage(dat->pContainer->hwnd, WM_COMMAND, IDC_TOGGLESIDEBAR, 0); + break; + + case IDCANCEL: + ShowWindow(dat->pContainer->hwnd, SW_MINIMIZE); + return FALSE; + + case IDOK: { + char* pszRtf; + TCHAR* ptszText/*, *p1*/; + MODULEINFO* mi; + bool fSound = true; + + if (GetSendButtonState(hwndDlg) == PBS_DISABLED) + break; + + mi = MM_FindModule(si->pszModule); + + pszRtf = Chat_Message_GetFromStream(hwndDlg, si); + SM_AddCommand(si->ptszID, si->pszModule, pszRtf); + ptszText = Chat_DoRtfToTags(pszRtf, si); + DoTrimMessage(ptszText); + + if (mi && mi->bAckMsg) { + Utils::enableDlgControl(hwndDlg, IDC_CHAT_MESSAGE, FALSE); + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETREADONLY, TRUE, 0); + } else SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, WM_SETTEXT, 0, (LPARAM)_T("")); + + Utils::enableDlgControl(hwndDlg, IDOK, FALSE); + + if (ptszText[0] == '/' || si->iType == GCW_SERVER) + fSound = false; + DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, ptszText, (LPARAM)NULL); + mi->idleTimeStamp = time(0); + mi->lastIdleCheck = 0; + SM_BroadcastMessage(si->pszModule, GC_UPDATESTATUSBAR, 0, 1, TRUE); + if (dat && dat->pContainer) { + if (fSound && !nen_options.iNoSounds && !(dat->pContainer->dwFlags & CNT_NOSOUND)) + SkinPlaySound("ChatSent"); + } + mir_free(pszRtf); + mir_free(ptszText); + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + } + break; + + case IDC_SHOWNICKLIST: + if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_SHOWNICKLIST))) + break; + if (si->iType == GCW_SERVER) + break; + + si->bNicklistEnabled = !si->bNicklistEnabled; + + SendMessage(hwndDlg, WM_SIZE, 0, 0); + if (CSkin::m_skinEnabled) + InvalidateRect(hwndDlg, NULL, TRUE); + PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0); + break; + + case IDC_CHAT_MESSAGE: + if (g_Settings.MathMod) + MTH_updateMathWindow(dat); + + if (HIWORD(wParam) == EN_CHANGE) { + if (dat->pContainer->hwndActive == hwndDlg) + UpdateReadChars(dat); + dat->dwLastActivity = GetTickCount(); + dat->pContainer->dwLastActivity = dat->dwLastActivity; + SendDlgItemMessage(hwndDlg, IDOK, BUTTONSETASNORMAL, GetRichTextLength(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)) != 0, 0); + Utils::enableDlgControl(hwndDlg, IDOK, GetRichTextLength(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)) != 0); + } + break; + + case IDC_SMILEY: + case IDC_SMILEYBTN: { + SMADD_SHOWSEL3 smaddInfo = {0}; + RECT rc; + + if (lParam == 0) + GetWindowRect(GetDlgItem(hwndDlg, IDC_SMILEYBTN), &rc); + else + GetWindowRect((HWND)lParam, &rc); + smaddInfo.cbSize = sizeof(SMADD_SHOWSEL3); + smaddInfo.hwndTarget = GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE); + smaddInfo.targetMessage = EM_REPLACESEL; + smaddInfo.targetWParam = TRUE; + smaddInfo.Protocolname = si->pszModule; + smaddInfo.Direction = 0; + smaddInfo.xPosition = rc.left; + smaddInfo.yPosition = rc.top + 24; + smaddInfo.hContact = si->hContact; + smaddInfo.hwndParent = dat->pContainer->hwnd; + if (PluginConfig.g_SmileyAddAvail) + CallService(MS_SMILEYADD_SHOWSELECTION, 0, (LPARAM) &smaddInfo); + } + break; + + case IDC_CHAT_HISTORY: { + MODULEINFO * pInfo = MM_FindModule(si->pszModule); + + if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_HISTORY))) + break; + + if (ServiceExists("MSP/HTMLlog/ViewLog") && strstr(si->pszModule, "IRC")) { + char szName[MAX_PATH]; + + WideCharToMultiByte(CP_ACP, 0, si->ptszName, -1, szName, MAX_PATH, 0, 0); + szName[MAX_PATH - 1] = 0; + CallService("MSP/HTMLlog/ViewLog", (WPARAM)si->pszModule, (LPARAM)szName); + } else if (pInfo) + ShellExecute(hwndDlg, NULL, GetChatLogsFilename(si, 0), NULL, NULL, SW_SHOW); + } + break; + + case IDC_CHAT_CLOSE: + SendMessage(hwndDlg, WM_CLOSE, 0, 1); + break; + + case IDC_CHANMGR: + if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHANMGR))) + break; + DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_CHANMGR, NULL, NULL, (LPARAM)NULL); + break; + + case IDC_FILTER: + if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FILTER))) + break; + + if (si->iLogFilterFlags == 0 && !si->bFilterEnabled) { + MessageBox(0, TranslateT("The filter canoot be enabled, because there are no event types selected either global or for this chat room"), TranslateT("Event filter error"), MB_OK); + si->bFilterEnabled = 0; + } else + si->bFilterEnabled = !si->bFilterEnabled; + + SendDlgItemMessage(hwndDlg, IDC_FILTER, BUTTONSETOVERLAYICON, + (LPARAM)(si->bFilterEnabled ? PluginConfig.g_iconOverlayEnabled : PluginConfig.g_iconOverlayDisabled), 0); + + if (si->bFilterEnabled && M->GetByte("Chat", "RightClickFilter", 0) == 0) { + SendMessage(hwndDlg, GC_SHOWFILTERMENU, 0, 0); + break; + } + SendMessage(hwndDlg, GC_REDRAWLOG, 0, 0); + SendMessage(hwndDlg, GC_UPDATETITLE, 0, 0); + M->WriteByte(si->hContact, "Chat", "FilterEnabled", (BYTE)si->bFilterEnabled); + break; + + case IDC_BKGCOLOR: { + CHARFORMAT2 cf; + + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwEffects = 0; + + if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_BKGCOLOR))) + break; + + if (IsDlgButtonChecked(hwndDlg, IDC_BKGCOLOR)) { + if (M->GetByte("Chat", "RightClickFilter", 0) == 0) + SendMessage(hwndDlg, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_BKGCOLOR); + else if (si->bBGSet) { + cf.dwMask = CFM_BACKCOLOR; + cf.crBackColor = MM_FindModule(si->pszModule)->crColors[si->iBG]; + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } else { + cf.dwMask = CFM_BACKCOLOR; + cf.crBackColor = (COLORREF)M->GetDword(FONTMODULE, "inputbg", SRMSGDEFSET_BKGCOLOUR); + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } + break; + + case IDC_COLOR: { + CHARFORMAT2 cf; + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwEffects = 0; + + if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_COLOR))) + break; + + if (IsDlgButtonChecked(hwndDlg, IDC_COLOR)) { + if (M->GetByte("Chat", "RightClickFilter", 0) == 0) + SendMessage(hwndDlg, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_COLOR); + else if (si->bFGSet) { + cf.dwMask = CFM_COLOR; + cf.crTextColor = MM_FindModule(si->pszModule)->crColors[si->iFG]; + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } else { + COLORREF cr; + + LoadLogfont(MSGFONTID_MESSAGEAREA, NULL, &cr, FONTMODULE); + cf.dwMask = CFM_COLOR; + cf.crTextColor = cr; + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } + break; + + case IDC_CHAT_BOLD: + case IDC_ITALICS: + case IDC_CHAT_UNDERLINE: { + CHARFORMAT2 cf; + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE; + cf.dwEffects = 0; + + if (LOWORD(wParam) == IDC_CHAT_BOLD && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_BOLD))) + break; + if (LOWORD(wParam) == IDC_ITALICS && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_ITALICS))) + break; + if (LOWORD(wParam) == IDC_CHAT_UNDERLINE && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_UNDERLINE))) + break; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_BOLD)) + cf.dwEffects |= CFE_BOLD; + if (IsDlgButtonChecked(hwndDlg, IDC_ITALICS)) + cf.dwEffects |= CFE_ITALIC; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_UNDERLINE)) + cf.dwEffects |= CFE_UNDERLINE; + + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } + break; + + case WM_KEYDOWN: + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + break; + + case WM_MOVE: + break; + + case WM_ERASEBKGND: { + HDC hdc = (HDC)wParam; + RECT rcClient, rcWindow, rc; + CSkinItem *item; + POINT pt; + UINT item_ids[3] = {ID_EXTBKUSERLIST, ID_EXTBKHISTORY, ID_EXTBKINPUTAREA}; + UINT ctl_ids[3] = {IDC_LIST, IDC_CHAT_LOG, IDC_CHAT_MESSAGE}; + int i; + bool fAero = M->isAero(); + bool fInfoPanel = dat->Panel->isActive(); + HANDLE hbp = 0; + HDC hdcMem = 0; + HBITMAP hbm, hbmOld; + + GetClientRect(hwndDlg, &rcClient); + LONG cx = rcClient.right - rcClient.left; + LONG cy = rcClient.bottom - rcClient.top; + + if (CMimAPI::m_haveBufferedPaint) + hbp = CSkin::InitiateBufferedPaint(hdc, rcClient, hdcMem); + else { + hdcMem = CreateCompatibleDC(hdc); + hbm = CSkin::CreateAeroCompatibleBitmap(rcClient, hdc); + hbmOld = (HBITMAP)SelectObject(hdcMem, hbm); + } + + if (CSkin::m_skinEnabled && !fAero) { + CSkin::SkinDrawBG(hwndDlg, dat->pContainer->hwnd, dat->pContainer, &rcClient, hdcMem); + for (i=0; i < 3; i++) { + item = &SkinItems[item_ids[i]]; + if (!item->IGNORED) { + + GetWindowRect(GetDlgItem(hwndDlg, ctl_ids[i]), &rcWindow); + pt.x = rcWindow.left; + pt.y = rcWindow.top; + ScreenToClient(hwndDlg, &pt); + rc.left = pt.x - item->MARGIN_LEFT; + rc.top = pt.y - item->MARGIN_TOP; + rc.right = rc.left + item->MARGIN_RIGHT + (rcWindow.right - rcWindow.left) + item->MARGIN_LEFT; + rc.bottom = rc.top + item->MARGIN_BOTTOM + (rcWindow.bottom - rcWindow.top) + item->MARGIN_TOP; + CSkin::DrawItem(hdcMem, &rc, item); + } + } + } + else { + CSkin::FillBack(hdcMem, &rcClient); + + if (M->isAero()) { + LONG temp = rcClient.bottom; + rcClient.bottom = dat->Panel->isActive() ? dat->Panel->getHeight() + 5 : 5; + FillRect(hdcMem, &rcClient, (HBRUSH)GetStockObject(BLACK_BRUSH)); + rcClient.bottom = temp; + } + } + + GetClientRect(hwndDlg, &rc); + dat->Panel->renderBG(hdcMem, rc, &SkinItems[ID_EXTBKINFOPANELBG], fAero); + + + dat->Panel->renderContent(hdcMem); + + if (!CSkin::m_skinEnabled) + CSkin::RenderToolbarBG(dat, hdcMem, rcClient); + + if (hbp) + CSkin::FinalizeBufferedPaint(hbp, &rcClient); + else { + BitBlt(hdc, 0, 0, cx, cy, hdcMem, 0, 0, SRCCOPY); + SelectObject(hdcMem, hbmOld); + DeleteObject(hbm); + DeleteDC(hdcMem); + } + if (!dat->fLimitedUpdate) + SetAeroMargins(dat->pContainer); + return 1; + } + + case WM_NCPAINT: + if (CSkin::m_skinEnabled) + return 0; + break; + case WM_PAINT: { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwndDlg, &ps); + EndPaint(hwndDlg, &ps); + return 0; + } + + case DM_SETINFOPANEL: + CInfoPanel::setPanelHandler(dat, wParam, lParam); + return 0; + + case DM_INVALIDATEPANEL: + if (dat->Panel) + dat->Panel->Invalidate(true); + return 0; + + case WM_RBUTTONUP: { + POINT pt; + int iSelection; + HMENU subMenu; + int isHandled; + int menuID = 0; + + GetCursorPos(&pt); + + if (dat->Panel->invokeConfigDialog(pt)) + break; + + subMenu = GetSubMenu(dat->pContainer->hMenuContext, 0); + + MsgWindowUpdateMenu(dat, subMenu, MENU_TABCONTEXT); + + iSelection = TrackPopupMenu(subMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL); + if (iSelection >= IDM_CONTAINERMENU) { + DBVARIANT dbv = {0}; + char szIndex[10]; + char *szKey = "TAB_ContainersW"; + _snprintf(szIndex, 8, "%d", iSelection - IDM_CONTAINERMENU); + if (iSelection - IDM_CONTAINERMENU >= 0) { + if (!M->GetTString(NULL, szKey, szIndex, &dbv)) { + SendMessage(hwndDlg, DM_CONTAINERSELECTED, 0, (LPARAM)dbv.ptszVal); + DBFreeVariant(&dbv); + } + } + + break; + } + isHandled = MsgWindowMenuHandler(dat, iSelection, MENU_TABCONTEXT); + break; + } + + case WM_LBUTTONDBLCLK: { + if (LOWORD(lParam) < 30) + PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0); + break; + } + + case WM_CLOSE: + if (wParam == 0 && lParam == 0) { + if (PluginConfig.m_EscapeCloses == 1) { + SendMessage(dat->pContainer->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); + return(TRUE); + } else if (PluginConfig.m_HideOnClose && PluginConfig.m_EscapeCloses == 2) { + ShowWindow(dat->pContainer->hwnd, SW_HIDE); + return(TRUE); + } + _dlgReturn(hwndDlg, TRUE); + } + SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 1); + break; + + case DM_CONTAINERSELECTED: { + struct TContainerData *pNewContainer = 0; + TCHAR *szNewName = (TCHAR *)lParam; + if (!_tcscmp(szNewName, TranslateT("Default container"))) + szNewName = CGlobals::m_default_container_name; + int iOldItems = TabCtrl_GetItemCount(hwndTab); + if (!_tcsncmp(dat->pContainer->szName, szNewName, CONTAINER_NAMELEN)) + break; + pNewContainer = FindContainerByName(szNewName); + if (pNewContainer == NULL) + pNewContainer = CreateContainer(szNewName, FALSE, dat->hContact); + M->WriteTString(dat->hContact, SRMSGMOD_T, "containerW", szNewName); + PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_DOCREATETAB_CHAT, (WPARAM)pNewContainer, (LPARAM)hwndDlg); + if (iOldItems > 1) // there were more than 1 tab, container is still valid + SendMessage(dat->pContainer->hwndActive, WM_SIZE, 0, 0); + SetForegroundWindow(pNewContainer->hwnd); + SetActiveWindow(pNewContainer->hwnd); + } + break; + // container API support functions + + case DM_QUERYCONTAINER: { + struct TContainerData **pc = (struct TContainerData **) lParam; + if (pc) + *pc = dat->pContainer; + return 0; + } + + case DM_QUERYHCONTACT: { + HANDLE *phContact = (HANDLE *) lParam; + if (phContact) + *phContact = dat->hContact; + return 0; + } + + case GC_CLOSEWINDOW: { + int iTabs, i; + TCITEM item = {0}; + RECT rc; + struct TContainerData *pContainer = dat->pContainer; + BOOL bForced = (lParam == 2); + + iTabs = TabCtrl_GetItemCount(hwndTab); + if (iTabs == 1) { + if (/*!bForced && */CMimAPI::m_shutDown == 0) { + //DestroyWindow(GetParent(GetParent(hwndDlg))); + //PostMessage(hwndDlg, WM_CLOSE, 0, 1); + SendMessage(GetParent(GetParent(hwndDlg)), WM_CLOSE, 0, 1); + return 1; + } + } + + dat->pContainer->iChilds--; + i = GetTabIndexFromHWND(hwndTab, hwndDlg); + + /* + * after closing a tab, we need to activate the tab to the left side of + * the previously open tab. + * normally, this tab has the same index after the deletion of the formerly active tab + * unless, of course, we closed the last (rightmost) tab. + */ + if (!dat->pContainer->bDontSmartClose && iTabs > 1 && !bForced) { + if (i == iTabs - 1) + i--; + else + i++; + TabCtrl_SetCurSel(hwndTab, i); + item.mask = TCIF_PARAM; + TabCtrl_GetItem(hwndTab, i, &item); // retrieve dialog hwnd for the now active tab... + + dat->pContainer->hwndActive = (HWND) item.lParam; + SendMessage(dat->pContainer->hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rc); + SetWindowPos(dat->pContainer->hwndActive, HWND_TOP, rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top), SWP_SHOWWINDOW); + ShowWindow((HWND)item.lParam, SW_SHOW); + SetForegroundWindow(dat->pContainer->hwndActive); + SetFocus(dat->pContainer->hwndActive); + SendMessage(dat->pContainer->hwnd, WM_SIZE, 0, 0); + } + //SM_SetTabbedWindowHwnd(0, 0); + //DestroyWindow(hwndDlg); + if (iTabs == 1) + SendMessage(GetParent(GetParent(hwndDlg)), WM_CLOSE, 0, 1); + else { + PostMessage(pContainer->hwnd, WM_SIZE, 0, 0); + DestroyWindow(hwndDlg); + } + return 0; + } + + case DM_SETLOCALE: + if (dat->dwFlags & MWF_WASBACKGROUNDCREATE) + break; + if (dat->pContainer->hwndActive == hwndDlg && PluginConfig.m_AutoLocaleSupport && dat->hContact != 0 && dat->pContainer->hwnd == GetForegroundWindow() && dat->pContainer->hwnd == GetActiveWindow()) { + if (lParam) + dat->hkl = (HKL)lParam; + + if (dat->hkl) + ActivateKeyboardLayout(dat->hkl, 0); + } + return 0; + + case DM_SAVESIZE: { + RECT rcClient; + + if (dat->dwFlags & MWF_NEEDCHECKSIZE) + lParam = 0; + + dat->dwFlags &= ~MWF_NEEDCHECKSIZE; + if (dat->dwFlags & MWF_WASBACKGROUNDCREATE) + dat->dwFlags &= ~MWF_INITMODE; + + SendMessage(dat->pContainer->hwnd, DM_QUERYCLIENTAREA, 0, (LPARAM)&rcClient); + MoveWindow(hwndDlg, rcClient.left, rcClient.top, (rcClient.right - rcClient.left), (rcClient.bottom - rcClient.top), TRUE); + if (dat->dwFlags & MWF_WASBACKGROUNDCREATE) { + POINT pt = {0};; + + dat->dwFlags &= ~MWF_WASBACKGROUNDCREATE; + SendMessage(hwndDlg, WM_SIZE, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETSCROLLPOS, 0, (LPARAM)&pt); + if (PluginConfig.m_AutoLocaleSupport) { + if (dat->hkl == 0) + DM_LoadLocale(dat); + else + PostMessage(hwndDlg, DM_SETLOCALE, 0, 0); + } + } else { + SendMessage(hwndDlg, WM_SIZE, 0, 0); + if (lParam == 0) + PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 1, 1); + } + return 0; + } + + case DM_GETWINDOWSTATE: { + UINT state = 0; + + state |= MSG_WINDOW_STATE_EXISTS; + if (IsWindowVisible(hwndDlg)) + state |= MSG_WINDOW_STATE_VISIBLE; + if (GetForegroundWindow() == dat->pContainer->hwnd) + state |= MSG_WINDOW_STATE_FOCUS; + if (IsIconic(dat->pContainer->hwnd)) + state |= MSG_WINDOW_STATE_ICONIC; + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, state); + return TRUE; + } + + case DM_ADDDIVIDER: + if (!(dat->dwFlags & MWF_DIVIDERSET) && g_Settings.UseDividers) { + if (GetWindowTextLengthA(GetDlgItem(hwndDlg, IDC_CHAT_LOG)) > 0) { + dat->dwFlags |= MWF_DIVIDERWANTED; + dat->dwFlags |= MWF_DIVIDERSET; + } + } + return 0; + + case DM_CHECKSIZE: + dat->dwFlags |= MWF_NEEDCHECKSIZE; + return 0; + + case DM_REFRESHTABINDEX: + dat->iTabID = GetTabIndexFromHWND(GetParent(hwndDlg), hwndDlg); + return 0; + + case DM_STATUSBARCHANGED: + UpdateStatusBar(dat); + break; + + //mad: bb-api + case DM_BBNEEDUPDATE:{ + if (lParam) + CB_ChangeButton(hwndDlg,dat,(CustomButtonData*)lParam); + else + BB_InitDlgButtons(dat); + + BB_SetButtonsPos(dat); + }break; + + case DM_CBDESTROY:{ + if (lParam) + CB_DestroyButton(hwndDlg,dat,(DWORD)wParam,(DWORD)lParam); + else + CB_DestroyAllButtons(hwndDlg,dat); + }break; + // + + case DM_CONFIGURETOOLBAR: + SendMessage(hwndDlg, WM_SIZE, 0, 0); + break; + + case DM_SMILEYOPTIONSCHANGED: + ConfigureSmileyButton(dat); + SendMessage(hwndDlg, GC_REDRAWLOG, 0, 1); + break; + + case EM_THEMECHANGED: + DM_FreeTheme(dat); + return DM_ThemeChanged(dat); + + case WM_DWMCOMPOSITIONCHANGED: + BB_RefreshTheme(dat); + memset((void *)&dat->pContainer->mOld, -1000, sizeof(MARGINS)); + CProxyWindow::verify(dat); + break; + + case DM_ACTIVATEME: + ActivateExistingTab(dat->pContainer, hwndDlg); + return 0; + + case DM_ACTIVATETOOLTIP: { + if (IsIconic(dat->pContainer->hwnd) || dat->pContainer->hwndActive != hwndDlg) + break; + + dat->Panel->showTip(wParam, lParam); + break; + } + + case DM_SAVEMESSAGELOG: + DM_SaveLogAsRTF(dat); + return 0; + + case DM_CHECKAUTOHIDE: + DM_CheckAutoHide(dat, wParam, lParam); + return 0; + + case WM_NCDESTROY: + if (dat) { + memset((void *)&dat->pContainer->mOld, -1000, sizeof(MARGINS)); + PostMessage(dat->pContainer->hwnd, WM_SIZE, 0, 1); + delete dat->Panel; + if (dat->pContainer->dwFlags & CNT_SIDEBAR) + dat->pContainer->SideBar->removeSession(dat); + free(dat); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + } + break; + + case WM_DESTROY: { + int i; + + if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->hContact, (LPARAM)0)) + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->hContact, (LPARAM)szChatIconString); + si->wState &= ~STATE_TALK; + si->hWnd = NULL; + si->dat = 0; + si->pContainer = 0; + + //SetWindowLongPtr(hwndDlg,GWLP_USERDATA,0); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTERX), GWLP_WNDPROC, (LONG_PTR)OldSplitterProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SPLITTERY), GWLP_WNDPROC, (LONG_PTR)OldSplitterProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LIST), GWLP_WNDPROC, (LONG_PTR)OldNicklistProc); + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_UNSUBCLASSED, 0, 0); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), GWLP_WNDPROC, (LONG_PTR)OldMessageProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHAT_LOG), GWLP_WNDPROC, (LONG_PTR)OldLogProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_WNDPROC, (LONG_PTR)OldFilterButtonProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_COLOR), GWLP_WNDPROC, (LONG_PTR)OldFilterButtonProc); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_BKGCOLOR), GWLP_WNDPROC, (LONG_PTR)OldFilterButtonProc); + + TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSING, 0); + + if (!dat->fIsAutosizingInput) + DBWriteContactSettingWord(NULL, "Chat", "SplitterX", (WORD)g_Settings.iSplitterX); + + if (dat->pContainer->settings->fPrivate && !IsAutoSplitEnabled(dat)) + DBWriteContactSettingWord(NULL, "Chat", "splitY", (WORD)g_Settings.iSplitterY); + + DM_FreeTheme(dat); + + UpdateTrayMenuState(dat, FALSE); // remove me from the tray menu (if still there) + if (PluginConfig.g_hMenuTrayUnread) + DeleteMenu(PluginConfig.g_hMenuTrayUnread, (UINT_PTR)dat->hContact, MF_BYCOMMAND); + + if (dat->hSmileyIcon) + DestroyIcon(dat->hSmileyIcon); + + if (dat->hwndTip) + DestroyWindow(dat->hwndTip); + + if (hCurHyperlinkHand) + DestroyCursor(hCurHyperlinkHand); + + i = GetTabIndexFromHWND(hwndTab, hwndDlg); + if (i >= 0) { + SendMessage(hwndTab, WM_USER + 100, 0, 0); // clean up tooltip + TabCtrl_DeleteItem(hwndTab, i); + BroadCastContainer(dat->pContainer, DM_REFRESHTABINDEX, 0, 0); + dat->iTabID = -1; + } + if (dat->pWnd) { + delete dat->pWnd; + dat->pWnd = 0; + } + //MAD + M->RemoveWindow(hwndDlg); + + TABSRMM_FireEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSE, 0); + break; + } + } + return(FALSE); +} diff --git a/plugins/TabSRMM/src/commonheaders.h b/plugins/TabSRMM/src/commonheaders.h index 28a90ca0b9..83ccf13448 100644 --- a/plugins/TabSRMM/src/commonheaders.h +++ b/plugins/TabSRMM/src/commonheaders.h @@ -174,7 +174,7 @@ #include #include -#include "../include/resource.h" +#include "include/resource.h" /* State of icon with such flag will not be saved, and you must set it manually */ #define MBF_OWNERSTATE 0x04 @@ -211,7 +211,7 @@ #define safe_sizeof(a) (unsigned int)((sizeof((a)) / sizeof((a)[0]))) -#include "../include/version.h" +#include "include/version.h" #include "m_ieview.h" #include "m_popup2.h" #include "m_metacontacts.h" @@ -225,31 +225,31 @@ #include "m_historyevents.h" #include "m_smileyadd.h" -#include "../include/m_cln_skinedit.h" -#include "../include/buttonbar.h" -#include "../include/msgs.h" -#include "../include/msgdlgutils.h" -#include "../include/typingnotify.h" -#include "../include/generic_msghandlers.h" -#include "../include/nen.h" +#include "include/m_cln_skinedit.h" +#include "include/buttonbar.h" +#include "include/msgs.h" +#include "include/msgdlgutils.h" +#include "include/typingnotify.h" +#include "include/generic_msghandlers.h" +#include "include/nen.h" extern NEN_OPTIONS nen_options; -#include "../include/functions.h" -#include "../chat/chat.h" - -#include "../include/contactcache.h" -#include "../include/translator.h" -#include "../include/themes.h" -#include "../include/globals.h" -#include "../include/mim.h" -#include "../include/sendqueue.h" -#include "../include/taskbar.h" -#include "../include/controls.h" -#include "../include/infopanel.h" -#include "../include/sidebar.h" -#include "../include/utils.h" -#include "../include/sendlater.h" - -#include "../chat/muchighlight.h" +#include "include/functions.h" +#include "chat/chat.h" + +#include "include/contactcache.h" +#include "include/translator.h" +#include "include/themes.h" +#include "include/globals.h" +#include "include/mim.h" +#include "include/sendqueue.h" +#include "include/taskbar.h" +#include "include/controls.h" +#include "include/infopanel.h" +#include "include/sidebar.h" +#include "include/utils.h" +#include "include/sendlater.h" + +#include "chat/muchighlight.h" #if !defined(_WIN64) && !defined(_USE_32BIT_TIME_T) #define _USE_32BIT_TIME_T diff --git a/plugins/TabSRMM/src/include/ImageDataObject.h b/plugins/TabSRMM/src/include/ImageDataObject.h new file mode 100644 index 0000000000..0e2c112827 --- /dev/null +++ b/plugins/TabSRMM/src/include/ImageDataObject.h @@ -0,0 +1,136 @@ +/* +Miranda SmileyAdd Plugin +Copyright (C) 2004 Rein-Peter de Boer (peacow) + +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. +*/ + +//code taken partly from public example on the internet, source unknown. + +//make sure is include before this file +#include +#include +#include + +class CImageDataObject : IDataObject +{ +public: + // returns true on success, false on failure + static bool InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap); + // returns true on success, false on failure + //static bool InsertIcon(IRichEditOle* pRichEditOle, HICON hIcon, + //COLORREF backgroundColor, int sizeX = 0, int sizeY = 0); + +private: + ULONG m_ulRefCnt; + BOOL m_bRelease; + + STGMEDIUM m_stgmed; + FORMATETC m_format; + +public: + CImageDataObject() : m_ulRefCnt(0) + { + m_bRelease = FALSE; + } + + ~CImageDataObject() + { + if (m_bRelease) + ::ReleaseStgMedium(&m_stgmed); + } + + // IUnknown interface + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) + { + if (iid == IID_IUnknown || iid == IID_IDataObject) + { + *ppvObject = this; + AddRef(); + return S_OK; + } + else + return E_NOINTERFACE; + } + + STDMETHOD_(ULONG, AddRef)(void) + { + m_ulRefCnt++; + return m_ulRefCnt; + } + + STDMETHOD_(ULONG, Release)(void) + { + m_ulRefCnt--; + if (m_ulRefCnt == 0) + delete this; + return m_ulRefCnt; + } + + // IDataObject Interface + STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium) { + HANDLE hDst; + hDst = ::OleDuplicateData(m_stgmed.hBitmap, CF_BITMAP, 0); + if (hDst == NULL) + return E_HANDLE; + + pmedium->tymed = TYMED_GDI; + pmedium->hBitmap = (HBITMAP)hDst; + pmedium->pUnkForRelease = NULL; + + return S_OK; + } + + STDMETHOD(GetDataHere)(FORMATETC* pformatetc, STGMEDIUM* pmedium ) { + return E_NOTIMPL; + } + + STDMETHOD(QueryGetData)(FORMATETC* pformatetc ) { + return E_NOTIMPL; + } + + STDMETHOD(GetCanonicalFormatEtc)(FORMATETC* pformatectIn ,FORMATETC* pformatetcOut ) { + return E_NOTIMPL; + } + + STDMETHOD(SetData)(FORMATETC* pformatetc , STGMEDIUM* pmedium , BOOL fRelease ) { + m_format = *pformatetc; + m_stgmed = *pmedium; + + return S_OK; + } + + STDMETHOD(EnumFormatEtc)(DWORD dwDirection , IEnumFORMATETC** ppenumFormatEtc ) { + return E_NOTIMPL; + } + + STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, + DWORD *pdwConnection) { + return E_NOTIMPL; + } + + STDMETHOD(DUnadvise)(DWORD dwConnection) { + return E_NOTIMPL; + } + + STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise) { + return E_NOTIMPL; + } + + // Other + void SetBitmap(HBITMAP hBitmap); + IOleObject *GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage); +}; + diff --git a/plugins/TabSRMM/src/include/buttonbar.h b/plugins/TabSRMM/src/include/buttonbar.h new file mode 100644 index 0000000000..9be67e965b --- /dev/null +++ b/plugins/TabSRMM/src/include/buttonbar.h @@ -0,0 +1,54 @@ +#ifndef _BUTTONSBAR_H +#define _BUTTONSBAR_H + +#define MIN_CBUTTONID 4000 +#define MAX_CBUTTONID 5000 + +#define BBSF_IMBUTTON (1<<0) +#define BBSF_CHATBUTTON (1<<1) +#define BBSF_CANBEHIDDEN (1<<2) +#define BBSF_NTBSWAPED (1<<3) +#define BBSF_NTBDESTRUCT (1<<4) + +typedef struct _tagCustomButtonData + { + DWORD dwButtonOrigID; // id of button used while button creation and to store button info in DB + char * pszModuleName; //module name without spaces and underline symbols (e.g. "tabsrmm") + + DWORD dwButtonCID; + DWORD dwArrowCID; //only use with BBBF_ISARROWBUTTON flag + + TCHAR * ptszTooltip; //button's tooltip + + DWORD dwPosition; // default order pos of button, counted from window edge (left or right) + int iButtonWidth; //must be 22 for regular button and 33 for button with arrow + HANDLE hIcon; //Handle to icolib registred icon + BOOL bIMButton,bChatButton; + BOOL bCanBeHidden,bHidden,bAutoHidden,bDummy,bDisabled,bPushButton; + BOOL bLSided,bRSided; + BYTE opFlags; + }CustomButtonData; + +static INT_PTR CB_ModifyButton(WPARAM wParam, LPARAM lParam); +static INT_PTR CB_RemoveButton(WPARAM wParam, LPARAM lParam); +static INT_PTR CB_AddButton(WPARAM wParam, LPARAM lParam); +static INT_PTR CB_GetButtonState(WPARAM wParam, LPARAM lParam); +static INT_PTR CB_SetButtonState(WPARAM wParam, LPARAM lParam); +static void CB_GetButtonSettings(HANDLE hContact,CustomButtonData *cbd); + +void CB_WriteButtonSettings(HANDLE hContact,CustomButtonData *cbd); +int sstSortButtons(const void * vmtbi1, const void * vmtbi2); + +void CB_DeInitCustomButtons(); +void CB_InitCustomButtons(); +void CB_InitDefaultButtons(); +void CB_ReInitCustomButtons(); + +/* MinGW doesn't like this struct declatations below */ +void BB_UpdateIcons(HWND hdlg,struct TWindowData *dat); +void BB_RefreshTheme(const TWindowData *dat); +void CB_DestroyAllButtons(HWND hwndDlg,struct TWindowData *dat); +void CB_DestroyButton(HWND hwndDlg,struct TWindowData *dat,DWORD dwButtonCID,DWORD dwFlags); +void CB_ChangeButton(HWND hwndDlg,struct TWindowData *dat,CustomButtonData* cbd); + +#endif diff --git a/plugins/TabSRMM/src/include/contactcache.h b/plugins/TabSRMM/src/include/contactcache.h new file mode 100644 index 0000000000..309e95131d --- /dev/null +++ b/plugins/TabSRMM/src/include/contactcache.h @@ -0,0 +1,167 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: contactcache.h 12846 2010-10-01 03:26:02Z silvercircle $ + * + * the contact cache + * + */ + +#ifndef __CONTACTCACHE_H +#define __CONTACTCACHE_H + +#define C_INVALID_PROTO "" +#define C_INVALID_ACCOUNT _T("") +#define C_INVALID_PROTO_T _T("") +#define HISTORY_INITIAL_ALLOCSIZE 300 + + +struct TInputHistory { + TCHAR* szText; + size_t lLen; +}; + +struct TSessionStats { + enum { + BYTES_RECEIVED = 1, + BYTES_SENT = 2, + FAILURE = 3, + UPDATE_WITH_LAST_RCV= 4, + SET_LAST_RCV = 5, + INIT_TIMER = 6, + }; + + time_t started; + unsigned int iSent, iReceived, iSentBytes, iReceivedBytes; + unsigned int messageCount; + unsigned int iFailures; + unsigned int lastReceivedChars; + BOOL bWritten; +}; + +class CContactCache { +public: + + CContactCache () {} + CContactCache (const HANDLE hContact); + ~CContactCache () + { + releaseAlloced(); + } + void inc () { m_accessCount++; } + const bool isValid () const { return(m_Valid); } + const WORD getStatus () const { return(m_wStatus); } + const WORD getMetaStatus () const { return(m_wMetaStatus); } + const WORD getActiveStatus () const { return(m_isMeta ? m_wMetaStatus : m_wStatus); } + const WORD getOldStatus () const { return(m_wOldStatus); } + const TCHAR* getNick () const { return(m_szNick); } + const HANDLE getContact () const { return(m_hContact); } + const HANDLE getActiveContact () const { return(m_isMeta ? (m_hSubContact ? m_hSubContact : m_hContact) : m_hContact); } + const DWORD getIdleTS () const { return(m_idleTS); } + const char* getProto () const { return(m_szProto); } + const TCHAR* getProtoT () const { return(m_tszProto); } + const char* getMetaProto () const { return(m_szMetaProto ? m_szMetaProto : C_INVALID_PROTO); } + const TCHAR* getMetaProtoT () const { return(m_szMetaProto ? m_tszMetaProto : C_INVALID_PROTO_T); } + const char* getActiveProto () const { return(m_isMeta ? (m_szMetaProto ? m_szMetaProto : m_szProto) : m_szProto); } + const TCHAR* getActiveProtoT () const { return(m_isMeta ? (m_szMetaProto ? m_tszMetaProto : m_tszProto) : m_tszProto); } + bool isMeta () const { return(m_isMeta); } + bool isSubContact () const { return(m_isSubcontact); } + bool isFavorite () const { return(m_isFavorite); } + bool isRecent () const { return(m_isRecent); } + const TCHAR* getRealAccount () const { return(m_szAccount ? m_szAccount : C_INVALID_ACCOUNT); } + const TCHAR* getUIN () const { return(m_szUIN); } + const TCHAR* getStatusMsg () const { return(m_szStatusMsg); } + const TCHAR* getXStatusMsg () const { return(m_xStatusMsg); } + const TCHAR* getListeningInfo () const { return(m_ListeningInfo); } + BYTE getXStatusId () const { return(m_xStatus); } + const HWND getWindowData (TWindowData*& dat) const { dat = m_dat; return(m_hwnd); } + const HWND getHwnd () const { return(m_hwnd); } + int getMaxMessageLength (); + + TWindowData* getDat () const { return(m_dat); } + + void updateStats (int iType, size_t value = 0); + const DWORD getSessionStart () const { return(m_stats->started); } + const int getSessionMsgCount () const { return((int)m_stats->messageCount) ; } + void updateState (); + bool updateStatus (); + bool updateNick (); + void updateMeta (bool fForce = false); + bool updateUIN (); + void updateStatusMsg (const char *szKey = 0); + void setWindowData (const HWND hwnd = 0, TWindowData *dat = 0); + void resetMeta (); + void closeWindow (); + void deletedHandler (); + void updateFavorite (); + TCHAR* getNormalizedStatusMsg (const TCHAR *src, bool fStripAll = false); + HICON getIcon (int& iSize) const; + + /* + * input history + */ + void saveHistory (WPARAM wParam, LPARAM lParam); + void inputHistoryEvent (WPARAM wParam); + + HANDLE m_hContact; + CContactCache* m_next; + + static CContactCache* m_cCache; + static CContactCache* getContactCache(const HANDLE hContact); + +private: + void allocStats (); + void initPhaseTwo (); + void allocHistory (); + void releaseAlloced (); + +private: + size_t m_accessCount; + HANDLE m_hSubContact; + WORD m_wStatus, m_wMetaStatus; + WORD m_wOldStatus; + char* m_szProto, *m_szMetaProto; + TCHAR* m_tszProto, m_tszMetaProto[40]; + TCHAR* m_szAccount; + TCHAR m_szNick[80], m_szUIN[80]; + TCHAR* m_szStatusMsg, *m_xStatusMsg, *m_ListeningInfo; + BYTE m_xStatus; + DWORD m_idleTS; + bool m_isMeta, m_isSubcontact; + bool m_Valid; + bool m_isFavorite; + bool m_isRecent; + HWND m_hwnd; + int m_nMax; + int m_iHistoryCurrent, m_iHistoryTop, m_iHistorySize; + TWindowData* m_dat; + TSessionStats* m_stats; + TInputHistory* m_history; +}; + +#endif /* __CONTACTCACHE_H */ diff --git a/plugins/TabSRMM/src/include/controls.h b/plugins/TabSRMM/src/include/controls.h new file mode 100644 index 0000000000..2f6e236ca3 --- /dev/null +++ b/plugins/TabSRMM/src/include/controls.h @@ -0,0 +1,136 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: controls.h 11635 2010-04-26 07:17:39Z silvercircle $ + * + * menu bar and status bar classes for the container window. + * + */ + +#ifndef __CONTROLS_H +#define __CONTROLS_H + +extern LONG_PTR CALLBACK StatusBarSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +class CMenuBar +{ +public: + enum { + NR_BUTTONS = 8 + }; + + CMenuBar(HWND hwndParent, const TContainerData *pContainer); + ~CMenuBar(); + + const RECT& TSAPI getClientRect(); + void TSAPI Resize(WORD wWidth, WORD wHeight, BOOL redraw) const + { + ::SetWindowPos(m_hwndToolbar, 0, 4, 0, wWidth, m_size_y, SWP_NOZORDER | SWP_NOACTIVATE | + SWP_NOCOPYBITS|SWP_NOREDRAW); + + } + LONG TSAPI getHeight() const; + void TSAPI Show(int showCmd) const + { + ::ShowWindow(m_hwndToolbar, showCmd); + } + LONG_PTR TSAPI Handle(const NMTOOLBAR *nmtb); + void TSAPI Cancel(); + LONG_PTR TSAPI processMsg(const UINT msg, const WPARAM wParam, const LPARAM lParam); + bool TSAPI isContactMenu() const { return(m_isContactMenu); } + bool TSAPI isMainMenu() const { return(m_isMainMenu); } + void TSAPI configureMenu(void) const; + void TSAPI setActive(HMENU hMenu) + { + m_activeSubMenu = hMenu; + } + void setAero(bool fState) { m_isAero = fState; } + const bool getAero(void) const { return(m_isAero); } + + const LRESULT processAccelerator(TCHAR a, UINT& ctlId) const + { + UINT _ctlId; + + const LRESULT result = ::SendMessage(m_hwndToolbar, TB_MAPACCELERATOR, (WPARAM)a, (LPARAM)&_ctlId); + ctlId = _ctlId; + + return(result); + } + void TSAPI autoShow(const int showcmd = 1); + + const int idToIndex(const int id) const + { + for (int i = 0; i < NR_BUTTONS; i++) { + if (m_TbButtons[i].idCommand == id ) + return(i); + } + return(-1); + } +public: + static HHOOK m_hHook; + static HBITMAP m_MimIcon; + +private: + HWND m_hwndToolbar; + RECT m_rcClient; + TContainerData *m_pContainer; + HMENU m_activeMenu, m_activeSubMenu;; + int m_activeID; + bool m_fTracking; + bool m_isContactMenu; + bool m_isMainMenu; + bool m_isAero; + bool m_mustAutoHide; + LONG m_size_y; + WNDPROC m_oldWndProc; + /* + * for custom drawing + */ + RECT m_rcItem; + HDC m_hdcDraw; + HBITMAP m_hbmDraw, m_hbmOld; + HANDLE m_hTheme; + HFONT m_hOldFont; + + static TBBUTTON m_TbButtons[8]; + static bool m_buttonsInit; + static CMenuBar *m_Owner; + static int m_MimIconRefCount; +private: + LONG_PTR TSAPI customDrawWorker(NMCUSTOMDRAW *nm); + void TSAPI updateState(const HMENU hMenu) const; + void TSAPI invoke(const int id); + void TSAPI cancel(const int id); + void TSAPI obtainHook(); + void TSAPI releaseHook(); + + static LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // subclassing for the toolbar control + static LRESULT CALLBACK MessageHook(int nCode, WPARAM wParam, LPARAM lParam); // message hook (only active when modal menus are active) +}; + +#endif /* __CONTROLS_H */ diff --git a/plugins/TabSRMM/src/include/functions.h b/plugins/TabSRMM/src/include/functions.h new file mode 100644 index 0000000000..49ae0f79ab --- /dev/null +++ b/plugins/TabSRMM/src/include/functions.h @@ -0,0 +1,199 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: functions.h 11636 2010-04-27 22:08:16Z silvercircle $ + * + * Global function prototypes + * + */ + +#ifndef _TABSRMM_FUNCTIONS_H +#define _TABSRMM_FUNCTIONS_H + +int Chat_PreShutdown (); +int Chat_ModulesLoaded (WPARAM wp, LPARAM lp); +int AvatarChanged (WPARAM wParam, LPARAM lParam); +int MyAvatarChanged (WPARAM wParam, LPARAM lParam); +int IcoLibIconsChanged (WPARAM wParam, LPARAM lParam); +int FontServiceFontsChanged (WPARAM wParam, LPARAM lParam); +int SmileyAddOptionsChanged (WPARAM wParam, LPARAM lParam); +int IEViewOptionsChanged (WPARAM wParam, LPARAM lParam); +void RegisterFontServiceFonts (); +int ModPlus_PreShutdown (WPARAM wparam, LPARAM lparam); +int ModPlus_Init (WPARAM wparam, LPARAM lparam); +LONG_PTR CALLBACK HotkeyHandlerDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + + +/* + * nen / event popup stuff + */ + +int TSAPI NEN_ReadOptions (NEN_OPTIONS *options); +int TSAPI NEN_WriteOptions (NEN_OPTIONS *options); +int TSAPI UpdateTrayMenu (const TWindowData *dat, WORD wStatus, const char *szProto, + const TCHAR *szStatus, HANDLE hContact, DWORD fromEvent); +static int TSAPI PopupPreview (NEN_OPTIONS *pluginOptions); +void TSAPI DeletePopupsForContact (HANDLE hContact, DWORD dwMask); + +/* + * tray stuff + */ + +void TSAPI CreateSystrayIcon (int create); +void TSAPI FlashTrayIcon (HICON hIcon); +void TSAPI UpdateTrayMenuState (TWindowData *dat, BOOL bForced); +void TSAPI LoadFavoritesAndRecent (); +void TSAPI AddContactToFavorites (HANDLE hContact, const TCHAR *szNickname, const char *szProto, TCHAR *szStatus, + WORD wStatus, HICON hIcon, BOOL mode, HMENU hMenu); +void TSAPI CreateTrayMenus (int mode); +void TSAPI HandleMenuEntryFromhContact (int iSelection); + +/* + * gneric msgwindow functions (creation, container management etc.) + */ + +BOOL TSAPI IsUtfSendAvailable (HANDLE hContact); +HWND TSAPI CreateNewTabForContact (TContainerData *pContainer, HANDLE hContact, int isSend, + const char *pszInitialText, BOOL bActivateTAb, BOOL bPopupContainer, BOOL bWantPopup, HANDLE hdbEvent); +int TSAPI ActivateTabFromHWND (HWND hwndTab, HWND hwnd); +void TSAPI FlashContainer (TContainerData *pContainer, int iMode, int iNum); +void TSAPI CreateImageList (BOOL bInitial); +TContainerData* TSAPI FindMatchingContainer(const TCHAR *szName, HANDLE hContact); +TContainerData* TSAPI CreateContainer (const TCHAR *name, int iTemp, HANDLE hContactFrom); +TContainerData* TSAPI FindContainerByName (const TCHAR *name); +int TSAPI GetTabIndexFromHWND (HWND hwndTab, HWND hwnd); +int TSAPI GetTabItemFromMouse (HWND hwndTab, POINT *pt); +int TSAPI ActivateTabFromHWND (HWND hwndTab, HWND hwnd); +void TSAPI AdjustTabClientRect (TContainerData *pContainer, RECT *rc); +void TSAPI ReflashContainer (TContainerData *pContainer); +HMENU TSAPI BuildMCProtocolMenu (HWND hwndDlg); + +TContainerData* TSAPI AppendToContainerList(TContainerData *pContainer); +TContainerData* TSAPI RemoveContainerFromList(TContainerData *pContainer); + +void TSAPI DeleteContainer (int iIndex); +void TSAPI RenameContainer (int iIndex, const TCHAR *newName); +int TSAPI GetContainerNameForContact (HANDLE hContact, TCHAR *szName, int iNameLen); +HMENU TSAPI BuildContainerMenu (); +void TSAPI BuildCodePageList (); +void TSAPI PreTranslateDates (); +void TSAPI ApplyContainerSetting (TContainerData *pContainer, DWORD flags, UINT mode, bool fForceResize); +void TSAPI BroadCastContainer (const TContainerData *pContainer, UINT message, WPARAM wParam, LPARAM lParam, BYTE iType = 0); +void TSAPI GetDefaultContainerTitleFormat(); +INT_PTR MessageWindowOpened(WPARAM wParam, LPARAM lParam); +void TSAPI SetAeroMargins (TContainerData *pContainer); +int TABSRMM_FireEvent (HANDLE hContact, HWND hwnd, unsigned int type, unsigned int subType); + +LRESULT CALLBACK IEViewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK HPPKFSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +/* + * skinning engine + */ +void TSAPI DrawAlpha (HDC hdcwnd, PRECT rc, DWORD basecolor, int alpha, DWORD basecolor2, + BYTE transparent, BYTE FLG_GRADIENT, BYTE FLG_CORNER, DWORD BORDERSTYLE, CImageItem *imageItem); +// the cached message log icons + +void TSAPI CacheMsgLogIcons (); +void TSAPI CacheLogFonts (); +void TSAPI InitAPI (); +void TSAPI LoadIconTheme (); +int TSAPI LoadFromIconLib (); +int TSAPI SetupIconLibConfig (); +void TSAPI RTF_CTableInit (); + +INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +int TSAPI InitOptions (void); +INT_PTR CALLBACK DlgProcContainer (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +int TSAPI DbEventIsShown (TWindowData *dat, DBEVENTINFO *dbei); +void TSAPI StreamInEvents (HWND hwndDlg,HANDLE hDbEventFirst,int count,int fAppend, DBEVENTINFO *dbei_s); +void TSAPI LoadLogfont (int i,LOGFONTA *lf,COLORREF *colour, char *szModule); + + +// custom tab control + +void TSAPI ReloadTabConfig (); +void TSAPI FreeTabConfig (); +int TSAPI RegisterTabCtrlClass (void); + +// buttons + +int TSAPI LoadTSButtonModule (void); +int TSAPI UnloadTSButtonModule (); + + +/* + * debugging support + */ + +int _DebugTraceW(const wchar_t *fmt, ...); +int _DebugTraceA(const char *fmt, ...); +int _DebugPopup(HANDLE hContact, const TCHAR *fmt, ...); +int _DebugMessage(HWND hwndDlg, struct TWindowData *dat, const char *fmt, ...); + +// themes + +const TCHAR* TSAPI GetThemeFileName (int iMode); +void TSAPI LoadLogfontFromINI (int i, char *szKey, LOGFONTA *lf, COLORREF *colour, const char *szIniFilename); +int TSAPI CheckThemeVersion (const TCHAR *szIniFilename); +void TSAPI WriteThemeToINI (const TCHAR *szIniFilename, TWindowData *dat); +void TSAPI ReadThemeFromINI (const TCHAR *szIniFilename, TContainerData *dat, int noAdvanced, DWORD dwFlags); + +// compatibility + +// user prefs + +int TSAPI LoadLocalFlags (HWND hwnd, TWindowData *dat); + +//TypingNotify +int TN_ModuleInit (); +int TN_OptionsInitialize (WPARAM wParam, LPARAM lParam); +int TN_ModuleDeInit (); +int TN_TypingMessage (WPARAM wParam, LPARAM lParam); + +// mod plus + +int ChangeClientIconInStatusBar (const TWindowData *dat); + +// hotkeys + +LRESULT ProcessHotkeysByMsgFilter (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR ctrlId); + +void TSAPI DrawMenuItem (DRAWITEMSTRUCT *dis, HICON hIcon, DWORD dwIdle); + +/* + * dialog procedures + */ + +INT_PTR CALLBACK SelectContainerDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK DlgProcContainerOptions (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK DlgProcAbout (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + + +#endif /* _TABSRMM_FUNCTIONS_H */ diff --git a/plugins/TabSRMM/src/include/generic_msghandlers.h b/plugins/TabSRMM/src/include/generic_msghandlers.h new file mode 100644 index 0000000000..4f756b24f0 --- /dev/null +++ b/plugins/TabSRMM/src/include/generic_msghandlers.h @@ -0,0 +1,67 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: generic_msghandlers.h 12058 2010-06-24 15:26:10Z silvercircle $ + * + * prototypes from generic_msghandlers.c + * + */ + +void TSAPI DM_SetDBButtonStates (HWND hwndChild, struct TWindowData *dat); +int TSAPI BTN_GetStockItem (ButtonItem *item, const TCHAR *szName); +HWND TSAPI DM_CreateClist (TWindowData *dat); + +void TSAPI DM_OptionsApplied (TWindowData *dat, WPARAM wParam, LPARAM lParam); +void TSAPI DM_UpdateTitle (TWindowData *dat, WPARAM wParam, LPARAM lParam); +LRESULT TSAPI DM_ScrollToBottom (TWindowData *dat, WPARAM wParam, LPARAM lParam); +LRESULT TSAPI DM_LoadLocale (TWindowData *dat); +LRESULT TSAPI DM_SaveLocale (TWindowData *dat, WPARAM wParam, LPARAM lParam); +LRESULT TSAPI DM_UpdateLastMessage (const TWindowData *dat); +LRESULT __stdcall DM_RecalcPictureSize (TWindowData *dat); +LRESULT TSAPI DM_WMCopyHandler (HWND hwnd, WNDPROC oldWndProc, WPARAM wParam, LPARAM lParam); +LRESULT TSAPI DM_MouseWheelHandler (HWND hwnd, HWND hwndParent, struct TWindowData *mwdat, WPARAM wParam, LPARAM lParam); +LRESULT TSAPI DM_ThemeChanged (TWindowData *dat); +void TSAPI DM_Typing (TWindowData *dat, bool fForceOff = false); +void TSAPI DM_FreeTheme (TWindowData *dat); +void TSAPI DM_NotifyTyping (TWindowData *dat, int mode); +int TSAPI DM_SplitterGlobalEvent (TWindowData *dat, WPARAM wParam, LPARAM lParam); +void TSAPI BB_InitDlgButtons (TWindowData *dat); + +BOOL TSAPI BB_SetButtonsPos (TWindowData *dat); +void TSAPI BB_RedrawButtons (TWindowData *dat); +void TSAPI BB_CustomButtonClick (TWindowData *dat,DWORD idFrom ,HWND hwndFrom, BOOL code) ; +void TSAPI DM_EventAdded (TWindowData *dat, WPARAM wParam, LPARAM lParam); +void TSAPI DM_InitRichEdit (TWindowData *dat); +LRESULT TSAPI DM_ContainerCmdHandler (TContainerData *pContainer, UINT cmd, WPARAM wParam, LPARAM lParam); +LRESULT TSAPI DM_MsgWindowCmdHandler (HWND hwndDlg, TContainerData *pContainer, TWindowData *dat, UINT cmd, WPARAM wParam, LPARAM lParam); +LRESULT TSAPI DM_GenericHotkeysCheck (MSG *message, TWindowData *dat); +void TSAPI DM_DismissTip (TWindowData *dat, const POINT& pt); +void TSAPI DM_InitTip (TWindowData *dat); +void TSAPI DM_HandleAutoSizeRequest(TWindowData *dat, REQRESIZE* rr); +void TSAPI DM_SaveLogAsRTF (const TWindowData* dat); +void TSAPI DM_CheckAutoHide (const TWindowData* dat, WPARAM wParam, LPARAM lParam); diff --git a/plugins/TabSRMM/src/include/globals.h b/plugins/TabSRMM/src/include/globals.h new file mode 100644 index 0000000000..69d62f66f7 --- /dev/null +++ b/plugins/TabSRMM/src/include/globals.h @@ -0,0 +1,245 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: globals.h 13046 2010-10-28 10:02:50Z silvercircle $ + * + * Plugin configuration variables and functions. Implemented as a class + * though there will always be only a single instance. + * + */ + +#ifndef __GLOBALS_H +#define __GLOBALS_H + +struct TSplitterBroadCast { + TContainerData *pSrcContainer; + TWindowData *pSrcDat; + LONG pos, pos_chat; + LONG off_chat, off_im; + LPARAM lParam; + BYTE bSync; +}; + +typedef BOOL (WINAPI *pfnSetMenuInfo )( HMENU hmenu, LPCMENUINFO lpcmi ); + +class CRTException : public std::runtime_error +{ +public: + CRTException(const char *szMsg, const TCHAR *szParam); + ~CRTException() {} + + void display() const; + +private: + TCHAR m_szParam[MAX_PATH]; +}; + + +class CGlobals +{ +public: + enum { + H_MS_MSG_SENDMESSAGE = 0, + H_MS_MSG_SENDMESSAGEW = 1, + H_MS_MSG_FORWARDMESSAGE = 2, + H_MS_MSG_GETWINDOWAPI = 3, + H_MS_MSG_GETWINDOWCLASS = 4, + H_MS_MSG_GETWINDOWDATA = 5, + H_MS_MSG_READMESSAGE = 6, + H_MS_MSG_TYPINGMESSAGE = 7, + H_MS_MSG_MOD_MESSAGEDIALOGOPENED = 8, + H_MS_TABMSG_SETUSERPREFS = 9, + H_MS_TABMSG_TRAYSUPPORT = 10, + H_MSG_MOD_GETWINDOWFLAGS = 11, + H_MS_TABMSG_SLQMGR = 12, + SERVICE_LAST = 13 + }; + + CGlobals() + { + ::ZeroMemory(this, sizeof(CGlobals)); + m_TypingSoundAdded = false; + } + + ~CGlobals() + { + if (m_MenuBar) + ::DestroyMenu(m_MenuBar); + + CContactCache* c = CContactCache::m_cCache, *cTemp; + while(c) { + cTemp = c->m_next; + delete c; + c = cTemp; + } + } + void reloadAdv(); + void reloadSystemStartup(); + void reloadSystemModulesChanged(); + void reloadSettings(bool fReloadSkins = true); + + void hookSystemEvents(); + bool haveAutoSwitch(); + + const HMENU getMenuBar(); + + HWND g_hwndHotkeyHandler; + HICON g_iconIn, g_iconOut, g_iconErr, g_iconContainer, g_iconStatus; + HICON g_iconOverlayDisabled, g_iconOverlayEnabled, g_iconClock; + HCURSOR hCurSplitNS, hCurSplitWE, hCurHyperlinkHand; + HBITMAP g_hbmUnknown; + int g_MetaContactsAvail, g_SmileyAddAvail, g_WantIEView, g_PopupAvail, g_PopupWAvail, g_WantHPP; + int g_FlashAvatarAvail; + HIMAGELIST g_hImageList; + HICON g_IconMsgEvent, g_IconTypingEvent, g_IconFileEvent, g_IconSend; + HICON g_IconMsgEventBig, g_IconTypingEventBig; + HICON g_IconFolder, g_IconChecked, g_IconUnchecked; + HMENU g_hMenuContext, g_hMenuContainer, g_hMenuEncoding, g_hMenuTrayUnread; + HMENU g_hMenuFavorites, g_hMenuRecent, g_hMenuTrayContext; + HICON g_buttonBarIcons[NR_BUTTONBARICONS]; + HICON g_sideBarIcons[NR_SIDEBARICONS]; + HANDLE g_buttonBarIconHandles[23]; + // dynamic options, need reload when options change + int m_SendOnShiftEnter; + int m_SendOnEnter; + int m_SendOnDblEnter; + int m_AutoLocaleSupport; + int m_AutoSwitchTabs; + int m_CutContactNameOnTabs; + int m_CutContactNameTo; + int m_StatusOnTabs; + int m_LogStatusChanges; + int m_UseDividers; + int m_DividersUsePopupConfig; + int m_MsgTimeout; + int m_EscapeCloses; + int m_FlashOnClist; + int m_AlwaysFullToolbarWidth; + int m_LimitStaticAvatarHeight; + int m_SendFormat; + int m_FormatWholeWordsOnly; + int m_RTLDefault; + int m_MathModAvail; + TCHAR m_MathModStartDelimiter[40]; + int m_UnreadInTray; + int m_TrayFlashes; + int m_TrayFlashState; + BOOL m_SuperQuiet; + HANDLE m_UserMenuItem; + double g_DPIscaleX; + double g_DPIscaleY; + BOOL m_HideOnClose; + BOOL g_bSoundOnTyping; + BOOL m_AllowTab; + BYTE m_AllowOfflineMultisend; + BOOL g_bDisableAniAvatars; + HBITMAP m_hbmMsgArea; + BYTE g_iButtonsBarGap; + BYTE m_WinVerMajor; + BYTE m_WinVerMinor; + bool m_bIsXP, m_bIsVista, m_bIsWin7; + HWND m_hwndClist; + int m_TabAppearance; + struct myTabCtrl tabConfig; + int m_panelHeight, m_MUCpanelHeight; + WINDOWPLACEMENT m_GlobalContainerWpos; + int m_IdleDetect; + int m_smcxicon, m_smcyicon; + int m_PasteAndSend; + TCHAR *m_szNoStatus; + COLORREF crIncoming, crOutgoing, crOldIncoming, crOldOutgoing, crStatus; + BOOL bUnicodeBuild; + HFONT hFontCaption; + DWORD m_LangPackCP; + BYTE m_SmileyButtonOverride; + NONCLIENTMETRICS m_ncm; + HICON m_AnimTrayIcons[4]; + BOOL m_visualMessageSizeIndicator; + BOOL m_autoSplit; + BOOL m_FlashOnMTN; + DWORD dwThreadID; + char szMetaName[256]; + BYTE bMetaEnabled; + HANDLE m_hMessageWindowList, hUserPrefsWindowList; + bool m_chat_enabled; + HMENU m_MenuBar; + COLORREF m_ipBackgroundGradient; + COLORREF m_ipBackgroundGradientHigh; + COLORREF m_tbBackgroundHigh, m_tbBackgroundLow, m_fillColor, m_cRichBorders, m_genericTxtColor; + BYTE g_bClientInStatusBar; + BYTE m_dontUseDefaultKbd; + HANDLE hSvc[SERVICE_LAST]; + HANDLE m_event_MsgWin, m_event_MsgPopup; + HANDLE m_hMenuItem; + BYTE m_useAeroPeek; + + TSplitterBroadCast lastSPlitterPos; + TContainerSettings globalContainerSettings; + + static HANDLE m_event_FoldersChanged; + static TCHAR* m_default_container_name; + static void cacheUpdateMetaChanged(); + static void logStatusChange(WPARAM wParam, const CContactCache *c); + + static void Ex_CopyEditToClipboard(HWND hWnd); + static void Ex_Handler(); + static int Ex_ShowDialog(EXCEPTION_POINTERS *ep, const char *szFile, int line, wchar_t* szReason, bool fAllowContinue); + static INT_PTR CALLBACK Ex_DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +private: + bool m_TypingSoundAdded; + static HANDLE m_event_ModulesLoaded, m_event_PrebuildMenu, m_event_SettingChanged; + static HANDLE m_event_ContactDeleted, m_event_Dispatch, m_event_EventAdded; + static HANDLE m_event_IconsChanged, m_event_TypingEvent, m_event_ProtoAck, m_event_PreShutdown, m_event_OkToExit; + static HANDLE m_event_IcoLibChanged, m_event_AvatarChanged, m_event_MyAvatarChanged, m_event_FontsChanged; + static HANDLE m_event_SmileyAdd, m_event_IEView; + static HANDLE m_event_ME_MC_SUBCONTACTSCHANGED, m_event_ME_MC_FORCESEND, m_event_ME_MC_UNFORCESEND; + + static EXCEPTION_RECORD m_exRecord; + static CONTEXT m_exCtx; + static LRESULT m_exLastResult; + static char m_exSzFile[MAX_PATH]; + static wchar_t m_exReason[256]; + static int m_exLine; + static bool m_exAllowContinue; +private: + static int ModulesLoaded(WPARAM wParam, LPARAM lParam); + static int DBSettingChanged(WPARAM wParam, LPARAM lParam); + static int DBContactDeleted(WPARAM wParam, LPARAM lParam); + static int PreshutdownSendRecv(WPARAM wParam, LPARAM lParam); + static int MetaContactEvent(WPARAM wParam, LPARAM lParam); + static int OkToExit(WPARAM wParam, LPARAM lParam); + static void RestoreUnreadMessageAlerts(void); +}; + +extern CGlobals PluginConfig; +extern CGlobals *pConfig; + +#define DPISCALEY_S(argY) ((int) ((double)(argY) * PluginConfig.g_DPIscaleY)) +#define DPISCALEX_S(argX) ((int) ((double)(argX) * PluginConfig.g_DPIscaleX)) + +#endif /* __GLOBALS_H */ diff --git a/plugins/TabSRMM/src/include/infopanel.h b/plugins/TabSRMM/src/include/infopanel.h new file mode 100644 index 0000000000..3a2812444e --- /dev/null +++ b/plugins/TabSRMM/src/include/infopanel.h @@ -0,0 +1,220 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: infopanel.h 12396 2010-08-22 17:17:05Z silvercircle $ + * + * the info area for both im and chat sessions + */ + +#ifndef __INFOPANEL_H +#define __INFOPANEL_H + +/* + * configuration data for the info panel (fonts, colors) + * this is global for all panels + */ + +#define IPFONTCOUNT 6 // # of fonts needed for the info panel + +/* + * command ids for the info panel contextual menus + */ + +#define CMD_IP_USERDETAILS 20000 +#define CMD_IP_USERPREFS 20001 +#define CMD_IP_ROOMPREFS 20002 +#define CMD_IP_HISTORY 20003 +#define CMD_IP_COPY 21000 + +struct TInfoPanelConfig { + HFONT hFonts[IPFONTCOUNT]; + COLORREF clrs[IPFONTCOUNT]; + UINT height1, height2; +}; + +extern TCHAR *xStatusDescr[]; + +/** + * a simple tooltip class using a richedit control to display its content. Allows + * for formatted text and clickable hyperlinks + * + * Used by: Info panel to display status messages, topics etc. + */ +class CTip +{ +public: + enum { + TOP_BORDER = 25, + LEFT_BORDER = 2, + RIGHT_BORDER = 2, + BOTTOM_BORDER = 1, + LEFT_BAR_WIDTH = 20 + }; + + CTip (const HWND hwndParent, const HANDLE hContact, const TCHAR *pszText = 0, const CInfoPanel *panel = 0); + ~CTip() + { + if (m_pszText) + mir_free(m_pszText); + } + void show (const RECT& rc, POINT& pt, const HICON hIcon = 0, const TCHAR *szTitle = 0); + const HWND getHwnd () const { return(m_hwnd); } + + static void registerClass (); +private: + + INT_PTR CALLBACK WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK WndProcStub (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK RichEditProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + HWND m_hwnd; // our window handle + HWND m_hRich; // handle of the rich edit child + HWND m_hwndParent; // parent window (used for position calculations and to send notifications) + HANDLE m_hContact; // contact handle + char* m_pszText; // the richedit text + SIZE m_szRich; // size of the richedit control (height auto-calculated to make it fit the text) + RECT m_rcRich; // adjusted rectangle for the richedit control (client coordinates) + const CInfoPanel* m_panel; // the info panel parent (if any) + HICON m_hIcon; // optional icon to show in the title line + const TCHAR* m_szTitle; // optional text to show in the title + int m_leftWidth; + +private: + static WNDPROC m_OldMessageEditProc; // stores original richedit wnd proc + +}; + +/** + * the info panel class definition. The panel itself is not a real window class - it + * is implemented as a drawing canvas on the message window background. + * + * Each message session has its own info panel object + */ +class CInfoPanel +{ +public: + enum { + DEGRADE_THRESHOLD = 37, // defines the height at which the infopanel will do the transition from 1 to 2 lines + LEFT_OFFSET_LOGO = 3 + }; + enum { + HOVER_NICK = 1, + HOVER_STATUS = 2, + HOVER_UIN = 4 + }; + enum { + HTNICK = 1, + HTUIN = 2, + HTSTATUS = 3, + HTNIRVANA = 0 + }; + CInfoPanel(TWindowData *dat) + { + if (dat) { + m_dat = dat; + m_isChat = dat->bType == SESSIONTYPE_CHAT ? true : false; + } + m_defaultHeight = PluginConfig.m_panelHeight; + m_defaultMUCHeight = PluginConfig.m_MUCpanelHeight; + m_hwndConfig = 0; + m_hoverFlags = 0; + m_tip = 0; + } + + ~CInfoPanel() + { + if (m_hwndConfig) + ::DestroyWindow(m_hwndConfig); + saveHeight(true); + } + + const LONG getHeight () const { return(m_height); } + void setHeight (LONG newHeight, bool fBroadcast = false); + bool isActive () const { return(m_active); } + bool isPrivateHeight () const { return(m_fPrivateHeight); } + DWORD isHovered () const { return(m_active ? m_hoverFlags : 0); } + const TWindowData* getDat () const { return(m_dat); } + void setActive (const int newActive); + void loadHeight (); + void saveHeight (bool fFlush = false); + + void Configure () const; + void showHide () const; + bool getVisibility (); + void renderBG (const HDC hdc, RECT& rc, CSkinItem *item, bool fAero, bool fAutoCalc = true) const; + void renderContent (const HDC hdcMem); + void Invalidate (BOOL fErase = FALSE) const; + void trackMouse (POINT& pt); + int hitTest (POINT pt); + void handleClick (const POINT& pt); + void showTip (UINT ctrlId, const LPARAM lParam); + void hideTip (const HWND hWndNew); + int invokeConfigDialog (const POINT& pt); + void dismissConfig (bool fForced = false); + +public: + static TInfoPanelConfig m_ipConfig; + static int setPanelHandler (TWindowData *dat, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK avatarParentSubclass (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +private: + void mapRealRect (const RECT& rcSrc, RECT& rcDest, const SIZE& sz); + HFONT setUnderlinedFont (const HDC hdc, HFONT hFontOrig); + void RenderIPNickname (const HDC hdc, RECT& rc); + void RenderIPUIN (const HDC hdc, RECT& rcItem); + void RenderIPStatus (const HDC hdc, RECT& rcItem); + void Chat_RenderIPNickname (const HDC hdc, RECT& rcItem); + void Chat_RenderIPSecondLine (const HDC hdc, RECT& rcItem); + LRESULT cmdHandler (UINT cmd); + HMENU constructContextualMenu () const; + INT_PTR CALLBACK ConfigDlgProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK ConfigDlgProcStub (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +private: + bool m_isChat; // is MUC session + bool m_active; // panel active and visible + bool m_fPrivateHeight; + bool m_fDialogCreated; + TWindowData* m_dat; // this one OWNS us... + LONG m_height; // height (determined by position of IDC_PANELSPLITTER) + LONG m_defaultHeight, m_defaultMUCHeight; // global values for the info bar height + HWND m_hwndConfig; // window handle of the config dialog window + HFONT m_configDlgFont, m_configDlgBoldFont; + SIZE m_szNick; // rectangle where the nick has been rendered, + /* + * these are used to store rectangles important to mouse tracking. + */ + RECT m_rcNick; + RECT m_rcUIN; + RECT m_rcStatus; + DWORD m_hoverFlags; + CTip* m_tip; +}; + +#endif /* __INFOPANEL_H */ + diff --git a/plugins/TabSRMM/src/include/m_cln_skinedit.h b/plugins/TabSRMM/src/include/m_cln_skinedit.h new file mode 100644 index 0000000000..5ee66829c5 --- /dev/null +++ b/plugins/TabSRMM/src/include/m_cln_skinedit.h @@ -0,0 +1,147 @@ + +/* + * services + */ + +#define MS_CLNSE_INVOKE "CLN_Skinedit/Invoke" +#define MS_CLNSE_FILLBYCURRENTSEL "CLN_Skinedit/FillByCurrentSel" + +/* + * data structs + */ + +struct TWindowData; +class CImageItem; + +struct ButtonItem { + TCHAR szName[40]; + HWND hWnd; + LONG xOff, yOff; + LONG width, height; + CImageItem *imgNormal, *imgPressed, *imgHover; + LONG_PTR normalGlyphMetrics[4]; + LONG_PTR hoverGlyphMetrics[4]; + LONG_PTR pressedGlyphMetrics[4]; + DWORD dwFlags, dwStockFlags; + DWORD uId; + TCHAR szTip[256]; + char szService[256]; + char szModule[256], szSetting[256]; + BYTE bValuePush[256], bValueRelease[256]; + DWORD type; + void (*pfnAction)(ButtonItem *item, HWND hwndDlg, TWindowData *dat, HWND hwndItem); + void (*pfnCallback)(ButtonItem *item, HWND hwndDlg, TWindowData *dat, HWND hwndItem); + TCHAR tszLabel[40]; + ButtonItem* nextItem; + HANDLE hContact; + TWindowData *dat; +}; + +typedef struct _tagButtonSet { + ButtonItem *items; + LONG left, top, right, bottom; // client area offsets, calculated from button layout +} ButtonSet; + +struct CSkinItem { + TCHAR szName[40]; + char szDBname[40]; + int statusID; + + BYTE GRADIENT; + BYTE CORNER; + + DWORD COLOR; + DWORD COLOR2; + + BYTE COLOR2_TRANSPARENT; + + DWORD TEXTCOLOR; + + int ALPHA; + + int MARGIN_LEFT; + int MARGIN_TOP; + int MARGIN_RIGHT; + int MARGIN_BOTTOM; + BYTE IGNORED; + DWORD BORDERSTYLE; + CImageItem *imageItem; +}; + +typedef struct _tagSkinDescription { + DWORD cbSize; + CSkinItem *StatusItems; + int lastItem; + int firstItem; + char szModule[100]; + HWND hWndParent, hWndTab; + HWND hwndCLUI; + HWND hwndSkinEdit; /* out param */ + HWND hwndImageEdit; /* out param */ + HMENU hMenuItems; + void (*pfnSaveCompleteStruct)(void); + void (*pfnClcOptionsChanged )(void); + void* (*pfnMalloc)(unsigned int); + void (*pfnFree)(void); + void* (*pfnRealloc)(void *, unsigned int); + void* reserved[20]; +} SKINDESCRIPTION; + +// defines + +// FLAGS +#define CORNER_NONE 0 +#define CORNER_ACTIVE 1 +#define CORNER_TL 2 +#define CORNER_TR 4 +#define CORNER_BR 8 +#define CORNER_BL 16 +#define CORNER_ALL (CORNER_TL | CORNER_TR | CORNER_BR | CORNER_BL | CORNER_ACTIVE) + +#define GRADIENT_NONE 0 +#define GRADIENT_ACTIVE 1 +#define GRADIENT_LR 2 +#define GRADIENT_RL 4 +#define GRADIENT_TB 8 +#define GRADIENT_BT 16 + +#define IMAGE_PERPIXEL_ALPHA 1 +#define IMAGE_FLAG_DIVIDED 2 +#define IMAGE_FILLSOLID 4 +#define IMAGE_GLYPH 8 + +#define IMAGE_STRETCH_V 1 +#define IMAGE_STRETCH_H 2 +#define IMAGE_STRETCH_B 4 + +#define BUTTON_ISINTERNAL 1 +#define BUTTON_ISTOGGLE 2 +#define BUTTON_ISSERVICE 4 +#define BUTTON_ISPROTOSERVICE 8 +#define BUTTON_PASSHCONTACTW 16 +#define BUTTON_PASSHCONTACTL 32 +#define BUTTON_ISDBACTION 64 +#define BUTTON_ISCONTACTDBACTION 128 +#define BUTTON_DBACTIONONCONTACT 256 +#define BUTTON_ISSIDEBAR 512 +#define BUTTON_NORMALGLYPHISICON 1024 +#define BUTTON_PRESSEDGLYPHISICON 2048 +#define BUTTON_HOVERGLYPHISICON 4096 +#define BUTTON_HASLABEL 8192 + +#define CLCDEFAULT_GRADIENT 0 +#define CLCDEFAULT_CORNER 0 + +#define CLCDEFAULT_COLOR 0xd0d0d0 +#define CLCDEFAULT_COLOR2 0xd0d0d0 + +#define CLCDEFAULT_TEXTCOLOR 0x000000 + +#define CLCDEFAULT_COLOR2_TRANSPARENT 1 + +#define CLCDEFAULT_ALPHA 100 +#define CLCDEFAULT_MRGN_LEFT 0 +#define CLCDEFAULT_MRGN_TOP 0 +#define CLCDEFAULT_MRGN_RIGHT 0 +#define CLCDEFAULT_MRGN_BOTTOM 0 +#define CLCDEFAULT_IGNORE 1 diff --git a/plugins/TabSRMM/src/include/mim.h b/plugins/TabSRMM/src/include/mim.h new file mode 100644 index 0000000000..c971cb7fdf --- /dev/null +++ b/plugins/TabSRMM/src/include/mim.h @@ -0,0 +1,301 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: mim.h 12272 2010-08-04 08:24:08Z silvercircle $ + * + * wraps some parts of Miranda API + * Also, OS dependent stuff (visual styles api etc.) + * + */ + +#ifndef __MIM_H +#define __MIM_H + + +extern FI_INTERFACE *FIF; + +/* + * Win32 API definitions of functions dynamically obtained via GetProcAddress() + * - uxtheme + * - dwmapi + * - some GDI functions (AlphaBlend()..) + */ +typedef BOOL (WINAPI *SMI)( HMENU hmenu, LPCMENUINFO lpcmi ); +typedef HRESULT (WINAPI *DEFICA)(HWND hwnd, const MARGINS *margins); +typedef HRESULT (WINAPI *DICE)(BOOL *); +typedef DWORD (WINAPI *PSLWA)(HWND, DWORD, BYTE, DWORD); +typedef BOOL (WINAPI *PULW)(HWND, HDC, POINT *, SIZE *, HDC, POINT *, COLORREF, BLENDFUNCTION *, DWORD); +typedef BOOL (WINAPI *PFWEX)(FLASHWINFO *); +typedef BOOL (WINAPI *PAB)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION); +typedef BOOL (WINAPI *PGF)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); + +typedef BOOL (WINAPI *PITA)(); +typedef HANDLE (WINAPI *POTD)(HWND, LPCWSTR); +typedef UINT (WINAPI *PDTB)(HANDLE, HDC, int, int, RECT *, RECT *); +typedef UINT (WINAPI *PCTD)(HANDLE); +typedef UINT (WINAPI *PDTT)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, DWORD, RECT *); +typedef UINT (WINAPI *PDTTE)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, RECT *, const DTTOPTS *); +typedef BOOL (WINAPI *PITBPT)(HANDLE, int, int); +typedef HRESULT (WINAPI *PDTPB)(HWND, HDC, RECT *); +typedef HRESULT (WINAPI *PGTBCR)(HANDLE, HDC, int, int, const RECT *, const RECT *); + +typedef HMONITOR(WINAPI *MMFW)(HWND, DWORD); +typedef BOOL (WINAPI *GMIA)(HMONITOR, LPMONITORINFO); +typedef HRESULT (WINAPI *DRT)(HWND, HWND, PHTHUMBNAIL); +typedef BOOL (WINAPI *ETDT)(HANDLE, DWORD); +typedef HANDLE (WINAPI *BBP)(HDC, RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *); +typedef HRESULT (WINAPI *EBP)(HANDLE, BOOL); +typedef HRESULT (WINAPI *BPI)(void); +typedef HRESULT (WINAPI *BPU)(void); +typedef HRESULT (WINAPI *BBW)(HWND, DWM_BLURBEHIND *); +typedef HRESULT (WINAPI *DGC)(DWORD *, BOOL *); +typedef HRESULT (WINAPI *BPSA)(HANDLE, const RECT *, BYTE); +typedef int (WINAPI *GLIX)(LPCWSTR, LCTYPE, LPCWSTR, int); +typedef HRESULT (WINAPI *DWMSWA)(HWND, DWORD, LPCVOID, DWORD); +typedef HRESULT (WINAPI *DWMIIB)(HWND); +typedef HRESULT (WINAPI *DWMUT)(HTHUMBNAIL, DWM_THUMBNAIL_PROPERTIES *); +typedef HRESULT (WINAPI *DURT)(HTHUMBNAIL); +typedef HRESULT (WINAPI *DSIT)(HWND, HBITMAP, DWORD); +typedef HRESULT (WINAPI *DSILP)(HWND, HBITMAP, POINT *, DWORD); + +/* + * used to encapsulate some parts of the Miranda API + * constructor does early time initialization - do NOT put anything + * here, except thngs that deal with the core and database API. + * + * it is UNSAFE to assume that any plugin provided services are available + * when the object is instantiated. + */ + +class CMimAPI +{ +public: + CMimAPI() + { + InitPaths(); + InitAPI(); + getAeroState(); + + LRESULT fi_version = CallService(MS_IMG_GETIFVERSION, 0, 0); + CallService(MS_IMG_GETINTERFACE, fi_version, (LPARAM)&FIF); + + ::QueryPerformanceFrequency((LARGE_INTEGER *)&m_tFreq); + m_dFreq = (double)(1.0f / m_tFreq); + m_hChatLogLock = INVALID_HANDLE_VALUE; + } + + ~CMimAPI() { + if (m_haveBufferedPaint) + m_pfnBufferedPaintUninit(); + if (m_hUxTheme != 0) + FreeLibrary(m_hUxTheme); + if (m_hDwmApi != 0) + FreeLibrary(m_hDwmApi); + + if (m_hChatLogLock != INVALID_HANDLE_VALUE) + CloseHandle(m_hChatLogLock); + } + + /* + * database functions + */ + + DWORD FASTCALL GetDword (const HANDLE hContact, const char *szModule, const char *szSetting, DWORD uDefault) const; + + DWORD FASTCALL GetDword (const char *szModule, const char *szSetting, DWORD uDefault) const; + DWORD FASTCALL GetDword (const char *szSetting, DWORD uDefault) const; + DWORD FASTCALL GetDword (const HANDLE hContact, const char *szSetting, DWORD uDefault) const; + + int FASTCALL GetByte (const HANDLE hContact, const char *szModule, const char *szSetting, int uDefault) const; + int FASTCALL GetByte (const char *szModule, const char *szSetting, int uDefault) const; + int FASTCALL GetByte (const char *szSetting, int uDefault) const; + int FASTCALL GetByte (const HANDLE hContact, const char *szSetting, int uDefault) const; + + INT_PTR FASTCALL GetTString (const HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) const; + INT_PTR FASTCALL GetString (const HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) const; + + INT_PTR FASTCALL WriteDword (const HANDLE hContact, const char *szModule, const char *szSetting, DWORD value) const; + INT_PTR FASTCALL WriteDword (const char *szModule, const char *szSetting, DWORD value) const; + + INT_PTR FASTCALL WriteByte (const HANDLE hContact, const char *szModule, const char *szSetting, BYTE value) const; + INT_PTR FASTCALL WriteByte (const char *szModule, const char *szSetting, BYTE value) const; + + INT_PTR FASTCALL WriteTString (const HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *st) const; + + /* + * path utilities + */ + + int pathIsAbsolute (const TCHAR *path) const; + size_t pathToAbsolute (const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase = 0) const; + size_t pathToRelative (const TCHAR *pSrc, TCHAR *pOut, const TCHAR *szBase = 0) const; + + const TCHAR* getDataPath() const { return(m_szProfilePath); } + const TCHAR* getSkinPath() const { return(m_szSkinsPath); } + const TCHAR* getSavedAvatarPath() const { return(m_szSavedAvatarsPath); } + const TCHAR* getChatLogPath() const { return(m_szChatLogsPath); } + const bool haveFoldersPlugin() const { return(m_haveFolders); } + + const TCHAR* getUserDir(); + void configureCustomFolders(); + INT_PTR foldersPathChanged(); + + void startTimer(); + void stopTimer (const char *szMsg = 0); + void timerMsg (const char *szMsg); + __int64 getTimerStart() const { return(m_tStart); } + __int64 getTimerStop() const { return(m_tStop); } + __int64 getTicks() const { return(m_tStop - m_tStart); } + double getFreq() const { return(m_dFreq); } + double getMsec() const { return(1000 * ((double)(m_tStop - m_tStart) * m_dFreq)); } + + /* + * os dependant stuff (aero, visual styles etc.) + */ + + const bool isVSAPIState() const { return m_VsAPI; } + /** + * return status of Vista Aero + * + * @return bool: true if aero active, false otherwise + */ + const bool isAero() const { return(m_isAero); } + const bool isDwmActive() const { return(m_DwmActive); } + + /** + * Refresh Aero status. + * Called on: + * * plugin init + * * WM_DWMCOMPOSITIONCHANGED message received + * + * @return + */ + bool getAeroState(); + /** + * return status of visual styles theming engine (Windows XP+) + * + * @return bool: themes are enabled + */ + bool isVSThemed() + { + return(m_isVsThemed); + } + /* + * window lists + */ + + void BroadcastMessage (UINT msg, WPARAM wParam, LPARAM lParam); + void BroadcastMessageAsync (UINT msg, WPARAM wParam, LPARAM lParam); + INT_PTR AddWindow (HWND hWnd, HANDLE h); + INT_PTR RemoveWindow (HWND hWnd); + HWND FindWindow (HANDLE h) const; + + static int FoldersPathChanged(WPARAM wParam, LPARAM lParam); // hook subscriber for folders plugin + static const TCHAR* TSAPI StriStr(const TCHAR *szString, const TCHAR *szSearchFor); + static int TypingMessage(WPARAM wParam, LPARAM lParam); + static int ProtoAck(WPARAM wParam, LPARAM lParam); + static int PrebuildContactMenu(WPARAM wParam, LPARAM lParam); + static int DispatchNewEvent(WPARAM wParam, LPARAM lParam); + static int MessageEventAdded(WPARAM wParam, LPARAM lParam); +public: + HANDLE m_hMessageWindowList; + /* + various function pointers + */ + static PITA m_pfnIsThemeActive; + static POTD m_pfnOpenThemeData; + static PDTB m_pfnDrawThemeBackground; + static PCTD m_pfnCloseThemeData; + static PDTT m_pfnDrawThemeText; + static PDTTE m_pfnDrawThemeTextEx; + static PITBPT m_pfnIsThemeBackgroundPartiallyTransparent; + static PDTPB m_pfnDrawThemeParentBackground; + static PGTBCR m_pfnGetThemeBackgroundContentRect; + static ETDT m_pfnEnableThemeDialogTexture; + static PSLWA m_pSetLayeredWindowAttributes; + static PFWEX m_MyFlashWindowEx; + static PAB m_MyAlphaBlend; + static PGF m_MyGradientFill; + static DEFICA m_pfnDwmExtendFrameIntoClientArea; + static DICE m_pfnDwmIsCompositionEnabled; + static MMFW m_pfnMonitorFromWindow; + static GMIA m_pfnGetMonitorInfoA; + static DRT m_pfnDwmRegisterThumbnail; + static BPI m_pfnBufferedPaintInit; + static BPU m_pfnBufferedPaintUninit; + static BBP m_pfnBeginBufferedPaint; + static EBP m_pfnEndBufferedPaint; + static BBW m_pfnDwmBlurBehindWindow; + static DGC m_pfnDwmGetColorizationColor; + static BPSA m_pfnBufferedPaintSetAlpha; + static GLIX m_pfnGetLocaleInfoEx; + static DWMSWA m_pfnDwmSetWindowAttribute; + static DWMIIB m_pfnDwmInvalidateIconicBitmaps; + static DWMUT m_pfnDwmUpdateThumbnailProperties; + static DURT m_pfnDwmUnregisterThumbnail; + static DSIT m_pfnDwmSetIconicThumbnail; + static DSILP m_pfnDwmSetIconicLivePreviewBitmap; + static bool m_shutDown, m_haveBufferedPaint; + +private: + TCHAR m_szProfilePath[MAX_PATH + 2], m_szSkinsPath[MAX_PATH + 2], m_szSavedAvatarsPath[MAX_PATH + 2], m_szChatLogsPath[MAX_PATH + 2]; + HMODULE m_hUxTheme, m_hDwmApi; + bool m_VsAPI; + bool m_isAero; + bool m_DwmActive; + bool m_isVsThemed; + HANDLE m_hDataPath, m_hSkinsPath, m_hAvatarsPath, m_hChatLogsPath; + __int64 m_tStart, m_tStop, m_tFreq; + double m_dFreq; + char m_timerMsg[256]; + bool m_haveFolders; + HANDLE m_hChatLogLock; + + void InitAPI(); + void InitPaths(); + +private: + static TCHAR m_userDir[MAX_PATH + 2]; +}; + +inline void CMimAPI::startTimer() +{ + ::QueryPerformanceCounter((LARGE_INTEGER *)&m_tStart); +} + +inline void CMimAPI::stopTimer(const char *szMsg) +{ + ::QueryPerformanceCounter((LARGE_INTEGER *)&m_tStop); + + if (szMsg) + timerMsg(szMsg); +} + +extern CMimAPI *M; + +#endif /* __MIM_H */ diff --git a/plugins/TabSRMM/src/include/msgdlgutils.h b/plugins/TabSRMM/src/include/msgdlgutils.h new file mode 100644 index 0000000000..59e349f07c --- /dev/null +++ b/plugins/TabSRMM/src/include/msgdlgutils.h @@ -0,0 +1,103 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: msgdlgutils.h 12833 2010-09-27 23:45:55Z silvercircle $ + * + * + */ + +#ifndef _MSGDLGUTILS_H +#define _MSGDLGUTILS_H + +#define WANT_IEVIEW_LOG 1 +#define WANT_HPP_LOG 2 + +void TSAPI CalcDynamicAvatarSize (TWindowData *dat, BITMAP *bminfo); +char* TSAPI GetCurrentMetaContactProto (TWindowData *dat); +void TSAPI WriteStatsOnClose (TWindowData *dat); +int TSAPI MsgWindowUpdateMenu (TWindowData *dat, HMENU submenu, int menuID); +int TSAPI MsgWindowMenuHandler (TWindowData *dat, int selection, int menuId); +int TSAPI GetAvatarVisibility (HWND hwndDlg, TWindowData *dat); +void TSAPI UpdateStatusBar (const TWindowData *dat); +int TSAPI CheckValidSmileyPack (const char *szProto, HANDLE hContact); +TCHAR* TSAPI QuoteText (const TCHAR *text, int charsPerLine, int removeExistingQuotes); +void TSAPI UpdateReadChars (const TWindowData *dat); +void TSAPI ShowPicture (TWindowData *dat, BOOL showNewPic); +void TSAPI AdjustBottomAvatarDisplay (TWindowData *dat); +void TSAPI SetDialogToType (HWND hwndDlg); +void TSAPI FlashOnClist (HWND hwndDlg, TWindowData *dat, HANDLE hEvent, DBEVENTINFO *dbei); +char* TSAPI Message_GetFromStream (HWND hwndDlg, const TWindowData* dat, DWORD dwPassedFlags); +BOOL TSAPI DoRtfToTags (TCHAR * pszText, const TWindowData *dat); +void TSAPI DoTrimMessage (TCHAR *msg); +void TSAPI GetMYUIN (TWindowData *dat); +void TSAPI SetMessageLog (TWindowData *dat); +void TSAPI SwitchMessageLog (TWindowData *dat, int iMode); +UINT TSAPI GetIEViewMode (HWND hwndDlg, HANDLE hContact); +void TSAPI FindFirstEvent (TWindowData *dat); +void TSAPI SaveSplitter (TWindowData *dat); +void TSAPI LoadSplitter (TWindowData *dat); +void TSAPI PlayIncomingSound (const TWindowData *dat); +void TSAPI GetSendFormat (TWindowData *dat, int mode); +void TSAPI GetLocaleID (TWindowData *dat, const TCHAR *szKLName); +void TSAPI LoadOwnAvatar (TWindowData *dat); +void TSAPI LoadContactAvatar (TWindowData *dat); +void TSAPI LoadTimeZone (TWindowData *dat); +void TSAPI HandlePasteAndSend (const TWindowData *dat); +int TSAPI MsgWindowDrawHandler (WPARAM wParam, LPARAM lParam, TWindowData *dat); +void TSAPI LoadOverrideTheme (TContainerData *pContainer); +void TSAPI LoadThemeDefaults (TContainerData *pContainer); +void TSAPI ConfigureSmileyButton (TWindowData *dat); +int TSAPI CutContactName (const TCHAR *szold, TCHAR *sznew, unsigned int size); +void TSAPI SendNudge (const TWindowData *dat); +void TSAPI EnableSendButton (const TWindowData *dat, int iMode); +LRESULT TSAPI GetSendButtonState (HWND hwnd); +HICON TSAPI GetXStatusIcon (const TWindowData *dat); +void TSAPI FlashTab (TWindowData *dat, HWND hwndTab, int iTabindex, BOOL *bState, BOOL mode, HICON origImage); +void TSAPI GetClientIcon (TWindowData *dat); +void TSAPI RearrangeTab (HWND hwndDlg, const TWindowData *dat, int iMode, BOOL fSavePos); +void TSAPI GetCachedStatusMsg (TWindowData *dat); +BOOL TSAPI IsStatusEvent (int eventType); +void TSAPI GetMyNick (TWindowData *dat); +HICON TSAPI MY_GetContactIcon (const TWindowData *dat); +void TSAPI CheckAndDestroyIEView (TWindowData *dat); +void TSAPI KbdState (TWindowData *dat, BOOL& isShift, BOOL& isControl, BOOL& isAlt); +void TSAPI ClearLog (TWindowData *dat); +bool TSAPI IsAutoSplitEnabled (const TWindowData* dat); +LONG TSAPI GetDefaultMinimumInputHeight (const TWindowData* dat); +void TSAPI DetermineMinHeight (TWindowData* dat); +// mathmod + +void TSAPI MTH_updateMathWindow (const TWindowData *dat); + +void TSAPI CleanTempFiles (); +void TSAPI SendHBitmapAsFile (const TWindowData* dat, HBITMAP hbmp); + +extern INT_PTR CALLBACK SelectContainerDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +extern INT_PTR CALLBACK DlgProcContainerOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + +#endif diff --git a/plugins/TabSRMM/src/include/msgs.h b/plugins/TabSRMM/src/include/msgs.h new file mode 100644 index 0000000000..5f4adef350 --- /dev/null +++ b/plugins/TabSRMM/src/include/msgs.h @@ -0,0 +1,1062 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: msgs.h 13587 2011-04-12 13:54:26Z george.hazan $ + * + * + */ + +#ifndef _MSGS_H +#define _MSGS_H + +#ifdef _MSC_VER +#if _MSC_VER < 1400 +#define uintptr_t UINT_PTR +#define _localtime32 localtime +#define __time32_t time_t +#endif +#endif +/* + * required for MingW32 compatibility + */ + +#define CF_TEXTT CF_UNICODETEXT + +#include +#include +#include "m_avatars.h" +#include "m_message.h" + +#define MSGERROR_CANCEL 0 +#define MSGERROR_RETRY 1 +#define MSGERROR_SENDLATER 2 + +#define CONTAINER_NAMELEN 25 +#define TITLE_FORMATLEN 30 + +#define MWF_SAVEBTN_SAV 2 + +#define MWF_DEFERREDSCROLL 4 +#define MWF_NEEDHISTORYSAVE 8 +#define MWF_WASBACKGROUNDCREATE 16 +//#define MWF_MOUSEDOWN 32 +#define MWF_ERRORSTATE 128 +#define MWF_DEFERREDREMAKELOG 256 + +#define MWF_LOG_NORMALTEMPLATES 512 +#define MWF_LOG_SHOWTIME 1024 +#define MWF_LOG_SHOWSECONDS 2048 +#define MWF_LOG_SHOWDATES 4096 + +#define MWF_LOG_INDENT 16384 +#define MWF_LOG_RTL 32768 + +//MAD: ieview still mistakenly uses these... +#define MWF_LOG_NEWLINE 8192 +#define MWF_LOG_UNDERLINE 65536 +#define MWF_LOG_SWAPNICK 131072 +// +//#define MWF_LOG_BBCODE 65536 +//#define MWF_LOG_STATUSCHANGES 131072 +//#define MWF_LOG_LOCALTIME 8192 +#define MWF_LOG_BBCODE 1 +#define MWF_LOG_STATUSCHANGES 32 +#define MWF_LOG_LOCALTIME 64 + +#define MWF_LOG_SHOWICONS 262144 +#define MWF_LOG_SYMBOLS 0x200000 +#define MWF_INITMODE 0x400000 +#define MWF_NEEDCHECKSIZE 0x800000 +#define MWF_DIVIDERSET 0x1000000 +#define MWF_LOG_TEXTFORMAT 0x2000000 +#define MWF_LOG_GRID 0x4000000 +// #define MWF_LOG_INDIVIDUALBKG 0x8000000 * FREE * +#define MWF_LOG_INOUTICONS 0x10000000 +#define MWF_SMBUTTONSELECTED 0x20000000 +#define MWF_DIVIDERWANTED 0x40000000 +#define MWF_LOG_GROUPMODE 0x80000000 + +#define MWF_SHOW_URLEVENTS 1 +#define MWF_SHOW_FILEEVENTS 2 +//#define MWF_SHOW_PRIVATETHEME 4 +//#define MWF_SHOW_EMPTYLINEFIX 8 +//#define MWF_SHOW_MICROLF 16 +//#define MWF_SHOW_MARKFOLLOWUPTS 32 +#define MWF_SHOW_FLASHCLIST 64 +#define MWF_SHOW_SPLITTEROVERRIDE 128 +#define MWF_SHOW_SCROLLINGDISABLED 256 +//#define MWF_SHOW_INFONOTES ** FREE ** +#define MWF_SHOW_ISIDLE 4096 +#define MWF_SHOW_AWAYMSGTIMER 8192 +#define MWF_EX_DELAYEDSPLITTER 32768 +#define MWF_EX_AVATARCHANGED 65536 +#define MWF_EX_WARNCLOSE 0x20000 + +#define SMODE_DEFAULT 0 +#define SMODE_MULTIPLE 1 +#define SMODE_CONTAINER 2 +#define SMODE_FORCEANSI 4 +#define SMODE_SENDLATER 8 +#define SMODE_NOACK 16 + +#define SENDFORMAT_BBCODE 1 +#define SENDFORMAT_NONE 0 + +#define AVATARMODE_DYNAMIC 0 + +#define MSGDLGFONTCOUNT 22 +#define CHATFONTCOUNT 19 + +#define TMPL_MSGIN 0 +#define TMPL_MSGOUT 1 +#define TMPL_GRPSTARTIN 2 +#define TMPL_GRPSTARTOUT 3 +#define TMPL_GRPINNERIN 4 +#define TMPL_GRPINNEROUT 5 +#define TMPL_STATUSCHG 6 +#define TMPL_ERRMSG 7 + +#define TEMPLATE_LENGTH 150 +#define CUSTOM_COLORS 5 + +struct TTemplateSet { + BOOL valid; // all templates populated (may still contain crap.. so it's only half-assed safety :) + TCHAR szTemplates[TMPL_ERRMSG + 1][TEMPLATE_LENGTH]; // the template strings + char szSetName[20]; // everything in this world needs a name. so does this poor template set. +}; + +struct TitleBtn { + BOOL isHot; + BOOL isPressed; +}; + +#define BTN_MIN 0 +#define BTN_MAX 1 +#define BTN_CLOSE 2 + +#define NR_LOGICONS 8 +#define NR_BUTTONBARICONS 37//MaD: 29 +#define NR_SIDEBARICONS 2 + +class CTaskbarInteract; +class CMenuBar; +class CInfoPanel; +class CSideBar; +class CContactCache; +class CProxyWindow; + +#define STICK_ICON_MSG 10 +struct TLogTheme { + COLORREF inbg, outbg, bg, oldinbg, oldoutbg, statbg, inputbg; + COLORREF hgrid; + COLORREF custom_colors[5]; + DWORD dwFlags; + DWORD left_indent, right_indent; + LOGFONTA* logFonts; + COLORREF* fontColors; + char* rtfFonts; + bool isPrivate; +}; + +struct TContainerSettings { + bool fPrivate; + DWORD dwFlags; + DWORD dwFlagsEx; + DWORD dwTransparency; + DWORD panelheight; + DWORD splitterPos; + TCHAR szTitleFormat[TITLE_FORMATLEN + 2]; + WORD avatarMode; + WORD ownAvatarMode; + WORD autoCloseSeconds; + BYTE reserved[10]; +}; + +struct TContainerData { + TContainerData *pNextContainer; + TCHAR szName[CONTAINER_NAMELEN + 4]; // container name + HWND hwndActive; // active message window + HWND hwnd; // the container handle + int iTabIndex; // next tab id + int iChilds; + int iContainerIndex; + bool fHidden; + HMENU hMenuContext; + HWND hwndTip; // tab - tooltips... + BOOL bDontSmartClose; // if set, do not search and select the next possible tab after closing one. + DWORD dwFlags; + DWORD dwFlagsEx; + LONG uChildMinHeight; + int tBorder; + int tBorder_outer_left, tBorder_outer_right, tBorder_outer_top, tBorder_outer_bottom; + HANDLE hContactFrom; + BOOL isCloned; + HWND hwndStatus; + int statusBarHeight; + DWORD dwLastActivity; + int hIcon; // current window icon stick indicator + HICON hIconTaskbarOverlay; // contains a "sticky" taskbar overlay (e.g. new message icon) + DWORD dwFlashingStarted; + HWND hWndOptions; + BOOL bSizingLoop; + TCHAR szRelThemeFile[MAX_PATH], szAbsThemeFile[MAX_PATH]; + TTemplateSet *ltr_templates, *rtl_templates; + HDC cachedDC; + HBITMAP cachedHBM, oldHBM; + SIZE oldDCSize; + RECT rcClose, rcMin, rcMax; + struct TitleBtn buttons[3]; + struct TitleBtn oldbuttons[3]; + int ncActive; + HWND hwndSaved; + ButtonItem *buttonItems; + RECT rcSaved, rcLogSaved; + POINT ptLogSaved; + DWORD exFlags; + BOOL fPrivateThemeChanged; + MARGINS mOld; + HDC cachedToolbarDC; + HBITMAP hbmToolbarBG, oldhbmToolbarBG; + SIZE szOldToolbarSize; + SIZE oldSize, preSIZE; + WORD avatarMode, ownAvatarMode; + BYTE bTBRenderingMode; + TLogTheme theme; + TContainerSettings* settings; + CTaskbarInteract* TaskBar; + CMenuBar* MenuBar; + CSideBar* SideBar; +}; + +struct SESSIONINFO_TYPE; + +struct TWindowData { + UINT cbSize; + BYTE bType; + struct TContainerData *pContainer; // parent container description structure + HWND hwnd; + DWORD dwFlags; + DWORD dwFlagsEx; + HANDLE hContact; + char *szProto; + TCHAR szMyNickname[130]; + TCHAR szStatusBar[100]; + TCHAR newtitle[130]; // tab title... + TCHAR szStatus[50]; + WORD wStatus; + char *sendBuffer; + int iSendBufferSize; + int iSendLength; // message length in utf-8 octets + HICON hTabIcon, hTabStatusIcon, hXStatusIcon, hClientIcon, hTaskbarIcon; + HICON iFlashIcon; + BOOL mayFlashTab; + BOOL bTabFlash; + HWND hwndIEView, hwndFlash, hwndIWebBrowserControl, hwndHPP; + HWND hwndContactPic, hwndPanelPic, hwndPanelPicParent; + UINT bbLSideWidth; //MAD + UINT bbRSideWidth; //MAD + BYTE kstate[256]; + struct TStatusBarIconNode *pSINod; + SESSIONINFO_TYPE* si; + + RECT rcNick, rcUIN, rcStatus, rcPic; + HANDLE hDbEventFirst, hDbEventLast; + int sendMode; + int splitterY, originalSplitterY, dynaSplitter, savedSplitter, savedSplitY, savedDynaSplit; + int multiSplitterX; + SIZE minEditBoxSize; + int showUIElements; + int nTypeSecs; + int nTypeMode; + DWORD nLastTyping; + int showTyping; + DWORD lastMessage; + int iTabID; + HKL hkl; // keyboard layout identifier + DWORD dwTickLastEvent, dwUnread; + HBITMAP hOwnPic; + SIZE pic; + int showPic, showInfoPic; + BOOL fMustOffset; + BOOL isHistory; + int doSmileys; + UINT codePage; + HICON hSmileyIcon; + int iLastEventType; + time_t lastEventTime; + int iRealAvatarHeight; + int iButtonBarReallyNeeds; + DWORD dwLastActivity; + int iOpenJobs; + int iCurrentQueueError; + BOOL bIsMeta; + HANDLE hFlashingEvent; + TCHAR myUin[80]; + BOOL bNotOnList; + int SendFormat; + HANDLE *hQueuedEvents; + int iNextQueuedEvent; +#define EVENT_QUEUE_SIZE 10 + int iEventQueueSize; + LCID lcid; + TCHAR lcID[10]; + int panelWidth; + DWORD idle; + HWND hwndTip; + TOOLINFO ti; + HANDLE hTimeZone; + DWORD panelStatusCX; + COLORREF inputbg; + struct avatarCacheEntry *ace, *ownAce; + HANDLE *hHistoryEvents; + int maxHistory, curHistory; + HANDLE hTheme, hThemeIP, hThemeToolbar; + char szMicroLf[128]; + DWORD isAutoRTL; + int nMax; // max message size + int textLen; // current text len + LONG ipFieldHeight; + WNDPROC oldIEViewProc; + BOOL clr_added; + BOOL fIsReattach; + WPARAM wParam; // used for "delayed" actions like moved splitters in minimized windows + LPARAM lParam; + int iHaveRTLLang; + BOOL fInsertMode; + bool fkeyProcessed; + bool fEditNotesActive; + CInfoPanel *Panel; + CContactCache *cache; + CProxyWindow *pWnd; // proxy window object (win7+, for taskbar support). + // ALWAYS check this pointer before using it, it is not guaranteed to exist. + DWORD iSplitterSaved; + BYTE bWasDeleted; + BOOL bActualHistory; + POINT ptTipActivation; + LONG iInputAreaHeight; + bool fIsAutosizingInput; + bool fLimitedUpdate; +}; + +#define MESSAGE_WINDOW_DATA_SIZE offsetof(_MessageWindowData, hdbEventFirst); + +typedef struct _recentinfo { + DWORD dwFirst, dwMostRecent; // timestamps + int iFirstIndex, iMostRecent; // tab indices + HWND hwndFirst, hwndMostRecent; // client window handles +} RECENTINFO; + +/* + * configuration data for custom tab ctrl + */ + +struct myTabCtrl { + HPEN m_hPenShadow, m_hPenItemShadow, m_hPenLight; + HFONT m_hMenuFont; + COLORREF colors[10]; + HBRUSH m_brushes[4]; + DWORD m_fixedwidth; + int m_bottomAdjust; +}; + +struct TIconDesc { + char *szName; + char *szDesc; + HICON *phIcon; // where the handle is saved... + INT_PTR uId; // icon ID + BOOL bForceSmall; // true: force 16x16 +}; + +struct TIconDescW { + TCHAR *szName; + TCHAR *szDesc; + HICON *phIcon; // where the handle is saved... + INT_PTR uId; // icon ID + BOOL bForceSmall; // true: force 16x16 +}; + +// menu IDS + +#define MENU_LOGMENU 1 +#define MENU_PICMENU 2 +#define MENU_TABCONTEXT 3 +#define MENU_PANELPICMENU 4 + +#define TABSRMM_SMILEYADD_BKGCOLORMODE 0x10000000 +#define ADDEDEVENTSQUEUESIZE 100 + +/* + * tab config flags + */ + +#define TCF_FLAT 1 +//#define TCF_STYLED 2 +#define TCF_CLOSEBUTTON 4 +#define TCF_FLASHICON 8 +#define TCF_FLASHLABEL 16 +#define TCF_SINGLEROWTABCONTROL 32 +//#define TCF_LABELUSEWINCOLORS 64 +//#define TCF_BKGUSEWINCOLORS 128 +#define TCF_SBARLEFT 256 +#define TCF_SBARRIGHT 512 + +#define TCF_DEFAULT (TCF_FLASHICON) + +#define MIN_PANELHEIGHT 20 + +struct TNewWindowData { + HANDLE hContact; + int isWchar; + const char* szInitialText; + int iTabID; + int iTabImage; + int iActivate; + TCITEM item; + TContainerData* pContainer; + BOOL bWantPopup; + HANDLE hdbEvent; + HKL hkl; +}; + +// flags for the container dwFlags +#define CNT_MOUSEDOWN 1 +#define CNT_NOTITLE 2 +#define CNT_HIDETABS 4 +#define CNT_SIDEBAR 8 +#define CNT_NOFLASH 0x10 +#define CNT_STICKY 0x20 +#define CNT_DONTREPORT 0x40 +#define CNT_FLASHALWAYS 0x80 +#define CNT_TRANSPARENCY 0x100 +#define CNT_AUTOHIDE 0x200 +#define CNT_DONTREPORTFOCUSED 0x400 +//#define CNT_GLOBALSETTINGS 0x400 +#define CNT_GLOBALSIZE 0x800 +#define CNT_INFOPANEL 0x1000 +#define CNT_NOSOUND 0x2000 +#define CNT_AUTOSPLITTER 0x4000 +#define CNT_DEFERREDCONFIGURE 0x8000 +#define CNT_CREATE_MINIMIZED 0x10000 +#define CNT_NEED_UPDATETITLE 0x20000 +#define CNT_DEFERREDSIZEREQUEST 0x40000 +#define CNT_DONTREPORTUNFOCUSED 0x80000 +#define CNT_DONTREPORTFOCUSED 0x400 +#define CNT_ALWAYSREPORTINACTIVE 0x100000 +#define CNT_NEWCONTAINERFLAGS 0x200000 +#define CNT_DEFERREDTABSELECT 0x400000 +#define CNT_CREATE_CLONED 0x800000 +#define CNT_NOSTATUSBAR 0x1000000 +#define CNT_NOMENUBAR 0x2000000 +#define CNT_TABSBOTTOM 0x4000000 +#define CNT_AVATARSONTASKBAR 0x200 +#define CNT_BOTTOMTOOLBAR 0x10000000 +#define CNT_HIDETOOLBAR 0x20000000 +#define CNT_UINSTATUSBAR 0x40000000 +#define CNT_VERTICALMAX 0x80000000 + +#define CNT_EX_SOUNDS_MINIMIZED 1024 +#define CNT_EX_SOUNDS_UNFOCUSED 2048 +#define CNT_EX_SOUNDS_INACTIVETABS 4096 +#define CNT_EX_SOUNDS_FOCUSED 8192 + +#define CNT_FLAGS_DEFAULT (CNT_DONTREPORT | CNT_DONTREPORTUNFOCUSED | CNT_ALWAYSREPORTINACTIVE | CNT_HIDETABS | CNT_NEWCONTAINERFLAGS | CNT_NOMENUBAR | CNT_INFOPANEL) +#define CNT_TRANS_DEFAULT 0x00ff00ff + +#define CNT_FLAGSEX_DEFAULT (TCF_FLASHICON | CNT_EX_SOUNDS_MINIMIZED | CNT_EX_SOUNDS_UNFOCUSED | CNT_EX_SOUNDS_INACTIVETABS | CNT_EX_SOUNDS_FOCUSED) + +#define CNT_CREATEFLAG_CLONED 1 +#define CNT_CREATEFLAG_MINIMIZED 2 + +#define CNT_EX_CLOSEWARN 1 + +#define MWF_LOG_ALL (MWF_LOG_NORMALTEMPLATES | MWF_LOG_SHOWTIME | MWF_LOG_SHOWSECONDS | \ + MWF_LOG_SHOWDATES | MWF_LOG_INDENT | MWF_LOG_TEXTFORMAT | MWF_LOG_SYMBOLS | MWF_LOG_INOUTICONS | \ + MWF_LOG_SHOWICONS | MWF_LOG_GRID | MWF_LOG_GROUPMODE | \ + MWF_LOG_RTL | MWF_LOG_BBCODE | MWF_LOG_LOCALTIME/*MAD:*/ | \ + MWF_LOG_STATUSCHANGES|MWF_LOG_NEWLINE|MWF_LOG_UNDERLINE|MWF_LOG_SWAPNICK /*_MAD*/) + +#define MWF_LOG_DEFAULT (MWF_LOG_SHOWTIME | MWF_LOG_NORMALTEMPLATES | MWF_LOG_SHOWDATES | MWF_LOG_SYMBOLS | MWF_LOG_GRID | MWF_LOG_STATUSCHANGES | MWF_LOG_INOUTICONS) + +/* + * custom dialog window messages + */ +#define EM_SUBCLASSED (WM_USER+0x101) +#define EM_SEARCHSCROLLER (WM_USER+0x103) +#define EM_VALIDATEBOTTOM (WM_USER+0x104) +#define EM_THEMECHANGED (WM_USER+0x105) +#define EM_UNSUBCLASSED (WM_USER+0x106) +#define EM_REFRESHWITHOUTCLIP (WM_USER+0x107) + +#define HM_EVENTSENT (WM_USER+10) +#define DM_REMAKELOG (WM_USER+11) +#define HM_DBEVENTADDED (WM_USER+12) +#define DM_SETINFOPANEL (WM_USER+13) +#define DM_OPTIONSAPPLIED (WM_USER+14) +#define DM_SPLITTERMOVED (WM_USER+15) +#define DM_UPDATETITLE (WM_USER+16) +#define DM_APPENDTOLOG (WM_USER+17) +#define DM_ERRORDECIDED (WM_USER+18) +#define DM_SPLITSENDACK (WM_USER+19) +#define DM_TYPING (WM_USER+20) +#define DM_UPDATEWINICON (WM_USER+21) +#define DM_UPDATELASTMESSAGE (WM_USER+22) + +#define DM_SELECTTAB (WM_USER+23) +#define DM_CLOSETABATMOUSE (WM_USER+24) +#define DM_STATUSICONCHANGE (WM_USER+25) +#define DM_SETLOCALE (WM_USER+26) +#define DM_SESSIONLIST (WM_USER+27) +#define DM_QUERYLASTUNREAD (WM_USER+28) +#define DM_QUERYPENDING (WM_USER+29) +#define DM_UPDATEPICLAYOUT (WM_USER+30) +#define DM_QUERYCONTAINER (WM_USER+31) +#define DM_MUCFLASHWORKER (WM_USER+32) +#define DM_INVALIDATEPANEL (WM_USER+33) +//#define DM_REPORTMINHEIGHT (WM_USER+34) // msg dialog reports its minimum height to the container +#define DM_CHECKINFOTIP (WM_USER+35) +#define DM_SAVESIZE (WM_USER+36) +#define DM_CHECKSIZE (WM_USER+37) +#define DM_FORCEREDRAW (WM_USER+38) +#define DM_CONTAINERSELECTED (WM_USER+39) +#define DM_CONFIGURECONTAINER (WM_USER+40) +#define DM_QUERYHCONTACT (WM_USER+41) +#define DM_DEFERREDREMAKELOG (WM_USER+42) +#define DM_RESTOREWINDOWPOS (WM_USER+43) +#define DM_FORCESCROLL (WM_USER+44) +#define DM_QUERYCLIENTAREA (WM_USER+45) +#define DM_QUERYRECENT (WM_USER+47) +#define DM_ACTIVATEME (WM_USER+46) +// #define DM_REMOVEFROMSENDLATER (WM_USER+48) +#define DM_SENDLATER_RESEND (WM_USER+49) +#define DM_ADDDIVIDER (WM_USER+50) +#define DM_STATUSMASKSET (WM_USER+51) +#define DM_CONTACTSETTINGCHANGED (WM_USER+52) +#define DM_UPDATESTATUSMSG (WM_USER+53) +#define DM_PROTOACK (WM_USER+54) +#define DM_OWNNICKCHANGED (WM_USER+55) +#define DM_CONFIGURETOOLBAR (WM_USER+56) +#define DM_LOADBUTTONBARICONS (WM_USER+57) +#define DM_ACTIVATETOOLTIP (WM_USER+58) +#define DM_UINTOCLIPBOARD (WM_USER+59) +//#define DM_SPLITTEREMERGENCY (WM_USER+60) +#define DM_SENDMESSAGECOMMAND (WM_USER+61) +#define DM_FORCEDREMAKELOG (WM_USER+62) +//#define DM_QUERYFLAGS (WM_USER+63) +#define DM_STATUSBARCHANGED (WM_USER+64) +#define DM_SAVEMESSAGELOG (WM_USER+65) +#define DM_CHECKAUTOCLOSE (WM_USER+66) +#define DM_UPDATEMETACONTACTINFO (WM_USER+67) +#define DM_SETICON (WM_USER+68) +#define DM_CLOSEIFMETA (WM_USER+69) +#define DM_CHECKQUEUEFORCLOSE (WM_USER+70) +#define DM_CHECKAUTOHIDE (WM_USER+71) +#define DM_SETPARENTDIALOG (WM_USER+72) +#define DM_HANDLECLISTEVENT (WM_USER+73) +#define DM_TRAYICONNOTIFY (WM_USER+74) +#define DM_REMOVECLISTEVENT (WM_USER+75) +#define DM_GETWINDOWSTATE (WM_USER+76) +#define DM_DOCREATETAB (WM_USER+77) +#define DM_DELAYEDSCROLL (WM_USER+78) +#define DM_REPLAYQUEUE (WM_USER+79) +#define DM_REFRESHTABINDEX (WM_USER+83) +#define DM_PROTOAVATARCHANGED (WM_USER+84) +#define DM_SMILEYOPTIONSCHANGED (WM_USER+85) +#define DM_MYAVATARCHANGED (WM_USER+86) +#define DM_PRINTCLIENT (WM_USER+87) +#define DM_IEVIEWOPTIONSCHANGED (WM_USER+88) +#define DM_SPLITTERGLOBALEVENT (WM_USER + 89) +#define DM_DOCREATETAB_CHAT (WM_USER+90) +#define DM_CLIENTCHANGED (WM_USER+91) +#define DM_PLAYINCOMINGSOUND (WM_USER+92) +#define DM_SENDMESSAGECOMMANDW (WM_USER+93) +#define DM_REMOVEPOPUPS (WM_USER+94) +#define DM_BBNEEDUPDATE (WM_USER+96) +#define DM_CBDESTROY (WM_USER+97) +#define DM_LOGSTATUSCHANGE (WM_USER+98) +//#define DM_SPLITTERMOVEDGLOBAL_NOSYNC_IM (WM_USER+99) +#define DM_SC_BUILDLIST (WM_USER+100) +#define DM_SC_INITDIALOG (WM_USER+101) +#define DM_SC_CONFIG (WM_USER+104) +#define DM_SCROLLIEVIEW (WM_USER+102) +#define DM_UPDATEUIN (WM_USER+103) + +#define MINSPLITTERY 42 +#define MINLOGHEIGHT 30 +#define ERRORPANEL_HEIGHT 51 + +// wParam values for DM_SELECTTAB + +#define DM_SELECT_NEXT 1 +#define DM_SELECT_PREV 2 + +#define DM_SELECT_BY_HWND 3 // lParam specifies hwnd +#define DM_SELECT_BY_INDEX 4 // lParam specifies tab index + +#define DM_QUERY_NEXT 1 +#define DM_QUERY_MOSTRECENT 2 + +/* + * implement a callback for the rich edit. Without it, no bitmaps + * can be added to the richedit control. + * this class has to implement the GetNewStorage() method + */ + +class REOLECallback : IRichEditOleCallback +{ + +public: + + REOLECallback() + { + mRefCounter = 0; + } + + ~REOLECallback() + {} + + STDMETHOD_(ULONG, AddRef)(void) + { + mRefCounter++; + return (mRefCounter); + } + + STDMETHOD_(ULONG, Release)(void) + { + --mRefCounter; + //if (--mRefCounter == 0) + // delete this; + return (mRefCounter); + } + + STDMETHOD(QueryInterface)(REFIID iid, void** ppvObject) + { + if ( iid == IID_IUnknown || iid == IID_IRichEditOleCallback ) { + *ppvObject = this; AddRef(); return (S_OK); + } + else + return (E_NOINTERFACE); + } + + STDMETHOD(ContextSensitiveHelp) (BOOL fEnterMode) { return (E_NOTIMPL);} + STDMETHOD(DeleteObject) (LPOLEOBJECT lpoleobj) { return (E_NOTIMPL);} + STDMETHOD(GetClipboardData) (CHARRANGE FAR *lpchrg, DWORD reco, LPDATAOBJECT FAR *lplpdataobj) { return (E_NOTIMPL);} + STDMETHOD(GetContextMenu) (WORD seltype, LPOLEOBJECT lpoleobj, CHARRANGE FAR *lpchrg, HMENU FAR *lphmenu) { return (E_NOTIMPL);} + STDMETHOD(GetDragDropEffect) (BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect) { return (E_NOTIMPL);} + STDMETHOD(GetInPlaceContext) (LPOLEINPLACEFRAME FAR *lplpFrame, LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo) { return (E_NOTIMPL);} + STDMETHOD(GetNewStorage) (LPSTORAGE FAR *lplpstg); + STDMETHOD(QueryAcceptData) (LPDATAOBJECT lpdataobj, CLIPFORMAT FAR *lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict) { return (E_NOTIMPL);} + STDMETHOD(QueryInsertObject) (LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp) { return (S_OK);} + STDMETHOD(ShowContainerUI) (BOOL fShow) { return (E_NOTIMPL);} +private: + UINT mRefCounter; +}; + +#define MSGFONTID_MYMSG 0 +#define MSGFONTID_MYMISC 1 +#define MSGFONTID_YOURMSG 2 +#define MSGFONTID_YOURMISC 3 +#define MSGFONTID_MYNAME 4 +#define MSGFONTID_MYTIME 5 +#define MSGFONTID_YOURNAME 6 +#define MSGFONTID_YOURTIME 7 +#define H_MSGFONTID_MYMSG 8 +#define H_MSGFONTID_MYMISC 9 +#define H_MSGFONTID_YOURMSG 10 +#define H_MSGFONTID_YOURMISC 11 +#define H_MSGFONTID_MYNAME 12 +#define H_MSGFONTID_MYTIME 13 +#define H_MSGFONTID_YOURNAME 14 +#define H_MSGFONTID_YOURTIME 15 +#define MSGFONTID_MESSAGEAREA 16 +#define H_MSGFONTID_STATUSCHANGES 17 +#define H_MSGFONTID_DIVIDERS 18 +#define MSGFONTID_ERROR 19 +#define MSGFONTID_SYMBOLS_IN 20 +#define MSGFONTID_SYMBOLS_OUT 21 + +#define IPFONTID_NICK 0 +#define IPFONTID_UIN 1 +#define IPFONTID_STATUS 2 +#define IPFONTID_PROTO 3 +#define IPFONTID_TIME 4 + +extern const int msgDlgFontCount; + +#define LOADHISTORY_UNREAD 0 +#define LOADHISTORY_COUNT 1 +#define LOADHISTORY_TIME 2 + +#define SRMSGSET_AUTOPOPUP "AutoPopup" +#define SRMSGDEFSET_AUTOPOPUP 0 +#define SRMSGSET_AUTOMIN "AutoMin" +#define SRMSGDEFSET_AUTOMIN 0 +#define SRMSGSET_SENDONENTER "SendOnEnter" +#define SRMSGDEFSET_SENDONENTER 0 +#define SRMSGSET_MSGTIMEOUT "MessageTimeout" +#define SRMSGDEFSET_MSGTIMEOUT 60000 +#define SRMSGSET_MSGTIMEOUT_MIN 30000 // minimum value (30 seconds) + +#define SRMSGSET_LOADHISTORY "LoadHistory" +#define SRMSGDEFSET_LOADHISTORY LOADHISTORY_COUNT +#define SRMSGSET_LOADCOUNT "LoadCount" +#define SRMSGDEFSET_LOADCOUNT 10 +#define SRMSGSET_LOADTIME "LoadTime" +#define SRMSGDEFSET_LOADTIME 10 + +#define SRMSGSET_SHOWURLS "ShowURLs" +#define SRMSGDEFSET_SHOWURLS 1 +#define SRMSGSET_SHOWFILES "ShowFiles" +#define SRMSGDEFSET_SHOWFILES 1 +#define SRMSGSET_BKGCOLOUR "BkgColour" +#define SRMSGSET_BKGCOLOUR_MUC "BkgColourMUC" + +#define SRMSGDEFSET_BKGCOLOUR RGB(250,250,250) +//#define SRMSGDEFSET_BKGCOLOUR GetSysColor(COLOR_WINDOW) +#define SRMSGDEFSET_BKGINCOLOUR RGB(245,255,245) +#define SRMSGDEFSET_BKGOUTCOLOUR RGB(245,245,255) + +#define SRMSGSET_TYPING "SupportTyping" +#define SRMSGSET_TYPINGNEW "DefaultTyping" +#define SRMSGDEFSET_TYPINGNEW 1 + +#define SRMSGSET_TYPINGUNKNOWN "UnknownTyping" +#define SRMSGDEFSET_TYPINGUNKNOWN 0 + +#define SRMSGSET_SHOWTYPING "ShowTyping" +#define SRMSGDEFSET_SHOWTYPING 1 + +#define SRMSGSET_SHOWTYPINGWINFLASH "ShowTypingWinFlash" +#define SRMSGDEFSET_SHOWTYPINGWINFLASH 1 + +#define SRMSGSET_SHOWTYPINGNOWINOPEN "ShowTypingNoWinOpen" + +#define SRMSGSET_SHOWTYPINGWINOPEN "ShowTypingWinOpen" + +#define SRMSGSET_SHOWTYPINGCLIST "ShowTypingClist" +#define SRMSGDEFSET_SHOWTYPINGCLIST 1 + +// rtl support +#define SRMSGDEFSET_MOD_RTL 0 + +#define TIMERID_FLASHWND 1 +#define TIMEOUT_FLASHWND 900 +#define TIMERID_HEARTBEAT 2 +#define TIMEOUT_HEARTBEAT 20000 +#define TIMERID_HOVER 10 +#define TIMERID_HOVER_T 11 + +#define SRMSGMOD "SRMsg" +#define SRMSGMOD_T "Tab_SRMsg" +#define FONTMODULE "TabSRMM_Fonts" +#define CHAT_FONTMODULE "TabSRMM_chat_Fonts" + +#define IDM_STAYONTOP (WM_USER + 1) +#define IDM_NOTITLE (WM_USER + 2) +#define IDM_MOREOPTIONS (WM_USER +4) + +// constants for the container management functions + +#define CNT_ENUM_DELETE 1 // delete the target container... +#define CNT_ENUM_RENAME 2 +#define CNT_ENUM_WRITEFLAGS 4 + +#define IDM_CONTAINERMENU 50500 + +#define EVENTTYPE_STATUSCHANGE 25368 +#define EVENTTYPE_DIVIDER 25367 +#define EVENTTYPE_ERRMSG 25366 + +// hotkey modifiers... + +#define HOTKEY_MODIFIERS_CTRLSHIFT 0 +#define HOTKEY_MODIFIERS_CTRLALT 1 +#define HOTKEY_MODIFIERS_ALTSHIFT 2 + +struct TLogIcon { + HBITMAP hBmp, hoBmp; + HDC hdc, hdcMem; + HBRUSH hBkgBrush; +}; + +#include "..\TabSRMM_icons\resource.h" // icon pack values + +struct TCpTable { + UINT cpId; + TCHAR *cpName; +}; + +#define LOI_TYPE_FLAG 1 +#define LOI_TYPE_SETTING 2 + +struct TOptionListGroup { + LRESULT handle; + TCHAR *szName; +}; + +struct TOptionListItem { + LRESULT handle; + TCHAR *szName; + UINT id; + UINT uType; + UINT_PTR lParam; + UINT uGroup; +}; + +// sidebar button flags + +#define SBI_TOP 1 +#define SBI_BOTTOM 2 +#define SBI_HIDDEN 4 +#define SBI_DISABLED 8 +#define SBI_TOGGLE 16 +#define SBI_HANDLEBYCLIENT 32 + +// fixed stock button identifiers + +#define IDC_SBAR_SLIST 1111 +#define IDC_SBAR_FAVORITES 1112 +#define IDC_SBAR_RECENT 1113 +#define IDC_SBAR_SETUP 1114 +#define IDC_SBAR_USERPREFS 1115 +#define IDC_SBAR_TOGGLEFORMAT 1117 +#define IDC_SBAR_CANCEL 1118 + +struct SIDEBARITEM { + UINT uId; + DWORD dwFlags; + HICON *hIcon, *hIconPressed, *hIconHover; + TCHAR *szName; + void (*pfnAction)(ButtonItem *item, HWND hwndDlg, struct TWindowData *dat, HWND hwndItem); + void (*pfnCallback)(ButtonItem *item, HWND hwndDlg, struct TWindowData *dat, HWND hwndItem); + TCHAR *tszTip; +}; + +#define FONTF_BOLD 1 +#define FONTF_ITALIC 2 +#define FONTF_UNDERLINE 4 +#define FONTF_STRIKEOUT 8 + +#define RTFCACHELINESIZE 128 + +#define ID_EXTBKCONTAINER 0 +#define ID_EXTBKBUTTONBAR 1 +#define ID_EXTBKBUTTONSPRESSED 2 +#define ID_EXTBKBUTTONSNPRESSED 3 +#define ID_EXTBKBUTTONSMOUSEOVER 4 +#define ID_EXTBKINFOPANEL 5 +#define ID_EXTBKTITLEBUTTON 6 +#define ID_EXTBKTITLEBUTTONMOUSEOVER 7 +#define ID_EXTBKTITLEBUTTONPRESSED 8 +#define ID_EXTBKTABPAGE 9 +#define ID_EXTBKTABITEM 10 +#define ID_EXTBKTABITEMACTIVE 11 +#define ID_EXTBKTABITEMBOTTOM 12 +#define ID_EXTBKTABITEMACTIVEBOTTOM 13 +#define ID_EXTBKFRAME 14 +#define ID_EXTBKHISTORY 15 +#define ID_EXTBKINPUTAREA 16 +#define ID_EXTBKFRAMEINACTIVE 17 +#define ID_EXTBKTABITEMHOTTRACK 18 +#define ID_EXTBKTABITEMHOTTRACKBOTTOM 19 +#define ID_EXTBKSTATUSBARPANEL 20 +#define ID_EXTBKSTATUSBAR 21 +#define ID_EXTBKUSERLIST 22 +#define ID_EXTBKINFOPANELBG 23 +#define ID_EXTBKSIDEBARBG 24 +#define ID_EXTBK_LAST 24 + +#define SESSIONTYPE_ANY 0 +#define SESSIONTYPE_IM 1 +#define SESSIONTYPE_CHAT 2 + +#define DEFAULT_SIDEBARWIDTH 30 + +#define THEME_READ_FONTS 1 +#define THEME_READ_TEMPLATES 2 +#define THEME_READ_ALL (THEME_READ_FONTS | THEME_READ_TEMPLATES) + +#define IDC_TBFIRSTUID 10000 // first uId for custom buttons + +#include "templates.h" + +struct TStatusBarIconNode { + TStatusBarIconNode* next; + StatusIconData sid; +}; + +struct TABSRMM_SessionInfo { + unsigned int cbSize; + unsigned short evtCode; + HWND hwnd; // handle of the message dialog (tab) + HWND hwndContainer; // handle of the parent container + HWND hwndInput; // handle of the input area (rich edit) + UINT extraFlags; + UINT extraFlagsEX; + void *local; +}; + +typedef struct { + int cbSize; + HANDLE hContact; + int uFlags; // should be same as input data unless 0, then it will be the actual type + HWND hwndWindow; //top level window for the contact or NULL if no window exists + int uState; // see window states + void *local; // used to store pointer to custom data +} MessageWindowOutputData; + +#define MS_MSG_GETWINDOWDATA "MessageAPI/GetWindowData" +//wparam=(MessageWindowInputData*) +//lparam=(MessageWindowData*) +//returns 0 on success and returns non-zero (1) on error or if no window data exists for that hcontact + +// callback for the user menu entry + +#define MS_TABMSG_SETUSERPREFS "SRMsg_MOD/SetUserPrefs" +#define MS_TABMSG_SLQMGR "SRMsg_MOD/InvokeQmgr" + +// show one of the tray menus +// wParam = 0 -> session list +// wParam = 1 -> tray menu +// lParam must be 0 +#define MS_TABMSG_TRAYSUPPORT "SRMsg_MOD/Show_TrayMenu" + +/* + * the service which processes globally registered hotkeys + */ +#define MS_TABMSG_HOTKEYPROCESS "SRMsg_MOD/ProcessHotkey" + +#define MBF_DISABLED 0x01 + +#define TEMPLATES_MODULE "tabSRMM_Templates" +#define RTLTEMPLATES_MODULE "tabSRMM_RTLTemplates" + +//Checks if there is a message window opened +//wParam=(LPARAM)(HANDLE)hContact - handle of the contact for which the window is searched. ignored if lParam +//is not zero. +//lParam=(LPARAM)(HWND)hwnd - a window handle - SET THIS TO 0 if you want to obtain the window handle +//from the hContact. +#define MS_MSG_MOD_MESSAGEDIALOGOPENED "SRMsg_MOD/MessageDialogOpened" + +//obtain the message window flags +//wParam = hContact - ignored if lParam is given. +//lParam = hwnd +//returns struct MessageWindowData *dat, 0 if no window is found +#define MS_MSG_MOD_GETWINDOWFLAGS "SRMsg_MOD/GetWindowFlags" + +// custom tabSRMM events + +#define tabMSG_WINDOW_EVT_CUSTOM_BEFORESEND 1 + + +/* temporary HPP API for emulating message log */ + +#define MS_HPP_EG_WINDOW "History++/ExtGrid/NewWindow" +#define MS_HPP_EG_EVENT "History++/ExtGrid/Event" +#define MS_HPP_EG_UTILS "History++/ExtGrid/Utils" +#define MS_HPP_EG_OPTIONSCHANGED "History++/ExtGrid/OptionsChanged" +#define MS_HPP_EG_NOTIFICATION "History++/ExtGrid/Notification" + +#define SB_CHAR_WIDTH 45 // default width for status bar panel #2 +#define DEFAULT_CONTAINER_POS 0x00400040 // default container position and size +#define DEFAULT_CONTAINER_SIZE 0x019001f4 + +/* + * core hotkey service ids + */ + +#define TABSRMM_HK_LASTUNREAD 2 +#define TABSRMM_HK_LASTRECENT 4 +#define TABSRMM_HK_PASTEANDSEND 8 +#define TABSRMM_HK_SETUSERPREFS 9 +#define TABSRMM_HK_CONTAINEROPTIONS 10 +#define TABSRMM_HK_NUDGE 11 +#define TABSRMM_HK_SENDFILE 12 +#define TABSRMM_HK_QUOTEMSG 13 +#define TABSRMM_HK_SEND 14 +#define TABSRMM_HK_EMOTICONS 15 +#define TABARMM_HK_TOGGLEINFOPANEL 16 +#define TABSRMM_HK_HISTORY 17 +#define TABSRMM_HK_TOGGLETOOLBAR 18 +#define TABSRMM_HK_TOGGLEMULTISEND 19 +#define TABSRMM_HK_TOGGLERTL 20 +#define TABSRMM_HK_USERMENU 21 +#define TABSRMM_HK_USERDETAILS 22 +#define TABSRMM_HK_TOGGLEINFOPANEL 23 +#define TABSRMM_HK_CLEARLOG 24 +#define TABSRMM_HK_EDITNOTES 25 +#define TABSRMM_HK_TOGGLESENDLATER 26 +#define TABSRMM_HK_TOGGLESIDEBAR 27 +#define TABSRMM_HK_CHANNELMGR 28 +#define TABSRMM_HK_FILTERTOGGLE 29 +#define TABSRMM_HK_LISTTOGGLE 30 +#define TABSRMM_HK_MUC_SHOWSERVER 31 + +#define TABSRMM_HK_SECTION_IM "Message windows - IM" +#define TABSRMM_HK_SECTION_GENERIC "Message windows - all" +#define TABSRMM_HK_SECTION_GC "Message windows - groupchats" + +/* + * encryption status bar indicator + */ + +// extern HANDLE hHookIconPressedEvt; +extern int status_icon_list_size; + +int SI_InitStatusIcons(); +int SI_DeinitStatusIcons(); + +int GetStatusIconsCount(); +void DrawStatusIcons(struct TWindowData *dat, HDC hdc, RECT r, int gap); +void SI_CheckStatusIconClick(struct TWindowData *dat, HWND hwndFrom, POINT pt, RECT rc, int gap, int code); + +typedef struct _tagSKINDesc { + ULONG ulID; // resource id + TCHAR tszName[30]; +} SKINDESC; + +#define SKIN_NR_ELEMENTS 6 +#define SKIN_VERSION 2 + +/* + * icon defintions (index into g_buttonBarIcons) + */ + +#define ICON_DEFAULT_SOUNDS 22 +#define ICON_DEFAULT_PULLDOWN 16 +#define ICON_DEFAULT_LEFT 25 +#define ICON_DEFAULT_RIGHT 28 +#define ICON_DEFAULT_UP 26 +#define ICON_DEFAULT_TYPING 5 + +#define ICON_BUTTON_ADD 0 +#define ICON_BUTTON_CANCEL 6 +#define ICON_BUTTON_SAVE 7 + +#endif /* _MSGS_H */ + + diff --git a/plugins/TabSRMM/src/include/nen.h b/plugins/TabSRMM/src/include/nen.h new file mode 100644 index 0000000000..106238b320 --- /dev/null +++ b/plugins/TabSRMM/src/include/nen.h @@ -0,0 +1,169 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: nen.h 13750 2011-08-03 20:10:43Z george.hazan $ + * + * This implements the event notification module for tabSRMM. The code + * is largely based on the NewEventNotify plugin for Miranda NG. See + * notices below for original copyright + * + * Name: NewEventNotify - Plugin for Miranda ICQ + * Description: Notifies you when you receive a message + * Author: icebreaker, + * Date: 18.07.02 13:59 / Update: 16.09.02 17:45 + * Copyright: (C) 2002 Starzinger Michael + * + */ + +#ifndef _NEN_H_ +#define _NEN_H_ + +//#include "m_popup.h" +//#include "m_popupw.h" + +#define MODULE "tabSRMM_NEN" + +int tabSRMM_ShowPopup(WPARAM wParam, LPARAM lParam, WORD eventType, int windowOpen, struct TContainerData *pContainer, HWND hwndChild, const char *szProto, struct TWindowData *dat); + + +#define DEFAULT_COLBACK RGB(255,255,128) +#define DEFAULT_COLTEXT RGB(0,0,0) +#define DEFAULT_MASKNOTIFY (MASK_MESSAGE|MASK_URL|MASK_FILE|MASK_OTHER) +#define DEFAULT_MASKACTL (MASK_OPEN|MASK_DISMISS) +#define DEFAULT_MASKACTR (MASK_DISMISS) +#define DEFAULT_DELAY -1 + +#define MASK_MESSAGE 0x0001 +#define MASK_URL 0x0002 +#define MASK_FILE 0x0004 +#define MASK_OTHER 0x0008 + +#define MASK_DISMISS 0x0001 +#define MASK_OPEN 0x0002 +#define MASK_REMOVE 0x0004 + +#define PU_REMOVE_ON_FOCUS 1 +#define PU_REMOVE_ON_TYPE 2 +#define PU_REMOVE_ON_SEND 4 + +#define SETTING_LIFETIME_MIN 1 +#define SETTING_LIFETIME_MAX 60 +#define SETTING_LIFETIME_DEFAULT 4 + +//Entrys in the database, don't translate +#define OPT_PREVIEW "Preview" +#define OPT_COLDEFAULT_MESSAGE "DefaultColorMsg" +#define OPT_COLBACK_MESSAGE "ColorBackMsg" +#define OPT_COLTEXT_MESSAGE "ColorTextMsg" +#define OPT_COLDEFAULT_OTHERS "DefaultColorOthers" +#define OPT_COLDEFAULT_ERR "DefaultColorErr" +#define OPT_COLBACK_OTHERS "ColorBackOthers" +#define OPT_COLTEXT_OTHERS "ColorTextOthers" +#define OPT_COLBACK_ERR "ColorBackErr" +#define OPT_COLTEXT_ERR "ColorTextErr" +#define OPT_MASKNOTIFY "Notify" +#define OPT_MASKACTL "ActionLeft" +#define OPT_MASKACTR "ActionRight" +#define OPT_MASKACTTE "ActionTimeExpires" +#define OPT_MERGEPOPUP "MergePopup" +#define OPT_DELAY_MESSAGE "DelayMessage" +#define OPT_DELAY_OTHERS "DelayOthers" +#define OPT_DELAY_ERR "DelayErr" +#define OPT_SHOW_HEADERS "ShowHeaders" +#define OPT_NORSS "NoRSSAnnounces" +#define OPT_DISABLE "Disabled" +#define OPT_MUCDISABLE "MUCDisabled" +#define OPT_WINDOWCHECK "WindowCheck" +#define OPT_LIMITPREVIEW "LimitPreview" +#define OPT_REMOVEMASK "removemask" + +struct NEN_OPTIONS { + BOOL bPreview; + BOOL bDefaultColorMsg; + BOOL bDefaultColorOthers; + BOOL bDefaultColorErr; + BOOL bDisableNonMessage; + COLORREF colBackMsg; + COLORREF colTextMsg; + COLORREF colBackOthers; + COLORREF colTextOthers; + COLORREF colBackErr; + COLORREF colTextErr; + UINT maskActL; + UINT maskActR; + UINT maskActTE; + int iDelayMsg; + int iDelayOthers; + int iDelayErr; + int iDelayDefault; + BOOL bMergePopup; + BOOL bShowHeaders; + BOOL bNoRSS; + int iDisable; + int iMUCDisable; + int dwStatusMask; + BOOL bTraySupport; + BOOL bTrayExist; + BOOL iNoSounds; + BOOL iNoAutoPopup; + BOOL bWindowCheck; + int iLimitPreview; + WORD wMaxRecent; + WORD wMaxFavorites; + DWORD dwRemoveMask; +}; + +typedef struct { + HANDLE hEvent; + TCHAR szText[MAX_SECONDLINE + 2]; + DWORD timestamp; +} EVENT_DATAT; + +typedef struct { + UINT eventType; + HANDLE hContact; + NEN_OPTIONS *pluginOptions; + POPUPDATAT_V2* pud; + HWND hWnd; + long iSeconds; + TCHAR szHeader[256]; + int nrMerged; + EVENT_DATAT *eventData; + int nrEventsAlloced; + int iActionTaken; + HWND hContainer; +} PLUGIN_DATAT; + +#define NR_MERGED 5 + +#define TIMER_TO_ACTION 50685 + +#define MAX_DATASIZE 50 +#define MAX_POPUPS 20 + +#endif diff --git a/plugins/TabSRMM/src/include/resource.h b/plugins/TabSRMM/src/include/resource.h new file mode 100644 index 0000000000..25f9547d0f --- /dev/null +++ b/plugins/TabSRMM/src/include/resource.h @@ -0,0 +1,796 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by C:\tabsrmm\trunk\miranda\plugins\tabsrmm\resource.rc +// +#define IDD_TEMPLATEEDIT 1 +#define IDD_USERPREFS 2 +#define IDOK2 2 +#define IDD_USERPREFS1 3 +#define IDD_TABCONFIG 4 +#define IDD_ABOUT 7 +#define IDD_INFOPANEL 8 +#define IDC_TESTVALUE 10 +#define IDB_BITMAP1 10 +#define IDB_LOGO 10 +#define IDD_USERPREFS_FRAME 11 +#define IDR_SKIN1 13 +#define IDR_SKIN_AERO 14 +#define IDR_SKIN_AERO_GLOW 15 +#define IDD_SENDLATER_QMGR 15 +#define IDR_SKIN_AERO_SWITCHBAR 16 +#define IDD_WARNING 16 +#define IDR_SKIN_LOGO 20 +#define IDI_IMGOPEN 102 +#define IDI_IMGCLOSE 103 +#define IDI_FEATURE_DISABLED 104 +#define IDI_FEATURE_ENABLED 105 +#define IDR_CONTEXT 180 +#define IDM_PASTEFORMATTED 181 +#define IDM_CUT 182 +#define IDM_PASTE 183 +#define IDD_MSGSPLITNEW 184 +#define IDM_QUOTE 185 +#define IDM_COPY 186 +#define IDM_COPYALL 187 +#define IDM_SELECTALL 188 +#define IDM_CLEAR 189 +#define IDM_OPENNEW 190 +#define IDM_OPENEXISTING 191 +#define IDM_COPYLINK 192 +#define IDM_STICKY 193 +#define IDM_REPORTALWAY 194 +#define IDM_REPORTNEVER 195 +#define IDM_DONTREPORTMINIMIZED 196 +#define IDD_OPT_MSGDLG 243 +#define IDD_OPT_MSGLOG 245 +#define IDD_OPT_MSGTYPE 275 +#define IDD_MSGCONTAINER 276 +#define IDD_OPT_TABBEDMSG 277 +#define IDD_POPUP_OPT 278 +#define IDR_ACCEL 283 +#define IDR_TABCONTEXT 286 +#define IDD_MODERNOPTS 288 +#define IDD_SELECTCONTAINER 299 +#define IDD_CONTAINEROPTIONS 300 +#define IDD_OPT_CONTAINERS 301 +#define IDD_OPT_TOOLBAR 304 +#define IDR_MENUBAR 308 +#define IDD_CHOOSESTATUSMODES 310 +#define IDD_SKINTABDIALOG 312 +#define IDD_OPT_SKIN 313 +#define IDD_OPTIONS_PLUS 333 +#define IDD_EXCEPTION 400 +#define IDC_QMGR_REMOVE 1000 +#define IDC_EXCEPTION_DETAILS 1000 +#define IDC_UNLOAD 1000 +#define IDC_READNEXT 1000 +#define IDC_MINIMIZE 1000 +#define IDC_COPY_EXCEPTION 1001 +#define IDC_RELOADSKIN 1001 +#define IDC_APPLY 1001 +#define IDC_MAXIMIZE 1001 +#define IDC_SKINFILE 1002 +#define IDC_MESSAGE 1002 +#define IDC_THEMEEXPORT 1002 +#define IDC_HYPERLINKHAND 1003 +#define IDC_THEMEEXPORT2 1003 +#define IDC_THEMEIMPORT 1003 +#define IDC_EXPORT 1005 +#define IDC_IMPORT 1006 +#define IDC_PREVIEW 1006 +#define IDC_LOG 1006 +#define IDC_CHKNOTIFY_MESSAGE 1007 +#define IDC_FASTGRADIENT 1008 +#define IDC_CHKNOTIFY_URL 1009 +#define IDC_USESKIN 1011 +#define IDC_AUTOCLOSE 1012 +#define IDC_CHKNOTIFY_OTHER 1013 +#define IDC_AUTOMIN 1014 +#define IDC_CHKMENUITEM 1015 +#define IDC_TIME 1016 +#define IDC_CHKDISABLE 1017 +#define IDC_SENDMENU 1018 +#define IDC_CHKACTL_DISMISS 1019 +#define IDC_QUOTE 1020 +#define IDC_CHKACTL_OPEN 1021 +#define IDC_NAME 1022 +#define IDC_CHKACTL_REMOVE 1023 +#define IDC_INFOPANELMENU 1023 +#define IDC_CLOSE 1024 +#define IDC_SAVE 1025 +#define IDC_CHKACTR_DISMISS 1026 +#define IDC_CHKACTR_OPEN 1028 +#define IDC_CONTACTPIC 1029 +#define IDC_ST_ENTERMSG 1031 +#define IDC_PANELNICK 1032 +#define IDC_CHKWINDOWCHECK 1032 +#define IDC_PANELUIN 1033 +#define IDC_CHKPREVIEW 1034 +#define IDC_CHKINFINITE 1035 +#define IDC_PANELSTATUS 1036 +#define IDC_SPLITTER 1037 +#define IDC_CHKDEFAULTCOL_MESSAGE 1038 +#define IDC_CHKDEFAULTCOL_MUC 1039 +#define IDC_CHKDEFAULTCOL_ERR 1040 +#define IDC_COLBACK_MESSAGE 1041 +#define IDC_COLTEXT_MESSAGE 1042 +#define IDC_COLTEXT_MUC 1043 +#define IDC_COLBACK_MUC 1044 +#define IDC_COLTEXT_ERR 1045 +#define IDC_COLBACK_ERR 1046 +#define IDC_SHOWNAMES 1047 +#define IDC_CHKDEFAULTCOL_OTHERS 1050 +#define IDC_COLBACK_OTHERS 1051 +#define IDC_CLOSEONREPLY 1052 +#define IDC_COLTEXT_OTHERS 1053 +#define IDC_SHOWFILES 1054 +#define IDC_MERGEPOPUP 1056 +#define IDC_CHKINFINITE_MESSAGE 1057 +#define IDC_CHKMERGEPOPUP 1058 +#define IDC_IMGTAG 1058 +#define IDC_SHOWURLS 1059 +#define IDC_ANIAVATAR 1059 +#define IDC_DELAY_MESSAGE 1060 +#define IDC_SCROLLFIX 1060 +#define IDC_CLIENTINSTATBAR 1061 +#define IDC_TYPINGSOUNDS 1062 +#define IDC_OFFLINEMULTI 1063 +#define IDC_CLIENTINSTATBAR2 1063 +#define IDC_ICONWARNINGS 1063 +#define IDC_AUTOCLOSEV2 1064 +#define IDC_RESTART 1065 +#define IDC_DELAY_OTHERS 1066 +#define IDC_CLIST 1067 +#define IDC_DELAY_MUC 1067 +#define IDC_NUMBERMSG 1068 +#define IDC_MULTISPLITTER 1069 +#define IDC_CHKSHOWDATE 1070 +#define IDC_SAVEPERCONTACT 1071 +#define IDC_CHKSHOWTIME 1072 +#define IDC_CHKSHOWHEADERS 1073 +#define IDC_LOADCOUNTN 1074 +#define IDC_RDNEW 1075 +#define IDC_LOADCOUNTSPIN 1076 +#define IDC_RDOLD 1077 +#define IDC_SHOWINFOLINE 1078 +#define IDC_LBNUMBERMSG 1079 +#define IDC_SHOWBUTTONLINE 1080 +#define IDC_CHKINFINITE_URL 1081 +#define IDC_LOADUNREAD 1082 +#define IDC_SENDONENTER 1083 +#define IDC_CHKINFINITE_FILE 1084 +#define IDC_LOADCOUNT 1085 +#define IDC_SENDONDBLENTER 1086 +#define IDC_CHKINFINITE_OTHERS 1087 +#define IDC_LOADTIMEN 1088 +#define IDC_LOADTIMESPIN 1089 +#define IDC_LOADTIME 1090 +#define IDC_CMDEDITHEADERS 1091 +#define IDC_TRIM 1091 +#define IDC_FONTLIST 1092 +#define IDC_TRIMSPIN 1092 +#define IDC_USEOSD 1093 +#define IDC_CHOOSEFONT 1094 +#define IDC_CHKACTTE_DISMISS 1095 +#define IDC_CHKACTTE_OPEN 1096 +#define IDC_STMINSOLD 1097 +#define IDC_CHKACTTE_REMOVE 1098 +#define IDC_NORSS 1099 +#define IDC_DETAILS 1100 +#define IDC_ADD 1101 +#define IDC_DELAY_ERR 1102 +#define IDC_RTL 1103 +#define IDC_PIC 1104 +#define IDC_SMILEYBTN 1105 +#define IDC_FONTBOLD 1106 +#define IDC_FONTITALIC 1107 +#define IDC_FONTUNDERLINE 1108 +#define IDC_FONTFACE 1110 +#define IDC_HISTORY 1111 +#define IDC_CANCELADD 1112 +#define IDC_FONTSTRIKEOUT 1113 +#define IDC_MATH_BKGCOLOUR 1124 +#define IDC_FONTCOLOR 1127 +#define IDC_LOGFROZENTEXT 1128 +#define IDC_FONTCOLOUR 1128 +#define IDC_STSIZETEXT 1135 +#define IDC_STCOLOURTEXT 1136 +#define IDC_PRESETSPLIT 1137 +#define IDC_PRESETSINGLE 1138 +#define IDC_STMSGLOGGROUP 1139 +#define IDC_PROTOCOL 1140 +#define IDC_STMSGLOGGROUP2 1140 +#define IDC_STMSGLOGGROUP3 1141 +#define IDC_PROTOMENU 1141 +#define IDC_TYPING 1143 +#define IDC_TOGGLETOOLBAR 1144 +#define IDC_ERRORTEXT 1145 +#define IDC_SHOWNOTIFY 1146 +#define IDC_STATUSWIN 1147 +#define IDC_TYPEFLASHWIN 1148 +#define IDC_CHARCOUNT 1149 +#define IDC_TYPENOWIN 1150 +#define IDC_TYPEWIN 1151 +#define IDC_CASCADE 1151 +#define IDC_SECONDS 1152 +#define IDC_NOTIFYTRAY 1153 +#define IDC_NOTIFYBALLOON 1154 +#define IDC_NOTIFYBALLOON2 1155 +#define IDC_NOTIFYPOPUP 1155 +#define IDC_MathSubst 1156 +#define IDC_INDENT 1157 +#define IDC_INDENTAMOUNT 1158 +#define IDC_MSGTABS 1159 +#define IDC_SIDEBARUP 1160 +#define IDC_SIDEBARDOWN 1161 +#define IDC_WARNONCLOSE 1162 +#define IDC_CUT_TABTITLE 1163 +#define IDC_CUT_TITLEMAX 1164 +#define IDC_SHOWTABTIP 1165 +#define IDC_SHOWSTATUSONTAB 1166 +#define IDC_SWAPTIMESTAMP 1167 +#define IDC_AUTOCREATETABS 1168 +#define IDC_LOCALTIME 1169 +#define IDC_O_HIDETITLE 1170 +#define IDC_STICKY 1171 +#define IDC_LOGSTATUS 1172 +#define IDC_DEBUGPOPUPS 1173 +#define IDC_CONTAINERGROUPMODE 1174 +#define IDC_SELFTYPING 1175 +#define IDC_LOGHOTKEYS 1176 +#define IDC_NOTITLE 1177 +#define IDC_TABPADDING 1178 +#define IDC_PADSPIN 1179 +#define IDC_HTABPADDING 1179 +#define IDC_BOTTOMTABADJUST 1180 +#define IDC_POPUPCONTAINER 1181 +#define IDC_TABWIDTH 1181 +#define IDC_PRIVATESPLITTER 1182 +#define IDC_CNTPRIVATE 1182 +#define IDC_NEWSPLITLAYOUT 1183 +#define IDC_O_NOTABS 1184 +#define IDC_DONTREPORTUNFOCUSED 1185 +#define IDC_ESC_MINIMIZE 1186 +#define IDC_USEDIVIDERS 1187 +#define IDC_DRAWGRID 1188 +#define IDC_LIMITTABS 1189 +#define IDC_WANTVERTICALGRID 1190 +#define IDC_LIMITPREVIEW 1191 +#define IDC_AUTOLOCALE 1192 +#define IDC_MUC_LOGCOLORS 1192 +#define IDC_DONTREPORTUNFOCUSED2 1193 +#define IDC_GCHECK 1194 +#define IDC_HIDETAB 1195 +#define IDC_O_DONTREPORT 1196 +#define IDC_USEDEFERRED 1197 +#define IDC_AUTOSWITCHTABS 1198 +#define IDC_USEINDIVIDUALBKG 1199 +#define IDC_SINGLEWINDOWMODE 1200 +#define IDC_FLATBUTTONS 1201 +#define IDC_O_STICKY 1202 +#define IDC_DIVIDERSUSEPOPUPCONFIG 1203 +#define IDC_FLASHFOREVER 1205 +#define IDC_DONTFLASH 1206 +#define IDC_O_FLASHDEFAULT 1208 +#define IDC_FLASHDEFAULT 1209 +#define IDC_DEFAULTCONTAINERMODE 1210 +#define IDC_ALWAYS 1211 +#define IDC_DONTREPORTFOCUSED2 1212 +#define IDC_TRANSPARENCY 1215 +#define IDC_PANELSPLITTER 1216 +#define IDC_AUTOCREATECONTAINER 1216 +#define IDC_LIMITAVATARS 1217 +#define IDC_DONTREPORT 1219 +#define IDC_SPIN1 1220 +#define IDC_CNTLIST 1221 +#define IDC_SPIN3 1221 +#define IDC_NEWCONTAINER 1222 +#define IDC_TABWIDTHSPIN 1222 +#define IDC_UPDATEPREVIEW 1223 +#define IDC_MODIFY 1223 +#define IDC_SAVESIZEASGLOBAL 1223 +#define IDC_REVERTGLOBAL 1223 +#define IDC_CREATENEW 1224 +#define IDC_RTLMODIFY 1224 +#define IDC_RESETALLTEMPLATES 1224 +#define IDC_SENDLATER 1226 +#define IDC_RETRY 1227 +#define IDC_SETUPAUTOCREATEMODES 1228 +#define IDC_POPUPSTATUSMODES 1229 +#define IDC_DELETECONTAINER 1230 +#define IDC_CANCELSEND 1231 +#define IDC_O_FLASHALWAYS 1232 +#define IDC_RENAMECONTAINER 1233 +#define IDC_RETRY2 1234 +#define IDC_MSGSENDLATER 1235 +#define IDC_O_FLASHNEVER 1236 +#define IDC_NEWCONTAINERNAME 1237 +#define IDC_O_TITLENEVER 1238 +#define IDC_O_TITLEFRONT 1239 +#define IDC_O_TITLESUFFIX 1240 +#define IDC_TRANSPARENCY_ACTIVE 1241 +#define IDC_TRANSPARENCY_INACTIVE 1242 +#define IDC_INDENTSPIN 1250 +#define IDC_TABBORDER 1251 +#define IDC_SPIN2 1252 +#define IDC_TABBORDERSPIN 1253 +#define IDC_FLASHINTERVALSPIN 1254 +#define IDC_HIDESBAR 1255 +#define IDC_TABBORDEROUTER 1256 +#define IDC_TABBORDEROUTERRIGHT 1257 +#define IDC_TABBORDERSPINOUTER 1258 +#define IDC_ALWAYSPOPUPSINACTIVE 1259 +#define IDC_TABBORDERSPINOUTER2 1259 +#define IDC_BOTTOMTABADJUSTSPIN 1259 +#define IDC_HISTORYSIZE 1260 +#define IDC_TABBORDERSPINOUTERRIGHT 1260 +#define IDC_HISTORYSIZESPIN 1261 +#define IDC_TABBORDEROUTERTOP 1261 +#define IDC_HOTKEYSAREGLOBAL 1262 +#define IDC_TABBORDERSPINOUTERTOP 1262 +#define IDC_SINGLEROWTAB 1263 +#define IDC_STREAMTHREADING 1264 +#define IDC_TABBORDEROUTERBOTTOM 1264 +#define IDC_IEVIEWMODE 1265 +#define IDC_TABBORDERSPINOUTERBOTTOM 1265 +#define IDC_TEXTFORMATTING 1266 +#define IDC_AVATARMODE 1267 +#define IDC_CODEPAGES 1268 +#define IDC_OWNAVATARMODE 1268 +#define IDC_EMPTYLINEFIX 1272 +#define IDC_SPLITTERSTATICEDGES 1273 +#define IDC_MAXAVATARHEIGHT 1275 +#define IDC_TABLIMIT 1276 +#define IDC_RIGHTINDENT 1277 +#define IDC_AVATARSPIN 1278 +#define IDC_TABLIMITSPIN 1279 +#define IDC_SHOWFORMATTING 1280 +#define IDC_AGGRESSIVEUPDATE 1283 +#define IDC_THINSEPARATORS 1284 +#define IDC_RINDENTSPIN 1285 +#define IDC_STATICERRORICON 1286 +#define IDC_STATICTEXT 1287 +#define IDC_GROUPMODE 1288 +#define IDC_ANIMATED 1289 +#define IDC_ISFAVORITE 1289 +#define IDC_ALWAYSTRIM 1289 +#define IDC_SKIN_LOADFONTS 1289 +#define IDC_PRESERVEAVATARSIZE 1289 +#define IDC_UPREFS_SHOWICONS 1289 +#define IDC_ALWAYSTRIM2 1290 +#define IDC_SKIN_LOADTEMPLATES 1290 +#define IDC_UPREFS_SHOWSYMBOLS 1290 +#define IDC_SKIN_LOADTEMPLATES2 1291 +#define IDC_UPREFS_INOUTICONS 1291 +#define IDC_AVADYNAMIC 1292 +#define IDC_UPREFS_SHOWTIMESTAMP 1292 +#define IDC_USESNAPPING 1293 +#define IDC_UPREFS_SHOWSECONDS 1293 +#define IDC_UPREFS_SHOWICONS3 1294 +#define IDC_UPREFS_SHOWDATES 1294 +#define IDC_SENDFORMAT 1295 +#define IDC_UPREFS_LOCALTIME 1295 +#define IDC_FLATMSGLOG 1296 +#define IDC_UPREFS_INDENT 1296 +#define IDC_UPREFS_GRID 1297 +#define IDC_UPREFS_GROUPING 1298 +#define IDC_TOGGLESIDEBAR 1299 +#define IDC_CNTNOSTATUSBAR 1299 +#define IDC_UPREFS_BBCODE 1299 +#define IDC_SECTIONTREE 1300 +#define IDC_UPREFS_RTL 1301 +#define IDC_CHECKICONDLL 1302 +#define IDC_UPREFS_LOGSTATUS 1302 +#define IDC_ENABLETRAYSUPPORT 1303 +#define IDC_UPREFS_LOGSTATUS2 1303 +#define IDC_UPREFS_NORMALTEMPLATES 1303 +#define IDC_HEADERSHADING 1304 +#define IDC_HIDEMENUBAR 1305 +#define IDC_STATICCONTROL 1307 +#define IDC_AUTOCLOSETABTIME 1308 +#define IDC_AUTOCLOSETABSPIN 1309 +#define IDC_SENDONSHIFTENTER 1310 +#define IDC_USEGLOBALSIZE 1311 +#define IDC_LOADONLYACTUAL 1311 +#define IDC_MICROLF 1312 +#define IDC_EVENTAPI 1313 +#define IDC_MINIMIZETOTRAY 1316 +#define IDC_DELETETEMP 1318 +#define IDC_FORMATTING 1319 +#define IDC_AUTOSELECTCOPY 1319 +#define IDC_HIDETOOLBAR 1320 +#define IDC_FLASHCLIST 1322 +#define IDC_MSGLOGPLUGIN 1323 +#define IDC_UIDSTATUSBAR 1324 +#define IDC_NRFLASH 1325 +#define IDC_NRFLASHSPIN 1326 +#define IDC_FLASHINTERVAL 1327 +#define IDC_USEKBDHOOK 1328 +#define IDC_STATIC111 1329 +#define IDC_TAB1 1330 +#define IDC_ALWAYSFULLWIDTHTOOLBAR 1335 +#define IDC_FORMATWHOLEWORDSONLY 1337 +#define IDC_STATUSGROUP 1338 +#define IDC_ALLOWSENDBUTTONHIDE 1340 +#define IDC_VERTICALMAX 1341 +#define IDC_AUTOSPLITTER 1342 +#define IDC_ICONDLLNAME 1343 +#define IDC_SAVETEMPLATE 1344 +#define IDC_SELECTICONDLL 1345 +#define IDC_RTLDEFAULT 1346 +#define IDC_MATHMODSUPPORT 1348 +#define IDC_MESSAGEPREVIEWLIMIT 1349 +#define IDC_MESSAGEPREVIEWLIMITSPIN 1350 +#define IDC_DELAY_MESSAGE_SPIN 1351 +#define IDC_DELAY_MESSAGE_MUC_SPIN 1352 +#define IDC_DELAY_ERR_SPIN 1353 +#define IDC_MESSAGEPREVIEWLIMITSPIN2 1354 +#define IDC_DELAY_OTHERS_SPIN 1354 +#define IDC_TEMPLATELIST 1361 +#define IDC_EDITTEMPLATE 1362 +#define IDC_REVERT 1363 +#define IDC_FORGET 1364 +#define IDC_COLOR1 1366 +#define IDC_COLOR2 1367 +#define IDC_COLOR3 1368 +#define IDC_COLOR4 1369 +#define IDC_COLOR5 1370 +#define IDC_FORCEANSI 1371 +#define IDC_TEMPLOVERRIDE 1372 +#define IDC_IGNORETIMEOUTS 1372 +#define IDC_RTLTEMPLOVERRIDE 1373 +#define IDC_SELECTTHEME 1376 +#define IDC_RELOAD 1376 +#define IDC_LOGOPTIONS 1377 +#define IDC_WINDOWOPTIONS 1378 +#define IDC_TRAYCONTAINER 1379 +#define IDC_EVENTOPTIONS 1380 +#define IDC_VARIABLESHELP 1381 +#define IDC_TABMSGOPTIONS 1384 +#define IDC_HELPTEXT 1392 +#define IDC_TITLEFORMAT 1393 +#define IDC_THEME 1394 +#define IDC_INFOPANEL 1395 +#define IDC_SUPPORT 1396 +#define IDC_SHOWAVATAR 1396 +#define IDC_NOPOPUPAVAIL 1398 +#define IDC_QHTM 1399 +#define IDC_TSLABEL_ACTIVE 1400 +#define IDC_TSLABEL_INACTIVE 1401 +#define IDC_TITLEBOX 1402 +#define IDC_DESC 1404 +#define IDC_LABEL_PRIVATETHEME 1405 +#define IDC_MSGLOGDIDSPLAY 1407 +#define IDC_IMCHECK 1410 +#define IDC_CHATCHECK 1411 +#define IDC_CANBEHIDDEN 1412 +#define IDC_BBRESET 1413 +#define IDC_BOTTOMTOOLBAR 1414 +#define IDC_BUTTON1 1415 +#define IDC_SEPARATOR 1415 +#define IDC_PLUS_REVERT 1415 +#define IDC_SIZECOMPACT 1415 +#define IDC_RESCANSKIN 1415 +#define IDC_RESETWARNINGS 1415 +#define IDC_TIMEOUTSPIN 1416 +#define IDC_SIZENORMAL 1416 +#define IDC_SIZELARGE 1417 +#define IDC_MTN_POPUPMODE 1418 +#define IDC_MTN_HELP 1419 +#define IDC_CUT_TITLEMAXSPIN 1420 +#define IDC_HELP_CONTAINERS 1421 +#define IDC_HELP_GENERAL 1422 +#define IDC_CLOSEONESC 1423 +#define IDC_ALWAYSPOPUP 1424 +#define IDC_AEROEFFECT 1424 +#define IDC_CREATEMIN 1425 +#define IDC_ESCMODE 1425 +#define IDC_CHECK5 1426 +#define IDC_TABMODE 1426 +#define IDC_SENDSHIFTENTER 1427 +#define IDC_O_TABMODE 1427 +#define IDC_SENDENTER 1428 +#define IDC_O_SBARLAYOUT 1428 +#define IDC_PANELVISIBILITY 1428 +#define IDC_SENDDBLENTER 1429 +#define IDC_SBARLAYOUT 1429 +#define IDC_PANELSIZE 1429 +#define IDC_MINSEND 1430 +#define IDC_IPCONFIG_TITLE 1430 +#define IDC_SENDCTRLENTER 1431 +#define IDC_NOSYNC 1431 +#define IDC_USETABS 1432 +#define IDC_IPCONFIG_FOOTER 1432 +#define IDC_NOOPENPOPUP 1433 +#define IDC_NOOPENNOTIFY 1433 +#define IDC_GROUP_SCOPE 1433 +#define IDC_CREATENOACTIVATE 1434 +#define IDC_GROUP_SIZE 1434 +#define IDC_NOTIFYMSG 1435 +#define IDC_GROUP_OTHER 1435 +#define IDC_POPUPONCREATE 1436 +#define IDC_SIZE_TIP 1436 +#define IDC_IPCONFIG_PRIVATECONTAINER 1437 +#define IDC_EXPLAINMSGLOGSETTINGS 1437 +#define IDC_NOTIFYFILE 1438 +#define IDC_PANELPICTUREVIS 1438 +#define IDC_SKINNAME 1438 +#define IDC_NOTIFYURL 1439 +#define IDC_SKINROOTFOLDER 1439 +#define IDC_NOTIFYOTHER 1440 +#define IDC_SKIN_WARN 1440 +#define IDC_QMGR_LIST 1441 +#define IDC_QMGR_FILTER 1442 +#define IDC_TOOLBARTREE 1444 +#define IDC_QMGR_HELP 1444 +#define IDC_QMGR_ERRORPOPUPS 1445 +#define IDC_QMGR_ERRORPOPUPS2 1446 +#define IDC_QMGR_SUCCESSPOPUPS 1446 +#define IDC_BUTTON2 1446 +#define IDC_SKIN_CLOSENOW 1446 +#define IDC_CHECK1 1447 +#define IDC_DONTSHOWAGAIN 1447 +#define IDC_CAPTION 1448 +#define IDC_WARNTEXT 1449 +#define IDC_WARNICON 1450 +#define IDC_WARNGROUP 1451 +#define IDC_EX_REASON 1452 +#define IDC_FLASHICON 1489 +#define IDC_FLASHLABEL 1490 +#define IDC_STATIC_VISIBILTY 1491 +#define IDC_BUTTONTABS 1492 +#define IDC_CLOSEBUTTONONTABS 1493 +#define IDC_O_STATIC_AVATAR 1501 +#define IDC_O_STATIC_OWNAVATAR 1502 +#define IDC_USEAERO 1531 +#define IDC_USEAEROPEEK 1532 +#define IDC_TXT_TITLE1 1617 +#define IDC_TXT_TITLE2 1618 +#define IDC_TXT_TITLE4 1620 +#define IDC_TXT_TITLE5 1622 +#define IDC_TXT_TITLE3 1623 +#define IDC_O_EXPLAINGLOBALNOTIFY 1624 +#define IDC_O_AUTOHIDE 1625 +#define IDC_O_AUTOHIDESECONDS 1626 +#define IDC_O_ENABLESOUNDS 1701 +#define IDC_O_SOUNDSMINIMIZED 1702 +#define IDC_O_SOUNDSUNFOCUSED 1703 +#define IDC_O_SOUNDSINACTIVE 1704 +#define IDC_O_SOUNDSFOCUSED 1705 +#define IDC_O_TITLEBARFORMAT 1706 +#define IDC_EDIT1 1720 +#define IDC_O_CNTPRIVATE 1901 +#define IDC_PLUS_CHECKTREE 2000 +#define IDC_COPYRIGHT 2002 +#define IDC_PLUS_HELP 2004 +#define IDC_O_HELP_TITLEFORMAT 2064 +#define IDC_OPTIONSTAB 2111 +#define IDC_HEADERBAR 2397 +#define IDC_AVATARSONTASKBAR 2735 +#define IDC_TSLABEL_EXPLAINTHEME 3123 +#define IDC_TSLABEL_REOPENWARN 3124 +#define IDD_OPT_TYPINGNOTIFYPOPUP 30159 +#define IDI_START1 30160 +#define IDI_STOP1 30161 +#define IDI_START2 30162 +#define IDI_STOP2 30163 +#define IDI_ENABLED 30164 +#define IDI_DISABLED 30165 +#define IDD_OPT 30166 +#define IDC_START 30167 +#define IDC_STOP 30168 +#define IDI_START3 30169 +#define IDI_STOP3 30170 +#define IDI_START4 30171 +#define IDI_STOP4 30172 +#define IDI_START5 30173 +#define IDI_STOP5 30174 +#define IDI_START6 30175 +#define IDI_STOP6 30176 +#define IDI_START7 30177 +#define IDI_STOP7 30178 +#define IDI_START8 30179 +#define IDI_STOP8 30180 +#define IDI_START9 30181 +#define IDI_STOP9 30182 +#define IDC_ICON1 31600 +#define IDC_ICON2 31601 +#define IDC_TIMEOUT_POPUP2 31602 +#define IDC_TIMEOUT_CUSTOM2 31603 +#define IDC_TIMEOUT_POPUP 31604 +#define IDC_TIMEOUT_PROTO 31605 +#define IDC_TIMEOUT_CUSTOM 31606 +#define IDC_TIMEOUT_VALUE 31607 +#define IDC_TIMEOUT_POPUP3 31608 +#define IDC_TIMEOUT_PERMANENT2 31608 +#define IDC_USEWINCOLORS 31609 +#define IDC_USEPOPUPCOLORS 31610 +#define IDC_TYPEON_BG 31611 +#define IDC_TYPEON_TX 31612 +#define IDC_TYPEOFF_BG 31613 +#define IDC_TYPEOFF_TX 31614 +#define IDC_INFO 31615 +#define IDC_INFO2 31616 +#define IDC_WO 31617 +#define IDC_TIMEOUT_PERMANENT1 31618 +#define IDC_TIMEOUT_PERMANENT 31618 +#define IDC_SHOWMENU 31619 +#define IDC_DISABLED 31620 +#define IDC_ONEPOPUP 31621 +#define IDC_WOCL 31622 +#define IDC_ICONS 31623 +#define IDC_TIMEOUT_VALUE2 31624 +#define IDC_PREVIEW_ALL 31625 +#define ID_CLOSETAB_DETACHTAB 40025 +#define ID_TABCONTEXT_NEXTTAB 40026 +#define ID_TABCONTEXT_ATTACH 40027 +#define ID_TABCONTEXT_CLOSECONTAINER 40028 +#define ID_TABCONTEXT_PREVTAB 40029 +#define ID_CLOSETAB 40030 +#define ID_TABMENU_CLOSETAB 40031 +#define ID_TABMENU_SAVELOCALESETTINGFORTHISCONTACT 40034 +#define ID_TABMENU_OPENWINDOWSERVICE 40035 +#define ID_TABMENU_ATTACHTOCONTAINER 40036 +#define ID_Menu 40037 +#define ID_PICMENU_TOGGLEAVATARDISPLAY 40041 +#define ID_PICMENU_SETTINGS 40042 +#define ID_LOG_CONTAINEROPTIONS 40045 +#define ID_TABMENU_CONTAINEROPTIONS 40046 +#define ID_LOGMENU_SHOWMESSAGEICONS 40056 +#define ID_LOGMENU_LOADDEFAULTS 40057 +#define ID_LOGMENU_ALWAYSUSEGLOBALSPLITTERPOSITION 40060 +#define ID_LOGMENU_TIMESTAMPSETTINGS 40061 +#define ID_LOGMENU_MESSAGELOGFORMATTING 40062 +#define ID_TABMENU_CLOSECONTAINER 40063 +#define ID_STATUSBARSETTINGS_USEGLOBALDEFAULT 40065 +#define ID_STATUSBARSETTINGS_SHOWTHESTATUSBAR 40066 +#define ID_STATUSBARSETTINGS_HIDETHESTATUSBAR 40067 +#define ID_VIEW_SHOWMENUBAR 40076 +#define ID_VIEW_SHOWSTATUSBAR 40077 +#define ID_VIEW_SHOWTOOLBAR 40078 +#define ID_TOOLBAR_SENDBUTTON 40079 +#define ID_TOOLBAR_USERINFORMATION 40080 +#define ID_TOOLBAR_EXTRABUTTONS 40081 +#define ID_VIEW_SHOWAVATAR 40082 +#define ID_VIEW_SHOWTITLEBAR 40083 +#define ID_FILE 40084 +#define ID_FILE_CLOSE 40085 +#define ID_FILE_CLOSEMESSAGESESSION 40086 +#define ID_VIEW_SHOWMULTISENDCONTACTLIST 40087 +#define ID_VIEW_TITLEBAR 40088 +#define ID_VIEW_TABSATBOTTOM 40093 +#define ID_VIEW_STAYONTOP 40095 +#define ID_HELP 40096 +#define ID_OPTIONS_EVENTPOPUPS 40097 +#define ID_EVENTPOPUPS_DISABLEALLEVENTPOPUPS 40098 +#define ID_OPTIONS_SOUNDS 40101 +#define ID_SOUNDS_DISABLEALLMESSAGESOUNDS 40102 +#define ID_SOUNDS_SYNCSOUNDSWITHEVENTPOPUPS 40103 +#define ID_SOUNDS_ENABLEALLMESSAGESOUNDS 40104 +#define ID_VIEW_FLASHING 40105 +#define ID_WINDOWFLASHING_USEDEFAULTVALUES 40106 +#define ID_WINDOWFLASHING_FLASHUNTILFOCUSED 40107 +#define ID_WINDOWFLASHING_DISABLEFLASHING 40108 +#define ID_FILE_SAVEMESSAGELOGAS 40109 +#define ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISMINIMIZED 40110 +#define ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISUNFOCUSED 40111 +#define ID_EVENTPOPUPS_SHOWPOPUPSFORALLINACTIVESESSIONS 40112 +#define ID_OPTIONS_SAVECURRENTWINDOWPOSITIONASDEFAULT 40113 +#define ID_CONTAINER_CONTAINEROPTIONS 40114 +#define ID_MESSAGELOG 40115 +#define ID_MESSAGELOG_LOGITEMSTOSHOW 40116 +#define ID_LOGITEMSTOSHOW_USETHINGRIDLINES 40117 +#define ID_MESSAGELOG_TIMESTAMPSETTINGS 40118 +#define ID_MESSAGELOG_MESSAGELOGFORMATTING 40119 +#define ID_EVENTPOPUPS_SHOWPOPUPSIFWINDOWISFOCUSED 40120 +#define ID_LOGMENU_MESSAGELOGSETTINGSAREGLOBAL 40124 +#define ID_USER 40125 +#define ID_TITLEBAR_USESTATICCONTAINERICON 40126 +#define ID_PICMENU_ALWAYSKEEPTHEBUTTONBARATFULLWIDTH 40134 +#define ID_SENDMENU_SENDDEFAULT 40135 +#define ID_SENDMENU_SENDTOMULTIPLEUSERS 40136 +#define ID_SENDMENU_SENDTOCONTAINER 40137 +#define ID_SENDMENU_FORCEANSISEND 40138 +#define ID_VIEW_VERTICALMAXIMIZE 40143 +#define ID_SENDMENU_SENDLATER 40144 +#define ID_PROTOMENU_SPLITTER 40145 +#define ID_MODE_GLOBAL 40148 +#define ID_MODE_PRIVATE 40150 +#define ID_UNREADMENU_TEST 40151 +#define ID_UNREADMENU_FOOBAR 40152 +#define ID_UNREADMENU_ 40153 +#define ID_TRAYCONTEXT_RECENTSESSIONS 40154 +#define ID_RECENTSESSIONS_1 40155 +#define ID_TRAYCONTEXT_FAVORITES 40156 +#define ID_FAVORITES_1 40157 +#define ID_TRAYCONTEXT_DISABLEALLPOPUPS 40158 +#define ID_TRAYCONTEXT_DON 40159 +#define ID_TRAYCONTEXT_HIDEALLMESSAGECONTAINERS 40160 +#define ID_TRAYCONTEXT_RESTOREALLMESSAGECONTAINERS 40161 +#define ID_TRAYCONTEXT_DON40223 40164 +#define ID_TRAYCONTEXT_BE 40165 +#define ID_RECENTSESSIONS_2 40166 +#define ID_PROTOMENU_SENDTEXTFORMATTING 40167 +#define ID_SENDTEXTFORMATTING_GLOBAL 40169 +#define ID_Menu40228 40170 +#define ID_VIEW_BOTTOMTOOLBAR 40171 +#define ID_GLOBAL_OFF 40172 +#define ID_SENDTEXTFORMATTING_THISCONTACT 40173 +#define ID_THISCONTACT_GLOBALSETTING 40174 +#define ID_THISCONTACT_BBCODE 40175 +#define ID_THISCONTACT_OFF 40177 +#define ID_GLOBAL_BBCODE 40178 +#define ID_PROTOMENU_FAVORITES 40179 +#define ID_FAVORITES_ADDCONTACTTOFAVORITES 40180 +#define ID_FAVORITES_REMOVECONTACTFROMFAVORITES 40181 +#define ID_FILE_HTTP 40182 +#define ID_LOG_FREEZELOG 40183 +#define ID_FONT_SIZE 40186 +#define ID_SIZE_LARGE 40187 +#define ID_SIZE_BIGGER 40188 +#define ID_SIZE_NORMAL 40189 +#define ID_SIZE_SMALLER 40190 +#define ID_SIZE_TINY 40191 +#define ID_FONT_RED 40192 +#define ID_FONT_GREEN 40193 +#define ID_FONT_BLUE 40194 +#define ID_FONT_MAGENTA 40195 +#define ID_FONT_YELLOW 40196 +#define ID_FONT_BLACK 40197 +#define ID_FONT_WHITE 40198 +#define ID_FONT_CLEARALLFORMATTING 40199 +#define ID_FONT_DEFAULTCOLOR 40200 +#define ID_FONT_CYAN 40201 +#define ID_SENDMENU_SENDWITHOUTTIMEOUTS 40201 +#define ID_DUMMY_NOMESSAGESESSIONSOPENED 40202 +#define ID_TRAYCONTEXT_SHOWTHETRAYICON 40204 +#define ID_INFOPANEL_QUICKTOGGLE 40206 +#define ID_INFOPANEL_GLOBAL 40207 +#define ID_VIEW_INFOPANEL 40208 +#define ID_GLOBAL_ENABLED 40208 +#define ID_GLOBAL_DISABLED 40209 +#define ID_INFOPANEL_THISCONTACT 40210 +#define ID_THISCONTACT_USEGLOBALSETTING 40211 +#define ID_THISCONTACT_ALWAYSON 40212 +#define ID_THISCONTACT_ALWAYSOFF 40213 +#define ID_PANELPICMENU_RESETTHEAVATAR 40218 +#define ID_EDITOR_PASTEANDSENDIMMEDIATELY 40221 +#define ID_HELP_ABOUTTABSRMM 40223 +#define ID_SENDMENU_SENDNUDGE 40228 +#define ID_SPLITTERCONTEXT_SAVEGLOBALFORALLSESSIONS 40229 +#define ID_SPLITTERCONTEXT_SAVEFORTHISCONTACTONLY 40230 +#define ID_SPLITTERCONTEXT_FORGETTHECHANGES 40231 +#define ID_SPLITTERCONTEXT_SETPOSITIONFORTHISSESSION 40232 +#define ID_FONT_CYAN40233 40233 +#define ID_TABMENU_LEAVECHATROOM 40234 +#define ID_PANELPICMENU_SAVETHISPICTUREAS 40235 +#define ID_PICMENU_SAVETHISPICTUREAS 40236 +#define ID_TABMENU_SAVETABPOSITION 40239 +#define ID_TABMENU_CLEARSAVEDTABPOSITION 40240 +#define ID_VISIBILITY_DEFAULT 40241 +#define ID_VISIBILITY_HIDDENFORTHISCONTACT 40242 +#define ID_VISIBILITY_VISIBLEFORTHISCONTACT 40243 +#define ID_LOGMENU_USEADVANCEDTEMPLATE 40244 +#define ID_MESSAGELOG_USESIMPLETEMPLATES 40246 +#define ID_EDITOR_SHOWMESSAGELENGTHINDICATOR 40248 +#define ID_LOGMENU_MESSAGELOGSETTINGS 40250 +#define ID_MESSAGELOGSETTINGS_GLOBAL 40251 +#define ID_MESSAGELOGSETTINGS_FORTHISCONTACT 40252 +#define ID_MESSAGELOG_MESSAGELOGSETTINGS 40253 +#define ID_QUEUEMANAGER_MARKSELECTEDFORREMOVAL 40256 +#define ID_QUEUEMANAGER_RESETSELECTED 40257 +#define ID_QUEUEMANAGER_HOLDSELECTED 40258 +#define ID_QUEUEMANAGER_RESUMESELECTED 40259 +#define ID_QUEUEMANAGER_CANCELALLMULTISENDJOBS 40260 +#define ID_QUEUEMANAGER_COPYMESSAGETOCLIPBOARD 40261 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 17 +#define _APS_NEXT_COMMAND_VALUE 40263 +#define _APS_NEXT_CONTROL_VALUE 1453 +#define _APS_NEXT_SYMED_VALUE 40283 +#endif +#endif diff --git a/plugins/TabSRMM/src/include/sendlater.h b/plugins/TabSRMM/src/include/sendlater.h new file mode 100644 index 0000000000..a81c08f4ae --- /dev/null +++ b/plugins/TabSRMM/src/include/sendlater.h @@ -0,0 +1,155 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: sendlater.h 11707 2010-05-05 13:53:11Z silvercircle $ + * + * the sendlater class + */ + +#ifndef __SENDLATER_H +#define __SENDLATER_H + +#define TIMERID_SENDLATER 12000 +#define TIMERID_SENDLATER_TICK 13000 + +#define TIMEOUT_SENDLATER 10000 +#define TIMEOUT_SENDLATER_TICK 200 + +class CSendLaterJob { + +public: + /* + * job status/error codes + */ + enum { + INVALID_CONTACT = 'I', + JOB_DEFERRED = 'D', + JOB_AGE = 'O', + JOB_MYSTATUS = 'M', + JOB_STATUS = 'S', + JOB_WAITACK = 'A', + JOB_REMOVABLE = 'R', + JOB_HOLD = 'H', + }; + /* + * internal flags + */ + enum { + SLF_SUSPEND = 1, + SLF_INVALID = 2 + }; + void readFlags(); + void writeFlags(); + void cleanDB(); + bool isPersistentJob(); + bool mustDelete(); + CSendLaterJob(); + ~CSendLaterJob(); + char szId[20]; // database key name (time stamp of original send) + HANDLE hContact; // original contact where the message has been assigned + HANDLE hTargetContact; // *real* contact (can be different for metacontacts, e.g). + HANDLE hProcess; // returned from the protocols sending service. needed to find it in the ACK handler + time_t created; // job was created at this time (important to kill jobs, that are too old) + time_t lastSent; // time at which the delivery was initiated. used to handle timeouts + char *sendBuffer; // utf-8 send buffer + PBYTE pBuf; // conventional send buffer (for non-utf8 protocols) + DWORD dwFlags; + int iSendCount; // # of times we tried to send it... + bool fSuccess, fFailed; + BYTE bCode; // error/progress code (for the UI) +}; + +typedef std::vector::iterator SendLaterJobIterator; + +class CSendLater { + +public: + enum { + SENDLATER_AGE_THRESHOLD = (86400 * 3), // 3 days, older messages will be removed from the db. + SENDLATER_RESEND_THRESHOLD = 180, // timeouted messages should be resent after that many seconds + SENDLATER_PROCESS_INTERVAL = 50 // process the list of waiting job every this many seconds + }; + + CSendLater(); + ~CSendLater(); + bool isAvail() const { return(m_fAvail); } + bool isInteractive() const { return(m_fIsInteractive); } + bool isJobListEmpty() const { return(m_sendLaterJobList.empty() ? true : false); } + bool haveErrorPopups() const { return(m_fErrorPopups); } + bool haveSuccessPopups() const { return(m_fSuccessPopups); } + void startJobListProcess(); + time_t lastProcessed() const { return(m_last_sendlater_processed); } + void setLastProcessed(const time_t _t) { m_last_sendlater_processed = _t; } + void flushQueue() { m_last_sendlater_processed = 0; } + bool haveJobs() const + { + if (m_sendLaterJobList.empty() || m_jobIterator == m_sendLaterJobList.end()) + return(false); + else + return(true); + } + bool processCurrentJob(); + void processContacts(); + int addJob(const char *szSetting, LPARAM lParam); + void addContact(const HANDLE hContact); + static int _cdecl addStub(const char *szSetting, LPARAM lParam); + HANDLE processAck(const ACKDATA *ack); + + void invokeQueueMgrDlg(); + void qMgrUpdate(bool fReEnable = false); + static INT_PTR svcQMgr(WPARAM wParam, LPARAM lParam); + +private: + void processSingleContact(const HANDLE hContact); + int sendIt(CSendLaterJob *job); + + INT_PTR CALLBACK DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK DlgProcStub(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + void qMgrFillList(bool fClear = true); + void qMgrSetupColumns(); + void qMgrSaveColumns(); + LRESULT qMgrAddFilter(const HANDLE hContact, const TCHAR* tszNick); + + std::vector m_sendLaterContactList; + std::vector m_sendLaterJobList; + bool m_fAvail; + bool m_fIsInteractive; + bool m_fErrorPopups; + bool m_fSuccessPopups; + time_t m_last_sendlater_processed; + SendLaterJobIterator m_jobIterator; + + HWND m_hwndDlg; + HWND m_hwndList, m_hwndFilter; + HANDLE m_hFilter; // contact handle to filter the qmgr list (0 = no filter, show all) + LRESULT m_sel; // index of the combo box entry corresponding to the contact filter; +}; + +extern CSendLater* sendLater; + +#endif /* __SENDLATER_H */ diff --git a/plugins/TabSRMM/src/include/sendqueue.h b/plugins/TabSRMM/src/include/sendqueue.h new file mode 100644 index 0000000000..8fdb8205d7 --- /dev/null +++ b/plugins/TabSRMM/src/include/sendqueue.h @@ -0,0 +1,123 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +$Id: sendqueue.h 12065 2010-06-25 17:30:24Z silvercircle $ + +*/ + +#ifndef __SENDQUEUE_H +#define __SENDQUEUE_H + +#define TIMERID_MSGSEND 100 +#define TIMERID_TYPE 3 +#define TIMERID_AWAYMSG 4 +//#define TIMERID_TOOLTIP 5 +#define TIMEOUT_TYPEOFF 10000 // send type off after 10 seconds of inactivity +#define SB_CHAR_WIDTH 45 +#define SEND_FLAGS PREF_UNICODE + +/* + * send flags + */ + +#define SENDJOBS_MAX_SENDS 100 + +struct SendJob { + HANDLE hSendId; + char *sendBuffer; + int dwLen; // actual buffer length (checked for reallocs() + int iSendLength; // length of message in utf-8 octets (used to check maxlen) + int sendCount; + HANDLE hOwner; + HWND hwndOwner; + unsigned int iStatus; + TCHAR szErrorMsg[128]; + DWORD dwFlags; + int iAcksNeeded; + HANDLE hEventSplit; + int chunkSize; + DWORD dwTime; +}; + +class SendQueue { +public: + enum { + NR_SENDJOBS = 30, + SQ_ERROR = 2, + SQ_INPROGRESS = 1, + SQ_UNDEFINED = 0 + }; + + SendQueue() + { + ZeroMemory(m_jobs, (sizeof(SendJob) * NR_SENDJOBS)); + m_currentIndex = 0; + } + + void inc() { m_currentIndex++; } + void dec() { m_currentIndex--; } + + ~SendQueue() + { + for (int i = 0; i < NR_SENDJOBS; i++) { + if (m_jobs[i].sendBuffer) + free(m_jobs[i].sendBuffer); + } + } + + SendJob *getJobByIndex(const int index) { return(&m_jobs[index]); } + + void clearJob (const int index); + int findNextFailed (const TWindowData *dat) const; + void handleError (TWindowData *dat, const int iEntry) const; + int addTo (TWindowData *dat, const int iLen, int dwFlags); + int sendQueued (TWindowData *dat, const int iEntry); + int getSendLength (const int iEntry, const int sendMode); + void checkQueue (const TWindowData *dat) const; + void logError (const TWindowData *dat, int iSendJobIndex, + const TCHAR *szErrMsg) const; + void recallFailed (const TWindowData *dat, int iEntry) const; + void showErrorControls (TWindowData *dat, const int showCmd) const; + int ackMessage (TWindowData *dat, WPARAM wParam, LPARAM lParam); + int doSendLater (int iIndex, TWindowData *dat, HANDLE hContact = 0, bool fIsSendLater = true); + /* + * static members + */ + static int TSAPI RTL_Detect (const wchar_t *pszwText); + static char* TSAPI MsgServiceName (const HANDLE hContact, const TWindowData *dat, int isUnicode); + static int TSAPI GetProtoIconFromList (const char *szProto, int iStatus); + static LRESULT TSAPI WarnPendingJobs (unsigned int uNrMessages); + static void TSAPI NotifyDeliveryFailure (const TWindowData *dat); + static void TSAPI UpdateSaveAndSendButton (TWindowData *dat); + static void TSAPI EnableSending (const TWindowData *dat, const int iMode); +private: + SendJob m_jobs[NR_SENDJOBS]; + int m_currentIndex; +}; + +extern SendQueue *sendQueue; + +int TSAPI ActivateExistingTab (TContainerData *pContainer, HWND hwndChild); +void TSAPI ShowMultipleControls (const HWND hwndDlg, const UINT * controls, int cControls, int state); +void TSAPI HandleIconFeedback (TWindowData *dat, HICON iIcon); + +#endif /* __SENDQUEUE_H */ diff --git a/plugins/TabSRMM/src/include/sidebar.h b/plugins/TabSRMM/src/include/sidebar.h new file mode 100644 index 0000000000..415b96c5ac --- /dev/null +++ b/plugins/TabSRMM/src/include/sidebar.h @@ -0,0 +1,239 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: sidebar.h 11744 2010-05-13 20:34:30Z silvercircle $ + * + * the contact switch bar on the left (or right) side + * + */ + +#ifndef __SIDEBAR_H +#define __SIDEBAR_H + +struct TSideBarNotify { + NMHDR nmHdr; + const TWindowData* dat; +}; +/* layout descrtiption structure */ + +struct TSideBarLayout { + TCHAR szName[50]; // everything wants a name... + LONG width; // width of the switchbar element (a single button) + LONG height; // height of a single switchbar element + DWORD dwFlags; // flags, obviously :) + + /* + * the following 4 items define pointers to the actual renderer functions for that sidebar layout + * a default is always provided, however, it has been designed to be easily extendible without + * rewriting lots of code just in order to change how the switchbar items look like. + */ + void (__fastcall *pfnContentRenderer)(const HDC hdc, const RECT *rc, const CSideBarButton *item); + void (__fastcall *pfnBackgroundRenderer)(const HDC hdc, const RECT *rc, const CSideBarButton *item); + const SIZE& (__fastcall *pfnMeasureItem)(CSideBarButton *item); + void (__fastcall *pfnLayout)(const CSideBar *sideBar, RECT *rc); + UINT uId; // numeric id by which the layout is identified. basically, the index into the array. +}; + +class CSideBar; + +class CSideBarButton +{ +public: + CSideBarButton(const UINT id, CSideBar *sideBar); + CSideBarButton(const TWindowData *dat, CSideBar *sideBar); + ~CSideBarButton(); + + LONG getHeight() const { return(m_sz.cy); } + const SIZE& getSize() const { return(m_sz); } + void setSize(const SIZE& newSize){ m_sz = newSize; } + const bool isTopAligned() const { return(m_isTopAligned); } + const HWND getHwnd() const { return(m_hwnd); } + const UINT getID() const { return(m_id); } + const HANDLE getContactHandle() const { return(m_dat->hContact); } + const TWindowData* getDat() const { return(m_dat); } + const TSideBarLayout* getLayout() const { return(m_sideBarLayout); } + + void RenderThis (const HDC hdc) const; + void renderIconAndNick (const HDC hdc, const RECT *rcItem) const; + int testCloseButton() const; + void Show(const int showCmd) const; + void activateSession() const; + const SIZE& measureItem(); + void setLayout(const TSideBarLayout *newLayout); + void invokeContextMenu(); + +public: + CSideBar* m_sideBar; + const MButtonCtrl* m_buttonControl; // private data struct of the Win32 button object +private: + void _create(); +private: + const TSideBarLayout* m_sideBarLayout; + HWND m_hwnd; // window handle for the TSButton object + const TWindowData* m_dat; // session data + UINT m_id; // control id + bool m_isTopAligned; + SIZE m_sz; +}; + +typedef std::vector::iterator ButtonIterator; + +class CSideBar +{ +public: + enum { + NR_LAYOUTS = 4 + }; + + enum { + /* layout ids. index into m_layouts[] */ + + SIDEBARLAYOUT_VERTICAL = 0, + SIDEBARLAYOUT_NORMAL = 1, + SIDEBARLAYOUT_COMPLEX = 2, + SIDEBARLAYOUT_LARGE = 3, + + /* flags */ + + SIDEBARORIENTATION_LEFT = 8, + SIDEBARORIENTATION_RIGHT = 16, + + SIDEBARLAYOUT_DYNHEIGHT = 32, + SIDEBARLAYOUT_VERTICALORIENTATION = 64, + SIDEBARLAYOUT_NOCLOSEBUTTONS = 128 + }; + + enum { + SIDEBAR_GAP = 2 // gap between sidebar container window and content tab sheet border + }; + + CSideBar(TContainerData *pContainer); + ~CSideBar(); + + void Init (const bool fForce = false); + void addSession (const TWindowData *dat, int position = -1); + HRESULT removeSession (const TWindowData *dat); + void updateSession (const TWindowData *dat); + + void processScrollerButtons (UINT cmd); + void Layout (const RECT *rc = 0, bool fOnlyCalc = false); + void setVisible (bool fNewVisibility); + void showAll (int showCmd); + + const LONG getWidth() const { return(m_isVisible ? m_width + SIDEBAR_GAP : 0); } + const DWORD getFlags() const { return(m_dwFlags); } + const TContainerData* getContainer() const { return(m_pContainer); } + const bool isActive() const { return(m_isActive); } + const bool isVisible() const { return(m_isVisible); } + const CSideBarButton* getActiveItem() const { return(m_activeItem); } + const CSideBarButton* getScrollUp() const { return(m_up); } + const CSideBarButton* getScrollDown() const { return(m_down); } + bool isSkinnedContainer() const { return(CSkin::m_skinEnabled ? true : false); } + const UINT getLayoutId() const { return(m_uLayout); } + void invalidateButton (const TWindowData* dat); + + const CSideBarButton* setActiveItem (const CSideBarButton *newItem) + { + CSideBarButton *oldItem = m_activeItem; + m_activeItem = const_cast(newItem); + if (oldItem) + ::InvalidateRect(oldItem->getHwnd(), NULL, FALSE); + ::InvalidateRect(m_activeItem->getHwnd(), NULL, FALSE); + scrollIntoView(m_activeItem); + return(oldItem); + } + /** + * this item has its close button currently hovered + * @param item: the CSideBarButton* which is hovered + */ + void setHoveredClose (CSideBarButton* item) + { + m_hoveredClose = item; + } + HWND getScrollWnd() const { return(m_hwndScrollWnd); } + const CSideBarButton* getHoveredClose() const { return(m_hoveredClose); } + const CSideBarButton* setActiveItem (const TWindowData *dat); + + static const TSideBarLayout* getLayouts (int& uLayoutCount) + { + uLayoutCount = NR_LAYOUTS; + return(m_layouts); + } + void scrollIntoView (const CSideBarButton *item = 0); + void resizeScrollWnd (LONG x, LONG y, LONG width, LONG height) const; + static LRESULT CALLBACK wndProcStub (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +private: + void createScroller(); + void destroyScroller(); + void populateAll(); + void removeAll(); + void Invalidate(); + ButtonIterator findSession (const TWindowData *dat); + ButtonIterator findSession (const HANDLE hContact); + + LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +private: + HWND m_hwndScrollWnd; + std::vector m_buttonlist; // our list of buttons + TContainerData* m_pContainer; // our master and commander... + LONG m_width; // required width of the bar (m_elementWidth + padding) + DWORD m_dwFlags; + CSideBarButton* m_up, *m_down; // the scroller buttons (up down) + CSideBarButton* m_activeItem; // active button item (for highlighting) + const CSideBarButton* m_hoveredClose; // item which must display an active close button + LONG m_topHeight, m_bottomHeight; + LONG m_firstVisibleOffset, m_totalItemHeight; + int m_iTopButtons, m_iBottomButtons; + LONG m_elementHeight, m_elementWidth; // width / height for a single element. + // can be dynamic (see measeureItem() in CSideBarButtonItem + bool m_isActive; // the sidebar is active (false, if it does _nothing at all_ + bool m_isVisible; // visible aswell (not collapsed) + TSideBarLayout* m_currentLayout; // the layout in use. will be passed to new button items + UINT m_uLayout; // layout id number, currently in use + +private: + /* + * layouts. m_layouts[] is static and contains layout descriptions + * renderer functions are static aswell + */ + static TSideBarLayout m_layouts[NR_LAYOUTS]; + static void __fastcall m_DefaultBackgroundRenderer(const HDC hdc, const RECT *rc, const CSideBarButton *item); + static void __fastcall m_DefaultContentRenderer(const HDC hdc, const RECT *rc, const CSideBarButton *item); + static void __fastcall m_AdvancedContentRenderer(const HDC hdc, const RECT *rc, const CSideBarButton *item); + + static const SIZE& __fastcall m_measureAdvancedVertical(CSideBarButton *item); +}; + +inline void CSideBarButton::setLayout(const TSideBarLayout *newLayout) +{ + m_sideBarLayout = newLayout; +} + +#endif diff --git a/plugins/TabSRMM/src/include/taskbar.h b/plugins/TabSRMM/src/include/taskbar.h new file mode 100644 index 0000000000..9267f6a76a --- /dev/null +++ b/plugins/TabSRMM/src/include/taskbar.h @@ -0,0 +1,197 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: taskbar.h 12227 2010-07-23 16:57:25Z silvercircle $ + * + * - Windows 7 taskbar integration class + * - Proxy window class, needed to support custom aero peek tab + * thumbnails + * - Thumbnail classes to provide task bar thumbnails for Aero peek + * preview. + */ + +#ifndef __TASKBAR_H +#define __TASKBAR_H + +#define PROXYCLASSNAME _T("TabSRMM_DWMProxy") +extern HINSTANCE g_hInst; + +class CProxyWindow; + +class CThumbBase { +public: + CThumbBase (const CProxyWindow* pWnd); + virtual ~CThumbBase (); + + const HBITMAP getHBM () const { return(m_hbmThumb); } + const bool isValid () const { return(m_isValid); } + virtual void setValid (const bool fNewValid) { m_isValid = fNewValid; } + virtual void update () = 0; + +protected: + HBITMAP m_hbmThumb, m_hbmOld; + const TWindowData* m_dat; + LONG m_width, m_height; + HDC m_hdc; + const CProxyWindow* m_pWnd; + RECT m_rc, m_rcTop, m_rcBottom, m_rcIcon; + DWORD m_dtFlags; + SIZE m_sz; + LONG m_cx, m_cy; + HFONT m_hOldFont; + + virtual void renderBase (); + +private: + virtual void renderContent () = 0; + void setupRect (); + +private: + bool m_isValid; +}; + +class CThumbIM : public CThumbBase { + +public: + CThumbIM (const CProxyWindow* pWnd); + virtual ~CThumbIM () {}; + void update (); + +private: + void renderContent (); +}; + +class CThumbMUC : public CThumbBase { + +public: + CThumbMUC (const CProxyWindow* pWnd); + virtual ~CThumbMUC () {}; + void update (); + +private: + void renderContent (); +}; + +class CProxyWindow +{ +public: + CProxyWindow(const TWindowData *dat); + ~CProxyWindow(); + + void updateIcon (const HICON hIcon) const; + void updateTitle (const TCHAR *tszTitle) const; + void setBigIcon (const HICON hIcon, bool fInvalidate = true); + void setOverlayIcon (const HICON hIcon, bool fInvalidate = true); + void activateTab () const; + void Invalidate () const; + const TWindowData* getDat () const { return(m_dat); } + const LONG getWidth () const { return(m_width); } + const LONG getHeight () const { return(m_height); } + const HWND getHwnd () const { return(m_hwndProxy); } + const HICON getBigIcon () const { return(m_hBigIcon); } + const HICON getOverlayIcon () const { return(m_hOverlayIcon); } + void verifyDwmState (); + + static LRESULT CALLBACK stubWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + static void add (TWindowData *dat); + static void verify (TWindowData *dat); + +private: + const TWindowData* m_dat; + HWND m_hwndProxy; + LONG m_width, m_height; + HICON m_hBigIcon, m_hOverlayIcon; + + LRESULT CALLBACK wndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + void sendThumb (LONG width, LONG height); + void sendPreview (); + CThumbBase* m_thumb; +}; + +class CTaskbarInteract +{ +public: + CTaskbarInteract() + { + m_pTaskbarInterface = 0; + m_IconSize = 0; + m_isEnabled = IsWinVer7Plus() ? true : false; + + if (m_isEnabled) { + ::CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL, IID_ITaskbarList3, (void**)&m_pTaskbarInterface); + updateMetrics(); + if (0 == m_pTaskbarInterface) + m_isEnabled = false; + } + + /* + * register proxy window class + */ + WNDCLASSEX wcex = {0}; + wcex.cbSize = sizeof(wcex); + wcex.lpfnWndProc = CProxyWindow::stubWndProc; + wcex.hInstance = g_hInst; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszClassName = PROXYCLASSNAME; + ::RegisterClassEx(&wcex); + } + + ~CTaskbarInteract() + { + if (m_isEnabled && m_pTaskbarInterface) { + m_pTaskbarInterface->Release(); + m_pTaskbarInterface = 0; + m_isEnabled = false; + } + ::UnregisterClass(PROXYCLASSNAME, g_hInst); + } + const LONG getIconSize () const { return(m_IconSize); } + const bool haveAlwaysGroupingMode () const { return(m_fHaveAlwaysGrouping); } + + bool setOverlayIcon (HWND hwndDlg, LPARAM lParam) const; + void clearOverlayIcon (HWND hwndDlg) const; + bool haveLargeIcons (); + LONG updateMetrics (); + void registerTab (const HWND hwndTab, const HWND hwndContainer) const; + void unRegisterTab (const HWND hwndTab) const; + void SetTabActive (const HWND hwndTab, const HWND hwndGroup) const; + + //const TCHAR* getFileNameFromWindow (const HWND hWnd); +private: + bool m_isEnabled; + ITaskbarList3* m_pTaskbarInterface; + bool m_fHaveLargeicons; + bool m_fHaveAlwaysGrouping; + LONG m_IconSize; +}; + +extern CTaskbarInteract* Win7Taskbar; + +#endif /* __TASKBAR_H */ + diff --git a/plugins/TabSRMM/src/include/templates.h b/plugins/TabSRMM/src/include/templates.h new file mode 100644 index 0000000000..c2b84b1cbd --- /dev/null +++ b/plugins/TabSRMM/src/include/templates.h @@ -0,0 +1,50 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright 2000-2003 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. + +$Id: templates.h 11044 2009-12-11 09:16:30Z silvercircle $ + +templates for the message log... + +*/ + +struct TemplateEditorInfo { + BOOL rtl; + BOOL changed; // template in edit field is changed + BOOL selchanging; + int inEdit; // template currently in editor + BOOL updateInfo[TMPL_ERRMSG + 1]; // item states... + HWND hwndParent; + HANDLE hContact; +}; + +struct TemplateEditorNew { + HANDLE hContact; + BOOL rtl; + HWND hwndParent; +}; + +BOOL CALLBACK DlgProcTemplateEdit(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +static void LoadTemplatesFrom(TTemplateSet *tSet, HANDLE hContact, int rtl); +void LoadDefaultTemplates(); + +#define DM_UPDATETEMPLATEPREVIEW (WM_USER + 50) + diff --git a/plugins/TabSRMM/src/include/themes.h b/plugins/TabSRMM/src/include/themes.h new file mode 100644 index 0000000000..ca899ffdb7 --- /dev/null +++ b/plugins/TabSRMM/src/include/themes.h @@ -0,0 +1,415 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: themes.h 11997 2010-06-14 20:12:34Z silvercircle $ + * + * The class CSkin implements the skinning engine and loads skins from + * their skin definition files (.tsk). + * + * CImageItem implements a single rectangular skin item with an image + * and its rendering. + * + */ + +#ifndef __THEMES_H +#define __THEMES_H + +HBITMAP IMG_LoadLogo(const TCHAR *szName); + +class CSideBarButton; + +typedef struct { + HWND hwnd; + int stateId; // button state + int focus; // has focus (1 or 0) + HFONT hFont; // font + HICON arrow; // uses down arrow + int defbutton; // default button + HICON hIcon, hIconPrivate; + HBITMAP hBitmap; + int pushBtn; + int pbState; + HANDLE hThemeButton; + HANDLE hThemeToolbar; + BOOL bThemed; + BOOL bToolbarButton; // is a toolbar button (important for aero background rendering) + BOOL bTitleButton; + TCHAR cHot; + int flatBtn; + int dimmed; + HICON overlay; + struct TContainerData *pContainer; + CSideBarButton *sitem; +} MButtonCtrl; + +#define BUTTONSETASDIMMED (BUTTONSETASFLATBTN + 11) +#define BUTTONSETCONTAINER (BUTTONSETASFLATBTN + 12) +#define BUTTONSETASTITLE (BUTTONSETASFLATBTN + 13) +#define BUTTONSETASNORMAL (BUTTONSETASFLATBTN + 14) +#define BUTTONGETSTATEID (BUTTONSETASFLATBTN + 15) +#define BUTTONSETASTOOLBARBUTTON (BUTTONSETASFLATBTN + 21) +#define BUTTONSETASSIDEBARBUTTON (BUTTONSETASFLATBTN + 22) +#define BUTTONSETOVERLAYICON (BUTTONSETASFLATBTN + 23) + +struct AeroEffect { + TCHAR tszName[40]; + DWORD m_baseColor; + DWORD m_gradientColor; + BYTE m_baseAlpha; + BYTE m_finalAlpha; + BYTE m_cornerType; + BYTE m_gradientType; + DWORD m_cornerRadius; + DWORD m_glowSize; + COLORREF m_clrBack; + COLORREF m_clrToolbar; + COLORREF m_clrToolbar2; + void (TSAPI *pfnEffectRenderer)(const HDC hdc, const RECT *rc, int iEffectArea); +}; +/** + * CImageItem implementes image-based skin items. These items are loaded + * from a skin file definition (.tsk file) and are then linked to one or + * more skin items. + */ +class CImageItem +{ +public: + CImageItem() + { + ZeroMemory(this, sizeof(CImageItem)); + } + CImageItem(const CImageItem& From) + { + *this = From; + m_nextItem = 0; + } + CImageItem(const TCHAR *szName) + { + ZeroMemory(this, sizeof(CImageItem)); + _sntprintf(m_szName, 40, szName); + m_szName[39] = 0; + } + + CImageItem(BYTE bottom, BYTE left, BYTE top, BYTE right, HDC hdc, HBITMAP hbm, DWORD dwFlags, + HBRUSH brush, BYTE alpha, LONG inner_height, LONG inner_width, LONG height, LONG width) + { + m_bBottom = bottom; + m_bLeft = left, + m_bTop = top; + m_bRight = right; + m_hdc = hdc; + m_hbm = hbm; + m_dwFlags = dwFlags; + m_fillBrush = brush; + m_inner_height = inner_height; + m_inner_width = inner_width; + m_height = height; + m_width = width; + + m_bf.SourceConstantAlpha = alpha; + m_bf.AlphaFormat = 0; + m_bf.BlendOp = AC_SRC_OVER; + m_bf.BlendFlags = 0; + } + ~CImageItem() + { + Free(); + } + + void Clear() + { + m_hdc = 0; m_hbm = 0; m_hbmOld = 0; + m_fillBrush = (HBRUSH)0; + } + + void setBitmap(const HBITMAP hbm) + { + m_hbm = hbm; + } + + void setAlphaFormat(const BYTE bFormat, const BYTE bConstantAlpha) + { + m_bf.AlphaFormat = bFormat; + m_bf.SourceConstantAlpha = bConstantAlpha; + } + + void setMetrics(const LONG width, const LONG height) + { + m_height = height; + m_width = width; + + m_inner_height = m_height - m_bBottom - m_bTop; + m_inner_width = m_width - m_bLeft - m_bRight; + if (!(m_dwFlags & IMAGE_FLAG_DIVIDED)) + m_bStretch = IMAGE_STRETCH_B; + } + + void Free(); + CImageItem* getNextItem() const { return(m_nextItem); } + void setNextItem(CImageItem *item) { m_nextItem = item; } + HBITMAP getHbm() const { return(m_hbm); } + DWORD getFlags() const { return(m_dwFlags); } + HDC getDC() const { return(m_hdc); } + const BLENDFUNCTION& getBF() const + { + const BLENDFUNCTION &bf = m_bf; + return(bf); + } + const TCHAR* getName() const { return (m_szName); } + TCHAR* Read(const TCHAR *szFilename); + void Create(const TCHAR *szImageFile); + void __fastcall Render(const HDC hdc, const RECT *rc, bool fIgnoreGlyph) const; + static void TSAPI PreMultiply(HBITMAP hBitmap, int mode); + static void TSAPI SetBitmap32Alpha(HBITMAP hBitmap, BYTE bAlpha = 255); + static void TSAPI Colorize(HBITMAP hBitmap, BYTE dr, BYTE dg, BYTE db, BYTE alpha = 0); + static HBITMAP TSAPI LoadPNG(const TCHAR *szFilename); + +public: + bool m_fValid; // verified item, indicates that all parameters are valid +private: + TCHAR m_szName[40]; // everything wants a name, an image item doesn't need one though + HBITMAP m_hbm; // the bitmap handle + BYTE m_bLeft, m_bRight, m_bTop, m_bBottom; // sizing margins for the outer 8 image parts + BYTE m_alpha; // constant alpha for the entire image, applied via m_bf. sums with perpixel alpha + DWORD m_dwFlags; // flags + HDC m_hdc; // *can* hold a pre-created hdc to speed up rendering + HBITMAP m_hbmOld; // old bitmap, needs to be selected into m_hdc before destroying it + LONG m_inner_height, m_inner_width; // dimensions of the inner image part + LONG m_width, m_height; // width and height of the image, in pixels + BLENDFUNCTION m_bf; // for AlphaBlend() + BYTE m_bStretch; // stretch mode (unused in tabSRMM + HBRUSH m_fillBrush; // brush to fill the inner part (faster) dwFlags & IMAGE_FILLSOLID must be set + LONG m_glyphMetrics[4]; // these coordinates point into the glyph image (if IMAGE_GLYPH is set) + CImageItem* m_nextItem; // next item in a set of image items (usually the skin set) +}; + +/** + * Implements the skinning engine. There is only one instance of this class and + * it always holds the currently loaded skin (if any). + */ +class CSkin +{ +public: + enum { + AERO_EFFECT_NONE = 0, + AERO_EFFECT_MILK = 1, + AERO_EFFECT_CARBON = 2, + AERO_EFFECT_SOLID = 3, + AERO_EFFECT_WHITE = 4, + AERO_EFFECT_CUSTOM = 5, + AERO_EFFECT_LAST = 6 + }; + enum { + AERO_EFFECT_AREA_MENUBAR = 0, + AERO_EFFECT_AREA_STATUSBAR = 1, + AERO_EFFECT_AREA_INFOPANEL = 2, + AERO_EFFECT_AREA_TAB_ACTIVE = 3, + AERO_EFFECT_AREA_TAB_HOVER = 4, + AERO_EFFECT_AREA_TAB_NORMAL = 5, + AERO_EFFECT_AREA_SIDEBAR_LEFT = 6, + AERO_EFFECT_AREA_SIDEBAR_RIGHT = 7, + AERO_EFFECT_AREA_TAB_TOP = 0x1000, + AERO_EFFECT_AREA_TAB_BOTTOM = 0x2000 + }; + + enum { + DEFAULT_GLOW_SIZE = 10 + }; + + /* + * avatar border types (skinned mode only) + */ + enum { + AVBORDER_NONE = 0, + AVBORDER_NORMAL = 1, + AVBORDER_ROUNDED = 2 + }; + + CSkin() + { + ZeroMemory(this, sizeof(CSkin)); + m_default_bf.SourceConstantAlpha = 255; + m_default_bf.AlphaFormat = AC_SRC_ALPHA; + m_default_bf.BlendOp = AC_SRC_OVER; + } + + ~CSkin() + { + Unload(); + } + + void Init(bool fStartup = false); + void Load(void); + void Unload(); + void UnloadAeroTabs(); + void setFileName(); + void ReadItem(const int id, const TCHAR *section); + void LoadItems(); + void LoadIcon(const TCHAR *szSection, const TCHAR *name, HICON *hIcon); + void ReadImageItem(const TCHAR *szItemName); + void ReadButtonItem(const TCHAR *itemName) const; + bool haveGlyphItem() const { return(m_fHaveGlyph); } + int getNrIcons() const { return(m_nrSkinIcons); } + const DWORD getDwmColor() const { return(m_dwmColor); } + + const TIconDescW* getIconDesc(const int id) const { return(&m_skinIcons[id]); } + /** + * get the glyph image item (a single PNG image, containing a number of textures + * for the skin. + * + * @return CImageItem&: reference to the glyph item. Cannot be + * modified. + * + */ + const CImageItem* getGlyphItem() const + { + return(m_fHaveGlyph ? &m_glyphItem : 0); + } + bool warnToClose() const; + COLORREF getColorKey() const { return(m_ContainerColorKey); } + + void setupAeroSkins(); + void extractSkinsAndLogo(bool fForceOverwrite = false) const; + void setupTabCloseBitmap(bool fDeleteOnly = false); + + /* + * static member functions + */ + static void TSAPI SkinDrawBGFromDC(HWND hwndClient, HWND hwnd, RECT *rcClient, HDC hdcTarget); + static void TSAPI SkinDrawBG(HWND hwndClient, HWND hwnd, struct TContainerData *pContainer, RECT *rcClient, HDC hdcTarget); + static void TSAPI MY_AlphaBlend(HDC hdcDraw, DWORD left, DWORD top, int width, int height, int bmWidth, int bmHeight, HDC hdcMem); + static void TSAPI DrawDimmedIcon(HDC hdc, LONG left, LONG top, LONG dx, LONG dy, HICON hIcon, BYTE alpha); + static DWORD __fastcall HexStringToLong(const TCHAR *szSource); + static UINT TSAPI DrawRichEditFrame(HWND hwnd, const TWindowData *mwdat, UINT skinID, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC OldWndProc); + static UINT TSAPI NcCalcRichEditFrame(HWND hwnd, const TWindowData *mwdat, UINT skinID, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC OldWndProc); + static HBITMAP TSAPI CreateAeroCompatibleBitmap(const RECT &rc, HDC dc); + static int TSAPI RenderText(HDC hdc, HANDLE hTheme, const TCHAR *szText, RECT *rc, DWORD dtFlags, const int iGlowSize = DEFAULT_GLOW_SIZE, COLORREF clr = 0, bool fForceAero = false); + static void TSAPI MapClientToParent(HWND hwndClient, HWND hwndParent, RECT &rc); + static void TSAPI RenderToolbarBG(const TWindowData *dat, HDC hdc, const RECT &rcWindow); + static HBITMAP TSAPI ResizeBitmap(HBITMAP hBmpSrc, LONG width, LONG height, bool &mustFree); + static void TSAPI ApplyAeroEffect(const HDC hdc, const RECT* rc, int iEffectArea, HANDLE hbp = 0); + static void TSAPI setAeroEffect(const LRESULT effect); + static void TSAPI initAeroEffect(); + static HANDLE TSAPI InitiateBufferedPaint(const HDC hdcSrc, RECT& rc, HDC& hdcOut); + static void TSAPI FinalizeBufferedPaint(HANDLE hbp, RECT *rc); + static bool __fastcall DrawItem(const HDC hdc, const RECT *rc, const CSkinItem *item); + static void TSAPI UpdateToolbarBG(TWindowData* dat, DWORD dwRdwOptFlags = 0); + static void TSAPI FillBack(const HDC hdc, RECT* rc); + +public: + static bool m_DisableScrollbars, m_bClipBorder; + static char m_SkinnedFrame_left, m_SkinnedFrame_right, m_SkinnedFrame_bottom, m_SkinnedFrame_caption; + static char m_realSkinnedFrame_left, m_realSkinnedFrame_right, m_realSkinnedFrame_bottom, m_realSkinnedFrame_caption; + static HPEN m_SkinLightShadowPen, m_SkinDarkShadowPen; + static int m_titleBarLeftOff, m_titleButtonTopOff, m_captionOffset, m_captionPadding, + m_titleBarRightOff, m_sidebarTopOffset, m_sidebarBottomOffset, m_bRoundedCorner; + static SIZE m_titleBarButtonSize; + static int m_bAvatarBorderType; + static COLORREF m_avatarBorderClr, m_tmp_tb_low, m_tmp_tb_high; + static COLORREF m_sideBarContainerBG; + static COLORREF m_ContainerColorKey, m_DefaultFontColor; + static HBRUSH m_ContainerColorKeyBrush, m_MenuBGBrush; + static bool m_skinEnabled; + static bool m_frameSkins; + static HICON m_closeIcon, m_minIcon, m_maxIcon; + static BLENDFUNCTION m_default_bf; // general purpose bf, dynamically modified when needed + + /* + * cached bitmap for tab close button + */ + + static HBITMAP m_tabCloseBitmap, m_tabCloseOldBitmap; + static HDC m_tabCloseHDC; + + /* + * controls the aero effect. Set by initAeroEffect() + */ + + static UINT m_aeroEffect; // effect id, initAeroEffect() is using it to set + // the parameters below. + static AeroEffect m_aeroEffects[AERO_EFFECT_LAST]; + static AeroEffect m_currentAeroEffect; + static AeroEffect* m_pCurrentAeroEffect; + static DWORD m_glowSize; + static HBRUSH m_BrushBack, m_BrushFill; + + static COLORREF m_dwmColorRGB; + + static CImageItem *m_switchBarItem, *m_tabTop, *m_tabBottom, *m_tabGlowTop, *m_tabGlowBottom; + static bool m_fAeroSkinsValid; + +private: + TCHAR m_tszFileName[MAX_PATH]; // full path and filename of the currently loaded skin + CSkinItem* m_SkinItems; + CImageItem* m_ImageItems; // the list of image item objects + CImageItem m_glyphItem; + + bool m_fLoadOnStartup; // load the skin on plugin initialization. + bool m_fHaveGlyph; + void SkinCalcFrameWidth(); + TIconDescW *m_skinIcons; + int m_nrSkinIcons; + DWORD m_dwmColor; + +private: + static void TSAPI AeroEffectCallback_Milk(const HDC hdc, const RECT *rc, int iEffectArea); + static void TSAPI AeroEffectCallback_Carbon(const HDC hdc, const RECT *rc, int iEffectArea); + static void TSAPI AeroEffectCallback_Solid(const HDC hdc, const RECT *rc, int iEffectArea); +}; + +/* + * window data for the tab control window class + */ + +struct TabControlData { + BOOL m_VisualStyles; + HWND hwnd; + DWORD dwStyle; + DWORD cx, cy; + HANDLE hTheme, hThemeButton, hbp; + BYTE m_xpad; + TContainerData *pContainer; + BOOL bDragging; + int iBeginIndex; + int iHoveredCloseIcon; + HWND hwndDrag; + TWindowData *dragDat; + HIMAGELIST himlDrag; + BOOL bRefreshWithoutClip; + BOOL fSavePos; + BOOL fTipActive; + BOOL fAeroTabs; + BOOL fCloseButton; + TWindowData* helperDat; // points to the client data of the active tab + CImageItem* helperItem, *helperGlowItem; // aero ui, holding the skin image for the tabs +}; + +extern CSkin *Skin; + +#endif /* __THEMES_H */ + diff --git a/plugins/TabSRMM/src/include/translator.h b/plugins/TabSRMM/src/include/translator.h new file mode 100644 index 0000000000..61590c6b16 --- /dev/null +++ b/plugins/TabSRMM/src/include/translator.h @@ -0,0 +1,63 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: translator.h 12299 2010-08-10 02:39:36Z silvercircle $ + * + * string handling + * + */ + +#ifndef __STRINGS_H +#define __STRINGS_H + +class CTranslator { + +public: + + /* + * identities for the option trees + */ + + enum { + TREE_MODPLUS = 0, + TREE_NEN = 1, + TREE_MSG = 2, + TREE_LOG = 3, + TREE_TAB = 4, + }; + + CTranslator(); + ~CTranslator(); + + static TOptionListItem* getTree(UINT id); + static TOptionListGroup* getGroupTree(UINT id); +}; + +#endif + + diff --git a/plugins/TabSRMM/src/include/typingnotify.h b/plugins/TabSRMM/src/include/typingnotify.h new file mode 100644 index 0000000000..03fb9851b7 --- /dev/null +++ b/plugins/TabSRMM/src/include/typingnotify.h @@ -0,0 +1,76 @@ +#define UM_SETDLGITEMINT 5674 + +#define TIMEOUT_MINVALUE -1 +#define TIMEOUT_MAXVALUE 99 +#define TIMEOUT_POPUP 1 +#define TIMEOUT_CUSTOM 2 +#define TIMEOUT_PROTO 3 +#define TIMEOUT_PERMANENT 4 +#define COLOR_OWN 1 +#define COLOR_WINDOWS 2 +#define COLOR_POPUP 3 + +#define Module "TypingNotify" + +#define SET_WO "NotWhenFocused" +#define DEF_WO 0 +#define SET_DISABLED "Disabled" +#define DEF_DISABLED 0 +#define SET_TIMEOUT "Timeout" +#define DEF_TIMEOUT 7 +#define SET_TIMEOUT2 "Timeout2" +#define DEF_TIMEOUT2 7 +#define SET_TIMEOUT_MODE "TimeoutMode" +#define DEF_TIMEOUT_MODE TIMEOUT_POPUP +#define SET_TIMEOUT_MODE2 "TimeoutMode2" +#define DEF_TIMEOUT_MODE2 TIMEOUT_POPUP +#define SET_COLOR_MODE "ColorMode" +#define DEF_COLOR_MODE COLOR_OWN +#define SET_ICON_SETID "IconSet" +#define DEF_ICON_SETID 0 +#define SET_SHOWDISABLEMENU "ShowDisableMenu" +#define DEF_SHOWDISABLEMENU 1 +#define SET_ONEPOPUP "OnePopUp" +#define DEF_ONEPOPUP 1 + + +static HANDLE hDisableMenu = NULL; +static HANDLE hPopUpsList = NULL; + +static BYTE OnePopUp; +static BYTE ShowMenu; +static BYTE PopupService=0; +static BYTE StartDisabled; +static BYTE StopDisabled; +static BYTE Disabled; +static BYTE ColorMode; +static BYTE TimeoutMode; +static BYTE TimeoutMode2; +static int Timeout; +static int Timeout2; +static int newTimeout; +static int newTimeout2; +static BYTE newTimeoutMode; +static BYTE newTimeoutMode2; +static BYTE newColorMode; +static TCHAR szStart[128]; +static TCHAR szStop[128]; + +static HANDLE hntfStarted = 0; +static HANDLE hntfStopped = 0; + + +struct colors_s +{ + int res; + char desc[10]; + COLORREF color; +}; + +static struct colors_s colorPicker[4] = +{ + {IDC_TYPEON_BG, "ON_BG", RGB(255,255,255)}, + {IDC_TYPEON_TX, "ON_TX", RGB(0,0,0)}, + {IDC_TYPEOFF_BG, "OFF_BG", RGB(255,255,255)}, + {IDC_TYPEOFF_TX, "OFF_TX", RGB(0,0,0)} +}; diff --git a/plugins/TabSRMM/src/include/utils.h b/plugins/TabSRMM/src/include/utils.h new file mode 100644 index 0000000000..b2f2dab659 --- /dev/null +++ b/plugins/TabSRMM/src/include/utils.h @@ -0,0 +1,268 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: utils.h 12833 2010-09-27 23:45:55Z silvercircle $ + * + * utility functions for TabSRMM + * + */ + +#ifndef __UTILS_H +#define __UTILS_H + +#define RTF_CTABLE_DEFSIZE 8 + +#define RTF_DEFAULT_HEADER _T("{\\rtf1\\ansi\\deff0\\pard\\li%u\\fi-%u\\ri%u\\tx%u") + +#define CNT_KEYNAME "CNTW_Def" +#define CNT_BASEKEYNAME "CNTW_" + +struct TRTFColorTable { + TCHAR szName[10]; + COLORREF clr; + int index; + int menuid; +}; + +static TRTFColorTable _rtf_ctable[] = { + _T("red"), RGB(255, 0, 0), 0, ID_FONT_RED, + _T("blue"), RGB(0, 0, 255), 0, ID_FONT_BLUE, + _T("green"), RGB(0, 255, 0), 0, ID_FONT_GREEN, + _T("magenta"), RGB(255, 0, 255), 0, ID_FONT_MAGENTA, + _T("yellow"), RGB(255, 255, 0), 0, ID_FONT_YELLOW, + _T("cyan"), RGB(0, 255, 255), 0, ID_FONT_CYAN, + _T("black"), 0, 0, ID_FONT_BLACK, + _T("white"), RGB(255, 255, 255), 0, ID_FONT_WHITE, + _T(""), 0, 0, 0 +}; + +class Utils { + +public: + enum { + CMD_CONTAINER = 1, + CMD_MSGDIALOG = 2, + CMD_INFOPANEL = 4, + }; + static int TSAPI FindRTLLocale (TWindowData *dat); + static TCHAR* TSAPI GetPreviewWithEllipsis (TCHAR *szText, size_t iMaxLen); + static TCHAR* TSAPI FilterEventMarkers (TCHAR *wszText); + static const TCHAR* TSAPI FormatRaw (TWindowData *dat, const TCHAR *msg, int flags, BOOL isSent); + static const TCHAR* TSAPI FormatTitleBar (const TWindowData *dat, const TCHAR *szFormat); + static char* TSAPI FilterEventMarkers (char *szText); + static const TCHAR* TSAPI DoubleAmpersands (TCHAR *pszText); + static void TSAPI RTF_CTableInit (); + static void TSAPI RTF_ColorAdd (const TCHAR *tszColname, size_t length); + static void TSAPI CreateColorMap (TCHAR *Text); + static int TSAPI RTFColorToIndex (int iCol); + static int TSAPI ReadContainerSettingsFromDB (const HANDLE hContact, TContainerSettings *cs, const char *szKey = 0); + static int TSAPI WriteContainerSettingsToDB (const HANDLE hContact, TContainerSettings *cs, const char *szKey = 0); + static void TSAPI SettingsToContainer (TContainerData *pContainer); + static void TSAPI ContainerToSettings (TContainerData *pContainer); + static void TSAPI ReadPrivateContainerSettings (TContainerData *pContainer, bool fForce = false); + static void TSAPI SaveContainerSettings (TContainerData *pContainer, const char *szSetting); + static DWORD CALLBACK StreamOut (DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb); + static LRESULT TSAPI CmdDispatcher (UINT uType, HWND hwndDlg, UINT cmd, WPARAM wParam, LPARAM lParam, TWindowData *dat = 0, + TContainerData *pContainer = 0); + static void TSAPI addMenuItem (const HMENU& m, MENUITEMINFO& mii, HICON hIcon, + const TCHAR *szText, UINT uID, UINT pos); + static void TSAPI enableDlgControl (const HWND hwnd, UINT id, BOOL fEnable = 1); + static void TSAPI showDlgControl (const HWND hwnd, UINT id, int showCmd); + static int TSAPI mustPlaySound (const TWindowData *dat); + static HICON TSAPI iconFromAvatar (const TWindowData *dat); + static void TSAPI getIconSize (HICON hIcon, int& sizeX, int& sizeY); + + static void TSAPI extractResource (const HMODULE h, const UINT uID, const TCHAR *tszName, const TCHAR *tszPath, + const TCHAR *tszFilename, bool fForceOverwrite); + static void TSAPI scaleAvatarHeightLimited (const HBITMAP hBm, double& dNewWidth, double& dNewHeight, const LONG maxHeight); + + static AVATARCACHEENTRY* TSAPI loadAvatarFromAVS (const HANDLE hContact); + static void TSAPI sanitizeFilename (wchar_t *tszFilename); + static void TSAPI ensureTralingBackslash (wchar_t *szPathname); + + static void* TSAPI safeAlloc (const size_t size); + static void* TSAPI safeCalloc (const size_t size); + static void* TSAPI safeMirAlloc (const size_t size); + static void* TSAPI safeMirCalloc (const size_t size); + + static HMODULE TSAPI loadSystemLibrary (const wchar_t* szFilename); + + static INT_PTR CALLBACK PopupDlgProcError (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + static const TCHAR* extractURLFromRichEdit (const ENLINK* _e, const HWND hwndRich); + + template static size_t TSAPI CopyToClipBoard(T* _t, const HWND hwndOwner) + { + HGLOBAL hData; + + if (!OpenClipboard(hwndOwner) || _t == 0) + return 0; + + std::basic_string *s = new std::basic_string(_t); + size_t _s = sizeof(T); + size_t i = _s * (s->length() + 1); + + EmptyClipboard(); + hData = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, i); + + CopyMemory((void *)GlobalLock(hData), (void *)_t, i); + GlobalUnlock(hData); + SetClipboardData(_s == sizeof(char) ? CF_TEXT : CF_UNICODETEXT, hData); + CloseClipboard(); + delete s; + return(i); + } + + template static void AddToFileList(T ***pppFiles, int *totalCount, const TCHAR* szFilename) + { + size_t _s = sizeof(T); + + *pppFiles = (T**)mir_realloc(*pppFiles, (++*totalCount + 1) * sizeof(T*)); + (*pppFiles)[*totalCount] = NULL; + + if (_s == 1) + (*pppFiles)[*totalCount-1] = reinterpret_cast(mir_t2a(szFilename)); + else + (*pppFiles)[*totalCount-1] = reinterpret_cast(mir_tstrdup(szFilename)); + + if (GetFileAttributes(szFilename) & FILE_ATTRIBUTE_DIRECTORY) { + WIN32_FIND_DATA fd; + HANDLE hFind; + TCHAR szPath[MAX_PATH]; + + lstrcpy(szPath, szFilename); + lstrcat(szPath, _T("\\*")); + if ((hFind = FindFirstFile(szPath, &fd)) != INVALID_HANDLE_VALUE) { + do { + if (!lstrcmp(fd.cFileName, _T(".")) || !lstrcmp(fd.cFileName, _T(".."))) + continue; + lstrcpy(szPath, szFilename); + lstrcat(szPath, _T("\\")); + lstrcat(szPath, fd.cFileName); + AddToFileList(pppFiles, totalCount, szPath); + } while (FindNextFile(hFind, &fd)); + FindClose(hFind); + } + } + } + + /** + * safe strlen function - do not overflow the given buffer length + * if the buffer does not contain a valid (zero-terminated) string, it + * will return 0. + * + * careful: maxlen must be given in element counts!! + */ + template static size_t safe_strlen(const T* src, const size_t maxlen = 0) + { + size_t s = 0; + + while(s < maxlen && *(src++)) + s++; + + if (s >= maxlen && *src != 0) + return 0; + else + return(s); + } + +public: + static TRTFColorTable* rtf_ctable; + static int rtf_ctable_size; +}; + +LRESULT TSAPI _dlgReturn(HWND hWnd, LRESULT result); + + + +/** + * implement a warning dialog with a "do not show this again" check + * box + */ + +class CWarning { + +public: + /* + * the warning IDs + */ + enum { + WARN_RELNOTES = 0, + WARN_ICONPACK_VERSION = 1, + WARN_EDITUSERNOTES = 2, + WARN_ICONPACKMISSING = 3, + WARN_AEROPEEK_SKIN = 4, + WARN_CHAT_ENABLED = 5, + WARN_SENDFILE = 6, + WARN_HPP_APICHECK = 7, + WARN_NO_SENDLATER = 8, + WARN_CLOSEWINDOW = 9, + WARN_OPTION_CLOSE = 10, + WARN_THEME_OVERWRITE = 11, + WARN_LAST = 12 + }; + + /* + * the flags (low word is reserved for default windows flags like MB_OK etc. + */ + + enum { + CWF_UNTRANSLATED = 0x00010000, // do not translate the msg (useful for some error messages) + CWF_NOALLOWHIDE = 0x00020000 // critical message, hide the "do not show this again" check box + }; + + CWarning(const wchar_t* tszTitle, const wchar_t* tszText, const UINT uId, const DWORD dwFlags); + ~CWarning(); + +public: + /* + * static function to construct and show the dialog, returns the + * user's choice + */ + static LRESULT show (const int uId, DWORD dwFlags = 0, const wchar_t* tszTxt = 0); + static void destroyAll (); + LRESULT ShowDialog () const; + +private: + std::basic_string* m_szTitle; + std::basic_string* m_szText; + UINT m_uId; + HFONT m_hFontCaption; + DWORD m_dwFlags; + HWND m_hwnd; + bool m_fIsModal; + + INT_PTR CALLBACK dlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + //void resize () const; + static INT_PTR CALLBACK stubDlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static __int64 getMask (); // get bit mask for disabled message classes + +private: + static HANDLE hWindowList; +}; + +#endif /* __UTILS_H */ diff --git a/plugins/TabSRMM/src/include/version.h b/plugins/TabSRMM/src/include/version.h new file mode 100644 index 0000000000..4390ed33dc --- /dev/null +++ b/plugins/TabSRMM/src/include/version.h @@ -0,0 +1,15 @@ +#define VER_PLAIN "3,1,99,8" +#define _VER_MAJOR 3 +#define _VER_MINOR 1 +#define _VER_REVISION 99 +#define _VER_BUILD 8 + +#if defined(_WIN64) + #define RES_FILE_DESC "TabSRMM (Unicode) x86_amd64" + #define ADDONS_UPDATE_URL "http://miranda-ng.org/" + #define ADDONS_DL_URL "http://miranda-ng.org/distr/x64/Plugins/tabsrmm.zip" +#else + #define RES_FILE_DESC "TabSRMM (Unicode) x86" + #define ADDONS_UPDATE_URL "http://miranda-ng.org/" + #define ADDONS_DL_URL "http://miranda-ng.org/distr/x32/Plugins/tabsrmm.zip" +#endif diff --git a/plugins/TabSRMM/src/modplus.cpp b/plugins/TabSRMM/src/modplus.cpp new file mode 100644 index 0000000000..3e9865f5f5 --- /dev/null +++ b/plugins/TabSRMM/src/modplus.cpp @@ -0,0 +1,276 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: modplus.cpp 11848 2010-05-27 14:57:22Z silvercircle $ + * + * implements features of the tabSRMM "MADMOD" patch, developed by + * Mad Cluster in May 2008 + * + * the "mad mod" patch added the following features: + * + * ) typing sounds + * ) support for animated avatars through ACC (avs) + * ) a fully customizable tool bar providing services useable by external plugins + * to add and change buttons + * ) toolbar on the bottom + * ) image tag button + * ) client icon in status bar + * ) close tab/window on send and the "hide container feature" + * ) bug fixes + * + */ + +#include "commonheaders.h" + +static HANDLE hEventCBButtonPressed,hEventCBInit, hEventDbOptionsInit, hEventDbPluginsLoaded; + +int g_bStartup=0; + +BOOL g_bIMGtagButton; + +static char* getMirVer(HANDLE hContact) +{ + char *szProto = NULL; + char *msg = NULL; + DBVARIANT dbv = {0}; + + szProto = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if ( !szProto ) + return (NULL); + + if ( !DBGetContactSettingString(hContact, szProto, "MirVer", &dbv)) { + msg=mir_strdup(dbv.pszVal); + DBFreeVariant(&dbv); + } + return (msg); +} + +static TCHAR* getMenuEntry(int i) { + TCHAR *msg = NULL; + char MEntry[256] = {'\0'}; + DBVARIANT dbv = {0}; + + mir_snprintf(MEntry, 255, "MenuEntry_%u", i); + if ( !M->GetTString(NULL, "tabmodplus",MEntry, &dbv)) { + msg = mir_tstrdup(dbv.ptszVal); + DBFreeVariant(&dbv); + } + return (msg); +} + +int ChangeClientIconInStatusBar(const TWindowData *dat) +{ + if (!ServiceExists(MS_FP_GETCLIENTICON)) + return(S_FALSE); + + char *msg = getMirVer(dat->hContact); + + if ( !msg ) + return (S_FALSE); + + StatusIconData sid = {0}; + + sid.cbSize = sizeof(sid); + sid.szModule = (char *)"tabmodplus"; + sid.hIcon = sid.hIconDisabled = dat->hClientIcon; + sid.dwId = 1; + sid.szTooltip = msg; + sid.flags = MBF_OWNERSTATE; + CallService(MS_MSG_MODIFYICON,(WPARAM)dat->hContact, (LPARAM)&sid); + mir_free(msg); + return (S_OK); +} + + +int ModPlus_PreShutdown(WPARAM wparam, LPARAM lparam) +{ + if ( hEventCBButtonPressed ) + UnhookEvent(hEventCBButtonPressed); + if ( hEventCBInit ) + UnhookEvent(hEventCBInit); + UnhookEvent(hEventDbPluginsLoaded); + UnhookEvent(hEventDbOptionsInit); + + return (0); +} + +static int RegisterCustomButton(WPARAM wParam,LPARAM lParam) +{ + if ( ServiceExists(MS_BB_ADDBUTTON)) { + BBButton bbd = {0}; + bbd.cbSize = sizeof(BBButton); + bbd.bbbFlags = BBBF_ISIMBUTTON|BBBF_ISLSIDEBUTTON|BBBF_ISPUSHBUTTON; + bbd.dwButtonID = 1; + bbd.dwDefPos =200; + bbd.hIcon = PluginConfig.g_buttonBarIconHandles[3]; + bbd.pszModuleName = (char *)"Tabmodplus"; + bbd.ptszTooltip = TranslateT("Insert [img] tag / surround selected text with [img][/img]"); + + return (CallService(MS_BB_ADDBUTTON, 0, (LPARAM)&bbd)); + } + return (1); +} + +static int CustomButtonPressed(WPARAM wParam,LPARAM lParam) +{ + CustomButtonClickData *cbcd=(CustomButtonClickData *)lParam; + + CHARRANGE cr; + TCHAR* pszMenu[256]={0};//=NULL; + int i=0; + TCHAR* pszText = (TCHAR *)_T(""); + TCHAR* pszFormatedText=NULL; + UINT textlenght=0; + BBButton bbd={0}; + + int state=0; + + if ( strcmp(cbcd->pszModule,"Tabmodplus")||cbcd->dwButtonId!=1 ) return (0); + + bbd.cbSize=sizeof(BBButton); + bbd.dwButtonID=1; + bbd.pszModuleName = (char *)"Tabmodplus"; + CallService(MS_BB_GETBUTTONSTATE, wParam, (LPARAM)&bbd); + + cr.cpMin = cr.cpMax = 0; + SendDlgItemMessage(cbcd->hwndFrom,IDC_MESSAGE, EM_EXGETSEL, 0, (LPARAM)&cr); + textlenght=cr.cpMax-cr.cpMin; + if ( textlenght ) { + pszText = (TCHAR *)mir_alloc((textlenght+1)*sizeof(TCHAR)); + ZeroMemory(pszText,(textlenght+1)*sizeof(TCHAR)); + SendDlgItemMessage(cbcd->hwndFrom, IDC_MESSAGE,EM_GETSELTEXT, 0, (LPARAM)pszText); + } + + if ( cbcd->flags & BBCF_RIGHTBUTTON ) + state=1; + else if ( textlenght ) + state = 2; + else if ( bbd.bbbFlags & BBSF_PUSHED ) + state = 3; + else + state = 4; + + switch ( state ) { + case 1: + { + int res=0; + int menunum; + int menulimit; + HMENU hMenu=NULL; + + menulimit = M->GetByte("tabmodplus","MenuCount", 0); + if ( menulimit ) { + hMenu = CreatePopupMenu(); + //pszMenu=malloc(menulimit*sizeof(TCHAR*)); + } else break; + for ( menunum=0;menunumpt.x, cbcd->pt.y, 0, cbcd->hwndFrom, NULL); + if ( res==0 ) break; + + pszFormatedText = (TCHAR *)mir_alloc((textlenght+lstrlen(pszMenu[res-1])+2)*sizeof(TCHAR)); + ZeroMemory(pszFormatedText,(textlenght+lstrlen(pszMenu[res-1])+2)*sizeof(TCHAR)); + + mir_sntprintf(pszFormatedText,(textlenght+lstrlen(pszMenu[res-1])+2)*sizeof(TCHAR),pszMenu[res-1],pszText); + + }break; + case 2: + { + pszFormatedText = (TCHAR *)mir_alloc((textlenght+12)*sizeof(TCHAR)); + ZeroMemory(pszFormatedText,(textlenght+12)*sizeof(TCHAR)); + + SendDlgItemMessage(cbcd->hwndFrom, IDC_MESSAGE,EM_GETSELTEXT, 0, (LPARAM)pszText); + mir_sntprintf(pszFormatedText,(textlenght+12)*sizeof(TCHAR),_T("[img]%s[/img]"),pszText); + + bbd.ptszTooltip=0; + bbd.hIcon=0; + bbd.bbbFlags=BBSF_RELEASED; + CallService(MS_BB_SETBUTTONSTATE, wParam, (LPARAM)&bbd); + }break; + + case 3: + { + pszFormatedText = (TCHAR *)mir_alloc(6*sizeof(TCHAR)); + ZeroMemory(pszFormatedText,6*sizeof(TCHAR)); + + _sntprintf(pszFormatedText,6*sizeof(TCHAR),_T("%s"),_T("[img]")); + + bbd.ptszTooltip = TranslateT("Insert [img] tag / surround selected text with [img][/img]"); + CallService(MS_BB_SETBUTTONSTATE, wParam, (LPARAM)&bbd); + + }break; + case 4: + { + + pszFormatedText = (TCHAR *)mir_alloc(7*sizeof(TCHAR)); + ZeroMemory(pszFormatedText,7*sizeof(TCHAR)); + _sntprintf(pszFormatedText,7*sizeof(TCHAR),_T("%s"),_T("[/img]")); + + bbd.ptszTooltip = TranslateT("Insert [img] tag / surround selected text with [img][/img]"); + CallService(MS_BB_SETBUTTONSTATE, wParam, (LPARAM)&bbd); + + }break; + } + + while ( pszMenu[i] ) { + mir_free(pszMenu[i]); + i++; + } + + if ( pszFormatedText ) SendDlgItemMessage(cbcd->hwndFrom, IDC_MESSAGE, EM_REPLACESEL, TRUE, (LPARAM)pszFormatedText); + + if ( textlenght ) mir_free(pszText); + if ( pszFormatedText ) mir_free(pszFormatedText); + return (1); + +} + +#define MBF_OWNERSTATE 0x04 + +int ModPlus_Init(WPARAM wparam,LPARAM lparam) +{ + g_bStartup = 1; + + hEventCBButtonPressed=HookEvent(ME_MSG_BUTTONPRESSED,CustomButtonPressed); + hEventCBInit=HookEvent(ME_MSG_TOOLBARLOADED,RegisterCustomButton); + + if (PluginConfig.g_bClientInStatusBar&&ServiceExists(MS_MSG_ADDICON)) { + StatusIconData sid = {0}; + sid.cbSize = sizeof(sid); + sid.szModule = (char *)"tabmodplus"; + sid.flags = MBF_OWNERSTATE|MBF_HIDDEN; + sid.dwId = 1; + sid.szTooltip = 0; + sid.hIcon = sid.hIconDisabled = 0; + CallService(MS_MSG_ADDICON, 0, (LPARAM)&sid); + } + g_bStartup = 0; + return (0); +} diff --git a/plugins/TabSRMM/src/msgoptions_plus.cpp b/plugins/TabSRMM/src/msgoptions_plus.cpp new file mode 100644 index 0000000000..e407f392d6 --- /dev/null +++ b/plugins/TabSRMM/src/msgoptions_plus.cpp @@ -0,0 +1,189 @@ +/* + * astyle --force-indent=tab=4 --brackets=linux --indent-switches + * --pad=oper --one-line=keep-blocks --unpad=paren + * + * Miranda NG: the free IM client for Microsoft* Windows* + * + * Copyright 2000-2009 Miranda ICQ/IM project, + * all portions of this codebase are copyrighted to the people + * listed in contributors.txt. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * you should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * part of tabSRMM messaging plugin for Miranda. + * + * (C) 2005-2009 by silvercircle _at_ gmail _dot_ com and contributors + * + * $Id: msgoptions_plus.cpp 13034 2010-10-24 20:39:04Z silvercircle $ + * + * implements the "advanced tweak" option page + * + * originally developed by Mad Cluster for the tabSRMM "MADMOD" patch in + * May 2008. + * + */ + +#include "commonheaders.h" + +extern HINSTANCE hinstance; +extern BOOL g_bIMGtagButton; +extern HIMAGELIST g_himlOptions, CreateStateImageList(); + +static void FillDialog(HWND hwndDlg) +{ + TVINSERTSTRUCT tvi = {0}; + int i; + + TOptionListGroup *lvGroups = CTranslator::getGroupTree(CTranslator::TREE_MODPLUS); + for (i=0; lvGroups[i].szName != NULL; i++) { + tvi.hParent = 0; + tvi.hInsertAfter = TVI_LAST; + tvi.item.mask = TVIF_TEXT | TVIF_STATE; + tvi.item.pszText = TranslateTS(lvGroups[i].szName); + tvi.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_EXPANDED | TVIS_BOLD; + tvi.item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_EXPANDED | TVIS_BOLD; + lvGroups[i].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_PLUS_CHECKTREE), &tvi); + } + + TOptionListItem *lvItems = CTranslator::getTree(CTranslator::TREE_MODPLUS); + for (i=0; lvItems[i].szName != 0; i++) { + tvi.hParent = (HTREEITEM)lvGroups[lvItems[i].uGroup].handle; + tvi.hInsertAfter = TVI_LAST; + tvi.item.pszText = TranslateTS(lvItems[i].szName); + tvi.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM; + tvi.item.lParam = i; + tvi.item.stateMask = TVIS_STATEIMAGEMASK; + if (lvItems[i].uType == LOI_TYPE_SETTING) + tvi.item.state = INDEXTOSTATEIMAGEMASK(M->GetByte((char *)lvItems[i].lParam, lvItems[i].id) ? 3 : 2); // NOTE: was 2 : 1 without state image mask + lvItems[i].handle = (LRESULT)TreeView_InsertItem(GetDlgItem(hwndDlg, IDC_PLUS_CHECKTREE), &tvi); + } + + PluginConfig.g_bClientInStatusBar = M->GetByte("adv_ClientIconInStatusBar", 0); + + SendDlgItemMessage(hwndDlg, IDC_TIMEOUTSPIN, UDM_SETRANGE, 0, MAKELONG(300, SRMSGSET_MSGTIMEOUT_MIN / 1000)); + SendDlgItemMessage(hwndDlg, IDC_TIMEOUTSPIN, UDM_SETPOS, 0, PluginConfig.m_MsgTimeout / 1000); + + SendDlgItemMessage(hwndDlg, IDC_HISTORYSIZESPIN, UDM_SETRANGE, 0, MAKELONG(255, 15)); + SendDlgItemMessage(hwndDlg, IDC_HISTORYSIZESPIN, UDM_SETPOS, 0, (int)M->GetByte("historysize", 0)); +} + +INT_PTR CALLBACK PlusOptionsProc(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PLUS_CHECKTREE), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PLUS_CHECKTREE), GWL_STYLE) | (TVS_NOHSCROLL | TVS_CHECKBOXES)); + + g_himlOptions = (HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_PLUS_CHECKTREE, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)CreateStateImageList()); + ImageList_Destroy(g_himlOptions); + + FillDialog(hwndDlg); + return TRUE; + + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->idFrom) { + case IDC_PLUS_CHECKTREE: + if (((LPNMHDR)lParam)->code == NM_CLICK || (((LPNMHDR)lParam)->code == TVN_KEYDOWN && ((LPNMTVKEYDOWN)lParam)->wVKey == VK_SPACE)) { + TVHITTESTINFO hti; + TVITEM item = {0}; + + item.mask = TVIF_HANDLE | TVIF_STATE; + item.stateMask = TVIS_STATEIMAGEMASK | TVIS_BOLD; + hti.pt.x = (short)LOWORD(GetMessagePos()); + hti.pt.y = (short)HIWORD(GetMessagePos()); + ScreenToClient(((LPNMHDR)lParam)->hwndFrom, &hti.pt); + if (TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti) || ((LPNMHDR)lParam)->code == TVN_KEYDOWN) { + if (((LPNMHDR)lParam)->code == TVN_KEYDOWN) { + hti.flags |= TVHT_ONITEMSTATEICON; + item.hItem = TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom); + } else + item.hItem = (HTREEITEM)hti.hItem; + SendDlgItemMessageA(hwndDlg, IDC_PLUS_CHECKTREE, TVM_GETITEMA, 0, (LPARAM)&item); + if (item.state & TVIS_BOLD && hti.flags & TVHT_ONITEMSTATEICON) { + item.state = INDEXTOSTATEIMAGEMASK(0) | TVIS_BOLD; + SendDlgItemMessageA(hwndDlg, IDC_PLUS_CHECKTREE, TVM_SETITEMA, 0, (LPARAM)&item); + } + else if (hti.flags & TVHT_ONITEMSTATEICON) { + if (((item.state & TVIS_STATEIMAGEMASK) >> 12) == 3) { + item.state = INDEXTOSTATEIMAGEMASK(1); + SendDlgItemMessageA(hwndDlg, IDC_PLUS_CHECKTREE, TVM_SETITEMA, 0, (LPARAM)&item); + } + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + } + break; + + default: + switch (((LPNMHDR) lParam)->code) { + case PSN_APPLY: { + TVITEM item = {0}; + DWORD msgTimeout; + /* + * scan the tree view and obtain the options... + */ + TOptionListItem* lvItems = CTranslator::getTree(CTranslator::TREE_MODPLUS); + + for (int i=0; lvItems[i].szName != NULL; i++) { + item.mask = TVIF_HANDLE | TVIF_STATE; + item.hItem = (HTREEITEM)lvItems[i].handle; + item.stateMask = TVIS_STATEIMAGEMASK; + + SendDlgItemMessageA(hwndDlg, IDC_PLUS_CHECKTREE, TVM_GETITEMA, 0, (LPARAM)&item); + if (lvItems[i].uType == LOI_TYPE_SETTING) + M->WriteByte(SRMSGMOD_T, (char *)lvItems[i].lParam, (BYTE)((item.state >> 12) == 3/*2*/ ? 1 : 0)); // NOTE: state image masks changed + } + + msgTimeout = 1000 * GetDlgItemInt(hwndDlg, IDC_SECONDS, NULL, FALSE); + PluginConfig.m_MsgTimeout = msgTimeout >= SRMSGSET_MSGTIMEOUT_MIN ? msgTimeout : SRMSGSET_MSGTIMEOUT_MIN; + M->WriteDword(SRMSGMOD, SRMSGSET_MSGTIMEOUT, PluginConfig.m_MsgTimeout); + + M->WriteByte(SRMSGMOD_T, "historysize", (BYTE)SendDlgItemMessage(hwndDlg, IDC_HISTORYSIZESPIN, UDM_GETPOS, 0, 0)); + PluginConfig.reloadAdv(); + return TRUE; + } + } + break; + } + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDC_PLUS_HELP) { + CallService(MS_UTILS_OPENURL, 0, (LPARAM)"http://wiki.miranda.or.at/TabSRMM/AdvancedTweaks"); + break; + } + else if (LOWORD(wParam) == IDC_PLUS_REVERT) { // revert to defaults... + TOptionListItem *lvItems = CTranslator::getTree(CTranslator::TREE_MODPLUS); + + for (int i=0; lvItems[i].szName; i++) + if (lvItems[i].uType == LOI_TYPE_SETTING) + M->WriteByte(SRMSGMOD_T, (char *)lvItems[i].lParam, (BYTE)lvItems[i].id); + + TreeView_DeleteAllItems(GetDlgItem(hwndDlg, IDC_PLUS_CHECKTREE)); + FillDialog(hwndDlg); + break; + } + if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus()) + return TRUE; + + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + + case WM_CLOSE: + EndDialog(hwndDlg,0); + return 0; + } + return 0; +} -- cgit v1.2.3