From 88e9a3438231b9dc6e1101e739f55bceead19796 Mon Sep 17 00:00:00 2001
From: George Hazan <ghazan@miranda.im>
Date: Tue, 1 Nov 2016 23:26:59 +0300
Subject: StdChat merged with StdMsg

---
 src/core/stdmsg/res/1.ico            |  Bin 0 -> 502 bytes
 src/core/stdmsg/res/2.ico            |  Bin 0 -> 502 bytes
 src/core/stdmsg/res/3.ico            |  Bin 0 -> 502 bytes
 src/core/stdmsg/res/4.ico            |  Bin 0 -> 502 bytes
 src/core/stdmsg/res/5.ico            |  Bin 0 -> 502 bytes
 src/core/stdmsg/res/6.ico            |  Bin 0 -> 502 bytes
 src/core/stdmsg/res/action.ico       |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/addmode.ico      |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/bkgcolor.ico     |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/blank.ico        |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/bold.ico         |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/close.ico        |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/color.ico        |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/excl.ico         |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/filter.ico       |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/filter2.ico      |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/highlight.ico    |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/history.ico      |  Bin 0 -> 5430 bytes
 src/core/stdmsg/res/info.ico         |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/italics.ico      |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/join.ico         |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/kick.ico         |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/message.ico      |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/messageout.ico   |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/nick.ico         |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/nicklist.ico     |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/nicklist2.ico    |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/overlay.ico      |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/part.ico         |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/quit.ico         |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/removestatus.ico |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/resource.rc      |  291 ++++
 src/core/stdmsg/res/smiley.ico       |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/smileyc.ico      |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/tag1.ico         |  Bin 0 -> 286 bytes
 src/core/stdmsg/res/tag2.ico         |  Bin 0 -> 2862 bytes
 src/core/stdmsg/res/topic.ico        |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/topicbut.ico     |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/underline.ico    |  Bin 0 -> 1150 bytes
 src/core/stdmsg/res/window.ico       |  Bin 0 -> 5430 bytes
 src/core/stdmsg/src/chat_manager.cpp |  474 ++++++
 src/core/stdmsg/src/chat_options.cpp |  761 ++++++++++
 src/core/stdmsg/src/chat_util.cpp    |  482 +++++++
 src/core/stdmsg/src/chat_window.cpp  | 2610 ++++++++++++++++++++++++++++++++++
 src/core/stdmsg/src/msgdialog.cpp    |    1 -
 src/core/stdmsg/src/msgs.cpp         |    3 +-
 src/core/stdmsg/src/resource.h       |  139 +-
 src/core/stdmsg/src/srmm.cpp         |    9 +-
 src/core/stdmsg/src/stdafx.h         |   95 ++
 49 files changed, 4851 insertions(+), 14 deletions(-)
 create mode 100644 src/core/stdmsg/res/1.ico
 create mode 100644 src/core/stdmsg/res/2.ico
 create mode 100644 src/core/stdmsg/res/3.ico
 create mode 100644 src/core/stdmsg/res/4.ico
 create mode 100644 src/core/stdmsg/res/5.ico
 create mode 100644 src/core/stdmsg/res/6.ico
 create mode 100644 src/core/stdmsg/res/action.ico
 create mode 100644 src/core/stdmsg/res/addmode.ico
 create mode 100644 src/core/stdmsg/res/bkgcolor.ico
 create mode 100644 src/core/stdmsg/res/blank.ico
 create mode 100644 src/core/stdmsg/res/bold.ico
 create mode 100644 src/core/stdmsg/res/close.ico
 create mode 100644 src/core/stdmsg/res/color.ico
 create mode 100644 src/core/stdmsg/res/excl.ico
 create mode 100644 src/core/stdmsg/res/filter.ico
 create mode 100644 src/core/stdmsg/res/filter2.ico
 create mode 100644 src/core/stdmsg/res/highlight.ico
 create mode 100644 src/core/stdmsg/res/history.ico
 create mode 100644 src/core/stdmsg/res/info.ico
 create mode 100644 src/core/stdmsg/res/italics.ico
 create mode 100644 src/core/stdmsg/res/join.ico
 create mode 100644 src/core/stdmsg/res/kick.ico
 create mode 100644 src/core/stdmsg/res/message.ico
 create mode 100644 src/core/stdmsg/res/messageout.ico
 create mode 100644 src/core/stdmsg/res/nick.ico
 create mode 100644 src/core/stdmsg/res/nicklist.ico
 create mode 100644 src/core/stdmsg/res/nicklist2.ico
 create mode 100644 src/core/stdmsg/res/overlay.ico
 create mode 100644 src/core/stdmsg/res/part.ico
 create mode 100644 src/core/stdmsg/res/quit.ico
 create mode 100644 src/core/stdmsg/res/removestatus.ico
 create mode 100644 src/core/stdmsg/res/smiley.ico
 create mode 100644 src/core/stdmsg/res/smileyc.ico
 create mode 100644 src/core/stdmsg/res/tag1.ico
 create mode 100644 src/core/stdmsg/res/tag2.ico
 create mode 100644 src/core/stdmsg/res/topic.ico
 create mode 100644 src/core/stdmsg/res/topicbut.ico
 create mode 100644 src/core/stdmsg/res/underline.ico
 create mode 100644 src/core/stdmsg/res/window.ico
 create mode 100644 src/core/stdmsg/src/chat_manager.cpp
 create mode 100644 src/core/stdmsg/src/chat_options.cpp
 create mode 100644 src/core/stdmsg/src/chat_util.cpp
 create mode 100644 src/core/stdmsg/src/chat_window.cpp

(limited to 'src/core')

diff --git a/src/core/stdmsg/res/1.ico b/src/core/stdmsg/res/1.ico
new file mode 100644
index 0000000000..61fa00e172
Binary files /dev/null and b/src/core/stdmsg/res/1.ico differ
diff --git a/src/core/stdmsg/res/2.ico b/src/core/stdmsg/res/2.ico
new file mode 100644
index 0000000000..5c1dc06fbc
Binary files /dev/null and b/src/core/stdmsg/res/2.ico differ
diff --git a/src/core/stdmsg/res/3.ico b/src/core/stdmsg/res/3.ico
new file mode 100644
index 0000000000..f103719b68
Binary files /dev/null and b/src/core/stdmsg/res/3.ico differ
diff --git a/src/core/stdmsg/res/4.ico b/src/core/stdmsg/res/4.ico
new file mode 100644
index 0000000000..47d8f35fe2
Binary files /dev/null and b/src/core/stdmsg/res/4.ico differ
diff --git a/src/core/stdmsg/res/5.ico b/src/core/stdmsg/res/5.ico
new file mode 100644
index 0000000000..7008463787
Binary files /dev/null and b/src/core/stdmsg/res/5.ico differ
diff --git a/src/core/stdmsg/res/6.ico b/src/core/stdmsg/res/6.ico
new file mode 100644
index 0000000000..8a681faeb7
Binary files /dev/null and b/src/core/stdmsg/res/6.ico differ
diff --git a/src/core/stdmsg/res/action.ico b/src/core/stdmsg/res/action.ico
new file mode 100644
index 0000000000..ec7694b075
Binary files /dev/null and b/src/core/stdmsg/res/action.ico differ
diff --git a/src/core/stdmsg/res/addmode.ico b/src/core/stdmsg/res/addmode.ico
new file mode 100644
index 0000000000..fcfa03a6ad
Binary files /dev/null and b/src/core/stdmsg/res/addmode.ico differ
diff --git a/src/core/stdmsg/res/bkgcolor.ico b/src/core/stdmsg/res/bkgcolor.ico
new file mode 100644
index 0000000000..8ff040dd1b
Binary files /dev/null and b/src/core/stdmsg/res/bkgcolor.ico differ
diff --git a/src/core/stdmsg/res/blank.ico b/src/core/stdmsg/res/blank.ico
new file mode 100644
index 0000000000..d8a5b3d80d
Binary files /dev/null and b/src/core/stdmsg/res/blank.ico differ
diff --git a/src/core/stdmsg/res/bold.ico b/src/core/stdmsg/res/bold.ico
new file mode 100644
index 0000000000..63810159f9
Binary files /dev/null and b/src/core/stdmsg/res/bold.ico differ
diff --git a/src/core/stdmsg/res/close.ico b/src/core/stdmsg/res/close.ico
new file mode 100644
index 0000000000..6facfcffeb
Binary files /dev/null and b/src/core/stdmsg/res/close.ico differ
diff --git a/src/core/stdmsg/res/color.ico b/src/core/stdmsg/res/color.ico
new file mode 100644
index 0000000000..b75015154a
Binary files /dev/null and b/src/core/stdmsg/res/color.ico differ
diff --git a/src/core/stdmsg/res/excl.ico b/src/core/stdmsg/res/excl.ico
new file mode 100644
index 0000000000..7cb1691367
Binary files /dev/null and b/src/core/stdmsg/res/excl.ico differ
diff --git a/src/core/stdmsg/res/filter.ico b/src/core/stdmsg/res/filter.ico
new file mode 100644
index 0000000000..a2edc9e60c
Binary files /dev/null and b/src/core/stdmsg/res/filter.ico differ
diff --git a/src/core/stdmsg/res/filter2.ico b/src/core/stdmsg/res/filter2.ico
new file mode 100644
index 0000000000..3adc966a6c
Binary files /dev/null and b/src/core/stdmsg/res/filter2.ico differ
diff --git a/src/core/stdmsg/res/highlight.ico b/src/core/stdmsg/res/highlight.ico
new file mode 100644
index 0000000000..850afb2f46
Binary files /dev/null and b/src/core/stdmsg/res/highlight.ico differ
diff --git a/src/core/stdmsg/res/history.ico b/src/core/stdmsg/res/history.ico
new file mode 100644
index 0000000000..10bbd7aaf7
Binary files /dev/null and b/src/core/stdmsg/res/history.ico differ
diff --git a/src/core/stdmsg/res/info.ico b/src/core/stdmsg/res/info.ico
new file mode 100644
index 0000000000..419bb1adb5
Binary files /dev/null and b/src/core/stdmsg/res/info.ico differ
diff --git a/src/core/stdmsg/res/italics.ico b/src/core/stdmsg/res/italics.ico
new file mode 100644
index 0000000000..42d3fea61b
Binary files /dev/null and b/src/core/stdmsg/res/italics.ico differ
diff --git a/src/core/stdmsg/res/join.ico b/src/core/stdmsg/res/join.ico
new file mode 100644
index 0000000000..1b6176d0ad
Binary files /dev/null and b/src/core/stdmsg/res/join.ico differ
diff --git a/src/core/stdmsg/res/kick.ico b/src/core/stdmsg/res/kick.ico
new file mode 100644
index 0000000000..f8dee5c356
Binary files /dev/null and b/src/core/stdmsg/res/kick.ico differ
diff --git a/src/core/stdmsg/res/message.ico b/src/core/stdmsg/res/message.ico
new file mode 100644
index 0000000000..7d98eb94e3
Binary files /dev/null and b/src/core/stdmsg/res/message.ico differ
diff --git a/src/core/stdmsg/res/messageout.ico b/src/core/stdmsg/res/messageout.ico
new file mode 100644
index 0000000000..83c8e296e5
Binary files /dev/null and b/src/core/stdmsg/res/messageout.ico differ
diff --git a/src/core/stdmsg/res/nick.ico b/src/core/stdmsg/res/nick.ico
new file mode 100644
index 0000000000..27d9fea978
Binary files /dev/null and b/src/core/stdmsg/res/nick.ico differ
diff --git a/src/core/stdmsg/res/nicklist.ico b/src/core/stdmsg/res/nicklist.ico
new file mode 100644
index 0000000000..460e7890a2
Binary files /dev/null and b/src/core/stdmsg/res/nicklist.ico differ
diff --git a/src/core/stdmsg/res/nicklist2.ico b/src/core/stdmsg/res/nicklist2.ico
new file mode 100644
index 0000000000..236787629b
Binary files /dev/null and b/src/core/stdmsg/res/nicklist2.ico differ
diff --git a/src/core/stdmsg/res/overlay.ico b/src/core/stdmsg/res/overlay.ico
new file mode 100644
index 0000000000..dc9738d792
Binary files /dev/null and b/src/core/stdmsg/res/overlay.ico differ
diff --git a/src/core/stdmsg/res/part.ico b/src/core/stdmsg/res/part.ico
new file mode 100644
index 0000000000..5d6e5b90df
Binary files /dev/null and b/src/core/stdmsg/res/part.ico differ
diff --git a/src/core/stdmsg/res/quit.ico b/src/core/stdmsg/res/quit.ico
new file mode 100644
index 0000000000..febcbecb96
Binary files /dev/null and b/src/core/stdmsg/res/quit.ico differ
diff --git a/src/core/stdmsg/res/removestatus.ico b/src/core/stdmsg/res/removestatus.ico
new file mode 100644
index 0000000000..b772f6a9c6
Binary files /dev/null and b/src/core/stdmsg/res/removestatus.ico differ
diff --git a/src/core/stdmsg/res/resource.rc b/src/core/stdmsg/res/resource.rc
index 0d7d7d4593..9a0800758c 100644
--- a/src/core/stdmsg/res/resource.rc
+++ b/src/core/stdmsg/res/resource.rc
@@ -200,7 +200,149 @@ BEGIN
     LTEXT           "Load history events",IDC_TXT_TITLE2,0,52,369,8
 END
 
+IDD_CHANNEL DIALOGEX 0, 0, 252, 140
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | 
+	WS_MAXIMIZEBOX | WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | 
+	WS_THICKFRAME
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+    CONTROL         "",IDC_MESSAGE,"RichEdit50W",ES_MULTILINE | 
+					ES_AUTOVSCROLL | ES_NOHIDESEL | ES_WANTRETURN | 
+					ES_NUMBER | WS_VSCROLL | WS_TABSTOP,0,128,127,12,
+					WS_EX_STATICEDGE
+    PUSHBUTTON      "&Send",IDOK,136,126,115,14,WS_DISABLED
+    CONTROL         "&Emoticons",IDC_SMILEY,"MButtonClass",WS_DISABLED | WS_TABSTOP,112,108,15,13,0x18000000L
+    CONTROL         "&Bold",IDC_BOLD,"MButtonClass",WS_DISABLED | WS_TABSTOP,8,108,15,13,0x18000000L
+    CONTROL         "&Italic",IDC_ITALICS,"MButtonClass",WS_DISABLED | WS_TABSTOP,24,108,15,13,0x18000000L
+    CONTROL         "&Underline",IDC_UNDERLINE,"MButtonClass",WS_DISABLED | WS_TABSTOP,40,108,15,13,0x18000000L
+    CONTROL         "&Color",IDC_COLOR,"MButtonClass",WS_DISABLED | WS_TABSTOP,68,108,15,13,0x18000000L
+    CONTROL         "&Background color",IDC_BKGCOLOR,"MButtonClass",WS_DISABLED | WS_TABSTOP,84,108,15,13,0x18000000L
+    CONTROL         "&History",IDC_HISTORY,"MButtonClass",WS_TABSTOP,188,108,15,13,0x18000000L
+    CONTROL         "&Filter",IDC_FILTER,"MButtonClass",WS_TABSTOP,220,108,15,13,0x18000000L
+    CONTROL         "&Room settings",IDC_CHANMGR,"MButtonClass",WS_DISABLED | WS_TABSTOP,204,108,15,13,0x18000000L
+    CONTROL         "&Show/Hide nick list",IDC_SHOWNICKLIST,"MButtonClass",WS_TABSTOP,236,108,15,13,0x18000000L
+    CONTROL         "",IDC_LOG,"RichEdit50W",ES_MULTILINE | ES_AUTOVSCROLL | 
+                    ES_READONLY | ES_NUMBER | WS_VSCROLL | WS_TABSTOP,8,23,
+                    164,73,WS_EX_STATICEDGE
+    CONTROL         "",IDC_SPLITTERX,"Static",SS_ENHMETAFILE,172,23,10,73
+    CONTROL         "",IDC_SPLITTERY,"Static",SS_ENHMETAFILE,0,102,251,6
+    LISTBOX         IDC_LIST,182,23,69,73,LBS_OWNERDRAWFIXED | 
+                    LBS_NOINTEGRALHEIGHT | LBS_NODATA | NOT WS_BORDER | 
+                    WS_VSCROLL | WS_TABSTOP,WS_EX_STATICEDGE
+    CONTROL         "Tab1",IDC_TAB,"SysTabControl32",TCS_MULTILINE,0,0,231,102
+    CONTROL         "",IDC_CLOSE,"MButtonClass",WS_TABSTOP,236,2,15,13,0x18000000L
+END
+
+IDD_FILTER DIALOGEX 0, 0, 83, 125
+STYLE DS_FIXEDSYS | DS_SETFONT | WS_POPUP | WS_BORDER
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+    CTEXT           "Show these events only:",IDC_TEXTO,0,0,83,13,
+                    SS_CENTERIMAGE
+    LTEXT           "",IDC_STATIC,0,13,83,112
+    CONTROL         "Actions",IDC_1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,13,73,10
+    CONTROL         "Messages",IDC_2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,23,73,10
+    CONTROL         "Nick changes",IDC_3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,33,73,10
+    CONTROL         "Users joining",IDC_4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,43,73,10
+    CONTROL         "Users leaving",IDC_5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,53,73,10
+    CONTROL         "Topic changes",IDC_6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,63,73,10
+    CONTROL         "Status changes",IDC_7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,73,73,10
+    CONTROL         "Information",IDC_8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,83,73,10
+    CONTROL         "Disconnects",IDC_9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,93,73,10
+    CONTROL         "User kicks",IDC_10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,103,73,10
+    CONTROL         "Notices",IDC_11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,113,73,10
+END
+
+IDD_OPTIONS1 DIALOGEX 0, 0, 300, 230
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+    CONTROL         "Tree1",IDC_CHECKBOXES,"SysTreeView32",TVS_HASBUTTONS | 
+                    TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | 
+                    TVS_FULLROWSELECT | WS_BORDER | WS_TABSTOP,10,12,280,205
+    GROUPBOX        "Options",IDC_STATIC,0,0,300,227
+END
+
+IDD_OPTIONS2 DIALOGEX 0, 0, 300, 200
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+    GROUPBOX        "Log options",IDC_STATIC,1,1,294,134
+    EDITTEXT        IDC_OUTSTAMP,10,19,35,14,ES_AUTOHSCROLL
+    EDITTEXT        IDC_INSTAMP,60,19,35,14,ES_AUTOHSCROLL
+    LTEXT           "Log timestamp",IDC_STATIC,205,11,81,8
+    EDITTEXT        IDC_LOGTIMESTAMP,205,19,81,14,ES_AUTOHSCROLL
+    LTEXT           "Timestamp",IDC_STATIC,119,11,78,8
+    EDITTEXT        IDC_TIMESTAMP,118,19,81,14,ES_AUTOHSCROLL
+    LTEXT           "Other name",IDC_STATIC,60,11,57,8
+    LTEXT           "Your name",IDC_STATIC,10,11,50,8
+    CONTROL         "Enable highlighting",IDC_HIGHLIGHT,"Button",
+					BS_AUTOCHECKBOX | WS_TABSTOP,10,46,118,10
+    LTEXT           "Limit log text to (events):",IDC_STATIC,133,46,112,8
+    LTEXT           "Trim to (KB)",IDC_STATIC,248,104,38,8
+    EDITTEXT        IDC_LOGLIMIT,248,44,38,14,ES_RIGHT | ES_AUTOHSCROLL | 
+					ES_NUMBER
+    CONTROL         "Spin1",IDC_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | 
+					UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | 
+					UDS_NOTHOUSANDS | UDS_HOTTRACK,275,43,11,14
+    LTEXT           "Words to highlight (wildcards allowed)",IDC_STATIC,10,
+					58,240,8
+    EDITTEXT        IDC_HIGHLIGHTWORDS,10,67,276,14,ES_AUTOHSCROLL
+    CONTROL         "",IDC_STATIC,"Static",SS_ETCHEDHORZ,10,86,275,1
+    CONTROL         "Enable logging to disk",IDC_LOGGING,"Button",
+					BS_AUTOCHECKBOX | WS_TABSTOP,10,94,211,10
+    LTEXT           "Log directory",IDC_STATIC,10,106,211,8
+    EDITTEXT        IDC_LOGDIRECTORY,10,114,211,14,ES_AUTOHSCROLL | 
+					ES_READONLY
+    PUSHBUTTON      "...",IDC_FONTCHOOSE,221,114,19,14
+    EDITTEXT        IDC_LIMIT,248,114,38,14,ES_RIGHT | ES_AUTOHSCROLL | 
+					ES_NUMBER
+    CONTROL         "Spin1",IDC_SPIN3,"msctls_updown32",UDS_SETBUDDYINT | 
+					UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | 
+					UDS_NOTHOUSANDS | UDS_HOTTRACK,275,112,11,14
+    GROUPBOX        "Other",IDC_STATIC,1,145,294,53
+    LTEXT           "Add new rooms to group:",IDC_STATIC,11,159,132,8
+    EDITTEXT        IDC_GROUP,158,158,49,14,ES_AUTOHSCROLL
+    LTEXT           "Nick list row distance (pixels):",IDC_STATIC,11,180,132,
+					8
+    EDITTEXT        IDC_NICKROW2,158,178,29,14,ES_RIGHT | ES_AUTOHSCROLL | 
+					ES_NUMBER
+    CONTROL         "",IDC_SPIN4,"msctls_updown32",UDS_SETBUDDYINT | 
+					UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | 
+					UDS_NOTHOUSANDS | UDS_HOTTRACK,183,178,11,14
+END
 
+IDD_OPTIONSPOPUP DIALOGEX 0, 0, 277, 177
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+    CONTROL         "Use same style as in the message log",IDC_RADIO1,"Button",
+					BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,33,29,225,10
+    CONTROL         "Use default colors",IDC_RADIO2,"Button",
+					BS_AUTORADIOBUTTON,33,62,217,10
+    CONTROL         "Use custom colors",IDC_RADIO3,"Button",
+					BS_AUTORADIOBUTTON,33,95,105,10
+    CONTROL         "Custom1",IDC_TEXT,"ColourPicker",WS_TABSTOP,141,93,50,
+					14,0x18000000L
+    CONTROL         "Custom2",IDC_BKG,"ColourPicker",WS_TABSTOP,201,93,50,14,
+					0x18000000L
+    EDITTEXT        IDC_TIMEOUT,132,134,38,14,ES_RIGHT | ES_AUTOHSCROLL | 
+					ES_NUMBER
+    CONTROL         "Spin1",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | 
+					UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | 
+					UDS_NOTHOUSANDS | UDS_HOTTRACK,169,135,11,14
+    GROUPBOX        "Popups for the Chat plugin",IDC_STATIC,0,0,277,174
+    LTEXT           "Timeout (s)",IDC_STATIC,33,138,92,8
+    LTEXT           "Text",IDC_STATIC,141,83,49,8
+    LTEXT           "Background",IDC_STATIC,201,83,67,8
+    LTEXT           "(Setting timeout to 0 means default setting and -1 means indefinite time)",
+					IDC_STATIC,33,151,207,17
+END
+	
 /////////////////////////////////////////////////////////////////////////////
 //
 // DESIGNINFO
@@ -252,6 +394,71 @@ BEGIN
         TOPMARGIN, 7
         BOTTOMMARGIN, 245
     END
+    IDD_CHANNEL, DIALOG
+    BEGIN
+        RIGHTMARGIN, 251
+        VERTGUIDE, 8
+        VERTGUIDE, 172
+        VERTGUIDE, 182
+        VERTGUIDE, 237
+        HORZGUIDE, 8
+        HORZGUIDE, 23
+        HORZGUIDE, 70
+        HORZGUIDE, 96
+        HORZGUIDE, 102
+        HORZGUIDE, 108
+        HORZGUIDE, 121
+    END
+
+    IDD_FILTER, DIALOG
+    BEGIN
+        VERTGUIDE, 5
+        VERTGUIDE, 78
+        HORZGUIDE, 13
+        HORZGUIDE, 117
+    END
+    IDD_OPTIONS1, DIALOG
+    BEGIN
+        VERTGUIDE, 10
+        VERTGUIDE, 153
+        VERTGUIDE, 181
+        VERTGUIDE, 202
+        VERTGUIDE, 290
+        HORZGUIDE, 12
+        HORZGUIDE, 174
+        HORZGUIDE, 192
+        HORZGUIDE, 213
+    END
+
+    IDD_OPTIONS2, DIALOG
+    BEGIN
+        LEFTMARGIN, 1
+        RIGHTMARGIN, 295
+        VERTGUIDE, 10
+        VERTGUIDE, 60
+        VERTGUIDE, 144
+        VERTGUIDE, 158
+        VERTGUIDE, 183
+        VERTGUIDE, 221
+        VERTGUIDE, 286
+        TOPMARGIN, 1
+        BOTTOMMARGIN, 198
+        HORZGUIDE, 108
+        HORZGUIDE, 126
+        HORZGUIDE, 146
+        HORZGUIDE, 158
+        HORZGUIDE, 174
+    END
+
+    IDD_OPTIONSPOPUP, DIALOG
+    BEGIN
+        VERTGUIDE, 33
+        VERTGUIDE, 157
+        VERTGUIDE, 201
+        HORZGUIDE, 49
+        HORZGUIDE, 81
+        HORZGUIDE, 174
+    END
 END
 #endif    // APSTUDIO_INVOKED
 
@@ -294,6 +501,44 @@ END
 IDI_INCOMING            ICON                    "incoming.ico"
 IDI_OUTGOING            ICON                    "outgoing.ico"
 IDI_NOTICE              ICON                    "notice.ico"
+IDI_TAG1                ICON                    "tag1.ico"
+IDI_TAG2                ICON                    "tag2.ico"
+IDI_BUNDERLINE          ICON                    "underline.ico"
+IDI_BBOLD               ICON                    "bold.ico"
+IDI_BITALICS            ICON                    "italics.ico"
+IDI_BSMILEY             ICON                    "smiley.ico"
+IDI_JOIN                ICON                    "join.ico"
+IDI_TOPIC               ICON                    "topic.ico"
+IDI_ADDSTATUS           ICON                    "addmode.ico"
+IDI_INFO                ICON                    "info.ico"
+IDI_KICK                ICON                    "kick.ico"
+IDI_MESSAGE             ICON                    "message.ico"
+IDI_NICK                ICON                    "nick.ico"
+IDI_EXCL                ICON                    "excl.ico"
+IDI_PART                ICON                    "part.ico"
+IDI_QUIT                ICON                    "quit.ico"
+IDI_REMSTATUS           ICON                    "removestatus.ico"
+IDI_HIGHLIGHT           ICON                    "highlight.ico"
+IDI_MESSAGEOUT          ICON                    "messageout.ico"
+IDI_ACTION              ICON                    "action.ico"
+IDI_TOPICBUT            ICON                    "topicbut.ico"
+IDI_BKGCOLOR            ICON                    "bkgcolor.ico"
+IDI_CHANMGR             ICON                    "window.ico"
+IDI_COLOR               ICON                    "color.ico"
+IDI_FILTER              ICON                    "filter.ico"
+IDI_HISTORY             ICON                    "history.ico"
+IDI_NICKLIST            ICON                    "nicklist.ico"
+IDI_BLANK               ICON                    "blank.ico"
+IDI_STATUS3             ICON                    "4.ico"
+IDI_STATUS2             ICON                    "3.ico"
+IDI_STATUS4             ICON                    "5.ico"
+IDI_STATUS1             ICON                    "2.ico"
+IDI_STATUS0             ICON                    "1.ico"
+IDI_STATUS5             ICON                    "6.ico"
+IDI_CLOSE               ICON                    "close.ico"
+IDI_OVERLAY             ICON                    "overlay.ico"
+IDI_NICKLIST2           ICON                    "nicklist2.ico"
+IDI_FILTER2             ICON                    "filter2.ico"
 
 /////////////////////////////////////////////////////////////////////////////
 //
@@ -309,6 +554,52 @@ IDC_DROPUSER            CURSOR                  "dropuser.cur"
 // Menu
 //
 
+IDR_MENU MENU 
+BEGIN
+    POPUP "List"
+    BEGIN
+        MENUITEM "&Message",                    ID_MESS
+    END
+    POPUP "Log"
+    BEGIN
+        MENUITEM "Clear lo&g",                  ID_CLEARLOG
+        MENUITEM SEPARATOR
+        MENUITEM "Co&py all",                   ID_COPYALL
+        MENUITEM SEPARATOR
+        POPUP "Word lookup", GRAYED
+        BEGIN
+            MENUITEM "Google",                      ID_SEARCH_GOOGLE
+            MENUITEM "Wikipedia",                   ID_SEARCH_WIKIPEDIA
+        END
+    END
+    POPUP "Link"
+    BEGIN
+        MENUITEM "Open a &new browser window",  ID_NEW
+        MENUITEM "&Open in current browser window", ID_CURR
+        MENUITEM "&Copy link",                  ID_COPY
+    END
+    MENUITEM "",                            65535
+    POPUP "Message"
+    BEGIN
+        MENUITEM "Undo",                        ID_MESSAGE_UNDO, GRAYED
+        MENUITEM "Redo",                        ID_MESSAGE_REDO, GRAYED
+        MENUITEM SEPARATOR
+        MENUITEM "Copy",                        ID_MESSAGE_COPY, GRAYED
+        MENUITEM "Cut",                         ID_MESSAGE_CUT, GRAYED
+        MENUITEM "Paste",                       ID_MESSAGE_PASTE
+        MENUITEM "Select all",                  ID_MESSAGE_SELECTALL
+        MENUITEM SEPARATOR
+        MENUITEM "Clear",                       ID_MESSAGE_CLEAR
+    END
+    POPUP "Tabs"
+    BEGIN
+        MENUITEM "&Close tab",                  ID_CLOSE
+        MENUITEM "C&lose other tabs",           ID_CLOSEOTHER
+        MENUITEM SEPARATOR
+        MENUITEM "&Open at this position",      ID_LOCKPOSITION
+    END
+END
+
 IDR_CONTEXT MENU
 BEGIN
     POPUP "Log"
