From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Scriver/chat/chat.h | 440 +++++++ plugins/Scriver/chat/clist.c | 366 ++++++ plugins/Scriver/chat/colorchooser.c | 282 +++++ plugins/Scriver/chat/log.c | 998 +++++++++++++++ plugins/Scriver/chat/m_uninstaller.h | 700 +++++++++++ plugins/Scriver/chat/main.c | 111 ++ plugins/Scriver/chat/manager.c | 1402 ++++++++++++++++++++++ plugins/Scriver/chat/message.c | 351 ++++++ plugins/Scriver/chat/options.c | 953 +++++++++++++++ plugins/Scriver/chat/services.c | 690 +++++++++++ plugins/Scriver/chat/tools.c | 976 +++++++++++++++ plugins/Scriver/chat/window.c | 2200 ++++++++++++++++++++++++++++++++++ 12 files changed, 9469 insertions(+) create mode 100644 plugins/Scriver/chat/chat.h create mode 100644 plugins/Scriver/chat/clist.c create mode 100644 plugins/Scriver/chat/colorchooser.c create mode 100644 plugins/Scriver/chat/log.c create mode 100644 plugins/Scriver/chat/m_uninstaller.h create mode 100644 plugins/Scriver/chat/main.c create mode 100644 plugins/Scriver/chat/manager.c create mode 100644 plugins/Scriver/chat/message.c create mode 100644 plugins/Scriver/chat/options.c create mode 100644 plugins/Scriver/chat/services.c create mode 100644 plugins/Scriver/chat/tools.c create mode 100644 plugins/Scriver/chat/window.c (limited to 'plugins/Scriver/chat') diff --git a/plugins/Scriver/chat/chat.h b/plugins/Scriver/chat/chat.h new file mode 100644 index 0000000000..283adcdecd --- /dev/null +++ b/plugins/Scriver/chat/chat.h @@ -0,0 +1,440 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +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. +*/ + +#ifndef _CHAT_H_ +#define _CHAT_H_ + +#include +#include + +#ifndef TVM_GETITEMSTATE +#define TVM_GETITEMSTATE (TV_FIRST + 39) +#endif + +#ifndef TreeView_GetItemState +#define TreeView_GetItemState(hwndTV, hti, mask) \ + (UINT)SNDMSG((hwndTV), TVM_GETITEMSTATE, (WPARAM)(hti), (LPARAM)(mask)) +#endif + +#ifndef CFM_BACKCOLOR +#define CFM_BACKCOLOR 0x04000000 +#endif + +//defines +#define OPTIONS_FONTCOUNT 17 +#define GC_SPLITTERMOVED (WM_USER+101) +#define GC_CLOSEWINDOW (WM_USER+103) +#define GC_GETITEMDATA (WM_USER+104) +#define GC_SETITEMDATA (WM_USER+105) +#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_SETWINDOWPOS (WM_USER+114) +//#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_TABCHANGE (WM_USER+127) +#define GC_SCROLLTOBOTTOM (WM_USER+129) +#define GC_FIXTABICONS (WM_USER+132) +#define GC_SETTABHIGHLIGHT (WM_USER+138) +#define GC_SETMESSAGEHIGHLIGHT (WM_USER+139) +#define GC_REDRAWLOG2 (WM_USER+140) +#define GC_REDRAWLOG3 (WM_USER+141) + +//#define EM_SUBCLASSED (WM_USER+200) +//#define EM_UNSUBCLASSED (WM_USER+201) +#define EM_ACTIVATE (WM_USER+202) + +#define GCW_TABROOM 10 +#define GCW_TABPRIVMSG 11 + +#define GC_EVENT_HIGHLIGHT 0x1000 +#define STATE_TALK 0x0001 + + +// special service for tweaking performance +#define MS_GC_GETEVENTPTR "GChat/GetNewEventPtr" +typedef INT_PTR (*GETEVENTFUNC)(WPARAM wParam, LPARAM lParam); +typedef struct { + GETEVENTFUNC pfnAddEvent; +}GCPTRS; + +//structs + +typedef struct MODULE_INFO_TYPE +{ + char* pszModule; + TCHAR* ptszModDispName; + BOOL bBold; + BOOL bUnderline; + BOOL bItalics; + BOOL bColor; + BOOL bBkgColor; + BOOL bFontSize; + BOOL bChanMgr; + BOOL bAckMsg; + BOOL bSingleFormat; + int nColorCount; + COLORREF* crColors; + HICON hOnlineIcon; + HICON hOfflineIcon; + HICON hOnlineIconBig; + HICON hOfflineIconBig; + HICON hOnlineTalkIcon; + HICON hOfflineTalkIcon; + int iMaxText; + struct MODULE_INFO_TYPE *next; +} + MODULEINFO; + +typedef struct COMMAND_INFO_TYPE +{ + char* lpCommand; + struct COMMAND_INFO_TYPE *prev, *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; + 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 TABLIST_TYPE +{ + TCHAR* pszID; + char* pszModule; + struct TABLIST_TYPE *next; +} + TABLIST; + +typedef struct SESSION_INFO_TYPE +{ + HWND hWnd; + + BOOL bFGSet; + BOOL bBGSet; + BOOL bFilterEnabled; + BOOL bNicklistEnabled; + BOOL bInitDone; + + char* pszModule; + char* pszHeader; + TCHAR* ptszID; + TCHAR* ptszName; + TCHAR* ptszStatusbarText; + TCHAR* ptszTopic; + + #if defined( _UNICODE ) + 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 + #endif + + int iType; + int iFG; + int iBG; + int iSplitterY; + int desiredInputAreaHeight; + int iSplitterX; + int iLogFilterFlags; + int nUsersInNicklist; + int iEventCount; + int iStatusCount; + + WORD wStatus; + WORD wState; + WORD wCommandsNum; + DWORD dwItemData; + DWORD dwFlags; + time_t LastTime; + CommonWindowData windowData; + LOGINFO* pLog; + LOGINFO* pLogEnd; + USERINFO* pUsers; + USERINFO* pMe; + STATUSINFO* pStatuses; + TCHAR szSearch[255]; + + struct SESSION_INFO_TYPE *next; + +}SESSION_INFO; + +typedef struct +{ + char* buffer; + int bufferOffset, bufferLen; + HWND hwnd; + LOGINFO* lin; + BOOL bStripFormat; + BOOL bRedraw; + BOOL isFirst; + SESSION_INFO* si; +} + LOGSTREAMDATA; + +struct GlobalLogSettings_t { + BOOL ShowTime; + BOOL ShowTimeIfChanged; + BOOL LoggingEnabled; + BOOL FlashWindow; + BOOL HighlightEnabled; + BOOL LogIndentEnabled; + BOOL StripFormat; + BOOL SoundsFocus; + BOOL PopUpInactiveOnly; + BOOL TrayIconInactiveOnly; + BOOL AddColonToAutoComplete; + BOOL LogLimitNames; + BOOL TimeStampEventColour; + DWORD dwIconFlags; + DWORD dwTrayIconFlags; + DWORD dwPopupFlags; + int LogTextIndent; + int LoggingLimit; + int iEventLimit; + int iPopupStyle; + int iPopupTimeout; + int iSplitterX; + int iSplitterY; + TCHAR* pszTimeStamp; + TCHAR* pszTimeStampLog; + TCHAR* pszIncomingNick; + TCHAR* pszOutgoingNick; + TCHAR* pszHighlightWords; + TCHAR* pszLogDir; + HFONT UserListFont; + HFONT UserListHeadingsFont; + HFONT MessageBoxFont; + HFONT NameFont; + COLORREF crLogBackground; + COLORREF crUserListColor; + COLORREF crUserListBGColor; + COLORREF crUserListSelectedBGColor; + COLORREF crUserListHeadingsColor; + COLORREF crPUTextColour; + COLORREF crPUBkgColour; + BOOL ShowContactStatus; + BOOL ContactStatusFirst; +}; +extern struct GlobalLogSettings_t g_Settings; + +typedef struct{ + MODULEINFO* pModule; + int xPosition; + int yPosition; + HWND hWndTarget; + BOOL bForeground; + SESSION_INFO* si; +} + COLORCHOOSER; + +//main.c +void LoadIcons(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); +void LoadMsgLogBitmaps(void); +void FreeMsgLogBitmaps(void); +TCHAR* GetChatLogsFilename (HANDLE hContact, time_t tTime); +TCHAR* MakeTimeStamp(TCHAR* pszStamp, time_t time); +char* Log_CreateRtfHeader(MODULEINFO * mi, SESSION_INFO* si); + +//window.c +INT_PTR CALLBACK RoomWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); +int GetTextPixelSize( TCHAR* pszText, HFONT hFont, BOOL bWidth); + +//options.c +int OptionsInit(void); +int OptionsUnInit(void); +void LoadGlobalSettings(void); +void LoadLogFonts(void); +void SetIndentSize(); + +//services.c +void HookEvents(void); +void UnhookEvents(void); +void CreateServiceFunctions(void); +void DestroyServiceFunctions(void); +void DestroyHookableEvents(void); +void CreateHookableEvents(void); +int Chat_ModulesLoaded(WPARAM wParam,LPARAM lParam); +int Chat_FontsChanged(WPARAM wParam,LPARAM lParam); +int Chat_SmileyOptionsChanged(WPARAM wParam,LPARAM lParam); +int Chat_PreShutdown(WPARAM wParam,LPARAM lParam); +int Chat_IconsChanged(WPARAM wParam,LPARAM lParam); +void ShowRoom(SESSION_INFO* si, WPARAM wp, BOOL bSetForeground); + +//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); +SESSION_INFO* SM_FindSession(const TCHAR* pszID, const char* pszModule); +HWND SM_FindWindowByContact(HANDLE hContact); +USERINFO* SM_AddUser(SESSION_INFO* si, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus); +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); +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 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); +int SM_GetCount(const char* pszModule); +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); +char SM_GetStatusIndicator(SESSION_INFO* si, USERINFO * ui); +SESSION_INFO* SM_FindSessionAutoComplete(const char* pszModule, SESSION_INFO* currSession, SESSION_INFO* prevSession, const TCHAR* pszOriginal, const TCHAR* pszCurrent); +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 CList_EventDoubleclicked(WPARAM wParam,LPARAM lParam); +INT_PTR CList_EventDoubleclickedSvc(WPARAM wParam,LPARAM lParam); +INT_PTR CList_JoinChat(WPARAM wParam, LPARAM lParam); +INT_PTR CList_LeaveChat(WPARAM wParam, LPARAM lParam); +INT_PTR CList_PrebuildContactMenuSvc(WPARAM wParam, LPARAM lParam); +int CList_PrebuildContactMenu(WPARAM wParam, LPARAM lParam); +void CList_CreateGroup(TCHAR* group); +BOOL CList_AddEvent(HANDLE hContact, HICON Icon, HANDLE event, int type, 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 DoSoundsFlashPopupTrayStuff(SESSION_INFO* si, GCEVENT * gce, BOOL bHighlight, int bManyFix); +int GetColorIndex(const char* pszModule, COLORREF cr); +void CheckColorsInModule(const char* pszModule); +TCHAR* my_strstri(const TCHAR* s1, const TCHAR* s2) ; +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); + +// message.c +TCHAR* DoRtfToTags( char* pszRtfText, SESSION_INFO* si); + +////////////////////////////////////////////////////////////////////////////////// + +TCHAR* a2tf( const TCHAR* str, int flags ); +TCHAR* replaceStr( TCHAR** dest, const TCHAR* src ); +char* replaceStrA( char** dest, const char* src ); + +#define DEFLOGFILENAME _T("%miranda_logpath%\\%proto%\\%userid%.log") +#endif diff --git a/plugins/Scriver/chat/clist.c b/plugins/Scriver/chat/clist.c new file mode 100644 index 0000000000..7d43578a4b --- /dev/null +++ b/plugins/Scriver/chat/clist.c @@ -0,0 +1,366 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "../commonheaders.h" +#include "chat.h" + +extern HINSTANCE g_hInst; + +extern HANDLE hJoinMenuItem, hLeaveMenuItem; + +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 ( !DBGetContactSettingTString( 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 ) { //contact exist, make sure it is in the right group + DBVARIANT dbv; + DBVARIANT dbv2; + char str[50]; + int i; + + if ( pszGroup[0] ) { + for (i = 0;; i++) { + _itoa(i, str, 10); + if ( DBGetContactSettingTString( NULL, "CListGroups", str, &dbv )) { + DBWriteContactSettingTString(hContact, "CList", "Group", pszGroup); + goto END_GROUPLOOP; + } + + if ( !DBGetContactSettingTString( hContact, "CList", "Group", &dbv2 )) { + if ( dbv.ptszVal[0] != '\0' && dbv2.ptszVal[0] != '\0' && !lstrcmpi( dbv.ptszVal + 1, dbv2.ptszVal )) { + DBFreeVariant(&dbv); + DBFreeVariant(&dbv2); + goto END_GROUPLOOP; + } + DBFreeVariant(&dbv2); + } + DBFreeVariant(&dbv); + } } + +END_GROUPLOOP: + DBWriteContactSettingWord(hContact, pszModule, "Status", ID_STATUS_OFFLINE); + DBWriteContactSettingTString(hContact, pszModule, "Nick", pszDisplayName ); +/* if(iType != GCW_SERVER) + DBWriteContactSettingByte(hContact, "CList", "Hidden", 1);*/ + 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 ( lstrlen( pszGroup ) > 0 ) + DBWriteContactSettingTString(hContact, "CList", "Group", pszGroup ); + else + DBDeleteContactSetting(hContact, "CList", "Group"); + DBWriteContactSettingTString( hContact, pszModule, "Nick", pszDisplayName ); + DBWriteContactSettingTString( hContact, pszModule, "ChatRoomID", pszRoom ); + DBWriteContactSettingByte(hContact, pszModule, "ChatRoom", (BYTE)iType); + DBWriteContactSettingWord(hContact, pszModule, "Status", ID_STATUS_OFFLINE); +// if(iType == GCW_SERVER) + // DBWriteContactSettingByte(hContact, "CList", "Hidden", 1); + return hContact; + } + +BOOL CList_SetOffline(HANDLE hContact, BOOL bHide) +{ + if ( hContact ) { + char * szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + DBWriteContactSettingWord(hContact, szProto,"ApparentMode",(LPARAM) 0); + DBWriteContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE); +/* + int i = DBGetContactSettingByte(hContact, szProto, "ChatRoom", 0); + if (bHide && i != GCW_SERVER) + DBWriteContactSettingByte(hContact, "CList", "Hidden", 1);*/ + return TRUE; + } + + return FALSE; +} + +BOOL CList_SetAllOffline(BOOL bHide, const char *pszModule) +{ + HANDLE hContact; + char * szProto; + + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while ( hContact ) { + szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if ( MM_FindModule( szProto )) { + if (!pszModule || (pszModule && !strcmp(pszModule, szProto))) { + int i = DBGetContactSettingByte(hContact, szProto, "ChatRoom", 0); + if ( i != 0 ) { + DBWriteContactSettingWord(hContact, szProto,"ApparentMode",(LPARAM)(WORD) 0); + DBWriteContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE); +/* if (bHide && i == GCW_CHATROOM) + DBWriteContactSettingByte(hContact, "CList", "Hidden", 1);*/ + } + } + } + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0); + } + return TRUE; +} + +int CList_RoomDoubleclicked(WPARAM wParam,LPARAM lParam) +{ + DBVARIANT dbv; + char *szProto; + + HANDLE hContact = (HANDLE)wParam; + if (!hContact) + return 0; + + szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if ( MM_FindModule(szProto)) { + if(DBGetContactSettingByte(hContact, szProto, "ChatRoom", 0) == 0) + return 0; + + if ( !DBGetContactSettingTString( 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 + && DBGetContactSettingByte(NULL, "Chat", "ToggleVisibility", 0)==1 + && !CallService(MS_CLIST_GETEVENT, (WPARAM)hContact, 0) + && IsWindowVisible(si->hWnd) + && !IsIconic(si->hWnd)) + { + PostMessage(si->hWnd, GC_CLOSEWINDOW, 0, 0); + DBFreeVariant(&dbv); + return 1; + } + ShowRoom(si, WINDOW_VISIBLE, TRUE); + } + DBFreeVariant(&dbv); + return 1; + } + } + return 0; +} + +int CList_EventDoubleclicked(WPARAM wParam,LPARAM lParam) +{ + return CList_RoomDoubleclicked((WPARAM) ((CLISTEVENT*)lParam)->hContact,(LPARAM) 0); +} + +INT_PTR CList_EventDoubleclickedSvc(WPARAM wParam,LPARAM lParam) +{ + return CList_EventDoubleclicked(wParam, lParam); +} + +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 ( DBGetContactSettingByte( 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) +{ + int i; + char str[50]; + TCHAR name[256]; + DBVARIANT dbv; + + if (!group) + return; + + for (i = 0;; i++) + { + _itoa(i, str, 10); + if ( DBGetContactSettingTString( NULL, "CListGroups", str, &dbv )) + break; + + if ( dbv.pszVal[0] != '\0' && !lstrcmpi(dbv.ptszVal + 1, group)) { + DBFreeVariant(&dbv); + return; + } + + DBFreeVariant(&dbv); + } + + // CallService(MS_CLIST_GROUPCREATE, (WPARAM)group, 0); + name[0] = 1 | GROUPF_EXPANDED; + _tcsncpy(name + 1, group, SIZEOF(name) - 1); + name[ lstrlen(group) + 1] = '\0'; + DBWriteContactSettingTString(NULL, "CListGroups", str, name); + CallService(MS_CLUI_GROUPADDED, i + 1, 0); +} + +BOOL CList_AddEvent(HANDLE hContact, HICON Icon, HANDLE event, int type, 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); + _vsntprintf(szBuf, 4096, 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)event); + CallService(MS_CLIST_ADDEVENT,(WPARAM) hContact,(LPARAM) &cle); + } + return TRUE; +} + +HANDLE CList_FindRoom ( const char* pszModule, const TCHAR* pszRoom) +{ + HANDLE hContact = ( HANDLE )CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) { + char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0 ); + if ( szProto && !lstrcmpiA( szProto, pszModule )) { + if ( DBGetContactSettingByte( hContact, szProto, "ChatRoom", 0) != 0 ) { + DBVARIANT dbv; + if ( !DBGetContactSettingTString( hContact, szProto, "ChatRoomID", &dbv )) { + if ( !lstrcmpi(dbv.ptszVal, pszRoom)) { + DBFreeVariant(&dbv); + return hContact; + } + DBFreeVariant(&dbv); + } } } + + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0); + } + return 0; +} + +int WCCmp(TCHAR* wild, TCHAR* string) +{ + TCHAR *cp = NULL, *mp = NULL; + if ( wild == NULL || !lstrlen(wild) || string == NULL || !lstrlen(string)) + return 0; + + while ((*string) && (*wild != '*')) { + if ((*wild != *string) && (*wild != '?')) + return 0; + + wild++; + string++; + } + + while (*string) { + if (*wild == '*') { + if (!*++wild) + return 1; + + mp = wild; + cp = string+1; + } + else if ((*wild == *string) || (*wild == '?')) { + wild++; + string++; + } + else { + wild = mp; + string = cp++; + } } + + while (*wild == '*') + wild++; + + return !*wild; +} diff --git a/plugins/Scriver/chat/colorchooser.c b/plugins/Scriver/chat/colorchooser.c new file mode 100644 index 0000000000..eb330bfe89 --- /dev/null +++ b/plugins/Scriver/chat/colorchooser.c @@ -0,0 +1,282 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +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. +*/ + +// this color chooser window is inspired by PeaCow's smiley chooser window for the Smileyadd plugin + +#include "../commonheaders.h" +#include "chat.h" +#include + +//globals, defined int main.cpp +extern HINSTANCE g_hInst; + +static int CalculateCoordinatesToButton(COLORCHOOSER * pCC, POINT pt) +{ + int iSquareRoot = (int)sqrt(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(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(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, GetWindowLong(hwndDlg, GWL_STYLE), FALSE, GetWindowLong(hwndDlg, GWL_EXSTYLE)); + + width = rc.right - rc.left; + height = rc.bottom - rc.top; + + pCC->yPosition -= height; + + + SetDlgItemText(hwndDlg, IDC_CHAT_COLORTEXT, pCC->bForeground?TranslateT("Text colour"):TranslateT("Background colour")); + SetWindowPos(GetDlgItem(hwndDlg, IDC_CHAT_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_CHAT_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_CHAT_COLOR )) { + cf.dwMask = CFM_COLOR; + cf.crTextColor = pCC->pModule->crColors[iCurrentHotTrack]; + if (pCC->pModule->bSingleFormat) { + SendMessage(pCC->hWndTarget, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf); + } else { + SendMessage(pCC->hWndTarget, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } + } + else { + pCC->si->bBGSet = TRUE; + pCC->si->iBG = iCurrentHotTrack; + if(IsDlgButtonChecked(hWindow, IDC_CHAT_BKGCOLOR)) { + cf.dwMask = CFM_BACKCOLOR; + cf.crBackColor = pCC->pModule->crColors[iCurrentHotTrack]; + if (pCC->pModule->bSingleFormat) { + SendMessage(pCC->hWndTarget, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf); + } else { + 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; + 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=0; 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, GetStockObject(BLACK_BRUSH)); + + 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/Scriver/chat/log.c b/plugins/Scriver/chat/log.c new file mode 100644 index 0000000000..5887708957 --- /dev/null +++ b/plugins/Scriver/chat/log.c @@ -0,0 +1,998 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "../commonheaders.h" +#include "chat.h" +#include +#include +#include + + +#ifndef EM_GETSCROLLPOS +#define EM_GETSCROLLPOS (WM_USER+221) +#endif +// 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]; + +static PBYTE pLogIconBmpBits[14]; +static const char *logIconNames[14] = { + "chat_log_action", "chat_log_addstatus", "chat_log_highlight", "chat_log_info", "chat_log_join", + "chat_log_kick", "chat_log_message_in", "chat_log_message_out", "chat_log_nick", "chat_log_notice", + "chat_log_part", "chat_log_quit", "chat_log_removestatus", "chat_log_topic" +}; +static int logIconBmpSize[ SIZEOF(pLogIconBmpBits) ]; + +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 int EventToIcon(LOGINFO * lin) +{ + switch (lin->iType) { + case GC_EVENT_MESSAGE: + if (lin->bIsMe) + return 7; + else + return 6; + + case GC_EVENT_JOIN: return 4; + case GC_EVENT_PART: return 10; + case GC_EVENT_QUIT: return 11; + case GC_EVENT_NICK: return 8; + case GC_EVENT_KICK: return 5; + case GC_EVENT_NOTICE: return 9; + case GC_EVENT_TOPIC: return 13; + case GC_EVENT_INFORMATION:return 3; + case GC_EVENT_ADDSTATUS: return 1; + case GC_EVENT_REMOVESTATUS: return 12; + case GC_EVENT_ACTION: return 0; + } + return 0; +} + +static char *Log_SetStyle(int style, int fontindex) +{ + static char szStyle[128]; + mir_snprintf(szStyle, SIZEOF(szStyle), "\\f%u\\cf%u\\ul0\\highlight0\\b%d\\i%d\\fs%u", style, style+1, aFonts[fontindex].lf.lfWeight >= FW_BOLD ? 1 : 0, aFonts[fontindex].lf.lfItalic, 2 * abs(aFonts[fontindex].lf.lfHeight) * 74 / g_dat->logPixelSY); + return szStyle; +} + +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); + *buffer = (char *) mir_realloc(*buffer, *cbBufferAlloced); + } + + 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 { + #if defined( _UNICODE ) + d += sprintf(d, "\\u%u ?", (WORD)*line); + #else + d += sprintf(d, "\\'%02x", (BYTE)*line); + #endif + } + } + + *cbBufferEnd = (int) (d - *buffer); + return textCharsCount; +} + +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 = _tcslen(szTemp); + memcpy( d, szTemp, iLen * sizeof(TCHAR)); + d += iLen; + } + } + else if (*line == '%') { + *d++ = '%'; + *d++ = (char) *line; + } + else { + *d++ = (char) *line; + } + } + *d = '\0'; + *cbBufferEnd = (int) (d - *buffer); + return textCharsCount; +} + + +static void AddEventTextToBuffer(char **buffer, int *bufferEnd, int *bufferAlloced, LOGSTREAMDATA *streamData) +{ + if (streamData->lin->ptszText) + Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T(": %s"), streamData->lin->ptszText); +} + +static void AddEventToBuffer(char **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 defined( _UNICODE ) + if (streamData->si->windowData.codePage != CP_ACP) { + char *aText = t2acp(streamData->lin->ptszText, CP_ACP); + ptszText = ptszTemp = a2tcp(aText, streamData->si->windowData.codePage); + mir_free(aText); + } + #endif + Log_AppendRTF( streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), ptszText ); + mir_free(ptszTemp); + } + break; + case GC_EVENT_ACTION: + if ( pszNick && streamData->lin->ptszText) { + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, _T("%s "), pszNick); + Log_AppendRTF(streamData, FALSE, buffer, bufferEnd, bufferAlloced, _T("%s"), streamData->lin->ptszText); + } + break; + case GC_EVENT_JOIN: + if (pszNick) { + if (!streamData->lin->bIsMe) + 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); + AddEventTextToBuffer(buffer, bufferEnd, bufferAlloced, streamData); + break; + case GC_EVENT_QUIT: + if (pszNick) + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("%s has disconnected"), pszNick); + AddEventTextToBuffer(buffer, bufferEnd, bufferAlloced, streamData); + 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); + AddEventTextToBuffer(buffer, bufferEnd, bufferAlloced, streamData); + break; + case GC_EVENT_NOTICE: + if (pszNick && streamData->lin->ptszText) { + Log_AppendRTF(streamData, TRUE, buffer, bufferEnd, bufferAlloced, TranslateT("Notice from %s"), pszNick ); + AddEventTextToBuffer(buffer, bufferEnd, bufferAlloced, streamData); + } + 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; +} } } + + +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 defined( _UNICODE ) + if (streamData->si->windowData.codePage != CP_ACP) { + char *aText = t2acp(streamData->lin->ptszText, CP_ACP); + ptszText = ptszTemp = a2tcp(aText, streamData->si->windowData.codePage); + mir_free(aText); + } + #endif + 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->si->windowData.hwndLog; + event.hContact = streamData->si->windowData.hContact; + event.codepage = streamData->si->windowData.codePage; + event.pszProto = streamData->si->pszModule; + /* + if (!fAppend) { + event.iType = IEE_CLEAR_LOG; + CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event); + } + */ + 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; +#if defined( _UNICODE ) + ied.dwFlags = IEEDF_UNICODE_TEXT | IEEDF_UNICODE_NICK | IEEDF_UNICODE_TEXT2; +#endif + ied.next = NULL; + /* + ied.color = event->color; + ied.fontSize = event->iFontSize; + ied.fontStyle = event->dwFlags; + ied.fontName = getFontName(event->iFont); + */ + CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&event); + mir_free(buffer); +/* + iew.cbSize = sizeof(IEVIEWWINDOW); + iew.iType = IEW_SCROLLBOTTOM; + iew.hwnd = hWndLog; + CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&iew); +*/ +} + +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, BOOL ieviewMode) +{ + char *buffer, *header; + int bufferAlloced, bufferEnd, i; + LOGINFO * lin = streamData->lin; + + // guesstimate amount of memory for the RTF + bufferEnd = 0; + bufferAlloced = streamData->bRedraw ? 1024 * (streamData->si->iEventCount+2) : 2048; + buffer = (char *) mir_alloc(bufferAlloced); + buffer[0] = '\0'; + + // ### RTF HEADER + header = streamData->si->pszHeader; + + if (header) + AppendToBuffer(&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) + { + TCHAR szTemp[512], szTemp2[512]; + TCHAR* pszNick = NULL; + streamData->lin = lin; + + if ( lin->ptszNick ) { + if ( g_Settings.LogLimitNames && lstrlen( lin->ptszNick ) > 20 ) { + lstrcpyn( szTemp2, lin->ptszNick, 20 ); + lstrcpyn( szTemp2+20, _T("..."), 4); + } + else lstrcpyn( szTemp2, lin->ptszNick, 511 ); + + if ( lin->ptszUserInfo && lin->iType != GC_EVENT_TOPIC) + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%s (%s)"), szTemp2, lin->ptszUserInfo ); + else + mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%s"), szTemp2 ); + pszNick = szTemp; + } + + if (streamData->si->windowData.hwndLog != NULL) { + LogEventIEView(streamData, pszNick); + } + { + // create new line, and set font and color + if (!streamData->isFirst) { + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\par"); + } + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", Log_SetStyle(0, 0)); + // Insert icon + if ((lin->iType&g_Settings.dwIconFlags) || (lin->bIsHighlighted&&g_Settings.dwIconFlags&GC_EVENT_HIGHLIGHT)) + { + int iIndex = (lin->bIsHighlighted&&g_Settings.dwIconFlags&GC_EVENT_HIGHLIGHT) ? 2 : EventToIcon(lin); + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\fs1 "); + while (bufferAlloced - bufferEnd < logIconBmpSize[0]) + bufferAlloced += 4096; + buffer = (char *) mir_realloc(buffer, bufferAlloced); + CopyMemory(buffer + bufferEnd, pLogIconBmpBits[iIndex], logIconBmpSize[iIndex]); + bufferEnd += logIconBmpSize[iIndex]; + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " "); + } + + 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\\fs%u", iii+1, aFonts[0].lf.lfWeight >= FW_BOLD ? 1 : 0, aFonts[0].lf.lfItalic, 2 * abs(aFonts[0].lf.lfHeight) * 74 / g_dat->logPixelSY); + AppendToBuffer(&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\\fs%u", iii+1, aFonts[0].lf.lfWeight >= FW_BOLD ? 1 : 0, aFonts[0].lf.lfItalic, 2 * abs(aFonts[0].lf.lfHeight) * 74 / g_dat->logPixelSY); + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", szStyle); + } + } + else + AppendToBuffer(&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) +// AppendToBuffer(&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 ); + } + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\tab "); + } + + // Insert the nick + + if (pszNick && lin->iType == GC_EVENT_MESSAGE) + { + TCHAR pszTemp[300], *p1; + + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", Log_SetStyle(lin->bIsMe ? 2 : 1, lin->bIsMe ? 2 : 1)); + lstrcpyn(pszTemp, lin->bIsMe ? g_Settings.pszOutgoingNick : g_Settings.pszIncomingNick, 299); + p1 = _tcsstr(pszTemp, _T("%n")); + if (p1) + p1[1] = 's'; + + Log_AppendRTF(streamData, TRUE, &buffer, &bufferEnd, &bufferAlloced, pszTemp, pszNick); + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, " "); + } + + // Insert the message + i = lin->bIsHighlighted?16:EventToIndex(lin); + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "%s ", Log_SetStyle(i, i)); + AddEventToBuffer(&buffer, &bufferEnd, &bufferAlloced, streamData, pszNick); + } + streamData->isFirst = FALSE; + + } + lin = lin->prev; + } + + // ### RTF END + AppendToBuffer(&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->si->windowData.hwndLog != NULL); + 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) +{ + EDITSTREAM stream; + LOGSTREAMDATA streamData; + CHARRANGE oldsel, sel, newsel; + POINT point ={0}; + SCROLLINFO scroll; + WPARAM wp; + HWND hwndRich; + + if (hwndDlg == 0 || lin == 0 || si == 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.isFirst = bRedraw ? 1 : (GetRichTextLength(hwndRich, CP_ACP, FALSE) == 0); + + // bPhaseTwo = bRedraw && bPhaseTwo; + + if (bRedraw || si->iType != GCW_CHATROOM || !si->bFilterEnabled || (si->iLogFilterFlags&lin->iType) != 0) + { + BOOL bFlag = FALSE; + + 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(hwndRich, 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, CP_ACP, FALSE); + SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) & sel); + SendMessage(hwndRich, EM_EXGETSEL, 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) + { + SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0); + bFlag = TRUE; +// SetCursor(LoadCursor(NULL, IDC_CHAT_ARROW)); + } + + // stream in the event(s) + streamData.lin = lin; + streamData.bRedraw = bRedraw; + SendMessage(hwndRich, EM_STREAMIN, wp, (LPARAM) & stream); + + // do smileys + if (g_dat->smileyAddInstalled && (bRedraw + || (lin->ptszText + && lin->iType != GC_EVENT_JOIN + && lin->iType != GC_EVENT_NICK + && lin->iType != GC_EVENT_ADDSTATUS + && lin->iType != GC_EVENT_REMOVESTATUS ))) + { + SMADD_RICHEDIT3 sm; + + 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.flags = 0; + sm.disableRedraw = TRUE; + sm.hContact = si->windowData.hContact; + CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm); + } + + // 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, CP_ACP, FALSE); + SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) & sel); + SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0); + InvalidateRect(hwndRich, NULL, TRUE); +} } } + +char * Log_CreateRtfHeader(MODULEINFO * mi, SESSION_INFO* si) +{ + char *buffer; + int bufferAlloced, bufferEnd, i = 0; + int charset = 0; + BOOL forceCharset = FALSE; + +#if !defined ( _UNICODE ) + if (si->windowData.codePage != CP_ACP) { + CHARSETINFO csi; + if(TranslateCharsetInfo((DWORD*)si->windowData.codePage, &csi, TCI_SRCCODEPAGE)) { + forceCharset = TRUE; + charset = csi.ciCharset; + } + } +#endif + // guesstimate amount of memory for the RTF header + bufferEnd = 0; + bufferAlloced = 4096; + buffer = (char *) mir_realloc(si->pszHeader, bufferAlloced); + buffer[0] = '\0'; + + // ### RTF HEADER + + // font table + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "{\\rtf1\\ansi\\deff0{\\fonttbl"); + for (i = 0; i < OPTIONS_FONTCOUNT; i++) { + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "{\\f%u\\fnil\\fcharset%u" TCHAR_STR_PARAM ";}", i, (!forceCharset) ? aFonts[i].lf.lfCharSet : charset, aFonts[i].lf.lfFaceName); + } + // colour table + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}{\\colortbl ;"); + + for (i = 0; i < OPTIONS_FONTCOUNT; i++) + AppendToBuffer(&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++) + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\red%u\\green%u\\blue%u;", GetRValue(mi->crColors[i]), GetGValue(mi->crColors[i]), GetBValue(mi->crColors[i])); + + // new paragraph + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "}\\pard"); + + // set tabs and indents + { + int iIndent = 0; + + if (g_Settings.dwIconFlags) + { + iIndent += (14*1440)/g_dat->logPixelSX; + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\tx%u", iIndent); + } + if (g_Settings.ShowTime) + { + int iSize = (g_Settings.LogTextIndent*1440)/g_dat->logPixelSX; + AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "\\tx%u", iIndent + iSize ); + if (g_Settings.LogIndentEnabled) + iIndent += iSize; + } + AppendToBuffer(&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; + + hBkgBrush = CreateSolidBrush(DBGetContactSettingDword(NULL, "Chat", "ColorLogBG", GetSysColor(COLOR_WINDOW))); + bih.biSize = sizeof(bih); + bih.biBitCount = 24; + bih.biCompression = BI_RGB; + bih.biHeight = 10; //GetSystemMetrics(SM_CYSMICON); + bih.biPlanes = 1; + bih.biWidth = 10; //GetSystemMetrics(SM_CXSMICON); + widthBytes = ((bih.biWidth * bih.biBitCount + 31) >> 5) * 4; + rc.top = rc.left = 0; + rc.right = bih.biWidth; + rc.bottom = bih.biHeight; + 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 = GetCachedIcon(logIconNames[i]); + pLogIconBmpBits[i] = (PBYTE) mir_alloc(RTFPICTHEADERMAXSIZE + (bih.biSize + widthBytes * bih.biHeight) * 2); + rtfHeaderSize = sprintf(pLogIconBmpBits[i], "{\\pict\\dibitmap0\\wbmbitspixel%u\\wbmplanes1\\wbmwidthbytes%u\\picw%u\\pich%u ", bih.biBitCount, widthBytes, (unsigned int)bih.biWidth, (unsigned int)bih.biHeight); + hoBmp = (HBITMAP) SelectObject(hdcMem, hBmp); + FillRect(hdcMem, &rc, hBkgBrush); + DrawIconEx(hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 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(pLogIconBmpBits[i] + rtfHeaderSize + n * 2, "%02X", ((PBYTE) & bih)[n]); + for (n = 0; n < widthBytes * bih.biHeight; n += 4) + sprintf(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); +} + +void FreeMsgLogBitmaps(void) +{ + int i; + for (i = 0; i < SIZEOF(pLogIconBmpBits); i++) + mir_free(pLogIconBmpBits[i]); +} diff --git a/plugins/Scriver/chat/m_uninstaller.h b/plugins/Scriver/chat/m_uninstaller.h new file mode 100644 index 0000000000..15cd268452 --- /dev/null +++ b/plugins/Scriver/chat/m_uninstaller.h @@ -0,0 +1,700 @@ +/* + + PluginUninstaller 1.1.2.1 for Miranda IM 0.3.3a and + + ------------------------------------------------------------------------ + Developers - C/C++ Header File + + Plugin Info: ---------------------------- + | Version: 1.1.2.1 + | Filename: uninstaller.dll + | Author: H. Herkenrath (hrathh@users.sourceforge.net) + | Description: Extends the plugin options and offers the possibility + | to directly remove plugins and delete all associated + | settings and files. + + Contents: ------------------------------- + | > General Info: + | - Uninstall Example/Template + | - Changing displayed icon + | - Changing displayed docs + | - Message boxes on uninstall + | - Service Accesibility + | - Including this file + | + | > Structs: + | - Uninstall Params (PLUGINUNINSTALLPARAMS) + | + | > Helpers: + | - Macro: Run service while uninstalling (PUICallService) + | - Function: Remove some files in directory (PUIRemoveFilesInDirectory) + | + | > Events: + | - Allow to uninstall a plugin (ME_PLUGINUNINSTALLER_OKTOUNINSTALL) + | - Plugin gets uninstalled (ME_PLUGINUNINSTALLER_UNINSTALL) + | + | > Services: + | - Remove database module (MS_PLUGINUNINSTALLER_REMOVEDBMODULE) + | - Remove a setting globally (MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY) + | - Remove skinned sound (MS_PLUGINUNINSTALLER_REMOVESKINSOUND) + | - Uninstall a plugin (MS_PLUGINUNISTALLER_UNISTALLPLUGIN) + | - Getting handles (MS_PLUGINUNINSTALLER_GETHANDLE) + | + + + This file is only thought for plugin developers. + If you only want to use "PluginUninstaller" and don't want to develop a plugin + or something with it you don't need this file. + + If there are any problems or bugs with or in this file or something else + please mail me. My e-mail address is: hrathh@users.sourceforge.net + For more documentation you can use this address, too. :-) + + If you have any whishes on some plugin uninstalling for your + plugin you can mail me, too. :-) + +*/ +#ifndef M_UNINSTALLER_H +#define M_UNINSTALLER_H + +#ifndef CallService + #pragma message("Mistake Alert!: "m_uninstaller.h" needs to be included after "newpluginapi.h"!\n The following errors are resulting of this mistake.\n") +#endif + + +// | General Info +// ----------------------------- + +// Uninstall Example/Template +// --------------------------- +// Making your plugin uninstallable is very easy. +// Just add the following "Uninstall" function near the "Unload" function +// in your plugin. +// A template plugin is available in the source code package. + +// Old: +// int __declspec(dllexport) Uninstall(BOOL bIsMirandaRunning, BOOL bDoDeleteSettings, char* pszPluginPath); + +// New: +//int __declspec(dllexport) UninstallEx(PLUGINUNINSTALLPARAMS* ppup) +//{ + // Available Variables: + // ----------------------------- + // ppup->bIsMirandaRunning: + // Contains if Miranda is running + // (Currently this is always TRUE). + + // ppup->bDoDeleteSettings: + // Contains if the users selected + // that he wants all settings be deleted. + + // ppup->pszPluginsPath: + // Contains the plugins directory name. + + + // Notes: + // ----------------------------- + + // Run before "Unload" function: + // -> IMPORTANT: Be careful not to write to the database or to files in "Unload" again!!! + // -> Perhaps create a global BOOL variable which is set to TRUE when your plugin gets uninstalled + // or check of a database setting "IsInstalled" in Unload() or sth. like that + + // All Miranda is still loaded + + // Here you can do: + // - Delete settings group in database + // - Delete registry items + // - Delete ini-files and other settings files + // - Delete other files + + // Your plugin dll gets automatically deleted + + // Services to remove are offered: + // MS_PLUGINUNINSTALLER_REMOVEDBMODULE + // MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY + // MS_PLUGINUNINSTALLER_REMOVESKINSOUND + + + // Getting other useful paths: + // ----------------------------- + + // System directory: + + //char szSysPath[MAX_PATH]; + //GetSystemDirectory(szSysPath, MAX_PATH); + + + // Windows directory: + + //char szWinPath[MAX_PATH]; + //GetWindowsDirectory(szWinPath, MAX_PATH); + + + // Other directories: + + // char szPath[MAX_PATH]; + // SHGetSpecialFolderPath(NULL, szPath, CSIDL_* , FALSE); + + // Some available dirs: + // CSIDL_APPDATA CSIDL_SENDTO CSIDL_FAVORITES + // CSIDL_STARTUP CSIDL_PROFILE CSIDL_DESKTOPDIRECTORY + + + // Delete Files + //const char* apszFiles[] = {"MyPlugin_Readme.txt", "MyPlugin_License.txt", "MyPlugin_Developer.txt", "MyPlugin_Translation.txt"}; + //PUIRemoveFilesInPath(ppup->pszPluginsPath, apszFiles); + + // Delete Settings + //if(ppup->bDoDeleteSettings == TRUE) + //{ + //if (ppup->bIsMirandaRunning == TRUE) // Check if it is possible to access services + //{ + // Remove plugin's module + //PUIRemoveDbModule("MyPlugin"); + + // Remove plugin's sounds + //PUIRemoveSkinSound("MySoundSetting1"); + //PUIRemoveSkinSound("MySoundSetting2"); + //} + //} + + // Remember: + // Do not forget to remove your (eventually) created registry items here, too. + + + // The plugin's dll file gets deleted after returning. + + // Remember: + // If your DLL file is additionally in use by another application (eg. Windows) + // you need to free the DLL *here* completely. Otherwise it can't be deleted. + +// return 0; +//} + + + +// Changing displayed icon +// --------------------------- +// The icon that gets displayed on the options page is always the "first" +// icon in your DLL file. +// An icon in your DLL file is the first icon when it has the lowest recource ID. +// If you would like to have an other icon shown in the options please change your +// icon resource IDs so that the icon you would like to have has the lowest one. +// For example if you use MS Visual C++, open "resource.h" and change the resource define +// of your prefered icon to the lowest icon number. + + +// Changing displayed docs +// --------------------------- +// The items "License" and "More Information" on the plugin details page +// are created when the a license and/or a readme file for the plugin exists. +// The files get detected automatically and need a special name +// so that they get detected. +// The text files need to be either placed in the "Plugins" directory or +// in the "Docs" directory. Whereof the last one is the better one :-) +// +// For the license file the following file name formatings are possible: +// PluginName-License.txt (I personally think that this is the best naming solution... :-) ) +// PluginName_License.txt, +// +// For the readme file the following ones are possible: +// PluginName-Readme.txt (Again...I like this one :-D ), +// PluginName_Readme.txt, + +// Message boxes on uninstall +// --------------------------- +// If you would like to ask the user for something to remove/uninstall +// please hook the event ME_PLUGINUNINSTALLER_UNINSTALL and show your +// message box there. Save the action the user chose in a +// global BOOL variable and do the chosen action in "UninstallEx". +// You can get the plugins options window handle with MS_PLUGINUNINSTALLER_GETHANDLE. + + +// Service Accessibility +// --------------------------- +// Remember that you only can use these functions after the event ME_SYSTEM_MODULESLOADED +// or later because "PluginUninstaller" needs to be loaded first. +// Normally you only use them in your "UninstallEx" function. +// +// IMPORTANT!: +// Please make sure that you always use the macro PUICallService +// in the "UninstallEx" function instead of the CallService function. + + +// Including this file +// --------------------------- +// To use some of the uninstalling functionality you have to include this file +// into your project. +// +// IMPORTANT!: +// Please make sure that you include the file "newpluginapi.h" before this one. +// If this isn't the case there may some compile errors come up. + + // -> Example: + // If your plugin is in the directory "Plugins/MyPlugin/" and + // this include file is in the directory "Plugins/PluginUninstaller" + // you can use the following: + + //#include "../PluginUninstaller/m_uninstaller.h" + + // If your plugin is in an directory that is different to that one just + // change the include path to the one you want. + + + + + +// | Structs +// ----------------------------- + +// --------------------------------------------- +// -- Struct: Uninstall Params ----------------- +// --------------------------------------------- + +// Struct: PLUGINUNINSTALLPARAMS +// (Gets passed to "UninstallEx" function) + +typedef int (*HELPERPROC)(const char*, WPARAM, LPARAM); // Used internally (for pHelperProcAddress) + +typedef struct { + BOOL bIsMirandaRunning; // Is TRUE when Miranda is loaded and services are available (Please use PUICallService instead of CallService) + BOOL bDoDeleteSettings; // Is TRUE when user wants to delete settings (If this is FALSE, please only delete your files) + char* pszPluginsPath; // Contains the plugin directory path + char* pszDocsPath; // Contains the document directory for plugins documentation (Added in version 1.1.1.0) + char* pszIconsPath; // Contains the icon directory for icon dlls (Added in version 1.1.2.0) + HELPERPROC pHelperProcAddress; // Used internally (Contains proc address for PUICallService) +} PLUGINUNINSTALLPARAMS; + + + + + +// | Helper +// ----------------------------- + + +// --------------------------------------------- +// -- Macro: Run service while uninstalling ---- +// --------------------------------------------- + +// Macro: PUICallService + +#define PUICallService(service, wParam, lParam) (ppup->pHelperProcAddress) (service, wParam, lParam); + +// Description: +// ------------- +// This service provides the possibility to call a Miranda +// service in the "UninstallEx" function. +// Important!: Use this macro always instead of "CallService", +// because else a crash occurs when the plugin was decativated +// and gets uninstalled + +// Parameters: +// ------------- +// Same parameters as CallService of Miranda Core. + +// Return Values: +// -------------- +// Return values are the same as the CallService function of Miranda Core. +// Additionaly returns CALLSERVICE_NOTFOUND if Miranda is not loaded +// which means the services are not accessable. + + + // Example: + // ---------------------------------- + + //if ( (bIsMirandaRunning == TRUE) && (bDoDeleteSettings == TRUE) ) + //{ + // Remove plugin's module + //PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBMODULE, (WPARAM)"MyPlugin", 0); + //} + + + + +// --------------------------------------------- +// -- Function: Remove some files in directory - +// --------------------------------------------- + +// Function: PUIRemoveFilesInDirectory + +static BOOL __inline PUIRemoveFilesInDirectory(char* pszPath, const char* apszFiles[]); + +// Description: +// ------------- +// This helper provides the possibility to easily +// remove specified files in a specified directory. + +// Note: The last version of this helper (PUIRemoveFilesInPath) +// did not work correctly. +// Please do now always append a NULL slot to the end of your array. + +// Parameters: +// ------------- +// char* pszPath = Path to the files in array +// const LPCSTR apszFiles[] = NULL-terminated array of files to be deleted. + +// Return Values: +// -------------- +// Returns TRUE if the files could be deleted. +// FALSE if the files could not be deleted or did not exist. + + +static BOOL __inline PUIRemoveFilesInDirectory(char* pszPath, const char* apszFiles[]) +{ + char szFile[MAX_PATH]; + BOOL bReturn = FALSE; + int iFile = 0; + + while (apszFiles[iFile] != NULL) + { + strncpy(szFile, pszPath, SIZEOF(szFile)); + strncat(szFile, apszFiles[iFile], SIZEOF(szFile)-strlen(szFile)); + + if ((BOOL)DeleteFile(szFile) == TRUE) bReturn = TRUE; + iFile++; + } + + return bReturn; +} + + // Example: + // ---------------------------------- + + //const char* apszFiles[] = {"File1.txt", "File2.txt", "File3.txt", NULL}; + //PUIRemoveFilesInDirectory(ppup->pszPluginsPath, apszFiles); + + + + +// | Events +// ----------------------------- + + +// --------------------------------------------- +// -- Event: Allow to uninstall a plugin ------- +// --------------------------------------------- + +// Event: ME_PLUGINUNINSTALLER_OKTOUNINSTALL + +#define ME_PLUGINUNINSTALLER_OKTOUNINSTALL "PluginUninstaller/OkToUninstall" + +// Submitted Values: +// ----------------- +// wParam = pszPluginName (String containing the translated plugin name) +// lParam = pszPluginFile (String containing the plugin dll file name in lower case) + +// Return Values: +// ----------------- +// Returning 1 on this event causes the "Remove Plugin" button to be disabled. + + + +// --------------------------------------------- +// -- Event: Plugin gets uninstalled ----------- +// --------------------------------------------- + +// Event: ME_PLUGINUNINSTALLER_UNINSTALL + +#define ME_PLUGINUNINSTALLER_UNINSTALL "PluginUninstaller/Uninstall" + +// Submitted Values: +// ----------------- +// wParam = pszPluginName (String containing the translated plugin name) +// lParam = pszPluginFile (String containing the plugin dll file name in lower case) + +// Return Values: +// ----------------- +// Returning 1 on this event causes the uninstall process to be canceled. + +// Notice: +// Hook this event if you would like to ask the user for something to remove/uninstall +// and show your message box on this event. Save the action the user chose in a +// global BOOL variable and do the chosen action in "UninstallEx". +// You can get the plugins options window handle with MS_PLUGINUNINSTALLER_GETHANDLE. + +// Other plugins can use this event to be noticed that another plugin isn't installed anylonger. + + + + +// | Services +// ----------------------------- + + +// --------------------------------------------- +// -- Service: Remove database module ---------- +// --------------------------------------------- + +// Service: MS_PLUGINUNINSTALLER_REMOVEDBMODULE + +#define MS_PLUGINUNINSTALLER_REMOVEDBMODULE "PluginUninstaller/RemoveDbModule" + +// Description: +// ------------- +// This service provides the possibility to delete all database modules +// associated to your plugin. +// The specified database module will be removed in all contacts +// including the NULL contact. +// Remember to call it always with PUICallService in "UninstallEx" function. + +// Parameters: +// ------------- +// wParam = (char*)pszModule // Pointer to a string containd module name. Can't be NULL +// lParam = (const char*)apszIgnoreSettings // NULL terminated array of strings. Can be 0 if no settings should be ignored. + // See example 3 for more details + +// Return Values: +// -------------- +// Returns 0 on success. +// Nonzero if the module was not present in database. + + +#ifndef UNINSTALLER_NOHELPERS + +// Can only be used in "UninstallEx" function +#define PUIRemoveDbModule(pszModule) PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBMODULE, (WPARAM)pszModule, 0); + +#endif + + + // Example 1: + // ---------------------------------- + + //PUIRemoveDbModule("MyPlugin"); + + + // Example 2: + // ---------------------------------- + + //char szModule[] = "MyModule"; + //PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBMODULE, (WPARAM)szModule, 0); + + + // Example 3: + // ---------------------------------- + + // This deletes all settings in the specified module exept + // the specified settings: "Setting1",..."Setting4" + + // char szModule[] = "MyModule"; + // const char* apszIgnoreSettings[] = {"Setting1", "Setting2", "Setting3", "Setting4", NULL}; + // PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBMODULE, (WPARAM)szModule, (LPARAM)&apszIgnoreSettings); + + + +// --------------------------------------------- +// -- Service: Remove a setting globally ------- +// --------------------------------------------- + +// Service: MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY + +#define MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY "PluginUninstaller/RemoveDbSettingGlobally" + +// Description: +// ------------- +// This service provides the possibility to delete a specific +// setting in database in all contacts including the NULL contact. +// Remember to call it always with PUICallService in "UninstallEx" function. + +// Parameters: +// ------------- +// wParam = (char*)pszModule +// lParam = (char*)pszSetting + +// Return Values: +// -------------- +// Returns 0 on success. +// Nonzero if the setting was not present in database. + + +#ifndef UNINSTALLER_NOHELPERS + +// Can only be used in "UninstallEx" function +#define PUIRemoveDbSettingGlobally(pszModule, pszSetting) PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY, (WPARAM)pszModule, (LPARAM)pszSetting); + + +#endif + + + // Example 1: + // ---------------------------------- + + //PUIRemoveDbSettingGlobally("MyPlugin", "MySetting"); + + + // Example 2: + // ---------------------------------- + + //szModule[] = "MyPlugin"; + //szSetting[] = "MySetting"; + //PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBSETTINGGLOBALLY, (WPARAM)szModule, (LPARAM)szSetting); + + + + + + +// --------------------------------------------- +// -- Service: Remove skinned sound ------------ +// --------------------------------------------- + +// Service: MS_PLUGINUNINSTALLER_REMOVESKINSOUND + +#define MS_PLUGINUNINSTALLER_REMOVESKINSOUND "PluginUninstaller/RemoveSkinSound" + +// Description: +// ------------- +// This service provides the possibility to delete all your sound settings +// associated to your plugin. +// The specified sound will be be removed. +// Remember to call it always with PUICallService in "UninstallEx" function. + +// Parameters: +// ------------- +// wParam = (char*)pszSoundSetting +// lParam = 0 + +// Return Values: +// -------------- +// Returns 0 on success. +// Nonzero if the sound was not present in database. + + +#ifndef UNINSTALLER_NOHELPERS + +// Can only be used in "UninstallEx" function +#define PUIRemoveSkinSound(pszSoundSetting) PUICallService(MS_PLUGINUNINSTALLER_REMOVESKINSOUND, (WPARAM)pszSoundSetting, 0); + +#endif + + + // Example 1: + // ---------------------------------- + + //PUIRemoveSkinSound("MySoundSetting"); + + + // Example 2: + // ---------------------------------- + + //szSoundModule[] = "MySoundSetting"; + //PUICallService(MS_PLUGINUNINSTALLER_REMOVEDBMODULE, (WPARAM)szSoundSetting, 0); + + + + + +// --------------------------------------------- +// -- Service: Uninstall a plugin -------------- +// --------------------------------------------- + +// Service: MS_PLUGINUNINSTALLER_UNINSTALLPLUGIN + +#define MS_PLUGINUNINSTALLER_UNINSTALLPLUGIN "PluginUninstaller/UninstallPlugin" + +// Description: +// ------------- +// This service marks a plugin to be uninstalled at next restart of Miranda IM. +// It uses the default value for "Delete all settings". +// You can use this service for example when you want that your sub-plugin gets +// also removed when your main-plugin is uninstalled. +// Note: This service is not needed for the normal uninstalling functionality. + +// Parameters: +// ------------- +// wParam = (char*)pszPluginName // do not translate this! +// lParam = (char*)pszPluginFile // without path, only file name! + +// Return Values: +// -------------- +// Returns always 0. + + +#ifndef UNINSTALLER_NOHELPERS + +int __inline PUIUninstallPlugin(char* pszPluginName, char* pszPluginFile) +{ + return CallService(MS_PLUGINUNINSTALLER_UNINSTALLPLUGIN, (WPARAM)pszPluginName, (LPARAM)pszPluginFile); +} + +#endif + + + // Example 1: + // ---------------------------------- + + //PUIUninstallPlugin("PluginName", "plugin.dll"); + + + // Example 2: + // ---------------------------------- + + // hInst => Handle of a specific (your?) plugin + // char szPluginName[] = "YourPluginName"; + + //char* pFileName; + //char szPath[MAX_PATH]; + + //GetModuleFileName(hInst, szPath, sizeof(szPath)); + //pFileName = strrchr(szPath, '\\'); + //pFileName = pFileName+1; // Pointer arithmetic + + //CallService(MS_PLUGINUNINSTALLER_UNINSTALLPLUGIN, (WPARAM)szPluginName, (LPARAM)pFileName); + + + + +// --------------------------------------------- +// -- Service: Getting handles ----------------- +// --------------------------------------------- + +// Service: MS_PLUGINUNINSTALLER_GETHANDLE + +#define MS_PLUGINUNINSTALLER_GETHANDLE "PluginUninstaller/GetHandle" + +// Description: +// ------------- +// This service gets a specified window/instance handle. + +// Note: This service must not be used in "UninstallEx" function. +// It is mainly thought for being used in ME_PLUGINUNINSTALLER_UNINSTALL event +// to give out a MessageBox or something like that. + +// Parameters: +// ------------- +// wParam = UINT uHandleType; +// lParam = 0 + +// Possible values for wParam: +#define PUIHT_HINST_PLUGIN_INSTANCE 0 // HINSTANCE of the PluginUninstaller plugin +#define PUIHT_HWND_PLUGIN_OPTIONS 1 // HWND of the plugin options dialog (if it is loaded; else NULL) + +// Return Values: +// -------------- +// Returns the specified handle value. +// If no handle type is specified it returns NULL. +// The handle doesn't need to be destroyed. + + +#ifndef UNINSTALLER_NOHELPERS + +HANDLE __inline PUIGetHandle(UINT uHandleType) +{ + return (HANDLE)CallService(MS_PLUGINUNINSTALLER_GETHANDLE, uHandleType, 0); +} + +#endif + + + // Example + // ---------------------------------- + + //HWND hwndDlg; + //hwndDlg = (HWND)PUIGetHandle(PUIHT_HWND_PLUGIN_OPTIONS); + + + + + +#endif // M_UNINSTALLER_H diff --git a/plugins/Scriver/chat/main.c b/plugins/Scriver/chat/main.c new file mode 100644 index 0000000000..115eca156d --- /dev/null +++ b/plugins/Scriver/chat/main.c @@ -0,0 +1,111 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "../commonheaders.h" +#include "chat.h" + +void RegisterChatFonts( void ); + +extern struct GlobalMessageData *g_dat; +extern CRITICAL_SECTION cs; +//globals +HINSTANCE g_hInst; +HMENU g_hMenu = NULL; +HANDLE hJoinMenuItem, hLeaveMenuItem; + +FONTINFO aFonts[OPTIONS_FONTCOUNT]; +HBRUSH hListBkgBrush = NULL; +HBRUSH hListSelectedBkgBrush = NULL; + +TCHAR* pszActiveWndID = 0; +char* pszActiveWndModule = 0; + +struct GlobalLogSettings_t g_Settings; + +int Chat_Load() +{ + InitializeCriticalSection(&cs); + g_hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENU)); + CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) g_hMenu, 0); + HookEvents(); + CreateServiceFunctions(); + CreateHookableEvents(); + return 0; +} + +int Chat_Unload(void) +{ + DBWriteContactSettingWord(NULL, "Chat", "SplitterX", (WORD)g_Settings.iSplitterX); + + CList_SetAllOffline(TRUE, NULL); + + mir_free( pszActiveWndID ); + mir_free( pszActiveWndModule ); + + DestroyHookableEvents(); + + DestroyMenu(g_hMenu); + FreeIcons(); + OptionsUnInit(); + DeleteCriticalSection(&cs); + return 0; +} + +int Chat_ModulesLoaded(WPARAM wParam,LPARAM lParam) +{ + char* mods[3] = { "Chat", "ChatFonts" }; + CallService( "DBEditorpp/RegisterModule", (WPARAM)mods, 2 ); + RegisterChatFonts(); + OptionsInit(); + 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 = ( HANDLE )CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & 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 = ( HANDLE )CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi); + } + CList_SetAllOffline(TRUE, NULL); + return 0; +} + + +void LoadIcons(void) +{ + LoadMsgLogBitmaps(); + return ; +} + +void FreeIcons(void) +{ + FreeMsgLogBitmaps(); + return; +} diff --git a/plugins/Scriver/chat/manager.c b/plugins/Scriver/chat/manager.c new file mode 100644 index 0000000000..62542fd14a --- /dev/null +++ b/plugins/Scriver/chat/manager.c @@ -0,0 +1,1402 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "../commonheaders.h" +#include "chat.h" + +extern TCHAR* pszActiveWndID ; +extern char* pszActiveWndModule ; +extern struct MM_INTERFACE mmi ; + +extern struct GlobalMessageData *g_dat; + +void LoadModuleIcons(MODULEINFO * mi); + +#define WINDOWS_COMMANDS_MAX 30 +#define STATUSICONCOUNT 6 + +SESSION_INFO* m_WndList = 0; +TABLIST * g_TabList = 0; +MODULEINFO *m_ModList = 0; + +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 ); + node->windowData.flags = CWDF_RTF_INPUT; + + if (m_WndList == NULL) { // list is empty + m_WndList = node; + node->next = NULL; + } + else { + node->next = m_WndList; + m_WndList = node; + } + return node; + } + return NULL; +} + +int SM_RemoveSession( const TCHAR* pszID, const char* pszModule) +{ + 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 + { + 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->windowData.hContact) + { + CList_SetOffline(pTemp->windowData.hContact, pTemp->iType == GCW_CHATROOM?TRUE:FALSE); +/* if (pTemp->iType != GCW_SERVER) + DBWriteContactSettingByte(pTemp->windowData.hContact, "CList", "Hidden", 1);*/ + } + DBWriteContactSettingString(pTemp->windowData.hContact, pTemp->pszModule , "Topic", ""); + DBWriteContactSettingString(pTemp->windowData.hContact, pTemp->pszModule, "StatusBar", ""); + DBDeleteContactSetting(pTemp->windowData.hContact, "CList", "StatusMsg"); + + mir_free( pTemp->pszModule ); + mir_free( pTemp->ptszID ); + mir_free( pTemp->ptszName ); + mir_free( pTemp->ptszStatusbarText ); + mir_free( pTemp->ptszTopic ); + mir_free( pTemp->pszHeader ); + #if defined( _UNICODE ) + mir_free( pTemp->pszID ); + mir_free( pTemp->pszName ); + #endif + + // delete commands + tcmdlist_free(pTemp->windowData.cmdList); + 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; + + if ( !pszID || !pszModule ) + return NULL; + + while ( pTemp != NULL ) { + if ( !lstrcmpi( pTemp->ptszID, pszID ) && !lstrcmpiA(pTemp->pszModule,pszModule)) + return pTemp; + + pTemp = pTemp->next; + } + return NULL; +} + +HWND SM_FindWindowByContact(HANDLE hContact) +{ + SESSION_INFO *pTemp = m_WndList; + + while ( pTemp != NULL ) { + if ( pTemp->windowData.hContact == hContact) + return pTemp->hWnd; + + 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_CHAT_LIST), NULL, NULL, RDW_INVALIDATE); + if (pszID) + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +char SM_GetStatusIndicator(SESSION_INFO* si, USERINFO * ui) +{ + STATUSINFO * ti; + if (!ui || !si) + return '\0'; + + ti = TM_FindStatus(si->pStatuses, TM_WordToString(si->pStatuses, ui->Status)); + if (ti) + { + if ((INT_PTR)ti->hIcon < STATUSICONCOUNT) + { + INT_PTR id = si->iStatusCount - (INT_PTR)ti->hIcon - 1; + if (id == 0) + return '\0'; + if (id == 1) + return '+'; + if (id == 2) + return '%'; + if (id == 3) + return '@'; + if (id == 4) + return '!'; + if (id == 5) + return '*'; + } + else + return '\0'; + } + return '\0'; +} + +HICON SM_GetStatusIcon(SESSION_INFO* si, USERINFO * ui) +{ + STATUSINFO * ti; + if (!ui || !si) + return NULL; + + ti = TM_FindStatus(si->pStatuses, TM_WordToString(si->pStatuses, ui->Status)); + if (ti) + { + if ((INT_PTR)ti->hIcon < STATUSICONCOUNT) + { + INT_PTR id = si->iStatusCount - (INT_PTR)ti->hIcon - 1; + char name[128]; + sprintf(name, "chat_status%d", id); + return GetCachedIcon(name); + } + else + return ti->hIcon; + } + return GetCachedIcon("chat_status0"); +} + +BOOL SM_AddEventToAllMatchingUID(GCEVENT * gce) +{ + 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, FALSE, 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 + 20) { + LM_TrimLog(&pTemp->pLog, &pTemp->pLogEnd, pTemp->iEventCount - g_Settings.iEventLimit); + pTemp->iEventCount = g_Settings.iEventLimit; + return FALSE; + } + return TRUE; + } + pLast = pTemp; + pTemp = pTemp->next; + } + return TRUE; +} + +USERINFO * SM_AddUser( SESSION_INFO * si, const TCHAR* pszUID, const TCHAR* pszNick, WORD wStatus) +{ + USERINFO * p = UM_AddUser( si->pStatuses, &si->pUsers, pszUID, pszNick, wStatus); + si->nUsersInNicklist++; + return p; +} + +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_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->windowData.hContact ) { + if ( pTemp->iType != GCW_SERVER && wStatus != ID_STATUS_OFFLINE ) + DBDeleteContactSetting(pTemp->windowData.hContact, "CList", "Hidden"); + + DBWriteContactSettingWord(pTemp->windowData.hContact, pTemp->pszModule, "Status", (WORD)wStatus); + } + + PostMessage(pTemp->hWnd, GC_FIXTABICONS, 0, 0); + + 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 (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->windowData.hContact) + CList_SetOffline(m_WndList->windowData.hContact, m_WndList->iType == GCW_CHATROOM?TRUE:FALSE); + DBWriteContactSettingString(m_WndList->windowData.hContact, m_WndList->pszModule , "Topic", ""); + DBDeleteContactSetting(m_WndList->windowData.hContact, "CList", "StatusMsg"); + DBWriteContactSettingString(m_WndList->windowData.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 ); + mir_free( m_WndList->pszHeader); + tcmdlist_free(m_WndList->windowData.cmdList); + mir_free(m_WndList); + m_WndList = pLast; + } + m_WndList = NULL; + return TRUE; +} + +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_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; + +} + +char* SM_GetUsers(SESSION_INFO* si) +{ + SESSION_INFO* pTemp = m_WndList; + USERINFO* utemp = NULL; + 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 = mir_realloc( p, alloced += 4096 ); + + #if !defined( _UNICODE ) + lstrcpy( p + pLen, utemp->pszUID ); + #else + WideCharToMultiByte( CP_ACP, 0, utemp->pszUID, -1, p + pLen, nameLen+1, 0, 0 ); + #endif + lstrcpyA( p + pLen + nameLen, " " ); + utemp = utemp->next; + } + while ( utemp != NULL ); + return p; +} + + +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; + +} + + +//--------------------------------------------------- +// 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_calloc(sizeof(MODULEINFO)); + + node->pszModule = mir_strdup(pszModule); + + if (m_ModList == NULL) // list is empty + { + m_ModList = node; + } + else + { + node->next = m_ModList; + m_ModList = node; + } + return node; + } + return FALSE; +} + +void MM_IconsChanged(void) +{ + MODULEINFO *pTemp = m_ModList; + + while (pTemp != NULL) + { + if (pTemp->hOnlineTalkIcon) + DestroyIcon(pTemp->hOnlineTalkIcon); + if (pTemp->hOfflineTalkIcon) + DestroyIcon(pTemp->hOfflineTalkIcon); + + LoadModuleIcons(pTemp); + pTemp = pTemp->next; + } + return; +} +void MM_FontsChanged(void) +{ + SESSION_INFO* pTemp = m_WndList; + SetIndentSize(); + while (pTemp != NULL) + { + pTemp->pszHeader = Log_CreateRtfHeader(MM_FindModule(pTemp->pszModule), 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); + mir_free(m_ModList->crColors); + + if (m_ModList->hOnlineTalkIcon) + DestroyIcon(m_ModList->hOnlineTalkIcon); + if (m_ModList->hOfflineTalkIcon) + DestroyIcon(m_ModList->hOfflineTalkIcon); + + 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_PTR)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_PTR)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 +//--------------------------------------------------- + + +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 )) + return lstrcmp( u1->pszNick, pszNick ); + + dw1 = dw1 >> 1; + dw2 = dw2 >> 1; + } + 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 = _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/Scriver/chat/message.c b/plugins/Scriver/chat/message.c new file mode 100644 index 0000000000..2951cc3856 --- /dev/null +++ b/plugins/Scriver/chat/message.c @@ -0,0 +1,351 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "../commonheaders.h" +#include "chat.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 )) + temp[i++] = *p++; + temp[i] = 0; + + if ( result != NULL ) + *result = atoi( temp ); + + return i; +} + +TCHAR* DoRtfToTags( char* pszText, SESSION_INFO* si) +{ + char *p1; + int* pIndex; + int i, iRemoveChars; + char InsertThis[50]; + BOOL bJustRemovedRTF = TRUE; + BOOL bTextHasStarted = FALSE; + #if defined(_UNICODE) + TCHAR *ptszResult; + #endif + 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 = 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, "\\line", 5 )) { // newline + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = 5; + strcpy(InsertThis, "\n" ); + } + else if (!memcmp(p1, "\\bullet", 7)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; +#if defined(_UNICODE) + strcpy(InsertThis, "\xE2\x80\xA2"); +#else + strcpy(InsertThis, "\x95"); +#endif + } + else if ( !memcmp(p1, "\\b", 2 )) { //bold + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = (p1[2] != '0')?2:3; + mir_snprintf(InsertThis, SIZEOF(InsertThis), (p1[2] != '0') ? "%%b": "%%B" ); + } + else if ( !memcmp(p1, "\\i", 2 )) { // italics + bTextHasStarted = bJustRemovedRTF = TRUE; + iRemoveChars = (p1[2] != '0')?2:3; + mir_snprintf(InsertThis, SIZEOF(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 ( !memcmp(p1, "\\tab", 4 )) { // tab + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 4; + strcpy(InsertThis, " " ); + } + else if (!memcmp(p1, "\\endash", 7)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; +#if defined(_UNICODE) + strcpy(InsertThis, "\xE2\x80\x93"); +#else + strcpy(InsertThis, "\x96"); +#endif + } + else if (!memcmp(p1, "\\emdash", 7)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; +#if defined(_UNICODE) + strcpy(InsertThis, "\xE2\x80\x94"); +#else + strcpy(InsertThis, "\x97"); +#endif + } + else if (!memcmp(p1, "\\lquote",7)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; +#if defined(_UNICODE) + strcpy(InsertThis, "\xE2\x80\x98"); +#else + strcpy(InsertThis, "\x91"); +#endif + } + else if (!memcmp(p1, "\\rquote",7)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 7; +#if defined(_UNICODE) + strcpy(InsertThis, "\xE2\x80\x99"); +#else + strcpy(InsertThis, "\x92"); +#endif + } + else if (!memcmp(p1, "\\ldblquote",10)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 10; +#if defined(_UNICODE) + strcpy(InsertThis, "\xe2\x80\x9c"); +#else + strcpy(InsertThis, "\""); +#endif + } + else if (!memcmp(p1, "\\rdblquote",10)) { + bTextHasStarted = TRUE; + bJustRemovedRTF = TRUE; + iRemoveChars = 10; +#if defined(_UNICODE) + strcpy(InsertThis, "\xe2\x80\x9d"); +#else + strcpy(InsertThis, "\""); +#endif + } + 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; +#if defined(_UNICODE) + strcpy(InsertThis, "\xC2\xA0"); +#else + strcpy(InsertThis, "\xA0"); +#endif + } + 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; + mir_snprintf(InsertThis, SIZEOF(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); + + #if !defined( _UNICODE ) + return pszText; + #else + mir_utf8decode(pszText, &ptszResult); + return ptszResult; + #endif +} + diff --git a/plugins/Scriver/chat/options.c b/plugins/Scriver/chat/options.c new file mode 100644 index 0000000000..bf768be19e --- /dev/null +++ b/plugins/Scriver/chat/options.c @@ -0,0 +1,953 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "../commonheaders.h" +#include "chat.h" +#include +#include + +#define UM_CHECKSTATECHANGE (WM_USER+100) + +extern HANDLE g_hInst; +extern HBRUSH hListBkgBrush; +extern HBRUSH hListSelectedBkgBrush; +extern FONTINFO aFonts[OPTIONS_FONTCOUNT]; + +HANDLE g_hOptions = NULL; +static HWND hPathTip = 0; + +struct branch_t +{ + TCHAR* szDescr; + char* szDBName; + int iMode; + BYTE bDefault; + HTREEITEM hItem; +}; + +static struct branch_t branch1[] = { + {LPGENT("Flash when someone speaks"), "FlashWindow", 0,0, NULL}, + {LPGENT("Flash when a word is highlighted"), "FlashWindowHighlight", 0,1, NULL}, + {LPGENT("Show chat user list"), "ShowNicklist", 0,1, NULL}, + {LPGENT("Enable button context menus"), "RightClickFilter", 0,0, NULL}, + {LPGENT("Show topic on your contact list (if supported)"), "TopicOnClist", 0, 0, NULL}, + {LPGENT("Do not play sounds when focused"), "SoundsFocus", 0, 0, NULL}, + {LPGENT("Do not pop up when joining"), "PopupOnJoin", 0,0, NULL}, + {LPGENT("Show and hide by double clicking in the contact list"), "ToggleVisibility", 0,0, NULL}, + {LPGENT("Show contact statuses (if supported)"), "ShowContactStatus", 0,0, NULL}, + {LPGENT("Display contact status icon before role icon"), "ContactStatusFirst", 0,0, NULL}, + {LPGENT("Add \':\' to auto-completed names"), "AddColonToAutoComplete", 0, 1, NULL} +}; +static struct branch_t branch2[] = { + {LPGENT("Show icons"), "IconFlags", GC_EVENT_TOPIC|GC_EVENT_JOIN|GC_EVENT_QUIT| + GC_EVENT_MESSAGE|GC_EVENT_ACTION|GC_EVENT_HIGHLIGHT|GC_EVENT_PART| + GC_EVENT_KICK|GC_EVENT_NOTICE|GC_EVENT_NICK|GC_EVENT_INFORMATION|GC_EVENT_ADDSTATUS, 0, NULL}, + {LPGENT("Prefix all events with a timestamp"), "ShowTimeStamp", 0,1, NULL}, + {LPGENT("Only prefix with timestamp if it has changed"), "ShowTimeStampIfChanged", 0,0, NULL}, + {LPGENT("Timestamp has same colour as event"), "TimeStampEventColour", 0,0, NULL}, + {LPGENT("Indent the second line of a message"), "LogIndentEnabled", 0,1, NULL}, + {LPGENT("Limit user names to 20 characters"), "LogLimitNames", 0,1, NULL}, + {LPGENT("Strip colors from messages"), "StripFormatting", 0, 0, NULL}, + {LPGENT("Enable \'event filter\' for new rooms"), "FilterEnabled", 0,0, NULL} +}; +static struct branch_t branch3[] = { + {LPGENT("Show topic changes"), "FilterFlags", GC_EVENT_TOPIC, 0, NULL}, + {LPGENT("Show users joining"), "FilterFlags", GC_EVENT_JOIN, 0, NULL}, + {LPGENT("Show users disconnecting"), "FilterFlags", GC_EVENT_QUIT, 0, NULL}, + {LPGENT("Show messages"), "FilterFlags", GC_EVENT_MESSAGE, 1, NULL}, + {LPGENT("Show actions"), "FilterFlags", GC_EVENT_ACTION, 1, NULL}, + {LPGENT("Show users leaving"), "FilterFlags", GC_EVENT_PART, 0, NULL}, + {LPGENT("Show users being kicked"), "FilterFlags", GC_EVENT_KICK, 1, NULL}, + {LPGENT("Show notices"), "FilterFlags", GC_EVENT_NOTICE, 1, NULL}, + {LPGENT("Show users changing name"), "FilterFlags", GC_EVENT_NICK, 0, NULL}, + {LPGENT("Show information messages"), "FilterFlags", GC_EVENT_INFORMATION, 1, NULL}, + {LPGENT("Show status changes of users"), "FilterFlags", GC_EVENT_ADDSTATUS, 0, NULL}, +}; + +static struct branch_t branch4[] = { + {LPGENT("Show icons in tray only when the chat room is not active"), "TrayIconInactiveOnly", 0, 1, NULL}, + {LPGENT("Show icon in tray for topic changes"), "TrayIconFlags", GC_EVENT_TOPIC, 0, NULL}, + {LPGENT("Show icon in tray for users joining"), "TrayIconFlags", GC_EVENT_JOIN, 0, NULL}, + {LPGENT("Show icon in tray for users disconnecting"), "TrayIconFlags", GC_EVENT_QUIT, 0, NULL}, + {LPGENT("Show icon in tray for messages"), "TrayIconFlags", GC_EVENT_MESSAGE, 0, NULL}, + {LPGENT("Show icon in tray for actions"), "TrayIconFlags", GC_EVENT_ACTION, 0, NULL}, + {LPGENT("Show icon in tray for highlights"), "TrayIconFlags", GC_EVENT_HIGHLIGHT, 1, NULL}, + {LPGENT("Show icon in tray for users leaving"), "TrayIconFlags", GC_EVENT_PART, 0, NULL}, + {LPGENT("Show icon in tray for users kicking other user"), "TrayIconFlags", GC_EVENT_KICK, 0, NULL}, + {LPGENT("Show icon in tray for notices "), "TrayIconFlags", GC_EVENT_NOTICE, 0, NULL}, + {LPGENT("Show icon in tray for name changes"), "TrayIconFlags", GC_EVENT_NICK, 0, NULL}, + {LPGENT("Show icon in tray for information messages"), "TrayIconFlags", GC_EVENT_INFORMATION, 0, NULL}, + {LPGENT("Show icon in tray for status changes"), "TrayIconFlags", GC_EVENT_ADDSTATUS, 0, NULL}, +}; + +static struct branch_t branch6[] = { + {LPGENT("Show pop-ups only when the chat room is not active"), "PopUpInactiveOnly", 0, 1, NULL}, + {LPGENT("Show pop-up for topic changes"), "PopupFlags", GC_EVENT_TOPIC, 0, NULL}, + {LPGENT("Show pop-up for users joining"), "PopupFlags", GC_EVENT_JOIN, 0, NULL}, + {LPGENT("Show pop-up for users disconnecting"), "PopupFlags", GC_EVENT_QUIT, 0, NULL}, + {LPGENT("Show pop-up for messages"), "PopupFlags", GC_EVENT_MESSAGE, 0, NULL}, + {LPGENT("Show pop-up for actions"), "PopupFlags", GC_EVENT_ACTION, 0, NULL}, + {LPGENT("Show pop-up for highlights"), "PopupFlags", GC_EVENT_HIGHLIGHT, 0, NULL}, + {LPGENT("Show pop-up for users leaving"), "PopupFlags", GC_EVENT_PART, 0, NULL}, + {LPGENT("Show pop-up for users kicking other user"), "PopupFlags", GC_EVENT_KICK, 0, NULL}, + {LPGENT("Show pop-up for notices "), "PopupFlags", GC_EVENT_NOTICE, 0, NULL}, + {LPGENT("Show pop-up for name changes"), "PopupFlags", GC_EVENT_NICK, 0, NULL}, + {LPGENT("Show pop-up for information messages"), "PopupFlags", GC_EVENT_INFORMATION, 0, NULL}, + {LPGENT("Show pop-up for status changes"), "PopupFlags", GC_EVENT_ADDSTATUS, 0, NULL}, +}; + +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.item.state=bExpanded?INDEXTOSTATEIMAGEMASK(1)|TVIS_EXPANDED:INDEXTOSTATEIMAGEMASK(1); + 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; + + tvis.hParent=hParent; + tvis.hInsertAfter=TVI_LAST; + tvis.item.mask=TVIF_TEXT|TVIF_STATE; + for(i=0;i>12==1)?0:1; + if(branch[i].iMode) + { + if (bChecked) + iState |= branch[i].iMode; + if (iState&GC_EVENT_ADDSTATUS) + iState |= GC_EVENT_REMOVESTATUS; + DBWriteContactSettingDword(NULL, "Chat", branch[i].szDBName, (DWORD)iState); + } + else DBWriteContactSettingByte(NULL, "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==1)) + bChecked = FALSE; + } + tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem); + } + tvi.stateMask = TVIS_STATEIMAGEMASK; + tvi.state=INDEXTOSTATEIMAGEMASK(bChecked?2:1); + 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==2)) + bChecked = FALSE; + tvi.hItem=TreeView_GetNextItem(hwndTree, hHeading, TVGN_CHILD); + tvi.stateMask = TVIS_STATEIMAGEMASK; + while(tvi.hItem) { + tvi.state=INDEXTOSTATEIMAGEMASK(bChecked?2:1); + 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: + SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData); + break; + case BFFM_SELCHANGED: + if (SHGetPathFromIDListA((LPITEMIDLIST) lp ,szDir)) + SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szDir); + break; + } + return 0; +} + +void LoadLogFonts(void) +{ + int i; + for( i = 0; iidFrom) + { + case IDC_CHAT_CHECKBOXES: + if(((LPNMHDR)lParam)->code==NM_CLICK) { + 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)) + if(hti.flags&TVHT_ONITEMSTATEICON) { + SendMessage(hwndDlg, UM_CHECKSTATECHANGE, (WPARAM)((LPNMHDR)lParam)->hwndFrom, (LPARAM)hti.hItem); + } + + } else if (((LPNMHDR) lParam)->code == TVN_KEYDOWN) { + if (((LPNMTVKEYDOWN) lParam)->wVKey == VK_SPACE) { + SendMessage(hwndDlg, UM_CHECKSTATECHANGE, (WPARAM)((LPNMHDR)lParam)->hwndFrom, + (LPARAM)TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom)); + } + } + break; + + case 0: + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { + int iLen; + char * pszText = NULL; + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_CHAT_GROUP)); + if(iLen > 0) + { + pszText = mir_realloc(pszText, iLen+1); + GetDlgItemTextA(hwndDlg, IDC_CHAT_GROUP, pszText,iLen+1); + DBWriteContactSettingString(NULL, "Chat", "AddToGroup", pszText); + } + else DBWriteContactSettingString(NULL, "Chat", "AddToGroup", ""); + mir_free(pszText); + + iLen = SendDlgItemMessage(hwndDlg,IDC_CHAT_SPIN2,UDM_GETPOS,0,0); + if(iLen > 0) + DBWriteContactSettingByte(NULL, "Chat", "NicklistRowDist", (BYTE)iLen); + else + DBDeleteContactSetting(NULL, "Chat", "NicklistRowDist"); + SaveBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), branch1, SIZEOF(branch1)); + SaveBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), branch4, SIZEOF(branch4)); + + SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE); + } + return TRUE; + } + } + }break; + case WM_DESTROY: + { + BYTE b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), hListHeading1, TVIS_EXPANDED)&TVIS_EXPANDED?1:0; + DBWriteContactSettingByte(NULL, "Chat", "Branch1Exp", b); + b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), hListHeading4, TVIS_EXPANDED)&TVIS_EXPANDED?1:0; + DBWriteContactSettingByte(NULL, "Chat", "Branch5Exp", b); + }break; + + default:break; + } + return FALSE; +} + +BOOL CALLBACK DlgProcOptions2(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + static HTREEITEM hListHeading2= 0; + static HTREEITEM hListHeading3= 0; + switch (uMsg) { + case WM_INITDIALOG: + { + TCHAR tszTemp[MAX_PATH]; + + TranslateDialogDefault(hwndDlg); + SetWindowLong(GetDlgItem(hwndDlg,IDC_CHAT_CHECKBOXES),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_CHAT_CHECKBOXES),GWL_STYLE)|TVS_NOHSCROLL|TVS_CHECKBOXES); + 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(10000,0)); + SendDlgItemMessage(hwndDlg,IDC_CHAT_SPIN3,UDM_SETPOS,0,MAKELONG(DBGetContactSettingWord(NULL,"Chat","LoggingLimit",100),0)); + CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)g_Settings.pszLogDir, (LPARAM)tszTemp ); + SetDlgItemText(hwndDlg, IDC_CHAT_LOGDIRECTORY, tszTemp); + + if (ServiceExists(MS_UTILS_REPLACEVARS)) { + TCHAR tszTooltipText[2048]; + RECT rect; + + 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") ); + GetClientRect (GetDlgItem(hwndDlg, IDC_CHAT_LOGDIRECTORY), &rect); + rect.left = -85; + hPathTip = CreateToolTip(GetDlgItem(hwndDlg, IDC_CHAT_LOGDIRECTORY), tszTooltipText, TranslateT("Variables"), &rect); + SetTimer(hwndDlg, 0, 3000, NULL); + } + + + SetDlgItemText(hwndDlg, IDC_CHAT_HIGHLIGHTWORDS, g_Settings.pszHighlightWords); + SetDlgItemText(hwndDlg, IDC_CHAT_LOGTIMESTAMP, g_Settings.pszTimeStampLog); + SetDlgItemText(hwndDlg, IDC_CHAT_TIMESTAMP, g_Settings.pszTimeStamp); + SetDlgItemText(hwndDlg, IDC_CHAT_OUTSTAMP, g_Settings.pszOutgoingNick); + SetDlgItemText(hwndDlg, IDC_CHAT_INSTAMP, g_Settings.pszIncomingNick); + CheckDlgButton(hwndDlg, IDC_CHAT_HIGHLIGHT, g_Settings.HighlightEnabled); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_HIGHLIGHTWORDS), g_Settings.HighlightEnabled?TRUE:FALSE); + CheckDlgButton(hwndDlg, IDC_CHAT_LOGGING, g_Settings.LoggingEnabled); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_LOGDIRECTORY), g_Settings.LoggingEnabled?TRUE:FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_LOGDIRCHOOSE), g_Settings.LoggingEnabled?TRUE:FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIMIT), g_Settings.LoggingEnabled?TRUE:FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIMITTEXT2), g_Settings.LoggingEnabled?TRUE:FALSE); + + hListHeading2 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), TranslateT("Appearance"), DBGetContactSettingByte(NULL, "Chat", "Branch2Exp", 0)?TRUE:FALSE); + hListHeading3 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), TranslateT("Default events to show in new chat rooms if the \'event filter\' is enabled"), DBGetContactSettingByte(NULL, "Chat", "Branch3Exp", 0)?TRUE:FALSE); + FillBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), hListHeading2, branch2, SIZEOF(branch2), 0x0); + FillBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), hListHeading3, branch3, SIZEOF(branch3), 0x03E0); + SendMessage(hwndDlg, OPT_FIXHEADINGS, 0, 0); + + break; + } + case OPT_FIXHEADINGS: + CheckHeading(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), hListHeading2); + CheckHeading(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), hListHeading3); + break; + case WM_COMMAND: + if( (LOWORD(wParam) == IDC_CHAT_INSTAMP + || LOWORD(wParam) == IDC_CHAT_OUTSTAMP + || LOWORD(wParam) == IDC_CHAT_TIMESTAMP + || LOWORD(wParam) == IDC_CHAT_LOGLIMIT + || LOWORD(wParam) == IDC_CHAT_HIGHLIGHTWORDS + || LOWORD(wParam) == IDC_CHAT_LOGDIRECTORY + || LOWORD(wParam) == IDC_CHAT_LOGTIMESTAMP + || LOWORD(wParam) == IDC_CHAT_LIMIT) + && (HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus())) return 0; + + switch (LOWORD(wParam)) { + case IDC_CHAT_LOGGING: + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_LOGDIRECTORY), IsDlgButtonChecked(hwndDlg, IDC_CHAT_LOGGING) == BST_CHECKED?TRUE:FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_LOGDIRCHOOSE), IsDlgButtonChecked(hwndDlg, IDC_CHAT_LOGGING) == BST_CHECKED?TRUE:FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIMIT), IsDlgButtonChecked(hwndDlg, IDC_CHAT_LOGGING) == BST_CHECKED?TRUE:FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIMITTEXT2), IsDlgButtonChecked(hwndDlg, IDC_CHAT_LOGGING) == BST_CHECKED?TRUE:FALSE); + break; + case IDC_CHAT_LOGDIRCHOOSE: + { + 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) { + SHGetPathFromIDList(idList,tszDirectory); + lstrcat(tszDirectory, _T("\\")); + CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)tszDirectory, (LPARAM)tszTemp ); + SetWindowText(GetDlgItem(hwndDlg, IDC_CHAT_LOGDIRECTORY), lstrlen(tszTemp) > 1?tszTemp:DEFLOGFILENAME); + } + psMalloc->lpVtbl->Free(psMalloc,idList); + psMalloc->lpVtbl->Release(psMalloc); + } + break; + } + case IDC_CHAT_HIGHLIGHT: + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_HIGHLIGHTWORDS), IsDlgButtonChecked(hwndDlg, IDC_CHAT_HIGHLIGHT) == BST_CHECKED?TRUE:FALSE); + break; + } + + if(lParam != (LPARAM)NULL) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + + case UM_CHECKSTATECHANGE: + { + TVITEM tvi = {0}; + tvi.mask=TVIF_HANDLE|TVIF_STATE; + tvi.hItem=(HTREEITEM) lParam; + TreeView_GetItem((HWND)wParam,&tvi); + if (tvi.hItem == hListHeading2) + CheckBranches(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), hListHeading2); + else if (tvi.hItem == hListHeading3) + CheckBranches(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), hListHeading3); + else + PostMessage(hwndDlg, OPT_FIXHEADINGS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + } + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == IDC_CHAT_CHECKBOXES) { + if (((LPNMHDR)lParam)->code==NM_CLICK) { + 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)) + if(hti.flags&TVHT_ONITEMSTATEICON) { + SendMessage(hwndDlg, UM_CHECKSTATECHANGE, (WPARAM)((LPNMHDR)lParam)->hwndFrom, (LPARAM)hti.hItem); + } + + } else if (((LPNMHDR) lParam)->code == TVN_KEYDOWN) { + if (((LPNMTVKEYDOWN) lParam)->wVKey == VK_SPACE) { + SendMessage(hwndDlg, UM_CHECKSTATECHANGE, (WPARAM)((LPNMHDR)lParam)->hwndFrom, + (LPARAM)TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom)); + } + } + } else if (((LPNMHDR)lParam)->idFrom == 0 && ((LPNMHDR)lParam)->code == PSN_APPLY ) { + char *pszText = NULL; + int iLen; + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_CHAT_HIGHLIGHTWORDS)); + if ( iLen > 0 ) { + TCHAR *ptszText = mir_alloc((iLen+2) * sizeof(TCHAR)); + TCHAR *p2 = NULL; + + if(ptszText) { + GetDlgItemText(hwndDlg, IDC_CHAT_HIGHLIGHTWORDS, ptszText, iLen + 1); + p2 = _tcschr(ptszText, (TCHAR)','); + while ( p2 ) { + *p2 = ' '; + p2 = _tcschr(ptszText, (TCHAR)','); + } + DBWriteContactSettingTString(NULL, "Chat", "HighlightWords", ptszText); + mir_free(ptszText); + } + } + else DBDeleteContactSetting(NULL, "Chat", "HighlightWords"); + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_CHAT_LOGDIRECTORY)); + if ( iLen > 0 ) { + TCHAR *pszText1 = malloc(iLen*sizeof(TCHAR) + 2); + GetDlgItemText(hwndDlg, IDC_CHAT_LOGDIRECTORY, pszText1, iLen + 1); + DBWriteContactSettingTString(NULL, "Chat", "LogDirectory", pszText1); + CallService(MS_UTILS_PATHTOABSOLUTET, (WPARAM)pszText1, (LPARAM)g_Settings.pszLogDir); + free(pszText1); + } + else { + lstrcpyn(g_Settings.pszLogDir, DEFLOGFILENAME, MAX_PATH); + DBDeleteContactSetting(NULL, "Chat", "LogDirectory"); + } + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_CHAT_LOGTIMESTAMP)); + if ( iLen > 0 ) { + pszText = mir_realloc(pszText, iLen+1); + GetDlgItemTextA(hwndDlg, IDC_CHAT_LOGTIMESTAMP, pszText,iLen+1); + DBWriteContactSettingString(NULL, "Chat", "LogTimestamp", pszText); + } + else DBDeleteContactSetting(NULL, "Chat", "LogTimestamp"); + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_CHAT_TIMESTAMP)); + if( iLen > 0 ) { + pszText = mir_realloc(pszText, iLen+1); + GetDlgItemTextA(hwndDlg, IDC_CHAT_TIMESTAMP, pszText,iLen+1); + DBWriteContactSettingString(NULL, "Chat", "HeaderTime", pszText); + } + else DBDeleteContactSetting(NULL, "Chat", "HeaderTime"); + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_CHAT_INSTAMP)); + if ( iLen > 0 ) { + pszText = mir_realloc(pszText, iLen+1); + GetDlgItemTextA(hwndDlg, IDC_CHAT_INSTAMP, pszText,iLen+1); + DBWriteContactSettingString(NULL, "Chat", "HeaderIncoming", pszText); + } + else DBDeleteContactSetting(NULL, "Chat", "HeaderIncoming"); + + iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_CHAT_OUTSTAMP)); + if( iLen > 0 ) { + pszText = mir_realloc(pszText, iLen+1); + GetDlgItemTextA(hwndDlg, IDC_CHAT_OUTSTAMP, pszText,iLen+1); + DBWriteContactSettingString(NULL, "Chat", "HeaderOutgoing", pszText); + } + else DBDeleteContactSetting(NULL, "Chat", "HeaderOutgoing"); + + g_Settings.HighlightEnabled = IsDlgButtonChecked(hwndDlg, IDC_CHAT_HIGHLIGHT) == BST_CHECKED?TRUE:FALSE; + DBWriteContactSettingByte(NULL, "Chat", "HighlightEnabled", (BYTE)g_Settings.HighlightEnabled); + + g_Settings.LoggingEnabled = IsDlgButtonChecked(hwndDlg, IDC_CHAT_LOGGING) == BST_CHECKED?TRUE:FALSE; + DBWriteContactSettingByte(NULL, "Chat", "LoggingEnabled", (BYTE)g_Settings.LoggingEnabled); + + iLen = SendDlgItemMessage(hwndDlg,IDC_CHAT_SPIN2,UDM_GETPOS,0,0); + DBWriteContactSettingWord(NULL, "Chat", "LogLimit", (WORD)iLen); + iLen = SendDlgItemMessage(hwndDlg,IDC_CHAT_SPIN3,UDM_GETPOS,0,0); + DBWriteContactSettingWord(NULL, "Chat", "LoggingLimit", (WORD)iLen); + + SaveBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), branch2, SIZEOF(branch2)); + SaveBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), branch3, SIZEOF(branch3)); + + mir_free(pszText); + + g_Settings.dwIconFlags = DBGetContactSettingDword(NULL, "Chat", "IconFlags", 0x0000); + g_Settings.dwTrayIconFlags = DBGetContactSettingDword(NULL, "Chat", "TrayIconFlags", 0x1000); + g_Settings.dwPopupFlags = DBGetContactSettingDword(NULL, "Chat", "PopupFlags", 0x0000); + g_Settings.StripFormat = (BOOL)DBGetContactSettingByte(NULL, "Chat", "TrimFormatting", 0); + g_Settings.TrayIconInactiveOnly = (BOOL)DBGetContactSettingByte(NULL, "Chat", "TrayIconInactiveOnly", 1); + g_Settings.PopUpInactiveOnly = (BOOL)DBGetContactSettingByte(NULL, "Chat", "PopUpInactiveOnly", 1); + + g_Settings.LogIndentEnabled = (DBGetContactSettingByte(NULL, "Chat", "LogIndentEnabled", 1) != 0)?TRUE:FALSE; + MM_FontsChanged(); + SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE); + 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; + } + { + BYTE b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), hListHeading2, TVIS_EXPANDED)&TVIS_EXPANDED?1:0; + DBWriteContactSettingByte(NULL, "Chat", "Branch2Exp", b); + b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), hListHeading3, TVIS_EXPANDED)&TVIS_EXPANDED?1:0; + DBWriteContactSettingByte(NULL, "Chat", "Branch3Exp", b); + } + break; + } + return FALSE; +} + +static INT_PTR CALLBACK DlgProcOptionsPopup(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + SetWindowLong(GetDlgItem(hwndDlg,IDC_CHAT_CHECKBOXES),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_CHAT_CHECKBOXES),GWL_STYLE)|TVS_NOHSCROLL|TVS_CHECKBOXES); + SendDlgItemMessage(hwndDlg, IDC_CHAT_BKG, CPM_SETCOLOUR,0,g_Settings.crPUBkgColour); + SendDlgItemMessage(hwndDlg, IDC_CHAT_TEXT, CPM_SETCOLOUR,0,g_Settings.crPUTextColour); + + if(g_Settings.iPopupStyle ==2) + CheckDlgButton(hwndDlg, IDC_CHAT_RADIO2, BST_CHECKED); + else if(g_Settings.iPopupStyle ==3) + CheckDlgButton(hwndDlg, IDC_CHAT_RADIO3, BST_CHECKED); + else + CheckDlgButton(hwndDlg, IDC_CHAT_RADIO1, BST_CHECKED); + + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_BKG), IsDlgButtonChecked(hwndDlg, IDC_CHAT_RADIO3) ==BST_CHECKED?TRUE:FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_TEXT), IsDlgButtonChecked(hwndDlg, IDC_CHAT_RADIO3) ==BST_CHECKED?TRUE:FALSE); + + SendDlgItemMessage(hwndDlg,IDC_CHAT_SPIN1,UDM_SETRANGE,0,MAKELONG(100,-1)); + SendDlgItemMessage(hwndDlg,IDC_CHAT_SPIN1,UDM_SETPOS,0,MAKELONG(g_Settings.iPopupTimeout,0)); + //hListHeading6 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), TranslateT("Pop-ups to display"), TRUE); + FillBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), NULL, branch6, SIZEOF(branch6), 0x0000); + }break; + + case WM_COMMAND: + if( (LOWORD(wParam) == IDC_CHAT_TIMEOUT) + && (HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus())) return 0; + + if(lParam != (LPARAM)NULL) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + switch (LOWORD(wParam)) { + + case IDC_CHAT_RADIO1: + case IDC_CHAT_RADIO2: + case IDC_CHAT_RADIO3: + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_BKG), IsDlgButtonChecked(hwndDlg, IDC_CHAT_RADIO3) ==BST_CHECKED?TRUE:FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_TEXT), IsDlgButtonChecked(hwndDlg, IDC_CHAT_RADIO3) ==BST_CHECKED?TRUE:FALSE); + break; + + default:break; + } + + break; + + case WM_NOTIFY: + { + switch(((LPNMHDR)lParam)->idFrom) + { + case IDC_CHAT_CHECKBOXES: + if(((LPNMHDR)lParam)->code==NM_CLICK) { + 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)) + if(hti.flags&TVHT_ONITEMSTATEICON) { + SendMessage(hwndDlg, UM_CHECKSTATECHANGE, (WPARAM)((LPNMHDR)lParam)->hwndFrom, (LPARAM)hti.hItem); + } + + } else if (((LPNMHDR) lParam)->code == TVN_KEYDOWN) { + if (((LPNMTVKEYDOWN) lParam)->wVKey == VK_SPACE) { + SendMessage(hwndDlg, UM_CHECKSTATECHANGE, (WPARAM)((LPNMHDR)lParam)->hwndFrom, + (LPARAM)TreeView_GetSelection(((LPNMHDR)lParam)->hwndFrom)); + } + } + break; + case 0: + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { + int iLen; + + if(IsDlgButtonChecked(hwndDlg, IDC_CHAT_RADIO2) == BST_CHECKED) + iLen = 2; + else if(IsDlgButtonChecked(hwndDlg, IDC_CHAT_RADIO3) == BST_CHECKED) + iLen = 3; + else + iLen = 1; + + g_Settings.iPopupStyle = iLen; + DBWriteContactSettingByte(NULL, "Chat", "PopupStyle", (BYTE)iLen); + + iLen = SendDlgItemMessage(hwndDlg,IDC_CHAT_SPIN1,UDM_GETPOS,0,0); + g_Settings.iPopupTimeout = iLen; + DBWriteContactSettingWord(NULL, "Chat", "PopupTimeout", (WORD)iLen); + + g_Settings.crPUBkgColour = SendDlgItemMessage(hwndDlg,IDC_CHAT_BKG,CPM_GETCOLOUR,0,0); + DBWriteContactSettingDword(NULL, "Chat", "PopupColorBG", (DWORD)SendDlgItemMessage(hwndDlg,IDC_CHAT_BKG,CPM_GETCOLOUR,0,0)); + g_Settings.crPUTextColour = SendDlgItemMessage(hwndDlg,IDC_CHAT_TEXT,CPM_GETCOLOUR,0,0); + DBWriteContactSettingDword(NULL, "Chat", "PopupColorText", (DWORD)SendDlgItemMessage(hwndDlg,IDC_CHAT_TEXT,CPM_GETCOLOUR,0,0)); + SaveBranch(GetDlgItem(hwndDlg, IDC_CHAT_CHECKBOXES), branch6, SIZEOF(branch6)); + } + return TRUE; + } + } + }break; + case UM_CHECKSTATECHANGE: + { + PostMessage(hwndDlg, OPT_FIXHEADINGS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + break; + } + + default:break; + } + return FALSE; +} + +static int OptionsInitialize(WPARAM wParam, LPARAM lParam) +{ + + OPTIONSDIALOGPAGE odp = {0}; + if(g_dat->popupInstalled) + { + odp.cbSize = sizeof(odp); + odp.position = 910000002; + odp.hInstance = g_hInst; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONSPOPUP); + odp.ptszTitle = LPGENT("Messaging"); + odp.ptszGroup = LPGENT("Popups"); + odp.pfnDlgProc = DlgProcOptionsPopup; + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR; + odp.ptszTab = NULL; + CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp); + } + + return 0; +} + +void LoadGlobalSettings(void) +{ + LOGFONT lf; + + g_Settings.LogLimitNames = DBGetContactSettingByte(NULL, "Chat", "LogLimitNames", 1); + g_Settings.ShowTime = DBGetContactSettingByte(NULL, "Chat", "ShowTimeStamp", 1); + g_Settings.SoundsFocus = DBGetContactSettingByte(NULL, "Chat", "SoundsFocus", 0); + g_Settings.ShowTimeIfChanged = (BOOL)DBGetContactSettingByte(NULL, "Chat", "ShowTimeStampIfChanged", 0); + g_Settings.TimeStampEventColour = (BOOL)DBGetContactSettingByte(NULL, "Chat", "TimeStampEventColour", 0); + g_Settings.iEventLimit = DBGetContactSettingWord(NULL, "Chat", "LogLimit", 100); + g_Settings.dwIconFlags = DBGetContactSettingDword(NULL, "Chat", "IconFlags", 0x0000); + g_Settings.dwTrayIconFlags = DBGetContactSettingDword(NULL, "Chat", "TrayIconFlags", 0x1000); + g_Settings.dwPopupFlags = DBGetContactSettingDword(NULL, "Chat", "PopupFlags", 0x0000); + g_Settings.LoggingLimit = DBGetContactSettingWord(NULL, "Chat", "LoggingLimit", 100); + g_Settings.LoggingEnabled = (BOOL)DBGetContactSettingByte(NULL, "Chat", "LoggingEnabled", 0); + g_Settings.FlashWindow = (BOOL)DBGetContactSettingByte(NULL, "Chat", "FlashWindow", 0); + g_Settings.HighlightEnabled = (BOOL)DBGetContactSettingByte(NULL, "Chat", "HighlightEnabled", 1); + g_Settings.crUserListColor = DBGetContactSettingDword(NULL, "ChatFonts", "Font18Col", RGB(0,0,0)); + g_Settings.crUserListBGColor = DBGetContactSettingDword(NULL, "Chat", "ColorNicklistBG", GetSysColor(COLOR_WINDOW)); + g_Settings.crUserListSelectedBGColor = DBGetContactSettingDword(NULL, "Chat", "ColorNicklistSelectedBG", GetSysColor(COLOR_HIGHLIGHT)); + g_Settings.crUserListHeadingsColor = DBGetContactSettingDword(NULL, "ChatFonts", "Font19Col", RGB(170,170,170)); + g_Settings.crLogBackground = DBGetContactSettingDword(NULL, "Chat", "ColorLogBG", GetSysColor(COLOR_WINDOW)); + g_Settings.StripFormat = (BOOL)DBGetContactSettingByte(NULL, "Chat", "StripFormatting", 0); + g_Settings.TrayIconInactiveOnly = (BOOL)DBGetContactSettingByte(NULL, "Chat", "TrayIconInactiveOnly", 1); + g_Settings.PopUpInactiveOnly = (BOOL)DBGetContactSettingByte(NULL, "Chat", "PopUpInactiveOnly", 1); + g_Settings.AddColonToAutoComplete = (BOOL)DBGetContactSettingByte(NULL, "Chat", "AddColonToAutoComplete", 1); + g_Settings.iPopupStyle = DBGetContactSettingByte(NULL, "Chat", "PopupStyle", 1); + g_Settings.iPopupTimeout = DBGetContactSettingWord(NULL, "Chat", "PopupTimeout", 3); + g_Settings.crPUBkgColour = DBGetContactSettingDword(NULL, "Chat", "PopupColorBG", GetSysColor(COLOR_WINDOW)); + g_Settings.crPUTextColour = DBGetContactSettingDword(NULL, "Chat", "PopupColorText", 0); + g_Settings.ShowContactStatus = DBGetContactSettingByte(NULL, "Chat", "ShowContactStatus", 0); + g_Settings.ContactStatusFirst = DBGetContactSettingByte(NULL, "Chat", "ContactStatusFirst", 0); + + 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:")); + InitSetting( &g_Settings.pszHighlightWords, "HighlightWords", _T("%m")); + + { + DBVARIANT dbv; + g_Settings.pszLogDir = (TCHAR *)mir_realloc(g_Settings.pszLogDir, MAX_PATH*sizeof(TCHAR)); + if (!DBGetContactSettingTString(NULL, "Chat", "LogDirectory", &dbv)) { + lstrcpyn(g_Settings.pszLogDir, dbv.ptszVal, MAX_PATH); + DBFreeVariant(&dbv); + } else lstrcpyn(g_Settings.pszLogDir, DEFLOGFILENAME, MAX_PATH); + } + + g_Settings.LogIndentEnabled = (DBGetContactSettingByte(NULL, "Chat", "LogIndentEnabled", 1) != 0)?TRUE:FALSE; + + if(g_Settings.MessageBoxFont) + DeleteObject(g_Settings.MessageBoxFont); + LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, &lf, NULL, FALSE); + g_Settings.MessageBoxFont = CreateFontIndirect(&lf); + + if(g_Settings.UserListFont) + DeleteObject(g_Settings.UserListFont); + LoadMsgDlgFont(18, &lf, NULL, TRUE); + g_Settings.UserListFont = CreateFontIndirect(&lf); + + if(g_Settings.UserListHeadingsFont) + DeleteObject(g_Settings.UserListHeadingsFont); + LoadMsgDlgFont(19, &lf, NULL, TRUE); + g_Settings.UserListHeadingsFont = CreateFontIndirect(&lf); + if (hListBkgBrush != NULL) { + DeleteObject(hListBkgBrush); + } + hListBkgBrush = CreateSolidBrush(DBGetContactSettingDword(NULL, "Chat", "ColorNicklistBG", GetSysColor(COLOR_WINDOW))); + if (hListSelectedBkgBrush != NULL) { + DeleteObject(hListSelectedBkgBrush); + } + hListSelectedBkgBrush = CreateSolidBrush(DBGetContactSettingDword(NULL, "Chat", "ColorNicklistSelectedBG", GetSysColor(COLOR_HIGHLIGHT))); +} + +static void FreeGlobalSettings(void) +{ + mir_free(g_Settings.pszTimeStamp); + mir_free(g_Settings.pszTimeStampLog); + mir_free(g_Settings.pszIncomingNick); + mir_free(g_Settings.pszOutgoingNick); + mir_free(g_Settings.pszHighlightWords); + mir_free(g_Settings.pszLogDir); + if(g_Settings.MessageBoxFont) + DeleteObject(g_Settings.MessageBoxFont); + if(g_Settings.UserListFont) + DeleteObject(g_Settings.UserListFont); + if(g_Settings.UserListHeadingsFont) + DeleteObject(g_Settings.UserListHeadingsFont); +} + +void SetIndentSize() +{ + if (g_Settings.ShowTime) { + LOGFONT lf; + HFONT hFont; + int iText; + + LoadMsgDlgFont(0, &lf, NULL, TRUE); + hFont = CreateFontIndirect(&lf); + iText = GetTextPixelSize(MakeTimeStamp(g_Settings.pszTimeStamp, time(NULL)),hFont, TRUE); + DeleteObject(hFont); + g_Settings.LogTextIndent = iText*12/10; + } else { + g_Settings.LogTextIndent = 0; + } + +} + +int OptionsInit(void) +{ + LOGFONT lf; + + g_hOptions = HookEvent(ME_OPT_INITIALISE, OptionsInitialize); + + LoadLogFonts(); + LoadMsgDlgFont(18, &lf, NULL, TRUE); + lstrcpy(lf.lfFaceName, _T("MS Shell Dlg")); + lf.lfUnderline = lf.lfItalic = lf.lfStrikeOut = 0; + lf.lfHeight = -17; + lf.lfWeight = FW_BOLD; + g_Settings.NameFont = CreateFontIndirect(&lf); + g_Settings.UserListFont = NULL; + g_Settings.UserListHeadingsFont = NULL; + g_Settings.MessageBoxFont = NULL; + g_Settings.iSplitterX = DBGetContactSettingWord(NULL, "Chat", "SplitterX", 105); + LoadGlobalSettings(); + + SkinAddNewSoundEx("ChatMessage", LPGEN("Group chats"), LPGEN("Incoming 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")); + SetIndentSize(); + return 0; +} + + +int OptionsUnInit(void) +{ + FreeGlobalSettings(); + UnhookEvent(g_hOptions); + DeleteObject(hListBkgBrush); + DeleteObject(hListSelectedBkgBrush); + DeleteObject(g_Settings.NameFont); + return 0; +} diff --git a/plugins/Scriver/chat/services.c b/plugins/Scriver/chat/services.c new file mode 100644 index 0000000000..1104aa262b --- /dev/null +++ b/plugins/Scriver/chat/services.c @@ -0,0 +1,690 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "../commonheaders.h" +#include "chat.h" +#include "../msgwindow.h" + +extern HANDLE g_hInst; +extern HICON hIcons[30]; + +HANDLE hSendEvent; +HANDLE hBuildMenuEvent ; +HANDLE g_hHookContactDblClick, g_hHookPrebuildMenu; +CRITICAL_SECTION cs; + +#ifdef _WIN64 + +#define SIZEOF_STRUCT_GCREGISTER_V1 40 +#define SIZEOF_STRUCT_GCWINDOW_V1 48 +#define SIZEOF_STRUCT_GCEVENT_V1 76 +#define SIZEOF_STRUCT_GCEVENT_V2 80 + +#else + +#define SIZEOF_STRUCT_GCREGISTER_V1 28 +#define SIZEOF_STRUCT_GCWINDOW_V1 32 +#define SIZEOF_STRUCT_GCEVENT_V1 44 +#define SIZEOF_STRUCT_GCEVENT_V2 48 + +#endif + +int Chat_SmileyOptionsChanged(WPARAM wParam,LPARAM lParam) +{ + SM_BroadcastMessage(NULL, GC_REDRAWLOG, 0, 1, FALSE); + return 0; +} + +int Chat_PreShutdown(WPARAM wParam,LPARAM lParam) +{ + SM_BroadcastMessage(NULL, GC_CLOSEWINDOW, 0, 1, FALSE); + + SM_RemoveAll(); + MM_RemoveAll(); + return 0; +} + +int Chat_FontsChanged(WPARAM wParam,LPARAM lParam) +{ + LoadLogFonts(); + LoadMsgLogBitmaps(); + MM_FontsChanged(); + MM_FixColors(); + SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE); + return 0; +} + +int Chat_IconsChanged(WPARAM wParam,LPARAM lParam) +{ + FreeMsgLogBitmaps(); + LoadMsgLogBitmaps(); + MM_IconsChanged(); + SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, FALSE); + return 0; +} + +static 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; +} + +static 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->windowData.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 defined( _UNICODE ) + 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; + } + #else + if ( gci->Flags & ID ) gci->pszID = si->ptszID; + if ( gci->Flags & NAME ) gci->pszName = si->ptszName; + #endif + + LeaveCriticalSection(&cs); + return 0; + } + + LeaveCriticalSection(&cs); + return 1; +} + +void LoadModuleIcons(MODULEINFO * mi) { + int index; + + HIMAGELIST hList = ImageList_Create(16, 16, IsWinVerXPPlus() ? ILC_COLOR32 | ILC_MASK : ILC_COLOR8 | ILC_MASK, 0, 0); + + int overlayIcon = ImageList_AddIcon(hList, GetCachedIcon("chat_overlay")); + ImageList_SetOverlayImage(hList, overlayIcon, 1); + + mi->hOnlineIconBig = LoadSkinnedProtoIconBig(mi->pszModule, ID_STATUS_ONLINE); + mi->hOnlineIcon = LoadSkinnedProtoIcon(mi->pszModule, ID_STATUS_ONLINE); + index = ImageList_AddIcon(hList, mi->hOnlineIcon); + mi->hOnlineTalkIcon = ImageList_GetIcon(hList, index, ILD_TRANSPARENT | INDEXTOOVERLAYMASK(1)); + + mi->hOfflineIconBig = LoadSkinnedProtoIconBig(mi->pszModule, ID_STATUS_OFFLINE); + mi->hOfflineIcon = LoadSkinnedProtoIcon(mi->pszModule, ID_STATUS_OFFLINE); + index = ImageList_AddIcon(hList, mi->hOfflineIcon); + mi->hOfflineTalkIcon = ImageList_GetIcon(hList, index, ILD_TRANSPARENT | INDEXTOOVERLAYMASK(1)); + + ImageList_Destroy(hList); +} + +static 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_STRUCT_GCREGISTER_V1) + return GC_REGISTER_WRONGVER; + + #ifndef _UNICODE + if (gcr->dwFlags & GC_UNICODE) + return GC_REGISTER_NOUNICODE; + #endif + + 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->bFontSize = gcr->dwFlags&GC_FONTSIZE; + mi->bAckMsg = gcr->dwFlags&GC_ACKMSG ; + mi->bChanMgr = gcr->dwFlags&GC_CHANMGR ; + mi->bSingleFormat = gcr->dwFlags&GC_SINGLEFORMAT; + mi->iMaxText= gcr->iMaxText; + mi->nColorCount = gcr->nColors; + if ( gcr->nColors > 0) { + mi->crColors = mir_alloc(sizeof(COLORREF) * gcr->nColors); + memcpy(mi->crColors, gcr->pColors, sizeof(COLORREF) * gcr->nColors); + } + + CheckColorsInModule((char*)gcr->pszModule); + CList_SetAllOffline(TRUE, gcr->pszModule); + + LeaveCriticalSection(&cs); + return 0; + } + + LeaveCriticalSection(&cs); + return GC_REGISTER_ERROR; +} + +static 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_STRUCT_GCWINDOW_V1) + 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); + + if (mi->hOfflineIcon == NULL) { + LoadModuleIcons(mi); + } + // 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->iSplitterY = g_Settings.iSplitterY; + si->iLogFilterFlags = (int)DBGetContactSettingDword(NULL, "Chat", "FilterFlags", 0x03E0); + si->bFilterEnabled = DBGetContactSettingByte(NULL, "Chat", "FilterEnabled", 0); + si->bNicklistEnabled = DBGetContactSettingByte(NULL, "Chat", "ShowNicklist", 1); + #if defined( _UNICODE ) + if ( !( gcw->dwFlags & GC_UNICODE )) { + si->pszID = mir_strdup( gcw->pszID ); + si->pszName = mir_strdup( gcw->pszName ); + } + #endif + + 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->windowData.hContact = CList_AddRoom( gcw->pszModule, ptszID, szTemp, si->iType); + si->windowData.codePage = DBGetContactSettingWord(si->windowData.hContact, si->pszModule, "CodePage", (WORD) CP_ACP); + si->pszHeader = Log_CreateRtfHeader(mi, si); + DBWriteContactSettingString(si->windowData.hContact, si->pszModule , "Topic", ""); + DBDeleteContactSetting(si->windowData.hContact, "CList", "StatusMsg"); + if (si->ptszStatusbarText) + DBWriteContactSettingTString(si->windowData.hContact, si->pszModule, "StatusBar", si->ptszStatusbarText); + else + DBWriteContactSettingString(si->windowData.hContact, si->pszModule, "StatusBar", ""); + } + 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->hWnd ) + RedrawWindow(GetDlgItem(si2->hWnd, IDC_CHAT_LIST), NULL, NULL, RDW_INVALIDATE); + + } + } + + LeaveCriticalSection(&cs); + mir_free( ptszID ); + return 0; + } + + LeaveCriticalSection(&cs); + return GC_NEWSESSION_ERROR; +} + +static INT_PTR DoControl(GCEVENT * gce, WPARAM wp) +{ + if ( gce->pDest->iType == GC_EVENT_CONTROL ) { + switch (wp) { + case WINDOW_HIDDEN: + { + SESSION_INFO* 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: + { + SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + si->bInitDone = TRUE; + if (wp != SESSION_INITDONE || DBGetContactSettingByte(NULL, "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: + { + SESSION_INFO* 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); + } + SM_SendMessage(gce->pDest->ptszID, gce->pDest->pszModule, GC_EVENT_CONTROL + WM_USER + 500, wp, 0); + } + + else if (gce->pDest->iType == GC_EVENT_CHUID && gce->pszText) + { + SM_ChangeUID( gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszNick, gce->ptszText); + } + + else if (gce->pDest->iType == GC_EVENT_CHANGESESSIONAME && gce->pszText) + { + SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if ( si ) { + replaceStr( &si->ptszName, gce->ptszText ); + if (si->hWnd) + SendMessage(si->hWnd, DM_UPDATETITLEBAR, 0, 0); + + } + } + + else if (gce->pDest->iType == GC_EVENT_SETITEMDATA) { + SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) + si->dwItemData = gce->dwItemData; + } + + else if (gce->pDest->iType ==GC_EVENT_GETITEMDATA) { + SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + gce->dwItemData = si->dwItemData; + return si->dwItemData; + } + return 0; + } + else if (gce->pDest->iType ==GC_EVENT_SETSBTEXT) + { + SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if (si) { + replaceStr( &si->ptszStatusbarText, gce->ptszText ); + if ( si->ptszStatusbarText ) + DBWriteContactSettingTString(si->windowData.hContact, si->pszModule, "StatusBar", si->ptszStatusbarText); + else + DBWriteContactSettingString(si->windowData.hContact, si->pszModule, "StatusBar", ""); + if (si->hWnd) + { + SendMessage(si->hWnd, DM_UPDATESTATUSBAR, 0, 0); + } + } + } + else if (gce->pDest->iType == GC_EVENT_ACK) + { + SM_SendMessage(gce->pDest->ptszID, gce->pDest->pszModule, GC_ACKMESSAGE, 0, 0); + } + else if (gce->pDest->iType == GC_EVENT_SENDMESSAGE && gce->pszText) + { + SM_SendUserMessage( gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszText); + } + else if (gce->pDest->iType == GC_EVENT_SETSTATUSEX) + { + SM_SetStatusEx( gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszText, gce->dwItemData); + } + else 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( si, 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); + } + } + } +} + + +void ShowRoom(SESSION_INFO * si, WPARAM wp, BOOL bSetForeground) +{ + HWND hParent = NULL; + if (!si) + return; + + //Do we need to create a window? + if (si->hWnd == NULL) + { + hParent = GetParentWindow(si->windowData.hContact, TRUE); + si->hWnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CHANNEL), hParent, RoomWndProc, (LPARAM)si); + } + SendMessage(si->hWnd, DM_UPDATETABCONTROL, -1, (LPARAM)si); + SendMessage(GetParent(si->hWnd), CM_ACTIVATECHILD, 0, (LPARAM) si->hWnd); + SendMessage(GetParent(si->hWnd), CM_POPUPWINDOW, 0, (LPARAM) si->hWnd); + SendMessage(si->hWnd, WM_MOUSEACTIVATE, 0, 0); + SetFocus(GetDlgItem(si->hWnd, IDC_CHAT_MESSAGE)); +} + +static INT_PTR Service_AddEvent(WPARAM wParam, LPARAM lParam) +{ + GCEVENT *gce = (GCEVENT*)lParam, save_gce; + GCDEST *gcd = NULL, save_gcd; + TCHAR* pWnd = NULL; + char* pMod = NULL; + BOOL bIsHighlighted = FALSE; + BOOL bRemoveFlag = FALSE; + int iRetVal = GC_EVENT_ERROR; + + if ( gce == NULL ) + return GC_EVENT_ERROR; + + gcd = gce->pDest; + if ( gcd == NULL ) + return GC_EVENT_ERROR; + + if ( gce->cbSize != SIZEOF_STRUCT_GCEVENT_V1 && gce->cbSize != SIZEOF_STRUCT_GCEVENT_V2 ) + return GC_EVENT_WRONGVER; + + if ( !IsEventSupported( gcd->iType ) ) + return GC_EVENT_ERROR; + + EnterCriticalSection(&cs); + + #if defined( _UNICODE ) + 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 ); + gce->ptszText = a2tf( gce->ptszText, gce->dwFlags ); + gce->ptszUserInfo = a2tf( gce->ptszUserInfo, gce->dwFlags ); + } + #endif + + // 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: + { + SESSION_INFO* si = SM_FindSession(gce->pDest->ptszID, gce->pDest->pszModule); + if ( si ) { + if ( gce->pszText ) { + replaceStr( &si->ptszTopic, gce->ptszText); + DBWriteContactSettingTString( si->windowData.hContact, si->pszModule , "Topic", RemoveFormatting( si->ptszTopic )); + if ( DBGetContactSettingByte( NULL, "Chat", "TopicOnClist", 0 )) + DBWriteContactSettingTString( si->windowData.hContact, "CList" , "StatusMsg", RemoveFormatting( si->ptszTopic )); + } } + break; + } + case GC_EVENT_ADDSTATUS: + SM_GiveStatus( gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID, gce->ptszStatus ); + break; + + case GC_EVENT_REMOVESTATUS: + SM_TakeStatus( gce->pDest->ptszID, gce->pDest->pszModule, gce->ptszUID, gce->ptszStatus); + break; + + case GC_EVENT_MESSAGE: + case GC_EVENT_ACTION: + if ( !gce->bIsMe && gce->pDest->pszID && gce->pszText ) { + SESSION_INFO* si = SM_FindSession( gce->pDest->ptszID, gce->pDest->pszModule ); + if ( si ) + if ( IsHighlighted( si, gce->ptszText )) + bIsHighlighted = TRUE; + } + break; + + case GC_EVENT_NICK: + SM_ChangeNick( gce->pDest->ptszID, gce->pDest->pszModule, gce); + break; + + case GC_EVENT_JOIN: + AddUser(gce); + break; + + case GC_EVENT_PART: + case GC_EVENT_QUIT: + case GC_EVENT_KICK: + bRemoveFlag = TRUE; + 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 ); + if ( !bRemoveFlag ) { + iRetVal = 0; + goto LBL_Exit; + } } + + // add to log + if ( pWnd ) { + SESSION_INFO* 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 defined( _UNICODE ) + if ( !( gce->dwFlags & GC_UNICODE )) { + 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; + } + #endif + + 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) +{ + HookEvent_Ex(ME_CLIST_PREBUILDCONTACTMENU, CList_PrebuildContactMenu); +} + +void CreateServiceFunctions(void) +{ + CreateServiceFunction_Ex(MS_GC_REGISTER, Service_Register); + CreateServiceFunction_Ex(MS_GC_NEWSESSION, Service_NewChat); + CreateServiceFunction_Ex(MS_GC_EVENT, Service_AddEvent); + CreateServiceFunction_Ex(MS_GC_GETEVENTPTR, Service_GetAddEventPtr); + CreateServiceFunction_Ex(MS_GC_GETINFO, Service_GetInfo); + CreateServiceFunction_Ex(MS_GC_GETSESSIONCOUNT, Service_GetCount); + + CreateServiceFunction_Ex("GChat/DblClickEvent", CList_EventDoubleclickedSvc); + CreateServiceFunction_Ex("GChat/PrebuildMenuEvent", CList_PrebuildContactMenuSvc); + CreateServiceFunction_Ex("GChat/JoinChat", CList_JoinChat); + CreateServiceFunction_Ex("GChat/LeaveChat", CList_LeaveChat); +} + +void CreateHookableEvents(void) +{ + hSendEvent = CreateHookableEvent(ME_GC_EVENT); + hBuildMenuEvent = CreateHookableEvent(ME_GC_BUILDMENU); +} + +void DestroyHookableEvents(void) +{ + DestroyHookableEvent(hSendEvent); + DestroyHookableEvent(hBuildMenuEvent); +} diff --git a/plugins/Scriver/chat/tools.c b/plugins/Scriver/chat/tools.c new file mode 100644 index 0000000000..2dd4bedf3f --- /dev/null +++ b/plugins/Scriver/chat/tools.c @@ -0,0 +1,976 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "../commonheaders.h" +#include "chat.h" +#include +#include + +extern HINSTANCE g_hInst; +extern FONTINFO aFonts[OPTIONS_FONTCOUNT]; +extern HMENU g_hMenu; +extern HANDLE hBuildMenuEvent ; +extern HANDLE hSendEvent; + +TCHAR* RemoveFormatting(const TCHAR* pszWord) +{ + static TCHAR szTemp[10000]; + int i = 0; + int j = 0; + + if ( pszWord == 0 || lstrlen(pszWord) == 0 ) + return NULL; + + while(j < 9999 && i <= lstrlen( pszWord )) { + 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 { + szTemp[j] = pszWord[i]; + j++; + i++; + } } + + return (TCHAR*) &szTemp; +} + +static void __stdcall ShowRoomFromPopup(void * pi) +{ + SESSION_INFO* si = (SESSION_INFO*) pi; + ShowRoom(si, WINDOW_VISIBLE, TRUE); +} + +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);; + + CallFunctionAsync(ShowRoomFromPopup, si); + + PUDeletePopUp(hWnd); + return TRUE; + } + break; + case WM_CONTEXTMENU: + { + SESSION_INFO* si = (SESSION_INFO*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd,(LPARAM)0); + if (si->windowData.hContact) + if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->windowData.hContact, (LPARAM)0)) + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->windowData.hContact, (LPARAM)"chaticon"); + + PUDeletePopUp( 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 pd = {0}; + va_list marker; + static TCHAR szBuf[4*1024]; + + if (!fmt || lstrlen(fmt) == 0 || lstrlen(fmt) > 2000) + return 0; + + va_start(marker, fmt); + _vsntprintf(szBuf, 4096, fmt, marker); + va_end(marker); + + pd.lchContact = hContact; + + if ( hIcon ) + pd.lchIcon = hIcon ; + else + pd.lchIcon = GetCachedIcon("chat_window"); + + 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 = g_Settings.crLogBackground; + pd.colorText = crBkg; + } + + pd.PluginWindowProc = PopupDlgProc; + pd.PluginData = si; + return PUAddPopUpT(&pd); +} + +static BOOL DoTrayIcon(SESSION_INFO* si, GCEVENT * gce) +{ + int iEvent = gce->pDest->iType; + + if ( iEvent&g_Settings.dwTrayIconFlags ) { + switch ( iEvent ) { + case GC_EVENT_MESSAGE|GC_EVENT_HIGHLIGHT : + case GC_EVENT_ACTION|GC_EVENT_HIGHLIGHT : + CList_AddEvent(si->windowData.hContact, LoadSkinnedIcon(SKINICON_EVENT_MESSAGE), "chaticon", 0, TranslateT("%s wants your attention in %s"), gce->ptszNick, si->ptszName); + break; + case GC_EVENT_MESSAGE : + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_message_in"), "chaticon", CLEF_ONLYAFEW, TranslateT("%s speaks in %s"), gce->ptszNick, si->ptszName); + break; + case GC_EVENT_ACTION: + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_action"), "chaticon", CLEF_ONLYAFEW, TranslateT("%s speaks in %s"), gce->ptszNick, si->ptszName); + break; + case GC_EVENT_JOIN: + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_join"), "chaticon", CLEF_ONLYAFEW, TranslateT("%s has joined %s"), gce->ptszNick, si->ptszName); + break; + case GC_EVENT_PART: + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_part"), "chaticon", CLEF_ONLYAFEW, TranslateT("%s has left %s"), gce->ptszNick, si->ptszName); + break; + case GC_EVENT_QUIT: + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_quit"), "chaticon", CLEF_ONLYAFEW, TranslateT("%s has disconnected"), gce->ptszNick); + break; + case GC_EVENT_NICK: + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_nick"), "chaticon", CLEF_ONLYAFEW, TranslateT("%s is now known as %s"), gce->ptszNick, gce->pszText); + break; + case GC_EVENT_KICK: + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_kick"), "chaticon", CLEF_ONLYAFEW, TranslateT("%s kicked %s from %s"), gce->pszStatus, gce->ptszNick, si->ptszName); + break; + case GC_EVENT_NOTICE: + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_notice"), "chaticon", CLEF_ONLYAFEW, TranslateT("Notice from %s"), gce->ptszNick); + break; + case GC_EVENT_TOPIC: + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_topic"), "chaticon", CLEF_ONLYAFEW, TranslateT("Topic change in %s"), si->ptszName); + break; + case GC_EVENT_INFORMATION: + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_info"), "chaticon", CLEF_ONLYAFEW, TranslateT("Information in %s"), si->ptszName); + break; + case GC_EVENT_ADDSTATUS: + CList_AddEvent(si->windowData.hContact, GetCachedIcon("chat_log_addstatus"), "chaticon", 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->windowData.hContact, GetCachedIcon("chat_log_removestatus"), "chaticon", 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) +{ + int iEvent = gce->pDest->iType; + + if ( iEvent & g_Settings.dwPopupFlags ) { + switch (iEvent) { + case GC_EVENT_MESSAGE|GC_EVENT_HIGHLIGHT : + ShowPopup(si->windowData.hContact, si, LoadSkinnedIcon(SKINICON_EVENT_MESSAGE), si->pszModule, si->ptszName, aFonts[16].color, TranslateT("%s says: %s"), gce->ptszNick, RemoveFormatting( gce->ptszText )); + break; + case GC_EVENT_ACTION|GC_EVENT_HIGHLIGHT : + ShowPopup(si->windowData.hContact, si, LoadSkinnedIcon(SKINICON_EVENT_MESSAGE), si->pszModule, si->ptszName, aFonts[16].color, _T("%s %s"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_MESSAGE : + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_message_in"), si->pszModule, si->ptszName, aFonts[9].color, TranslateT("%s says: %s"), gce->ptszNick, RemoveFormatting( gce->ptszText)); + break; + case GC_EVENT_ACTION: + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_action"), si->pszModule, si->ptszName, aFonts[15].color, _T("%s %s"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_JOIN: + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_join"), si->pszModule, si->ptszName, aFonts[3].color, TranslateT("%s has joined"), gce->ptszNick); + break; + case GC_EVENT_PART: + if (!gce->pszText) + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_part"), si->pszModule, si->ptszName, aFonts[4].color, TranslateT("%s has left"), gce->ptszNick); + else + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_part"), si->pszModule, si->ptszName, aFonts[4].color, TranslateT("%s has left (%s)"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_QUIT: + if (!gce->pszText) + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_quit"), si->pszModule, si->ptszName, aFonts[5].color, TranslateT("%s has disconnected"), gce->ptszNick); + else + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_quit"), si->pszModule, si->ptszName, aFonts[5].color, TranslateT("%s has disconnected (%s)"), gce->ptszNick,RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_NICK: + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_nick"), si->pszModule, si->ptszName, aFonts[7].color, TranslateT("%s is now known as %s"), gce->ptszNick, gce->ptszText); + break; + case GC_EVENT_KICK: + if (!gce->pszText) + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_kick"), si->pszModule, si->ptszName, aFonts[6].color, TranslateT("%s kicked %s"), (char *)gce->pszStatus, gce->ptszNick); + else + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_kick"), si->pszModule, si->ptszName, aFonts[6].color, TranslateT("%s kicked %s (%s)"), (char *)gce->pszStatus, gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_NOTICE: + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_notice"), si->pszModule, si->ptszName, aFonts[8].color, TranslateT("Notice from %s: %s"), gce->ptszNick, RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_TOPIC: + if (!gce->ptszNick) + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_topic"), si->pszModule, si->ptszName, aFonts[11].color, TranslateT("The topic is \'%s\'"), RemoveFormatting(gce->ptszText)); + else + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_topic"), si->pszModule, si->ptszName, aFonts[11].color, TranslateT("The topic is \'%s\' (set by %s)"), RemoveFormatting(gce->ptszText), gce->ptszNick); + break; + case GC_EVENT_INFORMATION: + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_info"), si->pszModule, si->ptszName, aFonts[12].color, _T("%s"), RemoveFormatting(gce->ptszText)); + break; + case GC_EVENT_ADDSTATUS: + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_addstatus"), si->pszModule, si->ptszName, aFonts[13].color, TranslateT("%s enables \'%s\' status for %s"), gce->ptszText, (char *)gce->pszStatus, gce->ptszNick); + break; + case GC_EVENT_REMOVESTATUS: + ShowPopup(si->windowData.hContact, si, GetCachedIcon("chat_log_removestatus"), si->pszModule, si->ptszName, aFonts[14].color, TranslateT("%s disables \'%s\' status for %s"), gce->ptszText, (char *)gce->pszStatus, gce->ptszNick); + break; + } } + + return TRUE; +} + +BOOL DoSoundsFlashPopupTrayStuff(SESSION_INFO* si, GCEVENT * gce, BOOL bHighlight, int bManyFix) +{ + BOOL bInactive; + int iEvent; + + if (!gce || !si || gce->bIsMe || si->iType == GCW_SERVER) + return FALSE; + + bInactive = si->hWnd == NULL || GetForegroundWindow() != GetParent(si->hWnd); + // bInactive |= GetActiveWindow() != si->hWnd; // Removed this, because it seemed to be FALSE, even when window was focused, causing incorrect notifications + + iEvent = gce->pDest->iType; + + if ( bHighlight ) { + gce->pDest->iType |= GC_EVENT_HIGHLIGHT; + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatHighlight"); + if (bInactive && si->hWnd && DBGetContactSettingByte(NULL, "Chat", "FlashWindowHighlight", 0) != 0) + SendMessage(GetParent(si->hWnd), CM_STARTFLASHING, 0, 0); + if (DBGetContactSettingByte(si->windowData.hContact, "CList", "Hidden", 0) != 0) + DBDeleteContactSetting(si->windowData.hContact, "CList", "Hidden"); + if (bInactive) + DoTrayIcon(si, gce); + if (bInactive || !g_Settings.PopUpInactiveOnly) + DoPopup(si, gce); + if (bInactive && si->hWnd) + SendMessage(si->hWnd, GC_SETMESSAGEHIGHLIGHT, 0, 0); + return TRUE; + } + + // do blinking icons in tray + if (bInactive || !g_Settings.TrayIconInactiveOnly) + DoTrayIcon(si, gce); + + // stupid thing to not create multiple popups for a QUIT event for instance + if (bManyFix == 0) { + // do popups + if (bInactive || !g_Settings.PopUpInactiveOnly) + DoPopup(si, gce); + + // do sounds and flashing + switch (iEvent) { + case GC_EVENT_JOIN: + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatJoin"); + break; + case GC_EVENT_PART: + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatPart"); + break; + case GC_EVENT_QUIT: + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatQuit"); + break; + case GC_EVENT_ADDSTATUS: + case GC_EVENT_REMOVESTATUS: + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatMode"); + break; + case GC_EVENT_KICK: + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatKick"); + break; + case GC_EVENT_MESSAGE: + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatMessage"); + if (bInactive && g_Settings.FlashWindow && si->hWnd) + SendMessage(GetParent(si->hWnd), CM_STARTFLASHING, 0, 0); + + if (bInactive && !( si->wState & STATE_TALK )) { + si->wState |= STATE_TALK; + DBWriteContactSettingWord(si->windowData.hContact, si->pszModule,"ApparentMode",(LPARAM)(WORD) 40071); + } + if (bInactive && si->hWnd) + SendMessage(si->hWnd, GC_SETTABHIGHLIGHT, 0, 0); + break; + case GC_EVENT_ACTION: + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatAction"); + break; + case GC_EVENT_NICK: + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatNick"); + break; + case GC_EVENT_NOTICE: + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatNotice"); + break; + case GC_EVENT_TOPIC: + if (bInactive || !g_Settings.SoundsFocus) + SkinPlaySound("ChatTopic"); + break; + } } + + return TRUE; +} + +int 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)DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR); + + LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, NULL, &crFG, FALSE); + + 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; + 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; +} + +BOOL IsHighlighted(SESSION_INFO* si, const TCHAR* pszText) +{ + if ( g_Settings.HighlightEnabled && g_Settings.pszHighlightWords && pszText && si->pMe ) { + TCHAR* p1 = g_Settings.pszHighlightWords; + TCHAR* p2 = NULL; + const TCHAR* p3 = pszText; + static TCHAR szWord1[1000]; + static TCHAR szWord2[1000]; + static TCHAR szTrimString[] = _T(":,.!?;\'>)"); + + // compare word for word + while (*p1 != '\0') { + // find the next/first word in the highlight word string + // skip 'spaces' be4 the word + while(*p1 == ' ' && *p1 != '\0') + p1 += 1; + + //find the end of the word + p2 = _tcschr(p1, ' '); + if (!p2) + p2 = _tcschr(p1, '\0'); + if (p1 == p2) + return FALSE; + + // copy the word into szWord1 + lstrcpyn(szWord1, p1, p2-p1>998?999:p2-p1+1); + p1 = p2; + + // replace %m with the users nickname + p2 = _tcschr(szWord1, '%'); + if (p2 && p2[1] == 'm') { + TCHAR szTemp[50]; + + p2[1] = 's'; + lstrcpyn(szTemp, szWord1, SIZEOF(szTemp)); + mir_sntprintf(szWord1, SIZEOF(szWord1), szTemp, si->pMe->pszNick); + } + + // time to get the next/first word in the incoming text string + while(*p3 != '\0') + { + // skip 'spaces' be4 the word + while(*p3 == ' ' && *p3 != '\0') + p3 += 1; + + //find the end of the word + p2 = _tcschr(p3, ' '); + if (!p2) + p2 = _tcschr(p3, '\0'); + + + if (p3 != p2) { + // eliminate ending character if needed + if (p2-p3 > 1 && _tcschr(szTrimString, p2[-1])) + p2 -= 1; + + // copy the word into szWord2 and remove formatting + lstrcpyn(szWord2, p3, p2-p3>998?999:p2-p3+1); + + // reset the pointer if it was touched because of an ending character + if (*p2 != '\0' && *p2 != ' ') + p2 += 1; + p3 = p2; + + CharLower(szWord1); + CharLower(szWord2); + + // compare the words, using wildcards + if (WCCmp(szWord1, RemoveFormatting(szWord2))) + return TRUE; + } } + + p3 = pszText; + } } + + return FALSE; +} + +BOOL LogToFile(SESSION_INFO* si, GCEVENT * gce) +{ + MODULEINFO * mi = NULL; + TCHAR szBuffer[4096]; + TCHAR szLine[4096]; + TCHAR szTime[100]; + FILE *hFile = NULL; + TCHAR tszFile[MAX_PATH]; + TCHAR tszFolder[MAX_PATH]; + TCHAR p = '\0'; + BOOL bFileJustCreated = TRUE; + + if (!si || !gce) + return FALSE; + + mi = MM_FindModule(si->pszModule); + if ( !mi ) + return FALSE; + + szBuffer[0] = '\0'; + + lstrcpyn(tszFile, GetChatLogsFilename(si->windowData.hContact, gce->time), MAX_PATH); + bFileJustCreated = !PathFileExists(tszFile); + _tcscpy(tszFolder, tszFile); + PathRemoveFileSpec(tszFolder); + if (!PathIsDirectory(tszFolder)) + CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)tszFolder); + + lstrcpyn(szTime, MakeTimeStamp(g_Settings.pszTimeStampLog, gce->time), 99); + + hFile = _tfopen(tszFile, _T("ab+")); + if (hFile) { + TCHAR szTemp[512], szTemp2[512]; + TCHAR* pszNick = NULL; +#ifdef _UNICODE + if (bFileJustCreated) + fputws((const wchar_t*)"\377\376", hFile); //UTF-16 LE BOM == FF FE +#endif + 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; + } + if (p) + mir_sntprintf(szLine, SIZEOF(szLine), TranslateT("%s %c %s\r\n"), szTime, p, szBuffer); + else + mir_sntprintf(szLine, SIZEOF(szLine), TranslateT("%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 + 1024 * 10; + if (dwSize > trimlimit) { + BYTE * pBuffer = 0; + BYTE * pBufferTemp = 0; + size_t read = 0; + + pBuffer = (BYTE *)mir_alloc(g_Settings.LoggingLimit * 1024 + 2); + pBuffer[g_Settings.LoggingLimit*1024] = '\0'; + pBuffer[g_Settings.LoggingLimit*1024+1] = '\0'; + fseek(hFile, -g_Settings.LoggingLimit*1024, SEEK_END); + read = fread(pBuffer, 1, g_Settings.LoggingLimit * 1024, hFile); + fclose(hFile); + hFile = NULL; + + // trim to whole lines, should help with broken log files I hope. + pBufferTemp = (BYTE*)_tcschr((TCHAR*)pBuffer, _T('\n')); + if (pBufferTemp) { + pBufferTemp+= sizeof(TCHAR); + read = read - (pBufferTemp - pBuffer); + } else pBufferTemp = pBuffer; + + if (read > 0) { + hFile = _tfopen(tszFile, _T("wb")); + if (hFile) { +#ifdef _UNICODE + fputws((const wchar_t*)"\377\376", hFile); //UTF-16 LE BOM == FF FE +#endif + fwrite(pBufferTemp, 1, read, hFile); + fclose(hFile); + hFile = NULL; + } } + mir_free(pBuffer); + } } } + + if (hFile) + fclose(hFile); + hFile = NULL; + return TRUE; + } + return FALSE; +} + +UINT CreateGCMenu(HWND hwnd, HMENU *hMenu, int iIndex, POINT pt, SESSION_INFO* si, TCHAR* pszUID, TCHAR* pszWordText) +{ + GCMENUITEMS gcmi = {0}; + int i; + HMENU hSubMenu = 0; + + *hMenu = GetSubMenu(g_hMenu, iIndex); + gcmi.pszID = si->ptszID; + gcmi.pszModule = si->pszModule; + gcmi.pszUID = pszUID; + + if (iIndex == 1) { + int iLen = GetRichTextLength(hwnd, CP_ACP, FALSE); + + EnableMenuItem(*hMenu, IDM_CLEAR, MF_ENABLED); + EnableMenuItem(*hMenu, ID_COPYALL, MF_ENABLED); + if (!iLen) { + EnableMenuItem(*hMenu, ID_COPYALL, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(*hMenu, IDM_CLEAR, MF_BYCOMMAND | MF_GRAYED); + } + + 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 ); + SetSearchEngineIcons(*hMenu, g_dat->hSearchEngineIconList); + } + 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 ); + 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, ptszDescr ); + } + else if (gcmi.Item[i].uType == MENU_POPUPHMENU) + AppendMenu( hSubMenu==0?*hMenu:hSubMenu, dwState|MF_POPUP, gcmi.Item[i].dwID, ptszDescr); + else if (gcmi.Item[i].uType == MENU_POPUPITEM) + AppendMenu( hSubMenu==0?*hMenu:hSubMenu, dwState|MF_STRING, gcmi.Item[i].dwID, ptszDescr); + else if (gcmi.Item[i].uType == MENU_POPUPCHECK) + AppendMenu( hSubMenu==0?*hMenu:hSubMenu, dwState|MF_CHECKED|MF_STRING, gcmi.Item[i].dwID, ptszDescr); + else if (gcmi.Item[i].uType == MENU_POPUPSEPARATOR) + AppendMenu( hSubMenu==0?*hMenu:hSubMenu, MF_SEPARATOR, 0, ptszDescr ); + else if (gcmi.Item[i].uType == MENU_SEPARATOR) + AppendMenu( *hMenu, MF_SEPARATOR, 0, ptszDescr ); + else if (gcmi.Item[i].uType == MENU_HMENU) + AppendMenu( *hMenu, dwState|MF_POPUP, gcmi.Item[i].dwID, ptszDescr); + else if (gcmi.Item[i].uType == MENU_ITEM) + AppendMenu( *hMenu, dwState|MF_STRING, gcmi.Item[i].dwID, ptszDescr ); + else if (gcmi.Item[i].uType == MENU_CHECK) + AppendMenu( *hMenu, dwState|MF_CHECKED|MF_STRING, gcmi.Item[i].dwID, ptszDescr ); + + mir_free( ptszDescr ); + } + return TrackPopupMenu(*hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, 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) +{ + #if defined( _UNICODE ) + SESSION_INFO* si; + #endif + 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 defined( _UNICODE ) + if (( si = SM_FindSession(pszID, pszModule)) == NULL ) + return FALSE; + + if ( !( si->dwFlags & GC_UNICODE )) { + gcd->pszID = t2a( pszID ); + gch->pszUID = t2a( pszUID ); + gch->pszText = t2a( pszText ); + } + else { + #endif + replaceStr( &gcd->ptszID, pszID ); + replaceStr( &gch->ptszUID, pszUID); + replaceStr( &gch->ptszText, pszText); + #if defined( _UNICODE ) + } + #endif + 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) +{ + #if defined( _UNICODE ) + SESSION_INFO* si; + #endif + GCHOOK gch = {0}; + GCDEST gcd = {0}; + + gcd.pszModule = (char*)pszModule; + #if defined( _UNICODE ) + if (( si = SM_FindSession(pszID, pszModule)) == NULL ) + return FALSE; + + if ( !( si->dwFlags & GC_UNICODE )) { + gcd.pszID = t2a( pszID ); + gch.pszUID = t2a( pszUID ); + gch.pszText = t2a( pszText ); + } + else { + #endif + gcd.ptszID = mir_tstrdup( pszID ); + gch.ptszUID = mir_tstrdup( pszUID ); + gch.ptszText = mir_tstrdup( pszText ); + #if defined( _UNICODE ) + } + #endif + + 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 ) +{ + if ( str == NULL ) + return NULL; + + #if defined( _UNICODE ) + if ( flags & GC_UNICODE ) + return mir_tstrdup( str ); + else { + int codepage = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 ); + + int cbLen = MultiByteToWideChar( codepage, 0, (char*)str, -1, 0, 0 ); + TCHAR* result = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( cbLen+1 )); + if ( result == NULL ) + return NULL; + + MultiByteToWideChar( codepage, 0, (char*)str, -1, result, cbLen ); + result[ cbLen ] = 0; + return result; + } + #else + return mir_strdup( str ); + #endif +} + +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; +} + +TCHAR* GetChatLogsFilename (HANDLE hContact, time_t tTime) +{ REPLACEVARSARRAY rva[11]; + REPLACEVARSDATA dat = {0}; + static TCHAR tszFileName[MAX_PATH]; + TCHAR *p = {0}, *tszParsedName = {0}; + int i; + + if (g_Settings.pszLogDir[_tcslen(g_Settings.pszLogDir)-1] == '\\') + _tcscat(g_Settings.pszLogDir, _T("%userid%.log")); + if(!tTime) + time(&tTime); + + // day 1-31 + 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; + + dat.cbSize = sizeof(dat); + dat.dwFlags = RVF_TCHAR; + dat.hContact = hContact; + dat.variables = rva; + tszParsedName = (TCHAR*)CallService(MS_UTILS_REPLACEVARS, (WPARAM)g_Settings.pszLogDir, (LPARAM)&dat); + _tcsncpy(tszFileName, tszParsedName, MAX_PATH); + mir_free(tszParsedName); + for (i=0; i < SIZEOF(rva);i++) + mir_free(rva[i].lptzValue); + + for (p = tszFileName + 2; *p; ++p) { + if (*p == ':' || *p == '*' || *p == '?' || *p == '"' || *p == '<' || *p == '>' || *p == '|' ) + *p = _T('_'); + } + + return tszFileName; +} diff --git a/plugins/Scriver/chat/window.c b/plugins/Scriver/chat/window.c new file mode 100644 index 0000000000..762bb0e95c --- /dev/null +++ b/plugins/Scriver/chat/window.c @@ -0,0 +1,2200 @@ +/* +Chat module plugin for Miranda IM + +Copyright (C) 2003 Jörgen Persson +Copyright 2003-2009 Miranda ICQ/IM project, + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "../commonheaders.h" +#include "chat.h" +#include "../utils.h" +#include "../statusicon.h" + +#ifndef WM_UNICHAR +#define WM_UNICHAR 0x0109 +#endif + +extern HBRUSH hListBkgBrush; +extern HBRUSH hListSelectedBkgBrush; +extern HANDLE hSendEvent; +extern HINSTANCE g_hInst; +extern struct CREOleCallback reOleCallback; +extern HMENU g_hMenu; +extern TABLIST * g_TabList; +extern HANDLE hHookWinPopup; +extern HCURSOR hCurSplitNS, hCurSplitWE; + +static WNDPROC OldSplitterProc; +static WNDPROC OldMessageProc; +static WNDPROC OldNicklistProc; +static WNDPROC OldFilterButtonProc; +static WNDPROC OldLogProc; + +static ToolbarButton toolbarButtons[] = { + {_T("Bold"), IDC_CHAT_BOLD, 0, 4, 24}, + {_T("Italic"), IDC_CHAT_ITALICS, 0, 0, 24}, + {_T("Underline"), IDC_CHAT_UNDERLINE, 0, 0, 24}, + {_T("Text color"), IDC_CHAT_COLOR, 0, 0, 24}, + {_T("Background color"), IDC_CHAT_BKGCOLOR, 0, 0, 24}, +// {_T("Font size"), IDC_CHAT_FONTSIZE, 0, 0, 48}, + {_T("Smiley"), IDC_CHAT_SMILEY, 0, 8, 24}, + {_T("History"), IDC_CHAT_HISTORY, 1, 0, 24}, + {_T("Filter"), IDC_CHAT_FILTER, 1, 0, 24}, + {_T("Manager"), IDC_CHAT_CHANMGR, 1, 0, 24}, + {_T("Nick list"), IDC_CHAT_SHOWNICKLIST, 1, 0, 24}, + {_T("Send"), IDOK, 1, 0, 38}, +}; + +typedef struct +{ + time_t lastEnterTime; + TCHAR* szSearchQuery; + TCHAR* szSearchResult; + SESSION_INFO *lastSession; +} MESSAGESUBDATA; + + +static LRESULT CALLBACK SplitterSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + switch(msg) { + case WM_NCHITTEST: + return HTCLIENT; + + case WM_SETCURSOR: + { + RECT rc; + GetClientRect(hwnd, &rc); + SetCursor(rc.right > rc.bottom ? hCurSplitNS : hCurSplitWE); + return TRUE; + } + return 0; + case WM_LBUTTONDOWN: + SetCapture(hwnd); + return 0; + + case WM_MOUSEMOVE: + if (GetCapture()==hwnd) { + RECT rc; + GetClientRect(hwnd,&rc); + SendMessage(GetParent(hwnd),GC_SPLITTERMOVED,rc.right>rc.bottom?(short)HIWORD(GetMessagePos())+rc.bottom/2:(short)LOWORD(GetMessagePos())+rc.right/2,(LPARAM)hwnd); + } + return 0; + + case WM_LBUTTONUP: + ReleaseCapture(); + PostMessage(GetParent(hwnd),WM_SIZE, 0, 0); + return 0; + } + return CallWindowProc(OldSplitterProc,hwnd,msg,wParam,lParam); +} + +static void InitButtons(HWND hwndDlg, SESSION_INFO* si) +{ + MODULEINFO * pInfo = MM_FindModule(si->pszModule); + + SendDlgItemMessage(hwndDlg,IDC_CHAT_SMILEY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon("chat_smiley")); + SendDlgItemMessage(hwndDlg,IDC_CHAT_BOLD,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon("chat_bold")); + SendDlgItemMessage(hwndDlg,IDC_CHAT_ITALICS,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon("chat_italics")); + SendDlgItemMessage(hwndDlg,IDC_CHAT_UNDERLINE,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon("chat_underline")); + SendDlgItemMessage(hwndDlg,IDC_CHAT_COLOR,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon("chat_fgcol")); + SendDlgItemMessage(hwndDlg,IDC_CHAT_BKGCOLOR,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon("chat_bkgcol")); + SendDlgItemMessage(hwndDlg,IDC_CHAT_HISTORY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon("chat_history")); + SendDlgItemMessage(hwndDlg,IDC_CHAT_CHANMGR,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon("chat_settings")); + SendDlgItemMessage(hwndDlg,IDC_CHAT_SHOWNICKLIST,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon(si->bNicklistEnabled?"chat_nicklist":"chat_nicklist2")); + SendDlgItemMessage(hwndDlg,IDC_CHAT_FILTER,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon(si->bFilterEnabled?"chat_filter":"chat_filter2")); + SendDlgItemMessage(hwndDlg, IDOK, BM_SETIMAGE, IMAGE_ICON, (LPARAM) GetCachedIcon("scriver_SEND")); + + SendDlgItemMessage(hwndDlg,IDC_CHAT_SMILEY, BUTTONSETASFLATBTN, 0, 0); + SendDlgItemMessage(hwndDlg,IDC_CHAT_BOLD, BUTTONSETASFLATBTN, 0, 0); + SendDlgItemMessage(hwndDlg,IDC_CHAT_ITALICS, BUTTONSETASFLATBTN, 0, 0); + SendDlgItemMessage(hwndDlg,IDC_CHAT_UNDERLINE, BUTTONSETASFLATBTN, 0, 0); + SendDlgItemMessage(hwndDlg,IDC_CHAT_BKGCOLOR, BUTTONSETASFLATBTN, 0, 0); + SendDlgItemMessage(hwndDlg,IDC_CHAT_COLOR, BUTTONSETASFLATBTN, 0, 0); + SendDlgItemMessage(hwndDlg,IDC_CHAT_HISTORY, BUTTONSETASFLATBTN, 0, 0); + SendDlgItemMessage(hwndDlg,IDC_CHAT_SHOWNICKLIST, BUTTONSETASFLATBTN, 0, 0); + SendDlgItemMessage(hwndDlg,IDC_CHAT_CHANMGR, BUTTONSETASFLATBTN, 0, 0); + SendDlgItemMessage(hwndDlg,IDC_CHAT_FILTER, BUTTONSETASFLATBTN, 0, 0); + SendDlgItemMessage(hwndDlg,IDOK, BUTTONSETASFLATBTN, 0, 0); + + SendMessage(GetDlgItem(hwndDlg,IDC_CHAT_SMILEY), BUTTONADDTOOLTIP, (WPARAM)Translate("Insert a smiley"), 0); + SendMessage(GetDlgItem(hwndDlg,IDC_CHAT_BOLD), BUTTONADDTOOLTIP, (WPARAM)Translate("Make the text bold (CTRL+B)"), 0); + SendMessage(GetDlgItem(hwndDlg,IDC_CHAT_ITALICS), BUTTONADDTOOLTIP, (WPARAM)Translate("Make the text italicized (CTRL+I)"), 0); + SendMessage(GetDlgItem(hwndDlg,IDC_CHAT_UNDERLINE), BUTTONADDTOOLTIP, (WPARAM)Translate("Make the text underlined (CTRL+U)"), 0); + SendMessage(GetDlgItem(hwndDlg,IDC_CHAT_BKGCOLOR), BUTTONADDTOOLTIP, (WPARAM)Translate("Select a background color for the text (CTRL+L)"), 0); + SendMessage(GetDlgItem(hwndDlg,IDC_CHAT_COLOR), BUTTONADDTOOLTIP, (WPARAM)Translate("Select a foreground color for the text (CTRL+K)"), 0); + SendMessage(GetDlgItem(hwndDlg,IDC_CHAT_HISTORY), BUTTONADDTOOLTIP, (WPARAM)Translate("Show the history (CTRL+H)"), 0); + SendMessage(GetDlgItem(hwndDlg,IDC_CHAT_SHOWNICKLIST), BUTTONADDTOOLTIP, (WPARAM)Translate("Show/hide the nicklist (CTRL+N)"), 0); + SendMessage(GetDlgItem(hwndDlg,IDC_CHAT_CHANMGR), BUTTONADDTOOLTIP, (WPARAM)Translate("Control this room (CTRL+O)"), 0); + SendMessage(GetDlgItem(hwndDlg,IDC_CHAT_FILTER), BUTTONADDTOOLTIP, (WPARAM)Translate("Enable/disable the event filter (CTRL+F)"), 0); + SendMessage(GetDlgItem(hwndDlg, IDOK), BUTTONADDTOOLTIP, (WPARAM) Translate("Send Message"), 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_BOLD, BUTTONSETASPUSHBTN, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_ITALICS, BUTTONSETASPUSHBTN, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_UNDERLINE, BUTTONSETASPUSHBTN, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_COLOR, BUTTONSETASPUSHBTN, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_BKGCOLOR, BUTTONSETASPUSHBTN, 0, 0); +// SendDlgItemMessage(hwndDlg, IDC_CHAT_SHOWNICKLIST, BUTTONSETASPUSHBTN, 0, 0); +// SendDlgItemMessage(hwndDlg, IDC_CHAT_FILTER, BUTTONSETASPUSHBTN, 0, 0); + + if (pInfo) + { + + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_BOLD), pInfo->bBold); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_ITALICS), pInfo->bItalics); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_UNDERLINE), pInfo->bUnderline); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_COLOR), pInfo->bColor); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_BKGCOLOR), pInfo->bBkgColor); + if (si->iType == GCW_CHATROOM) + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_CHANMGR), pInfo->bChanMgr); + } +} + + +static void MessageDialogResize(HWND hwndDlg, SESSION_INFO *si, int w, int h) { + int logBottom, toolbarTopY; + HDWP hdwp; + BOOL bNick = si->iType!=GCW_SERVER && si->bNicklistEnabled; + BOOL bToolbar = SendMessage(GetParent(hwndDlg), CM_GETTOOLBARSTATUS, 0, 0); + int buttonVisibility = bToolbar ? g_dat->chatBbuttonVisibility : 0; + int hSplitterMinTop = TOOLBAR_HEIGHT + si->windowData.minLogBoxHeight, hSplitterMinBottom = si->windowData.minEditBoxHeight; + int toolbarHeight = bToolbar ? IsToolbarVisible(SIZEOF(toolbarButtons), g_dat->chatBbuttonVisibility) ? TOOLBAR_HEIGHT : TOOLBAR_HEIGHT / 3 : 0; + + si->iSplitterY = si->desiredInputAreaHeight + SPLITTER_HEIGHT + 3; + + if (h - si->iSplitterY < hSplitterMinTop) { + si->iSplitterY = h - hSplitterMinTop; + } + if (si->iSplitterY < hSplitterMinBottom) { + si->iSplitterY = hSplitterMinBottom; + } + + ShowToolbarControls(hwndDlg, SIZEOF(toolbarButtons), toolbarButtons, buttonVisibility, SW_SHOW); + ShowWindow(GetDlgItem(hwndDlg, IDC_CHAT_SPLITTERX), bNick?SW_SHOW:SW_HIDE); + if (si->iType != GCW_SERVER) + ShowWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIST), si->bNicklistEnabled?SW_SHOW:SW_HIDE); + else + ShowWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIST), SW_HIDE); + + if (si->iType == GCW_SERVER) { + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_SHOWNICKLIST), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_FILTER), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_CHANMGR), FALSE); + } else { + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_SHOWNICKLIST), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_FILTER), TRUE); + if (si->iType == GCW_CHATROOM) + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_CHANMGR), MM_FindModule(si->pszModule)->bChanMgr); + } + + hdwp = BeginDeferWindowPos(20); + toolbarTopY = bToolbar ? h - si->iSplitterY - toolbarHeight : h - si->iSplitterY; + if (si->windowData.hwndLog != NULL) { + logBottom = toolbarTopY / 2; + } else { + logBottom = toolbarTopY; + } + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_LOG), 0, 1, 0, bNick?w - si->iSplitterX - 1:w - 2, logBottom, SWP_NOZORDER); + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_LIST), 0, w - si->iSplitterX + 2, 0, si->iSplitterX - 3, toolbarTopY, SWP_NOZORDER); + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_SPLITTERX), 0, w - si->iSplitterX, 1, 2, toolbarTopY - 1, SWP_NOZORDER); + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_SPLITTERY), 0, 0, h - si->iSplitterY, w, SPLITTER_HEIGHT, SWP_NOZORDER); + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), 0, 1, h - si->iSplitterY + SPLITTER_HEIGHT, w - 2, si->iSplitterY - SPLITTER_HEIGHT - 1, SWP_NOZORDER); +/* + + toolbarTopY = h - toolbarHeight; + if (si->windowData.hwndLog != NULL) { + logBottom = (h - si->iSplitterY) / 2; + } else { + logBottom = h - si->iSplitterY; + } + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_LOG), 0, 0, 0, bNick?w - si->iSplitterX:w, logBottom, SWP_NOZORDER); + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_LIST), 0, w - si->iSplitterX + 2, 0, si->iSplitterX - 1, h - si->iSplitterY, SWP_NOZORDER); + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_SPLITTERX), 0, w - si->iSplitterX, 1, 2, h - si->iSplitterY, SWP_NOZORDER); + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_SPLITTERY), 0, 0, h - si->iSplitterY, w, splitterHeight, SWP_NOZORDER); + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), 0, 0, h - si->iSplitterY + splitterHeight, bSend?w-64:w, si->iSplitterY - toolbarHeight - splitterHeight, SWP_NOZORDER); + hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDOK), 0, w - 64, h - si->iSplitterY + splitterHeight, 64, si->iSplitterY - toolbarHeight - splitterHeight - 1, SWP_NOZORDER); + +*/ + + hdwp = ResizeToolbar(hwndDlg, hdwp, w, toolbarTopY + 1, toolbarHeight - 1, SIZEOF(toolbarButtons), toolbarButtons, buttonVisibility); + EndDeferWindowPos(hdwp); + if (si->windowData.hwndLog != NULL) { + RECT rect; + POINT pt; + IEVIEWWINDOW ieWindow; + GetWindowRect(GetDlgItem(hwndDlg,IDC_CHAT_LOG), &rect); + pt.x = 0; + pt.y = rect.top; + ScreenToClient(GetDlgItem(hwndDlg,IDC_CHAT_LOG),&pt); + ieWindow.cbSize = sizeof(IEVIEWWINDOW); + ieWindow.iType = IEW_SETPOS; + ieWindow.parent = hwndDlg; + ieWindow.hwnd = si->windowData.hwndLog; + ieWindow.x = 0; + ieWindow.y = logBottom + 1; + ieWindow.cx = bNick ? w - si->iSplitterX:w; + ieWindow.cy = logBottom; + CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow); + } else { + RedrawWindow(GetDlgItem(hwndDlg,IDC_CHAT_LOG), NULL, NULL, RDW_INVALIDATE); + } + RedrawWindow(GetDlgItem(hwndDlg,IDC_CHAT_LIST), NULL, NULL, RDW_INVALIDATE); + RedrawWindow(GetDlgItem(hwndDlg,IDC_CHAT_MESSAGE), NULL, NULL, RDW_INVALIDATE); +} + + +static LRESULT CALLBACK MessageSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static int start; + int result; + MESSAGESUBDATA *dat; + SESSION_INFO* Parentsi; + CommonWindowData *windowData; + BOOL isShift = GetKeyState(VK_SHIFT) & 0x8000; + BOOL isCtrl = GetKeyState(VK_CONTROL) & 0x8000; + BOOL isAlt = GetKeyState(VK_MENU) & 0x8000; + + Parentsi=(SESSION_INFO*)GetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA); + dat = (MESSAGESUBDATA *) GetWindowLongPtr(hwnd, GWLP_USERDATA); + windowData = &Parentsi->windowData; + + result = InputAreaShortcuts(hwnd, msg, wParam, lParam, windowData); + if (result != -1) { + return result; + } + + switch (msg) { + case EM_SUBCLASSED: + dat = (MESSAGESUBDATA *) mir_alloc(sizeof(MESSAGESUBDATA)); + ZeroMemory(dat, sizeof(MESSAGESUBDATA)); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) dat); + return 0; + + case WM_MOUSEWHEEL: + if ((GetWindowLong(hwnd, GWL_STYLE) & WS_VSCROLL) == 0) { + SendMessage(GetDlgItem(GetParent(hwnd), IDC_CHAT_LOG), WM_MOUSEWHEEL, wParam, lParam); + } + dat->lastEnterTime = 0; + return TRUE; + + case EM_REPLACESEL: + PostMessage(hwnd, EM_ACTIVATE, 0, 0); + break; + + case EM_ACTIVATE: + SetActiveWindow(GetParent(hwnd)); + break; + + case WM_KEYDOWN: + { + if (wParam == VK_RETURN) { + mir_free(dat->szSearchQuery); + dat->szSearchQuery = NULL; + mir_free(dat->szSearchResult); + dat->szSearchResult = NULL; + if (( isCtrl != 0 ) ^ (0 != DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SENDONENTER, SRMSGDEFSET_SENDONENTER))) { + PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0); + return 0; + } + if (DBGetContactSettingByte(NULL, SRMMMOD, SRMSGSET_SENDONDBLENTER, SRMSGDEFSET_SENDONDBLENTER)) { + if (dat->lastEnterTime + 2 < time(NULL)) + dat->lastEnterTime = time(NULL); + else { + SendMessage(hwnd, WM_KEYDOWN, VK_BACK, 0); + SendMessage(hwnd, WM_KEYUP, VK_BACK, 0); + PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0); + return 0; + } } } else { + dat->lastEnterTime = 0; + } + + + if (wParam == VK_TAB && isShift && !isCtrl) { // SHIFT-TAB (go to nick list) + SetFocus(GetDlgItem(GetParent(hwnd), IDC_CHAT_LIST)); + return TRUE; + } + + if (wParam == VK_TAB && !isCtrl && !isShift) { //tab-autocomplete + int iLen, end, topicStart; + BOOL isTopic = FALSE; + BOOL isRoom = FALSE; + TCHAR* pszText = NULL; + GETTEXTEX gt = {0}; + LRESULT lResult = (LRESULT)SendMessage(hwnd, EM_GETSEL, (WPARAM)NULL, (LPARAM)NULL); + + SendMessage(hwnd, WM_SETREDRAW, FALSE, 0); + start = LOWORD(lResult); + end = HIWORD(lResult); + SendMessage(hwnd, EM_SETSEL, end, end); + + #if defined( _UNICODE ) + gt.codepage = 1200; + #else + gt.codepage = CP_ACP; + #endif + iLen = GetRichTextLength(hwnd, gt.codepage, TRUE); + if (iLen >0) { + TCHAR *pszName = NULL; + pszText = mir_alloc(iLen + 100 * sizeof(TCHAR)); + gt.cb = iLen + 99 * sizeof(TCHAR); + gt.flags = GT_DEFAULT; + + 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 = 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) { + dat->szSearchQuery = mir_alloc( sizeof(TCHAR)*( end-start+1 )); + lstrcpyn( dat->szSearchQuery, pszText+start, end-start+1); + 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 = NULL; + if (pszName == NULL) { + if (end !=start) { + SendMessage(hwnd, EM_SETSEL, start, end); + SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) dat->szSearchQuery); + } + mir_free(dat->szSearchQuery); + dat->szSearchQuery = NULL; + } else { + dat->szSearchResult = mir_tstrdup(pszName); + if (end !=start) { + if (!isRoom && !isTopic && g_Settings.AddColonToAutoComplete && start == 0) { + pszText = mir_alloc((_tcslen(pszName) + 4) * sizeof(TCHAR)); + _tcscpy(pszText, pszName); + _tcscat(pszText, _T(": ")); + pszName = pszText; + } + SendMessage(hwnd, EM_SETSEL, start, end); + SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) pszName); + } + mir_free(pszText); + } + } + + SendMessage(hwnd, WM_SETREDRAW, TRUE, 0); + RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); + 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 == 0x49 && isCtrl && !isAlt) { // ctrl-i (italics) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_ITALICS, IsDlgButtonChecked(GetParent(hwnd), IDC_CHAT_ITALICS) == BST_UNCHECKED?BST_CHECKED:BST_UNCHECKED); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_ITALICS, 0), 0); + return TRUE; + } + + if (wParam == 0x42 && isCtrl && !isAlt) { // ctrl-b (bold) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_BOLD, IsDlgButtonChecked(GetParent(hwnd), IDC_CHAT_BOLD) == BST_UNCHECKED?BST_CHECKED:BST_UNCHECKED); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_BOLD, 0), 0); + return TRUE; + } + + if (wParam == 0x55 && isCtrl && !isAlt) { // ctrl-u (paste clean text) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_UNDERLINE, IsDlgButtonChecked(GetParent(hwnd), IDC_CHAT_UNDERLINE) == BST_UNCHECKED?BST_CHECKED:BST_UNCHECKED); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_UNDERLINE, 0), 0); + return TRUE; + } + + if (wParam == 0x4b && isCtrl && !isAlt) { // ctrl-k (paste clean text) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_COLOR, IsDlgButtonChecked(GetParent(hwnd), IDC_CHAT_COLOR) == BST_UNCHECKED?BST_CHECKED:BST_UNCHECKED); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_COLOR, 0), 0); + return TRUE; + } + + if (wParam == VK_SPACE && isCtrl && !isAlt) { // ctrl-space (paste clean text) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_BKGCOLOR, BST_UNCHECKED); + CheckDlgButton(GetParent(hwnd), IDC_CHAT_COLOR, BST_UNCHECKED); + CheckDlgButton(GetParent(hwnd), IDC_CHAT_BOLD, BST_UNCHECKED); + CheckDlgButton(GetParent(hwnd), IDC_CHAT_UNDERLINE, BST_UNCHECKED); + CheckDlgButton(GetParent(hwnd), IDC_CHAT_ITALICS, BST_UNCHECKED); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_BKGCOLOR, 0), 0); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_COLOR, 0), 0); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_BOLD, 0), 0); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_UNDERLINE, 0), 0); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_ITALICS, 0), 0); + return TRUE; + } + + if (wParam == 0x4c && isCtrl && !isAlt) { // ctrl-l (paste clean text) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_BKGCOLOR, IsDlgButtonChecked(GetParent(hwnd), IDC_CHAT_BKGCOLOR) == BST_UNCHECKED?BST_CHECKED:BST_UNCHECKED); + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_BKGCOLOR, 0), 0); + return TRUE; + } + + if (wParam == 0x46 && isCtrl && !isAlt) { // ctrl-f (paste clean text) + if (IsWindowEnabled(GetDlgItem(GetParent(hwnd), IDC_CHAT_FILTER))) + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_FILTER, 0), 0); + return TRUE; + } + + if (wParam == 0x4e && isCtrl && !isAlt) { // ctrl-n (nicklist) + if (IsWindowEnabled(GetDlgItem(GetParent(hwnd), IDC_CHAT_SHOWNICKLIST))) + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_SHOWNICKLIST, 0), 0); + return TRUE; + } + + if (wParam == 0x48 && isCtrl && !isAlt) { // ctrl-h (history) + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_HISTORY, 0), 0); + return TRUE; + } + + if (wParam == 0x4f && isCtrl && !isAlt) { // ctrl-o (options) + if (IsWindowEnabled(GetDlgItem(GetParent(hwnd), IDC_CHAT_CHANMGR))) + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHAT_CHANMGR, 0), 0); + return TRUE; + } + + if (wParam == VK_NEXT || wParam == VK_PRIOR) { + HWND htemp = GetParent(hwnd); + SendDlgItemMessage(htemp, IDC_CHAT_LOG, msg, wParam, lParam); + return TRUE; + } + break; + } + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_KILLFOCUS: + dat->lastEnterTime = 0; + break; + case WM_CONTEXTMENU: + InputAreaContextMenu(hwnd, wParam, lParam, Parentsi->windowData.hContact); + return TRUE; + + case WM_KEYUP: + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + { + CHARFORMAT2 cf; + UINT u = 0; + UINT u2 = 0; + COLORREF cr; + + LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, NULL, &cr, FALSE); + + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwMask = CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_BACKCOLOR|CFM_COLOR; + SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + + if (MM_FindModule(Parentsi->pszModule) && MM_FindModule(Parentsi->pszModule)->bColor) { + int index = GetColorIndex(Parentsi->pszModule, cf.crTextColor); + u = IsDlgButtonChecked(GetParent(hwnd), IDC_CHAT_COLOR); + + if (index >= 0) { + Parentsi->bFGSet = TRUE; + Parentsi->iFG = index; + } + + if (u == BST_UNCHECKED && cf.crTextColor != cr) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_COLOR, BST_CHECKED); + else if (u == BST_CHECKED && cf.crTextColor == cr) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_COLOR, BST_UNCHECKED); + } + + if (MM_FindModule(Parentsi->pszModule) && MM_FindModule(Parentsi->pszModule)->bBkgColor) { + int index = GetColorIndex(Parentsi->pszModule, cf.crBackColor); + COLORREF crB = DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR); + u = IsDlgButtonChecked(GetParent(hwnd), IDC_CHAT_BKGCOLOR); + + if (index >= 0) { + Parentsi->bBGSet = TRUE; + Parentsi->iBG = index; + } + if (u == BST_UNCHECKED && cf.crBackColor != crB) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_BKGCOLOR, BST_CHECKED); + else if (u == BST_CHECKED && cf.crBackColor == crB) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_BKGCOLOR, BST_UNCHECKED); + } + + if (MM_FindModule(Parentsi->pszModule) && MM_FindModule(Parentsi->pszModule)->bBold) { + u = IsDlgButtonChecked(GetParent(hwnd), IDC_CHAT_BOLD); + u2 = cf.dwEffects; + u2 &= CFE_BOLD; + if (u == BST_UNCHECKED && u2) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_BOLD, BST_CHECKED); + else if (u == BST_CHECKED && u2 == 0) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_BOLD, BST_UNCHECKED); + } + + if (MM_FindModule(Parentsi->pszModule) && MM_FindModule(Parentsi->pszModule)->bItalics) { + u = IsDlgButtonChecked(GetParent(hwnd), IDC_CHAT_ITALICS); + u2 = cf.dwEffects; + u2 &= CFE_ITALIC; + if (u == BST_UNCHECKED && u2) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_ITALICS, BST_CHECKED); + else if (u == BST_CHECKED && u2 == 0) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_ITALICS, BST_UNCHECKED); + } + + if (MM_FindModule(Parentsi->pszModule) && MM_FindModule(Parentsi->pszModule)->bUnderline) { + u = IsDlgButtonChecked(GetParent(hwnd), IDC_CHAT_UNDERLINE); + u2 = cf.dwEffects; + u2 &= CFE_UNDERLINE; + if (u == BST_UNCHECKED && u2) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_UNDERLINE, BST_CHECKED); + else if (u == BST_CHECKED && u2 == 0) + CheckDlgButton(GetParent(hwnd), IDC_CHAT_UNDERLINE, BST_UNCHECKED); + } } + break; + + case EM_UNSUBCLASSED: + mir_free(dat->szSearchQuery); + mir_free(dat->szSearchResult); + mir_free(dat); + return 0; + } + + return CallWindowProc(OldMessageProc, hwnd, msg, wParam, lParam); +} + +static INT_PTR CALLBACK FilterWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + static SESSION_INFO* si = NULL; + switch (uMsg) { + case WM_INITDIALOG: + si = (SESSION_INFO *)lParam; + CheckDlgButton(hwndDlg, IDC_CHAT_1, si->iLogFilterFlags&GC_EVENT_ACTION); + CheckDlgButton(hwndDlg, IDC_CHAT_2, si->iLogFilterFlags&GC_EVENT_MESSAGE); + CheckDlgButton(hwndDlg, IDC_CHAT_3, si->iLogFilterFlags&GC_EVENT_NICK); + CheckDlgButton(hwndDlg, IDC_CHAT_4, si->iLogFilterFlags&GC_EVENT_JOIN); + CheckDlgButton(hwndDlg, IDC_CHAT_5, si->iLogFilterFlags&GC_EVENT_PART); + CheckDlgButton(hwndDlg, IDC_CHAT_6, si->iLogFilterFlags&GC_EVENT_TOPIC); + CheckDlgButton(hwndDlg, IDC_CHAT_7, si->iLogFilterFlags&GC_EVENT_ADDSTATUS); + CheckDlgButton(hwndDlg, IDC_CHAT_8, si->iLogFilterFlags&GC_EVENT_INFORMATION); + CheckDlgButton(hwndDlg, IDC_CHAT_9, si->iLogFilterFlags&GC_EVENT_QUIT); + CheckDlgButton(hwndDlg, IDC_CHAT_10, si->iLogFilterFlags&GC_EVENT_KICK); + CheckDlgButton(hwndDlg, IDC_CHAT_11, si->iLogFilterFlags&GC_EVENT_NOTICE); + break; + + case WM_CTLCOLOREDIT: + case WM_CTLCOLORSTATIC: + SetTextColor((HDC)wParam,RGB(60,60,150)); + SetBkColor((HDC)wParam,GetSysColor(COLOR_WINDOW)); + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); + + case WM_ACTIVATE: + if (LOWORD(wParam) == WA_INACTIVE) { + int iFlags = 0; + + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_1) == BST_CHECKED) + iFlags |= GC_EVENT_ACTION; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_2) == BST_CHECKED) + iFlags |= GC_EVENT_MESSAGE; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_3) == BST_CHECKED) + iFlags |= GC_EVENT_NICK; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_4) == BST_CHECKED) + iFlags |= GC_EVENT_JOIN; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_5) == BST_CHECKED) + iFlags |= GC_EVENT_PART; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_6) == BST_CHECKED) + iFlags |= GC_EVENT_TOPIC; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_7) == BST_CHECKED) + iFlags |= GC_EVENT_ADDSTATUS; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_8) == BST_CHECKED) + iFlags |= GC_EVENT_INFORMATION; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_9) == BST_CHECKED) + iFlags |= GC_EVENT_QUIT; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_10) == BST_CHECKED) + iFlags |= GC_EVENT_KICK; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_11) == BST_CHECKED) + iFlags |= GC_EVENT_NOTICE; + + if (iFlags&GC_EVENT_ADDSTATUS) + iFlags |= GC_EVENT_REMOVESTATUS; + + SendMessage(si->hWnd, GC_CHANGEFILTERFLAG, 0, (LPARAM)iFlags); + if (si->bFilterEnabled) + SendMessage(si->hWnd, GC_REDRAWLOG, 0, 0); + PostMessage(hwndDlg, WM_CLOSE, 0, 0); + } + break; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + } + + return(FALSE); +} + +static LRESULT CALLBACK ButtonSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_RBUTTONUP: + { + HWND hFilter = GetDlgItem(GetParent(hwnd), IDC_CHAT_FILTER); + HWND hColor = GetDlgItem(GetParent(hwnd), IDC_CHAT_COLOR); + HWND hBGColor = GetDlgItem(GetParent(hwnd), IDC_CHAT_BKGCOLOR); + + if (DBGetContactSettingByte(NULL, "Chat", "RightClickFilter", 0) != 0) { + if (hFilter == hwnd) + SendMessage(GetParent(hwnd), GC_SHOWFILTERMENU, 0, 0); + if (hColor == hwnd) + SendMessage(GetParent(hwnd), GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_CHAT_COLOR); + if (hBGColor == hwnd) + SendMessage(GetParent(hwnd), GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_CHAT_BKGCOLOR); + } } + break; + } + + return CallWindowProc(OldFilterButtonProc, hwnd, msg, wParam, lParam); +} + +static LRESULT CALLBACK LogSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static BOOL inMenu = FALSE; + SESSION_INFO* si =(SESSION_INFO*)GetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA); + int result = InputAreaShortcuts(hwnd, msg, wParam, lParam, &si->windowData); + if (result != -1) { + return result; + } + switch (msg) { + case WM_MEASUREITEM: + MeasureMenuItem(wParam, lParam); + return TRUE; + case WM_DRAWITEM: + return DrawMenuItem(wParam, lParam); + case WM_SETCURSOR: + if (inMenu) { + SetCursor(LoadCursor(NULL, IDC_ARROW)); + return TRUE; + } + break; + case WM_LBUTTONUP: + { + CHARRANGE sel; + + 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(GetParent(hwnd), IDC_CHAT_MESSAGE)); + 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_CONTEXTMENU: + { + CHARRANGE sel, all = { 0, -1 }; + POINT pt; + UINT uID = 0; + HMENU hMenu = 0; + TCHAR *pszWord = NULL; + POINTL ptl; + + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) & sel); + if (lParam == 0xFFFFFFFF) { + SendMessage(hwnd, EM_POSFROMCHAR, (WPARAM) & pt, (LPARAM) sel.cpMax); + ClientToScreen(hwnd, &pt); + } else { + pt.x = (short) LOWORD(lParam); + pt.y = (short) HIWORD(lParam); + } + ptl.x = (LONG)pt.x; + ptl.y = (LONG)pt.y; + ScreenToClient(hwnd, (LPPOINT)&ptl); + pszWord = GetRichTextWord(hwnd, &ptl); + inMenu = TRUE; + uID = CreateGCMenu(hwnd, &hMenu, 1, pt, si, NULL, pszWord); + inMenu = FALSE; + switch (uID) { + case 0: + PostMessage(GetParent(hwnd), WM_MOUSEACTIVATE, 0, 0 ); + break; + + case ID_COPYALL: + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) & sel); + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & all); + SendMessage(hwnd, WM_COPY, 0, 0); + SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) & sel); + PostMessage(GetParent(hwnd), WM_MOUSEACTIVATE, 0, 0 ); + break; + + case IDM_CLEAR: + if (si) + { + SetWindowText(hwnd, _T("")); + LM_RemoveAll(&si->pLog, &si->pLogEnd); + si->iEventCount = 0; + si->LastTime = 0; + PostMessage(GetParent(hwnd), WM_MOUSEACTIVATE, 0, 0 ); + } + break; + + case IDM_SEARCH_GOOGLE: + case IDM_SEARCH_BING: + case IDM_SEARCH_YAHOO: + case IDM_SEARCH_WIKIPEDIA: + case IDM_SEARCH_FOODNETWORK: + case IDM_SEARCH_GOOGLE_MAPS: + case IDM_SEARCH_GOOGLE_TRANSLATE: + SearchWord(pszWord, uID - IDM_SEARCH_GOOGLE + SEARCHENGINE_GOOGLE); + PostMessage(GetParent(hwnd), WM_MOUSEACTIVATE, 0, 0 ); + break; + default: + PostMessage(GetParent(hwnd), WM_MOUSEACTIVATE, 0, 0 ); + DoEventHookAsync(GetParent(hwnd), si->ptszID, si->pszModule, GC_USER_LOGMENU, NULL, NULL, (LPARAM)uID); + break; + } + DestroyGCMenu(&hMenu, 5); + mir_free(pszWord); + break; + } + case WM_CHAR: + SetFocus(GetDlgItem(GetParent(hwnd), IDC_CHAT_MESSAGE)); + SendMessage(GetDlgItem(GetParent(hwnd), IDC_CHAT_MESSAGE), WM_CHAR, wParam, lParam); + break; + } + + return CallWindowProc(OldLogProc, hwnd, msg, wParam, lParam); +} + +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 ); + //SetWindowPos(hwndToolTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + 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) { + // /GetChatToolTipText + // wParam = roomID parentdat->ptszID + // lParam = userID ui1->pszUID + 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); + } +} + +static LRESULT CALLBACK NicklistSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + SESSION_INFO* si =(SESSION_INFO*)GetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA); + int result = InputAreaShortcuts(hwnd, msg, wParam, lParam, &si->windowData); + if (result != -1) { + return result; + } + switch (msg) { + case WM_ERASEBKGND: + { + HDC dc = (HDC)wParam; + if (dc) { + int height, index, items = 0; + + index = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0); + if (index == LB_ERR || si->nUsersInNicklist <= 0) + return 0; + + items = si->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; + + case WM_RBUTTONDOWN: + 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; + DWORD item; + int height=0; + USERINFO * ui; + + 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(si->ptszID, si->pszModule, (int)item); + 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, si, uinew.pszUID, NULL); + + switch (uID) { + case 0: + break; + + case ID_MESS: + DoEventHookAsync(GetParent(hwnd), si->ptszID, si->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, (LPARAM)NULL); + break; + + default: + DoEventHookAsync(GetParent(hwnd), si->ptszID, si->pszModule, GC_USER_NICKLISTMENU, ui->pszUID, NULL, (LPARAM)uID); + break; + } + DestroyGCMenu(&hMenu, 1); + return TRUE; + } } + break; + + case WM_GETDLGCODE : + { + BOOL isAlt = GetKeyState(VK_MENU) & 0x8000; + BOOL isCtrl = (GetKeyState(VK_CONTROL) & 0x8000) && !isAlt; + + LPMSG lpmsg; + if ( ( lpmsg = (LPMSG)lParam ) != NULL ) { + if ( lpmsg->message == WM_KEYDOWN + && (lpmsg->wParam == VK_RETURN || lpmsg->wParam == VK_ESCAPE || (lpmsg->wParam == VK_TAB && (isAlt || isCtrl)))) + return DLGC_WANTALLKEYS; + } + break; + } + case WM_KEYDOWN: + if (wParam == VK_RETURN) { + int index = SendMessage(hwnd, LB_GETCURSEL, 0, 0); + if (index!=LB_ERR) { + USERINFO *ui = SM_GetUserFromIndex(si->ptszID, si->pszModule, index); + DoEventHookAsync(GetParent(hwnd), si->ptszID, si->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, (LPARAM)NULL); + } + break; + } + 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) { + si->szSearch[0] = 0; + } + 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 (wParam == 27 && si->szSearch[0]) { // escape - reset everything + si->szSearch[0] = 0; + 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 + */ + char *str = t2a(si->szSearch); + mir_free(str); + 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_SETCURSEL, i, 0); + InvalidateRect(hwnd, NULL, FALSE); + return 0; + } + } + } + if (i == iItems) { + MessageBeep(MB_OK); + si->szSearch[lstrlen(si->szSearch) - 1] = '\0'; + } + return 0; + } + break; + + case WM_MOUSEMOVE: + { + POINT pt; + RECT clientRect; + BOOL bInClient; + pt.x=LOWORD(lParam); + pt.y=HIWORD(lParam); + GetClientRect(hwnd,&clientRect); + bInClient=PtInRect(&clientRect, pt); + //Mouse capturing/releasing + if ( bInClient && GetCapture()!=hwnd) + SetCapture(hwnd); + else if (!bInClient) + ReleaseCapture(); + + if (bInClient) { + //hit test item under mouse + DWORD nItemUnderMouse=(DWORD)SendMessage(hwnd, LB_ITEMFROMPOINT, 0, lParam); + if ( HIWORD( nItemUnderMouse ) == 1 ) + nItemUnderMouse = (DWORD)(-1); + else + nItemUnderMouse &= 0xFFFF; + + ProcessNickListHovering(hwnd, (int)nItemUnderMouse, &pt, si); + } else { + ProcessNickListHovering(hwnd, -1, &pt, NULL); + } } + break; + } + + return CallWindowProc(OldNicklistProc, hwnd, msg, wParam, lParam); +} + + +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 = 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); +} + +INT_PTR CALLBACK RoomWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + static HMENU hToolbarMenu; + SESSION_INFO * si; + si = (SESSION_INFO *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if (!si && uMsg!=WM_INITDIALOG) return FALSE; + switch (uMsg) { + case WM_INITDIALOG: + { + SESSION_INFO* psi = (SESSION_INFO*)lParam; + int mask; + RECT minEditInit; + HWND hNickList = GetDlgItem(hwndDlg,IDC_CHAT_LIST); + NotifyLocalWinEvent(psi->windowData.hContact, hwndDlg, MSG_WINDOW_EVT_OPENING); + + TranslateDialogDefault(hwndDlg); + SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)psi); + si = psi; + RichUtil_SubClass(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + RichUtil_SubClass(GetDlgItem(hwndDlg, IDC_CHAT_LOG)); + RichUtil_SubClass(GetDlgItem(hwndDlg, IDC_CHAT_LIST)); + OldSplitterProc=(WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_CHAT_SPLITTERX),GWLP_WNDPROC,(LONG_PTR)SplitterSubclassProc); + OldNicklistProc=(WNDPROC)SetWindowLongPtr(hNickList,GWLP_WNDPROC,(LONG_PTR)NicklistSubclassProc); + OldLogProc=(WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_CHAT_LOG),GWLP_WNDPROC,(LONG_PTR)LogSubclassProc); + OldFilterButtonProc=(WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_CHAT_FILTER),GWLP_WNDPROC,(LONG_PTR)ButtonSubclassProc); + SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_CHAT_COLOR),GWLP_WNDPROC,(LONG_PTR)ButtonSubclassProc); + SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_CHAT_BKGCOLOR),GWLP_WNDPROC,(LONG_PTR)ButtonSubclassProc); + OldMessageProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), GWLP_WNDPROC,(LONG_PTR)MessageSubclassProc); + + GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), &minEditInit); + si->windowData.minEditBoxHeight = minEditInit.bottom - minEditInit.top; + si->windowData.minLogBoxHeight = si->windowData.minEditBoxHeight; + + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SUBCLASSED, 0, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_AUTOURLDETECT, 1, 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); + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_CHANGE | ENM_REQUESTRESIZE); + SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_LIMITTEXT, (WPARAM)sizeof(TCHAR)*0x7FFFFFFF, 0); + SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETOLECALLBACK, 0, (LPARAM) & reOleCallback); + + if (DBGetContactSettingByte(NULL, "Chat", "UseIEView", 0)) { + IEVIEWWINDOW ieWindow; + IEVIEWEVENT iee; + + ZeroMemory(&ieWindow, sizeof(ieWindow)); + ieWindow.cbSize = sizeof(ieWindow); + ieWindow.iType = IEW_CREATE; + ieWindow.dwFlags = 0; + ieWindow.dwMode = IEWM_CHAT; + ieWindow.parent = hwndDlg; + ieWindow.x = 0; + ieWindow.y = 0; + ieWindow.cx = 200; + ieWindow.cy = 300; + CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow); + si->windowData.hwndLog = ieWindow.hwnd; + ZeroMemory(&iee, sizeof(iee)); + iee.cbSize = sizeof(iee); + iee.iType = IEE_CLEAR_LOG; + iee.hwnd = si->windowData.hwndLog; + iee.hContact = si->windowData.hContact; + iee.codepage = si->windowData.codePage; + iee.pszProto = si->pszModule; + CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&iee); + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_SMILEY), TRUE); + + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_HIDESELECTION, TRUE, 0); + + SendMessage(hwndDlg, GC_SETWNDPROPS, 0, 0); + SendMessage(hwndDlg, DM_UPDATESTATUSBAR, 0, 0); + SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0); + + SendMessage(GetParent(hwndDlg), CM_ADDCHILD, (WPARAM) hwndDlg, (LPARAM) psi->windowData.hContact); + PostMessage(hwndDlg, GC_UPDATENICKLIST, 0, 0); + NotifyLocalWinEvent(psi->windowData.hContact, hwndDlg, MSG_WINDOW_EVT_OPEN); + } + break; + + case GC_SETWNDPROPS: + { + LoadGlobalSettings(); + InitButtons(hwndDlg, si); + + SendMessage(hwndDlg, DM_UPDATESTATUSBAR, 0, 0); + SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0); + SendMessage(hwndDlg, GC_FIXTABICONS, 0, 0); + + { // log + //int iIndent = 0; + //PARAFORMAT2 pf2; + //if (g_Settings.dwIconFlags) + // iIndent += (14*1440)/g_dat->logPixelSX; + //if (g_Settings.ShowTime && g_Settings.LogIndentEnabled) + // iIndent += g_Settings.LogTextIndent*1440/g_dat->logPixelSX; + //pf2.cbSize = sizeof(pf2); + //pf2.dwMask = PFM_OFFSET; + //pf2.dxOffset = iIndent * 1440 / g_dat->logPixelSX; + //SendDlgItemMessage(hwndDlg, IDC_CHAT_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2); + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_SETBKGNDCOLOR , 0, g_Settings.crLogBackground); + } + + { //messagebox + COLORREF crFore; + + CHARFORMAT2 cf; + LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, NULL, &crFore, FALSE); + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_UNDERLINE|CFM_BACKCOLOR; + cf.dwEffects = 0; + cf.crTextColor = crFore; + cf.crBackColor = DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR); + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), EM_SETBKGNDCOLOR , 0, DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR)); + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, WM_SETFONT, (WPARAM) g_Settings.MessageBoxFont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, (WPARAM)SCF_ALL , (LPARAM)&cf); + } + { // nicklist + int ih; + int ih2; + int font; + int height; + + ih = GetTextPixelSize( _T("AQG_glo'"), g_Settings.UserListFont,FALSE); + ih2 = GetTextPixelSize( _T("AQG_glo'"), g_Settings.UserListHeadingsFont,FALSE); + height = DBGetContactSettingByte(NULL, "Chat", "NicklistRowDist", 12); + font = ih > ih2?ih:ih2; + // make sure we have space for icon! + if (DBGetContactSettingByte(NULL, "Chat", "ShowContactStatus", 0)) + font = font > 16 ? font : 16; + + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LIST), LB_SETITEMHEIGHT, 0, (LPARAM)height > font ? height : font); + InvalidateRect(GetDlgItem(hwndDlg, IDC_CHAT_LIST), NULL, TRUE); + } + SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_REQUESTRESIZE, 0, 0); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + SendMessage(hwndDlg, GC_REDRAWLOG2, 0, 0); + } + break; + + case DM_UPDATETITLEBAR: + { + TitleBarData tbd = {0}; + TCHAR szTemp [100]; + if (g_dat->flags & SMF_STATUSICON) { + MODULEINFO* mi = MM_FindModule(si->pszModule); + tbd.hIcon = (si->wStatus == ID_STATUS_ONLINE) ? mi->hOnlineIcon : mi->hOfflineIcon; + tbd.hIconBig = (si->wStatus == ID_STATUS_ONLINE) ? mi->hOnlineIconBig : mi->hOfflineIconBig; + } + else { + tbd.hIcon = GetCachedIcon("chat_window"); + tbd.hIconBig = g_dat->hIconChatBig; + } + tbd.hIconNot = (si->wState & (GC_EVENT_HIGHLIGHT | STATE_TALK)) ? GetCachedIcon("chat_overlay") : NULL; + + switch(si->iType) { + case GCW_CHATROOM: + mir_sntprintf(szTemp, SIZEOF(szTemp), + (si->nUsersInNicklist == 1) ? TranslateT("%s: Chat Room (%u user)") : TranslateT("%s: Chat Room (%u users)"), + si->ptszName, si->nUsersInNicklist); + 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); + break; + } + tbd.iFlags = TBDF_TEXT | TBDF_ICON; + tbd.pszText = szTemp; + SendMessage(GetParent(hwndDlg), CM_UPDATETITLEBAR, (WPARAM) &tbd, (LPARAM) hwndDlg); + SendMessage(hwndDlg, DM_UPDATETABCONTROL, 0, 0); + } + break; + + case DM_UPDATESTATUSBAR: + { + StatusIconData sid; + StatusBarData sbd; + HICON hIcon; + MODULEINFO* mi = MM_FindModule(si->pszModule); + TCHAR szTemp[512]; + hIcon = si->wStatus==ID_STATUS_ONLINE ? mi->hOnlineIcon : mi->hOfflineIcon; + mir_sntprintf(szTemp, SIZEOF(szTemp), _T("%s : %s"), mi->ptszModDispName, si->ptszStatusbarText ? si->ptszStatusbarText : _T("")); + sbd.iItem = 0; + sbd.iFlags = SBDF_TEXT | SBDF_ICON; + sbd.hIcon = hIcon; + sbd.pszText = szTemp; + SendMessage(GetParent(hwndDlg), CM_UPDATESTATUSBAR, (WPARAM) &sbd, (LPARAM) hwndDlg); + sbd.iItem = 1; + sbd.hIcon = NULL; + sbd.pszText = _T(""); + SendMessage(GetParent(hwndDlg), CM_UPDATESTATUSBAR, (WPARAM) &sbd, (LPARAM) hwndDlg); + sid.cbSize = sizeof(sid); + sid.szModule = SRMMMOD; + sid.dwId = 0; + #if defined( _UNICODE ) + sid.flags = 0; + #else + sid.flags = MBF_DISABLED; + #endif + ModifyStatusIcon((WPARAM)si->windowData.hContact, (LPARAM) &sid); + // SendMessage(hwndDlg, GC_FIXTABICONS, 0, (LPARAM)si); + } + break; + case DM_GETCODEPAGE: + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, si->windowData.codePage); + return TRUE; + case DM_SETCODEPAGE: + si->windowData.codePage = (int) lParam; + si->pszHeader = Log_CreateRtfHeader(MM_FindModule(si->pszModule), si); + SendMessage(hwndDlg, GC_REDRAWLOG2, 0, 0); + break; + case DM_SWITCHINFOBAR: + case DM_SWITCHTOOLBAR: + SendMessage(hwndDlg, WM_SIZE, 0, 0); + break; + case WM_SIZE: + { + + if (wParam == SIZE_MAXIMIZED) + PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0); + + if (IsIconic(hwndDlg)) break; + + if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED) { + int dlgWidth, dlgHeight; + RECT rc; + dlgWidth = LOWORD(lParam); + dlgHeight = HIWORD(lParam); + /*if (dlgWidth == 0 && dlgHeight ==0) */{ + GetClientRect(hwndDlg, &rc); + dlgWidth = rc.right - rc.left; + dlgHeight = rc.bottom - rc.top; + } + + MessageDialogResize(hwndDlg, si, dlgWidth, dlgHeight); + + } + } + 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); + mir_forkthread(phase2, si); + } + else Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE); + } + 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); + break; + + case GC_REDRAWLOG3: + si->LastTime = 0; + if (si->pLog) + Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE); + break; + + case GC_ADDLOG: + if (si->pLogEnd) + Log_StreamInEvent(hwndDlg, si->pLog, si, FALSE); + else + SendMessage(hwndDlg, GC_EVENT_CONTROL + WM_USER+500, WINDOW_CLEARLOG, 0); + break; + + + case DM_UPDATETABCONTROL: + { + TabControlData tcd; + tcd.iFlags = TCDF_TEXT; + tcd.pszText = si->ptszName; + SendMessage(GetParent(hwndDlg), CM_UPDATETABCONTROL, (WPARAM) &tcd, (LPARAM) hwndDlg); + + } + case GC_FIXTABICONS: + { + TabControlData tcd; + HICON hIcon; + if (!(si->wState & GC_EVENT_HIGHLIGHT)) + { + if (si->wState & STATE_TALK) + hIcon = (si->wStatus==ID_STATUS_ONLINE) ? MM_FindModule(si->pszModule)->hOnlineTalkIcon : MM_FindModule(si->pszModule)->hOfflineTalkIcon; + else + hIcon = (si->wStatus==ID_STATUS_ONLINE) ? MM_FindModule(si->pszModule)->hOnlineIcon : MM_FindModule(si->pszModule)->hOfflineIcon; + } else { + hIcon = g_dat->hMsgIcon; + } + tcd.iFlags = TCDF_ICON; + tcd.hIcon = hIcon; + SendMessage(GetParent(hwndDlg), CM_UPDATETABCONTROL, (WPARAM) &tcd, (LPARAM) hwndDlg); + } + break; + + case GC_SETMESSAGEHIGHLIGHT: + { + si->wState |= GC_EVENT_HIGHLIGHT; + SendMessage(si->hWnd, GC_FIXTABICONS, 0, 0); + SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0); + if (DBGetContactSettingByte(NULL, "Chat", "FlashWindowHighlight", 0) != 0 && GetActiveWindow() != hwndDlg && GetForegroundWindow() != GetParent(hwndDlg)) + SendMessage(GetParent(si->hWnd), CM_STARTFLASHING, 0, 0); + } + break; + + case GC_SETTABHIGHLIGHT: + { + SendMessage(si->hWnd, GC_FIXTABICONS, 0, 0); + SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0); + if (g_Settings.FlashWindow && GetActiveWindow() != GetParent(hwndDlg) && GetForegroundWindow() != GetParent(hwndDlg)) + SendMessage(GetParent(si->hWnd), CM_STARTFLASHING, 0, 0); + } + break; + + case DM_ACTIVATE: + { + if (si->wState & STATE_TALK) { + si->wState &= ~STATE_TALK; + + DBWriteContactSettingWord(si->windowData.hContact, si->pszModule ,"ApparentMode",(LPARAM) 0); + } + + if (si->wState & GC_EVENT_HIGHLIGHT) { + si->wState &= ~GC_EVENT_HIGHLIGHT; + + if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->windowData.hContact, (LPARAM)0)) + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->windowData.hContact, (LPARAM)"chaticon"); + } + + SendMessage(hwndDlg, GC_FIXTABICONS, 0, 0); + if (!si->hWnd) { + ShowRoom(si, (WPARAM)WINDOW_VISIBLE, TRUE); + SendMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 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: + if (!MeasureMenuItem(wParam, lParam)) { + MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *) lParam; + + if (mis->CtlType == ODT_MENU) + { + return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam); + } else + { + int ih = GetTextPixelSize( _T("AQGgl'"), g_Settings.UserListFont,FALSE); + int ih2 = GetTextPixelSize( _T("AQGg'"), g_Settings.UserListHeadingsFont,FALSE); + int font = ih > ih2?ih:ih2; + int height = DBGetContactSettingByte(NULL, "Chat", "NicklistRowDist", 12); + // make sure we have space for icon! + if (DBGetContactSettingByte(NULL, "Chat", "ShowContactStatus", 0)) + font = font > 16 ? font : 16; + mis->itemHeight = height > font?height:font; + } + + return TRUE; + } + + case WM_DRAWITEM: + if (!DrawMenuItem(wParam, lParam)) { + DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *) lParam; + if (dis->CtlType == ODT_MENU) { + return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam); + } else + if (dis->CtlID == IDC_CHAT_LIST) { + HFONT hFont, hOldFont; + HICON hIcon; + int offset; + int height; + int index = dis->itemID; + USERINFO * ui = SM_GetUserFromIndex(si->ptszID, si->pszModule, index); + if (ui) { + int x_offset = 2; + + height = dis->rcItem.bottom - dis->rcItem.top; + + if (height&1) + height++; + if (height == 10) + offset = 0; + else + offset = height/2 - 5; + hIcon = SM_GetStatusIcon(si, ui); + hFont = (ui->iStatusEx == 0) ? g_Settings.UserListFont : g_Settings.UserListHeadingsFont; + hOldFont = (HFONT) SelectObject(dis->hDC, hFont); + SetBkMode(dis->hDC, TRANSPARENT); + + if (dis->itemAction == ODA_FOCUS && dis->itemState & ODS_SELECTED) + FillRect(dis->hDC, &dis->rcItem, hListSelectedBkgBrush); + else //if (dis->itemState & ODS_INACTIVE) + FillRect(dis->hDC, &dis->rcItem, hListBkgBrush); + + 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-3,hIcon,16,16,0,NULL, DI_NORMAL); + CallService(MS_SKIN2_RELEASEICON,(WPARAM)hIcon, 0); + x_offset += 18; + } + DrawIconEx(dis->hDC,x_offset, dis->rcItem.top + offset,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-3,hIcon,16,16,0,NULL, DI_NORMAL); + CallService(MS_SKIN2_RELEASEICON,(WPARAM)hIcon, 0); + x_offset += 18; + } + + SetTextColor(dis->hDC, ui->iStatusEx == 0?g_Settings.crUserListColor:g_Settings.crUserListHeadingsColor); + TextOut(dis->hDC, dis->rcItem.left+x_offset, dis->rcItem.top, ui->pszNick, lstrlen(ui->pszNick)); + SelectObject(dis->hDC, hOldFont); + } + return TRUE; + } } + + case GC_UPDATENICKLIST: + { + int index=0; + SendDlgItemMessage(hwndDlg, IDC_CHAT_LIST, WM_SETREDRAW, FALSE, 0); + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LIST), LB_RESETCONTENT, 0, 0); + for (index=0; indexnUsersInNicklist; index++) { + USERINFO * ui = SM_GetUserFromIndex(si->ptszID, si->pszModule, index); + if (ui) { + char szIndicator = SM_GetStatusIndicator(si, ui); + if (szIndicator>'\0') { + static TCHAR ptszBuf[128]; + mir_sntprintf( ptszBuf, SIZEOF(ptszBuf), _T("%c%s"), szIndicator, ui->pszNick); + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LIST), LB_ADDSTRING, 0, (LPARAM)ptszBuf); + } else { + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LIST), LB_ADDSTRING, 0, (LPARAM)ui->pszNick); + } + } + } + SendDlgItemMessage(hwndDlg, IDC_CHAT_LIST, WM_SETREDRAW, TRUE, 0); + InvalidateRect(GetDlgItem(hwndDlg, IDC_CHAT_LIST), NULL, FALSE) ; + UpdateWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIST)) ; + SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0); + } + break; + + case GC_EVENT_CONTROL + WM_USER+500: + { + switch(wParam) { + case SESSION_OFFLINE: + SendMessage(hwndDlg, DM_UPDATESTATUSBAR, 0, 0); + SendMessage(si->hWnd, GC_UPDATENICKLIST, (WPARAM)0, (LPARAM)0); + return TRUE; + + case SESSION_ONLINE: + SendMessage(hwndDlg, DM_UPDATESTATUSBAR, 0, 0); + return TRUE; + + case WINDOW_HIDDEN: + SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 0); + return TRUE; + + case WINDOW_CLEARLOG: + SetDlgItemText(hwndDlg, IDC_CHAT_LOG, _T("")); + return TRUE; + + case SESSION_TERMINATE: + if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->windowData.hContact, (LPARAM)0)) + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->windowData.hContact, (LPARAM)"chaticon"); + si->wState &= ~STATE_TALK; + DBWriteContactSettingWord(si->windowData.hContact, si->pszModule ,"ApparentMode",(LPARAM) 0); + SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 0); + 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 (DBGetContactSettingByte(NULL, "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, DM_UPDATESTATUSBAR, 0, 0); + ShowWindow(hwndDlg, SW_SHOW); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + SetForegroundWindow(hwndDlg); + return TRUE; + } } + break; + + case GC_SPLITTERMOVED: + if ((HWND)lParam==GetDlgItem(hwndDlg,IDC_CHAT_SPLITTERX)) { + POINT pt; + RECT rc; + 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; + } + else if ((HWND)lParam==GetDlgItem(hwndDlg,IDC_CHAT_SPLITTERY)) { + POINT pt; + RECT rc; + int oldSplitterY; + GetClientRect(hwndDlg,&rc); + pt.x=0; pt.y=wParam; + ScreenToClient(hwndDlg,&pt); + oldSplitterY=si->iSplitterY; + si->iSplitterY=rc.bottom-pt.y; + g_Settings.iSplitterY = si->iSplitterY; + } + PostMessage(hwndDlg,WM_SIZE,0,0); + 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: + si->iLogFilterFlags = lParam; + break; + + case GC_SHOWFILTERMENU: + { + RECT rc; + HWND hwnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER), hwndDlg, FilterWndProc, (LPARAM)si); + TranslateDialogDefault(hwnd); + GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_FILTER), &rc); + SetWindowPos(hwnd, HWND_TOP, rc.left-85, (IsWindowVisible(GetDlgItem(hwndDlg, IDC_CHAT_FILTER))||IsWindowVisible(GetDlgItem(hwndDlg, IDC_CHAT_BOLD)))?rc.top-206:rc.top-186, 0, 0, SWP_NOSIZE|SWP_SHOWWINDOW); + } + break; + + case GC_SHOWCOLORCHOOSER: + { + HWND ColorWindow; + RECT rc; + BOOL bFG = lParam == IDC_CHAT_COLOR?TRUE:FALSE; + COLORCHOOSER * pCC = mir_alloc(sizeof(COLORCHOOSER)); + + GetWindowRect(GetDlgItem(hwndDlg, bFG?IDC_CHAT_COLOR:IDC_CHAT_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_CHAT_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: + { + SCROLLINFO si = { 0 }; + if ((GetWindowLong(GetDlgItem(hwndDlg, IDC_CHAT_LOG), GWL_STYLE) & WS_VSCROLL) != 0){ + CHARRANGE sel; + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE | SIF_RANGE; + GetScrollInfo(GetDlgItem(hwndDlg, IDC_CHAT_LOG), SB_VERT, &si); + si.fMask = SIF_POS; + si.nPos = si.nMax - si.nPage + 1; + SetScrollInfo(GetDlgItem(hwndDlg, IDC_CHAT_LOG), SB_VERT, &si, TRUE); + sel.cpMin = sel.cpMax = GetRichTextLength(GetDlgItem(hwndDlg, IDC_CHAT_LOG), CP_ACP, FALSE); + SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), EM_EXSETSEL, 0, (LPARAM) & sel); + PostMessage(GetDlgItem(hwndDlg, IDC_CHAT_LOG), WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0); + } } + break; + + case WM_ACTIVATE: + if (LOWORD(wParam) != WA_ACTIVE) + break; + + //fall through + case WM_MOUSEACTIVATE: + { + if (uMsg != WM_ACTIVATE) + SetFocus(GetDlgItem(hwndDlg,IDC_CHAT_MESSAGE)); + + SetActiveSession(si->ptszID, si->pszModule); + + if (DBGetContactSettingWord(si->windowData.hContact, si->pszModule ,"ApparentMode", 0) != 0) + DBWriteContactSettingWord(si->windowData.hContact, si->pszModule ,"ApparentMode",(LPARAM) 0); + if (CallService(MS_CLIST_GETEVENT, (WPARAM)si->windowData.hContact, (LPARAM)0)) + CallService(MS_CLIST_REMOVEEVENT, (WPARAM)si->windowData.hContact, (LPARAM)"chaticon"); + } + break; + + case WM_NOTIFY: + { + LPNMHDR pNmhdr; + + pNmhdr = (LPNMHDR)lParam; + switch (pNmhdr->code) { + case EN_REQUESTRESIZE: + if (pNmhdr->idFrom == IDC_CHAT_MESSAGE) { + REQRESIZE *rr = (REQRESIZE *)lParam; + int height = rr->rc.bottom - rr->rc.top + 1; + if (height < g_dat->minInputAreaHeight) { + height = g_dat->minInputAreaHeight; + } + if (si->desiredInputAreaHeight != height) { + si->desiredInputAreaHeight = height; + SendMessage(hwndDlg, WM_SIZE, 0, 0); + PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0); + } + } + break; + case EN_MSGFILTER: + if (pNmhdr->idFrom == IDC_CHAT_LOG && ((MSGFILTER *) lParam)->msg == WM_RBUTTONUP){ + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + break; + case EN_LINK: + if (pNmhdr->idFrom == IDC_CHAT_LOG) { + switch (((ENLINK *) lParam)->msg) { + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: + if (HandleLinkClick(g_hInst, hwndDlg, GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE),(ENLINK*)lParam)) { + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE); + return TRUE; + } + break; + } } + break; + case TTN_NEEDTEXT: + if (pNmhdr->idFrom == (UINT_PTR)GetDlgItem(hwndDlg,IDC_CHAT_LIST)) + { + LPNMTTDISPINFO lpttd = (LPNMTTDISPINFO)lParam; + POINT p; + int item; + USERINFO * ui; + SESSION_INFO* parentdat =(SESSION_INFO*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + + GetCursorPos( &p ); + ScreenToClient(GetDlgItem(hwndDlg, IDC_CHAT_LIST), &p); + item = LOWORD(SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LIST), LB_ITEMFROMPOINT, 0, MAKELPARAM(p.x, p.y))); + ui = SM_GetUserFromIndex(parentdat->ptszID, parentdat->pszModule, item); + if ( ui != NULL ) { + static TCHAR ptszBuf[ 1024 ]; + mir_sntprintf( ptszBuf, SIZEOF(ptszBuf), _T("%s: %s\r\n%s: %s\r\n%s: %s"), + TranslateT( "Nick name" ), ui->pszNick, + TranslateT( "Unique id" ), ui->pszUID, + TranslateT( "Status" ), TM_WordToString( parentdat->pStatuses, ui->Status )); + lpttd->lpszText = ptszBuf; + } } + break; + } } + break; + + case WM_COMMAND: + if (!lParam && CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM) si->windowData.hContact)) + break; + switch (LOWORD(wParam)) { + case IDC_CHAT_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_CHAT_LIST),&hti.pt); + + item = LOWORD(SendMessage(GetDlgItem(hwndDlg, IDC_CHAT_LIST), LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y))); + ui = SM_GetUserFromIndex(si->ptszID, si->pszModule, item); + if (ui) { + if (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); + } + else DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, (LPARAM)NULL); + } + + return TRUE; + } + + if ( HIWORD(wParam) == LBN_KILLFOCUS ) + RedrawWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIST), NULL, NULL, RDW_INVALIDATE); + break; + + case IDOK: + { + char* pszRtf; + TCHAR* ptszText, *p1; + if (!IsWindowEnabled(GetDlgItem(hwndDlg,IDOK))) + break; + + pszRtf = GetRichTextRTF(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + { + TCmdList *cmdListNew = tcmdlist_last(si->windowData.cmdList); + while (cmdListNew != NULL && cmdListNew->temporary) { + si->windowData.cmdList = tcmdlist_remove(si->windowData.cmdList, cmdListNew); + cmdListNew = tcmdlist_last(si->windowData.cmdList); + } + } + si->windowData.cmdList = tcmdlist_append(si->windowData.cmdList, pszRtf, 20, FALSE); + ptszText = DoRtfToTags(pszRtf, si); + p1 = _tcschr(ptszText, '\0'); + + //remove trailing linebreaks + while ( p1 > ptszText && (*p1 == '\0' || *p1 == '\r' || *p1 == '\n')) { + *p1 = '\0'; + p1--; + } + + if ( MM_FindModule(si->pszModule)->bAckMsg ) { + EnableWindow(GetDlgItem(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("")); + + EnableWindow(GetDlgItem(hwndDlg,IDOK),FALSE); + + DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, ptszText, (LPARAM)NULL); + mir_free(pszRtf); + #if defined( _UNICODE ) + mir_free(ptszText); + #endif + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + } + break; + + case IDC_CHAT_SHOWNICKLIST: + if (!IsWindowEnabled(GetDlgItem(hwndDlg,IDC_CHAT_SHOWNICKLIST))) + break; + if (si->iType == GCW_SERVER) + break; + + si->bNicklistEnabled = !si->bNicklistEnabled; + + SendDlgItemMessage(hwndDlg,IDC_CHAT_SHOWNICKLIST,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon(si->bNicklistEnabled?"chat_nicklist":"chat_nicklist2")); + SendMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0); + SendMessage(hwndDlg, WM_SIZE, 0, 0); + break; + + case IDC_CHAT_MESSAGE: + if (HIWORD(wParam) == EN_CHANGE) { + si->windowData.cmdListCurrent = NULL; + EnableWindow(GetDlgItem(hwndDlg, IDOK), GetRichTextLength(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE), si->windowData.codePage, FALSE) != 0); + } + break; + + case IDC_CHAT_SMILEY: + { + SMADD_SHOWSEL3 smaddInfo; + RECT rc; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_SMILEY), &rc); + + smaddInfo.cbSize = sizeof(SMADD_SHOWSEL3); + smaddInfo.hwndParent = GetParent(hwndDlg); + smaddInfo.hwndTarget = GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE); + smaddInfo.targetMessage = EM_REPLACESEL; + smaddInfo.targetWParam = TRUE; + smaddInfo.Protocolname = si->pszModule; + //smaddInfo.Direction = 3; + smaddInfo.Direction = 0; + smaddInfo.xPosition = rc.left; + smaddInfo.yPosition = rc.bottom; + smaddInfo.hContact = si->windowData.hContact; + 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 ( pInfo ) + ShellExecute(hwndDlg, NULL, GetChatLogsFilename(si->windowData.hContact, 0), NULL, NULL, SW_SHOW); + } + break; + + case IDC_CHAT_CHANMGR: + if (!IsWindowEnabled(GetDlgItem(hwndDlg,IDC_CHAT_CHANMGR))) + break; + DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_CHANMGR, NULL, NULL, (LPARAM)NULL); + break; + + case IDC_CHAT_FILTER: + if (!IsWindowEnabled(GetDlgItem(hwndDlg,IDC_CHAT_FILTER))) + break; + + si->bFilterEnabled = !si->bFilterEnabled; + SendDlgItemMessage(hwndDlg,IDC_CHAT_FILTER,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetCachedIcon(si->bFilterEnabled?"chat_filter":"chat_filter2")); + if (si->bFilterEnabled && DBGetContactSettingByte(NULL, "Chat", "RightClickFilter", 0) == 0) { + SendMessage(hwndDlg, GC_SHOWFILTERMENU, 0, 0); + break; + } + SendMessage(hwndDlg, GC_REDRAWLOG, 0, 0); + break; + + case IDC_CHAT_BKGCOLOR: + { + MODULEINFO * pInfo = MM_FindModule(si->pszModule); + CHARFORMAT2 cf; + + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwEffects = 0; + + if (!IsWindowEnabled(GetDlgItem(hwndDlg,IDC_CHAT_BKGCOLOR))) + break; + + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_BKGCOLOR)) { + if (DBGetContactSettingByte(NULL, "Chat", "RightClickFilter", 0) == 0) + SendMessage(hwndDlg, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_CHAT_BKGCOLOR); + else if (si->bBGSet){ + cf.dwMask = CFM_BACKCOLOR; + cf.crBackColor = pInfo->crColors[si->iBG]; + if (pInfo->bSingleFormat) { + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf); + } else { + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } } + else { + cf.dwMask = CFM_BACKCOLOR; + cf.crBackColor = (COLORREF)DBGetContactSettingDword(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR); + if (pInfo->bSingleFormat) { + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf); + } else { + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } } + break; + + case IDC_CHAT_COLOR: + { + MODULEINFO * pInfo = MM_FindModule(si->pszModule); + CHARFORMAT2 cf; + cf.cbSize = sizeof(CHARFORMAT2); + cf.dwEffects = 0; + + if (!IsWindowEnabled(GetDlgItem(hwndDlg,IDC_CHAT_COLOR))) + break; + + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_COLOR) ) { + if (DBGetContactSettingByte(NULL, "Chat", "RightClickFilter", 0) == 0) + SendMessage(hwndDlg, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_CHAT_COLOR); + else if (si->bFGSet) { + cf.dwMask = CFM_COLOR; + cf.crTextColor = pInfo->crColors[si->iFG]; + if (pInfo->bSingleFormat) { + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf); + } else { + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } } + else { + COLORREF cr; + + LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, NULL, &cr, FALSE); + cf.dwMask = CFM_COLOR; + cf.crTextColor = cr; + if (pInfo->bSingleFormat) { + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf); + } else { + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + + } } + break; + + case IDC_CHAT_BOLD: + case IDC_CHAT_ITALICS: + case IDC_CHAT_UNDERLINE: + + { + MODULEINFO * pInfo = MM_FindModule(si->pszModule); + 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_CHAT_ITALICS && !IsWindowEnabled(GetDlgItem(hwndDlg,IDC_CHAT_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_CHAT_ITALICS)) + cf.dwEffects |= CFE_ITALIC; + if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_UNDERLINE)) + cf.dwEffects |= CFE_UNDERLINE; + if (pInfo->bSingleFormat) { + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf); + } else { + SendDlgItemMessage(hwndDlg, IDC_CHAT_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf); + } + } + break; + case IDCANCEL: + PostMessage(hwndDlg, WM_CLOSE, 0, 0); + } + break; + + case WM_KEYDOWN: + SetFocus(GetDlgItem(hwndDlg, IDC_CHAT_MESSAGE)); + break; + + + + case WM_GETMINMAXINFO: + { + MINMAXINFO* mmi = (MINMAXINFO*)lParam; + mmi->ptMinTrackSize.x = si->iSplitterX + 43; + if (mmi->ptMinTrackSize.x < 350) + mmi->ptMinTrackSize.x = 350; + + mmi->ptMinTrackSize.y = si->windowData.minLogBoxHeight + TOOLBAR_HEIGHT + si->windowData.minEditBoxHeight + 5; + } + break; + + case WM_LBUTTONDBLCLK: + if (LOWORD(lParam) < 30) + PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0); + else + SendMessage(GetParent(hwndDlg), WM_SYSCOMMAND, SC_MINIMIZE, 0); + break; + + case WM_LBUTTONDOWN: + SendMessage(GetParent(hwndDlg), WM_LBUTTONDOWN, wParam, lParam); + return TRUE; + + case WM_RBUTTONUP: + { + int i; + POINT pt; + MENUITEMINFO mii; + hToolbarMenu = CreatePopupMenu(); + for (i = 0; i < SIZEOF(toolbarButtons); i++) { + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_BITMAP; + mii.fType = MFT_STRING; + mii.fState = (g_dat->chatBbuttonVisibility & (1<< i)) ? MFS_CHECKED : MFS_UNCHECKED; + mii.wID = i + 1; + mii.dwItemData = (ULONG_PTR)g_dat->hChatButtonIconList; + mii.hbmpItem = HBMMENU_CALLBACK; + mii.dwTypeData = TranslateTS((toolbarButtons[i].name)); + InsertMenuItem(hToolbarMenu, i, TRUE, &mii); + } +// CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hToolbarMenu, 0); + pt.x = (short) LOWORD(GetMessagePos()); + pt.y = (short) HIWORD(GetMessagePos()); + i = TrackPopupMenu(hToolbarMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL); + if (i > 0) { + g_dat->chatBbuttonVisibility ^= (1 << (i - 1)); + DBWriteContactSettingDword(NULL, SRMMMOD, SRMSGSET_CHATBUTTONVISIBILITY, g_dat->chatBbuttonVisibility); + SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE); + } + DestroyMenu(hToolbarMenu); + return TRUE; + } + + case DM_GETCONTEXTMENU: + { + HMENU hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) si->windowData.hContact, 0); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)hMenu); + return TRUE; + } + + case WM_CONTEXTMENU: + if (GetParent(hwndDlg) == (HWND) wParam) { + POINT pt; + HMENU hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) si->windowData.hContact, 0); + GetCursorPos(&pt); + TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hwndDlg, NULL); + DestroyMenu(hMenu); + } + break; + + case WM_CLOSE: + SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 0); + break; + + case GC_CLOSEWINDOW: + DestroyWindow(hwndDlg); + break; + + case WM_DESTROY: + + NotifyLocalWinEvent(si->windowData.hContact, hwndDlg, MSG_WINDOW_EVT_CLOSING); + si->hWnd = NULL; + SetWindowLongPtr(hwndDlg,GWLP_USERDATA,0); + SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_CHAT_SPLITTERY),GWLP_WNDPROC,(LONG_PTR)OldSplitterProc); + SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_CHAT_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_CHAT_FILTER),GWLP_WNDPROC,(LONG_PTR)OldFilterButtonProc); + SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_CHAT_COLOR),GWLP_WNDPROC,(LONG_PTR)OldFilterButtonProc); + SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_CHAT_BKGCOLOR),GWLP_WNDPROC,(LONG_PTR)OldFilterButtonProc); + + SendMessage(GetParent(hwndDlg), CM_REMOVECHILD, 0, (LPARAM) hwndDlg); + if (si->windowData.hwndLog != NULL) { + IEVIEWWINDOW ieWindow; + ieWindow.cbSize = sizeof(IEVIEWWINDOW); + ieWindow.iType = IEW_DESTROY; + ieWindow.hwnd = si->windowData.hwndLog; + CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow); + } + + NotifyLocalWinEvent(si->windowData.hContact, hwndDlg, MSG_WINDOW_EVT_CLOSE); + break; + } + return(FALSE); +} -- cgit v1.2.3