diff --git a/src/core/stdmsg/res/smiley.ico b/src/core/stdmsg/res/smiley.ico
new file mode 100644
index 0000000000..1062805741
Binary files /dev/null and b/src/core/stdmsg/res/smiley.ico differ
diff --git a/src/core/stdmsg/res/smileyc.ico b/src/core/stdmsg/res/smileyc.ico
new file mode 100644
index 0000000000..2290e97fe4
Binary files /dev/null and b/src/core/stdmsg/res/smileyc.ico differ
diff --git a/src/core/stdmsg/res/tag1.ico b/src/core/stdmsg/res/tag1.ico
new file mode 100644
index 0000000000..4db0312d9d
Binary files /dev/null and b/src/core/stdmsg/res/tag1.ico differ
diff --git a/src/core/stdmsg/res/tag2.ico b/src/core/stdmsg/res/tag2.ico
new file mode 100644
index 0000000000..5b5197a9cd
Binary files /dev/null and b/src/core/stdmsg/res/tag2.ico differ
diff --git a/src/core/stdmsg/res/topic.ico b/src/core/stdmsg/res/topic.ico
new file mode 100644
index 0000000000..7d7fe6d402
Binary files /dev/null and b/src/core/stdmsg/res/topic.ico differ
diff --git a/src/core/stdmsg/res/topicbut.ico b/src/core/stdmsg/res/topicbut.ico
new file mode 100644
index 0000000000..7c6b07c71a
Binary files /dev/null and b/src/core/stdmsg/res/topicbut.ico differ
diff --git a/src/core/stdmsg/res/underline.ico b/src/core/stdmsg/res/underline.ico
new file mode 100644
index 0000000000..646d58456d
Binary files /dev/null and b/src/core/stdmsg/res/underline.ico differ
diff --git a/src/core/stdmsg/res/window.ico b/src/core/stdmsg/res/window.ico
new file mode 100644
index 0000000000..d317845d55
Binary files /dev/null and b/src/core/stdmsg/res/window.ico differ
diff --git a/src/core/stdmsg/src/chat_manager.cpp b/src/core/stdmsg/src/chat_manager.cpp
new file mode 100644
index 0000000000..eabc191afc
--- /dev/null
+++ b/src/core/stdmsg/src/chat_manager.cpp
@@ -0,0 +1,474 @@
+/*
+Chat module plugin for Miranda IM
+
+Copyright 2000-12 Miranda IM, 2012-16 Miranda NG project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+TABLIST *g_TabList = 0;
+
+BOOL SM_SetTabbedWindowHwnd(SESSION_INFO *si, HWND hwnd)
+{
+	for (SESSION_INFO *p = pci->wndList; p != NULL; p = p->next) {
+		if (si && si == p)
+			p->hWnd = hwnd;
+		else
+			p->hWnd = NULL;
+	}
+	return TRUE;
+}
+
+SESSION_INFO* SM_GetPrevWindow(SESSION_INFO *si)
+{
+	if (!si)
+		return NULL;
+
+	BOOL bFound = FALSE;
+	SESSION_INFO *pTemp = pci->wndList;
+	while (pTemp != NULL) {
+		if (si == pTemp) {
+			if (bFound)
+				return NULL;
+			else
+				bFound = TRUE;
+		}
+		else if (bFound == TRUE && pTemp->hWnd)
+			return pTemp;
+		pTemp = pTemp->next;
+		if (pTemp == NULL && bFound)
+			pTemp = pci->wndList;
+	}
+	return NULL;
+}
+
+SESSION_INFO* SM_GetNextWindow(SESSION_INFO *si)
+{
+	if (!si)
+		return NULL;
+
+	SESSION_INFO *pTemp = pci->wndList, *pLast = NULL;
+	while (pTemp != NULL) {
+		if (si == pTemp) {
+			if (pLast) {
+				if (pLast != pTemp)
+					return pLast;
+				else
+					return NULL;
+			}
+		}
+		if (pTemp->hWnd)
+			pLast = pTemp;
+		pTemp = pTemp->next;
+		if (pTemp == NULL)
+			pTemp = pci->wndList;
+	}
+	return NULL;
+}
+
+//---------------------------------------------------
+//		Tab list manager functions
+//
+//		Necessary to keep track of what tabs should
+//		be restored
+//---------------------------------------------------
+
+BOOL TabM_AddTab(const wchar_t *pszID, const char* pszModule)
+{
+	TABLIST *node = NULL;
+	if (!pszID || !pszModule)
+		return FALSE;
+
+	node = (TABLIST*)mir_alloc(sizeof(TABLIST));
+	memset(node, 0, sizeof(TABLIST));
+	node->pszID = mir_wstrdup(pszID);
+	node->pszModule = mir_strdup(pszModule);
+
+	if (g_TabList == NULL) { // list is empty
+		g_TabList = node;
+		node->next = NULL;
+	}
+	else {
+		node->next = g_TabList;
+		g_TabList = node;
+	}
+	return TRUE;
+}
+
+BOOL TabM_RemoveAll(void)
+{
+	while (g_TabList != NULL) {
+		TABLIST *pLast = g_TabList->next;
+		mir_free(g_TabList->pszModule);
+		mir_free(g_TabList->pszID);
+		mir_free(g_TabList);
+		g_TabList = pLast;
+	}
+	g_TabList = NULL;
+	return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CHAT_MANAGER *pci, saveCI;
+
+SESSION_INFO g_TabSession;
+HMENU g_hMenu = NULL;
+
+BOOL SmileyAddInstalled = FALSE, PopupInstalled = FALSE;
+HIMAGELIST hIconsList;
+
+GlobalLogSettings g_Settings;
+
+static int OnShutdown(WPARAM, LPARAM)
+{
+	for (SESSION_INFO *si = pci->wndList; si; si = si->next)
+		SendMessage(si->hWnd, WM_CLOSE, 0, 0);
+
+	TabM_RemoveAll();
+	ImageList_Destroy(hIconsList);
+	return 0;
+}
+
+static void OnCreateModule(MODULEINFO *mi)
+{
+	mi->OnlineIconIndex = ImageList_AddIcon(hIconsList, Skin_LoadProtoIcon(mi->pszModule, ID_STATUS_ONLINE));
+	mi->hOnlineIcon = ImageList_GetIcon(hIconsList, mi->OnlineIconIndex, ILD_TRANSPARENT);
+	mi->hOnlineTalkIcon = ImageList_GetIcon(hIconsList, mi->OnlineIconIndex, ILD_TRANSPARENT | INDEXTOOVERLAYMASK(1));
+	ImageList_AddIcon(hIconsList, mi->hOnlineTalkIcon);
+
+	mi->OfflineIconIndex = ImageList_AddIcon(hIconsList, Skin_LoadProtoIcon(mi->pszModule, ID_STATUS_OFFLINE));
+	mi->hOfflineIcon = ImageList_GetIcon(hIconsList, mi->OfflineIconIndex, ILD_TRANSPARENT);
+	mi->hOfflineTalkIcon = ImageList_GetIcon(hIconsList, mi->OfflineIconIndex, ILD_TRANSPARENT | INDEXTOOVERLAYMASK(1));
+	ImageList_AddIcon(hIconsList, mi->hOfflineTalkIcon);
+}
+
+static void OnAddLog(SESSION_INFO *si, int isOk)
+{
+	if (isOk && si->hWnd) {
+		g_TabSession.pLog = si->pLog;
+		g_TabSession.pLogEnd = si->pLogEnd;
+		SendMessage(si->hWnd, GC_ADDLOG, 0, 0);
+	}
+	else if (si->hWnd) {
+		g_TabSession.pLog = si->pLog;
+		g_TabSession.pLogEnd = si->pLogEnd;
+		SendMessage(si->hWnd, GC_REDRAWLOG2, 0, 0);
+	}
+}
+
+static void OnClearLog(SESSION_INFO *si)
+{
+	if (si->hWnd) {
+		g_TabSession.pLog = si->pLog;
+		g_TabSession.pLogEnd = si->pLogEnd;
+	}
+}
+
+static void OnDblClickSession(SESSION_INFO *si)
+{
+	if (g_Settings.bTabsEnable)
+		SendMessage(si->hWnd, GC_REMOVETAB, 1, (LPARAM)si);
+	else
+		PostMessage(si->hWnd, GC_CLOSEWINDOW, 0, 0);
+}
+
+static void OnRemoveSession(SESSION_INFO *si)
+{
+	if (!g_Settings.bTabsEnable) {
+		if (si->hWnd)
+			SendMessage(si->hWnd, GC_CONTROL_MSG, SESSION_TERMINATE, 0);
+	}
+	else if (g_TabSession.hWnd)
+		SendMessage(g_TabSession.hWnd, GC_REMOVETAB, 1, (LPARAM)si);
+
+	if (si->hWnd)
+		g_TabSession.nUsersInNicklist = 0;
+}
+
+static void OnRenameSession(SESSION_INFO *si)
+{
+	if (g_TabSession.hWnd && g_Settings.bTabsEnable) {
+		g_TabSession.ptszName = si->ptszName;
+		SendMessage(g_TabSession.hWnd, GC_SESSIONNAMECHANGE, 0, (LPARAM)si);
+	}
+}
+
+static void OnReplaceSession(SESSION_INFO *si)
+{
+	if (si->hWnd)
+		g_TabSession.nUsersInNicklist = 0;
+
+	if (!g_Settings.bTabsEnable) {
+		if (si->hWnd)
+			RedrawWindow(GetDlgItem(si->hWnd, IDC_LIST), NULL, NULL, RDW_INVALIDATE);
+	}
+	else if (g_TabSession.hWnd)
+		RedrawWindow(GetDlgItem(g_TabSession.hWnd, IDC_LIST), NULL, NULL, RDW_INVALIDATE);
+}
+
+static void OnOfflineSession(SESSION_INFO *si)
+{
+	if (si->hWnd) {
+		g_TabSession.nUsersInNicklist = 0;
+		if (g_Settings.bTabsEnable)
+			g_TabSession.pUsers = 0;
+	}
+}
+
+static void OnEventBroadcast(SESSION_INFO *si, GCEVENT *gce)
+{
+	if (pci->SM_AddEvent(si->ptszID, si->pszModule, gce, FALSE) && si->hWnd && si->bInitDone) {
+		g_TabSession.pLog = si->pLog;
+		g_TabSession.pLogEnd = si->pLogEnd;
+		SendMessage(si->hWnd, GC_ADDLOG, 0, 0);
+	}
+	else if (si->hWnd && si->bInitDone) {
+		g_TabSession.pLog = si->pLog;
+		g_TabSession.pLogEnd = si->pLogEnd;
+		SendMessage(si->hWnd, GC_REDRAWLOG2, 0, 0);
+	}
+}
+
+static void OnSetStatusBar(SESSION_INFO *si)
+{
+	if (si->hWnd) {
+		g_TabSession.ptszStatusbarText = si->ptszStatusbarText;
+		SendMessage(si->hWnd, GC_UPDATESTATUSBAR, 0, 0);
+	}
+}
+
+static void OnAddUser(SESSION_INFO *si, USERINFO*)
+{
+	if (si->hWnd)
+		g_TabSession.nUsersInNicklist++;
+}
+
+static void OnNewUser(SESSION_INFO *si, USERINFO*)
+{
+	if (si->hWnd) {
+		g_TabSession.pUsers = si->pUsers;
+		SendMessage(si->hWnd, GC_UPDATENICKLIST, 0, 0);
+	}
+}
+
+static void OnRemoveUser(SESSION_INFO *si, USERINFO*)
+{
+	if (si->hWnd) {
+		g_TabSession.pUsers = si->pUsers;
+		g_TabSession.nUsersInNicklist--;
+	}
+}
+
+static void OnAddStatus(SESSION_INFO *si, STATUSINFO*)
+{
+	if (g_Settings.bTabsEnable && si->hWnd)
+		g_TabSession.pStatuses = si->pStatuses;
+}
+
+static void OnSetStatus(SESSION_INFO *si, int wStatus)
+{
+	if (g_Settings.bTabsEnable) {
+		if (si->hWnd)
+			g_TabSession.wStatus = wStatus;
+		if (g_TabSession.hWnd)
+			PostMessage(g_TabSession.hWnd, GC_FIXTABICONS, 0, (LPARAM)si);
+	}
+}
+
+static void OnSetTopic(SESSION_INFO *si)
+{
+	if (si->hWnd)
+		g_TabSession.ptszTopic = si->ptszTopic;
+}
+
+static void OnFlashHighlight(SESSION_INFO *si, int bInactive)
+{
+	if (!bInactive)
+		return;
+
+	if (!g_Settings.bTabsEnable && si->hWnd && g_Settings.bFlashWindowHighlight)
+		SetTimer(si->hWnd, TIMERID_FLASHWND, 900, NULL);
+	if (g_Settings.bTabsEnable && g_TabSession.hWnd)
+		SendMessage(g_TabSession.hWnd, GC_SETMESSAGEHIGHLIGHT, 0, (LPARAM)si);
+}
+
+static void OnFlashWindow(SESSION_INFO *si, int bInactive)
+{
+	if (!bInactive)
+		return;
+
+	if (!g_Settings.bTabsEnable && si->hWnd && g_Settings.bFlashWindow)
+		SetTimer(si->hWnd, TIMERID_FLASHWND, 900, NULL);
+	if (g_Settings.bTabsEnable && g_TabSession.hWnd)
+		SendMessage(g_TabSession.hWnd, GC_SETTABHIGHLIGHT, 0, (LPARAM)si);
+}
+
+static BOOL DoTrayIcon(SESSION_INFO *si, GCEVENT *gce)
+{
+	if (gce->pDest->iType & g_Settings.dwTrayIconFlags)
+		return saveCI.DoTrayIcon(si, gce);
+	return TRUE;
+}
+
+static BOOL DoPopup(SESSION_INFO *si, GCEVENT *gce)
+{
+	if (gce->pDest->iType & g_Settings.dwPopupFlags)
+		return saveCI.DoPopup(si, gce);
+	return TRUE;
+}
+
+static void OnLoadSettings()
+{
+	if (g_Settings.MessageAreaFont)
+		DeleteObject(g_Settings.MessageAreaFont);
+
+	LOGFONT lf;
+	LoadMessageFont(&lf, &g_Settings.MessageAreaColor);
+	g_Settings.MessageAreaFont = CreateFontIndirect(&lf);
+
+	g_Settings.iX = db_get_dw(NULL, CHAT_MODULE, "roomx", -1);
+	g_Settings.iY = db_get_dw(NULL, CHAT_MODULE, "roomy", -1);
+
+	g_Settings.bTabsEnable = db_get_b(NULL, CHAT_MODULE, "Tabs", 1) != 0;
+	g_Settings.TabRestore = db_get_b(NULL, CHAT_MODULE, "TabRestore", 0) != 0;
+	g_Settings.TabsAtBottom = db_get_b(NULL, CHAT_MODULE, "TabBottom", 0) != 0;
+	g_Settings.TabCloseOnDblClick = db_get_b(NULL, CHAT_MODULE, "TabCloseOnDblClick", 0) != 0;
+}
+
+static void RegisterFonts()
+{
+	ColourIDW colourid = { sizeof(colourid) };
+	strncpy(colourid.dbSettingsGroup, CHAT_MODULE, sizeof(colourid.dbSettingsGroup));
+	wcsncpy(colourid.group, LPGENW("Chat module"), _countof(colourid.group));
+
+	strncpy(colourid.setting, "ColorLogBG", _countof(colourid.setting));
+	wcsncpy(colourid.name, LPGENW("Group chat log background"), _countof(colourid.name));
+	colourid.defcolour = GetSysColor(COLOR_WINDOW);
+	Colour_RegisterW(&colourid);
+
+	strncpy(colourid.setting, "ColorMessageBG", _countof(colourid.setting));
+	wcsncpy(colourid.name, LPGENW("Message background"), _countof(colourid.name));
+	colourid.defcolour = GetSysColor(COLOR_WINDOW);
+	Colour_RegisterW(&colourid);
+
+	strncpy(colourid.setting, "ColorNicklistBG", _countof(colourid.setting));
+	wcsncpy(colourid.name, LPGENW("Nick list background"), _countof(colourid.name));
+	colourid.defcolour = GetSysColor(COLOR_WINDOW);
+	Colour_RegisterW(&colourid);
+
+	strncpy(colourid.setting, "ColorNicklistLines", _countof(colourid.setting));
+	wcsncpy(colourid.name, LPGENW("Nick list lines"), _countof(colourid.name));
+	colourid.defcolour = GetSysColor(COLOR_INACTIVEBORDER);
+	Colour_RegisterW(&colourid);
+
+	strncpy(colourid.setting, "ColorNicklistSelectedBG", _countof(colourid.setting));
+	wcsncpy(colourid.name, LPGENW("Nick list background (selected)"), _countof(colourid.name));
+	colourid.defcolour = GetSysColor(COLOR_HIGHLIGHT);
+	Colour_RegisterW(&colourid);
+}
+
+static int OnCheckPlugins(WPARAM, LPARAM)
+{
+	SmileyAddInstalled = ServiceExists(MS_SMILEYADD_REPLACESMILEYS);
+	PopupInstalled = ServiceExists(MS_POPUP_ADDPOPUPT);
+	return 0;
+}
+
+static void TabsInit()
+{
+	memset(&g_TabSession, 0, sizeof(SESSION_INFO));
+	g_TabSession.iType = GCW_TABROOM;
+	g_TabSession.iSplitterX = g_Settings.iSplitterX;
+	g_TabSession.iSplitterY = g_Settings.iSplitterY;
+	g_TabSession.iLogFilterFlags = (int)db_get_dw(NULL, CHAT_MODULE, "FilterFlags", 0x03E0);
+	g_TabSession.bFilterEnabled = db_get_b(NULL, CHAT_MODULE, "FilterEnabled", 0);
+	g_TabSession.bNicklistEnabled = db_get_b(NULL, CHAT_MODULE, "ShowNicklist", 1);
+	g_TabSession.iFG = 4;
+	g_TabSession.bFGSet = TRUE;
+	g_TabSession.iBG = 2;
+	g_TabSession.bBGSet = TRUE;
+}
+
+void Load_ChatModule()
+{
+	AddIcons();
+	RegisterFonts();
+
+	CHAT_MANAGER_INITDATA data = { &g_Settings, sizeof(MODULEINFO), sizeof(SESSION_INFO), LPGENW("Chat module"), FONTMODE_SKIP };
+	pci = Chat_GetInterface(&data);
+	saveCI = *pci;
+
+	pci->OnAddUser = OnAddUser;
+	pci->OnNewUser = OnNewUser;
+	pci->OnRemoveUser = OnRemoveUser;
+
+	pci->OnAddStatus = OnAddStatus;
+	pci->OnSetStatus = OnSetStatus;
+	pci->OnSetTopic = OnSetTopic;
+
+	pci->OnAddLog = OnAddLog;
+	pci->OnClearLog = OnClearLog;
+
+	pci->OnCreateModule = OnCreateModule;
+	pci->OnOfflineSession = OnOfflineSession;
+	pci->OnRemoveSession = OnRemoveSession;
+	pci->OnRenameSession = OnRenameSession;
+	pci->OnReplaceSession = OnReplaceSession;
+	pci->OnDblClickSession = OnDblClickSession;
+
+	pci->OnEventBroadcast = OnEventBroadcast;
+	pci->OnLoadSettings = OnLoadSettings;
+	pci->OnSetStatusBar = OnSetStatusBar;
+	pci->OnFlashWindow = OnFlashWindow;
+	pci->OnFlashHighlight = OnFlashHighlight;
+	pci->ShowRoom = ShowRoom;
+
+	pci->DoPopup = DoPopup;
+	pci->DoTrayIcon = DoTrayIcon;
+	pci->ReloadSettings();
+
+	g_hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENU));
+
+	hIconsList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 0, 100);
+	ImageList_AddIcon(hIconsList, Skin_LoadIcon(SKINICON_EVENT_MESSAGE));
+	ImageList_AddIcon(hIconsList, LoadIconEx("overlay", FALSE));
+	ImageList_SetOverlayImage(hIconsList, 1, 1);
+
+	TabsInit();
+
+	HookEvent(ME_OPT_INITIALISE, OptionsInitialize);
+	HookEvent(ME_SYSTEM_SHUTDOWN, OnShutdown);
+	HookEvent(ME_SYSTEM_MODULELOAD, OnCheckPlugins);
+	HookEvent(ME_SYSTEM_MODULESLOADED, OnCheckPlugins);
+}
+
+void Unload_ChatModule()
+{
+	db_set_w(NULL, CHAT_MODULE, "SplitterX", (WORD)g_Settings.iSplitterX);
+	db_set_w(NULL, CHAT_MODULE, "SplitterY", (WORD)g_Settings.iSplitterY);
+	db_set_dw(NULL, CHAT_MODULE, "roomx", g_Settings.iX);
+	db_set_dw(NULL, CHAT_MODULE, "roomy", g_Settings.iY);
+	db_set_dw(NULL, CHAT_MODULE, "roomwidth", g_Settings.iWidth);
+	db_set_dw(NULL, CHAT_MODULE, "roomheight", g_Settings.iHeight);
+
+	if (g_Settings.MessageAreaFont)
+		DeleteObject(g_Settings.MessageAreaFont);
+	DestroyMenu(g_hMenu);
+}
diff --git a/src/core/stdmsg/src/chat_options.cpp b/src/core/stdmsg/src/chat_options.cpp
new file mode 100644
index 0000000000..f234bdbeed
--- /dev/null
+++ b/src/core/stdmsg/src/chat_options.cpp
@@ -0,0 +1,761 @@
+/*
+Chat module plugin for Miranda IM
+
+Copyright (C) 2003 J�rgen Persson
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "resource.h"
+#include "stdafx.h"
+
+struct branch_t
+{
+	const wchar_t* szDescr;
+	const char*  szDBName;
+	int          iMode;
+	BYTE         bDefault;
+};
+
+static const struct branch_t branch0[] = {
+	{ LPGENW("Use a tabbed interface"), "Tabs", 0, 1 },
+	{ LPGENW("Close tab on double click"), "TabCloseOnDblClick", 0, 0 },
+	{ LPGENW("Restore previously open tabs when showing the window"), "TabRestore", 0, 0 },
+	{ LPGENW("Show tabs at the bottom"), "TabBottom", 0, 0 },
+};
+
+static const struct branch_t branch1[] = {
+	{ LPGENW("Send message by pressing the 'Enter' key"), "SendOnEnter", 0, 1 },
+	{ LPGENW("Send message by pressing the 'Enter' key twice"), "SendOnDblEnter", 0, 0 },
+	{ LPGENW("Flash window when someone speaks"), "FlashWindow", 0, 0 },
+	{ LPGENW("Flash window when a word is highlighted"), "FlashWindowHighlight", 0, 1 },
+	{ LPGENW("Show list of users in the chat room"), "ShowNicklist", 0, 1 },
+	{ LPGENW("Show button for sending messages"), "ShowSend", 0, 0 },
+	{ LPGENW("Show buttons for controlling the chat room"), "ShowTopButtons", 0, 1 },
+	{ LPGENW("Show buttons for formatting the text you are typing"), "ShowFormatButtons", 0, 1 },
+	{ LPGENW("Show button menus when right clicking the buttons"), "RightClickFilter", 0, 0 },
+	{ LPGENW("Show new windows cascaded"), "CascadeWindows", 0, 1 },
+	{ LPGENW("Save the size and position of chat rooms"), "SavePosition", 0, 0 },
+	{ LPGENW("Show the topic of the room on your contact list (if supported)"), "TopicOnClist", 0, 0 },
+	{ LPGENW("Do not play sounds when the chat room is focused"), "SoundsFocus", 0, 0 },
+	{ LPGENW("Do not pop up the window when joining a chat room"), "PopupOnJoin", 0, 0 },
+	{ LPGENW("Toggle the visible state when double clicking in the contact list"), "ToggleVisibility", 0, 0 },
+	{ LPGENW("Show contact statuses if protocol supports them"), "ShowContactStatus", 0, 0 },
+	{ LPGENW("Display contact status icon before user role icon"), "ContactStatusFirst", 0, 0 },
+};
+
+static const struct branch_t branch2[] = {
+	{ LPGENW("Prefix all events with a timestamp"), "ShowTimeStamp", 0, 1 },
+	{ LPGENW("Only prefix with timestamp if it has changed"), "ShowTimeStampIfChanged", 0, 0 },
+	{ LPGENW("Timestamp has same color as the event"), "TimeStampEventColour", 0, 0 },
+	{ LPGENW("Indent the second line of a message"), "LogIndentEnabled", 0, 1 },
+	{ LPGENW("Limit user names in the message log to 20 characters"), "LogLimitNames", 0, 1 },
+	{ LPGENW("Add ':' to auto-completed user names"), "AddColonToAutoComplete", 0, 1 },
+	{ LPGENW("Strip colors from messages in the log"), "StripFormatting", 0, 0 },
+	{ LPGENW("Enable the 'event filter' for new rooms"), "FilterEnabled", 0, 0 }
+};
+
+static const struct branch_t branch3[] = {
+	{ LPGENW("Show topic changes"), "FilterFlags", GC_EVENT_TOPIC, 0 },
+	{ LPGENW("Show users joining"), "FilterFlags", GC_EVENT_JOIN, 0 },
+	{ LPGENW("Show users disconnecting"), "FilterFlags", GC_EVENT_QUIT, 0 },
+	{ LPGENW("Show messages"), "FilterFlags", GC_EVENT_MESSAGE, 1 },
+	{ LPGENW("Show actions"), "FilterFlags", GC_EVENT_ACTION, 1 },
+	{ LPGENW("Show users leaving"), "FilterFlags", GC_EVENT_PART, 0 },
+	{ LPGENW("Show users being kicked"), "FilterFlags", GC_EVENT_KICK, 1 },
+	{ LPGENW("Show notices"), "FilterFlags", GC_EVENT_NOTICE, 1 },
+	{ LPGENW("Show users changing name"), "FilterFlags", GC_EVENT_NICK, 0 },
+	{ LPGENW("Show information messages"), "FilterFlags", GC_EVENT_INFORMATION, 1 },
+	{ LPGENW("Show status changes of users"), "FilterFlags", GC_EVENT_ADDSTATUS, 0 },
+};
+
+static const struct branch_t branch4[] = {
+	{ LPGENW("Show icon for topic changes"), "IconFlags", GC_EVENT_TOPIC, 0 },
+	{ LPGENW("Show icon for users joining"), "IconFlags", GC_EVENT_JOIN, 1 },
+	{ LPGENW("Show icon for users disconnecting"), "IconFlags", GC_EVENT_QUIT, 0 },
+	{ LPGENW("Show icon for messages"), "IconFlags", GC_EVENT_MESSAGE, 0 },
+	{ LPGENW("Show icon for actions"), "IconFlags", GC_EVENT_ACTION, 0 },
+	{ LPGENW("Show icon for highlights"), "IconFlags", GC_EVENT_HIGHLIGHT, 0 },
+	{ LPGENW("Show icon for users leaving"), "IconFlags", GC_EVENT_PART, 0 },
+	{ LPGENW("Show icon for users kicking other user"), "IconFlags", GC_EVENT_KICK, 0 },
+	{ LPGENW("Show icon for notices"), "IconFlags", GC_EVENT_NOTICE, 0 },
+	{ LPGENW("Show icon for name changes"), "IconFlags", GC_EVENT_NICK, 0 },
+	{ LPGENW("Show icon for information messages"), "IconFlags", GC_EVENT_INFORMATION, 0 },
+	{ LPGENW("Show icon for status changes"), "IconFlags", GC_EVENT_ADDSTATUS, 0 },
+};
+
+static const struct branch_t branch5[] = {
+	{ LPGENW("Show icons in tray only when the chat room is not active"), "TrayIconInactiveOnly", 0, 1 },
+	{ LPGENW("Show icon in tray for topic changes"), "TrayIconFlags", GC_EVENT_TOPIC, 0 },
+	{ LPGENW("Show icon in tray for users joining"), "TrayIconFlags", GC_EVENT_JOIN, 0 },
+	{ LPGENW("Show icon in tray for users disconnecting"), "TrayIconFlags", GC_EVENT_QUIT, 0 },
+	{ LPGENW("Show icon in tray for messages"), "TrayIconFlags", GC_EVENT_MESSAGE, 0 },
+	{ LPGENW("Show icon in tray for actions"), "TrayIconFlags", GC_EVENT_ACTION, 0 },
+	{ LPGENW("Show icon in tray for highlights"), "TrayIconFlags", GC_EVENT_HIGHLIGHT, 1 },
+	{ LPGENW("Show icon in tray for users leaving"), "TrayIconFlags", GC_EVENT_PART, 0 },
+	{ LPGENW("Show icon in tray for users kicking other user"), "TrayIconFlags", GC_EVENT_KICK, 0 },
+	{ LPGENW("Show icon in tray for notices"), "TrayIconFlags", GC_EVENT_NOTICE, 0 },
+	{ LPGENW("Show icon in tray for name changes"), "TrayIconFlags", GC_EVENT_NICK, 0 },
+	{ LPGENW("Show icon in tray for information messages"), "TrayIconFlags", GC_EVENT_INFORMATION, 0 },
+	{ LPGENW("Show icon in tray for status changes"), "TrayIconFlags", GC_EVENT_ADDSTATUS, 0 },
+};
+
+static const struct branch_t branch6[] = {
+	{ LPGENW("Show popups only when the chat room is not active"), "PopupInactiveOnly", 0, 1 },
+	{ LPGENW("Show popup for topic changes"), "PopupFlags", GC_EVENT_TOPIC, 0 },
+	{ LPGENW("Show popup for users joining"), "PopupFlags", GC_EVENT_JOIN, 0 },
+	{ LPGENW("Show popup for users disconnecting"), "PopupFlags", GC_EVENT_QUIT, 0 },
+	{ LPGENW("Show popup for messages"), "PopupFlags", GC_EVENT_MESSAGE, 0 },
+	{ LPGENW("Show popup for actions"), "PopupFlags", GC_EVENT_ACTION, 0 },
+	{ LPGENW("Show popup for highlights"), "PopupFlags", GC_EVENT_HIGHLIGHT, 0 },
+	{ LPGENW("Show popup for users leaving"), "PopupFlags", GC_EVENT_PART, 0 },
+	{ LPGENW("Show popup for users kicking other user"), "PopupFlags", GC_EVENT_KICK, 0 },
+	{ LPGENW("Show popup for notices"), "PopupFlags", GC_EVENT_NOTICE, 0 },
+	{ LPGENW("Show popup for name changes"), "PopupFlags", GC_EVENT_NICK, 0 },
+	{ LPGENW("Show popup for information messages"), "PopupFlags", GC_EVENT_INFORMATION, 0 },
+	{ LPGENW("Show popup for status changes"), "PopupFlags", GC_EVENT_ADDSTATUS, 0 },
+};
+
+HTREEITEM hItemB0[_countof(branch0)];
+HTREEITEM hItemB1[_countof(branch1)];
+HTREEITEM hItemB2[_countof(branch2)];
+HTREEITEM hItemB3[_countof(branch3)];
+HTREEITEM hItemB4[_countof(branch4)];
+HTREEITEM hItemB5[_countof(branch5)];
+HTREEITEM hItemB6[_countof(branch6)];
+
+static HTREEITEM InsertBranch(HWND hwndTree, char* pszDescr, BOOL bExpanded)
+{
+	TVINSERTSTRUCT tvis = { 0 };
+	tvis.hInsertAfter = TVI_LAST;
+	tvis.item.mask = TVIF_TEXT | TVIF_STATE;
+	tvis.item.pszText = Langpack_PcharToTchar(pszDescr);
+	tvis.item.stateMask = bExpanded ? TVIS_STATEIMAGEMASK | TVIS_EXPANDED : TVIS_STATEIMAGEMASK;
+	tvis.item.state = bExpanded ? INDEXTOSTATEIMAGEMASK(1) | TVIS_EXPANDED : INDEXTOSTATEIMAGEMASK(1);
+	HTREEITEM res = TreeView_InsertItem(hwndTree, &tvis);
+	mir_free(tvis.item.pszText);
+	return res;
+}
+
+static void FillBranch(HWND hwndTree, HTREEITEM hParent, const struct branch_t *branch, HTREEITEM *hItemB, int nValues, DWORD defaultval)
+{
+	int iState;
+
+	if (hParent == 0)
+		return;
+
+	TVINSERTSTRUCT tvis;
+	tvis.hParent = hParent;
+	tvis.hInsertAfter = TVI_LAST;
+	tvis.item.mask = TVIF_TEXT | TVIF_STATE;
+	for (int i = 0; i < nValues; i++) {
+		tvis.item.pszText = TranslateW(branch[i].szDescr);
+		tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+		if (branch[i].iMode)
+			iState = ((db_get_dw(NULL, CHAT_MODULE, branch[i].szDBName, defaultval)&branch[i].iMode)&branch[i].iMode) != 0 ? 2 : 1;
+		else
+			iState = db_get_b(NULL, CHAT_MODULE, branch[i].szDBName, branch[i].bDefault) != 0 ? 2 : 1;
+		tvis.item.state = INDEXTOSTATEIMAGEMASK(iState);
+		hItemB[i] = TreeView_InsertItem(hwndTree, &tvis);
+	}
+}
+
+static void SaveBranch(HWND hwndTree, const struct branch_t *branch, HTREEITEM *hItemB, int nValues)
+{
+	int iState = 0;
+
+	TVITEM tvi;
+	tvi.mask = TVIF_HANDLE | TVIF_STATE;
+	for (int i = 0; i < nValues; i++) {
+		tvi.hItem = hItemB[i];
+		TreeView_GetItem(hwndTree, &tvi);
+		BYTE bChecked = (((tvi.state & TVIS_STATEIMAGEMASK) >> 12) == 1) ? 0 : 1;
+		if (branch[i].iMode) {
+			if (bChecked)
+				iState |= branch[i].iMode;
+			if (iState & GC_EVENT_ADDSTATUS)
+				iState |= GC_EVENT_REMOVESTATUS;
+			db_set_dw(NULL, CHAT_MODULE, branch[i].szDBName, (DWORD)iState);
+		}
+		else db_set_b(NULL, CHAT_MODULE, branch[i].szDBName, bChecked);
+	}
+}
+
+static void CheckHeading(HWND hwndTree, HTREEITEM hHeading)
+{
+	BOOL bChecked = TRUE;
+
+	if (hHeading == 0)
+		return;
+
+	TVITEM tvi;
+	tvi.mask = TVIF_HANDLE | TVIF_STATE;
+	tvi.hItem = TreeView_GetNextItem(hwndTree, hHeading, TVGN_CHILD);
+	while (tvi.hItem && bChecked) {
+		if (tvi.hItem != hItemB1[0] && tvi.hItem != hItemB1[1]) {
+			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;
+
+	if (hHeading == 0)
+		return;
+
+	TVITEM tvi;
+	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 != hItemB1[0] && tvi.hItem != hItemB1[1])
+			TreeView_SetItem(hwndTree, &tvi);
+		tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem);
+	}
+}
+
+static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData)
+{
+	wchar_t szDir[MAX_PATH];
+	switch (uMsg) {
+	case BFFM_INITIALIZED:
+		SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData);
+		break;
+
+	case BFFM_SELCHANGED:
+		if (SHGetPathFromIDList((LPITEMIDLIST)lp, szDir))
+			SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)szDir);
+		break;
+	}
+	return 0;
+}
+
+// add icons to the skinning module
+
+static IconItem iconList[] =
+{
+	{ LPGEN("Window icon"), "chat_window", IDI_CHANMGR, 0 },
+	{ LPGEN("Text color"), "chat_fgcol", IDI_COLOR, 0 },
+	{ LPGEN("Background color"), "chat_bkgcol", IDI_BKGCOLOR, 0 },
+	{ LPGEN("Bold"), "chat_bold", IDI_BBOLD, 0 },
+	{ LPGEN("Italics"), "chat_italics", IDI_BITALICS, 0 },
+	{ LPGEN("Underlined"), "chat_underline", IDI_BUNDERLINE, 0 },
+	{ LPGEN("Smiley button"), "chat_smiley", IDI_BSMILEY, 0 },
+	{ LPGEN("Room history"), "chat_history", IDI_HISTORY, 0 },
+	{ LPGEN("Room settings"), "chat_settings", IDI_TOPICBUT, 0 },
+	{ LPGEN("Event filter disabled"), "chat_filter", IDI_FILTER, 0 },
+	{ LPGEN("Event filter enabled"), "chat_filter2", IDI_FILTER2, 0 },
+	{ LPGEN("Hide nick list"), "chat_nicklist", IDI_NICKLIST, 0 },
+	{ LPGEN("Show nick list"), "chat_nicklist2", IDI_NICKLIST2, 0 },
+	{ LPGEN("Icon overlay"), "chat_overlay", IDI_OVERLAY, 0 },
+	{ LPGEN("Close"), "chat_close", IDI_CLOSE, 0 },
+
+	{ LPGEN("Status 1 (10x10)"), "chat_status0", IDI_STATUS0, 10 },
+	{ LPGEN("Status 2 (10x10)"), "chat_status1", IDI_STATUS1, 10 },
+	{ LPGEN("Status 3 (10x10)"), "chat_status2", IDI_STATUS2, 10 },
+	{ LPGEN("Status 4 (10x10)"), "chat_status3", IDI_STATUS3, 10 },
+	{ LPGEN("Status 5 (10x10)"), "chat_status4", IDI_STATUS4, 10 },
+	{ LPGEN("Status 6 (10x10)"), "chat_status5", IDI_STATUS5, 10 },
+
+	{ LPGEN("Message in (10x10)"), "chat_log_message_in", IDI_MESSAGE, 10 },
+	{ LPGEN("Message out (10x10)"), "chat_log_message_out", IDI_MESSAGEOUT, 10 },
+	{ LPGEN("Action (10x10)"), "chat_log_action", IDI_ACTION, 10 },
+	{ LPGEN("Add status (10x10)"), "chat_log_addstatus", IDI_ADDSTATUS, 10 },
+	{ LPGEN("Remove status (10x10)"), "chat_log_removestatus", IDI_REMSTATUS, 10 },
+	{ LPGEN("Join (10x10)"), "chat_log_join", IDI_JOIN, 10 },
+	{ LPGEN("Leave (10x10)"), "chat_log_part", IDI_PART, 10 },
+	{ LPGEN("Quit (10x10)"), "chat_log_quit", IDI_QUIT, 10 },
+	{ LPGEN("Kick (10x10)"), "chat_log_kick", IDI_KICK, 10 },
+	{ LPGEN("Nick change (10x10)"), "chat_log_nick", IDI_NICK, 10 },
+	{ LPGEN("Notice (10x10)"), "chat_log_notice", IDI_NOTICE, 10 },
+	{ LPGEN("Topic (10x10)"), "chat_log_topic", IDI_TOPIC, 10 },
+	{ LPGEN("Highlight (10x10)"), "chat_log_highlight", IDI_HIGHLIGHT, 10 },
+	{ LPGEN("Information (10x10)"), "chat_log_info", IDI_INFO, 10 }
+};
+
+void AddIcons(void)
+{
+	Icon_Register(g_hInst, LPGEN("Messaging") "/" LPGEN("Group chats"), iconList, 21);
+	Icon_Register(g_hInst, LPGEN("Messaging") "/" LPGEN("Group chats log"), iconList + 21, 14);
+}
+
+// load icons from the skinning module if available
+HICON LoadIconEx(const char *pszIcoLibName, bool big)
+{
+	char szTemp[256];
+	mir_snprintf(szTemp, "chat_%s", pszIcoLibName);
+	return IcoLib_GetIcon(szTemp, big);
+}
+
+HANDLE GetIconHandle(const char *pszIcoLibName)
+{
+	char szTemp[256];
+	mir_snprintf(szTemp, "chat_%s", pszIcoLibName);
+	return IcoLib_GetIconHandle(szTemp);
+}
+
+static void InitSetting(wchar_t** ppPointer, char* pszSetting, wchar_t* pszDefault)
+{
+	DBVARIANT dbv;
+	if (!db_get_ws(NULL, CHAT_MODULE, pszSetting, &dbv)) {
+		replaceStrW(*ppPointer, dbv.ptszVal);
+		db_free(&dbv);
+	}
+	else replaceStrW(*ppPointer, pszDefault);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// General options
+
+#define OPT_FIXHEADINGS (WM_USER+1)
+
+static HTREEITEM hListHeading0, hListHeading1, hListHeading2, hListHeading3, hListHeading4, hListHeading5, hListHeading6;
+
+static INT_PTR CALLBACK DlgProcOptions1(HWND hwndDlg, UINT uMsg, WPARAM, LPARAM lParam)
+{
+	switch (uMsg) {
+	case WM_INITDIALOG:
+		TranslateDialogDefault(hwndDlg);
+		SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHECKBOXES), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CHECKBOXES), GWL_STYLE) | TVS_NOHSCROLL | TVS_CHECKBOXES);
+		hListHeading0 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), LPGEN("Options for using a tabbed interface"), db_get_b(NULL, CHAT_MODULE, "Branch0Exp", 0) ? TRUE : FALSE);
+		hListHeading1 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), LPGEN("Appearance and functionality of chat room windows"), db_get_b(NULL, CHAT_MODULE, "Branch1Exp", 0) ? TRUE : FALSE);
+		hListHeading2 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), LPGEN("Appearance of the message log"), db_get_b(NULL, CHAT_MODULE, "Branch2Exp", 0) ? TRUE : FALSE);
+		hListHeading3 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), LPGEN("Default events to show in new chat rooms if the 'event filter' is enabled"), db_get_b(NULL, CHAT_MODULE, "Branch3Exp", 0) ? TRUE : FALSE);
+		hListHeading4 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), LPGEN("Icons to display in the message log"), db_get_b(NULL, CHAT_MODULE, "Branch4Exp", 0) ? TRUE : FALSE);
+		hListHeading5 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), LPGEN("Icons to display in the tray"), db_get_b(NULL, CHAT_MODULE, "Branch5Exp", 0) ? TRUE : FALSE);
+		if (PopupInstalled)
+			hListHeading6 = InsertBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), LPGEN("Popups to display"), db_get_b(NULL, CHAT_MODULE, "Branch6Exp", 0) ? TRUE : FALSE);
+		FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading0, branch0, hItemB0, _countof(branch0), 0);
+		FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading1, branch1, hItemB1, _countof(branch1), 0);
+		FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading2, branch2, hItemB2, _countof(branch2), 0);
+		FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading3, branch3, hItemB3, _countof(branch3), 0x03E0);
+		FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading4, branch4, hItemB4, _countof(branch4), 0x0000);
+		FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading5, branch5, hItemB5, _countof(branch5), 0x1000);
+		FillBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading6, branch6, hItemB6, _countof(branch6), 0x0000);
+		SendMessage(hwndDlg, OPT_FIXHEADINGS, 0, 0);
+		break;
+
+	case OPT_FIXHEADINGS:
+		CheckHeading(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading1);
+		CheckHeading(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading2);
+		CheckHeading(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading3);
+		CheckHeading(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading4);
+		CheckHeading(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading5);
+		CheckHeading(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading6);
+		break;
+
+	case WM_COMMAND:
+		if (lParam != 0)
+			SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+		break;
+
+	case WM_NOTIFY:
+		switch (((LPNMHDR)lParam)->idFrom) {
+		case IDC_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) {
+						TVITEM tvi = { 0 };
+						tvi.mask = TVIF_HANDLE | TVIF_STATE;
+						tvi.hItem = hti.hItem;
+						TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom, &tvi);
+						if (tvi.hItem == hItemB1[0] && INDEXTOSTATEIMAGEMASK(1) == tvi.state)
+							TreeView_SetItemState(((LPNMHDR)lParam)->hwndFrom, hItemB1[1], INDEXTOSTATEIMAGEMASK(1), TVIS_STATEIMAGEMASK);
+						if (tvi.hItem == hItemB1[1] && INDEXTOSTATEIMAGEMASK(1) == tvi.state)
+							TreeView_SetItemState(((LPNMHDR)lParam)->hwndFrom, hItemB1[0], INDEXTOSTATEIMAGEMASK(1), TVIS_STATEIMAGEMASK);
+
+						if (tvi.hItem == hListHeading0)
+							CheckBranches(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading0);
+						else if (tvi.hItem == hListHeading1)
+							CheckBranches(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading1);
+						else if (tvi.hItem == hListHeading2)
+							CheckBranches(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading2);
+						else if (tvi.hItem == hListHeading3)
+							CheckBranches(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading3);
+						else if (tvi.hItem == hListHeading4)
+							CheckBranches(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading4);
+						else if (tvi.hItem == hListHeading5)
+							CheckBranches(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading5);
+						else if (tvi.hItem == hListHeading6)
+							CheckBranches(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading6);
+						else
+							PostMessage(hwndDlg, OPT_FIXHEADINGS, 0, 0);
+						SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+					}
+				}
+			}
+			break;
+
+		case 0:
+			switch (((LPNMHDR)lParam)->code) {
+			case PSN_APPLY:
+				BYTE b = db_get_b(NULL, CHAT_MODULE, "Tabs", 1);
+				SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch0, hItemB0, _countof(branch0));
+				SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch1, hItemB1, _countof(branch1));
+				SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch2, hItemB2, _countof(branch2));
+				SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch3, hItemB3, _countof(branch3));
+				SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch4, hItemB4, _countof(branch4));
+				SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch5, hItemB5, _countof(branch5));
+				if (PopupInstalled)
+					SaveBranch(GetDlgItem(hwndDlg, IDC_CHECKBOXES), branch6, hItemB6, _countof(branch6));
+				g_Settings.dwIconFlags = db_get_dw(NULL, CHAT_MODULE, "IconFlags", 0x0000);
+				g_Settings.dwTrayIconFlags = db_get_dw(NULL, CHAT_MODULE, "TrayIconFlags", 0x1000);
+				g_Settings.dwPopupFlags = db_get_dw(NULL, CHAT_MODULE, "PopupFlags", 0x0000);
+				g_Settings.bStripFormat = db_get_b(NULL, CHAT_MODULE, "TrimFormatting", 0) != 0;
+				g_Settings.bTrayIconInactiveOnly = db_get_b(NULL, CHAT_MODULE, "TrayIconInactiveOnly", 1) != 0;
+				g_Settings.bPopupInactiveOnly = db_get_b(NULL, CHAT_MODULE, "PopupInactiveOnly", 1) != 0;
+				g_Settings.bLogIndentEnabled = db_get_b(NULL, CHAT_MODULE, "LogIndentEnabled", 1) != 0;
+
+				if (b != db_get_b(NULL, CHAT_MODULE, "Tabs", 1)) {
+					pci->SM_BroadcastMessage(NULL, GC_CLOSEWINDOW, 0, 1, FALSE);
+					g_Settings.bTabsEnable = db_get_b(NULL, CHAT_MODULE, "Tabs", 1) != 0;
+				}
+				else pci->SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE);
+
+				return TRUE;
+			}
+		}
+		break;
+
+	case WM_DESTROY:
+		BYTE b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading1, TVIS_EXPANDED)&TVIS_EXPANDED ? 1 : 0;
+		db_set_b(NULL, CHAT_MODULE, "Branch1Exp", b);
+		b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading2, TVIS_EXPANDED)&TVIS_EXPANDED ? 1 : 0;
+		db_set_b(NULL, CHAT_MODULE, "Branch2Exp", b);
+		b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading3, TVIS_EXPANDED)&TVIS_EXPANDED ? 1 : 0;
+		db_set_b(NULL, CHAT_MODULE, "Branch3Exp", b);
+		b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading4, TVIS_EXPANDED)&TVIS_EXPANDED ? 1 : 0;
+		db_set_b(NULL, CHAT_MODULE, "Branch4Exp", b);
+		b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading5, TVIS_EXPANDED)&TVIS_EXPANDED ? 1 : 0;
+		db_set_b(NULL, CHAT_MODULE, "Branch5Exp", b);
+		b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading0, TVIS_EXPANDED)&TVIS_EXPANDED ? 1 : 0;
+		db_set_b(NULL, CHAT_MODULE, "Branch0Exp", b);
+		if (PopupInstalled) {
+			b = TreeView_GetItemState(GetDlgItem(hwndDlg, IDC_CHECKBOXES), hListHeading6, TVIS_EXPANDED)&TVIS_EXPANDED ? 1 : 0;
+			db_set_b(NULL, CHAT_MODULE, "Branch6Exp", b);
+		}
+		break;
+	}
+	return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Log & other options
+
+static INT_PTR CALLBACK DlgProcOptions2(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+	switch (uMsg) {
+	case WM_INITDIALOG:
+		TranslateDialogDefault(hwndDlg);
+		SendDlgItemMessage(hwndDlg, IDC_SPIN2, UDM_SETRANGE, 0, MAKELONG(5000, 0));
+		SendDlgItemMessage(hwndDlg, IDC_SPIN2, UDM_SETPOS, 0, MAKELONG(db_get_w(NULL, CHAT_MODULE, "LogLimit", 100), 0));
+		SendDlgItemMessage(hwndDlg, IDC_SPIN3, UDM_SETRANGE, 0, MAKELONG(10000, 0));
+		SendDlgItemMessage(hwndDlg, IDC_SPIN3, UDM_SETPOS, 0, MAKELONG(db_get_w(NULL, CHAT_MODULE, "LoggingLimit", 100), 0));
+		SendDlgItemMessage(hwndDlg, IDC_SPIN4, UDM_SETRANGE, 0, MAKELONG(255, 10));
+		SendDlgItemMessage(hwndDlg, IDC_SPIN4, UDM_SETPOS, 0, MAKELONG(db_get_b(NULL, CHAT_MODULE, "NicklistRowDist", 12), 0));
+		{
+			wchar_t* pszGroup = NULL;
+			InitSetting(&pszGroup, "AddToGroup", L"Chat rooms");
+			SetDlgItemText(hwndDlg, IDC_GROUP, pszGroup);
+			mir_free(pszGroup);
+		}
+		{
+			wchar_t szTemp[MAX_PATH];
+			PathToRelativeT(g_Settings.pszLogDir, szTemp);
+			SetDlgItemText(hwndDlg, IDC_LOGDIRECTORY, szTemp);
+		}
+		SetDlgItemText(hwndDlg, IDC_HIGHLIGHTWORDS, g_Settings.pszHighlightWords);
+		SetDlgItemText(hwndDlg, IDC_LOGTIMESTAMP, g_Settings.pszTimeStampLog);
+		SetDlgItemText(hwndDlg, IDC_TIMESTAMP, g_Settings.pszTimeStamp);
+		SetDlgItemText(hwndDlg, IDC_OUTSTAMP, g_Settings.pszOutgoingNick);
+		SetDlgItemText(hwndDlg, IDC_INSTAMP, g_Settings.pszIncomingNick);
+		CheckDlgButton(hwndDlg, IDC_HIGHLIGHT, g_Settings.bHighlightEnabled ? BST_CHECKED : BST_UNCHECKED);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_HIGHLIGHTWORDS), g_Settings.bHighlightEnabled ? TRUE : FALSE);
+		CheckDlgButton(hwndDlg, IDC_LOGGING, g_Settings.bLoggingEnabled ? BST_CHECKED : BST_UNCHECKED);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_LOGDIRECTORY), g_Settings.bLoggingEnabled ? TRUE : FALSE);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_FONTCHOOSE), g_Settings.bLoggingEnabled ? TRUE : FALSE);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT), g_Settings.bLoggingEnabled ? TRUE : FALSE);
+		break;
+
+	case WM_COMMAND:
+		if ((LOWORD(wParam) == IDC_INSTAMP
+			|| LOWORD(wParam) == IDC_OUTSTAMP
+			|| LOWORD(wParam) == IDC_TIMESTAMP
+			|| LOWORD(wParam) == IDC_LOGLIMIT
+			|| LOWORD(wParam) == IDC_HIGHLIGHTWORDS
+			|| LOWORD(wParam) == IDC_LOGDIRECTORY
+			|| LOWORD(wParam) == IDC_LOGTIMESTAMP
+			|| LOWORD(wParam) == IDC_NICKROW2
+			|| LOWORD(wParam) == IDC_GROUP
+			|| LOWORD(wParam) == IDC_LIMIT)
+			&& (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus()))	return 0;
+
+		switch (LOWORD(wParam)) {
+		case IDC_LOGGING:
+			EnableWindow(GetDlgItem(hwndDlg, IDC_LOGDIRECTORY), IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE);
+			EnableWindow(GetDlgItem(hwndDlg, IDC_FONTCHOOSE), IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE);
+			EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT), IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED ? TRUE : FALSE);
+			break;
+
+		case IDC_FONTCHOOSE:
+			{
+				wchar_t szDirectory[MAX_PATH];
+				wchar_t szTemp[MAX_PATH];
+
+				BROWSEINFO bi = { 0 };
+				bi.hwndOwner = hwndDlg;
+				bi.pszDisplayName = szDirectory;
+				bi.lpszTitle = TranslateT("Select folder");
+				bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_RETURNONLYFSDIRS;
+				bi.lpfn = BrowseCallbackProc;
+				bi.lParam = (LPARAM)szDirectory;
+				LPITEMIDLIST idList = SHBrowseForFolder(&bi);
+				if (idList) {
+					SHGetPathFromIDList(idList, szDirectory);
+					mir_wstrcat(szDirectory, L"\\");
+					PathToRelativeT(szDirectory, szTemp);
+					SetDlgItemText(hwndDlg, IDC_LOGDIRECTORY, mir_wstrlen(szTemp) > 1 ? szTemp : L"Logs\\");
+					CoTaskMemFree(idList);
+				}
+			}
+			break;
+
+		case IDC_HIGHLIGHT:
+			EnableWindow(GetDlgItem(hwndDlg, IDC_HIGHLIGHTWORDS), IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHT) == BST_CHECKED ? TRUE : FALSE);
+			break;
+		}
+
+		if (lParam != 0)
+			SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+		break;
+
+	case WM_NOTIFY:
+		if (((LPNMHDR)lParam)->idFrom == 0 && ((LPNMHDR)lParam)->code == PSN_APPLY) {
+			wchar_t * pszText = NULL;
+			int iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_HIGHLIGHTWORDS));
+			if (iLen > 0) {
+				wchar_t *ptszText = (wchar_t *)mir_alloc((iLen + 2) * sizeof(wchar_t));
+				wchar_t *p2 = NULL;
+
+				if (ptszText) {
+					GetDlgItemText(hwndDlg, IDC_HIGHLIGHTWORDS, ptszText, iLen + 1);
+					p2 = wcschr(ptszText, ',');
+					while (p2) {
+						*p2 = ' ';
+						p2 = wcschr(ptszText, ',');
+					}
+					db_set_ws(NULL, CHAT_MODULE, "HighlightWords", ptszText);
+					mir_free(ptszText);
+				}
+			}
+			else db_unset(NULL, CHAT_MODULE, "HighlightWords");
+
+			iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOGDIRECTORY));
+			if (iLen > 0) {
+				pszText = (wchar_t *)mir_realloc(pszText, (iLen + 1) * sizeof(wchar_t));
+				GetDlgItemText(hwndDlg, IDC_LOGDIRECTORY, pszText, iLen + 1);
+				db_set_ws(NULL, CHAT_MODULE, "LogDirectory", pszText);
+			}
+			else db_unset(NULL, CHAT_MODULE, "LogDirectory");
+			pci->SM_InvalidateLogDirectories();
+
+			iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_LOGTIMESTAMP));
+			if (iLen > 0) {
+				pszText = (wchar_t *)mir_realloc(pszText, (iLen + 1) * sizeof(wchar_t));
+				GetDlgItemText(hwndDlg, IDC_LOGTIMESTAMP, pszText, iLen + 1);
+				db_set_ws(NULL, CHAT_MODULE, "LogTimestamp", pszText);
+			}
+			else db_unset(NULL, CHAT_MODULE, "LogTimestamp");
+
+			iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_TIMESTAMP));
+			if (iLen > 0) {
+				pszText = (wchar_t *)mir_realloc(pszText, (iLen + 1) * sizeof(wchar_t));
+				GetDlgItemText(hwndDlg, IDC_TIMESTAMP, pszText, iLen + 1);
+				db_set_ws(NULL, CHAT_MODULE, "HeaderTime", pszText);
+			}
+			else db_unset(NULL, CHAT_MODULE, "HeaderTime");
+
+			iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_INSTAMP));
+			if (iLen > 0) {
+				pszText = (wchar_t *)mir_realloc(pszText, (iLen + 1) * sizeof(wchar_t));
+				GetDlgItemText(hwndDlg, IDC_INSTAMP, pszText, iLen + 1);
+				db_set_ws(NULL, CHAT_MODULE, "HeaderIncoming", pszText);
+			}
+			else db_unset(NULL, CHAT_MODULE, "HeaderIncoming");
+
+			iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_OUTSTAMP));
+			if (iLen > 0) {
+				pszText = (wchar_t *)mir_realloc(pszText, (iLen + 1) * sizeof(wchar_t));
+				GetDlgItemText(hwndDlg, IDC_OUTSTAMP, pszText, iLen + 1);
+				db_set_ws(NULL, CHAT_MODULE, "HeaderOutgoing", pszText);
+			}
+			else db_unset(NULL, CHAT_MODULE, "HeaderOutgoing");
+
+			g_Settings.bHighlightEnabled = IsDlgButtonChecked(hwndDlg, IDC_HIGHLIGHT) == BST_CHECKED;
+			db_set_b(NULL, CHAT_MODULE, "HighlightEnabled", g_Settings.bHighlightEnabled);
+
+			g_Settings.bLoggingEnabled = IsDlgButtonChecked(hwndDlg, IDC_LOGGING) == BST_CHECKED;
+			db_set_b(NULL, CHAT_MODULE, "LoggingEnabled", g_Settings.bLoggingEnabled);
+
+			iLen = SendDlgItemMessage(hwndDlg, IDC_SPIN2, UDM_GETPOS, 0, 0);
+			db_set_w(NULL, CHAT_MODULE, "LogLimit", (WORD)iLen);
+			iLen = SendDlgItemMessage(hwndDlg, IDC_SPIN3, UDM_GETPOS, 0, 0);
+			db_set_w(NULL, CHAT_MODULE, "LoggingLimit", (WORD)iLen);
+
+			iLen = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_GROUP));
+			if (iLen > 0) {
+				pszText = (wchar_t *)mir_realloc(pszText, (iLen + 1) * sizeof(wchar_t));
+				GetDlgItemText(hwndDlg, IDC_GROUP, pszText, iLen + 1);
+				db_set_ws(NULL, CHAT_MODULE, "AddToGroup", pszText);
+			}
+			else db_set_s(NULL, CHAT_MODULE, "AddToGroup", "");
+			mir_free(pszText);
+
+			iLen = SendDlgItemMessage(hwndDlg, IDC_SPIN4, UDM_GETPOS, 0, 0);
+			if (iLen > 0)
+				db_set_b(NULL, CHAT_MODULE, "NicklistRowDist", (BYTE)iLen);
+			else
+				db_unset(NULL, CHAT_MODULE, "NicklistRowDist");
+
+			pci->ReloadSettings();
+			pci->SM_BroadcastMessage(NULL, GC_SETWNDPROPS, 0, 0, TRUE);
+			return TRUE;
+		}
+		break;
+	}
+	return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Popup options
+
+static INT_PTR CALLBACK DlgProcOptionsPopup(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+	switch (uMsg) {
+	case WM_INITDIALOG:
+		TranslateDialogDefault(hwndDlg);
+
+		SendDlgItemMessage(hwndDlg, IDC_BKG, CPM_SETCOLOUR, 0, g_Settings.crPUBkgColour);
+		SendDlgItemMessage(hwndDlg, IDC_TEXT, CPM_SETCOLOUR, 0, g_Settings.crPUTextColour);
+
+		if (g_Settings.iPopupStyle == 2)
+			CheckDlgButton(hwndDlg, IDC_RADIO2, BST_CHECKED);
+		else if (g_Settings.iPopupStyle == 3)
+			CheckDlgButton(hwndDlg, IDC_RADIO3, BST_CHECKED);
+		else
+			CheckDlgButton(hwndDlg, IDC_RADIO1, BST_CHECKED);
+
+		EnableWindow(GetDlgItem(hwndDlg, IDC_BKG), IsDlgButtonChecked(hwndDlg, IDC_RADIO3) == BST_CHECKED ? TRUE : FALSE);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT), IsDlgButtonChecked(hwndDlg, IDC_RADIO3) == BST_CHECKED ? TRUE : FALSE);
+
+		SendDlgItemMessage(hwndDlg, IDC_SPIN1, UDM_SETRANGE, 0, MAKELONG(100, -1));
+		SendDlgItemMessage(hwndDlg, IDC_SPIN1, UDM_SETPOS, 0, MAKELONG(g_Settings.iPopupTimeout, 0));
+		break;
+
+	case WM_COMMAND:
+		if ((LOWORD(wParam) == IDC_TIMEOUT) && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus()))
+			return 0;
+
+		if (lParam != 0)
+			SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+
+		switch (LOWORD(wParam)) {
+
+		case IDC_RADIO1:
+		case IDC_RADIO2:
+		case IDC_RADIO3:
+			EnableWindow(GetDlgItem(hwndDlg, IDC_BKG), IsDlgButtonChecked(hwndDlg, IDC_RADIO3) == BST_CHECKED ? TRUE : FALSE);
+			EnableWindow(GetDlgItem(hwndDlg, IDC_TEXT), IsDlgButtonChecked(hwndDlg, IDC_RADIO3) == BST_CHECKED ? TRUE : FALSE);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		if (((LPNMHDR)lParam)->idFrom == 0 && ((LPNMHDR)lParam)->code == PSN_APPLY) {
+			int iLen;
+
+			if (IsDlgButtonChecked(hwndDlg, IDC_RADIO2) == BST_CHECKED)
+				iLen = 2;
+			else if (IsDlgButtonChecked(hwndDlg, IDC_RADIO3) == BST_CHECKED)
+				iLen = 3;
+			else
+				iLen = 1;
+
+			g_Settings.iPopupStyle = iLen;
+			db_set_b(NULL, CHAT_MODULE, "PopupStyle", (BYTE)iLen);
+
+			iLen = SendDlgItemMessage(hwndDlg, IDC_SPIN1, UDM_GETPOS, 0, 0);
+			g_Settings.iPopupTimeout = iLen;
+			db_set_w(NULL, CHAT_MODULE, "PopupTimeout", (WORD)iLen);
+
+			g_Settings.crPUBkgColour = SendDlgItemMessage(hwndDlg, IDC_BKG, CPM_GETCOLOUR, 0, 0);
+			db_set_dw(NULL, CHAT_MODULE, "PopupColorBG", (DWORD)SendDlgItemMessage(hwndDlg, IDC_BKG, CPM_GETCOLOUR, 0, 0));
+			g_Settings.crPUTextColour = SendDlgItemMessage(hwndDlg, IDC_TEXT, CPM_GETCOLOUR, 0, 0);
+			db_set_dw(NULL, CHAT_MODULE, "PopupColorText", (DWORD)SendDlgItemMessage(hwndDlg, IDC_TEXT, CPM_GETCOLOUR, 0, 0));
+			return TRUE;
+		}
+		break;
+	}
+	return FALSE;
+}
+
+int OptionsInitialize(WPARAM wParam, LPARAM)
+{
+	OPTIONSDIALOGPAGE odp = { 0 };
+	odp.position = 910000000;
+	odp.hInstance = g_hInst;
+	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS1);
+	odp.szGroup.a = LPGEN("Message sessions");
+	odp.szTitle.a = LPGEN("Group chats");
+	odp.szTab.a = LPGEN("General");
+	odp.pfnDlgProc = DlgProcOptions1;
+	odp.flags = ODPF_BOLDGROUPS;
+	Options_AddPage(wParam, &odp);
+
+	odp.position = 910000001;
+	odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS2);
+	odp.szTab.a = LPGEN("Chat log");
+	odp.pfnDlgProc = DlgProcOptions2;
+	Options_AddPage(wParam, &odp);
+
+	if (PopupInstalled) {
+		odp.position = 910000002;
+		odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONSPOPUP);
+		odp.szTitle.a = LPGEN(CHAT_MODULE);
+		odp.szGroup.a = LPGEN("Popups");
+		odp.szTab.a = NULL;
+		odp.pfnDlgProc = DlgProcOptionsPopup;
+		Options_AddPage(wParam, &odp);
+	}
+	return 0;
+}
diff --git a/src/core/stdmsg/src/chat_util.cpp b/src/core/stdmsg/src/chat_util.cpp
new file mode 100644
index 0000000000..73e0751bc7
--- /dev/null
+++ b/src/core/stdmsg/src/chat_util.cpp
@@ -0,0 +1,482 @@
+/*
+
+Copyright 2000-12 Miranda IM, 2012-16 Miranda NG project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+
+// The code for streaming the text is to a large extent copied from
+// the srmm module and then modified to fit the chat module.
+
+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 = pci->Log_CreateRTF(lstrdat);
+			lstrdat->bufferLen = (int)mir_strlen(lstrdat->buffer);
+		}
+
+		// give the RTF to the RE control
+		*pcb = min(cb, lstrdat->bufferLen - lstrdat->bufferOffset);
+		memcpy(pbBuff, lstrdat->buffer + lstrdat->bufferOffset, *pcb);
+		lstrdat->bufferOffset += *pcb;
+
+		// free stuff if the streaming operation is complete
+		if (lstrdat->bufferOffset == lstrdat->bufferLen) {
+			mir_free(lstrdat->buffer);
+			lstrdat->buffer = NULL;
+		}
+	}
+
+	return 0;
+}
+
+void Log_StreamInEvent(HWND hwndDlg,  LOGINFO* lin, SESSION_INFO *si, BOOL bRedraw, BOOL)
+{
+	CHARRANGE oldsel, sel, newsel;
+	POINT point ={0};
+	WPARAM wp;
+
+	if (hwndDlg == 0 || lin == 0 || si == 0)
+		return;
+
+	if (!bRedraw && si->iType == GCW_CHATROOM && si->bFilterEnabled && (si->iLogFilterFlags & lin->iType) == 0)
+		return;
+
+	HWND hwndRich = GetDlgItem(hwndDlg, IDC_LOG);
+	
+	LOGSTREAMDATA streamData;
+	memset(&streamData, 0, sizeof(streamData));
+	streamData.hwnd = hwndRich;
+	streamData.si = si;
+	streamData.lin = lin;
+	streamData.bStripFormat = FALSE;
+
+	BOOL bFlag = FALSE;
+
+	EDITSTREAM stream = { 0 };
+	stream.pfnCallback = Log_StreamCallback;
+	stream.dwCookie = (DWORD_PTR) & streamData;
+
+	SCROLLINFO scroll;
+	scroll.cbSize = sizeof(SCROLLINFO);
+	scroll.fMask= SIF_RANGE | SIF_POS|SIF_PAGE;
+	GetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &scroll);
+	SendMessage(hwndRich, EM_GETSCROLLPOS, 0, (LPARAM) &point);
+
+	// do not scroll to bottom if there is a selection
+	SendMessage(hwndRich, EM_EXGETSEL, 0, (LPARAM) &oldsel);
+	if (oldsel.cpMax != oldsel.cpMin)
+		SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0);
+
+	//set the insertion point at the bottom
+	sel.cpMin = sel.cpMax = GetRichTextLength(hwndRich);
+	SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) &sel);
+
+	// fix for the indent... must be a M$ bug
+	if (sel.cpMax == 0)
+		bRedraw = TRUE;
+
+	// should the event(s) be appended to the current log
+	wp = bRedraw?SF_RTF:SFF_SELECTION|SF_RTF;
+
+	//get the number of pixels per logical inch
+	if (bRedraw) {
+		HDC hdc = GetDC(NULL);
+		pci->logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
+		pci->logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX);
+		ReleaseDC(NULL, hdc);
+		SendMessage(hwndRich, WM_SETREDRAW, FALSE, 0);
+		bFlag = TRUE;
+	}
+
+	// stream in the event(s)
+	streamData.lin = lin;
+	streamData.bRedraw = bRedraw;
+	SendMessage(hwndRich, EM_STREAMIN, wp, (LPARAM) & stream);
+
+	// do smileys
+	if (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 = {0};
+
+		newsel.cpMax = -1;
+		newsel.cpMin = sel.cpMin;
+		if (newsel.cpMin < 0)
+			newsel.cpMin = 0;
+		memset(&sm, 0, sizeof(sm));
+		sm.cbSize = sizeof(sm);
+		sm.hwndRichEditControl = hwndRich;
+		sm.Protocolname = si->pszModule;
+		sm.rangeToReplace = bRedraw?NULL:&newsel;
+		sm.disableRedraw = TRUE;
+		sm.hContact = si->hContact;
+		CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm);
+	}
+
+	// scroll log to bottom if the log was previously scrolled to bottom, else restore old position
+	if (bRedraw ||  (UINT)scroll.nPos >= (UINT)scroll.nMax-scroll.nPage-5 || scroll.nMax-scroll.nMin-scroll.nPage < 50)
+		SendMessage(GetParent(hwndRich), GC_SCROLLTOBOTTOM, 0, 0);
+	else
+		SendMessage(hwndRich, EM_SETSCROLLPOS, 0, (LPARAM) &point);
+
+	// do we need to restore the selection
+	if (oldsel.cpMax != oldsel.cpMin) {
+		SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) & oldsel);
+		SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0);
+		InvalidateRect(hwndRich, NULL, TRUE);
+	}
+
+	// need to invalidate the window
+	if (bFlag) {
+		sel.cpMin = sel.cpMax = GetRichTextLength(hwndRich);
+		SendMessage(hwndRich, EM_EXSETSEL, 0, (LPARAM) &sel);
+		SendMessage(hwndRich, WM_SETREDRAW, TRUE, 0);
+		InvalidateRect(hwndRich, NULL, TRUE);
+}	}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static DWORD CALLBACK Message_StreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
+{
+	static DWORD dwRead;
+	char ** ppText = (char **)dwCookie;
+
+	if (*ppText == NULL) {
+		*ppText = (char *)mir_alloc(cb + 1);
+		memcpy(*ppText, pbBuff, cb);
+		(*ppText)[cb] = 0;
+		*pcb = cb;
+		dwRead = cb;
+	}
+	else {
+		char *p = (char *)mir_alloc(dwRead + cb + 1);
+		memcpy(p, *ppText, dwRead);
+		memcpy(p + dwRead, pbBuff, cb);
+		p[dwRead + cb] = 0;
+		mir_free(*ppText);
+		*ppText = p;
+		*pcb = cb;
+		dwRead += cb;
+	}
+
+	return 0;
+}
+
+char* Message_GetFromStream(HWND hwndDlg, SESSION_INFO *si)
+{
+	EDITSTREAM stream;
+	char* pszText = NULL;
+	DWORD dwFlags;
+
+	if (hwndDlg == 0 || si == 0)
+		return NULL;
+
+	memset(&stream, 0, sizeof(stream));
+	stream.pfnCallback = Message_StreamCallback;
+	stream.dwCookie = (DWORD_PTR)&pszText; // pass pointer to pointer
+
+	dwFlags = SF_RTFNOOBJS | SFF_PLAINRTF | SF_USECODEPAGE | (CP_UTF8 << 16);
+	SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_STREAMOUT, dwFlags, (LPARAM)& stream);
+	return pszText; // pszText contains the text
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void ShowRoom(SESSION_INFO *si, WPARAM wp, BOOL bSetForeground)
+{
+	if (!si)
+		return;
+
+	if (g_Settings.bTabsEnable) {
+		// the session is not the current tab, so we copy the necessary
+		// details into the SESSION_INFO for the tabbed window
+		if (!si->hWnd) {
+			g_TabSession.iEventCount = si->iEventCount;
+			g_TabSession.iStatusCount = si->iStatusCount;
+			g_TabSession.iType = si->iType;
+			g_TabSession.nUsersInNicklist = si->nUsersInNicklist;
+			g_TabSession.pLog = si->pLog;
+			g_TabSession.pLogEnd = si->pLogEnd;
+			g_TabSession.pMe = si->pMe;
+			g_TabSession.pStatuses = si->pStatuses;
+			g_TabSession.ptszID = si->ptszID;
+			g_TabSession.pszModule = si->pszModule;
+			g_TabSession.ptszName = si->ptszName;
+			g_TabSession.ptszStatusbarText = si->ptszStatusbarText;
+			g_TabSession.ptszTopic = si->ptszTopic;
+			g_TabSession.pUsers = si->pUsers;
+			g_TabSession.hContact = si->hContact;
+			g_TabSession.wStatus = si->wStatus;
+			g_TabSession.lpCommands = si->lpCommands;
+			g_TabSession.lpCurrentCommand = NULL;
+		}
+
+		// Do we need to create a tabbed window?
+		if (g_TabSession.hWnd == NULL)
+			g_TabSession.hWnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CHANNEL), NULL, RoomWndProc, (LPARAM)&g_TabSession);
+
+		SetWindowLongPtr(g_TabSession.hWnd, GWL_EXSTYLE, GetWindowLongPtr(g_TabSession.hWnd, GWL_EXSTYLE) | WS_EX_APPWINDOW);
+
+		// if the session was not the current tab we need to tell the window to
+		// redraw to show the contents of the current SESSION_INFO
+		if (!si->hWnd) {
+			SM_SetTabbedWindowHwnd(si, g_TabSession.hWnd);
+			SendMessage(g_TabSession.hWnd, GC_ADDTAB, -1, (LPARAM)si);
+			SendMessage(g_TabSession.hWnd, GC_TABCHANGE, 0, (LPARAM)&g_TabSession);
+		}
+
+		pci->SetActiveSession(si->ptszID, si->pszModule);
+
+		if (!IsWindowVisible(g_TabSession.hWnd) || wp == WINDOW_HIDDEN)
+			SendMessage(g_TabSession.hWnd, GC_CONTROL_MSG, wp, 0);
+		else {
+			if (IsIconic(g_TabSession.hWnd))
+				ShowWindow(g_TabSession.hWnd, SW_NORMAL);
+
+			PostMessage(g_TabSession.hWnd, WM_SIZE, 0, 0);
+			if (si->iType != GCW_SERVER)
+				SendMessage(g_TabSession.hWnd, GC_UPDATENICKLIST, 0, 0);
+			else
+				SendMessage(g_TabSession.hWnd, GC_UPDATETITLE, 0, 0);
+			SendMessage(g_TabSession.hWnd, GC_REDRAWLOG, 0, 0);
+			SendMessage(g_TabSession.hWnd, GC_UPDATESTATUSBAR, 0, 0);
+			ShowWindow(g_TabSession.hWnd, SW_SHOW);
+			if (bSetForeground)
+				SetForegroundWindow(g_TabSession.hWnd);
+		}
+		SendMessage(g_TabSession.hWnd, WM_MOUSEACTIVATE, 0, 0);
+		SetFocus(GetDlgItem(g_TabSession.hWnd, IDC_MESSAGE));
+		return;
+	}
+
+	// Do we need to create a window?
+	if (si->hWnd == NULL)
+		si->hWnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CHANNEL), NULL, RoomWndProc, (LPARAM)si);
+
+	SetWindowLongPtr(si->hWnd, GWL_EXSTYLE, GetWindowLongPtr(si->hWnd, GWL_EXSTYLE) | WS_EX_APPWINDOW);
+	if (!IsWindowVisible(si->hWnd) || wp == WINDOW_HIDDEN)
+		SendMessage(si->hWnd, GC_CONTROL_MSG, wp, 0);
+	else {
+		if (IsIconic(si->hWnd))
+			ShowWindow(si->hWnd, SW_NORMAL);
+		ShowWindow(si->hWnd, SW_SHOW);
+		SetForegroundWindow(si->hWnd);
+	}
+
+	SendMessage(si->hWnd, WM_MOUSEACTIVATE, 0, 0);
+	SetFocus(GetDlgItem(si->hWnd, IDC_MESSAGE));
+}
+
+bool LoadMessageFont(LOGFONT *lf, COLORREF *colour)
+{
+	char str[32];
+	int i = 8; // MSGFONTID_MESSAGEAREA
+
+	if (colour) {
+		mir_snprintf(str, "SRMFont%dCol", i);
+		*colour = db_get_dw(NULL, "SRMM", str, 0);
+	}
+	if (lf) {
+		mir_snprintf(str, "SRMFont%dSize", i);
+		lf->lfHeight = (char)db_get_b(NULL, "SRMM", str, -12);
+		lf->lfWidth = 0;
+		lf->lfEscapement = 0;
+		lf->lfOrientation = 0;
+		mir_snprintf(str, "SRMFont%dSty", i);
+		int style = db_get_b(NULL, "SRMM", str, 0);
+		lf->lfWeight = style & DBFONTF_BOLD ? FW_BOLD : FW_NORMAL;
+		lf->lfItalic = style & DBFONTF_ITALIC ? 1 : 0;
+		lf->lfUnderline = 0;
+		lf->lfStrikeOut = 0;
+		lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+		lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+		lf->lfQuality = DEFAULT_QUALITY;
+		lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+		mir_snprintf(str, "SRMFont%d", i);
+
+		DBVARIANT dbv;
+		if (db_get_ws(NULL, "SRMM", str, &dbv))
+			mir_wstrcpy(lf->lfFaceName, L"Arial");
+		else {
+			mir_wstrncpy(lf->lfFaceName, dbv.ptszVal, _countof(lf->lfFaceName));
+			db_free(&dbv);
+		}
+		mir_snprintf(str, "SRMFont%dSet", i);
+		lf->lfCharSet = db_get_b(NULL, "SRMM", str, DEFAULT_CHARSET);
+	}
+	return true;
+}
+
+int GetRichTextLength(HWND hwnd)
+{
+	GETTEXTLENGTHEX gtl;
+	gtl.flags = GTL_PRECISE;
+	gtl.codepage = CP_ACP;
+	return (int)SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
+}
+
+int GetColorIndex(const char* pszModule, COLORREF cr)
+{
+	MODULEINFO * pMod = pci->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 = pci->MM_FindModule(pszModule);
+	int i = 0;
+	COLORREF crBG = (COLORREF)db_get_dw(NULL, CHAT_MODULE, "ColorMessageBG", GetSysColor(COLOR_WINDOW));
+
+	if (!pMod)
+		return;
+
+	for (i = 0; i < pMod->nColorCount; i++) {
+		if (pMod->crColors[i] == g_Settings.MessageAreaColor || pMod->crColors[i] == crBG) {
+			if (pMod->crColors[i] == RGB(255, 255, 255))
+				pMod->crColors[i]--;
+			else
+				pMod->crColors[i]++;
+		}
+	}
+}
+
+UINT CreateGCMenu(HWND hwndDlg, HMENU *hMenu, int iIndex, POINT pt, SESSION_INFO *si, wchar_t* pszUID, wchar_t* pszWordText)
+{
+	HMENU hSubMenu = 0;
+	*hMenu = GetSubMenu(g_hMenu, iIndex);
+	TranslateMenu(*hMenu);
+
+	GCMENUITEMS gcmi = { 0 };
+	gcmi.pszID = si->ptszID;
+	gcmi.pszModule = si->pszModule;
+	gcmi.pszUID = pszUID;
+
+	if (iIndex == 1) {
+		int i = GetRichTextLength(GetDlgItem(hwndDlg, IDC_LOG));
+
+		EnableMenuItem(*hMenu, ID_CLEARLOG, MF_ENABLED);
+		EnableMenuItem(*hMenu, ID_COPYALL, MF_ENABLED);
+		ModifyMenu(*hMenu, 4, MF_GRAYED | MF_BYPOSITION, 4, NULL);
+		if (!i) {
+			EnableMenuItem(*hMenu, ID_COPYALL, MF_BYCOMMAND | MF_GRAYED);
+			EnableMenuItem(*hMenu, ID_CLEARLOG, MF_BYCOMMAND | MF_GRAYED);
+			if (pszWordText && pszWordText[0])
+				ModifyMenu(*hMenu, 4, MF_ENABLED | MF_BYPOSITION, 4, NULL);
+		}
+
+		if (pszWordText && pszWordText[0]) {
+			wchar_t szMenuText[4096];
+			mir_snwprintf(szMenuText, TranslateT("Look up '%s':"), pszWordText);
+			ModifyMenu(*hMenu, 4, MF_STRING | MF_BYPOSITION, 4, szMenuText);
+		}
+		else ModifyMenu(*hMenu, 4, MF_STRING | MF_GRAYED | MF_BYPOSITION, 4, TranslateT("No word to look up"));
+		gcmi.Type = MENU_ON_LOG;
+	}
+	else if (iIndex == 0) {
+		wchar_t szTemp[50];
+		if (pszWordText)
+			mir_snwprintf(szTemp, TranslateT("&Message %s"), pszWordText);
+		else
+			mir_wstrncpy(szTemp, TranslateT("&Message"), _countof(szTemp) - 1);
+
+		if (mir_wstrlen(szTemp) > 40)
+			mir_wstrcpy(szTemp + 40, L"...");
+		ModifyMenu(*hMenu, ID_MESS, MF_STRING | MF_BYCOMMAND, ID_MESS, szTemp);
+		gcmi.Type = MENU_ON_NICKLIST;
+	}
+
+	NotifyEventHooks(pci->hBuildMenuEvent, 0, (WPARAM)&gcmi);
+
+	if (gcmi.nItems > 0)
+		AppendMenu(*hMenu, MF_SEPARATOR, 0, 0);
+
+	for (int i = 0; i < gcmi.nItems; i++) {
+		wchar_t* ptszText = TranslateW(gcmi.Item[i].pszDesc);
+		DWORD dwState = gcmi.Item[i].bDisabled ? MF_GRAYED : 0;
+
+		if (gcmi.Item[i].uType == MENU_NEWPOPUP) {
+			hSubMenu = CreateMenu();
+			AppendMenu(*hMenu, dwState | MF_POPUP, (UINT_PTR)hSubMenu, ptszText);
+		}
+		else if (gcmi.Item[i].uType == MENU_POPUPHMENU)
+			AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_POPUP, gcmi.Item[i].dwID, ptszText);
+		else if (gcmi.Item[i].uType == MENU_POPUPITEM)
+			AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_STRING, gcmi.Item[i].dwID, ptszText);
+		else if (gcmi.Item[i].uType == MENU_POPUPCHECK)
+			AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, dwState | MF_CHECKED | MF_STRING, gcmi.Item[i].dwID, ptszText);
+		else if (gcmi.Item[i].uType == MENU_POPUPSEPARATOR)
+			AppendMenu(hSubMenu == 0 ? *hMenu : hSubMenu, MF_SEPARATOR, 0, ptszText);
+		else if (gcmi.Item[i].uType == MENU_SEPARATOR)
+			AppendMenu(*hMenu, MF_SEPARATOR, 0, ptszText);
+		else if (gcmi.Item[i].uType == MENU_HMENU)
+			AppendMenu(*hMenu, dwState | MF_POPUP, gcmi.Item[i].dwID, ptszText);
+		else if (gcmi.Item[i].uType == MENU_ITEM)
+			AppendMenu(*hMenu, dwState | MF_STRING, gcmi.Item[i].dwID, ptszText);
+		else if (gcmi.Item[i].uType == MENU_CHECK)
+			AppendMenu(*hMenu, dwState | MF_CHECKED | MF_STRING, gcmi.Item[i].dwID, ptszText);
+	}
+	return TrackPopupMenu(*hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL);
+}
+
+void DestroyGCMenu(HMENU *hMenu, int iIndex)
+{
+	MENUITEMINFO mii = { 0 };
+	mii.cbSize = sizeof(mii);
+	mii.fMask = MIIM_SUBMENU;
+	while (GetMenuItemInfo(*hMenu, iIndex, TRUE, &mii)) {
+		if (mii.hSubMenu != NULL)
+			DestroyMenu(mii.hSubMenu);
+		RemoveMenu(*hMenu, iIndex, MF_BYPOSITION);
+	}
+}
+
+void ValidateFilename(wchar_t *filename)
+{
+	wchar_t *p1 = filename;
+	wchar_t szForbidden[] = L"\\/:*?\"<>|";
+	while (*p1 != '\0') {
+		if (wcschr(szForbidden, *p1))
+			*p1 = '_';
+		p1 += 1;
+	}
+}
diff --git a/src/core/stdmsg/src/chat_window.cpp b/src/core/stdmsg/src/chat_window.cpp
new file mode 100644
index 0000000000..ccf26ee80e
--- /dev/null
+++ b/src/core/stdmsg/src/chat_window.cpp
@@ -0,0 +1,2610 @@
+/*
+Chat module plugin for Miranda IM
+
+Copyright 2000-12 Miranda IM, 2012-16 Miranda NG project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+static HKL hkl = NULL;
+
+struct MESSAGESUBDATA
+{
+	time_t lastEnterTime;
+	wchar_t  szTabSave[20];
+};
+
+static wchar_t szTrimString[] = L":;,.!?\'\"><()[]- \r\n";
+
+static LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	RECT rc;
+
+	switch (msg) {
+	case WM_NCHITTEST:
+		return HTCLIENT;
+
+	case WM_SETCURSOR:
+		GetClientRect(hwnd, &rc);
+		SetCursor(rc.right > rc.bottom ? LoadCursor(NULL, IDC_SIZENS) : LoadCursor(NULL, IDC_SIZEWE));
+		return TRUE;
+
+	case WM_LBUTTONDOWN:
+		SetCapture(hwnd);
+		return 0;
+
+	case WM_MOUSEMOVE:
+		if (GetCapture() == hwnd) {
+			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 mir_callNextSubclass(hwnd, SplitterSubclassProc, msg, wParam, lParam);
+}
+
+static void InitButtons(HWND hwndDlg, SESSION_INFO *si)
+{
+	SendDlgItemMessage(hwndDlg, IDC_SMILEY, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx("smiley", FALSE));
+	SendDlgItemMessage(hwndDlg, IDC_BOLD, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx("bold", FALSE));
+	SendDlgItemMessage(hwndDlg, IDC_ITALICS, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx("italics", FALSE));
+	SendDlgItemMessage(hwndDlg, IDC_UNDERLINE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx("underline", FALSE));
+	SendDlgItemMessage(hwndDlg, IDC_COLOR, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx("fgcol", FALSE));
+	SendDlgItemMessage(hwndDlg, IDC_BKGCOLOR, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx("bkgcol", FALSE));
+	SendDlgItemMessage(hwndDlg, IDC_HISTORY, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx("history", FALSE));
+	SendDlgItemMessage(hwndDlg, IDC_CHANMGR, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx("settings", FALSE));
+	SendDlgItemMessage(hwndDlg, IDC_CLOSE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx("close", FALSE));
+	SendDlgItemMessage(hwndDlg, IDC_SHOWNICKLIST, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx(si->bNicklistEnabled ? "nicklist" : "nicklist2", FALSE));
+	SendDlgItemMessage(hwndDlg, IDC_FILTER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx(si->bFilterEnabled ? "filter" : "filter2", FALSE));
+
+	SendDlgItemMessage(hwndDlg, IDC_SMILEY, BUTTONSETASFLATBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_BOLD, BUTTONSETASFLATBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_ITALICS, BUTTONSETASFLATBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_UNDERLINE, BUTTONSETASFLATBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_BKGCOLOR, BUTTONSETASFLATBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_COLOR, BUTTONSETASFLATBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_HISTORY, BUTTONSETASFLATBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_SHOWNICKLIST, BUTTONSETASFLATBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_CHANMGR, BUTTONSETASFLATBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_FILTER, BUTTONSETASFLATBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_CLOSE, BUTTONSETASFLATBTN, TRUE, 0);
+
+	SendDlgItemMessage(hwndDlg, IDC_SMILEY, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Insert a smiley"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_BOLD, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Make the text bold (CTRL+B)"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_ITALICS, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Make the text italicized (CTRL+I)"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_UNDERLINE, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Make the text underlined (CTRL+U)"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_BKGCOLOR, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Select a background color for the text (CTRL+L)"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_COLOR, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Select a foreground color for the text (CTRL+K)"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_HISTORY, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Show the history (CTRL+H)"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_SHOWNICKLIST, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Show/hide the nick list (CTRL+N)"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_CHANMGR, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Control this room (CTRL+O)"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_FILTER, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Enable/disable the event filter (CTRL+F)"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_CLOSE, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Close current tab (CTRL+F4)"), 0);
+	SendDlgItemMessage(hwndDlg, IDC_BOLD, BUTTONSETASPUSHBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_ITALICS, BUTTONSETASPUSHBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_UNDERLINE, BUTTONSETASPUSHBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_COLOR, BUTTONSETASPUSHBTN, TRUE, 0);
+	SendDlgItemMessage(hwndDlg, IDC_BKGCOLOR, BUTTONSETASPUSHBTN, TRUE, 0);
+
+	MODULEINFO *pInfo = pci->MM_FindModule(si->pszModule);
+	if (pInfo) {
+		EnableWindow(GetDlgItem(hwndDlg, IDC_BOLD), pInfo->bBold);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_ITALICS), pInfo->bItalics);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_UNDERLINE), pInfo->bUnderline);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_COLOR), pInfo->bColor);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_BKGCOLOR), pInfo->bBkgColor);
+		if (si->iType == GCW_CHATROOM)
+			EnableWindow(GetDlgItem(hwndDlg, IDC_CHANMGR), pInfo->bChanMgr);
+	}
+}
+
+static int RoomWndResize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL *urc)
+{
+	SESSION_INFO *si = (SESSION_INFO*)lParam;
+
+	BOOL bControl = (BOOL)db_get_b(NULL, CHAT_MODULE, "ShowTopButtons", 1);
+	BOOL bFormat = (BOOL)db_get_b(NULL, CHAT_MODULE, "ShowFormatButtons", 1);
+	BOOL bToolbar = bFormat || bControl;
+	BOOL bSend = (BOOL)db_get_b(NULL, CHAT_MODULE, "ShowSend", 0);
+	BOOL bNick = si->iType != GCW_SERVER && si->bNicklistEnabled;
+	BOOL bTabs = g_Settings.bTabsEnable;
+	BOOL bTabBottom = g_Settings.TabsAtBottom;
+
+	RECT rc, rcTabs;
+	GetClientRect(GetDlgItem(hwndDlg, IDC_TAB), &rcTabs);
+	int TabHeight = rcTabs.bottom - rcTabs.top;
+	TabCtrl_AdjustRect(GetDlgItem(hwndDlg, IDC_TAB), FALSE, &rcTabs);
+	TabHeight -= (rcTabs.bottom - rcTabs.top);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_SMILEY), (SmileyAddInstalled && bFormat) ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_BOLD), bFormat ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_UNDERLINE), bFormat ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_ITALICS), bFormat ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_COLOR), bFormat ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_BKGCOLOR), bFormat ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_HISTORY), bControl ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_SHOWNICKLIST), bControl ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_FILTER), bControl ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_CHANMGR), bControl ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDOK), bSend ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_SPLITTERX), bNick ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_CLOSE), g_Settings.bTabsEnable ? SW_SHOW : SW_HIDE);
+	ShowWindow(GetDlgItem(hwndDlg, IDC_TAB), g_Settings.bTabsEnable ? SW_SHOW : SW_HIDE);
+	if (si->iType != GCW_SERVER)
+		ShowWindow(GetDlgItem(hwndDlg, IDC_LIST), si->bNicklistEnabled ? SW_SHOW : SW_HIDE);
+	else
+		ShowWindow(GetDlgItem(hwndDlg, IDC_LIST), SW_HIDE);
+
+	if (si->iType == GCW_SERVER) {
+		EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWNICKLIST), FALSE);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_FILTER), FALSE);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_CHANMGR), FALSE);
+	}
+	else {
+		EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWNICKLIST), TRUE);
+		EnableWindow(GetDlgItem(hwndDlg, IDC_FILTER), TRUE);
+		if (si->iType == GCW_CHATROOM)
+			EnableWindow(GetDlgItem(hwndDlg, IDC_CHANMGR), pci->MM_FindModule(si->pszModule)->bChanMgr);
+	}
+
+	switch (urc->wId) {
+	case IDOK:
+		GetWindowRect(si->hwndStatus, &rc);
+		urc->rcItem.left = bSend ? 315 : urc->dlgNewSize.cx;
+		urc->rcItem.top = urc->dlgNewSize.cy - si->iSplitterY + 23;
+		urc->rcItem.bottom = urc->dlgNewSize.cy - (rc.bottom - rc.top) - 1;
+		return RD_ANCHORX_RIGHT | RD_ANCHORY_CUSTOM;
+
+	case IDC_TAB:
+		urc->rcItem.top = 1;
+		urc->rcItem.left = 0;
+		urc->rcItem.right = urc->dlgNewSize.cx - 24;
+		urc->rcItem.bottom = urc->dlgNewSize.cy - si->iSplitterY;
+		if (!bToolbar)
+			urc->rcItem.bottom += 20;
+		return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM;
+
+	case IDC_LOG:
+		urc->rcItem.top = bTabs ? (bTabBottom ? 0 : rcTabs.top - 1) : 0;
+		urc->rcItem.left = 0;
+		urc->rcItem.right = bNick ? urc->dlgNewSize.cx - si->iSplitterX : urc->dlgNewSize.cx;
+	LBL_CalcBottom:
+		urc->rcItem.bottom = urc->dlgNewSize.cy - si->iSplitterY;
+		if (bTabs && bTabBottom) urc->rcItem.bottom += 6 - TabHeight;
+		if (!bToolbar) urc->rcItem.bottom += 20;
+		return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM;
+
+	case IDC_LIST:
+		urc->rcItem.top = bTabs ? (bTabBottom ? 0 : rcTabs.top - 1) : 0;
+		urc->rcItem.right = urc->dlgNewSize.cx;
+		urc->rcItem.left = urc->dlgNewSize.cx - si->iSplitterX + 2;
+		goto LBL_CalcBottom;
+
+	case IDC_SPLITTERX:
+		urc->rcItem.top = bTabs ? rcTabs.top : 1;
+		urc->rcItem.left = urc->dlgNewSize.cx - si->iSplitterX;
+		urc->rcItem.right = urc->rcItem.left + 2;
+		goto LBL_CalcBottom;
+
+	case IDC_SPLITTERY:
+		urc->rcItem.top = urc->dlgNewSize.cy - si->iSplitterY;
+		if (!bToolbar)
+			urc->rcItem.top += 20;
+		urc->rcItem.bottom = urc->rcItem.top + 2;
+		return RD_ANCHORX_WIDTH | RD_ANCHORY_CUSTOM;
+
+	case IDC_MESSAGE:
+		GetWindowRect(si->hwndStatus, &rc);
+		urc->rcItem.right = bSend ? urc->dlgNewSize.cx - 64 : urc->dlgNewSize.cx;
+		urc->rcItem.top = urc->dlgNewSize.cy - si->iSplitterY + 22;
+		urc->rcItem.bottom = urc->dlgNewSize.cy - (rc.bottom - rc.top) - 1;
+		return RD_ANCHORX_LEFT | RD_ANCHORY_CUSTOM;
+
+	case IDC_SMILEY:
+	case IDC_ITALICS:
+	case IDC_BOLD:
+	case IDC_UNDERLINE:
+	case IDC_COLOR:
+	case IDC_BKGCOLOR:
+		urc->rcItem.top = urc->dlgNewSize.cy - si->iSplitterY + 3;
+		urc->rcItem.bottom = urc->rcItem.top + 16;
+		return RD_ANCHORX_LEFT | RD_ANCHORY_CUSTOM;
+
+	case IDC_HISTORY:
+	case IDC_CHANMGR:
+	case IDC_SHOWNICKLIST:
+	case IDC_FILTER:
+		urc->rcItem.top = urc->dlgNewSize.cy - si->iSplitterY + 3;
+		urc->rcItem.bottom = urc->rcItem.top + 16;
+		return RD_ANCHORX_RIGHT | RD_ANCHORY_CUSTOM;
+
+	case IDC_CLOSE:
+		urc->rcItem.left = urc->dlgNewSize.cx - 19;
+		urc->rcItem.right = urc->rcItem.left + 16;
+		urc->rcItem.top = bTabBottom ? (bToolbar ? urc->dlgNewSize.cy - si->iSplitterY - 18 : urc->dlgNewSize.cy - si->iSplitterY - 18 + 20) : 3;
+		urc->rcItem.bottom = urc->rcItem.top + 16;
+		return RD_ANCHORX_CUSTOM | RD_ANCHORY_CUSTOM;
+	}
+	return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+}
+
+static LRESULT CALLBACK MessageSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	SESSION_INFO *Parentsi = (SESSION_INFO*)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
+	MESSAGESUBDATA *dat = (MESSAGESUBDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+	switch (msg) {
+	case EM_SUBCLASSED:
+		dat = (MESSAGESUBDATA*)mir_alloc(sizeof(MESSAGESUBDATA));
+
+		SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)dat);
+		dat->szTabSave[0] = '\0';
+		dat->lastEnterTime = 0;
+		return 0;
+
+	case WM_MOUSEWHEEL:
+		SendDlgItemMessage(GetParent(hwnd), IDC_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_CHAR:
+		{
+			BOOL isCtrl = GetKeyState(VK_CONTROL) & 0x8000;
+			BOOL isAlt = GetKeyState(VK_MENU) & 0x8000;
+
+			if (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY)
+				break;
+
+			if (wParam == 9 && isCtrl && !isAlt) // ctrl-i (italics)
+				return TRUE;
+
+			if (wParam == VK_SPACE && isCtrl && !isAlt) // ctrl-space (paste clean text)
+				return TRUE;
+
+			if (wParam == '\n' || wParam == '\r') {
+				if ((isCtrl != 0) ^ (0 != db_get_b(NULL, CHAT_MODULE, "SendOnEnter", 1))) {
+					PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0);
+					return 0;
+				}
+				if (db_get_b(NULL, CHAT_MODULE, "SendOnDblEnter", 0)) {
+					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 == 1 && isCtrl && !isAlt) {      //ctrl-a
+				SendMessage(hwnd, EM_SETSEL, 0, -1);
+				return 0;
+			}
+		}
+		break;
+
+	case WM_KEYDOWN:
+		{
+			static int start, end;
+			BOOL isShift = GetKeyState(VK_SHIFT) & 0x8000;
+			BOOL isCtrl = GetKeyState(VK_CONTROL) & 0x8000;
+			BOOL isAlt = GetKeyState(VK_MENU) & 0x8000;
+			if (wParam == VK_RETURN) {
+				dat->szTabSave[0] = '\0';
+				if ((isCtrl != 0) ^ (0 != db_get_b(NULL, CHAT_MODULE, "SendOnEnter", 1)))
+					return 0;
+
+				if (db_get_b(NULL, CHAT_MODULE, "SendOnDblEnter", 0))
+					if (dat->lastEnterTime + 2 >= time(NULL))
+						return 0;
+
+				break;
+			}
+
+			if (wParam == VK_TAB && isShift && !isCtrl) { // SHIFT-TAB (go to nick list)
+				SetFocus(GetDlgItem(GetParent(hwnd), IDC_LIST));
+				return TRUE;
+			}
+
+			if (wParam == VK_TAB && isCtrl && !isShift) { // CTRL-TAB (switch tab/window)
+				if (g_Settings.bTabsEnable)
+					SendMessage(GetParent(hwnd), GC_SWITCHNEXTTAB, 0, 0);
+				else
+					pci->ShowRoom(SM_GetNextWindow(Parentsi), WINDOW_VISIBLE, TRUE);
+				return TRUE;
+			}
+
+			if (wParam == VK_TAB && isCtrl && isShift) { // CTRL_SHIFT-TAB (switch tab/window)
+				if (g_Settings.bTabsEnable)
+					SendMessage(GetParent(hwnd), GC_SWITCHPREVTAB, 0, 0);
+				else
+					pci->ShowRoom(SM_GetPrevWindow(Parentsi), WINDOW_VISIBLE, TRUE);
+				return TRUE;
+			}
+
+			if (wParam <= '9' && wParam >= '1' && isCtrl && !isAlt) // CTRL + 1 -> 9 (switch tab)
+				if (g_Settings.bTabsEnable)
+					SendMessage(GetParent(hwnd), GC_SWITCHTAB, 0, (int)wParam - (int)'1');
+
+			if (wParam <= VK_NUMPAD9 && wParam >= VK_NUMPAD1 && isCtrl && !isAlt) // CTRL + 1 -> 9 (switch tab)
+				if (g_Settings.bTabsEnable)
+					SendMessage(GetParent(hwnd), GC_SWITCHTAB, 0, (int)wParam - (int)VK_NUMPAD1);
+
+			if (wParam == VK_TAB && !isCtrl && !isShift) {    //tab-autocomplete
+				wchar_t* pszText = NULL;
+				LRESULT lResult = (LRESULT)SendMessage(hwnd, EM_GETSEL, 0, 0);
+
+				SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+				start = LOWORD(lResult);
+				end = HIWORD(lResult);
+				SendMessage(hwnd, EM_SETSEL, end, end);
+
+				GETTEXTLENGTHEX gtl = { 0 };
+				gtl.flags = GTL_PRECISE;
+				gtl.codepage = CP_ACP;
+				int iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
+				if (iLen > 0) {
+					pszText = (wchar_t *)mir_alloc(sizeof(wchar_t)*(iLen + 100));
+
+					GETTEXTEX gt = { 0 };
+					gt.cb = iLen + 99;
+					gt.flags = GT_DEFAULT;
+					gt.codepage = 1200;
+
+					SendMessage(hwnd, EM_GETTEXTEX, (WPARAM)&gt, (LPARAM)pszText);
+					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 (dat->szTabSave[0] == '\0')
+						mir_wstrncpy(dat->szTabSave, pszText + start, end - start + 1);
+
+					wchar_t *pszSelName = (wchar_t *)mir_alloc(sizeof(wchar_t)*(end - start + 1));
+					mir_wstrncpy(pszSelName, pszText + start, end - start + 1);
+
+					wchar_t *pszName = pci->UM_FindUserAutoComplete(Parentsi->pUsers, dat->szTabSave, pszSelName);
+					if (pszName == NULL) {
+						pszName = dat->szTabSave;
+						SendMessage(hwnd, EM_SETSEL, start, end);
+						if (end != start)
+							SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM)pszName);
+						dat->szTabSave[0] = '\0';
+					}
+					else {
+						SendMessage(hwnd, EM_SETSEL, start, end);
+						if (end != start)
+							SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM)pszName);
+					}
+					mir_free(pszText);
+					mir_free(pszSelName);
+				}
+
+				SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+				RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+				return 0;
+			}
+
+			if (dat->szTabSave[0] != '\0' && wParam != VK_RIGHT && wParam != VK_LEFT && wParam != VK_SPACE && wParam != VK_RETURN && wParam != VK_BACK && wParam != VK_DELETE) {
+				if (g_Settings.bAddColonToAutoComplete && start == 0)
+					SendMessageA(hwnd, EM_REPLACESEL, FALSE, (LPARAM) ": ");
+
+				dat->szTabSave[0] = '\0';
+			}
+
+			if (wParam == VK_F4 && isCtrl && !isAlt) { // ctrl-F4 (close tab)
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CLOSE, BN_CLICKED), 0);
+				return TRUE;
+			}
+
+			if (wParam == 0x49 && isCtrl && !isAlt) { // ctrl-i (italics)
+				CheckDlgButton(GetParent(hwnd), IDC_ITALICS, IsDlgButtonChecked(GetParent(hwnd), IDC_ITALICS) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED);
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_ITALICS, 0), 0);
+				return TRUE;
+			}
+
+			if (wParam == 0x42 && isCtrl && !isAlt) { // ctrl-b (bold)
+				CheckDlgButton(GetParent(hwnd), IDC_BOLD, IsDlgButtonChecked(GetParent(hwnd), IDC_BOLD) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED);
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_BOLD, 0), 0);
+				return TRUE;
+			}
+
+			if (wParam == 0x55 && isCtrl && !isAlt) { // ctrl-u (paste clean text)
+				CheckDlgButton(GetParent(hwnd), IDC_UNDERLINE, IsDlgButtonChecked(GetParent(hwnd), IDC_UNDERLINE) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED);
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_UNDERLINE, 0), 0);
+				return TRUE;
+			}
+
+			if (wParam == 0x4b && isCtrl && !isAlt) { // ctrl-k (paste clean text)
+				CheckDlgButton(GetParent(hwnd), IDC_COLOR, IsDlgButtonChecked(GetParent(hwnd), IDC_COLOR) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED);
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_COLOR, 0), 0);
+				return TRUE;
+			}
+
+			if (wParam == VK_SPACE && isCtrl && !isAlt) { // ctrl-space (paste clean text)
+				CheckDlgButton(GetParent(hwnd), IDC_BKGCOLOR, BST_UNCHECKED);
+				CheckDlgButton(GetParent(hwnd), IDC_COLOR, BST_UNCHECKED);
+				CheckDlgButton(GetParent(hwnd), IDC_BOLD, BST_UNCHECKED);
+				CheckDlgButton(GetParent(hwnd), IDC_UNDERLINE, BST_UNCHECKED);
+				CheckDlgButton(GetParent(hwnd), IDC_ITALICS, BST_UNCHECKED);
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_BKGCOLOR, 0), 0);
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_COLOR, 0), 0);
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_BOLD, 0), 0);
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_UNDERLINE, 0), 0);
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_ITALICS, 0), 0);
+				return TRUE;
+			}
+
+			if (wParam == 0x4c && isCtrl && !isAlt) { // ctrl-l (paste clean text)
+				CheckDlgButton(GetParent(hwnd), IDC_BKGCOLOR, IsDlgButtonChecked(GetParent(hwnd), IDC_BKGCOLOR) == BST_UNCHECKED ? BST_CHECKED : BST_UNCHECKED);
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_BKGCOLOR, 0), 0);
+				return TRUE;
+			}
+
+			if (wParam == 0x46 && isCtrl && !isAlt) { // ctrl-f (paste clean text)
+				if (IsWindowEnabled(GetDlgItem(GetParent(hwnd), IDC_FILTER)))
+					SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_FILTER, 0), 0);
+				return TRUE;
+			}
+
+			if (wParam == 0x4e && isCtrl && !isAlt) { // ctrl-n (nicklist)
+				if (IsWindowEnabled(GetDlgItem(GetParent(hwnd), IDC_SHOWNICKLIST)))
+					SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_SHOWNICKLIST, 0), 0);
+				return TRUE;
+			}
+
+			if (wParam == 0x48 && isCtrl && !isAlt) { // ctrl-h (history)
+				SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_HISTORY, 0), 0);
+				return TRUE;
+			}
+
+			if (wParam == 0x4f && isCtrl && !isAlt) { // ctrl-o (options)
+				if (IsWindowEnabled(GetDlgItem(GetParent(hwnd), IDC_CHANMGR)))
+					SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CHANMGR, 0), 0);
+				return TRUE;
+			}
+
+			if ((wParam == 45 && isShift || wParam == 0x56 && isCtrl) && !isAlt) { // ctrl-v (paste clean text)
+				SendMessage(hwnd, EM_PASTESPECIAL, CF_TEXT, 0);
+				return TRUE;
+			}
+
+			if (wParam == 0x57 && isCtrl && !isAlt) { // ctrl-w (close window)
+				PostMessage(GetParent(hwnd), WM_CLOSE, 0, 0);
+				return TRUE;
+			}
+
+			if (wParam == VK_NEXT || wParam == VK_PRIOR) {
+				HWND htemp = GetParent(hwnd);
+				SendDlgItemMessage(htemp, IDC_LOG, msg, wParam, lParam);
+				dat->lastEnterTime = 0;
+				return TRUE;
+			}
+
+			if (wParam == VK_UP && isCtrl && !isAlt) {
+				char* lpPrevCmd = pci->SM_GetPrevCommand(Parentsi->ptszID, Parentsi->pszModule);
+
+				SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+
+				if (lpPrevCmd) {
+					SETTEXTEX ste;
+					ste.flags = ST_DEFAULT;
+					ste.codepage = CP_ACP;
+					SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpPrevCmd);
+				}
+				else SetWindowText(hwnd, L"");
+
+				GETTEXTLENGTHEX gtl = { 0 };
+				gtl.flags = GTL_PRECISE;
+				gtl.codepage = CP_ACP;
+				int iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
+				SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
+				SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+				RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+				SendMessage(hwnd, EM_SETSEL, iLen, iLen);
+				dat->lastEnterTime = 0;
+				return TRUE;
+			}
+
+			if (wParam == VK_DOWN && isCtrl && !isAlt) {
+				char* lpPrevCmd = pci->SM_GetNextCommand(Parentsi->ptszID, Parentsi->pszModule);
+				SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
+
+				if (lpPrevCmd) {
+					SETTEXTEX ste;
+					ste.flags = ST_DEFAULT;
+					ste.codepage = CP_ACP;
+					SendMessage(hwnd, EM_SETTEXTEX, (WPARAM)&ste, (LPARAM)lpPrevCmd);
+				}
+				else SetWindowText(hwnd, L"");
+
+				GETTEXTLENGTHEX gtl = { 0 };
+				gtl.flags = GTL_PRECISE;
+				gtl.codepage = CP_ACP;
+				int iLen = SendMessage(hwnd, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
+				SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
+				SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
+				RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+				SendMessage(hwnd, EM_SETSEL, iLen, iLen);
+				dat->lastEnterTime = 0;
+				return TRUE;
+			}
+		}
+		//fall through
+
+	case WM_LBUTTONDOWN:
+	case WM_MBUTTONDOWN:
+	case WM_KILLFOCUS:
+		dat->lastEnterTime = 0;
+		break;
+
+	case WM_RBUTTONDOWN:
+		{
+			CHARRANGE sel, all = { 0, -1 };
+			HMENU hSubMenu = GetSubMenu(g_hMenu, 4);
+			TranslateMenu(hSubMenu);
+			SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
+
+			EnableMenuItem(hSubMenu, ID_MESSAGE_UNDO, SendMessage(hwnd, EM_CANUNDO, 0, 0) ? MF_ENABLED : MF_GRAYED);
+			EnableMenuItem(hSubMenu, ID_MESSAGE_REDO, SendMessage(hwnd, EM_CANREDO, 0, 0) ? MF_ENABLED : MF_GRAYED);
+			EnableMenuItem(hSubMenu, ID_MESSAGE_COPY, sel.cpMax != sel.cpMin ? MF_ENABLED : MF_GRAYED);
+			EnableMenuItem(hSubMenu, ID_MESSAGE_CUT, sel.cpMax != sel.cpMin ? MF_ENABLED : MF_GRAYED);
+
+			dat->lastEnterTime = 0;
+
+			POINT pt;
+			pt.x = (short)LOWORD(lParam);
+			pt.y = (short)HIWORD(lParam);
+			ClientToScreen(hwnd, &pt);
+
+			UINT uID = TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL);
+			switch (uID) {
+			case 0:
+				break;
+
+			case ID_MESSAGE_UNDO:
+				SendMessage(hwnd, EM_UNDO, 0, 0);
+				break;
+
+			case ID_MESSAGE_REDO:
+				SendMessage(hwnd, EM_REDO, 0, 0);
+				break;
+
+			case ID_MESSAGE_COPY:
+				SendMessage(hwnd, WM_COPY, 0, 0);
+				break;
+
+			case ID_MESSAGE_CUT:
+				SendMessage(hwnd, WM_CUT, 0, 0);
+				break;
+
+			case ID_MESSAGE_PASTE:
+				SendMessage(hwnd, EM_PASTESPECIAL, CF_TEXT, 0);
+				break;
+
+			case ID_MESSAGE_SELECTALL:
+				SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)& all);
+				break;
+
+			case ID_MESSAGE_CLEAR:
+				SetWindowText(hwnd, L"");
+				break;
+			}
+			PostMessage(hwnd, WM_KEYUP, 0, 0);
+		}
+		break;
+
+	case WM_KEYUP:
+	case WM_LBUTTONUP:
+	case WM_RBUTTONUP:
+	case WM_MBUTTONUP:
+		{
+			CHARFORMAT2 cf;
+			cf.cbSize = sizeof(CHARFORMAT2);
+			cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_BACKCOLOR | CFM_COLOR;
+			SendMessage(hwnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+
+			MODULEINFO *pmi = pci->MM_FindModule(Parentsi->pszModule);
+			if (pmi && pmi->bColor) {
+				int index = GetColorIndex(Parentsi->pszModule, cf.crTextColor);
+				UINT u = IsDlgButtonChecked(GetParent(hwnd), IDC_COLOR);
+
+				if (index >= 0) {
+					Parentsi->bFGSet = TRUE;
+					Parentsi->iFG = index;
+				}
+
+				if (u == BST_UNCHECKED && cf.crTextColor != g_Settings.MessageAreaColor)
+					CheckDlgButton(GetParent(hwnd), IDC_COLOR, BST_CHECKED);
+				else if (u == BST_CHECKED && cf.crTextColor == g_Settings.MessageAreaColor)
+					CheckDlgButton(GetParent(hwnd), IDC_COLOR, BST_UNCHECKED);
+			}
+
+			if (pmi && pmi->bBkgColor) {
+				int index = GetColorIndex(Parentsi->pszModule, cf.crBackColor);
+				COLORREF crB = (COLORREF)db_get_dw(NULL, CHAT_MODULE, "ColorMessageBG", GetSysColor(COLOR_WINDOW));
+				UINT u = IsDlgButtonChecked(GetParent(hwnd), IDC_BKGCOLOR);
+
+				if (index >= 0) {
+					Parentsi->bBGSet = TRUE;
+					Parentsi->iBG = index;
+				}
+				if (u == BST_UNCHECKED && cf.crBackColor != crB)
+					CheckDlgButton(GetParent(hwnd), IDC_BKGCOLOR, BST_CHECKED);
+				else if (u == BST_CHECKED && cf.crBackColor == crB)
+					CheckDlgButton(GetParent(hwnd), IDC_BKGCOLOR, BST_UNCHECKED);
+			}
+
+			if (pmi && pmi->bBold) {
+				UINT u = IsDlgButtonChecked(GetParent(hwnd), IDC_BOLD);
+				UINT u2 = cf.dwEffects;
+				u2 &= CFE_BOLD;
+				if (u == BST_UNCHECKED && u2)
+					CheckDlgButton(GetParent(hwnd), IDC_BOLD, BST_CHECKED);
+				else if (u == BST_CHECKED && u2 == 0)
+					CheckDlgButton(GetParent(hwnd), IDC_BOLD, BST_UNCHECKED);
+			}
+
+			if (pmi && pmi->bItalics) {
+				UINT u = IsDlgButtonChecked(GetParent(hwnd), IDC_ITALICS);
+				UINT u2 = cf.dwEffects;
+				u2 &= CFE_ITALIC;
+				if (u == BST_UNCHECKED && u2)
+					CheckDlgButton(GetParent(hwnd), IDC_ITALICS, BST_CHECKED);
+				else if (u == BST_CHECKED && u2 == 0)
+					CheckDlgButton(GetParent(hwnd), IDC_ITALICS, BST_UNCHECKED);
+			}
+
+			if (pmi && pmi->bUnderline) {
+				UINT u = IsDlgButtonChecked(GetParent(hwnd), IDC_UNDERLINE);
+				UINT u2 = cf.dwEffects;
+				u2 &= CFE_UNDERLINE;
+				if (u == BST_UNCHECKED && u2)
+					CheckDlgButton(GetParent(hwnd), IDC_UNDERLINE, BST_CHECKED);
+				else if (u == BST_CHECKED && u2 == 0)
+					CheckDlgButton(GetParent(hwnd), IDC_UNDERLINE, BST_UNCHECKED);
+			}
+		}
+		break;
+
+	case WM_DESTROY:
+		mir_free(dat);
+		return 0;
+	}
+
+	return mir_callNextSubclass(hwnd, MessageSubclassProc, 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_1, si->iLogFilterFlags & GC_EVENT_ACTION ? BST_CHECKED : BST_UNCHECKED);
+		CheckDlgButton(hwndDlg, IDC_2, si->iLogFilterFlags & GC_EVENT_MESSAGE ? BST_CHECKED : BST_UNCHECKED);
+		CheckDlgButton(hwndDlg, IDC_3, si->iLogFilterFlags & GC_EVENT_NICK ? BST_CHECKED : BST_UNCHECKED);
+		CheckDlgButton(hwndDlg, IDC_4, si->iLogFilterFlags & GC_EVENT_JOIN ? BST_CHECKED : BST_UNCHECKED);
+		CheckDlgButton(hwndDlg, IDC_5, si->iLogFilterFlags & GC_EVENT_PART ? BST_CHECKED : BST_UNCHECKED);
+		CheckDlgButton(hwndDlg, IDC_6, si->iLogFilterFlags & GC_EVENT_TOPIC ? BST_CHECKED : BST_UNCHECKED);
+		CheckDlgButton(hwndDlg, IDC_7, si->iLogFilterFlags & GC_EVENT_ADDSTATUS ? BST_CHECKED : BST_UNCHECKED);
+		CheckDlgButton(hwndDlg, IDC_8, si->iLogFilterFlags & GC_EVENT_INFORMATION ? BST_CHECKED : BST_UNCHECKED);
+		CheckDlgButton(hwndDlg, IDC_9, si->iLogFilterFlags & GC_EVENT_QUIT ? BST_CHECKED : BST_UNCHECKED);
+		CheckDlgButton(hwndDlg, IDC_10, si->iLogFilterFlags & GC_EVENT_KICK ? BST_CHECKED : BST_UNCHECKED);
+		CheckDlgButton(hwndDlg, IDC_11, si->iLogFilterFlags & GC_EVENT_NOTICE ? BST_CHECKED : BST_UNCHECKED);
+		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_1) == BST_CHECKED)
+				iFlags |= GC_EVENT_ACTION;
+			if (IsDlgButtonChecked(hwndDlg, IDC_2) == BST_CHECKED)
+				iFlags |= GC_EVENT_MESSAGE;
+			if (IsDlgButtonChecked(hwndDlg, IDC_3) == BST_CHECKED)
+				iFlags |= GC_EVENT_NICK;
+			if (IsDlgButtonChecked(hwndDlg, IDC_4) == BST_CHECKED)
+				iFlags |= GC_EVENT_JOIN;
+			if (IsDlgButtonChecked(hwndDlg, IDC_5) == BST_CHECKED)
+				iFlags |= GC_EVENT_PART;
+			if (IsDlgButtonChecked(hwndDlg, IDC_6) == BST_CHECKED)
+				iFlags |= GC_EVENT_TOPIC;
+			if (IsDlgButtonChecked(hwndDlg, IDC_7) == BST_CHECKED)
+				iFlags |= GC_EVENT_ADDSTATUS;
+			if (IsDlgButtonChecked(hwndDlg, IDC_8) == BST_CHECKED)
+				iFlags |= GC_EVENT_INFORMATION;
+			if (IsDlgButtonChecked(hwndDlg, IDC_9) == BST_CHECKED)
+				iFlags |= GC_EVENT_QUIT;
+			if (IsDlgButtonChecked(hwndDlg, IDC_10) == BST_CHECKED)
+				iFlags |= GC_EVENT_KICK;
+			if (IsDlgButtonChecked(hwndDlg, IDC_11) == BST_CHECKED)
+				iFlags |= GC_EVENT_NOTICE;
+
+			if (iFlags&GC_EVENT_ADDSTATUS)
+				iFlags |= GC_EVENT_REMOVESTATUS;
+
+			SendMessage(GetParent(hwndDlg), GC_CHANGEFILTERFLAG, 0, (LPARAM)iFlags);
+			if (si->bFilterEnabled)
+				SendMessage(GetParent(hwndDlg), 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:
+		if (db_get_b(NULL, CHAT_MODULE, "RightClickFilter", 0) != 0) {
+			if (GetDlgItem(GetParent(hwnd), IDC_FILTER) == hwnd)
+				SendMessage(GetParent(hwnd), GC_SHOWFILTERMENU, 0, 0);
+			if (GetDlgItem(GetParent(hwnd), IDC_COLOR) == hwnd)
+				SendMessage(GetParent(hwnd), GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_COLOR);
+			if (GetDlgItem(GetParent(hwnd), IDC_BKGCOLOR) == hwnd)
+				SendMessage(GetParent(hwnd), GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_BKGCOLOR);
+		}
+		break;
+	}
+
+	return mir_callNextSubclass(hwnd, ButtonSubclassProc, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK LogSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	switch (msg) {
+	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_MESSAGE));
+		}
+		break;
+	case WM_KEYDOWN:
+		if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window)
+			PostMessage(GetParent(hwnd), WM_CLOSE, 0, 0);
+			return TRUE;
+		}
+		break;
+
+	case WM_ACTIVATE:
+		if (LOWORD(wParam) == WA_INACTIVE) {
+			CHARRANGE sel;
+			SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
+			if (sel.cpMin != sel.cpMax) {
+				sel.cpMin = sel.cpMax;
+				SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
+			}
+		}
+		break;
+
+	case WM_CHAR:
+		SetFocus(GetDlgItem(GetParent(hwnd), IDC_MESSAGE));
+		SendDlgItemMessage(GetParent(hwnd), IDC_MESSAGE, WM_CHAR, wParam, lParam);
+		break;
+	}
+
+	return mir_callNextSubclass(hwnd, LogSubclassProc, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK TabSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	static BOOL bDragging = FALSE;
+	static int iBeginIndex = 0;
+	switch (msg) {
+	case WM_LBUTTONDOWN:
+		{
+			TCHITTESTINFO tci = { 0 };
+			tci.pt.x = (short)LOWORD(GetMessagePos());
+			tci.pt.y = (short)HIWORD(GetMessagePos());
+			if (DragDetect(hwnd, tci.pt) && TabCtrl_GetItemCount(hwnd) > 1) {
+				int i;
+				tci.flags = TCHT_ONITEM;
+
+				ScreenToClient(hwnd, &tci.pt);
+				i = TabCtrl_HitTest(hwnd, &tci);
+				if (i != -1) {
+					TCITEM tc;
+					SESSION_INFO *s = NULL;
+
+					tc.mask = TCIF_PARAM;
+					TabCtrl_GetItem(hwnd, i, &tc);
+					s = (SESSION_INFO*)tc.lParam;
+					if (s) {
+						BOOL bOnline = db_get_w(s->hContact, s->pszModule, "Status", ID_STATUS_OFFLINE) == ID_STATUS_ONLINE ? TRUE : FALSE;
+						MODULEINFO *mi = pci->MM_FindModule(s->pszModule);
+						bDragging = TRUE;
+						iBeginIndex = i;
+						ImageList_BeginDrag(hIconsList, bOnline ? mi->OnlineIconIndex : mi->OfflineIconIndex, 8, 8);
+						ImageList_DragEnter(hwnd, tci.pt.x, tci.pt.y);
+						SetCapture(hwnd);
+					}
+					return TRUE;
+				}
+			}
+			else PostMessage(GetParent(hwnd), GC_TABCLICKED, 0, 0);
+		}
+		break;
+
+	case WM_CAPTURECHANGED:
+		bDragging = FALSE;
+		ImageList_DragLeave(hwnd);
+		ImageList_EndDrag();
+		break;
+
+	case WM_MOUSEMOVE:
+		if (bDragging) {
+			TCHITTESTINFO tci = { 0 };
+			tci.pt.x = (short)LOWORD(GetMessagePos());
+			tci.pt.y = (short)HIWORD(GetMessagePos());
+			ScreenToClient(hwnd, &tci.pt);
+			ImageList_DragMove(tci.pt.x, tci.pt.y);
+		}
+		break;
+
+	case WM_LBUTTONUP:
+		if (bDragging && ReleaseCapture()) {
+			TCHITTESTINFO tci = { 0 };
+			tci.pt.x = (short)LOWORD(GetMessagePos());
+			tci.pt.y = (short)HIWORD(GetMessagePos());
+			tci.flags = TCHT_ONITEM;
+			bDragging = FALSE;
+			ImageList_DragLeave(hwnd);
+			ImageList_EndDrag();
+
+			ScreenToClient(hwnd, &tci.pt);
+			int i = TabCtrl_HitTest(hwnd, &tci);
+			if (i != -1 && i != iBeginIndex)
+				SendMessage(GetParent(hwnd), GC_DROPPEDTAB, (WPARAM)i, (LPARAM)iBeginIndex);
+		}
+		break;
+
+	case WM_LBUTTONDBLCLK:
+		{
+			TCHITTESTINFO tci = { 0 };
+			tci.pt.x = (short)LOWORD(GetMessagePos());
+			tci.pt.y = (short)HIWORD(GetMessagePos());
+			tci.flags = TCHT_ONITEM;
+
+			ScreenToClient(hwnd, &tci.pt);
+			int i = TabCtrl_HitTest(hwnd, &tci);
+			if (i != -1 && g_Settings.TabCloseOnDblClick)
+				PostMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(IDC_CLOSE, BN_CLICKED), 0);
+		}
+		break;
+
+	case WM_MBUTTONUP:
+		TCHITTESTINFO tci = { 0 };
+		tci.pt.x = (short)LOWORD(GetMessagePos());
+		tci.pt.y = (short)HIWORD(GetMessagePos());
+		tci.flags = TCHT_ONITEM;
+
+		ScreenToClient(hwnd, &tci.pt);
+		int i = TabCtrl_HitTest(hwnd, &tci);
+		if (i != -1) {
+			TCITEM tc;
+			tc.mask = TCIF_PARAM;
+			TabCtrl_GetItem(hwnd, i, &tc);
+			SESSION_INFO *si = (SESSION_INFO*)tc.lParam;
+			if (si)
+				SendMessage(GetParent(hwnd), GC_REMOVETAB, 1, (LPARAM)si);
+		}
+		break;
+	}
+
+	return mir_callNextSubclass(hwnd, TabSubclassProc, msg, wParam, lParam);
+}
+
+static void ProcessNickListHovering(HWND hwnd, int hoveredItem, SESSION_INFO *si)
+{
+	static int currentHovered = -1;
+	static HWND hwndToolTip = NULL;
+	static HWND oldParent = 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);
+		return;
+	}
+
+	BOOL bNewTip = FALSE;
+	if (!hwndToolTip) {
+		hwndToolTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
+			WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
+			CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+			hwnd, NULL, g_hInst, NULL);
+		bNewTip = TRUE;
+	}
+
+	RECT clientRect;
+	GetClientRect(hwnd, &clientRect);
+	TOOLINFO ti = { sizeof(TOOLINFO) };
+	ti.uFlags = TTF_SUBCLASS;
+	ti.hinst = g_hInst;
+	ti.hwnd = hwnd;
+	ti.uId = 1;
+	ti.rect = clientRect;
+
+	wchar_t tszBuf[1024]; tszBuf[0] = 0;
+	USERINFO *ui = pci->SM_GetUserFromIndex(si->ptszID, si->pszModule, currentHovered);
+	if (ui) {
+		if (ProtoServiceExists(si->pszModule, MS_GC_PROTO_GETTOOLTIPTEXT)) {
+			wchar_t *p = (wchar_t*)CallProtoService(si->pszModule, MS_GC_PROTO_GETTOOLTIPTEXT, (WPARAM)si->ptszID, (LPARAM)ui->pszUID);
+			if (p != NULL) {
+				wcsncpy_s(tszBuf, p, _TRUNCATE);
+				mir_free(p);
+			}
+		}
+
+		if (tszBuf[0] == 0)
+			mir_snwprintf(tszBuf, L"%s: %s\r\n%s: %s\r\n%s: %s",
+				TranslateT("Nickname"), ui->pszNick,
+				TranslateT("Unique ID"), ui->pszUID,
+				TranslateT("Status"), pci->TM_WordToString(si->pStatuses, ui->Status));
+
+		ti.lpszText = tszBuf;
+	}
+
+	SendMessage(hwndToolTip, bNewTip ? TTM_ADDTOOL : TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
+	SendMessage(hwndToolTip, TTM_ACTIVATE, ti.lpszText != NULL, 0);
+	SendMessage(hwndToolTip, TTM_SETMAXTIPWIDTH, 0, 400);
+}
+
+static LRESULT CALLBACK NicklistSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	SESSION_INFO *si = (SESSION_INFO*)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
+
+	switch (msg) {
+	case WM_ERASEBKGND:
+		{
+			HDC dc = (HDC)wParam;
+			if (dc == NULL)
+				return 0;
+
+			int index = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0);
+			if (index == LB_ERR || si->nUsersInNicklist <= 0)
+				return 0;
+
+			int height = SendMessage(hwnd, LB_GETITEMHEIGHT, 0, 0);
+			if (height == LB_ERR)
+				return 0;
+
+			RECT rc = { 0 };
+			GetClientRect(hwnd, &rc);
+
+			int items = si->nUsersInNicklist - index;
+			if (rc.bottom - rc.top > items * height) {
+				rc.top = items * height;
+				FillRect(dc, &rc, pci->hListBkgBrush);
+			}
+		}
+		return 1;
+
+	case WM_KEYDOWN:
+		if (wParam == 0x57 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-w (close window)
+			PostMessage(GetParent(hwnd), WM_CLOSE, 0, 0);
+			return TRUE;
+		}
+		break;
+
+	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 Menu_MeasureItem(lParam);
+		}
+		return FALSE;
+
+	case WM_DRAWITEM:
+		{
+			DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
+			if (dis->CtlType == ODT_MENU)
+				return Menu_DrawItem(lParam);
+		}
+		return FALSE;
+
+	case WM_CONTEXTMENU:
+		TVHITTESTINFO hti;
+		{
+			int height = 0;
+			hti.pt.x = GET_X_LPARAM(lParam);
+			hti.pt.y = GET_Y_LPARAM(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);
+
+			int item = LOWORD(SendDlgItemMessage(GetParent(hwnd), IDC_LIST, LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y)));
+			USERINFO *ui = pci->SM_GetUserFromIndex(si->ptszID, si->pszModule, item);
+			if (ui) {
+				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);
+
+				HMENU hMenu = 0;
+				UINT uID = CreateGCMenu(hwnd, &hMenu, 0, hti.pt, si, uinew.pszUID, uinew.pszNick);
+				switch (uID) {
+				case 0:
+					break;
+
+				case ID_MESS:
+					pci->DoEventHookAsync(GetParent(hwnd), si->ptszID, si->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, 0);
+					break;
+
+				default:
+					pci->DoEventHookAsync(GetParent(hwnd), si->ptszID, si->pszModule, GC_USER_NICKLISTMENU, ui->pszUID, NULL, (LPARAM)uID);
+					break;
+				}
+				DestroyGCMenu(&hMenu, 1);
+				return TRUE;
+			}
+		}
+		break;
+
+	case WM_MOUSEMOVE:
+		POINT pt = { LOWORD(lParam), HIWORD(lParam) };
+		RECT clientRect;
+		GetClientRect(hwnd, &clientRect);
+		BOOL 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, si);
+		}
+		else ProcessNickListHovering(hwnd, -1, NULL);
+		break;
+	}
+
+	return mir_callNextSubclass(hwnd, NicklistSubclassProc, msg, wParam, lParam);
+}
+
+static int RestoreWindowPosition(HWND hwnd, MCONTACT hContact, char * szModule, char * szNamePrefix, UINT showCmd)
+{
+	WINDOWPLACEMENT wp;
+	wp.length = sizeof(wp);
+	GetWindowPlacement(hwnd, &wp);
+
+	char szSettingName[64];
+	mir_snprintf(szSettingName, "%sx", szNamePrefix);
+	int x = db_get_dw(hContact, szModule, szSettingName, -1);
+	mir_snprintf(szSettingName, "%sy", szNamePrefix);
+	int y = (int)db_get_dw(hContact, szModule, szSettingName, -1);
+	mir_snprintf(szSettingName, "%swidth", szNamePrefix);
+	int width = db_get_dw(hContact, szModule, szSettingName, -1);
+	mir_snprintf(szSettingName, "%sheight", szNamePrefix);
+	int height = db_get_dw(hContact, szModule, szSettingName, -1);
+
+	if (x == -1)
+		return 0;
+
+	wp.rcNormalPosition.left = x;
+	wp.rcNormalPosition.top = y;
+	wp.rcNormalPosition.right = wp.rcNormalPosition.left + width;
+	wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + height;
+	wp.showCmd = showCmd;
+	SetWindowPlacement(hwnd, &wp);
+	return 1;
+}
+
+int GetTextPixelSize(wchar_t* pszText, HFONT hFont, BOOL bWidth)
+{
+	if (!pszText || !hFont)
+		return 0;
+
+	HDC hdc = GetDC(NULL);
+	HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
+	RECT rc = { 0 };
+	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)
+{
+	SESSION_INFO *si = (SESSION_INFO*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+	RECT rc;
+
+	switch (uMsg) {
+	case WM_INITDIALOG:
+		TranslateDialogDefault(hwndDlg);
+		{
+			HWND hNickList = GetDlgItem(hwndDlg, IDC_LIST);
+			si = (SESSION_INFO*)lParam;
+			si->pAccPropServicesForNickList = NULL;
+			CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER, IID_IAccPropServices, (LPVOID *)si->pAccPropServicesForNickList);
+			TranslateDialogDefault(hwndDlg);
+			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)si);
+			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_SPLITTERX), SplitterSubclassProc);
+			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_SPLITTERY), SplitterSubclassProc);
+			mir_subclassWindow(hNickList, NicklistSubclassProc);
+			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_TAB), TabSubclassProc);
+			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_LOG), LogSubclassProc);
+			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_FILTER), ButtonSubclassProc);
+			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_COLOR), ButtonSubclassProc);
+			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_BKGCOLOR), ButtonSubclassProc);
+			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), MessageSubclassProc);
+			SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SUBCLASSED, 0, 0);
+			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_AUTOURLDETECT, 1, 0);
+			int mask = (int)SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETEVENTMASK, 0, 0);
+			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETEVENTMASK, 0, mask | ENM_LINK | ENM_MOUSEEVENTS);
+			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_LIMITTEXT, (WPARAM)sizeof(wchar_t) * 0x7FFFFFFF, 0);
+			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETOLECALLBACK, 0, (LPARAM)& reOleCallback);
+
+			si->hwndStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP | SBT_TOOLTIPS, 0, 0, 0, 0, hwndDlg, NULL, g_hInst, NULL);
+			SendMessage(si->hwndStatus, SB_SETMINHEIGHT, GetSystemMetrics(SM_CYSMICON), 0);
+			TabCtrl_SetMinTabWidth(GetDlgItem(hwndDlg, IDC_TAB), 80);
+			TabCtrl_SetImageList(GetDlgItem(hwndDlg, IDC_TAB), hIconsList);
+
+			// restore previous tabs
+			if (g_Settings.bTabsEnable && g_Settings.TabRestore) {
+				TABLIST *node = g_TabList;
+				while (node) {
+					SESSION_INFO *s = pci->SM_FindSession(node->pszID, node->pszModule);
+					if (s)
+						SendMessage(hwndDlg, GC_ADDTAB, -1, (LPARAM)s);
+
+					node = node->next;
+				}
+			}
+
+			TabM_RemoveAll();
+
+			EnableWindow(GetDlgItem(hwndDlg, IDC_SMILEY), TRUE);
+
+			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_HIDESELECTION, TRUE, 0);
+
+			SendMessage(hwndDlg, GC_SETWNDPROPS, 0, 0);
+			SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
+			SendMessage(hwndDlg, GC_UPDATETITLE, 0, 0);
+			SendMessage(hwndDlg, GC_SETWINDOWPOS, 0, 0);
+		}
+		break;
+
+	case GC_SETWNDPROPS:
+		{
+			// LoadGlobalSettings(); !!!!!!!!!!!!!!!!!!!!!!
+			InitButtons(hwndDlg, si);
+
+			// stupid hack to make icons show. I dunno why this is needed currently
+			MODULEINFO *mi = pci->MM_FindModule(si->pszModule);
+			HICON hIcon = si->wStatus == ID_STATUS_ONLINE ? mi->hOnlineIcon : mi->hOfflineIcon;
+			if (!hIcon) {
+				pci->MM_IconsChanged();
+				hIcon = (si->wStatus == ID_STATUS_ONLINE) ? mi->hOnlineIcon : mi->hOfflineIcon;
+			}
+
+			SendMessage(hwndDlg, GC_FIXTABICONS, 0, 0);
+			SendMessage(si->hwndStatus, SB_SETICON, 0, (LPARAM)hIcon);
+			Window_SetIcon_IcoLib(hwndDlg, GetIconHandle("window"));
+
+			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETBKGNDCOLOR, 0, g_Settings.crLogBackground);
+
+			if (g_Settings.bTabsEnable) {
+				LONG_PTR mask = GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TAB), GWL_STYLE);
+				if (g_Settings.TabsAtBottom)
+					mask |= TCS_BOTTOM;
+				else
+					mask &= ~TCS_BOTTOM;
+				SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_TAB), GWL_STYLE, (LONG_PTR)mask);
+			}
+			{
+				CHARFORMAT2 cf;
+				cf.cbSize = sizeof(CHARFORMAT2);
+				cf.dwMask = CFM_COLOR | CFM_BOLD | CFM_UNDERLINE | CFM_BACKCOLOR;
+				cf.dwEffects = 0;
+				cf.crTextColor = g_Settings.MessageAreaColor;
+				cf.crBackColor = (COLORREF)db_get_dw(NULL, CHAT_MODULE, "ColorMessageBG", GetSysColor(COLOR_WINDOW));
+				SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETBKGNDCOLOR, 0, db_get_dw(NULL, CHAT_MODULE, "ColorMessageBG", GetSysColor(COLOR_WINDOW)));
+				SendDlgItemMessage(hwndDlg, IDC_MESSAGE, WM_SETFONT, (WPARAM)g_Settings.MessageAreaFont, MAKELPARAM(TRUE, 0));
+				SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, (WPARAM)SCF_ALL, (LPARAM)&cf);
+
+				// nicklist
+				int ih = GetTextPixelSize(L"AQGglo", g_Settings.UserListFont, FALSE);
+				int ih2 = GetTextPixelSize(L"AQGglo", g_Settings.UserListHeadingsFont, FALSE);
+				int height = db_get_b(NULL, CHAT_MODULE, "NicklistRowDist", 12);
+				int font = ih > ih2 ? ih : ih2;
+
+				// make sure we have space for icon!
+				if (g_Settings.bShowContactStatus)
+					font = font > 16 ? font : 16;
+
+				SendDlgItemMessage(hwndDlg, IDC_LIST, LB_SETITEMHEIGHT, 0, (LPARAM)height > font ? height : font);
+				InvalidateRect(GetDlgItem(hwndDlg, IDC_LIST), NULL, TRUE);
+			}
+			SendMessage(hwndDlg, WM_SIZE, 0, 0);
+			SendMessage(hwndDlg, GC_REDRAWLOG2, 0, 0);
+		}
+		break;
+
+	case GC_UPDATETITLE:
+		{
+			wchar_t szTemp[100];
+			switch (si->iType) {
+			case GCW_CHATROOM:
+				mir_snwprintf(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_snwprintf(szTemp,
+					(si->nUsersInNicklist == 1) ? TranslateT("%s: message session") : TranslateT("%s: message session (%u users)"),
+					si->ptszName, si->nUsersInNicklist);
+				break;
+			case GCW_SERVER:
+				mir_snwprintf(szTemp, L"%s: Server", si->ptszName);
+				break;
+			}
+			SetWindowText(hwndDlg, szTemp);
+		}
+		break;
+
+	case GC_UPDATESTATUSBAR:
+		{
+			MODULEINFO *mi = pci->MM_FindModule(si->pszModule);
+			wchar_t* ptszDispName = mi->ptszModDispName;
+			int x = 12;
+			x += GetTextPixelSize(ptszDispName, (HFONT)SendMessage(si->hwndStatus, WM_GETFONT, 0, 0), TRUE);
+			x += GetSystemMetrics(SM_CXSMICON);
+			int iStatusbarParts[2] = { x, -1 };
+			SendMessage(si->hwndStatus, SB_SETPARTS, 2, (LPARAM)&iStatusbarParts);
+
+			// stupid hack to make icons show. I dunno why this is needed currently
+			HICON hIcon = si->wStatus == ID_STATUS_ONLINE ? mi->hOnlineIcon : mi->hOfflineIcon;
+			if (!hIcon) {
+				pci->MM_IconsChanged();
+				hIcon = si->wStatus == ID_STATUS_ONLINE ? mi->hOnlineIcon : mi->hOfflineIcon;
+			}
+
+			SendMessage(si->hwndStatus, SB_SETICON, 0, (LPARAM)hIcon);
+			SendMessage(hwndDlg, GC_FIXTABICONS, 0, 0);
+
+			SendMessage(si->hwndStatus, SB_SETTEXT, 0, (LPARAM)ptszDispName);
+
+			SendMessage(si->hwndStatus, SB_SETTEXT, 1, (LPARAM)(si->ptszStatusbarText ? si->ptszStatusbarText : L""));
+			SendMessage(si->hwndStatus, SB_SETTIPTEXT, 1, (LPARAM)(si->ptszStatusbarText ? si->ptszStatusbarText : L""));
+		}
+		return TRUE;
+
+	case GC_SETWINDOWPOS:
+		{
+			SESSION_INFO *pActive = pci->GetActiveSession();
+			RECT screen;
+			int savePerContact = db_get_b(NULL, CHAT_MODULE, "SavePosition", 0);
+
+			WINDOWPLACEMENT wp;
+			wp.length = sizeof(wp);
+			GetWindowPlacement(hwndDlg, &wp);
+			SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0);
+
+			if (si->iX) {
+				wp.rcNormalPosition.left = si->iX;
+				wp.rcNormalPosition.top = si->iY;
+				wp.rcNormalPosition.right = wp.rcNormalPosition.left + si->iWidth;
+				wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + si->iHeight;
+				wp.showCmd = SW_HIDE;
+				SetWindowPlacement(hwndDlg, &wp);
+				break;
+			}
+			if (savePerContact) {
+				if (RestoreWindowPosition(hwndDlg, g_Settings.bTabsEnable ? NULL : si->hContact, CHAT_MODULE, "room", SW_HIDE))
+					break;
+				SetWindowPos(hwndDlg, 0, (screen.right - screen.left) / 2 - (550) / 2, (screen.bottom - screen.top) / 2 - (400) / 2, (550), (400), SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
+			}
+			else SetWindowPos(hwndDlg, 0, (screen.right - screen.left) / 2 - (550) / 2, (screen.bottom - screen.top) / 2 - (400) / 2, (550), (400), SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
+
+			if (!g_Settings.bTabsEnable && pActive && pActive->hWnd && db_get_b(NULL, CHAT_MODULE, "CascadeWindows", 1)) {
+				RECT rcThis, rcNew;
+				int dwFlag = SWP_NOZORDER | SWP_NOACTIVATE;
+				if (!IsWindowVisible((HWND)wParam))
+					dwFlag |= SWP_HIDEWINDOW;
+
+				GetWindowRect(hwndDlg, &rcThis);
+				GetWindowRect(pActive->hWnd, &rcNew);
+
+				int offset = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
+				SetWindowPos((HWND)hwndDlg, 0, rcNew.left + offset, rcNew.top + offset, rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, dwFlag);
+			}
+		}
+		break;
+
+	case GC_SAVEWNDPOS:
+		{
+			WINDOWPLACEMENT wp = { 0 };
+			wp.length = sizeof(wp);
+			GetWindowPlacement(hwndDlg, &wp);
+
+			g_Settings.iX = wp.rcNormalPosition.left;
+			g_Settings.iY = wp.rcNormalPosition.top;
+			g_Settings.iWidth = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
+			g_Settings.iHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
+
+			if (!lParam) {
+				si->iX = g_Settings.iX;
+				si->iY = g_Settings.iY;
+				si->iWidth = g_Settings.iWidth;
+				si->iHeight = g_Settings.iHeight;
+			}
+		}
+		break;
+
+	case WM_SIZE:
+		if (wParam == SIZE_MAXIMIZED)
+			PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
+
+		if (!IsIconic(hwndDlg)) {
+			SendMessage(si->hwndStatus, WM_SIZE, 0, 0);
+
+			Utils_ResizeDialog(hwndDlg, g_hInst, MAKEINTRESOURCEA(IDD_CHANNEL), RoomWndResize, (LPARAM)si);
+
+			InvalidateRect(si->hwndStatus, NULL, TRUE);
+			RedrawWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, NULL, RDW_INVALIDATE);
+			RedrawWindow(GetDlgItem(hwndDlg, IDOK), NULL, NULL, RDW_INVALIDATE);
+			SendMessage(hwndDlg, GC_SAVEWNDPOS, 0, 1);
+		}
+		break;
+
+	case GC_REDRAWWINDOW:
+		InvalidateRect(hwndDlg, NULL, TRUE);
+		break;
+
+	case GC_REDRAWLOG:
+		si->LastTime = 0;
+		if (si->pLog) {
+			LOGINFO * pLog = si->pLog;
+			if (si->iEventCount > 60) {
+				int index = 0;
+				while (index < 59) {
+					if (pLog->next == NULL)
+						break;
+
+					pLog = pLog->next;
+					if (si->iType != GCW_CHATROOM || !si->bFilterEnabled || (si->iLogFilterFlags&pLog->iType) != 0)
+						index++;
+				}
+				Log_StreamInEvent(hwndDlg, pLog, si, TRUE, FALSE);
+				mir_forkthread(phase2, si);
+			}
+			else Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE, FALSE);
+		}
+		else SendMessage(hwndDlg, GC_CONTROL_MSG, WINDOW_CLEARLOG, 0);
+		break;
+
+	case GC_REDRAWLOG2:
+		si->LastTime = 0;
+		if (si->pLog)
+			Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE, FALSE);
+		break;
+
+	case GC_REDRAWLOG3:
+		si->LastTime = 0;
+		if (si->pLog)
+			Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE, TRUE);
+		break;
+
+	case GC_ADDLOG:
+		if (si->pLogEnd)
+			Log_StreamInEvent(hwndDlg, si->pLog, si, FALSE, FALSE);
+		else
+			SendMessage(hwndDlg, GC_CONTROL_MSG, WINDOW_CLEARLOG, 0);
+		break;
+
+	case GC_SWITCHNEXTTAB:
+		{
+			int total = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB));
+			int i = TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TAB));
+			if (i != -1 && total != -1 && total != 1) {
+				if (i < total - 1)
+					i++;
+				else
+					i = 0;
+				TabCtrl_SetCurSel(GetDlgItem(hwndDlg, IDC_TAB), i);
+				PostMessage(hwndDlg, GC_TABCLICKED, 0, 0);
+			}
+		}
+		break;
+
+	case GC_SWITCHPREVTAB:
+		{
+			int total = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB));
+			int i = TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TAB));
+			if (i != -1 && total != -1 && total != 1) {
+				if (i > 0)
+					i--;
+				else
+					i = total - 1;
+				TabCtrl_SetCurSel(GetDlgItem(hwndDlg, IDC_TAB), i);
+				PostMessage(hwndDlg, GC_TABCLICKED, 0, 0);
+			}
+		}
+		break;
+
+	case GC_SWITCHTAB:
+		{
+			int total = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB));
+			int i = TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TAB));
+			if (i != -1 && total != -1 && total != 1 && i != lParam && total > lParam) {
+				TabCtrl_SetCurSel(GetDlgItem(hwndDlg, IDC_TAB), lParam);
+				PostMessage(hwndDlg, GC_TABCLICKED, 0, 0);
+			}
+		}
+		break;
+
+	case GC_REMOVETAB:
+		{
+			SESSION_INFO* s2;
+			int i = -1;
+			SESSION_INFO* s1 = (SESSION_INFO*)lParam;
+			int tabId = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB));
+
+			if (s1) {
+				if (tabId) {
+					for (i = 0; i < tabId; i++) {
+						int ii;
+						TCITEM tci = { 0 };
+						tci.mask = TCIF_PARAM;
+						ii = TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &tci);
+						if (ii != -1) {
+							s2 = (SESSION_INFO*)tci.lParam;
+							if (s1 == s2)
+								goto END_REMOVETAB;
+						}
+					}
+				}
+			}
+			else i = TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TAB));
+
+		END_REMOVETAB:
+			if (i != -1 && i < tabId) {
+				TCITEM id = { 0 };
+				SESSION_INFO *s;
+				TabCtrl_DeleteItem(GetDlgItem(hwndDlg, IDC_TAB), i);
+				id.mask = TCIF_PARAM;
+				if (!TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &id)) {
+					if (!TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i - 1, &id)) {
+						SendMessage(hwndDlg, WM_CLOSE, 0, 0);
+						break;
+					}
+				}
+
+				s = (SESSION_INFO*)id.lParam;
+				if (s)
+					pci->ShowRoom(s, (WPARAM)WINDOW_VISIBLE, wParam == 1 ? FALSE : TRUE);
+			}
+		}
+		break;
+
+	case GC_ADDTAB:
+		{
+			TCITEM tci;
+			int tabId;
+			WORD w = 0;
+			int i = 0;
+			int indexfound = -1;
+			int lastlocked = -1;
+			BOOL bFound = FALSE;
+			SESSION_INFO* s2;
+			SESSION_INFO* s1 = (SESSION_INFO*)lParam;
+
+			tci.mask = TCIF_PARAM;
+			tabId = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB));
+
+			// does the tab already exist?
+			for (i = 0; i < tabId; i++) {
+				TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &tci);
+				s2 = (SESSION_INFO*)tci.lParam;
+				if (s2) {
+					if (s1 == s2 && !bFound) {
+						if (!bFound) {
+							bFound = TRUE;
+							indexfound = i;
+						}
+					}
+
+					w = db_get_w(s2->hContact, s2->pszModule, "TabPosition", 0);
+					if (w)
+						lastlocked = (int)w;
+				}
+			}
+
+			w = 0;
+
+			if (!bFound) { // create a new tab
+				int insertat;
+				wchar_t szTemp[30];
+
+				mir_wstrncpy(szTemp, s1->ptszName, 21);
+				if (mir_wstrlen(s1->ptszName) > 20)
+					mir_wstrncpy(szTemp + 20, L"...", 4);
+
+				tci.mask = TCIF_TEXT | TCIF_PARAM;
+				tci.pszText = szTemp;
+				tci.lParam = lParam;
+
+				// determine insert position
+				w = db_get_w(s1->hContact, s1->pszModule, "TabPosition", 0);
+				if (wParam == -1)
+					insertat = w == 0 ? tabId : (int)w - 1;
+				else
+					insertat = (int)wParam;
+
+				w = TabCtrl_InsertItem(GetDlgItem(hwndDlg, IDC_TAB), insertat, &tci);
+				SendMessage(hwndDlg, GC_FIXTABICONS, 0, (LPARAM)s1);
+			}
+
+			if (wParam == -1) {
+				if (bFound)
+					TabCtrl_SetCurSel(GetDlgItem(hwndDlg, IDC_TAB), indexfound);
+				else
+					TabCtrl_SetCurSel(GetDlgItem(hwndDlg, IDC_TAB), w);
+			}
+		}
+		break;
+
+	case GC_FIXTABICONS:
+		{
+			SESSION_INFO *s = (SESSION_INFO*)lParam;
+			if (s) {
+				int tabId = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB));
+				for (int i = 0; i < tabId; i++) {
+					TCITEM tci;
+					tci.mask = TCIF_PARAM | TCIF_IMAGE;
+					TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &tci);
+					SESSION_INFO *s2 = (SESSION_INFO*)tci.lParam;
+					if (s2 && s == s2) {
+						int image = 0;
+						if (!(s2->wState & GC_EVENT_HIGHLIGHT)) {
+							MODULEINFO *mi = pci->MM_FindModule(s2->pszModule);
+							image = (s2->wStatus == ID_STATUS_ONLINE) ? mi->OnlineIconIndex : mi->OfflineIconIndex;
+							if (s2->wState & STATE_TALK)
+								image++;
+						}
+
+						if (tci.iImage != image) {
+							tci.mask = TCIF_IMAGE;
+							tci.iImage = image;
+							TabCtrl_SetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &tci);
+						}
+					}
+				}
+			}
+			else RedrawWindow(GetDlgItem(hwndDlg, IDC_TAB), NULL, NULL, RDW_INVALIDATE);
+		}
+		break;
+
+	case GC_SETMESSAGEHIGHLIGHT:
+		{
+			SESSION_INFO *s = (SESSION_INFO*)lParam;
+			if (s) {
+				int tabId = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB));
+				for (int i = 0; i < tabId; i++) {
+					TCITEM tci;
+					tci.mask = TCIF_PARAM;
+					TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &tci);
+					SESSION_INFO *s2 = (SESSION_INFO*)tci.lParam;
+					if (s2 && s == s2) { // highlight
+						s2->wState |= GC_EVENT_HIGHLIGHT;
+						if (pci->SM_FindSession(si->ptszID, si->pszModule) == s2)
+							si->wState = s2->wState;
+						SendMessage(hwndDlg, GC_FIXTABICONS, 0, (LPARAM)s2);
+						if (g_Settings.bFlashWindowHighlight && GetActiveWindow() != hwndDlg && GetForegroundWindow() != hwndDlg)
+							SetTimer(hwndDlg, TIMERID_FLASHWND, 900, NULL);
+						break;
+					}
+				}
+			}
+			else RedrawWindow(GetDlgItem(hwndDlg, IDC_TAB), NULL, NULL, RDW_INVALIDATE);
+		}
+		break;
+
+	case GC_SETTABHIGHLIGHT:
+		{
+			SESSION_INFO *s = (SESSION_INFO*)lParam;
+			if (s) {
+				int tabId = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB));
+				for (int i = 0; i < tabId; i++) {
+					TCITEM tci;
+					tci.mask = TCIF_PARAM;
+					TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &tci);
+					SESSION_INFO *s2 = (SESSION_INFO*)tci.lParam;
+					if (s2 && s == s2) { // highlight
+						SendMessage(hwndDlg, GC_FIXTABICONS, 0, (LPARAM)s2);
+						if (g_Settings.bFlashWindow && GetActiveWindow() != hwndDlg && GetForegroundWindow() != hwndDlg)
+							SetTimer(hwndDlg, TIMERID_FLASHWND, 900, NULL);
+						break;
+					}
+				}
+			}
+			else RedrawWindow(GetDlgItem(hwndDlg, IDC_TAB), NULL, NULL, RDW_INVALIDATE);
+		}
+		break;
+
+	case GC_TABCHANGE:
+		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
+		PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
+		break;
+
+	case GC_TABCLICKED:
+		{
+			int i = TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TAB));
+			if (i != -1) {
+				TCITEM id = { 0 };
+				id.mask = TCIF_PARAM;
+				TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &id);
+				SESSION_INFO *s = (SESSION_INFO*)id.lParam;
+				if (s) {
+					if (s->wState & STATE_TALK) {
+						s->wState &= ~STATE_TALK;
+						db_set_w(s->hContact, s->pszModule, "ApparentMode", (LPARAM)0);
+					}
+
+					if (s->wState & GC_EVENT_HIGHLIGHT) {
+						s->wState &= ~GC_EVENT_HIGHLIGHT;
+
+						if (pcli->pfnGetEvent(s->hContact, 0))
+							pcli->pfnRemoveEvent(s->hContact, GC_FAKE_EVENT);
+					}
+
+					SendMessage(hwndDlg, GC_FIXTABICONS, 0, (LPARAM)s);
+					if (!s->hWnd) {
+						pci->ShowRoom(s, (WPARAM)WINDOW_VISIBLE, TRUE);
+						SendMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+					}
+				}
+			}
+		}
+		break;
+
+	case GC_DROPPEDTAB:
+		{
+			int begin = (int)lParam;
+			int end = (int)wParam;
+			if (begin == end)
+				break;
+
+			TCITEM tci;
+			tci.mask = TCIF_PARAM;
+			TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), begin, &tci);
+			SESSION_INFO *s = (SESSION_INFO*)tci.lParam;
+			if (s) {
+				TabCtrl_DeleteItem(GetDlgItem(hwndDlg, IDC_TAB), begin);
+
+				SendMessage(hwndDlg, GC_ADDTAB, end, (LPARAM)s);
+
+				// fix the "fixed" positions
+				int tabId = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB));
+				for (int i = 0; i < tabId; i++) {
+					TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &tci);
+					s = (SESSION_INFO*)tci.lParam;
+					if (s && s->hContact && db_get_w(s->hContact, s->pszModule, "TabPosition", 0) != 0)
+						db_set_w(s->hContact, s->pszModule, "TabPosition", (WORD)(i + 1));
+				}
+			}
+		}
+		break;
+
+	case GC_SESSIONNAMECHANGE:
+		{
+			SESSION_INFO* s1 = (SESSION_INFO*)lParam;
+			int tabId = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB));
+			for (int i = 0; i < tabId; i++) {
+				TCITEM tci;
+				tci.mask = TCIF_PARAM;
+				int j = TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &tci);
+				if (j != -1) {
+					SESSION_INFO *s2 = (SESSION_INFO*)tci.lParam;
+					if (s1 == s2) {
+						tci.mask = TCIF_TEXT;
+						tci.pszText = s1->ptszName;
+						TabCtrl_SetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &tci);
+					}
+				}
+			}
+		}
+		break;
+
+	case WM_CTLCOLORLISTBOX:
+		SetBkColor((HDC)wParam, g_Settings.crUserListBGColor);
+		return (INT_PTR)pci->hListBkgBrush;
+
+	case WM_MEASUREITEM:
+		{
+			MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lParam;
+			if (mis->CtlType == ODT_MENU)
+				return Menu_MeasureItem(lParam);
+
+			int ih = GetTextPixelSize(L"AQGgl'", g_Settings.UserListFont, FALSE);
+			int ih2 = GetTextPixelSize(L"AQGg'", g_Settings.UserListHeadingsFont, FALSE);
+			int font = ih > ih2 ? ih : ih2;
+			int height = db_get_b(NULL, CHAT_MODULE, "NicklistRowDist", 12);
+
+			// make sure we have space for icon!
+			if (g_Settings.bShowContactStatus)
+				font = font > 16 ? font : 16;
+
+			mis->itemHeight = height > font ? height : font;
+		}
+		return TRUE;
+
+	case WM_DRAWITEM:
+		{
+			DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
+			if (dis->CtlType == ODT_MENU)
+				return Menu_DrawItem(lParam);
+
+			if (dis->CtlID == IDC_LIST) {
+				int index = dis->itemID;
+				USERINFO *ui = pci->SM_GetUserFromIndex(si->ptszID, si->pszModule, index);
+				if (ui) {
+					int x_offset = 2;
+
+					int height = dis->rcItem.bottom - dis->rcItem.top;
+					if (height & 1)
+						height++;
+
+					int offset = (height == 10) ? 0 : height / 2 - 4;
+					HFONT hFont = (ui->iStatusEx == 0) ? g_Settings.UserListFont : g_Settings.UserListHeadingsFont;
+					HFONT hOldFont = (HFONT)SelectObject(dis->hDC, hFont);
+					SetBkMode(dis->hDC, TRANSPARENT);
+
+					if (dis->itemAction == ODA_FOCUS && dis->itemState & ODS_SELECTED)
+						FillRect(dis->hDC, &dis->rcItem, pci->hListSelectedBkgBrush);
+					else //if (dis->itemState & ODS_INACTIVE)
+						FillRect(dis->hDC, &dis->rcItem, pci->hListBkgBrush);
+
+					if (g_Settings.bShowContactStatus && g_Settings.bContactStatusFirst && ui->ContactStatus) {
+						HICON hIcon = Skin_LoadProtoIcon(si->pszModule, ui->ContactStatus);
+						DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 3, hIcon, 16, 16, 0, NULL, DI_NORMAL);
+						x_offset += 18;
+					}
+					DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset, pci->SM_GetStatusIcon(si, ui), 10, 10, 0, NULL, DI_NORMAL);
+					x_offset += 12;
+					if (g_Settings.bShowContactStatus && !g_Settings.bContactStatusFirst && ui->ContactStatus) {
+						HICON hIcon = Skin_LoadProtoIcon(si->pszModule, ui->ContactStatus);
+						DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 3, hIcon, 16, 16, 0, NULL, DI_NORMAL);
+						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, (int)mir_wstrlen(ui->pszNick));
+					SelectObject(dis->hDC, hOldFont);
+
+					if (si->pAccPropServicesForNickList) {
+						wchar_t *nick = mir_wstrdup(ui->pszNick);
+						si->pAccPropServicesForNickList->SetHwndPropStr(GetDlgItem(hwndDlg, IDC_LIST), OBJID_CLIENT, dis->itemID + 1, PROPID_ACC_NAME, nick);
+						mir_free(nick);
+					}
+				}
+				return TRUE;
+			}
+		}
+		break;
+
+	case GC_UPDATENICKLIST:
+		{
+			int i = SendDlgItemMessage(hwndDlg, IDC_LIST, LB_GETTOPINDEX, 0, 0);
+			SendDlgItemMessage(hwndDlg, IDC_LIST, LB_SETCOUNT, si->nUsersInNicklist, 0);
+			SendDlgItemMessage(hwndDlg, IDC_LIST, LB_SETTOPINDEX, i, 0);
+			SendMessage(hwndDlg, GC_UPDATETITLE, 0, 0);
+		}
+		break;
+
+	case GC_CONTROL_MSG:
+		switch (wParam) {
+		case SESSION_OFFLINE:
+			SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
+			SendMessage(si->hWnd, GC_UPDATENICKLIST, 0, 0);
+			return TRUE;
+
+		case SESSION_ONLINE:
+			SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
+			return TRUE;
+
+		case WINDOW_HIDDEN:
+			SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 0);
+			return TRUE;
+
+		case WINDOW_CLEARLOG:
+			SetDlgItemText(hwndDlg, IDC_LOG, L"");
+			return TRUE;
+
+		case SESSION_TERMINATE:
+			SendMessage(hwndDlg, GC_SAVEWNDPOS, 0, 0);
+			if (db_get_b(NULL, CHAT_MODULE, "SavePosition", 0)) {
+				db_set_dw(si->hContact, CHAT_MODULE, "roomx", si->iX);
+				db_set_dw(si->hContact, CHAT_MODULE, "roomy", si->iY);
+				db_set_dw(si->hContact, CHAT_MODULE, "roomwidth", si->iWidth);
+				db_set_dw(si->hContact, CHAT_MODULE, "roomheight", si->iHeight);
+			}
+			if (pcli->pfnGetEvent(si->hContact, 0))
+				pcli->pfnRemoveEvent(si->hContact, GC_FAKE_EVENT);
+			si->wState &= ~STATE_TALK;
+			db_set_w(si->hContact, si->pszModule, "ApparentMode", 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 (db_get_b(NULL, CHAT_MODULE, "PopupOnJoin", 0) != 0)
+				return TRUE;
+			// fall through
+		case WINDOW_VISIBLE:
+			if (IsIconic(hwndDlg))
+				ShowWindow(hwndDlg, SW_NORMAL);
+		LABEL_SHOWWINDOW:
+			SendMessage(hwndDlg, WM_SIZE, 0, 0);
+			SendMessage(hwndDlg, GC_REDRAWLOG, 0, 0);
+			SendMessage(hwndDlg, GC_UPDATENICKLIST, 0, 0);
+			SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
+			ShowWindow(hwndDlg, SW_SHOW);
+			SendMessage(hwndDlg, WM_SIZE, 0, 0);
+			SetForegroundWindow(hwndDlg);
+			return TRUE;
+		}
+		break;
+
+	case GC_SPLITTERMOVED:
+		{
+			POINT pt;
+			RECT rcLog;
+			BOOL bFormat = IsWindowVisible(GetDlgItem(hwndDlg, IDC_SMILEY));
+
+			static int x = 0;
+
+			GetWindowRect(GetDlgItem(hwndDlg, IDC_LOG), &rcLog);
+			if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SPLITTERX)) {
+				int oldSplitterX;
+				GetClientRect(hwndDlg, &rc);
+				pt.x = wParam; pt.y = 0;
+				ScreenToClient(hwndDlg, &pt);
+
+				oldSplitterX = si->iSplitterX;
+				si->iSplitterX = rc.right - pt.x + 1;
+				if (si->iSplitterX < 35)
+					si->iSplitterX = 35;
+				if (si->iSplitterX > rc.right - rc.left - 35)
+					si->iSplitterX = rc.right - rc.left - 35;
+				g_Settings.iSplitterX = si->iSplitterX;
+			}
+			else if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SPLITTERY)) {
+				int oldSplitterY;
+				GetClientRect(hwndDlg, &rc);
+				pt.x = 0; pt.y = wParam;
+				ScreenToClient(hwndDlg, &pt);
+
+				oldSplitterY = si->iSplitterY;
+				si->iSplitterY = bFormat ? rc.bottom - pt.y + 1 : rc.bottom - pt.y + 20;
+				if (si->iSplitterY < 63)
+					si->iSplitterY = 63;
+				if (si->iSplitterY > rc.bottom - rc.top - 40)
+					si->iSplitterY = rc.bottom - rc.top - 40;
+				g_Settings.iSplitterY = si->iSplitterY;
+			}
+			if (x == 2) {
+				PostMessage(hwndDlg, WM_SIZE, 0, 0);
+				x = 0;
+			}
+			else x++;
+		}
+		break;
+
+	case GC_FIREHOOK:
+		if (lParam) {
+			GCHOOK *gch = (GCHOOK *)lParam;
+			NotifyEventHooks(pci->hSendEvent, 0, (WPARAM)gch);
+			if (gch->pDest) {
+				mir_free((void*)gch->pDest->ptszID);
+				mir_free((void*)gch->pDest->pszModule);
+				mir_free(gch->pDest);
+			}
+			mir_free((void*)gch->ptszText);
+			mir_free((void*)gch->ptszUID);
+			mir_free(gch);
+		}
+		break;
+
+	case GC_CHANGEFILTERFLAG:
+		si->iLogFilterFlags = lParam;
+		break;
+
+	case GC_SHOWFILTERMENU:
+		{
+			HWND hwnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER), hwndDlg, FilterWndProc, (LPARAM)si);
+			TranslateDialogDefault(hwnd);
+			GetWindowRect(GetDlgItem(hwndDlg, IDC_FILTER), &rc);
+			SetWindowPos(hwnd, HWND_TOP, rc.left - 85, (IsWindowVisible(GetDlgItem(hwndDlg, IDC_FILTER)) || IsWindowVisible(GetDlgItem(hwndDlg, IDC_BOLD))) ? rc.top - 206 : rc.top - 186, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
+		}
+		break;
+
+	case GC_SHOWCOLORCHOOSER:
+		pci->ColorChooser(si, lParam == IDC_COLOR, hwndDlg, GetDlgItem(hwndDlg, IDC_MESSAGE), GetDlgItem(hwndDlg, lParam));
+		break;
+
+	case GC_SCROLLTOBOTTOM:
+		if ((GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_STYLE) & WS_VSCROLL) != 0) {
+			SCROLLINFO scroll = { 0 };
+			scroll.cbSize = sizeof(scroll);
+			scroll.fMask = SIF_PAGE | SIF_RANGE;
+			GetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &scroll);
+
+			scroll.fMask = SIF_POS;
+			scroll.nPos = scroll.nMax - scroll.nPage + 1;
+			SetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &scroll, TRUE);
+
+			CHARRANGE sel;
+			sel.cpMin = sel.cpMax = GetRichTextLength(GetDlgItem(hwndDlg, IDC_LOG));
+			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM)&sel);
+			PostMessage(GetDlgItem(hwndDlg, IDC_LOG), WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0);
+		}
+		break;
+
+	case WM_TIMER:
+		if (wParam == TIMERID_FLASHWND)
+			FlashWindow(hwndDlg, TRUE);
+		break;
+
+	case WM_ACTIVATE:
+		if (LOWORD(wParam) != WA_ACTIVE)
+			break;
+
+		//fall through
+	case WM_MOUSEACTIVATE:
+		{
+			WINDOWPLACEMENT wp = { 0 };
+			wp.length = sizeof(wp);
+			GetWindowPlacement(hwndDlg, &wp);
+			g_Settings.iX = wp.rcNormalPosition.left;
+			g_Settings.iY = wp.rcNormalPosition.top;
+			g_Settings.iWidth = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
+			g_Settings.iHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
+
+			if (g_Settings.bTabsEnable) {
+				int i = TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TAB));
+				if (i != -1) {
+					TCITEM tci;
+					tci.mask = TCIF_PARAM;
+					TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &tci);
+					SESSION_INFO *s = (SESSION_INFO*)tci.lParam;
+					if (s) {
+						s->wState &= ~GC_EVENT_HIGHLIGHT;
+						s->wState &= ~STATE_TALK;
+						SendMessage(hwndDlg, GC_FIXTABICONS, 0, (LPARAM)s);
+					}
+				}
+			}
+
+			if (uMsg != WM_ACTIVATE)
+				SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+
+			pci->SetActiveSession(si->ptszID, si->pszModule);
+
+			if (KillTimer(hwndDlg, TIMERID_FLASHWND))
+				FlashWindow(hwndDlg, FALSE);
+			if (db_get_w(si->hContact, si->pszModule, "ApparentMode", 0) != 0)
+				db_set_w(si->hContact, si->pszModule, "ApparentMode", (LPARAM)0);
+			if (pcli->pfnGetEvent(si->hContact, 0))
+				pcli->pfnRemoveEvent(si->hContact, GC_FAKE_EVENT);
+		}
+		break;
+
+	case WM_NOTIFY:
+		switch (((LPNMHDR)lParam)->code) {
+		case NM_RCLICK:
+			if (((LPNMHDR)lParam)->idFrom == IDC_TAB) {
+				int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom);
+				if (i == -1)
+					break;
+
+				TCHITTESTINFO tci = { 0 };
+				tci.pt.x = (short)LOWORD(GetMessagePos());
+				tci.pt.y = (short)HIWORD(GetMessagePos());
+				tci.flags = TCHT_ONITEM;
+				ScreenToClient(GetDlgItem(hwndDlg, IDC_TAB), &tci.pt);
+				if ((i = TabCtrl_HitTest(((LPNMHDR)lParam)->hwndFrom, &tci)) == -1)
+					break;
+
+				TCITEM id = { 0 };
+				id.mask = TCIF_PARAM;
+				TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &id);
+				SESSION_INFO *s = (SESSION_INFO*)id.lParam;
+
+				ClientToScreen(GetDlgItem(hwndDlg, IDC_TAB), &tci.pt);
+				HMENU hSubMenu = GetSubMenu(g_hMenu, 5);
+				TranslateMenu(hSubMenu);
+				if (s) {
+					WORD w = db_get_w(s->hContact, s->pszModule, "TabPosition", 0);
+					if (w == 0)
+						CheckMenuItem(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND | MF_UNCHECKED);
+					else
+						CheckMenuItem(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND | MF_CHECKED);
+				}
+				else CheckMenuItem(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND | MF_UNCHECKED);
+
+				switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, tci.pt.x, tci.pt.y, 0, hwndDlg, NULL)) {
+				case ID_CLOSE:
+					if (TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TAB)) == i)
+						PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_CLOSE, BN_CLICKED), 0);
+					else
+						TabCtrl_DeleteItem(GetDlgItem(hwndDlg, IDC_TAB), i);
+					break;
+
+				case ID_CLOSEOTHER:
+					{
+						int tabId = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB)) - 1;
+						if (tabId > 0) {
+							if (TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TAB)) != i)
+								if (s)
+									pci->ShowRoom(s, WINDOW_VISIBLE, TRUE);
+
+							for (tabId; tabId >= 0; tabId--) {
+								if (tabId == i)
+									continue;
+
+								TabCtrl_DeleteItem(GetDlgItem(hwndDlg, IDC_TAB), tabId);
+							}
+						}
+					}
+					break;
+
+				case ID_LOCKPOSITION:
+					TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), i, &id);
+					if (s != 0) {
+						if (!(GetMenuState(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND)&MF_CHECKED)) {
+							if (s->hContact)
+								db_set_w(s->hContact, s->pszModule, "TabPosition", (WORD)(i + 1));
+						}
+						else db_unset(s->hContact, s->pszModule, "TabPosition");
+					}
+					break;
+				}
+			}
+			break;
+
+		case EN_MSGFILTER:
+			if (((LPNMHDR)lParam)->idFrom == IDC_LOG && ((MSGFILTER *)lParam)->msg == WM_RBUTTONUP) {
+				CHARRANGE sel, all = { 0, -1 };
+				POINT pt;
+				UINT uID = 0;
+				HMENU hMenu = 0;
+				wchar_t pszWord[4096];
+
+				pt.x = (short)LOWORD(((ENLINK *)lParam)->lParam);
+				pt.y = (short)HIWORD(((ENLINK *)lParam)->lParam);
+				ClientToScreen(((LPNMHDR)lParam)->hwndFrom, &pt);
+
+				// fixing stuff for searches
+				pszWord[0] = '\0';
+
+				POINTL ptl = { (LONG)pt.x, (LONG)pt.y };
+				ScreenToClient(GetDlgItem(hwndDlg, IDC_LOG), (LPPOINT)&ptl);
+				long iCharIndex = SendDlgItemMessage(hwndDlg, IDC_LOG, EM_CHARFROMPOS, 0, (LPARAM)&ptl);
+				if (iCharIndex < 0)
+					break;
+
+				long start = SendDlgItemMessage(hwndDlg, IDC_LOG, EM_FINDWORDBREAK, WB_LEFT, iCharIndex);//-iChars;
+				long end = SendDlgItemMessage(hwndDlg, IDC_LOG, EM_FINDWORDBREAK, WB_RIGHT, iCharIndex);//-iChars;
+
+				if (end - start > 0) {
+					TEXTRANGE tr;
+					memset(&tr, 0, sizeof(TEXTRANGE));
+
+					CHARRANGE cr;
+					cr.cpMin = start;
+					cr.cpMax = end;
+					tr.chrg = cr;
+					tr.lpstrText = pszWord;
+					long iRes = SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+					if (iRes > 0)
+						for (size_t iLen = mir_wstrlen(pszWord) - 1; wcschr(szTrimString, pszWord[iLen]); iLen--)
+							pszWord[iLen] = 0;
+				}
+
+				uID = CreateGCMenu(hwndDlg, &hMenu, 1, pt, si, NULL, pszWord);
+				switch (uID) {
+				case 0:
+					PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+					break;
+
+				case ID_COPYALL:
+					SendMessage(((LPNMHDR)lParam)->hwndFrom, EM_EXGETSEL, 0, (LPARAM)&sel);
+					SendMessage(((LPNMHDR)lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM)& all);
+					SendMessage(((LPNMHDR)lParam)->hwndFrom, WM_COPY, 0, 0);
+					SendMessage(((LPNMHDR)lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM)&sel);
+					PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+					break;
+
+				case ID_CLEARLOG:
+					{
+						SESSION_INFO *s = pci->SM_FindSession(si->ptszID, si->pszModule);
+						if (s) {
+							SetDlgItemText(hwndDlg, IDC_LOG, L"");
+							pci->LM_RemoveAll(&s->pLog, &s->pLogEnd);
+							s->iEventCount = 0;
+							s->LastTime = 0;
+							si->iEventCount = 0;
+							si->LastTime = 0;
+							si->pLog = s->pLog;
+							si->pLogEnd = s->pLogEnd;
+							PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+						}
+					}
+					break;
+
+				case ID_SEARCH_GOOGLE:
+					if (pszWord[0])
+						Utils_OpenUrlT(CMStringW(FORMAT, L"http://www.google.com/search?q=%s", pszWord));
+
+					PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+					break;
+
+				case ID_SEARCH_WIKIPEDIA:
+					if (pszWord[0])
+						Utils_OpenUrlT(CMStringW(FORMAT, L"http://en.wikipedia.org/wiki/%s", pszWord));
+
+					PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+					break;
+
+				default:
+					PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+					pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_LOGMENU, NULL, NULL, (LPARAM)uID);
+					break;
+				}
+				DestroyGCMenu(&hMenu, 5);
+			}
+			break;
+
+		case EN_LINK:
+			if (((LPNMHDR)lParam)->idFrom == IDC_LOG) {
+				switch (((ENLINK *)lParam)->msg) {
+				case WM_RBUTTONDOWN:
+				case WM_LBUTTONUP:
+				case WM_LBUTTONDBLCLK:
+					{
+						CHARRANGE sel;
+						SendMessage(((LPNMHDR)lParam)->hwndFrom, EM_EXGETSEL, 0, (LPARAM)&sel);
+						if (sel.cpMin != sel.cpMax)
+							break;
+
+						TEXTRANGE tr;
+						tr.chrg = ((ENLINK *)lParam)->chrg;
+						tr.lpstrText = (LPTSTR)mir_alloc(sizeof(wchar_t)*(tr.chrg.cpMax - tr.chrg.cpMin + 1));
+						SendMessage(((LPNMHDR)lParam)->hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
+
+						if (((ENLINK *)lParam)->msg == WM_RBUTTONDOWN) {
+							HMENU hSubMenu;
+							POINT pt;
+
+							hSubMenu = GetSubMenu(g_hMenu, 2);
+							TranslateMenu(hSubMenu);
+							pt.x = (short)LOWORD(((ENLINK *)lParam)->lParam);
+							pt.y = (short)HIWORD(((ENLINK *)lParam)->lParam);
+							ClientToScreen(((NMHDR *)lParam)->hwndFrom, &pt);
+							switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL)) {
+							case ID_NEW:
+								Utils_OpenUrlT(tr.lpstrText);
+								break;
+
+							case ID_CURR:
+								Utils_OpenUrlT(tr.lpstrText, false);
+								break;
+
+							case ID_COPY:
+								{
+									HGLOBAL hData;
+									if (!OpenClipboard(hwndDlg))
+										break;
+									EmptyClipboard();
+									hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t)*(mir_wstrlen(tr.lpstrText) + 1));
+									mir_wstrcpy((wchar_t*)GlobalLock(hData), tr.lpstrText);
+									GlobalUnlock(hData);
+									SetClipboardData(CF_UNICODETEXT, hData);
+									CloseClipboard();
+									SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+									break;
+								}
+							}
+							mir_free(tr.lpstrText);
+							return TRUE;
+						}
+
+						Utils_OpenUrlT(tr.lpstrText);
+						SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+						mir_free(tr.lpstrText);
+						break;
+					}
+				}
+			}
+			break;
+
+		case TTN_NEEDTEXT:
+			if (((LPNMHDR)lParam)->idFrom == (UINT_PTR)GetDlgItem(hwndDlg, IDC_LIST)) {
+				LPNMTTDISPINFO lpttd = (LPNMTTDISPINFO)lParam;
+				SESSION_INFO* parentdat = (SESSION_INFO*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+				POINT p;
+				GetCursorPos(&p);
+				ScreenToClient(GetDlgItem(hwndDlg, IDC_LIST), &p);
+				int item = LOWORD(SendDlgItemMessage(hwndDlg, IDC_LIST, LB_ITEMFROMPOINT, 0, MAKELPARAM(p.x, p.y)));
+				USERINFO *ui = pci->SM_GetUserFromIndex(parentdat->ptszID, parentdat->pszModule, item);
+				if (ui != NULL) {
+					static wchar_t ptszBuf[1024];
+					mir_snwprintf(ptszBuf, L"%s: %s\r\n%s: %s\r\n%s: %s",
+						TranslateT("Nickname"), ui->pszNick,
+						TranslateT("Unique ID"), ui->pszUID,
+						TranslateT("Status"), pci->TM_WordToString(parentdat->pStatuses, ui->Status));
+					lpttd->lpszText = ptszBuf;
+				}
+			}
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam)) {
+		case IDC_LIST:
+			if (HIWORD(wParam) == LBN_DBLCLK) {
+				TVHITTESTINFO hti;
+				hti.pt.x = (short)LOWORD(GetMessagePos());
+				hti.pt.y = (short)HIWORD(GetMessagePos());
+				ScreenToClient(GetDlgItem(hwndDlg, IDC_LIST), &hti.pt);
+
+				int item = LOWORD(SendDlgItemMessage(hwndDlg, IDC_LIST, LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y)));
+				USERINFO *ui = pci->SM_GetUserFromIndex(si->ptszID, si->pszModule, item);
+				if (ui) {
+					if (GetKeyState(VK_SHIFT) & 0x8000) {
+						LRESULT lResult = (LRESULT)SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETSEL, 0, 0);
+						int start = LOWORD(lResult);
+						size_t dwNameLenMax = (mir_wstrlen(ui->pszUID) + 3);
+						wchar_t* pszName = (wchar_t*)alloca(sizeof(wchar_t) * dwNameLenMax);
+						if (start == 0)
+							mir_snwprintf(pszName, dwNameLenMax, L"%s: ", ui->pszUID);
+						else
+							mir_snwprintf(pszName, dwNameLenMax, L"%s ", ui->pszUID);
+
+						SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_REPLACESEL, FALSE, (LPARAM)pszName);
+						PostMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
+					}
+					else pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_PRIVMESS, ui->pszUID, NULL, 0);
+				}
+
+				return TRUE;
+			}
+
+			if (HIWORD(wParam) == LBN_KILLFOCUS)
+				RedrawWindow(GetDlgItem(hwndDlg, IDC_LIST), NULL, NULL, RDW_INVALIDATE);
+			break;
+
+		case IDOK:
+			if (IsWindowEnabled(GetDlgItem(hwndDlg, IDOK))) {
+				ptrA pszRtf(Message_GetFromStream(hwndDlg, si));
+				if (pszRtf == NULL)
+					break;
+
+				MODULEINFO *mi = pci->MM_FindModule(si->pszModule);
+				if (mi == NULL)
+					break;
+
+				pci->SM_AddCommand(si->ptszID, si->pszModule, pszRtf);
+
+				CMStringW ptszText(ptrW(mir_utf8decodeW(pszRtf)));
+				pci->DoRtfToTags(ptszText, mi->nColorCount, mi->crColors);
+				ptszText.Trim();
+				ptszText.Replace(L"%", L"%%");
+
+				if (mi->bAckMsg) {
+					EnableWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), FALSE);
+					SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETREADONLY, TRUE, 0);
+				}
+				else SetDlgItemText(hwndDlg, IDC_MESSAGE, L"");
+
+				EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
+
+				pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, ptszText, 0);
+
+				SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+			}
+			break;
+
+		case IDC_SHOWNICKLIST:
+			if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_SHOWNICKLIST)))
+				break;
+			if (si->iType == GCW_SERVER)
+				break;
+
+			si->bNicklistEnabled = !si->bNicklistEnabled;
+
+			SendDlgItemMessage(hwndDlg, IDC_SHOWNICKLIST, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx(si->bNicklistEnabled ? "nicklist" : "nicklist2", FALSE));
+			SendMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
+			SendMessage(hwndDlg, WM_SIZE, 0, 0);
+			break;
+
+		case IDC_MESSAGE:
+			EnableWindow(GetDlgItem(hwndDlg, IDOK), GetRichTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE)) != 0);
+			break;
+
+		case IDC_SMILEY:
+			GetWindowRect(GetDlgItem(hwndDlg, IDC_SMILEY), &rc);
+
+			if (SmileyAddInstalled) {
+				SMADD_SHOWSEL3 smaddInfo = { sizeof(smaddInfo) };
+				smaddInfo.hwndTarget = GetDlgItem(hwndDlg, IDC_MESSAGE);
+				smaddInfo.targetMessage = EM_REPLACESEL;
+				smaddInfo.targetWParam = TRUE;
+				smaddInfo.Protocolname = si->pszModule;
+				smaddInfo.Direction = 3;
+				smaddInfo.xPosition = rc.left + 3;
+				smaddInfo.yPosition = rc.top - 1;
+				smaddInfo.hContact = si->hContact;
+				smaddInfo.hwndParent = hwndDlg;
+				CallService(MS_SMILEYADD_SHOWSELECTION, 0, (LPARAM)&smaddInfo);
+			}
+			break;
+
+		case IDC_HISTORY:
+			if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_HISTORY))) {
+				MODULEINFO *pInfo = pci->MM_FindModule(si->pszModule);
+				if (pInfo) {
+					wchar_t szFile[MAX_PATH], szName[MAX_PATH], szFolder[MAX_PATH];
+					wcsncpy_s(szName, (pInfo->ptszModDispName ? pInfo->ptszModDispName : _A2T(si->pszModule)), _TRUNCATE);
+					ValidateFilename(szName);
+
+					mir_snwprintf(szFolder, L"%s\\%s", g_Settings.pszLogDir, szName);
+					mir_snwprintf(szName, L"%s.log", si->ptszID);
+					ValidateFilename(szName);
+
+					mir_snwprintf(szFile, L"%s\\%s", szFolder, szName);
+					ShellExecute(hwndDlg, L"open", szFile, NULL, NULL, SW_SHOW);
+				}
+			}
+			break;
+
+		case IDC_CLOSE:
+			SendMessage(hwndDlg, GC_REMOVETAB, 0, 0);
+			break;
+
+		case IDC_CHANMGR:
+			if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHANMGR)))
+				pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_CHANMGR, NULL, NULL, 0);
+			break;
+
+		case IDC_FILTER:
+			if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FILTER)))
+				break;
+
+			si->bFilterEnabled = !si->bFilterEnabled;
+			SendDlgItemMessage(hwndDlg, IDC_FILTER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadIconEx(si->bFilterEnabled ? "filter" : "filter2", FALSE));
+			if (si->bFilterEnabled && db_get_b(NULL, CHAT_MODULE, "RightClickFilter", 0) == 0) {
+				SendMessage(hwndDlg, GC_SHOWFILTERMENU, 0, 0);
+				break;
+			}
+			SendMessage(hwndDlg, GC_REDRAWLOG, 0, 0);
+			break;
+
+		case IDC_BKGCOLOR:
+			if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_BKGCOLOR))) {
+				CHARFORMAT2 cf;
+				cf.cbSize = sizeof(CHARFORMAT2);
+				cf.dwEffects = 0;
+
+				if (IsDlgButtonChecked(hwndDlg, IDC_BKGCOLOR)) {
+					if (db_get_b(NULL, CHAT_MODULE, "RightClickFilter", 0) == 0)
+						SendMessage(hwndDlg, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_BKGCOLOR);
+					else if (si->bBGSet) {
+						cf.dwMask = CFM_BACKCOLOR;
+						cf.crBackColor = pci->MM_FindModule(si->pszModule)->crColors[si->iBG];
+						SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+					}
+				}
+				else {
+					cf.dwMask = CFM_BACKCOLOR;
+					cf.crBackColor = (COLORREF)db_get_dw(NULL, CHAT_MODULE, "ColorMessageBG", GetSysColor(COLOR_WINDOW));
+					SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+				}
+			}
+			break;
+
+		case IDC_COLOR:
+			if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_COLOR))) {
+				CHARFORMAT2 cf;
+				cf.cbSize = sizeof(CHARFORMAT2);
+				cf.dwEffects = 0;
+
+				if (IsDlgButtonChecked(hwndDlg, IDC_COLOR)) {
+					if (db_get_b(NULL, CHAT_MODULE, "RightClickFilter", 0) == 0)
+						SendMessage(hwndDlg, GC_SHOWCOLORCHOOSER, 0, (LPARAM)IDC_COLOR);
+					else if (si->bFGSet) {
+						cf.dwMask = CFM_COLOR;
+						cf.crTextColor = pci->MM_FindModule(si->pszModule)->crColors[si->iFG];
+						SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+					}
+				}
+				else {
+					cf.dwMask = CFM_COLOR;
+					cf.crTextColor = g_Settings.MessageAreaColor;
+					SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+				}
+			}
+			break;
+
+		case IDC_BOLD:
+		case IDC_ITALICS:
+		case IDC_UNDERLINE:
+			CHARFORMAT2 cf;
+			cf.cbSize = sizeof(CHARFORMAT2);
+			cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
+			cf.dwEffects = 0;
+
+			if (LOWORD(wParam) == IDC_BOLD && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_BOLD)))
+				break;
+			if (LOWORD(wParam) == IDC_ITALICS && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_ITALICS)))
+				break;
+			if (LOWORD(wParam) == IDC_UNDERLINE && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_UNDERLINE)))
+				break;
+			if (IsDlgButtonChecked(hwndDlg, IDC_BOLD))
+				cf.dwEffects |= CFE_BOLD;
+			if (IsDlgButtonChecked(hwndDlg, IDC_ITALICS))
+				cf.dwEffects |= CFE_ITALIC;
+			if (IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE))
+				cf.dwEffects |= CFE_UNDERLINE;
+
+			SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+		}
+		break;
+
+	case WM_KEYDOWN:
+		SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+		break;
+
+	case WM_MOVE:
+		SendMessage(hwndDlg, GC_SAVEWNDPOS, 0, 1);
+		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->iSplitterY + 80;
+		}
+		break;
+
+	case WM_LBUTTONDBLCLK:
+		if (LOWORD(lParam) < 30)
+			PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
+		break;
+
+	case WM_CLOSE:
+		if (g_Settings.bTabsEnable && g_Settings.TabRestore && lParam != 1) {
+			TCITEM id = { 0 };
+			int j = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TAB)) - 1;
+			id.mask = TCIF_PARAM;
+			for (j; j >= 0; j--) {
+				TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TAB), j, &id);
+				SESSION_INFO *s = (SESSION_INFO*)id.lParam;
+				if (s)
+					TabM_AddTab(s->ptszID, s->pszModule);
+			}
+		}
+
+		SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 0);
+		break;
+
+	case GC_CLOSEWINDOW:
+		if (g_Settings.bTabsEnable)
+			SM_SetTabbedWindowHwnd(0, 0);
+		DestroyWindow(hwndDlg);
+		break;
+
+	case WM_DESTROY:
+		SendMessage(hwndDlg, GC_SAVEWNDPOS, 0, 0);
+
+		si->hWnd = NULL;
+		si->wState &= ~STATE_TALK;
+		DestroyWindow(si->hwndStatus);
+		si->hwndStatus = NULL;
+
+		if (si->pAccPropServicesForNickList) si->pAccPropServicesForNickList->Release();
+		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+		break;
+	}
+	return FALSE;
+}
diff --git a/src/core/stdmsg/src/msgdialog.cpp b/src/core/stdmsg/src/msgdialog.cpp
index ad192efb95..879a294db4 100644
--- a/src/core/stdmsg/src/msgdialog.cpp
+++ b/src/core/stdmsg/src/msgdialog.cpp
@@ -212,7 +212,6 @@ static void SetEditorText(HWND hwnd, const wchar_t* txt)
 	SendMessage(hwnd, EM_SETSEL, -1, -1);
 }
 
-#define EM_SUBCLASSED             (WM_USER+0x101)
 #define ENTERCLICKTIME   1000   //max time in ms during which a double-tap on enter will cause a send
 
 static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
diff --git a/src/core/stdmsg/src/msgs.cpp b/src/core/stdmsg/src/msgs.cpp
index c35b3821ef..ec7f46d28c 100644
--- a/src/core/stdmsg/src/msgs.cpp
+++ b/src/core/stdmsg/src/msgs.cpp
@@ -447,7 +447,7 @@ int LoadSendRecvMessageModule(void)
 	return 0;
 }
 
-int SplitmsgShutdown(void)
+void SplitmsgShutdown(void)
 {
 	DestroyCursor(hCurSplitNS);
 	DestroyCursor(hCurHyperlinkHand);
@@ -461,7 +461,6 @@ int SplitmsgShutdown(void)
 	FreeLibrary(hMsftEdit);
 	RichUtil_Unload();
 	msgQueue_destroy();
-	return 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/stdmsg/src/resource.h b/src/core/stdmsg/src/resource.h
index 894ce3a063..872db1500b 100644
--- a/src/core/stdmsg/src/resource.h
+++ b/src/core/stdmsg/src/resource.h
@@ -2,7 +2,51 @@
 // Microsoft Visual C++ generated include file.
 // Used by resource.rc
 //
+#define IDD_CHANNEL                     101
 #define IDD_MSGSENDERROR                102
+#define IDD_OPTIONS2                    103
+#define IDD_OPTIONS1                    104
+#define IDD_FILTER                      105
+#define IDD_OPTIONSPOPUP                106
+#define IDI_BUNDERLINE                  120
+#define IDI_BBOLD                       121
+#define IDI_BITALICS                    122
+#define IDI_BSMILEY                     123
+#define IDI_TOPICBUT                    124
+#define IDI_BKGCOLOR                    125
+#define IDI_CHANMGR                     126
+#define IDI_COLOR                       127
+#define IDI_FILTER                      128
+#define IDI_HISTORY                     129
+#define IDI_NICKLIST                    130
+#define IDI_JOIN                        131
+#define IDI_PART                        132
+#define IDI_QUIT                        133
+#define IDI_KICK                        134
+#define IDI_NICK                        135
+#define IDI_NOTICE                      136
+#define IDI_MESSAGE                     137
+#define IDI_MESSAGEOUT                  138
+#define IDI_TOPIC                       139
+#define IDI_INFO                        140
+#define IDI_ADDSTATUS                   141
+#define IDI_REMSTATUS                   142
+#define IDI_ACTION                      143
+#define IDI_HIGHLIGHT                   144
+#define IDI_BLANK                       146
+#define IDI_TAG1                        149
+#define IDI_TAG2                        150
+#define IDR_MENU                        151
+#define IDI_STATUS3                     153
+#define IDI_STATUS2                     154
+#define IDI_STATUS4                     155
+#define IDI_STATUS1                     156
+#define IDI_STATUS0                     157
+#define IDI_STATUS5                     158
+#define IDI_CLOSE                       159
+#define IDI_OVERLAY                     160
+#define IDI_NICKLIST2                   161
+#define IDI_FILTER2                     162
 #define IDR_CONTEXT                     180
 #define IDC_DROP                        183
 #define IDC_HYPERLINKHAND               214
@@ -13,17 +57,36 @@
 #define IDD_OPT_MSGTYPE                 275
 #define IDI_INCOMING                    276
 #define IDI_OUTGOING                    277
-#define IDI_NOTICE                      282
+#define IDI_EXCL                        282
 #define IDD_MODERNOPT_MSGDLG            288
 #define IDD_MODERNOPT_MSGLOG            289
+
 #define IDC_LOG                         1001
 #define IDC_MESSAGE                     1002
+#define IDC_SPLITTERX                   1003
 #define IDC_AUTOCLOSE                   1004
 #define IDC_AUTOMIN                     1005
 #define IDC_DONOTSTEALFOCUS             1006
+#define IDC_SMILEY                      1007
+#define IDC_SPLITTERY                   1008
+#define IDC_SPLITTER                    1008
 #define IDC_NAME                        1009
-#define IDC_SPLITTER                    1017
-#define IDC_SHOWNAMES                   1024
+#define IDC_BOLD                        1010
+#define IDC_ITALICS                     1011
+#define IDC_UNDERLINE                   1012
+#define IDC_FILTER                      1013
+#define IDC_CHANMGR                     1014
+#define IDC_SHOWNICKLIST                1016
+#define IDC_COLOR                       1017
+#define IDC_CHECKBOXES                  1018
+#define IDC_BKGCOLOR                    1019
+#define IDC_NICKLISTBKG                 1021
+#define IDC_HISTORY                     1022
+#define IDC_CLOSE                       1023
+#define IDC_NICKROW                     1024
+#define IDC_LOGLIMIT                    1024
+#define IDC_NICKROW2                    1025
+#define IDC_SHOWNAMES                   1026
 #define IDC_SHOWSENDBTN                 1029
 #define IDC_SHOWLOGICONS                1032
 #define IDC_SHOWTIMES                   1033
@@ -42,11 +105,51 @@
 #define IDC_LOADTIMEN                   1045
 #define IDC_LOADTIMESPIN                1046
 #define IDC_LOADTIME                    1047
-#define IDC_STMINSOLD                   1051
-#define IDC_DETAILS                     1069
-#define IDC_ADD                         1070
-#define IDC_USERMENU                    1071
-#define IDC_HISTORY                     1080
+#define IDC_STMINSOLD                   1048
+#define IDC_SPIN1                       1049
+#define IDC_SPIN2                       1050
+#define IDC_SPIN3                       1051
+#define IDC_SPIN4                       1052
+#define IDC_FONTLIST                    1053
+#define IDC_CHOOSEFONT                  1054
+#define IDC_FONTCOLOR                   1055
+#define IDC_MESSAGEBKG                  1056
+#define IDC_LOGBKG                      1057
+#define IDC_HIGHLIGHTWORDS              1058
+#define IDC_INSTAMP                     1059
+#define IDC_OUTSTAMP                    1060
+#define IDC_TIMESTAMP                   1061
+#define IDC_FONTCHOOSE                  1062
+#define IDC_LOGDIRECTORY                1063
+#define IDC_LIMIT                       1064
+#define IDC_LOGTIMESTAMP                1065
+#define IDC_GROUP                       1066
+#define IDC_RADIO1                      1067
+#define IDC_RADIO2                      1068
+#define IDC_RADIO3                      1069
+#define IDC_TEXT                        1064
+#define IDC_BKG                         1065
+#define IDC_TIMEOUT                     1067
+#define IDC_HIGHLIGHT                   1068
+#define IDC_TEXTO                       1069
+#define IDC_LOGGING                     1069
+#define IDC_LIST                        1072
+#define IDC_TAB                         1074
+#define IDC_1                           1075
+#define IDC_2                           1076
+#define IDC_3                           1077
+#define IDC_4                           1078
+#define IDC_5                           1079
+#define IDC_6                           1080
+#define IDC_7                           1081
+#define IDC_8                           1082
+#define IDC_9                           1083
+#define IDC_10                          1084
+#define IDC_11                          1085
+
+#define IDC_DETAILS                     1469
+#define IDC_ADD                         1470
+#define IDC_USERMENU                    1471
 #define IDC_STMSGLOGGROUP               1442
 #define IDC_PROTOCOL                    1580
 #define IDC_ERRORTEXT                   1596
@@ -72,6 +175,7 @@
 #define IDC_TXT_TITLE1                  1617
 #define IDC_TXT_TITLE2                  1618
 #define IDC_TXT_TITLE3                  1619
+
 #define IDM_CUT                         40000
 #define IDM_COPY                        40001
 #define IDM_PASTE                       40002
@@ -85,6 +189,25 @@
 #define IDM_OPENLINK                    40014
 #define IDM_COPYLINK                    40016
 
+#define ID_MESS                         40021
+#define ID_NEW                          40022
+#define ID_CURR                         40023
+#define ID_COPY                         40024
+#define ID_COPYALL                      40026
+#define ID_CLEARLOG                     40029
+#define ID_MESSAGE_UNDO                 40033
+#define ID_MESSAGE_COPY                 40034
+#define ID_MESSAGE_CUT                  40035
+#define ID_MESSAGE_CLEAR                40037
+#define ID_MESSAGE_SELECTALL            40038
+#define ID_MESSAGE_REDO                 40039
+#define ID_MESSAGE_PASTE                40030
+#define ID_CLOSE                        40042
+#define ID_CLOSEOTHER                   40043
+#define ID_LOCKPOSITION                 40044
+#define ID_SEARCH_GOOGLE                40047
+#define ID_SEARCH_WIKIPEDIA             40048
+
 // Next default values for new objects
 // 
 #ifdef APSTUDIO_INVOKED
diff --git a/src/core/stdmsg/src/srmm.cpp b/src/core/stdmsg/src/srmm.cpp
index 397b84676c..434d561160 100644
--- a/src/core/stdmsg/src/srmm.cpp
+++ b/src/core/stdmsg/src/srmm.cpp
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "stdafx.h"
 
 int LoadSendRecvMessageModule(void);
-int SplitmsgShutdown(void);
+void SplitmsgShutdown(void);
 
 CLIST_INTERFACE *pcli;
 HINSTANCE g_hInst;
@@ -52,17 +52,20 @@ extern "C" __declspec(dllexport) PLUGININFOEX *MirandaPluginInfoEx(DWORD)
 	return &pluginInfo;
 }
 
-extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_SRMM, MIID_LAST};
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_SRMM, MIID_LAST };
 
 extern "C" int __declspec(dllexport) Load(void)
 {
 	mir_getLP(&pluginInfo);
 	pcli = Clist_GetInterface();
 
+	Load_ChatModule();
 	return LoadSendRecvMessageModule();
 }
 
 extern "C" int __declspec(dllexport) Unload(void)
 {
-	return SplitmsgShutdown();
+	SplitmsgShutdown();
+	Unload_ChatModule();
+	return 0;
 }
diff --git a/src/core/stdmsg/src/stdafx.h b/src/core/stdmsg/src/stdafx.h
index 35acfc8216..d08445ca47 100644
--- a/src/core/stdmsg/src/stdafx.h
+++ b/src/core/stdmsg/src/stdafx.h
@@ -28,6 +28,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <shlobj.h>
 #include <commctrl.h>
 #include <vssym32.h>
+
+#include <Initguid.h>
+#include <Oleacc.h>
 #include <Uxtheme.h>
 
 #include <malloc.h>
@@ -52,6 +55,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <m_userinfo.h>
 #include <m_history.h>
 #include <m_addcontact.h>
+#include <m_chat_int.h>
 #include <m_message.h>
 #include <m_file.h>
 #include <m_icolib.h>
@@ -59,6 +63,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <m_timezones.h>
 #include <m_avatars.h>
 #include <m_metacontacts.h>
+#include <m_ieview.h>
+#include <m_smileyadd.h>
+#include <m_popup.h>
 
 #include "cmdlist.h"
 #include "msgs.h"
@@ -66,7 +73,95 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "richutil.h"
 #include "version.h"
 
+#define EM_SUBCLASSED (WM_USER+0x101)
+#define EM_ACTIVATE   (WM_USER+0x102)
+
 extern HINSTANCE g_hInst;
 extern HCURSOR hCurSplitNS, hCurSplitWE, hCurHyperlinkHand;
 extern HANDLE hHookWinEvt, hHookWinPopup, hHookWinWrite;
 extern CREOleCallback reOleCallback;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct TABLIST
+{
+	wchar_t *pszID;
+	char *pszModule;
+	TABLIST *next;
+};
+
+struct MODULEINFO : public GCModuleInfoBase
+{
+	int OnlineIconIndex;
+	int OfflineIconIndex;
+};
+
+struct SESSION_INFO : public GCSessionInfoBase
+{
+	int iX, iY;
+	IAccPropServices* pAccPropServicesForNickList;
+};
+
+struct LOGSTREAMDATA : public GCLogStreamDataBase {};
+
+struct GlobalLogSettings : public GlobalLogSettingsBase
+{
+	int   iX, iY;
+	bool  bTabsEnable, TabsAtBottom, TabCloseOnDblClick, TabRestore;
+
+	HFONT MessageAreaFont;
+	COLORREF MessageAreaColor;
+};
+
+extern GlobalLogSettings g_Settings;
+extern SESSION_INFO g_TabSession;
+extern CHAT_MANAGER saveCI;
+extern TABLIST *g_TabList;
+extern HMENU g_hMenu;
+extern HIMAGELIST hIconsList;
+
+extern HINSTANCE g_hInst;
+extern BOOL SmileyAddInstalled, PopupInstalled;
+
+//main.c
+void LoadIcons(void);
+void Unload_ChatModule();
+void Load_ChatModule();
+
+// log.c
+void Log_StreamInEvent(HWND hwndDlg, LOGINFO* lin, SESSION_INFO *si, BOOL bRedraw, BOOL bPhaseTwo);
+void ValidateFilename(wchar_t * filename);
+char* Log_CreateRtfHeader(MODULEINFO * mi);
+
+// window.c
+INT_PTR CALLBACK RoomWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+int GetTextPixelSize(wchar_t* pszText, HFONT hFont, BOOL bWidth);
+
+BOOL SM_SetTabbedWindowHwnd(SESSION_INFO *si, HWND hwnd);
+SESSION_INFO* SM_GetPrevWindow(SESSION_INFO *si);
+SESSION_INFO* SM_GetNextWindow(SESSION_INFO *si);
+
+// options.c
+int OptionsInitialize(WPARAM wParam, LPARAM lParam);
+void AddIcons(void);
+HICON LoadIconEx(const char *pszIcoLibName, bool big);
+HANDLE GetIconHandle(const char *pszIcolibName);
+
+// services.c
+void ShowRoom(SESSION_INFO *si, WPARAM wp, BOOL bSetForeground);
+
+// tools.c
+int  GetColorIndex(const char* pszModule, COLORREF cr);
+void CheckColorsInModule(const char* pszModule);
+int  GetRichTextLength(HWND hwnd);
+UINT CreateGCMenu(HWND hwndDlg, HMENU *hMenu, int iIndex, POINT pt, SESSION_INFO *si, wchar_t* pszUID, wchar_t* pszWordText);
+void DestroyGCMenu(HMENU *hMenu, int iIndex);
+bool LoadMessageFont(LOGFONT *lf, COLORREF *colour);
+
+// message.c
+char* Message_GetFromStream(HWND hwndDlg, SESSION_INFO *si);
+
+BOOL TabM_AddTab(const wchar_t *pszID, const char* pszModule);
+BOOL TabM_RemoveAll(void);
+
+#pragma comment(lib,"comctl32.lib")
-- 
cgit v1.2.3