From 5c002a15891fc4cdfaeda7247003e13db28fc5ca Mon Sep 17 00:00:00 2001
From: George Hazan <ghazan@miranda.im>
Date: Sun, 26 Feb 2017 16:02:07 +0300
Subject: Scriver moved to UI classes

---
 plugins/Scriver/src/chat/chat.h     |    8 +-
 plugins/Scriver/src/chat/window.cpp | 1638 +++++++++++++++++------------------
 plugins/Scriver/src/infobar.cpp     |   34 +-
 plugins/Scriver/src/infobar.h       |    4 +-
 plugins/Scriver/src/input.cpp       |   53 --
 plugins/Scriver/src/input.h         |    1 -
 plugins/Scriver/src/msgdialog.cpp   | 1284 ++++++++++++++-------------
 plugins/Scriver/src/msglog.cpp      |   88 +-
 plugins/Scriver/src/msgs.cpp        |   40 +-
 plugins/Scriver/src/msgs.h          |  193 +++--
 plugins/Scriver/src/stdafx.h        |    1 +
 plugins/Scriver/src/tabs.cpp        |    6 +
 plugins/Scriver/src/utils.cpp       |    4 +-
 plugins/Scriver/src/utils.h         |    2 +-
 plugins/Scriver/src/version.h       |    6 +-
 15 files changed, 1634 insertions(+), 1728 deletions(-)

(limited to 'plugins/Scriver/src')

diff --git a/plugins/Scriver/src/chat/chat.h b/plugins/Scriver/src/chat/chat.h
index 3b03840bb9..b9cb61f0dd 100644
--- a/plugins/Scriver/src/chat/chat.h
+++ b/plugins/Scriver/src/chat/chat.h
@@ -22,8 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #ifndef _CHAT_H_
 #define _CHAT_H_
 
-#include <m_chat_int.h>
-
 #define EM_ACTIVATE (WM_USER+202)
 
 #define TIMERID_MSGSEND    201
@@ -45,7 +43,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define CFM_BACKCOLOR		0x04000000
 #endif
 
-//structs
+// structs
 
 struct MODULEINFO : public GCModuleInfoBase
 {
@@ -91,11 +89,11 @@ char          SM_GetStatusIndicator(SESSION_INFO *si, USERINFO *ui);
 
 // tools.c
 BOOL          DoSoundsFlashPopupTrayStuff(SESSION_INFO *si, GCEVENT *gce, BOOL bHighlight, int bManyFix);
-wchar_t*        my_strstri(const wchar_t* s1, const wchar_t* s2) ;
+wchar_t*      my_strstri(const wchar_t* s1, const wchar_t* s2) ;
 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);
 
-//////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
 
 #define DEFLOGFILENAME L"%miranda_logpath%\\%proto%\\%userid%.log"
 #endif
diff --git a/plugins/Scriver/src/chat/window.cpp b/plugins/Scriver/src/chat/window.cpp
index db29862b00..bb980fc252 100644
--- a/plugins/Scriver/src/chat/window.cpp
+++ b/plugins/Scriver/src/chat/window.cpp
@@ -78,69 +78,6 @@ static void InitButtons(HWND hwndDlg, SESSION_INFO *si)
 	}
 }
 
-static void MessageDialogResize(HWND hwndDlg, SESSION_INFO *si, int w, int h)
-{
-	bool bNick = si->iType != GCW_SERVER && si->bNicklistEnabled;
-	bool bToolbar = SendMessage(GetParent(hwndDlg), CM_GETTOOLBARSTATUS, 0, 0) != 0;
-	int  hSplitterMinTop = TOOLBAR_HEIGHT + si->minLogBoxHeight, hSplitterMinBottom = si->minEditBoxHeight;
-	int  toolbarHeight = bToolbar ? TOOLBAR_HEIGHT : 0;
-
-	si->iSplitterY = si->desiredInputAreaHeight + SPLITTER_HEIGHT + 3;
-
-	if (h - si->iSplitterY < hSplitterMinTop)
-		si->iSplitterY = h - hSplitterMinTop;
-	if (si->iSplitterY < hSplitterMinBottom)
-		si->iSplitterY = hSplitterMinBottom;
-
-	ShowWindow(GetDlgItem(hwndDlg, IDC_SPLITTERX), bNick ? SW_SHOW : SW_HIDE);
-	if (si->iType != GCW_SERVER)
-		ShowWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIST), si->bNicklistEnabled ? SW_SHOW : SW_HIDE);
-	else
-		ShowWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIST), SW_HIDE);
-
-	if (si->iType == GCW_SERVER) {
-		EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_SHOWNICKLIST), FALSE);
-		EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_FILTER), FALSE);
-		EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_CHANMGR), FALSE);
-	}
-	else {
-		EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_SHOWNICKLIST), TRUE);
-		EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_FILTER), TRUE);
-		if (si->iType == GCW_CHATROOM)
-			EnableWindow(GetDlgItem(hwndDlg, IDC_CHAT_CHANMGR), pci->MM_FindModule(si->pszModule)->bChanMgr);
-	}
-
-	HDWP hdwp = BeginDeferWindowPos(5);
-	int toolbarTopY = bToolbar ? h - si->iSplitterY - toolbarHeight : h - si->iSplitterY;
-	int logBottom = (si->hwndLog != NULL) ? toolbarTopY / 2 : toolbarTopY;
-
-	hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_LOG), 0, 1, 0, bNick ? w - si->iSplitterX - 1 : w - 2, logBottom, SWP_NOZORDER);
-	hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_CHAT_LIST), 0, w - si->iSplitterX + 2, 0, si->iSplitterX - 3, toolbarTopY, SWP_NOZORDER);
-	hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_SPLITTERX), 0, w - si->iSplitterX, 1, 2, toolbarTopY - 1, SWP_NOZORDER);
-	hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_SPLITTERY), 0, 0, h - si->iSplitterY, w, SPLITTER_HEIGHT, SWP_NOZORDER);
-	hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 1, h - si->iSplitterY + SPLITTER_HEIGHT, w - 2, si->iSplitterY - SPLITTER_HEIGHT - 1, SWP_NOZORDER);
-	EndDeferWindowPos(hdwp);
-
-	SetButtonsPos(hwndDlg, bToolbar);
-
-	if (si->hwndLog != NULL) {
-		IEVIEWWINDOW ieWindow;
-		ieWindow.cbSize = sizeof(IEVIEWWINDOW);
-		ieWindow.iType = IEW_SETPOS;
-		ieWindow.parent = hwndDlg;
-		ieWindow.hwnd = si->hwndLog;
-		ieWindow.x = 0;
-		ieWindow.y = logBottom + 1;
-		ieWindow.cx = bNick ? w - si->iSplitterX : w;
-		ieWindow.cy = logBottom;
-		CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
-	}
-	else RedrawWindow(GetDlgItem(hwndDlg, IDC_LOG), NULL, NULL, RDW_INVALIDATE);
-
-	RedrawWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIST), NULL, NULL, RDW_INVALIDATE);
-	RedrawWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, NULL, RDW_INVALIDATE);
-}
-
 static void TabAutoComplete(HWND hwnd, MESSAGESUBDATA *dat, SESSION_INFO *si)
 {
 	LRESULT lResult = (LRESULT)SendMessage(hwnd, EM_GETSEL, 0, 0);
@@ -906,897 +843,953 @@ static void __cdecl phase2(void *lParam)
 		PostMessage(si->hWnd, GC_REDRAWLOG2, 0, 0);
 }
 
-static INT_PTR CALLBACK RoomWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-	static HMENU hToolbarMenu;
-	RECT rc;
-	POINT pt;
-	HICON hIcon;
-	TabControlData tcd;
-	TitleBarData tbd;
-	wchar_t szTemp[512];
-
-	SESSION_INFO *si = (SESSION_INFO *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-	if (!si && uMsg != WM_INITDIALOG)
-		return FALSE;
-
-	switch (uMsg) {
-	case WM_INITDIALOG:
-		TranslateDialogDefault(hwndDlg);
-		{
-			SESSION_INFO *psi = (SESSION_INFO*)lParam;
-			NotifyLocalWinEvent(psi->hContact, hwndDlg, MSG_WINDOW_EVT_OPENING);
-
-			TranslateDialogDefault(hwndDlg);
-			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)psi);
-			si = psi;
-			RichUtil_SubClass(GetDlgItem(hwndDlg, IDC_MESSAGE));
-			RichUtil_SubClass(GetDlgItem(hwndDlg, IDC_LOG));
-			RichUtil_SubClass(GetDlgItem(hwndDlg, IDC_CHAT_LIST));
-			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_SPLITTERX), SplitterSubclassProc);
-			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIST), NicklistSubclassProc);
-			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_LOG), LogSubclassProc);
-			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_CHAT_FILTER), ButtonSubclassProc);
-			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_CHAT_COLOR), ButtonSubclassProc);
-			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_CHAT_BKGCOLOR), ButtonSubclassProc);
-			mir_subclassWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), MessageSubclassProc);
-
-			Srmm_CreateToolbarIcons(hwndDlg, BBBF_ISCHATBUTTON);
-
-			RECT minEditInit;
-			GetWindowRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &minEditInit);
-			si->minEditBoxHeight = minEditInit.bottom - minEditInit.top;
-			si->minLogBoxHeight = si->minEditBoxHeight;
-
-			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_MESSAGE, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_CHANGE | ENM_REQUESTRESIZE);
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_LIMITTEXT, sizeof(wchar_t) * 0x7FFFFFFF, 0);
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETOLECALLBACK, 0, (LPARAM)&reOleCallback);
-
-			if (db_get_b(NULL, CHAT_MODULE, "UseIEView", 0)) {
-				IEVIEWWINDOW ieWindow = { sizeof(ieWindow) };
-				ieWindow.iType = IEW_CREATE;
-				ieWindow.dwMode = IEWM_CHAT;
-				ieWindow.parent = hwndDlg;
-				ieWindow.cx = 200;
-				ieWindow.cy = 300;
-				CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
-
-				si->hwndLog = ieWindow.hwnd;
-
-				IEVIEWEVENT iee = { sizeof(iee) };
-				iee.iType = IEE_CLEAR_LOG;
-				iee.hwnd = si->hwndLog;
-				iee.hContact = si->hContact;
-				iee.pszProto = si->pszModule;
-				CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&iee);
-			}
+/////////////////////////////////////////////////////////////////////////////////////////
 
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_HIDESELECTION, TRUE, 0);
+class CChatRoomDlg : public CSrmmBaseDialog
+{
+	SESSION_INFO *m_si;
 
-			SendMessage(hwndDlg, GC_SETWNDPROPS, 0, 0);
-			SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
-			SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0);
+	CCtrlEdit m_message, m_log;
+	CCtrlListBox m_nickList;
 
-			SendMessage(GetParent(hwndDlg), CM_ADDCHILD, (WPARAM)hwndDlg, psi->hContact);
-			PostMessage(hwndDlg, GC_UPDATENICKLIST, 0, 0);
-			NotifyLocalWinEvent(psi->hContact, hwndDlg, MSG_WINDOW_EVT_OPEN);
-		}
-		break;
+	void MessageDialogResize(int w, int h)
+	{
+		bool bNick = m_si->iType != GCW_SERVER && m_si->bNicklistEnabled;
+		bool bToolbar = SendMessage(GetParent(m_hwnd), CM_GETTOOLBARSTATUS, 0, 0) != 0;
+		int  hSplitterMinTop = TOOLBAR_HEIGHT + m_si->minLogBoxHeight, hSplitterMinBottom = m_si->minEditBoxHeight;
+		int  toolbarHeight = bToolbar ? TOOLBAR_HEIGHT : 0;
 
-	case GC_SETWNDPROPS:
-		// LoadGlobalSettings();
-		InitButtons(hwndDlg, si);
+		m_si->iSplitterY = m_si->desiredInputAreaHeight + SPLITTER_HEIGHT + 3;
 
-		SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
-		SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0);
-		SendMessage(hwndDlg, GC_FIXTABICONS, 0, 0);
+		if (h - m_si->iSplitterY < hSplitterMinTop)
+			m_si->iSplitterY = h - hSplitterMinTop;
+		if (m_si->iSplitterY < hSplitterMinBottom)
+			m_si->iSplitterY = hSplitterMinBottom;
 
-		SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETBKGNDCOLOR, 0, g_Settings.crLogBackground);
-		{
-			// messagebox
-			COLORREF crFore;
-			LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, NULL, &crFore);
-
-			CHARFORMAT2 cf;
-			cf.cbSize = sizeof(CHARFORMAT2);
-			cf.dwMask = CFM_COLOR | CFM_BOLD | CFM_UNDERLINE | CFM_BACKCOLOR;
-			cf.dwEffects = 0;
-			cf.crTextColor = crFore;
-			cf.crBackColor = db_get_dw(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR);
-			SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETBKGNDCOLOR, 0, db_get_dw(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR));
-			SendDlgItemMessage(hwndDlg, IDC_MESSAGE, WM_SETFONT, (WPARAM)g_Settings.MessageBoxFont, MAKELPARAM(TRUE, 0));
-			SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
-		
-			// nicklist
-			int ih = GetTextPixelSize(L"AQG_glo'", g_Settings.UserListFont, FALSE);
-			int ih2 = GetTextPixelSize(L"AQG_glo'", 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 (db_get_b(NULL, CHAT_MODULE, "ShowContactStatus", 0))
-				font = font > 16 ? font : 16;
-
-			SendDlgItemMessage(hwndDlg, IDC_CHAT_LIST, LB_SETITEMHEIGHT, 0, height > font ? height : font);
-			InvalidateRect(GetDlgItem(hwndDlg, IDC_CHAT_LIST), NULL, TRUE);
-		}
-		SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_REQUESTRESIZE, 0, 0);
-		SendMessage(hwndDlg, WM_SIZE, 0, 0);
-		SendMessage(hwndDlg, GC_REDRAWLOG2, 0, 0);
-		break;
+		ShowWindow(GetDlgItem(m_hwnd, IDC_SPLITTERX), bNick ? SW_SHOW : SW_HIDE);
+		if (m_si->iType != GCW_SERVER)
+			ShowWindow(GetDlgItem(m_hwnd, IDC_CHAT_LIST), m_si->bNicklistEnabled ? SW_SHOW : SW_HIDE);
+		else
+			ShowWindow(GetDlgItem(m_hwnd, IDC_CHAT_LIST), SW_HIDE);
 
-	case DM_UPDATETITLEBAR:
-		if (g_dat.flags & SMF_STATUSICON) {
-			MODULEINFO *mi = pci->MM_FindModule(si->pszModule);
-			tbd.hIcon = (si->wStatus == ID_STATUS_ONLINE) ? mi->hOnlineIcon : mi->hOfflineIcon;
-			tbd.hIconBig = (si->wStatus == ID_STATUS_ONLINE) ? mi->hOnlineIconBig : mi->hOfflineIconBig;
+		if (m_si->iType == GCW_SERVER) {
+			EnableWindow(GetDlgItem(m_hwnd, IDC_CHAT_SHOWNICKLIST), FALSE);
+			EnableWindow(GetDlgItem(m_hwnd, IDC_CHAT_FILTER), FALSE);
+			EnableWindow(GetDlgItem(m_hwnd, IDC_CHAT_CHANMGR), FALSE);
 		}
 		else {
-			tbd.hIcon = GetCachedIcon("chat_window");
-			tbd.hIconBig = g_dat.hIconChatBig;
+			EnableWindow(GetDlgItem(m_hwnd, IDC_CHAT_SHOWNICKLIST), TRUE);
+			EnableWindow(GetDlgItem(m_hwnd, IDC_CHAT_FILTER), TRUE);
+			if (m_si->iType == GCW_CHATROOM)
+				EnableWindow(GetDlgItem(m_hwnd, IDC_CHAT_CHANMGR), pci->MM_FindModule(m_si->pszModule)->bChanMgr);
 		}
-		tbd.hIconNot = (si->wState & (GC_EVENT_HIGHLIGHT | STATE_TALK)) ? GetCachedIcon("chat_overlay") : NULL;
 
-		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;
-		}
-		tbd.iFlags = TBDF_TEXT | TBDF_ICON;
-		tbd.pszText = szTemp;
-		SendMessage(GetParent(hwndDlg), CM_UPDATETITLEBAR, (WPARAM)&tbd, (LPARAM)hwndDlg);
-		SendMessage(hwndDlg, DM_UPDATETABCONTROL, 0, 0);
-		break;
+		HDWP hdwp = BeginDeferWindowPos(5);
+		int toolbarTopY = bToolbar ? h - m_si->iSplitterY - toolbarHeight : h - m_si->iSplitterY;
+		int logBottom = (m_si->hwndIeview != NULL) ? toolbarTopY / 2 : toolbarTopY;
 
-	case GC_UPDATESTATUSBAR:
-		{
-			MODULEINFO *mi = pci->MM_FindModule(si->pszModule);
-			hIcon = si->wStatus == ID_STATUS_ONLINE ? mi->hOnlineIcon : mi->hOfflineIcon;
-			mir_snwprintf(szTemp, L"%s : %s", mi->ptszModDispName, si->ptszStatusbarText ? si->ptszStatusbarText : L"");
-
-			StatusBarData sbd;
-			sbd.iItem = 0;
-			sbd.iFlags = SBDF_TEXT | SBDF_ICON;
-			sbd.hIcon = hIcon;
-			sbd.pszText = szTemp;
-			SendMessage(GetParent(hwndDlg), CM_UPDATESTATUSBAR, (WPARAM)&sbd, (LPARAM)hwndDlg);
-
-			sbd.iItem = 1;
-			sbd.hIcon = NULL;
-			sbd.pszText = L"";
-			SendMessage(GetParent(hwndDlg), CM_UPDATESTATUSBAR, (WPARAM)&sbd, (LPARAM)hwndDlg);
-
-			StatusIconData sid = { sizeof(sid) };
-			sid.szModule = SRMMMOD;
-			Srmm_ModifyIcon(si->hContact, &sid);
+		hdwp = DeferWindowPos(hdwp, GetDlgItem(m_hwnd, IDC_LOG), 0, 1, 0, bNick ? w - m_si->iSplitterX - 1 : w - 2, logBottom, SWP_NOZORDER);
+		hdwp = DeferWindowPos(hdwp, GetDlgItem(m_hwnd, IDC_CHAT_LIST), 0, w - m_si->iSplitterX + 2, 0, m_si->iSplitterX - 3, toolbarTopY, SWP_NOZORDER);
+		hdwp = DeferWindowPos(hdwp, GetDlgItem(m_hwnd, IDC_SPLITTERX), 0, w - m_si->iSplitterX, 1, 2, toolbarTopY - 1, SWP_NOZORDER);
+		hdwp = DeferWindowPos(hdwp, GetDlgItem(m_hwnd, IDC_SPLITTERY), 0, 0, h - m_si->iSplitterY, w, SPLITTER_HEIGHT, SWP_NOZORDER);
+		hdwp = DeferWindowPos(hdwp, GetDlgItem(m_hwnd, IDC_MESSAGE), 0, 1, h - m_si->iSplitterY + SPLITTER_HEIGHT, w - 2, m_si->iSplitterY - SPLITTER_HEIGHT - 1, SWP_NOZORDER);
+		EndDeferWindowPos(hdwp);
+
+		SetButtonsPos(m_hwnd, bToolbar);
+
+		if (m_si->hwndIeview != NULL) {
+			IEVIEWWINDOW ieWindow;
+			ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+			ieWindow.iType = IEW_SETPOS;
+			ieWindow.parent = m_hwnd;
+			ieWindow.hwnd = m_si->hwndIeview;
+			ieWindow.x = 0;
+			ieWindow.y = logBottom + 1;
+			ieWindow.cx = bNick ? w - m_si->iSplitterX : w;
+			ieWindow.cy = logBottom;
+			CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
 		}
-		break;
+		else RedrawWindow(GetDlgItem(m_hwnd, IDC_LOG), NULL, NULL, RDW_INVALIDATE);
 
-	case DM_SWITCHINFOBAR:
-	case DM_SWITCHTOOLBAR:
-		SendMessage(hwndDlg, WM_SIZE, 0, 0);
-		break;
+		RedrawWindow(GetDlgItem(m_hwnd, IDC_CHAT_LIST), NULL, NULL, RDW_INVALIDATE);
+		RedrawWindow(GetDlgItem(m_hwnd, IDC_MESSAGE), NULL, NULL, RDW_INVALIDATE);
+	}
 
-	case WM_SIZE:
-		if (wParam == SIZE_MAXIMIZED)
-			PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
+public:
+	CChatRoomDlg(SESSION_INFO *si)
+		: CSrmmBaseDialog(g_hInst, IDD_CHANNEL),
+		m_si(si),
+		m_log(this, IDC_LOG),
+		m_message(this, IDC_MESSAGE),
+		m_nickList(this, IDC_CHAT_LIST)
+	{
+		m_pLog = &m_log;
+		m_pEntry = &m_message;
+		m_autoClose = 0;
+	}
 
-		if (IsIconic(hwndDlg)) break;
+	virtual void OnInitDialog() override
+	{
+		NotifyLocalWinEvent(m_si->hContact, m_hwnd, MSG_WINDOW_EVT_OPENING);
+
+		SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)m_si);
+
+		RichUtil_SubClass(m_message.GetHwnd());
+		RichUtil_SubClass(m_log.GetHwnd());
+		RichUtil_SubClass(m_nickList.GetHwnd());
+		mir_subclassWindow(GetDlgItem(m_hwnd, IDC_SPLITTERX), SplitterSubclassProc);
+		mir_subclassWindow(m_nickList.GetHwnd(), NicklistSubclassProc);
+		mir_subclassWindow(m_log.GetHwnd(), LogSubclassProc);
+		mir_subclassWindow(GetDlgItem(m_hwnd, IDC_CHAT_FILTER), ButtonSubclassProc);
+		mir_subclassWindow(GetDlgItem(m_hwnd, IDC_CHAT_COLOR), ButtonSubclassProc);
+		mir_subclassWindow(GetDlgItem(m_hwnd, IDC_CHAT_BKGCOLOR), ButtonSubclassProc);
+		mir_subclassWindow(m_message.GetHwnd(), MessageSubclassProc);
+
+		Srmm_CreateToolbarIcons(m_hwnd, BBBF_ISCHATBUTTON);
+
+		RECT minEditInit;
+		GetWindowRect(m_message.GetHwnd(), &minEditInit);
+		m_si->minEditBoxHeight = minEditInit.bottom - minEditInit.top;
+		m_si->minLogBoxHeight = m_si->minEditBoxHeight;
+
+		m_message.SendMsg(EM_SUBCLASSED, 0, 0);
+		m_message.SendMsg(EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_CHANGE | ENM_REQUESTRESIZE);
+
+		int mask = (int)m_log.SendMsg(EM_GETEVENTMASK, 0, 0);
+		m_log.SendMsg(EM_SETEVENTMASK, 0, mask | ENM_LINK | ENM_MOUSEEVENTS);
+		m_log.SendMsg(EM_LIMITTEXT, sizeof(wchar_t) * 0x7FFFFFFF, 0);
+		m_log.SendMsg(EM_SETOLECALLBACK, 0, (LPARAM)&reOleCallback);
+		m_log.SendMsg(EM_AUTOURLDETECT, 1, 0);
+
+		if (db_get_b(NULL, CHAT_MODULE, "UseIEView", 0)) {
+			IEVIEWWINDOW ieWindow = { sizeof(ieWindow) };
+			ieWindow.iType = IEW_CREATE;
+			ieWindow.dwMode = IEWM_CHAT;
+			ieWindow.parent = m_hwnd;
+			ieWindow.cx = 200;
+			ieWindow.cy = 300;
+			CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
 
-		if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) {
-			int dlgWidth, dlgHeight;
-			dlgWidth = LOWORD(lParam);
-			dlgHeight = HIWORD(lParam);
-			GetClientRect(hwndDlg, &rc);
+			m_si->hwndIeview = ieWindow.hwnd;
 
-			dlgWidth = rc.right - rc.left;
-			dlgHeight = rc.bottom - rc.top;
-			MessageDialogResize(hwndDlg, si, dlgWidth, dlgHeight);
+			IEVIEWEVENT iee = { sizeof(iee) };
+			iee.iType = IEE_CLEAR_LOG;
+			iee.hwnd = m_si->hwndIeview;
+			iee.hContact = m_si->hContact;
+			iee.pszProto = m_si->pszModule;
+			CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&iee);
 		}
-		break;
 
-	case GC_REDRAWWINDOW:
-		InvalidateRect(hwndDlg, NULL, TRUE);
-		break;
+		m_log.SendMsg(EM_HIDESELECTION, TRUE, 0);
 
-	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;
+		SendMessage(m_hwnd, GC_SETWNDPROPS, 0, 0);
+		SendMessage(m_hwnd, GC_UPDATESTATUSBAR, 0, 0);
+		SendMessage(m_hwnd, DM_UPDATETITLEBAR, 0, 0);
 
-					pLog = pLog->next;
-					if ((si->iType != GCW_CHATROOM && si->iType != GCW_PRIVMESS) || !si->bFilterEnabled || (si->iLogFilterFlags&pLog->iType) != 0)
-						index++;
-				}
-				Log_StreamInEvent(hwndDlg, pLog, si, TRUE);
-				mir_forkthread(phase2, si);
-			}
-			else Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE);
-		}
-		else SendMessage(hwndDlg, GC_CONTROL_MSG, WINDOW_CLEARLOG, 0);
-		break;
-
-	case GC_REDRAWLOG2:
-		si->LastTime = 0;
-		if (si->pLog)
-			Log_StreamInEvent(hwndDlg, si->pLogEnd, si, TRUE);
-		break;
+		SendMessage(GetParent(m_hwnd), CM_ADDCHILD, (WPARAM)m_hwnd, m_si->hContact);
+		PostMessage(m_hwnd, GC_UPDATENICKLIST, 0, 0);
+		NotifyLocalWinEvent(m_si->hContact, m_hwnd, MSG_WINDOW_EVT_OPEN);
+	}
 
-	case GC_ADDLOG:
-		if (si->pLogEnd)
-			Log_StreamInEvent(hwndDlg, si->pLog, si, FALSE);
-		else
-			SendMessage(hwndDlg, GC_CONTROL_MSG, WINDOW_CLEARLOG, 0);
-		break;
+	virtual void OnDestroy() override
+	{
+		NotifyLocalWinEvent(m_si->hContact, m_hwnd, MSG_WINDOW_EVT_CLOSING);
 
-	case DM_UPDATETABCONTROL:
-		tcd.iFlags = TCDF_TEXT;
-		tcd.pszText = si->ptszName;
-		SendMessage(GetParent(hwndDlg), CM_UPDATETABCONTROL, (WPARAM)&tcd, (LPARAM)hwndDlg);
-		// fall through
+		m_si->hWnd = NULL;
+		SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0);
 
-	case GC_FIXTABICONS:
-		if (!(si->wState & GC_EVENT_HIGHLIGHT)) {
-			if (si->wState & STATE_TALK)
-				hIcon = (si->wStatus == ID_STATUS_ONLINE) ? pci->MM_FindModule(si->pszModule)->hOnlineTalkIcon : pci->MM_FindModule(si->pszModule)->hOfflineTalkIcon;
-			else
-				hIcon = (si->wStatus == ID_STATUS_ONLINE) ? pci->MM_FindModule(si->pszModule)->hOnlineIcon : pci->MM_FindModule(si->pszModule)->hOfflineIcon;
+		SendMessage(GetParent(m_hwnd), CM_REMOVECHILD, 0, (LPARAM)m_hwnd);
+		if (m_si->hwndIeview != NULL) {
+			IEVIEWWINDOW ieWindow;
+			ieWindow.cbSize = sizeof(IEVIEWWINDOW);
+			ieWindow.iType = IEW_DESTROY;
+			ieWindow.hwnd = m_si->hwndIeview;
+			CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
 		}
-		else hIcon = g_dat.hMsgIcon;
 
-		tcd.iFlags = TCDF_ICON;
-		tcd.hIcon = hIcon;
-		SendMessage(GetParent(hwndDlg), CM_UPDATETABCONTROL, (WPARAM)&tcd, (LPARAM)hwndDlg);
-		break;
+		NotifyLocalWinEvent(m_si->hContact, m_hwnd, MSG_WINDOW_EVT_CLOSE);
+	}
 
-	case GC_SETMESSAGEHIGHLIGHT:
-		si->wState |= GC_EVENT_HIGHLIGHT;
-		SendMessage(si->hWnd, GC_FIXTABICONS, 0, 0);
-		SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0);
-		if (g_Settings.bFlashWindowHighlight && GetActiveWindow() != hwndDlg && GetForegroundWindow() != GetParent(hwndDlg))
-			SendMessage(GetParent(si->hWnd), CM_STARTFLASHING, 0, 0);
-		break;
+	virtual INT_PTR DlgProc(UINT uMsg, WPARAM wParam, LPARAM lParam) override
+	{
+		static HMENU hToolbarMenu;
+		RECT rc;
+		POINT pt;
+		HICON hIcon;
+		TabControlData tcd;
+		TitleBarData tbd;
+		wchar_t szTemp[512];
 
-	case GC_SETTABHIGHLIGHT:
-		SendMessage(si->hWnd, GC_FIXTABICONS, 0, 0);
-		SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0);
-		if (g_Settings.bFlashWindow && GetActiveWindow() != GetParent(hwndDlg) && GetForegroundWindow() != GetParent(hwndDlg))
-			SendMessage(GetParent(si->hWnd), CM_STARTFLASHING, 0, 0);
-		break;
+		switch (uMsg) {
+		case GC_SETWNDPROPS:
+			// LoadGlobalSettings();
+			InitButtons(m_hwnd, m_si);
 
-	case DM_ACTIVATE:
-		if (si->wState & STATE_TALK) {
-			si->wState &= ~STATE_TALK;
-			db_set_w(si->hContact, si->pszModule, "ApparentMode", 0);
-		}
+			SendMessage(m_hwnd, GC_UPDATESTATUSBAR, 0, 0);
+			SendMessage(m_hwnd, DM_UPDATETITLEBAR, 0, 0);
+			SendMessage(m_hwnd, GC_FIXTABICONS, 0, 0);
 
-		if (si->wState & GC_EVENT_HIGHLIGHT) {
-			si->wState &= ~GC_EVENT_HIGHLIGHT;
+			m_log.SendMsg(EM_SETBKGNDCOLOR, 0, g_Settings.crLogBackground);
+			{
+				// messagebox
+				COLORREF crFore;
+				LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, NULL, &crFore);
 
-			if (pcli->pfnGetEvent(si->hContact, 0))
-				pcli->pfnRemoveEvent(si->hContact, GC_FAKE_EVENT);
-		}
+				CHARFORMAT2 cf;
+				cf.cbSize = sizeof(CHARFORMAT2);
+				cf.dwMask = CFM_COLOR | CFM_BOLD | CFM_UNDERLINE | CFM_BACKCOLOR;
+				cf.dwEffects = 0;
+				cf.crTextColor = crFore;
+				cf.crBackColor = db_get_dw(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR);
+				m_message.SendMsg(EM_SETBKGNDCOLOR, 0, db_get_dw(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR));
+				m_message.SendMsg(WM_SETFONT, (WPARAM)g_Settings.MessageBoxFont, MAKELPARAM(TRUE, 0));
+				m_message.SendMsg(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
+
+				// nicklist
+				int ih = GetTextPixelSize(L"AQG_glo'", g_Settings.UserListFont, FALSE);
+				int ih2 = GetTextPixelSize(L"AQG_glo'", 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 (db_get_b(NULL, CHAT_MODULE, "ShowContactStatus", 0))
+					font = font > 16 ? font : 16;
+
+				m_nickList.SendMsg(LB_SETITEMHEIGHT, 0, height > font ? height : font);
+				InvalidateRect(m_nickList.GetHwnd(), NULL, TRUE);
+			}
+			m_message.SendMsg(EM_REQUESTRESIZE, 0, 0);
+			SendMessage(m_hwnd, WM_SIZE, 0, 0);
+			SendMessage(m_hwnd, GC_REDRAWLOG2, 0, 0);
+			break;
 
-		SendMessage(hwndDlg, GC_FIXTABICONS, 0, 0);
-		if (!si->hWnd) {
-			ShowRoom(si);
-			SendMessage(hwndDlg, WM_MOUSEACTIVATE, 0, 0);
-		}
-		break;
+		case DM_UPDATETITLEBAR:
+			if (g_dat.flags & SMF_STATUSICON) {
+				MODULEINFO *mi = pci->MM_FindModule(m_si->pszModule);
+				tbd.hIcon = (m_si->wStatus == ID_STATUS_ONLINE) ? mi->hOnlineIcon : mi->hOfflineIcon;
+				tbd.hIconBig = (m_si->wStatus == ID_STATUS_ONLINE) ? mi->hOnlineIconBig : mi->hOfflineIconBig;
+			}
+			else {
+				tbd.hIcon = GetCachedIcon("chat_window");
+				tbd.hIconBig = g_dat.hIconChatBig;
+			}
+			tbd.hIconNot = (m_si->wState & (GC_EVENT_HIGHLIGHT | STATE_TALK)) ? GetCachedIcon("chat_overlay") : NULL;
 
-	case WM_CTLCOLORLISTBOX:
-		SetBkColor((HDC)wParam, g_Settings.crUserListBGColor);
-		return (INT_PTR)pci->hListBkgBrush;
+			switch (m_si->iType) {
+			case GCW_CHATROOM:
+				mir_snwprintf(szTemp,
+					(m_si->nUsersInNicklist == 1) ? TranslateT("%s: chat room (%u user)") : TranslateT("%s: chat room (%u users)"),
+					m_si->ptszName, m_si->nUsersInNicklist);
+				break;
+			case GCW_PRIVMESS:
+				mir_snwprintf(szTemp,
+					(m_si->nUsersInNicklist == 1) ? TranslateT("%s: message session") : TranslateT("%s: message session (%u users)"),
+					m_si->ptszName, m_si->nUsersInNicklist);
+				break;
+			case GCW_SERVER:
+				mir_snwprintf(szTemp, L"%s: Server", m_si->ptszName);
+				break;
+			}
+			tbd.iFlags = TBDF_TEXT | TBDF_ICON;
+			tbd.pszText = szTemp;
+			SendMessage(GetParent(m_hwnd), CM_UPDATETITLEBAR, (WPARAM)&tbd, (LPARAM)m_hwnd);
+			SendMessage(m_hwnd, DM_UPDATETABCONTROL, 0, 0);
+			break;
 
-	case WM_MEASUREITEM:
-		if (!MeasureMenuItem(wParam, lParam)) {
-			MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lParam;
-			if (mis->CtlType == ODT_MENU)
-				return Menu_MeasureItem(lParam);
+		case GC_UPDATESTATUSBAR:
+			{
+				MODULEINFO *mi = pci->MM_FindModule(m_si->pszModule);
+				hIcon = m_si->wStatus == ID_STATUS_ONLINE ? mi->hOnlineIcon : mi->hOfflineIcon;
+				mir_snwprintf(szTemp, L"%s : %s", mi->ptszModDispName, m_si->ptszStatusbarText ? m_si->ptszStatusbarText : L"");
+
+				StatusBarData sbd;
+				sbd.iItem = 0;
+				sbd.iFlags = SBDF_TEXT | SBDF_ICON;
+				sbd.hIcon = hIcon;
+				sbd.pszText = szTemp;
+				SendMessage(GetParent(m_hwnd), CM_UPDATESTATUSBAR, (WPARAM)&sbd, (LPARAM)m_hwnd);
+
+				sbd.iItem = 1;
+				sbd.hIcon = NULL;
+				sbd.pszText = L"";
+				SendMessage(GetParent(m_hwnd), CM_UPDATESTATUSBAR, (WPARAM)&sbd, (LPARAM)m_hwnd);
+
+				StatusIconData sid = { sizeof(sid) };
+				sid.szModule = SRMMMOD;
+				Srmm_ModifyIcon(m_si->hContact, &sid);
+			}
+			break;
 
-			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 (db_get_b(NULL, CHAT_MODULE, "ShowContactStatus", 0))
-				font = font > 16 ? font : 16;
-			mis->itemHeight = height > font ? height : font;
-		}
-		return TRUE;
+		case DM_SWITCHINFOBAR:
+		case DM_SWITCHTOOLBAR:
+			SendMessage(m_hwnd, WM_SIZE, 0, 0);
+			break;
 
-	case WM_DRAWITEM:
-		if (!DrawMenuItem(wParam, lParam)) {
-			DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
-			if (dis->CtlType == ODT_MENU)
-				return Menu_DrawItem(lParam);
+		case WM_SIZE:
+			if (wParam == SIZE_MAXIMIZED)
+				PostMessage(m_hwnd, GC_SCROLLTOBOTTOM, 0, 0);
 
-			if (dis->CtlID == IDC_CHAT_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 - 5;
-					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 = Skin_LoadProtoIcon(si->pszModule, ui->ContactStatus);
-						DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 3, hIcon, 16, 16, 0, NULL, DI_NORMAL);
-						IcoLib_ReleaseIcon(hIcon);
-						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 = Skin_LoadProtoIcon(si->pszModule, ui->ContactStatus);
-						DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 3, hIcon, 16, 16, 0, NULL, DI_NORMAL);
-						IcoLib_ReleaseIcon(hIcon);
-						x_offset += 18;
-					}
+			if (IsIconic(m_hwnd)) break;
 
-					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);
-				}
-				return TRUE;
+			if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) {
+				GetClientRect(m_hwnd, &rc);
+				MessageDialogResize(rc.right - rc.left, rc.bottom - rc.top);
 			}
-		}
-		break;
+			break;
 
-	case GC_UPDATENICKLIST:
-		SendDlgItemMessage(hwndDlg, IDC_CHAT_LIST, WM_SETREDRAW, FALSE, 0);
-		SendDlgItemMessage(hwndDlg, IDC_CHAT_LIST, LB_RESETCONTENT, 0, 0);
-		for (int index = 0; index < si->nUsersInNicklist; index++) {
-			USERINFO *ui = pci->SM_GetUserFromIndex(si->ptszID, si->pszModule, index);
-			if (ui) {
-				char szIndicator = SM_GetStatusIndicator(si, ui);
-				if (szIndicator > '\0') {
-					static wchar_t ptszBuf[128];
-					mir_snwprintf(ptszBuf, L"%c%s", szIndicator, ui->pszNick);
-					SendDlgItemMessage(hwndDlg, IDC_CHAT_LIST, LB_ADDSTRING, 0, (LPARAM)ptszBuf);
+		case GC_REDRAWWINDOW:
+			InvalidateRect(m_hwnd, NULL, TRUE);
+			break;
+
+		case GC_REDRAWLOG:
+			m_si->LastTime = 0;
+			if (m_si->pLog) {
+				LOGINFO *pLog = m_si->pLog;
+				if (m_si->iEventCount > 60) {
+					int index = 0;
+					while (index < 59) {
+						if (pLog->next == NULL)
+							break;
+
+						pLog = pLog->next;
+						if ((m_si->iType != GCW_CHATROOM && m_si->iType != GCW_PRIVMESS) || !m_si->bFilterEnabled || (m_si->iLogFilterFlags&pLog->iType) != 0)
+							index++;
+					}
+					Log_StreamInEvent(m_hwnd, pLog, m_si, TRUE);
+					mir_forkthread(phase2, m_si);
 				}
-				else SendDlgItemMessage(hwndDlg, IDC_CHAT_LIST, LB_ADDSTRING, 0, (LPARAM)ui->pszNick);
+				else Log_StreamInEvent(m_hwnd, m_si->pLogEnd, m_si, TRUE);
 			}
-		}
-		SendDlgItemMessage(hwndDlg, IDC_CHAT_LIST, WM_SETREDRAW, TRUE, 0);
-		InvalidateRect(GetDlgItem(hwndDlg, IDC_CHAT_LIST), NULL, FALSE);
-		UpdateWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIST));
-		SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0);
-		break;
+			else SendMessage(m_hwnd, GC_CONTROL_MSG, WINDOW_CLEARLOG, 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 GC_REDRAWLOG2:
+			m_si->LastTime = 0;
+			if (m_si->pLog)
+				Log_StreamInEvent(m_hwnd, m_si->pLogEnd, m_si, TRUE);
+			break;
 
-		case SESSION_ONLINE:
-			SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
-			return TRUE;
+		case GC_ADDLOG:
+			if (m_si->pLogEnd)
+				Log_StreamInEvent(m_hwnd, m_si->pLog, m_si, FALSE);
+			else
+				SendMessage(m_hwnd, GC_CONTROL_MSG, WINDOW_CLEARLOG, 0);
+			break;
 
-		case WINDOW_HIDDEN:
-			SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 0);
-			return TRUE;
+		case DM_UPDATETABCONTROL:
+			tcd.iFlags = TCDF_TEXT;
+			tcd.pszText = m_si->ptszName;
+			SendMessage(GetParent(m_hwnd), CM_UPDATETABCONTROL, (WPARAM)&tcd, (LPARAM)m_hwnd);
+			// fall through
 
-		case WINDOW_CLEARLOG:
-			SetDlgItemText(hwndDlg, IDC_LOG, L"");
-			return TRUE;
+		case GC_FIXTABICONS:
+			if (!(m_si->wState & GC_EVENT_HIGHLIGHT)) {
+				if (m_si->wState & STATE_TALK)
+					hIcon = (m_si->wStatus == ID_STATUS_ONLINE) ? pci->MM_FindModule(m_si->pszModule)->hOnlineTalkIcon : pci->MM_FindModule(m_si->pszModule)->hOfflineTalkIcon;
+				else
+					hIcon = (m_si->wStatus == ID_STATUS_ONLINE) ? pci->MM_FindModule(m_si->pszModule)->hOnlineIcon : pci->MM_FindModule(m_si->pszModule)->hOfflineIcon;
+			}
+			else hIcon = g_dat.hMsgIcon;
 
-		case SESSION_TERMINATE:
-			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;
+			tcd.iFlags = TCDF_ICON;
+			tcd.hIcon = hIcon;
+			SendMessage(GetParent(m_hwnd), CM_UPDATETABCONTROL, (WPARAM)&tcd, (LPARAM)m_hwnd);
+			break;
 
-		case WINDOW_MINIMIZE:
-			ShowWindow(hwndDlg, SW_MINIMIZE);
-			goto LABEL_SHOWWINDOW;
+		case GC_SETMESSAGEHIGHLIGHT:
+			m_si->wState |= GC_EVENT_HIGHLIGHT;
+			SendMessage(m_si->hWnd, GC_FIXTABICONS, 0, 0);
+			SendMessage(m_hwnd, DM_UPDATETITLEBAR, 0, 0);
+			if (g_Settings.bFlashWindowHighlight && GetActiveWindow() != m_hwnd && GetForegroundWindow() != GetParent(m_hwnd))
+				SendMessage(GetParent(m_si->hWnd), CM_STARTFLASHING, 0, 0);
+			break;
 
-		case WINDOW_MAXIMIZE:
-			ShowWindow(hwndDlg, SW_MAXIMIZE);
-			goto LABEL_SHOWWINDOW;
+		case GC_SETTABHIGHLIGHT:
+			SendMessage(m_si->hWnd, GC_FIXTABICONS, 0, 0);
+			SendMessage(m_hwnd, DM_UPDATETITLEBAR, 0, 0);
+			if (g_Settings.bFlashWindow && GetActiveWindow() != GetParent(m_hwnd) && GetForegroundWindow() != GetParent(m_hwnd))
+				SendMessage(GetParent(m_si->hWnd), CM_STARTFLASHING, 0, 0);
+			break;
 
-		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 DM_ACTIVATE:
+			if (m_si->wState & STATE_TALK) {
+				m_si->wState &= ~STATE_TALK;
+				db_set_w(m_si->hContact, m_si->pszModule, "ApparentMode", 0);
+			}
 
-	case GC_SPLITTERMOVED:
-		if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SPLITTERX)) {
-			GetClientRect(hwndDlg, &rc);
-			pt.x = wParam; pt.y = 0;
-			ScreenToClient(hwndDlg, &pt);
-
-			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)) {
-			GetClientRect(hwndDlg, &rc);
-			pt.x = 0; pt.y = wParam;
-			ScreenToClient(hwndDlg, &pt);
-			si->iSplitterY = rc.bottom - pt.y;
-			g_Settings.iSplitterY = si->iSplitterY;
-		}
-		PostMessage(hwndDlg, WM_SIZE, 0, 0);
-		break;
+			if (m_si->wState & GC_EVENT_HIGHLIGHT) {
+				m_si->wState &= ~GC_EVENT_HIGHLIGHT;
 
-	case GC_FIREHOOK:
-		if (lParam) {
-			NotifyEventHooks(pci->hSendEvent, 0, lParam);
-			GCHOOK *gch = (GCHOOK*)lParam;
-			if (gch->pDest) {
-				mir_free((void*)gch->pDest->ptszID);
-				mir_free((void*)gch->pDest->pszModule);
-				mir_free(gch->pDest);
+				if (pcli->pfnGetEvent(m_si->hContact, 0))
+					pcli->pfnRemoveEvent(m_si->hContact, GC_FAKE_EVENT);
 			}
-			mir_free(gch->ptszText);
-			mir_free(gch->ptszUID);
-			mir_free(gch->ptszNick);
-			mir_free(gch);
-		}
-		break;
 
-	case GC_CHANGEFILTERFLAG:
-		si->iLogFilterFlags = lParam;
-		break;
+			SendMessage(m_hwnd, GC_FIXTABICONS, 0, 0);
+			if (!m_si->hWnd) {
+				ShowRoom(m_si);
+				SendMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
+			}
+			break;
 
-	case GC_SHOWFILTERMENU:
-		{
-			HWND hwnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER), hwndDlg, FilterWndProc, (LPARAM)si);
-			TranslateDialogDefault(hwnd);
-			GetWindowRect(GetDlgItem(hwndDlg, IDC_CHAT_FILTER), &rc);
-			SetWindowPos(hwnd, HWND_TOP, rc.left - 85, (IsWindowVisible(GetDlgItem(hwndDlg, IDC_CHAT_FILTER)) || IsWindowVisible(GetDlgItem(hwndDlg, IDC_CHAT_BOLD))) ? rc.top - 206 : rc.top - 186, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
-		}
-		break;
+		case WM_CTLCOLORLISTBOX:
+			SetBkColor((HDC)wParam, g_Settings.crUserListBGColor);
+			return (INT_PTR)pci->hListBkgBrush;
+
+		case WM_MEASUREITEM:
+			if (!MeasureMenuItem(wParam, lParam)) {
+				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 (db_get_b(NULL, CHAT_MODULE, "ShowContactStatus", 0))
+					font = font > 16 ? font : 16;
+				mis->itemHeight = height > font ? height : font;
+			}
+			return TRUE;
 
-	case GC_SHOWCOLORCHOOSER:
-		pci->ColorChooser(si, lParam == IDC_CHAT_COLOR, hwndDlg, GetDlgItem(hwndDlg, IDC_MESSAGE), GetDlgItem(hwndDlg, lParam));
-		break;
+		case WM_DRAWITEM:
+			if (!DrawMenuItem(wParam, lParam)) {
+				DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
+				if (dis->CtlType == ODT_MENU)
+					return Menu_DrawItem(lParam);
+
+				if (dis->CtlID == IDC_CHAT_LIST) {
+					int index = dis->itemID;
+					USERINFO *ui = pci->SM_GetUserFromIndex(m_si->ptszID, m_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 - 5;
+						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 = Skin_LoadProtoIcon(m_si->pszModule, ui->ContactStatus);
+							DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 3, hIcon, 16, 16, 0, NULL, DI_NORMAL);
+							IcoLib_ReleaseIcon(hIcon);
+							x_offset += 18;
+						}
+						DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset, pci->SM_GetStatusIcon(m_si, ui), 10, 10, 0, NULL, DI_NORMAL);
+						x_offset += 12;
+						if (g_Settings.bShowContactStatus && !g_Settings.bContactStatusFirst && ui->ContactStatus) {
+							hIcon = Skin_LoadProtoIcon(m_si->pszModule, ui->ContactStatus);
+							DrawIconEx(dis->hDC, x_offset, dis->rcItem.top + offset - 3, hIcon, 16, 16, 0, NULL, DI_NORMAL);
+							IcoLib_ReleaseIcon(hIcon);
+							x_offset += 18;
+						}
 
-	case GC_SCROLLTOBOTTOM:
-		if ((GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_STYLE) & WS_VSCROLL) != 0) {
-			SCROLLINFO sci = { 0 };
-			sci.cbSize = sizeof(sci);
-			sci.fMask = SIF_PAGE | SIF_RANGE;
-			GetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &sci);
-
-			sci.fMask = SIF_POS;
-			sci.nPos = sci.nMax - sci.nPage + 1;
-			SetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &sci, TRUE);
-
-			CHARRANGE sel;
-			sel.cpMin = sel.cpMax = GetRichTextLength(GetDlgItem(hwndDlg, IDC_LOG), CP_ACP, FALSE);
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM)&sel);
-			PostMessage(GetDlgItem(hwndDlg, IDC_LOG), WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0);
-		}
-		break;
+						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);
+					}
+					return TRUE;
+				}
+			}
+			break;
 
-	case WM_ACTIVATE:
-		if (LOWORD(wParam) != WA_ACTIVE)
+		case GC_UPDATENICKLIST:
+			m_nickList.SendMsg(WM_SETREDRAW, FALSE, 0);
+			m_nickList.SendMsg(LB_RESETCONTENT, 0, 0);
+			for (int index = 0; index < m_si->nUsersInNicklist; index++) {
+				USERINFO *ui = pci->SM_GetUserFromIndex(m_si->ptszID, m_si->pszModule, index);
+				if (ui) {
+					char szIndicator = SM_GetStatusIndicator(m_si, ui);
+					if (szIndicator > '\0') {
+						static wchar_t ptszBuf[128];
+						mir_snwprintf(ptszBuf, L"%c%s", szIndicator, ui->pszNick);
+						m_nickList.SendMsg(LB_ADDSTRING, 0, (LPARAM)ptszBuf);
+					}
+					else m_nickList.SendMsg(LB_ADDSTRING, 0, (LPARAM)ui->pszNick);
+				}
+			}
+			m_nickList.SendMsg(WM_SETREDRAW, TRUE, 0);
+			InvalidateRect(m_nickList.GetHwnd(), NULL, FALSE);
+			UpdateWindow(m_nickList.GetHwnd());
+			SendMessage(m_hwnd, DM_UPDATETITLEBAR, 0, 0);
 			break;
 
-		//fall through
-	case WM_MOUSEACTIVATE:
-		if (uMsg != WM_ACTIVATE)
-			SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+		case GC_CONTROL_MSG:
+			switch (wParam) {
+			case SESSION_OFFLINE:
+				SendMessage(m_hwnd, GC_UPDATESTATUSBAR, 0, 0);
+				SendMessage(m_si->hWnd, GC_UPDATENICKLIST, 0, 0);
+				return TRUE;
 
-		pci->SetActiveSession(si->ptszID, si->pszModule);
+			case SESSION_ONLINE:
+				SendMessage(m_hwnd, GC_UPDATESTATUSBAR, 0, 0);
+				return TRUE;
 
-		if (db_get_w(si->hContact, si->pszModule, "ApparentMode", 0) != 0)
-			db_set_w(si->hContact, si->pszModule, "ApparentMode", 0);
-		if (pcli->pfnGetEvent(si->hContact, 0))
-			pcli->pfnRemoveEvent(si->hContact, GC_FAKE_EVENT);
-		break;
+			case WINDOW_HIDDEN:
+				SendMessage(m_hwnd, GC_CLOSEWINDOW, 0, 0);
+				return TRUE;
 
-	case WM_NOTIFY:
-		{
-			LPNMHDR pNmhdr = (LPNMHDR)lParam;
-			switch (pNmhdr->code) {
-			case EN_REQUESTRESIZE:
-				if (pNmhdr->idFrom == IDC_MESSAGE) {
-					REQRESIZE *rr = (REQRESIZE *)lParam;
-					int height = rr->rc.bottom - rr->rc.top + 1;
-					if (height < g_dat.minInputAreaHeight)
-						height = g_dat.minInputAreaHeight;
-
-					if (si->desiredInputAreaHeight != height) {
-						si->desiredInputAreaHeight = height;
-						SendMessage(hwndDlg, WM_SIZE, 0, 0);
-						PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
-					}
-				}
-				break;
+			case WINDOW_CLEARLOG:
+				m_log.SetText(L"");
+				return TRUE;
 
-			case EN_MSGFILTER:
-				if (pNmhdr->idFrom == IDC_LOG && ((MSGFILTER *)lParam)->msg == WM_RBUTTONUP) {
-					SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+			case SESSION_TERMINATE:
+				if (pcli->pfnGetEvent(m_si->hContact, 0))
+					pcli->pfnRemoveEvent(m_si->hContact, GC_FAKE_EVENT);
+				m_si->wState &= ~STATE_TALK;
+				db_set_w(m_si->hContact, m_si->pszModule, "ApparentMode", 0);
+				SendMessage(m_hwnd, GC_CLOSEWINDOW, 0, 0);
+				return TRUE;
+
+			case WINDOW_MINIMIZE:
+				ShowWindow(m_hwnd, SW_MINIMIZE);
+				goto LABEL_SHOWWINDOW;
+
+			case WINDOW_MAXIMIZE:
+				ShowWindow(m_hwnd, SW_MAXIMIZE);
+				goto LABEL_SHOWWINDOW;
+
+			case SESSION_INITDONE:
+				if (db_get_b(NULL, CHAT_MODULE, "PopupOnJoin", 0) != 0)
 					return TRUE;
-				}
-				break;
+				// fall through
+			case WINDOW_VISIBLE:
+				if (IsIconic(m_hwnd))
+					ShowWindow(m_hwnd, SW_NORMAL);
+			LABEL_SHOWWINDOW:
+				SendMessage(m_hwnd, WM_SIZE, 0, 0);
+				SendMessage(m_hwnd, GC_REDRAWLOG, 0, 0);
+				SendMessage(m_hwnd, GC_UPDATENICKLIST, 0, 0);
+				SendMessage(m_hwnd, GC_UPDATESTATUSBAR, 0, 0);
+				ShowWindow(m_hwnd, SW_SHOW);
+				SendMessage(m_hwnd, WM_SIZE, 0, 0);
+				SetForegroundWindow(m_hwnd);
+				return TRUE;
+			}
+			break;
 
-			case EN_LINK:
-				if (pNmhdr->idFrom == IDC_LOG) {
-					switch (((ENLINK *)lParam)->msg) {
-					case WM_RBUTTONDOWN:
-					case WM_LBUTTONUP:
-					case WM_LBUTTONDBLCLK:
-						if (HandleLinkClick(g_hInst, hwndDlg, GetDlgItem(hwndDlg, IDC_MESSAGE), (ENLINK*)lParam)) {
-							SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
-							return TRUE;
-						}
-						break;
-					}
-				}
-				break;
+		case GC_SPLITTERMOVED:
+			if ((HWND)lParam == GetDlgItem(m_hwnd, IDC_SPLITTERX)) {
+				GetClientRect(m_hwnd, &rc);
+				pt.x = wParam; pt.y = 0;
+				ScreenToClient(m_hwnd, &pt);
+
+				m_si->iSplitterX = rc.right - pt.x + 1;
+				if (m_si->iSplitterX < 35)
+					m_si->iSplitterX = 35;
+				if (m_si->iSplitterX > rc.right - rc.left - 35)
+					m_si->iSplitterX = rc.right - rc.left - 35;
+				g_Settings.iSplitterX = m_si->iSplitterX;
+			}
+			else if ((HWND)lParam == GetDlgItem(m_hwnd, IDC_SPLITTERY)) {
+				GetClientRect(m_hwnd, &rc);
+				pt.x = 0; pt.y = wParam;
+				ScreenToClient(m_hwnd, &pt);
+				m_si->iSplitterY = rc.bottom - pt.y;
+				g_Settings.iSplitterY = m_si->iSplitterY;
+			}
+			PostMessage(m_hwnd, WM_SIZE, 0, 0);
+			break;
 
-			case TTN_NEEDTEXT:
-				if (pNmhdr->idFrom == (UINT_PTR)GetDlgItem(hwndDlg, IDC_CHAT_LIST)) {
-					LPNMTTDISPINFO lpttd = (LPNMTTDISPINFO)lParam;
-					SESSION_INFO* parentdat = (SESSION_INFO*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-
-					POINT p;
-					GetCursorPos(&p);
-					ScreenToClient(GetDlgItem(hwndDlg, IDC_CHAT_LIST), &p);
-					int item = LOWORD(SendDlgItemMessage(hwndDlg, IDC_CHAT_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;
-					}
+		case GC_FIREHOOK:
+			if (lParam) {
+				NotifyEventHooks(pci->hSendEvent, 0, lParam);
+				GCHOOK *gch = (GCHOOK*)lParam;
+				if (gch->pDest) {
+					mir_free((void*)gch->pDest->ptszID);
+					mir_free((void*)gch->pDest->pszModule);
+					mir_free(gch->pDest);
 				}
-				break;
+				mir_free(gch->ptszText);
+				mir_free(gch->ptszUID);
+				mir_free(gch->ptszNick);
+				mir_free(gch);
 			}
-		}
-		break;
+			break;
 
-	case WM_COMMAND:
-		if (!lParam && Clist_MenuProcessCommand(LOWORD(wParam), MPCF_CONTACTMENU, si->hContact))
+		case GC_CHANGEFILTERFLAG:
+			m_si->iLogFilterFlags = lParam;
 			break;
 
-		if (HIWORD(wParam) == BN_CLICKED)
-			if (LOWORD(wParam) >= MIN_CBUTTONID && LOWORD(wParam) <= MAX_CBUTTONID) {
-				Srmm_ClickToolbarIcon(si->hContact, LOWORD(wParam), GetDlgItem(hwndDlg, LOWORD(wParam)), 0);
-				break;
+		case GC_SHOWFILTERMENU:
+			{
+				HWND hwnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_FILTER), m_hwnd, FilterWndProc, (LPARAM)m_si);
+				TranslateDialogDefault(hwnd);
+				GetWindowRect(GetDlgItem(m_hwnd, IDC_CHAT_FILTER), &rc);
+				SetWindowPos(hwnd, HWND_TOP, rc.left - 85, (IsWindowVisible(GetDlgItem(m_hwnd, IDC_CHAT_FILTER)) || IsWindowVisible(GetDlgItem(m_hwnd, IDC_CHAT_BOLD))) ? rc.top - 206 : rc.top - 186, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
 			}
+			break;
 
-		switch (LOWORD(wParam)) {
-		case IDC_CHAT_LIST:
-			if (HIWORD(wParam) == LBN_DBLCLK) {
-				TVHITTESTINFO hti;
-				hti.pt.x = (short)LOWORD(GetMessagePos());
-				hti.pt.y = (short)HIWORD(GetMessagePos());
-				ScreenToClient(GetDlgItem(hwndDlg, IDC_CHAT_LIST), &hti.pt);
+		case GC_SHOWCOLORCHOOSER:
+			pci->ColorChooser(m_si, lParam == IDC_CHAT_COLOR, m_hwnd, m_message.GetHwnd(), GetDlgItem(m_hwnd, lParam));
+			break;
 
-				int item = LOWORD(SendDlgItemMessage(hwndDlg, IDC_CHAT_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) + 4);
-						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);
+		case GC_SCROLLTOBOTTOM:
+			if ((GetWindowLongPtr(m_log.GetHwnd(), GWL_STYLE) & WS_VSCROLL) != 0) {
+				SCROLLINFO sci = { 0 };
+				sci.cbSize = sizeof(sci);
+				sci.fMask = SIF_PAGE | SIF_RANGE;
+				GetScrollInfo(m_log.GetHwnd(), SB_VERT, &sci);
+
+				sci.fMask = SIF_POS;
+				sci.nPos = sci.nMax - sci.nPage + 1;
+				SetScrollInfo(m_log.GetHwnd(), SB_VERT, &sci, TRUE);
+
+				CHARRANGE sel;
+				sel.cpMin = sel.cpMax = GetRichTextLength(m_log.GetHwnd(), CP_ACP, FALSE);
+				m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
+				PostMessage(m_log.GetHwnd(), WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0);
+			}
+			break;
 
-						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, nullptr, 0);
-				}
+		case WM_ACTIVATE:
+			if (LOWORD(wParam) != WA_ACTIVE)
+				break;
 
-				return TRUE;
-			}
+			//fall through
+		case WM_MOUSEACTIVATE:
+			if (uMsg != WM_ACTIVATE)
+				SetFocus(m_message.GetHwnd());
+
+			pci->SetActiveSession(m_si->ptszID, m_si->pszModule);
 
-			if (HIWORD(wParam) == LBN_KILLFOCUS)
-				RedrawWindow(GetDlgItem(hwndDlg, IDC_CHAT_LIST), NULL, NULL, RDW_INVALIDATE);
+			if (db_get_w(m_si->hContact, m_si->pszModule, "ApparentMode", 0) != 0)
+				db_set_w(m_si->hContact, m_si->pszModule, "ApparentMode", 0);
+			if (pcli->pfnGetEvent(m_si->hContact, 0))
+				pcli->pfnRemoveEvent(m_si->hContact, GC_FAKE_EVENT);
 			break;
 
-		case IDOK:
-			if (IsWindowEnabled(GetDlgItem(hwndDlg, IDOK))) {
-				char *pszRtf = GetRichTextRTF(GetDlgItem(hwndDlg, IDC_MESSAGE));
-				if (pszRtf == NULL)
+		case WM_NOTIFY:
+			{
+				LPNMHDR pNmhdr = (LPNMHDR)lParam;
+				switch (pNmhdr->code) {
+				case EN_REQUESTRESIZE:
+					if (pNmhdr->idFrom == IDC_MESSAGE) {
+						REQRESIZE *rr = (REQRESIZE *)lParam;
+						int height = rr->rc.bottom - rr->rc.top + 1;
+						if (height < g_dat.minInputAreaHeight)
+							height = g_dat.minInputAreaHeight;
+
+						if (m_si->desiredInputAreaHeight != height) {
+							m_si->desiredInputAreaHeight = height;
+							SendMessage(m_hwnd, WM_SIZE, 0, 0);
+							PostMessage(m_hwnd, GC_SCROLLTOBOTTOM, 0, 0);
+						}
+					}
 					break;
 
-				MODULEINFO *mi = pci->MM_FindModule(si->pszModule);
-				if (mi == NULL)
+				case EN_MSGFILTER:
+					if (pNmhdr->idFrom == IDC_LOG && ((MSGFILTER *)lParam)->msg == WM_RBUTTONUP) {
+						SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE);
+						return TRUE;
+					}
 					break;
 
-				TCmdList *cmdListNew = tcmdlist_last(si->cmdList);
-				while (cmdListNew != NULL && cmdListNew->temporary) {
-					si->cmdList = tcmdlist_remove(si->cmdList, cmdListNew);
-					cmdListNew = tcmdlist_last(si->cmdList);
+				case TTN_NEEDTEXT:
+					if (pNmhdr->idFrom == (UINT_PTR)m_nickList.GetHwnd()) {
+						LPNMTTDISPINFO lpttd = (LPNMTTDISPINFO)lParam;
+						SESSION_INFO* parentdat = (SESSION_INFO*)GetWindowLongPtr(m_hwnd, GWLP_USERDATA);
+
+						POINT p;
+						GetCursorPos(&p);
+						ScreenToClient(m_nickList.GetHwnd(), &p);
+						int item = LOWORD(m_nickList.SendMsg(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;
 				}
+			}
+			break;
 
-				// takes pszRtf to a queue, no leak here
-				si->cmdList = tcmdlist_append(si->cmdList, pszRtf, 20, FALSE);
-
-				CMStringW ptszText(ptrW(mir_utf8decodeW(pszRtf)));
-				pci->DoRtfToTags(ptszText, mi->nColorCount, mi->crColors);
-				ptszText.Trim();
-				ptszText.Replace(L"%", L"%%");
+		case WM_COMMAND:
+			if (!lParam && Clist_MenuProcessCommand(LOWORD(wParam), MPCF_CONTACTMENU, m_si->hContact))
+				break;
 
-				if (mi->bAckMsg) {
-					EnableWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), FALSE);
-					SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETREADONLY, TRUE, 0);
+			if (HIWORD(wParam) == BN_CLICKED)
+				if (LOWORD(wParam) >= MIN_CBUTTONID && LOWORD(wParam) <= MAX_CBUTTONID) {
+					Srmm_ClickToolbarIcon(m_si->hContact, LOWORD(wParam), GetDlgItem(m_hwnd, LOWORD(wParam)), 0);
+					break;
 				}
-				else SetDlgItemText(hwndDlg, IDC_MESSAGE, L"");
 
-				EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
+			switch (LOWORD(wParam)) {
+			case IDC_CHAT_LIST:
+				if (HIWORD(wParam) == LBN_DBLCLK) {
+					TVHITTESTINFO hti;
+					hti.pt.x = (short)LOWORD(GetMessagePos());
+					hti.pt.y = (short)HIWORD(GetMessagePos());
+					ScreenToClient(m_nickList.GetHwnd(), &hti.pt);
+
+					int item = LOWORD(m_nickList.SendMsg(LB_ITEMFROMPOINT, 0, MAKELPARAM(hti.pt.x, hti.pt.y)));
+					USERINFO *ui = pci->SM_GetUserFromIndex(m_si->ptszID, m_si->pszModule, item);
+					if (ui) {
+						if (GetKeyState(VK_SHIFT) & 0x8000) {
+							LRESULT lResult = (LRESULT)m_message.SendMsg(EM_GETSEL, 0, 0);
+							int start = LOWORD(lResult);
+							size_t dwNameLenMax = (mir_wstrlen(ui->pszUID) + 4);
+							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);
+
+							m_message.SendMsg(EM_REPLACESEL, FALSE, (LPARAM)pszName);
+							PostMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0);
+						}
+						else pci->DoEventHookAsync(m_hwnd, m_si->ptszID, m_si->pszModule, GC_USER_PRIVMESS, ui, nullptr, 0);
+					}
 
-				pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_MESSAGE, NULL, ptszText, 0);
-				SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
-			}
-			break;
+					return TRUE;
+				}
 
-		case IDC_CHAT_SHOWNICKLIST:
-			if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_SHOWNICKLIST)))
-				break;
-			if (si->iType == GCW_SERVER)
+				if (HIWORD(wParam) == LBN_KILLFOCUS)
+					RedrawWindow(m_nickList.GetHwnd(), NULL, NULL, RDW_INVALIDATE);
 				break;
 
-			si->bNicklistEnabled = !si->bNicklistEnabled;
+			case IDOK:
+				if (IsWindowEnabled(GetDlgItem(m_hwnd, IDOK))) {
+					char *pszRtf = GetRichTextRTF(m_message.GetHwnd());
+					if (pszRtf == NULL)
+						break;
 
-			SendDlgItemMessage(hwndDlg, IDC_CHAT_SHOWNICKLIST, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetCachedIcon(si->bNicklistEnabled ? "chat_nicklist" : "chat_nicklist2"));
-			SendMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
-			SendMessage(hwndDlg, WM_SIZE, 0, 0);
-			break;
+					MODULEINFO *mi = pci->MM_FindModule(m_si->pszModule);
+					if (mi == NULL)
+						break;
 
-		case IDC_MESSAGE:
-			if (HIWORD(wParam) == EN_CHANGE) {
-				si->cmdListCurrent = NULL;
-				EnableWindow(GetDlgItem(hwndDlg, IDOK), GetRichTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE), 1200, FALSE) != 0);
-			}
-			break;
+					TCmdList *cmdListNew = tcmdlist_last(m_si->cmdList);
+					while (cmdListNew != NULL && cmdListNew->temporary) {
+						m_si->cmdList = tcmdlist_remove(m_si->cmdList, cmdListNew);
+						cmdListNew = tcmdlist_last(m_si->cmdList);
+					}
 
-		case IDC_HISTORY:
-			if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_HISTORY))) {
-				MODULEINFO *pInfo = pci->MM_FindModule(si->pszModule);
-				if (pInfo)
-					ShellExecute(hwndDlg, NULL, pci->GetChatLogsFilename(si, 0), NULL, NULL, SW_SHOW);
-			}
-			break;
+					// takes pszRtf to a queue, no leak here
+					m_si->cmdList = tcmdlist_append(m_si->cmdList, pszRtf, 20, FALSE);
+
+					CMStringW ptszText(ptrW(mir_utf8decodeW(pszRtf)));
+					pci->DoRtfToTags(ptszText, mi->nColorCount, mi->crColors);
+					ptszText.Trim();
+					ptszText.Replace(L"%", L"%%");
 
-		case IDC_CHAT_CHANMGR:
-			if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_CHANMGR)))
+					if (mi->bAckMsg) {
+						EnableWindow(m_message.GetHwnd(), FALSE);
+						m_message.SendMsg(EM_SETREADONLY, TRUE, 0);
+					}
+					else SetDlgItemText(m_hwnd, IDC_MESSAGE, L"");
+
+					EnableWindow(GetDlgItem(m_hwnd, IDOK), FALSE);
+
+					pci->DoEventHookAsync(m_hwnd, m_si->ptszID, m_si->pszModule, GC_USER_MESSAGE, NULL, ptszText, 0);
+					SetFocus(m_message.GetHwnd());
+				}
 				break;
-			pci->DoEventHookAsync(hwndDlg, si->ptszID, si->pszModule, GC_USER_CHANMGR, NULL, NULL, 0);
-			break;
 
-		case IDC_CHAT_FILTER:
-			if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_FILTER)))
+			case IDC_CHAT_SHOWNICKLIST:
+				if (!IsWindowEnabled(GetDlgItem(m_hwnd, IDC_CHAT_SHOWNICKLIST)))
+					break;
+				if (m_si->iType == GCW_SERVER)
+					break;
+
+				m_si->bNicklistEnabled = !m_si->bNicklistEnabled;
+
+				SendDlgItemMessage(m_hwnd, IDC_CHAT_SHOWNICKLIST, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetCachedIcon(m_si->bNicklistEnabled ? "chat_nicklist" : "chat_nicklist2"));
+				SendMessage(m_hwnd, GC_SCROLLTOBOTTOM, 0, 0);
+				SendMessage(m_hwnd, WM_SIZE, 0, 0);
 				break;
 
-			si->bFilterEnabled = !si->bFilterEnabled;
-			SendDlgItemMessage(hwndDlg, IDC_CHAT_FILTER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetCachedIcon(si->bFilterEnabled ? "chat_filter" : "chat_filter2"));
-			if (si->bFilterEnabled && db_get_b(NULL, CHAT_MODULE, "RightClickFilter", 0) == 0) {
-				SendMessage(hwndDlg, GC_SHOWFILTERMENU, 0, 0);
+			case IDC_MESSAGE:
+				if (HIWORD(wParam) == EN_CHANGE) {
+					m_si->cmdListCurrent = NULL;
+					EnableWindow(GetDlgItem(m_hwnd, IDOK), GetRichTextLength(m_message.GetHwnd(), 1200, FALSE) != 0);
+				}
 				break;
-			}
-			SendMessage(hwndDlg, GC_REDRAWLOG, 0, 0);
-			break;
 
-		case IDC_CHAT_BKGCOLOR:
-			if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_BKGCOLOR))) {
-				MODULEINFO *pInfo = pci->MM_FindModule(si->pszModule);
-				CHARFORMAT2 cf;
-				cf.cbSize = sizeof(CHARFORMAT2);
-				cf.dwEffects = 0;
+			case IDC_HISTORY:
+				if (IsWindowEnabled(GetDlgItem(m_hwnd, IDC_HISTORY))) {
+					MODULEINFO *pInfo = pci->MM_FindModule(m_si->pszModule);
+					if (pInfo)
+						ShellExecute(m_hwnd, NULL, pci->GetChatLogsFilename(m_si, 0), NULL, NULL, SW_SHOW);
+				}
+				break;
+
+			case IDC_CHAT_CHANMGR:
+				if (!IsWindowEnabled(GetDlgItem(m_hwnd, IDC_CHAT_CHANMGR)))
+					break;
+				pci->DoEventHookAsync(m_hwnd, m_si->ptszID, m_si->pszModule, GC_USER_CHANMGR, NULL, NULL, 0);
+				break;
+
+			case IDC_CHAT_FILTER:
+				if (!IsWindowEnabled(GetDlgItem(m_hwnd, IDC_CHAT_FILTER)))
+					break;
+
+				m_si->bFilterEnabled = !m_si->bFilterEnabled;
+				SendDlgItemMessage(m_hwnd, IDC_CHAT_FILTER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetCachedIcon(m_si->bFilterEnabled ? "chat_filter" : "chat_filter2"));
+				if (m_si->bFilterEnabled && db_get_b(NULL, CHAT_MODULE, "RightClickFilter", 0) == 0) {
+					SendMessage(m_hwnd, GC_SHOWFILTERMENU, 0, 0);
+					break;
+				}
+				SendMessage(m_hwnd, GC_REDRAWLOG, 0, 0);
+				break;
 
-				if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_BKGCOLOR)) {
-					if (db_get_b(NULL, CHAT_MODULE, "RightClickFilter", 0) == 0)
-						SendMessage(hwndDlg, GC_SHOWCOLORCHOOSER, 0, IDC_CHAT_BKGCOLOR);
-					else if (si->bBGSet) {
+			case IDC_CHAT_BKGCOLOR:
+				if (IsWindowEnabled(GetDlgItem(m_hwnd, IDC_CHAT_BKGCOLOR))) {
+					MODULEINFO *pInfo = pci->MM_FindModule(m_si->pszModule);
+					CHARFORMAT2 cf;
+					cf.cbSize = sizeof(CHARFORMAT2);
+					cf.dwEffects = 0;
+
+					if (IsDlgButtonChecked(m_hwnd, IDC_CHAT_BKGCOLOR)) {
+						if (db_get_b(NULL, CHAT_MODULE, "RightClickFilter", 0) == 0)
+							SendMessage(m_hwnd, GC_SHOWCOLORCHOOSER, 0, IDC_CHAT_BKGCOLOR);
+						else if (m_si->bBGSet) {
+							cf.dwMask = CFM_BACKCOLOR;
+							cf.crBackColor = pInfo->crColors[m_si->iBG];
+							if (pInfo->bSingleFormat)
+								m_message.SendMsg(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
+							else
+								m_message.SendMsg(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+						}
+					}
+					else {
 						cf.dwMask = CFM_BACKCOLOR;
-						cf.crBackColor = pInfo->crColors[si->iBG];
+						cf.crBackColor = (COLORREF)db_get_dw(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR);
 						if (pInfo->bSingleFormat)
-							SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
+							m_message.SendMsg(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
 						else
-							SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+							m_message.SendMsg(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
 					}
 				}
-				else {
-					cf.dwMask = CFM_BACKCOLOR;
-					cf.crBackColor = (COLORREF)db_get_dw(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR);
-					if (pInfo->bSingleFormat)
-						SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
-					else
-						SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
-				}
-			}
-			break;
+				break;
 
-		case IDC_CHAT_COLOR:
-			{
-				MODULEINFO *pInfo = pci->MM_FindModule(si->pszModule);
-				CHARFORMAT2 cf;
-				cf.cbSize = sizeof(CHARFORMAT2);
-				cf.dwEffects = 0;
+			case IDC_CHAT_COLOR:
+				{
+					MODULEINFO *pInfo = pci->MM_FindModule(m_si->pszModule);
+					CHARFORMAT2 cf;
+					cf.cbSize = sizeof(CHARFORMAT2);
+					cf.dwEffects = 0;
 
-				if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_COLOR)))
-					break;
+					if (!IsWindowEnabled(GetDlgItem(m_hwnd, IDC_CHAT_COLOR)))
+						break;
 
-				if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_COLOR)) {
-					if (db_get_b(NULL, CHAT_MODULE, "RightClickFilter", 0) == 0)
-						SendMessage(hwndDlg, GC_SHOWCOLORCHOOSER, 0, IDC_CHAT_COLOR);
-					else if (si->bFGSet) {
+					if (IsDlgButtonChecked(m_hwnd, IDC_CHAT_COLOR)) {
+						if (db_get_b(NULL, CHAT_MODULE, "RightClickFilter", 0) == 0)
+							SendMessage(m_hwnd, GC_SHOWCOLORCHOOSER, 0, IDC_CHAT_COLOR);
+						else if (m_si->bFGSet) {
+							cf.dwMask = CFM_COLOR;
+							cf.crTextColor = pInfo->crColors[m_si->iFG];
+							if (pInfo->bSingleFormat)
+								m_message.SendMsg(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
+							else
+								m_message.SendMsg(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+						}
+					}
+					else {
+						COLORREF cr;
+						LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, NULL, &cr);
 						cf.dwMask = CFM_COLOR;
-						cf.crTextColor = pInfo->crColors[si->iFG];
+						cf.crTextColor = cr;
 						if (pInfo->bSingleFormat)
-							SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
+							m_message.SendMsg(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
 						else
-							SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+							m_message.SendMsg(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
 					}
 				}
-				else {
-					COLORREF cr;
-					LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, NULL, &cr);
-					cf.dwMask = CFM_COLOR;
-					cf.crTextColor = cr;
+				break;
+
+			case IDC_CHAT_BOLD:
+			case IDC_CHAT_ITALICS:
+			case IDC_CHAT_UNDERLINE:
+				{
+					MODULEINFO *pInfo = pci->MM_FindModule(m_si->pszModule);
+					CHARFORMAT2 cf;
+					cf.cbSize = sizeof(CHARFORMAT2);
+					cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
+					cf.dwEffects = 0;
+
+					if (LOWORD(wParam) == IDC_CHAT_BOLD && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_CHAT_BOLD)))
+						break;
+					if (LOWORD(wParam) == IDC_CHAT_ITALICS && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_CHAT_ITALICS)))
+						break;
+					if (LOWORD(wParam) == IDC_CHAT_UNDERLINE && !IsWindowEnabled(GetDlgItem(m_hwnd, IDC_CHAT_UNDERLINE)))
+						break;
+					if (IsDlgButtonChecked(m_hwnd, IDC_CHAT_BOLD))
+						cf.dwEffects |= CFE_BOLD;
+					if (IsDlgButtonChecked(m_hwnd, IDC_CHAT_ITALICS))
+						cf.dwEffects |= CFE_ITALIC;
+					if (IsDlgButtonChecked(m_hwnd, IDC_CHAT_UNDERLINE))
+						cf.dwEffects |= CFE_UNDERLINE;
 					if (pInfo->bSingleFormat)
-						SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
+						m_message.SendMsg(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
 					else
-						SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+						m_message.SendMsg(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
 				}
+				break;
+
+			case IDCANCEL:
+				PostMessage(m_hwnd, WM_CLOSE, 0, 0);
 			}
 			break;
 
-		case IDC_CHAT_BOLD:
-		case IDC_CHAT_ITALICS:
-		case IDC_CHAT_UNDERLINE:
+		case WM_KEYDOWN:
+			SetFocus(m_message.GetHwnd());
+			break;
+
+		case WM_GETMINMAXINFO:
 			{
-				MODULEINFO *pInfo = pci->MM_FindModule(si->pszModule);
-				CHARFORMAT2 cf;
-				cf.cbSize = sizeof(CHARFORMAT2);
-				cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
-				cf.dwEffects = 0;
+				MINMAXINFO* mmi = (MINMAXINFO*)lParam;
+				mmi->ptMinTrackSize.x = m_si->iSplitterX + 43;
+				if (mmi->ptMinTrackSize.x < 350)
+					mmi->ptMinTrackSize.x = 350;
 
-				if (LOWORD(wParam) == IDC_CHAT_BOLD && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_BOLD)))
-					break;
-				if (LOWORD(wParam) == IDC_CHAT_ITALICS && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_ITALICS)))
-					break;
-				if (LOWORD(wParam) == IDC_CHAT_UNDERLINE && !IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHAT_UNDERLINE)))
-					break;
-				if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_BOLD))
-					cf.dwEffects |= CFE_BOLD;
-				if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_ITALICS))
-					cf.dwEffects |= CFE_ITALIC;
-				if (IsDlgButtonChecked(hwndDlg, IDC_CHAT_UNDERLINE))
-					cf.dwEffects |= CFE_UNDERLINE;
-				if (pInfo->bSingleFormat)
-					SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
-				else
-					SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+				mmi->ptMinTrackSize.y = m_si->minLogBoxHeight + TOOLBAR_HEIGHT + m_si->minEditBoxHeight + 5;
 			}
 			break;
 
-		case IDCANCEL:
-			PostMessage(hwndDlg, WM_CLOSE, 0, 0);
-		}
-		break;
-
-	case WM_KEYDOWN:
-		SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
-		break;
-
-	case WM_GETMINMAXINFO:
-		{
-			MINMAXINFO* mmi = (MINMAXINFO*)lParam;
-			mmi->ptMinTrackSize.x = si->iSplitterX + 43;
-			if (mmi->ptMinTrackSize.x < 350)
-				mmi->ptMinTrackSize.x = 350;
-
-			mmi->ptMinTrackSize.y = si->minLogBoxHeight + TOOLBAR_HEIGHT + si->minEditBoxHeight + 5;
-		}
-		break;
-
-	case WM_LBUTTONDBLCLK:
-		if (LOWORD(lParam) < 30)
-			PostMessage(hwndDlg, GC_SCROLLTOBOTTOM, 0, 0);
-		else
-			SendMessage(GetParent(hwndDlg), WM_SYSCOMMAND, SC_MINIMIZE, 0);
-		break;
-
-	case WM_LBUTTONDOWN:
-		SendMessage(GetParent(hwndDlg), WM_LBUTTONDOWN, wParam, lParam);
-		return TRUE;
-
-	case DM_GETCONTEXTMENU:
-		SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LPARAM)Menu_BuildContactMenu(si->hContact));
-		return TRUE;
-
-	case WM_CONTEXTMENU:
-		if (GetParent(hwndDlg) == (HWND)wParam) {
-			HMENU hMenu = Menu_BuildContactMenu(si->hContact);
-			GetCursorPos(&pt);
-			TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hwndDlg, NULL);
-			DestroyMenu(hMenu);
-		}
-		break;
+		case WM_LBUTTONDBLCLK:
+			if (LOWORD(lParam) < 30)
+				PostMessage(m_hwnd, GC_SCROLLTOBOTTOM, 0, 0);
+			else
+				SendMessage(GetParent(m_hwnd), WM_SYSCOMMAND, SC_MINIMIZE, 0);
+			break;
 
-	case WM_CLOSE:
-		SendMessage(hwndDlg, GC_CLOSEWINDOW, 0, 0);
-		break;
+		case WM_LBUTTONDOWN:
+			SendMessage(GetParent(m_hwnd), WM_LBUTTONDOWN, wParam, lParam);
+			return TRUE;
 
-	case GC_CLOSEWINDOW:
-		DestroyWindow(hwndDlg);
-		break;
+		case DM_GETCONTEXTMENU:
+			SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, (LPARAM)Menu_BuildContactMenu(m_si->hContact));
+			return TRUE;
 
-	case WM_DESTROY:
-		NotifyLocalWinEvent(si->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSING);
-		si->hWnd = NULL;
-		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+		case WM_CONTEXTMENU:
+			if (GetParent(m_hwnd) == (HWND)wParam) {
+				HMENU hMenu = Menu_BuildContactMenu(m_si->hContact);
+				GetCursorPos(&pt);
+				TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, m_hwnd, NULL);
+				DestroyMenu(hMenu);
+			}
+			break;
 
-		SendMessage(GetParent(hwndDlg), CM_REMOVECHILD, 0, (LPARAM)hwndDlg);
-		if (si->hwndLog != NULL) {
-			IEVIEWWINDOW ieWindow;
-			ieWindow.cbSize = sizeof(IEVIEWWINDOW);
-			ieWindow.iType = IEW_DESTROY;
-			ieWindow.hwnd = si->hwndLog;
-			CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
+		case GC_CLOSEWINDOW:
+			Close();
+			break;
 		}
-
-		NotifyLocalWinEvent(si->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSE);
-		break;
+		return CSrmmBaseDialog::DlgProc(uMsg, wParam, lParam);
 	}
-	return FALSE;
-}
+};
 
 void ShowRoom(SESSION_INFO *si)
 {
@@ -1806,8 +1799,13 @@ void ShowRoom(SESSION_INFO *si)
 	// Do we need to create a window?
 	if (si->hWnd == NULL) {
 		HWND hParent = GetParentWindow(si->hContact, TRUE);
+
+		CChatRoomDlg *pDlg = new CChatRoomDlg(si);
+		pDlg->SetParent(hParent);
+		pDlg->Show();
+		
 		si->parent = (ParentWindowData*)GetWindowLongPtr(hParent, GWLP_USERDATA);
-		si->hWnd = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_CHANNEL), hParent, RoomWndProc, (LPARAM)si);
+		si->hWnd = pDlg->GetHwnd();
 	}
 	SendMessage(si->hWnd, DM_UPDATETABCONTROL, -1, (LPARAM)si);
 	SendMessage(GetParent(si->hWnd), CM_ACTIVATECHILD, 0, (LPARAM)si->hWnd);
diff --git a/plugins/Scriver/src/infobar.cpp b/plugins/Scriver/src/infobar.cpp
index 54a4669311..be0d288d39 100644
--- a/plugins/Scriver/src/infobar.cpp
+++ b/plugins/Scriver/src/infobar.cpp
@@ -68,7 +68,7 @@ void SetupInfobar(InfobarWindowData* idat)
 
 static HICON GetExtraStatusIcon(InfobarWindowData* idat)
 {
-	BYTE bXStatus = db_get_b(idat->mwd->hContact, idat->mwd->szProto, "XStatusId", 0);
+	BYTE bXStatus = db_get_b(idat->mwd->m_hContact, idat->mwd->szProto, "XStatusId", 0);
 	if (bXStatus > 0)
 		return (HICON)CallProtoService(idat->mwd->szProto, PS_GETCUSTOMSTATUSICON, bXStatus, 0);
 
@@ -78,10 +78,10 @@ static HICON GetExtraStatusIcon(InfobarWindowData* idat)
 void RefreshInfobar(InfobarWindowData* idat)
 {
 	HWND hwnd = idat->hWnd;
-	SrmmWindowData *dat = idat->mwd;
-	ptrW szContactStatusMsg(db_get_wsa(dat->hContact, "CList", "StatusMsg"));
-	ptrW szXStatusName(db_get_wsa(idat->mwd->hContact, idat->mwd->szProto, "XStatusName"));
-	ptrW szXStatusMsg(db_get_wsa(idat->mwd->hContact, idat->mwd->szProto, "XStatusMsg"));
+	CSrmmWindow *dat = idat->mwd;
+	ptrW szContactStatusMsg(db_get_wsa(dat->m_hContact, "CList", "StatusMsg"));
+	ptrW szXStatusName(db_get_wsa(idat->mwd->m_hContact, idat->mwd->szProto, "XStatusName"));
+	ptrW szXStatusMsg(db_get_wsa(idat->mwd->m_hContact, idat->mwd->szProto, "XStatusMsg"));
 	HICON hIcon = GetExtraStatusIcon(idat);
 	wchar_t szText[2048];
 	SETTEXTEX st;
@@ -91,7 +91,7 @@ void RefreshInfobar(InfobarWindowData* idat)
 		wcsncpy_s(szText, TranslateW(szXStatusName), _TRUNCATE);
 	st.flags = ST_DEFAULT;
 	st.codepage = 1200;
-	SendDlgItemMessage(hwnd, IDC_INFOBAR_NAME, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)pcli->pfnGetContactDisplayName(dat->hContact, 0));
+	SendDlgItemMessage(hwnd, IDC_INFOBAR_NAME, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)pcli->pfnGetContactDisplayName(dat->m_hContact, 0));
 	SendDlgItemMessage(hwnd, IDC_INFOBAR_STATUS, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)szContactStatusMsg);
 	hIcon = (HICON)SendDlgItemMessage(hwnd, IDC_XSTATUSICON, STM_SETICON, (WPARAM)hIcon, 0);
 	if (hIcon)
@@ -198,20 +198,6 @@ static INT_PTR CALLBACK InfobarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARA
 						SetFocus(GetParent(hwnd));
 					}
 					break;
-
-				case EN_LINK:
-					switch (((ENLINK*)lParam)->msg) {
-					case WM_RBUTTONDOWN:
-					case WM_LBUTTONUP:
-						if (!bWasCopy) {
-							if (HandleLinkClick(g_hInst, hwnd, GetDlgItem(GetParent(hwnd), IDC_MESSAGE), (ENLINK*)lParam)) {
-								SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
-								return TRUE;
-							}
-						}
-						bWasCopy = FALSE;
-						break;
-					}
 				}
 				break;
 			}
@@ -245,7 +231,7 @@ static INT_PTR CALLBACK InfobarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARA
 						}
 
 						AVATARDRAWREQUEST adr = { sizeof(adr) };
-						adr.hContact = idat->mwd->hContact;
+						adr.hContact = idat->mwd->m_hContact;
 						adr.hTargetDC = hdcMem;
 						adr.rcDraw.right = avatarWidth - 1;
 						adr.rcDraw.bottom = avatarHeight - 1;
@@ -263,12 +249,12 @@ static INT_PTR CALLBACK InfobarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARA
 		return Menu_DrawItem(lParam);
 
 	case WM_LBUTTONDOWN:
-		SendMessage(idat->mwd->hwnd, WM_LBUTTONDOWN, wParam, lParam);
+		SendMessage(idat->mwd->GetHwnd(), WM_LBUTTONDOWN, wParam, lParam);
 		return TRUE;
 
 	case WM_RBUTTONUP:
 		{
-			HMENU hMenu = Menu_BuildContactMenu(idat->mwd->hContact);
+			HMENU hMenu = Menu_BuildContactMenu(idat->mwd->m_hContact);
 
 			POINT pt;
 			GetCursorPos(&pt);
@@ -287,7 +273,7 @@ static INT_PTR CALLBACK InfobarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARA
 	return FALSE;
 }
 
-InfobarWindowData* CreateInfobar(HWND hParent, SrmmWindowData *dat)
+InfobarWindowData* CreateInfobar(HWND hParent, CSrmmWindow *dat)
 {
 	InfobarWindowData *idat = (InfobarWindowData*)mir_alloc(sizeof(InfobarWindowData));
 	idat->mwd = dat;
diff --git a/plugins/Scriver/src/infobar.h b/plugins/Scriver/src/infobar.h
index 2da8737212..3b364a466d 100644
--- a/plugins/Scriver/src/infobar.h
+++ b/plugins/Scriver/src/infobar.h
@@ -25,12 +25,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 typedef struct InfobarWindowDataStruct
 {
-	struct SrmmWindowData *mwd;
+	class CSrmmWindow *mwd;
 	HWND    hWnd;
 	HWND	hXStatusTip;
 } InfobarWindowData;
 
-InfobarWindowData *CreateInfobar(HWND hParent, SrmmWindowData *dat);
+InfobarWindowData *CreateInfobar(HWND hParent, CSrmmWindow *dat);
 void SetupInfobar(InfobarWindowData* idat);
 void RefreshInfobar(InfobarWindowData* idat);
 
diff --git a/plugins/Scriver/src/input.cpp b/plugins/Scriver/src/input.cpp
index bb7b4449e0..8fe400cdd9 100644
--- a/plugins/Scriver/src/input.cpp
+++ b/plugins/Scriver/src/input.cpp
@@ -362,56 +362,3 @@ void RegisterKeyBindings()
 	desc.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL | HOTKEYF_SHIFT, VK_INSERT);
 	Hotkey_Register(&desc);
 }
-
-BOOL HandleLinkClick(HINSTANCE hInstance, HWND hwndDlg, HWND hwndFocus, ENLINK *lParam)
-{
-	CHARRANGE sel;
-	SendMessage(lParam->nmhdr.hwndFrom, EM_EXGETSEL, 0, (LPARAM)&sel);
-	if (sel.cpMin != sel.cpMax)
-		return FALSE;
-
-	TEXTRANGE tr;
-	tr.chrg = lParam->chrg;
-	tr.lpstrText = (LPWSTR)mir_alloc(sizeof(wchar_t)*(tr.chrg.cpMax - tr.chrg.cpMin + 8));
-	SendMessage(lParam->nmhdr.hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
-	if (wcschr(tr.lpstrText, '@') != NULL && wcschr(tr.lpstrText, ':') == NULL && wcschr(tr.lpstrText, '/') == NULL) {
-		memmove(tr.lpstrText + 7, tr.lpstrText, sizeof(wchar_t)*(tr.chrg.cpMax - tr.chrg.cpMin + 1));
-		memcpy(tr.lpstrText, L"mailto:", sizeof(wchar_t) * 7);
-	}
-
-	BOOL bOpenLink = TRUE;
-
-	if (((ENLINK*)lParam)->msg == WM_RBUTTONDOWN) {
-		bOpenLink = FALSE;
-		HMENU hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_CONTEXT));
-		HMENU hSubMenu = GetSubMenu(hMenu, 1);
-		TranslateMenu(hSubMenu);
-		POINT pt;
-		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 IDM_OPENLINK:
-			bOpenLink = TRUE;
-			break;
-
-		case IDM_COPYLINK:
-			if (!OpenClipboard(hwndDlg))
-				break;
-			EmptyClipboard();
-			HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t)*(mir_wstrlen(tr.lpstrText) + 1));
-			mir_wstrcpy((LPWSTR)GlobalLock(hData), tr.lpstrText);
-			GlobalUnlock(hData);
-			SetClipboardData(CF_UNICODETEXT, hData);
-			CloseClipboard();
-			break;
-		}
-		DestroyMenu(hMenu);
-	}
-	if (bOpenLink)
-		Utils_OpenUrlW(tr.lpstrText);
-
-	SetFocus(hwndFocus);
-	mir_free(tr.lpstrText);
-	return TRUE;
-}
diff --git a/plugins/Scriver/src/input.h b/plugins/Scriver/src/input.h
index 874b58ce9e..0761140346 100644
--- a/plugins/Scriver/src/input.h
+++ b/plugins/Scriver/src/input.h
@@ -26,6 +26,5 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 extern void InputAreaContextMenu(HWND hwnd, WPARAM wParam, LPARAM lParam, MCONTACT hContact);
 extern void RegisterKeyBindings();
 extern int InputAreaShortcuts(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, CommonWindowData *windowData);
-BOOL HandleLinkClick(HINSTANCE hInstance, HWND hwndDlg, HWND hwndFocus, ENLINK *lParam);
 
 #endif
diff --git a/plugins/Scriver/src/msgdialog.cpp b/plugins/Scriver/src/msgdialog.cpp
index 08012ac957..5d28d0412c 100644
--- a/plugins/Scriver/src/msgdialog.cpp
+++ b/plugins/Scriver/src/msgdialog.cpp
@@ -30,13 +30,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 extern HCURSOR hCurSplitNS, hCurSplitWE, hCurHyperlinkHand, hDragCursor;
 extern HANDLE hHookWinEvt;
 
-static void UpdateReadChars(HWND hwndDlg, SrmmWindowData * dat);
-
-static wchar_t* GetIEViewSelection(SrmmWindowData *dat)
+static wchar_t* GetIEViewSelection(CSrmmWindow *dat)
 {
 	IEVIEWEVENT evt = { sizeof(evt) };
-	evt.hwnd = dat->hwndLog;
-	evt.hContact = dat->hContact;
+	evt.hwnd = dat->hwndIeview;
+	evt.hContact = dat->m_hContact;
 	evt.iType = IEE_GET_SELECTION;
 	return mir_wstrdup((wchar_t*)CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&evt));
 }
@@ -162,25 +160,24 @@ static void AddToFileList(wchar_t ***pppFiles, int *totalCount, const wchar_t* s
 	}
 }
 
-static void SetDialogToType(HWND hwndDlg)
+void CSrmmWindow::SetDialogToType()
 {
-	BOOL showToolbar = SendMessage(GetParent(hwndDlg), CM_GETTOOLBARSTATUS, 0, 0);
-	SrmmWindowData *dat = (SrmmWindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-	ParentWindowData *pdat = dat->parent;
+	BOOL showToolbar = SendMessage(GetParent(m_hwnd), CM_GETTOOLBARSTATUS, 0, 0);
+	ParentWindowData *pdat = parent;
 
 	if (pdat->flags2 & SMF2_SHOWINFOBAR)
-		ShowWindow(dat->infobarData->hWnd, SW_SHOW);
+		ShowWindow(infobarData->hWnd, SW_SHOW);
 	else
-		ShowWindow(dat->infobarData->hWnd, SW_HIDE);
+		ShowWindow(infobarData->hWnd, SW_HIDE);
 
 	CustomButtonData *cbd;
 	for (int i = 0; cbd = Srmm_GetNthButton(i); i++) {
-		HWND hwndButton = GetDlgItem(hwndDlg, cbd->m_dwButtonCID);
+		HWND hwndButton = GetDlgItem(m_hwnd, cbd->m_dwButtonCID);
 		if (hwndButton == NULL)
 			continue;
 
-		if (dat->hContact) {
-			if (cbd->m_dwButtonCID == IDC_ADD && !db_get_b(dat->hContact, "CList", "NotOnList", 0))
+		if (m_hContact) {
+			if (cbd->m_dwButtonCID == IDC_ADD && !db_get_b(m_hContact, "CList", "NotOnList", 0))
 				ShowWindow(hwndButton, SW_HIDE);
 			else
 				ShowWindow(hwndButton, showToolbar ? SW_SHOW : SW_HIDE);
@@ -188,63 +185,63 @@ static void SetDialogToType(HWND hwndDlg)
 		else ShowWindow(hwndButton, SW_HIDE);
 	}
 
-	ShowWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), SW_SHOW);
-	if (dat->hwndLog != NULL)
-		ShowWindow(GetDlgItem(hwndDlg, IDC_LOG), SW_HIDE);
+	ShowWindow(m_message.GetHwnd(), SW_SHOW);
+	if (hwndIeview != NULL)
+		ShowWindow(m_log.GetHwnd(), SW_HIDE);
 	else
-		ShowWindow(GetDlgItem(hwndDlg, IDC_LOG), SW_SHOW);
+		ShowWindow(m_log.GetHwnd(), SW_SHOW);
 
-	ShowWindow(GetDlgItem(hwndDlg, IDC_SPLITTERY), SW_SHOW);
-	UpdateReadChars(hwndDlg, dat);
-	EnableWindow(GetDlgItem(hwndDlg, IDOK), GetRichTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE), 1200, FALSE) ? TRUE : FALSE);
-	SendMessage(hwndDlg, DM_CLISTSETTINGSCHANGED, 0, 0);
-	SendMessage(hwndDlg, WM_SIZE, 0, 0);
+	ShowWindow(GetDlgItem(m_hwnd, IDC_SPLITTERY), SW_SHOW);
+	UpdateReadChars();
+	EnableWindow(GetDlgItem(m_hwnd, IDOK), GetRichTextLength(GetDlgItem(m_hwnd, IDC_MESSAGE), 1200, FALSE) ? TRUE : FALSE);
+	SendMessage(m_hwnd, DM_CLISTSETTINGSCHANGED, 0, 0);
+	SendMessage(m_hwnd, WM_SIZE, 0, 0);
 }
 
-void SetStatusIcon(SrmmWindowData *dat)
+void CSrmmWindow::SetStatusIcon()
 {
-	if (dat->szProto == NULL)
+	if (szProto == NULL)
 		return;
 
-	MCONTACT hContact = db_mc_getSrmmSub(dat->hContact);
+	MCONTACT hContact = db_mc_getSrmmSub(m_hContact);
 	if (hContact == NULL)
-		hContact = dat->hContact;
+		hContact = hContact;
 
 	char *szProto = GetContactProto(hContact);
-	dat->statusIcon = Skin_LoadProtoIcon(szProto, dat->wStatus, false);
-	dat->statusIconBig = Skin_LoadProtoIcon(szProto, dat->wStatus, true);
+	statusIcon = Skin_LoadProtoIcon(szProto, wStatus, false);
+	statusIconBig = Skin_LoadProtoIcon(szProto, wStatus, true);
 
-	if (dat->statusIconOverlay != NULL)
-		DestroyIcon(dat->statusIconOverlay);
+	if (statusIconOverlay != NULL)
+		DestroyIcon(statusIconOverlay);
 
-	int index = ImageList_ReplaceIcon(g_dat.hHelperIconList, 0, dat->statusIcon);
-	dat->statusIconOverlay = ImageList_GetIcon(g_dat.hHelperIconList, index, ILD_TRANSPARENT | INDEXTOOVERLAYMASK(1));
+	int index = ImageList_ReplaceIcon(g_dat.hHelperIconList, 0, statusIcon);
+	statusIconOverlay = ImageList_GetIcon(g_dat.hHelperIconList, index, ILD_TRANSPARENT | INDEXTOOVERLAYMASK(1));
 }
 
-void GetTitlebarIcon(SrmmWindowData *dat, TitleBarData *tbd)
+void CSrmmWindow::GetTitlebarIcon(TitleBarData *tbd)
 {
-	if (dat->showTyping && (g_dat.flags2 & SMF2_SHOWTYPINGWIN))
+	if (showTyping && (g_dat.flags2 & SMF2_SHOWTYPINGWIN))
 		tbd->hIconNot = tbd->hIcon = GetCachedIcon("scriver_TYPING");
-	else if (dat->showUnread && (GetActiveWindow() != dat->hwndParent || GetForegroundWindow() != dat->hwndParent)) {
-		tbd->hIcon = (g_dat.flags & SMF_STATUSICON) ? dat->statusIcon : g_dat.hMsgIcon;
+	else if (showUnread && (GetActiveWindow() != m_hwndParent || GetForegroundWindow() != m_hwndParent)) {
+		tbd->hIcon = (g_dat.flags & SMF_STATUSICON) ? statusIcon : g_dat.hMsgIcon;
 		tbd->hIconNot = (g_dat.flags & SMF_STATUSICON) ? g_dat.hMsgIcon : GetCachedIcon("scriver_OVERLAY");
 	}
 	else {
-		tbd->hIcon = (g_dat.flags & SMF_STATUSICON) ? dat->statusIcon : g_dat.hMsgIcon;
+		tbd->hIcon = (g_dat.flags & SMF_STATUSICON) ? statusIcon : g_dat.hMsgIcon;
 		tbd->hIconNot = NULL;
 	}
-	tbd->hIconBig = (g_dat.flags & SMF_STATUSICON) ? dat->statusIconBig : g_dat.hMsgIconBig;
+	tbd->hIconBig = (g_dat.flags & SMF_STATUSICON) ? statusIconBig : g_dat.hMsgIconBig;
 }
 
-HICON GetTabIcon(SrmmWindowData *dat)
+HICON CSrmmWindow::GetTabIcon()
 {
-	if (dat->showTyping)
+	if (showTyping)
 		return GetCachedIcon("scriver_TYPING");
 
-	if (dat->showUnread != 0)
-		return dat->statusIconOverlay;
+	if (showUnread != 0)
+		return statusIconOverlay;
 
-	return dat->statusIcon;
+	return statusIcon;
 }
 
 static LRESULT CALLBACK LogEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
@@ -343,7 +340,7 @@ struct MsgEditSubclassData
 static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
 	MsgEditSubclassData *dat = (MsgEditSubclassData*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
-	SrmmWindowData *pdat = (SrmmWindowData*)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
+	CSrmmWindow *pdat = (CSrmmWindow*)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
 
 	int result = InputAreaShortcuts(hwnd, msg, wParam, lParam, pdat);
 	if (result != -1)
@@ -418,7 +415,7 @@ static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd, UINT msg, WPARAM wPar
 		return 0;
 
 	case WM_CONTEXTMENU:
-		InputAreaContextMenu(hwnd, wParam, lParam, pdat->hContact);
+		InputAreaContextMenu(hwnd, wParam, lParam, pdat->m_hContact);
 		return TRUE;
 
 	case WM_DESTROY:
@@ -442,12 +439,15 @@ static void SubclassLogEdit(HWND hwnd)
 	SendMessage(hwnd, EM_SUBCLASSED, 0, 0);
 }
 
-static void MessageDialogResize(HWND hwndDlg, SrmmWindowData *dat, int w, int h)
+void CSrmmWindow::MessageDialogResize(int w, int h)
 {
-	ParentWindowData *pdat = dat->parent;
+	if (!infobarData)
+		return;
+
+	ParentWindowData *pdat = parent;
 	bool bToolbar = (pdat->flags2 & SMF2_SHOWTOOLBAR) != 0;
-	int hSplitterPos = dat->splitterPos, toolbarHeight = (bToolbar) ? dat->toolbarSize.cy : 0;
-	int hSplitterMinTop = toolbarHeight + dat->minLogBoxHeight, hSplitterMinBottom = dat->minEditBoxHeight;
+	int hSplitterPos = splitterPos, toolbarHeight = (bToolbar) ? toolbarSize.cy : 0;
+	int hSplitterMinTop = toolbarHeight + minLogBoxHeight, hSplitterMinBottom = minEditBoxHeight;
 	int infobarInnerHeight = INFO_BAR_INNER_HEIGHT;
 	int infobarHeight = INFO_BAR_HEIGHT;
 	int avatarWidth = 0, avatarHeight = 0;
@@ -455,14 +455,11 @@ static void MessageDialogResize(HWND hwndDlg, SrmmWindowData *dat, int w, int h)
 	int messageEditWidth = w - 2;
 	int logY, logH;
 
-	if (!dat->infobarData)
-		return;
-
 	if (!(pdat->flags2 & SMF2_SHOWINFOBAR)) {
 		infobarHeight = 0;
 		infobarInnerHeight = 0;
 	}
-	hSplitterPos = dat->desiredInputAreaHeight + SPLITTER_HEIGHT + 3;
+	hSplitterPos = desiredInputAreaHeight + SPLITTER_HEIGHT + 3;
 
 	if (hSplitterPos > (h - toolbarHeight - infobarHeight + SPLITTER_HEIGHT + 1) / 2)
 		hSplitterPos = (h - toolbarHeight - infobarHeight + SPLITTER_HEIGHT + 1) / 2;
@@ -477,7 +474,7 @@ static void MessageDialogResize(HWND hwndDlg, SrmmWindowData *dat, int w, int h)
 		hSplitterPos = hSplitterMinBottom;
 
 	if (!(pdat->flags2 & SMF2_SHOWINFOBAR)) {
-		if (dat->avatarPic && (g_dat.flags & SMF_AVATAR)) {
+		if (avatarPic && (g_dat.flags & SMF_AVATAR)) {
 			avatarWidth = BOTTOM_RIGHT_AVATAR_HEIGHT;
 			avatarHeight = toolbarHeight + hSplitterPos - 2;
 			if (avatarHeight < BOTTOM_RIGHT_AVATAR_HEIGHT) {
@@ -490,54 +487,54 @@ static void MessageDialogResize(HWND hwndDlg, SrmmWindowData *dat, int w, int h)
 			if (avatarWidth > BOTTOM_RIGHT_AVATAR_HEIGHT && avatarWidth > w / 4)
 				avatarWidth = w / 4;
 
-			if ((toolbarWidth - avatarWidth - 2) < dat->toolbarSize.cx)
-				avatarWidth = toolbarWidth - dat->toolbarSize.cx - 2;
+			if ((toolbarWidth - avatarWidth - 2) < toolbarSize.cx)
+				avatarWidth = toolbarWidth - toolbarSize.cx - 2;
 
 			toolbarWidth -= avatarWidth + 2;
 			messageEditWidth -= avatarWidth + 1;
 		}
 	}
 
-	dat->splitterPos = hSplitterPos;
+	splitterPos = hSplitterPos;
 
 	logY = infobarInnerHeight;
 	logH = h - hSplitterPos - toolbarHeight - infobarInnerHeight;
 
 	HDWP hdwp = BeginDeferWindowPos(5);
-	hdwp = DeferWindowPos(hdwp, dat->infobarData->hWnd, 0, 1, 0, w - 2, infobarInnerHeight - 2, SWP_NOZORDER);
-	hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_LOG), 0, 1, logY, w - 2, logH, SWP_NOZORDER);
-	hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_MESSAGE), 0, 1, h - hSplitterPos + SPLITTER_HEIGHT, messageEditWidth, hSplitterPos - SPLITTER_HEIGHT - 1, SWP_NOZORDER);
-	hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_AVATAR), 0, w - avatarWidth - 1, h - (avatarHeight + avatarWidth) / 2 - 1, avatarWidth, avatarWidth, SWP_NOZORDER);
-	hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_SPLITTERY), 0, 0, h - hSplitterPos - 1, toolbarWidth, SPLITTER_HEIGHT, SWP_NOZORDER);
+	hdwp = DeferWindowPos(hdwp, infobarData->hWnd, 0, 1, 0, w - 2, infobarInnerHeight - 2, SWP_NOZORDER);
+	hdwp = DeferWindowPos(hdwp, m_log.GetHwnd(), 0, 1, logY, w - 2, logH, SWP_NOZORDER);
+	hdwp = DeferWindowPos(hdwp, GetDlgItem(m_hwnd, IDC_MESSAGE), 0, 1, h - hSplitterPos + SPLITTER_HEIGHT, messageEditWidth, hSplitterPos - SPLITTER_HEIGHT - 1, SWP_NOZORDER);
+	hdwp = DeferWindowPos(hdwp, GetDlgItem(m_hwnd, IDC_AVATAR), 0, w - avatarWidth - 1, h - (avatarHeight + avatarWidth) / 2 - 1, avatarWidth, avatarWidth, SWP_NOZORDER);
+	hdwp = DeferWindowPos(hdwp, GetDlgItem(m_hwnd, IDC_SPLITTERY), 0, 0, h - hSplitterPos - 1, toolbarWidth, SPLITTER_HEIGHT, SWP_NOZORDER);
 	EndDeferWindowPos(hdwp);
 
-	SetButtonsPos(hwndDlg, bToolbar);
+	SetButtonsPos(m_hwnd, bToolbar);
 
-	if (dat->hwndLog != NULL) {
+	if (hwndIeview != NULL) {
 		IEVIEWWINDOW ieWindow = { sizeof(ieWindow) };
 		ieWindow.iType = IEW_SETPOS;
-		ieWindow.parent = hwndDlg;
-		ieWindow.hwnd = dat->hwndLog;
+		ieWindow.parent = m_hwnd;
+		ieWindow.hwnd = hwndIeview;
 		ieWindow.x = 0;
 		ieWindow.y = logY;
 		ieWindow.cx = w;
 		ieWindow.cy = logH;
 		CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
 	}
-	else RedrawWindow(GetDlgItem(hwndDlg, IDC_LOG), NULL, NULL, RDW_INVALIDATE);
+	else RedrawWindow(m_log.GetHwnd(), NULL, NULL, RDW_INVALIDATE);
 
-	RedrawWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, NULL, RDW_INVALIDATE);
+	RedrawWindow(m_message.GetHwnd(), NULL, NULL, RDW_INVALIDATE);
 
-	RefreshInfobar(dat->infobarData);
+	RefreshInfobar(infobarData);
 
-	RedrawWindow(GetDlgItem(hwndDlg, IDC_AVATAR), NULL, NULL, RDW_INVALIDATE);
+	RedrawWindow(GetDlgItem(m_hwnd, IDC_AVATAR), NULL, NULL, RDW_INVALIDATE);
 }
 
-static void UpdateReadChars(HWND hwndDlg, SrmmWindowData *dat)
+void CSrmmWindow::UpdateReadChars()
 {
-	if (dat->parent->hwndActive == hwndDlg) {
+	if (parent->hwndActive == m_hwnd) {
 		wchar_t szText[256];
-		int len = GetRichTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE), 1200, FALSE);
+		int len = GetRichTextLength(GetDlgItem(m_hwnd, IDC_MESSAGE), 1200, FALSE);
 
 		StatusBarData sbd;
 		sbd.iItem = 1;
@@ -545,53 +542,53 @@ static void UpdateReadChars(HWND hwndDlg, SrmmWindowData *dat)
 		sbd.hIcon = NULL;
 		sbd.pszText = szText;
 		mir_snwprintf(szText, L"%d", len);
-		SendMessage(dat->hwndParent, CM_UPDATESTATUSBAR, (WPARAM)&sbd, (LPARAM)hwndDlg);
+		SendMessage(m_hwndParent, CM_UPDATESTATUSBAR, (WPARAM)&sbd, (LPARAM)m_hwnd);
 	}
 }
 
-void ShowAvatar(HWND hwndDlg, SrmmWindowData *dat)
+void CSrmmWindow::ShowAvatar()
 {
-	INT_PTR res = CallService(MS_AV_GETAVATARBITMAP, dat->hContact, 0);
-	dat->ace = res != CALLSERVICE_NOTFOUND ? (AVATARCACHEENTRY*)res : NULL;
-	dat->avatarPic = (dat->ace != NULL && (dat->ace->dwFlags & AVS_HIDEONCLIST) == 0) ? dat->ace->hbmPic : NULL;
-	SendMessage(hwndDlg, WM_SIZE, 0, 0);
+	INT_PTR res = CallService(MS_AV_GETAVATARBITMAP, m_hContact, 0);
+	ace = res != CALLSERVICE_NOTFOUND ? (AVATARCACHEENTRY*)res : NULL;
+	avatarPic = (ace != NULL && (ace->dwFlags & AVS_HIDEONCLIST) == 0) ? ace->hbmPic : NULL;
+	SendMessage(m_hwnd, WM_SIZE, 0, 0);
 
-	RefreshInfobar(dat->infobarData);
+	RefreshInfobar(infobarData);
 
-	RedrawWindow(GetDlgItem(hwndDlg, IDC_AVATAR), NULL, NULL, RDW_INVALIDATE);
+	RedrawWindow(GetDlgItem(m_hwnd, IDC_AVATAR), NULL, NULL, RDW_INVALIDATE);
 }
 
-static BOOL IsTypingNotificationSupported(SrmmWindowData *dat)
+bool CSrmmWindow::IsTypingNotificationSupported()
 {
-	if (!dat->hContact)
-		return FALSE;
+	if (!m_hContact)
+		return false;
 
-	if (!dat->szProto)
-		return FALSE;
+	if (!szProto)
+		return false;
 
-	DWORD typeCaps = CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_4, 0);
+	DWORD typeCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0);
 	if (!(typeCaps & PF4_SUPPORTTYPING))
-		return FALSE;
-	return TRUE;
+		return false;
+	return true;
 }
 
-static BOOL IsTypingNotificationEnabled(SrmmWindowData *dat)
+bool CSrmmWindow::IsTypingNotificationEnabled()
 {
-	if (!db_get_b(dat->hContact, SRMMMOD, SRMSGSET_TYPING, db_get_b(NULL, SRMMMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)))
+	if (!db_get_b(m_hContact, SRMMMOD, SRMSGSET_TYPING, db_get_b(NULL, SRMMMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)))
 		return FALSE;
 
-	DWORD protoStatus = CallProtoService(dat->szProto, PS_GETSTATUS, 0, 0);
+	DWORD protoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
 	if (protoStatus < ID_STATUS_ONLINE)
 		return FALSE;
 
-	DWORD protoCaps = CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_1, 0);
-	if (protoCaps & PF1_VISLIST && db_get_w(dat->hContact, dat->szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE)
+	DWORD protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+	if (protoCaps & PF1_VISLIST && db_get_w(m_hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE)
 		return FALSE;
 
-	if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && db_get_w(dat->hContact, dat->szProto, "ApparentMode", 0) != ID_STATUS_ONLINE)
+	if (protoCaps & PF1_INVISLIST && protoStatus == ID_STATUS_INVISIBLE && db_get_w(m_hContact, szProto, "ApparentMode", 0) != ID_STATUS_ONLINE)
 		return FALSE;
 
-	if (db_get_b(dat->hContact, "CList", "NotOnList", 0)
+	if (db_get_b(m_hContact, "CList", "NotOnList", 0)
 		&& !db_get_b(NULL, SRMMMOD, SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN))
 		return FALSE;
 	return TRUE;
@@ -602,17 +599,17 @@ static BOOL IsTypingNotificationEnabled(SrmmWindowData *dat)
 // Don't send to protocols that are offline
 // Don't send to users who are not visible and
 // Don't send to users who are not on the visible list when you are in invisible mode.
-static void NotifyTyping(SrmmWindowData *dat, int mode)
+void CSrmmWindow::NotifyTyping(int mode)
 {
-	if (!IsTypingNotificationSupported(dat))
+	if (!IsTypingNotificationSupported())
 		return;
 
-	if (!IsTypingNotificationEnabled(dat))
+	if (!IsTypingNotificationEnabled())
 		return;
 
 	// End user check
-	dat->nTypeMode = mode;
-	CallService(MS_PROTO_SELFISTYPING, dat->hContact, dat->nTypeMode);
+	nTypeMode = mode;
+	CallService(MS_PROTO_SELFISTYPING, m_hContact, nTypeMode);
 }
 
 static INT_PTR CALLBACK ConfirmSendAllDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM)
@@ -649,262 +646,300 @@ static INT_PTR CALLBACK ConfirmSendAllDlgProc(HWND hwndDlg, UINT msg, WPARAM wPa
 	return FALSE;
 }
 
-INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CSrmmWindow::CSrmmWindow(MCONTACT hContact, bool bIncoming, const char *szInitialText, bool bIsUnicode)
+	: CSrmmBaseDialog(g_hInst, IDD_MSG),
+	m_log(this, IDC_LOG),
+	m_message(this, IDC_MESSAGE),
+	m_bIncoming(bIncoming),
+	m_hContact(hContact)
+{
+	m_pLog = &m_log;
+	m_pEntry = &m_message;
+
+	m_hwndParent = GetParentWindow(hContact, FALSE);
+	m_wszInitialText = (bIsUnicode) ? mir_wstrdup((wchar_t*)szInitialText) : mir_a2u(szInitialText);
+}
+
+void CSrmmWindow::OnInitDialog()
 {
+	int len = 0;
+
+	SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this);
+	WindowList_Add(pci->hWindowList, m_hwnd, m_hContact);
+
+	NotifyLocalWinEvent(m_hContact, m_hwnd, MSG_WINDOW_EVT_OPENING);
+
+	parent = (ParentWindowData *)GetWindowLongPtr(m_hwndParent, GWLP_USERDATA);
+	szProto = GetContactProto(m_hContact);
+
+	if (m_hContact && szProto != NULL)
+		wStatus = db_get_w(m_hContact, szProto, "Status", ID_STATUS_OFFLINE);
+	else
+		wStatus = ID_STATUS_OFFLINE;
+
+	nTypeMode = PROTOTYPE_SELFTYPING_OFF;
+	SetTimer(m_hwnd, TIMERID_TYPE, 1000, NULL);
+
+	lastEventType = -1;
+	lastEventTime = time(NULL);
+	startTime = time(NULL);
+
+	if (db_get_b(m_hContact, SRMMMOD, "UseRTL", (BYTE)0))
+		flags |= SMF_RTL;
+
+	flags |= g_dat.ieviewInstalled ? g_dat.flags & SMF_USEIEVIEW : 0;
+
 	PARAFORMAT2 pf2;
-	CHARFORMAT2 cf2;
-	LPNMHDR pNmhdr;
-	HCURSOR hCur;
+	memset(&pf2, 0, sizeof(pf2));
+	pf2.cbSize = sizeof(pf2);
+	pf2.dwMask = PFM_RTLPARA;
+	if (!(flags & SMF_RTL)) {
+		pf2.wEffects = 0;
+		SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_MESSAGE), GWL_EXSTYLE) & ~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR));
+	}
+	else {
+		pf2.wEffects = PFE_RTLPARA;
+		SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_MESSAGE), GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR);
+	}
+	SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+	/* Workaround to make Richedit display RTL messages correctly */
+	memset(&pf2, 0, sizeof(pf2));
+	pf2.cbSize = sizeof(pf2);
+	pf2.dwMask = PFM_RTLPARA | PFM_OFFSETINDENT | PFM_RIGHTINDENT;
+	pf2.wEffects = PFE_RTLPARA;
+	pf2.dxStartIndent = 30;
+	pf2.dxRightIndent = 30;
+	SendDlgItemMessage(m_hwnd, IDC_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+	pf2.dwMask = PFM_RTLPARA;
+	pf2.wEffects = 0;
+	SendDlgItemMessage(m_hwnd, IDC_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+	if (flags & SMF_RTL)
+		SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LOG), GWL_EXSTYLE) | WS_EX_LEFTSCROLLBAR);
+	else
+		SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LOG), GWL_EXSTYLE) & ~WS_EX_LEFTSCROLLBAR);
+
+	RECT minEditInit;
+	GetWindowRect(GetDlgItem(m_hwnd, IDC_MESSAGE), &minEditInit);
+	minEditBoxHeight = minEditInit.bottom - minEditInit.top;
+	minLogBoxHeight = minEditBoxHeight;
+	toolbarSize.cy = TOOLBAR_HEIGHT;
+	toolbarSize.cx = 0;
+	if (splitterPos == -1)
+		splitterPos = minEditBoxHeight;
+
+	if (m_wszInitialText) {
+		SetDlgItemText(m_hwnd, IDC_MESSAGE, m_wszInitialText);
+		mir_free(m_wszInitialText);
+	}
+	else if (g_dat.flags & SMF_SAVEDRAFTS) {
+		ptrW ptszSavedMsg(db_get_wsa(m_hContact, "SRMM", "SavedMsg"));
+		if (ptszSavedMsg)
+			len = SetRichText(GetDlgItem(m_hwnd, IDC_MESSAGE), ptszSavedMsg);
+		PostMessage(GetDlgItem(m_hwnd, IDC_MESSAGE), EM_SETSEL, len, len);
+	}
 
-	SrmmWindowData *dat = (SrmmWindowData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
-	if (!dat && msg != WM_INITDIALOG)
-		return FALSE;
+	Srmm_CreateToolbarIcons(m_hwnd, BBBF_ISIMBUTTON);
+	SendMessage(m_hwnd, DM_CHANGEICONS, 0, 0);
+
+	SendDlgItemMessage(m_hwnd, IDC_LOG, EM_SETOLECALLBACK, 0, (LPARAM)&reOleCallback);
+	SendDlgItemMessage(m_hwnd, IDC_LOG, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK | ENM_KEYEVENTS);
+	SendDlgItemMessage(m_hwnd, IDC_LOG, EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, SES_EXTENDBACKCOLOR);
+	SendDlgItemMessage(m_hwnd, IDC_LOG, EM_SETLANGOPTIONS, 0, (LPARAM)SendDlgItemMessage(m_hwnd, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~(IMF_AUTOKEYBOARD | IMF_AUTOFONTSIZEADJUST));
+	SendDlgItemMessage(m_hwnd, IDC_LOG, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0));
+	SendDlgItemMessage(m_hwnd, IDC_LOG, EM_AUTOURLDETECT, TRUE, 0);
+
+	SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_SETLANGOPTIONS, 0, (LPARAM)SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
+	SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_SETOLECALLBACK, 0, (LPARAM)&reOleCallback2);
+	SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_CHANGE | ENM_REQUESTRESIZE);
+	if (m_hContact && szProto) {
+		int nMax = CallProtoService(szProto, PS_GETCAPS, PFLAG_MAXLENOFMESSAGE, m_hContact);
+		if (nMax)
+			SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_LIMITTEXT, nMax, 0);
+	}
 
-	switch (msg) {
-	case WM_INITDIALOG:
-		TranslateDialogDefault(hwndDlg);
-		{
-			int len = 0;
-			RECT minEditInit;
-			NewMessageWindowLParam *newData = (NewMessageWindowLParam*)lParam;
-			dat = (SrmmWindowData*)mir_calloc(sizeof(SrmmWindowData));
-			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
-			dat->hContact = newData->hContact;
-			WindowList_Add(pci->hWindowList, hwndDlg, dat->hContact);
-
-			NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPENING);
-
-			dat->hwnd = hwndDlg;
-			dat->hwndParent = GetParent(hwndDlg);
-			dat->parent = (ParentWindowData *)GetWindowLongPtr(dat->hwndParent, GWLP_USERDATA);
-			dat->hwndLog = NULL;
-			dat->szProto = GetContactProto(dat->hContact);
-			dat->avatarPic = 0;
-			if (dat->hContact && dat->szProto != NULL)
-				dat->wStatus = db_get_w(dat->hContact, dat->szProto, "Status", ID_STATUS_OFFLINE);
-			else
-				dat->wStatus = ID_STATUS_OFFLINE;
-			dat->hDbEventFirst = NULL;
-			dat->hDbEventLast = NULL;
-			dat->hDbUnreadEventFirst = NULL;
-			dat->messagesInProgress = 0;
-			dat->nTypeSecs = 0;
-			dat->nLastTyping = 0;
-			dat->showTyping = 0;
-			dat->showUnread = 0;
-			dat->sendAllConfirm = 0;
-			dat->nTypeMode = PROTOTYPE_SELFTYPING_OFF;
-			SetTimer(hwndDlg, TIMERID_TYPE, 1000, NULL);
-			dat->lastMessage = 0;
-			dat->lastEventType = -1;
-			dat->lastEventTime = time(NULL);
-			dat->startTime = time(NULL);
-			dat->flags = 0;
-			if (db_get_b(dat->hContact, SRMMMOD, "UseRTL", (BYTE)0))
-				dat->flags |= SMF_RTL;
-
-			dat->flags |= g_dat.ieviewInstalled ? g_dat.flags & SMF_USEIEVIEW : 0;
-			{
-				memset(&pf2, 0, sizeof(pf2));
-				pf2.cbSize = sizeof(pf2);
-				pf2.dwMask = PFM_RTLPARA;
-				if (!(dat->flags & SMF_RTL)) {
-					pf2.wEffects = 0;
-					SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_EXSTYLE) & ~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR));
-				}
-				else {
-					pf2.wEffects = PFE_RTLPARA;
-					SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR);
-				}
-				SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
-				/* Workaround to make Richedit display RTL messages correctly */
-				memset(&pf2, 0, sizeof(pf2));
-				pf2.cbSize = sizeof(pf2);
-				pf2.dwMask = PFM_RTLPARA | PFM_OFFSETINDENT | PFM_RIGHTINDENT;
-				pf2.wEffects = PFE_RTLPARA;
-				pf2.dxStartIndent = 30;
-				pf2.dxRightIndent = 30;
-				SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
-				pf2.dwMask = PFM_RTLPARA;
-				pf2.wEffects = 0;
-				SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
-				if (dat->flags & SMF_RTL)
-					SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_EXSTYLE) | WS_EX_LEFTSCROLLBAR);
-				else
-					SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_EXSTYLE) & ~WS_EX_LEFTSCROLLBAR);
-			}
-			dat->ace = NULL;
-			GetWindowRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &minEditInit);
-			dat->minEditBoxHeight = minEditInit.bottom - minEditInit.top;
-			dat->minLogBoxHeight = dat->minEditBoxHeight;
-			dat->toolbarSize.cy = TOOLBAR_HEIGHT;
-			dat->toolbarSize.cx = 0;
-			if (dat->splitterPos == -1)
-				dat->splitterPos = dat->minEditBoxHeight;
-
-			if (newData->szInitialText) {
-				if (newData->isWchar)
-					SetDlgItemText(hwndDlg, IDC_MESSAGE, (wchar_t*)newData->szInitialText);
+	// get around a lame bug in the Windows template resource code where richedits are limited to 0x7FFF
+	SendDlgItemMessage(m_hwnd, IDC_LOG, EM_LIMITTEXT, sizeof(wchar_t) * 0x7FFFFFFF, 0);
+	SubclassLogEdit(GetDlgItem(m_hwnd, IDC_LOG));
+	SubclassMessageEdit(GetDlgItem(m_hwnd, IDC_MESSAGE));
+	infobarData = CreateInfobar(m_hwnd, this);
+	if (flags & SMF_USEIEVIEW) {
+		IEVIEWWINDOW ieWindow = { sizeof(IEVIEWWINDOW) };
+		ieWindow.iType = IEW_CREATE;
+		ieWindow.dwMode = IEWM_SCRIVER;
+		ieWindow.parent = m_hwnd;
+		ieWindow.cx = 200;
+		ieWindow.cy = 300;
+		CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
+		hwndIeview = ieWindow.hwnd;
+		if (hwndIeview == NULL)
+			flags ^= SMF_USEIEVIEW;
+	}
+
+	bool notifyUnread = false;
+	if (m_hContact) {
+		int historyMode = db_get_b(NULL, SRMMMOD, SRMSGSET_LOADHISTORY, SRMSGDEFSET_LOADHISTORY);
+		// This finds the first message to display, it works like shit
+		hDbEventFirst = db_event_firstUnread(m_hContact);
+		if (hDbEventFirst != NULL) {
+			DBEVENTINFO dbei = {};
+			db_event_get(hDbEventFirst, &dbei);
+			if (DbEventIsMessageOrCustom(&dbei) && !(dbei.flags & DBEF_READ) && !(dbei.flags & DBEF_SENT))
+				notifyUnread = true;
+		}
+
+		DBEVENTINFO dbei = {};
+		MEVENT hPrevEvent;
+		switch (historyMode) {
+		case LOADHISTORY_COUNT:
+			for (int i = db_get_w(NULL, SRMMMOD, SRMSGSET_LOADCOUNT, SRMSGDEFSET_LOADCOUNT); i > 0; i--) {
+				if (hDbEventFirst == NULL)
+					hPrevEvent = db_event_last(m_hContact);
 				else
-					SetDlgItemTextA(hwndDlg, IDC_MESSAGE, newData->szInitialText);
-			}
-			else if (g_dat.flags & SMF_SAVEDRAFTS) {
-				ptrW ptszSavedMsg(db_get_wsa(dat->hContact, "SRMM", "SavedMsg"));
-				if (ptszSavedMsg)
-					len = SetRichText(GetDlgItem(hwndDlg, IDC_MESSAGE), ptszSavedMsg);
-				PostMessage(GetDlgItem(hwndDlg, IDC_MESSAGE), EM_SETSEL, len, len);
+					hPrevEvent = db_event_prev(m_hContact, hDbEventFirst);
+				if (hPrevEvent == NULL)
+					break;
+				dbei.cbBlob = 0;
+				hDbEventFirst = hPrevEvent;
+				db_event_get(hDbEventFirst, &dbei);
+				if (!DbEventIsShown(dbei))
+					i++;
 			}
+			break;
 
-			Srmm_CreateToolbarIcons(hwndDlg, BBBF_ISIMBUTTON);
-			SendMessage(hwndDlg, DM_CHANGEICONS, 0, 0);
-
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETOLECALLBACK, 0, (LPARAM)&reOleCallback);
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK | ENM_KEYEVENTS);
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETEDITSTYLE, SES_EXTENDBACKCOLOR, SES_EXTENDBACKCOLOR);
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETLANGOPTIONS, 0, (LPARAM)SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~(IMF_AUTOKEYBOARD | IMF_AUTOFONTSIZEADJUST));
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0));
-			/* duh, how come we didnt use this from the start? */
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_AUTOURLDETECT, TRUE, 0);
-
-			SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETLANGOPTIONS, 0, (LPARAM)SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
-			SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETOLECALLBACK, 0, (LPARAM)&reOleCallback2);
-			SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_CHANGE | ENM_REQUESTRESIZE);
-			if (dat->hContact && dat->szProto) {
-				int nMax = CallProtoService(dat->szProto, PS_GETCAPS, PFLAG_MAXLENOFMESSAGE, dat->hContact);
-				if (nMax)
-					SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_LIMITTEXT, nMax, 0);
+		case LOADHISTORY_TIME:
+			if (hDbEventFirst == NULL) {
+				dbei.timestamp = time(NULL);
+				hPrevEvent = db_event_last(m_hContact);
 			}
-			/* get around a lame bug in the Windows template resource code where richedits are limited to 0x7FFF */
-			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_LIMITTEXT, sizeof(wchar_t) * 0x7FFFFFFF, 0);
-			SubclassLogEdit(GetDlgItem(hwndDlg, IDC_LOG));
-			SubclassMessageEdit(GetDlgItem(hwndDlg, IDC_MESSAGE));
-			dat->infobarData = CreateInfobar(hwndDlg, dat);
-			if (dat->flags & SMF_USEIEVIEW) {
-				IEVIEWWINDOW ieWindow = { sizeof(IEVIEWWINDOW) };
-				ieWindow.iType = IEW_CREATE;
-				ieWindow.dwMode = IEWM_SCRIVER;
-				ieWindow.parent = hwndDlg;
-				ieWindow.cx = 200;
-				ieWindow.cy = 300;
-				CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
-				dat->hwndLog = ieWindow.hwnd;
-				if (dat->hwndLog == NULL)
-					dat->flags ^= SMF_USEIEVIEW;
+			else {
+				db_event_get(hDbEventFirst, &dbei);
+				hPrevEvent = db_event_prev(m_hContact, hDbEventFirst);
 			}
-
-			bool notifyUnread = false;
-			if (dat->hContact) {
-				int historyMode = db_get_b(NULL, SRMMMOD, SRMSGSET_LOADHISTORY, SRMSGDEFSET_LOADHISTORY);
-				// This finds the first message to display, it works like shit
-				dat->hDbEventFirst = db_event_firstUnread(dat->hContact);
-				if (dat->hDbEventFirst != NULL) {
-					DBEVENTINFO dbei = {};
-					db_event_get(dat->hDbEventFirst, &dbei);
-					if (DbEventIsMessageOrCustom(&dbei) && !(dbei.flags & DBEF_READ) && !(dbei.flags & DBEF_SENT))
-						notifyUnread = true;
-				}
-
-				DBEVENTINFO dbei = {};
-				MEVENT hPrevEvent;
-				switch (historyMode) {
-				case LOADHISTORY_COUNT:
-					for (int i = db_get_w(NULL, SRMMMOD, SRMSGSET_LOADCOUNT, SRMSGDEFSET_LOADCOUNT); i > 0; i--) {
-						if (dat->hDbEventFirst == NULL)
-							hPrevEvent = db_event_last(dat->hContact);
-						else
-							hPrevEvent = db_event_prev(dat->hContact, dat->hDbEventFirst);
-						if (hPrevEvent == NULL)
-							break;
-						dbei.cbBlob = 0;
-						dat->hDbEventFirst = hPrevEvent;
-						db_event_get(dat->hDbEventFirst, &dbei);
-						if (!DbEventIsShown(dbei))
-							i++;
-					}
+			DWORD firstTime = dbei.timestamp - 60 * db_get_w(NULL, SRMMMOD, SRMSGSET_LOADTIME, SRMSGDEFSET_LOADTIME);
+			for (;;) {
+				if (hPrevEvent == NULL)
 					break;
-
-				case LOADHISTORY_TIME:
-					if (dat->hDbEventFirst == NULL) {
-						dbei.timestamp = time(NULL);
-						hPrevEvent = db_event_last(dat->hContact);
-					}
-					else {
-						db_event_get(dat->hDbEventFirst, &dbei);
-						hPrevEvent = db_event_prev(dat->hContact, dat->hDbEventFirst);
-					}
-					DWORD firstTime = dbei.timestamp - 60 * db_get_w(NULL, SRMMMOD, SRMSGSET_LOADTIME, SRMSGDEFSET_LOADTIME);
-					for (;;) {
-						if (hPrevEvent == NULL)
-							break;
-						dbei.cbBlob = 0;
-						db_event_get(hPrevEvent, &dbei);
-						if (dbei.timestamp < firstTime)
-							break;
-						if (DbEventIsShown(dbei))
-							dat->hDbEventFirst = hPrevEvent;
-						hPrevEvent = db_event_prev(dat->hContact, hPrevEvent);
-					}
+				dbei.cbBlob = 0;
+				db_event_get(hPrevEvent, &dbei);
+				if (dbei.timestamp < firstTime)
 					break;
-				}
-			}
-			SendMessage(dat->hwndParent, CM_ADDCHILD, (WPARAM)hwndDlg, dat->hContact);
-			{
-				MEVENT hdbEvent = db_event_last(dat->hContact);
-				if (hdbEvent) {
-					DBEVENTINFO dbei = {};
-					do {
-						db_event_get(hdbEvent, &dbei);
-						if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) {
-							dat->lastMessage = dbei.timestamp;
-							break;
-						}
-					} while ((hdbEvent = db_event_prev(dat->hContact, hdbEvent)));
-				}
+				if (DbEventIsShown(dbei))
+					hDbEventFirst = hPrevEvent;
+				hPrevEvent = db_event_prev(m_hContact, hPrevEvent);
 			}
-			SendMessage(hwndDlg, DM_OPTIONSAPPLIED, 0, 0);
-			SendMessage(GetParent(hwndDlg), CM_POPUPWINDOW, newData->flags & NMWLP_INCOMING, (LPARAM)hwndDlg);
-			if (notifyUnread) {
-				if (GetForegroundWindow() != dat->hwndParent || dat->parent->hwndActive != hwndDlg) {
-					dat->showUnread = 1;
-					SendMessage(hwndDlg, DM_UPDATEICON, 0, 0);
-					SetTimer(hwndDlg, TIMERID_UNREAD, TIMEOUT_UNREAD, NULL);
-				}
-				SendMessage(dat->hwndParent, CM_STARTFLASHING, 0, 0);
+			break;
+		}
+	}
+	SendMessage(m_hwndParent, CM_ADDCHILD, (WPARAM)m_hwnd, m_hContact);
+
+	MEVENT hdbEvent = db_event_last(m_hContact);
+	if (hdbEvent) {
+		DBEVENTINFO dbei = {};
+		do {
+			db_event_get(hdbEvent, &dbei);
+			if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) {
+				lastMessage = dbei.timestamp;
+				break;
 			}
-			dat->messagesInProgress = ReattachSendQueueItems(hwndDlg, dat->hContact);
-			if (dat->messagesInProgress > 0)
-				SendMessage(hwndDlg, DM_SHOWMESSAGESENDING, 0, 0);
+		} while ((hdbEvent = db_event_prev(m_hContact, hdbEvent)));
+	}
 
-			NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_OPEN);
+	SendMessage(m_hwnd, DM_OPTIONSAPPLIED, 0, 0);
+	SendMessage(GetParent(m_hwnd), CM_POPUPWINDOW, m_bIncoming, (LPARAM)m_hwnd);
+	if (notifyUnread) {
+		if (GetForegroundWindow() != m_hwndParent || parent->hwndActive != m_hwnd) {
+			showUnread = 1;
+			SendMessage(m_hwnd, DM_UPDATEICON, 0, 0);
+			SetTimer(m_hwnd, TIMERID_UNREAD, TIMEOUT_UNREAD, NULL);
 		}
-		return TRUE;
+		SendMessage(m_hwndParent, CM_STARTFLASHING, 0, 0);
+	}
+	messagesInProgress = ReattachSendQueueItems(m_hwnd, m_hContact);
+	if (messagesInProgress > 0)
+		SendMessage(m_hwnd, DM_SHOWMESSAGESENDING, 0, 0);
+
+	NotifyLocalWinEvent(m_hContact, m_hwnd, MSG_WINDOW_EVT_OPEN);
+}
 
+void CSrmmWindow::OnDestroy()
+{
+	NotifyLocalWinEvent(m_hContact, m_hwnd, MSG_WINDOW_EVT_CLOSING);
+	if (nTypeMode == PROTOTYPE_SELFTYPING_ON)
+		NotifyTyping(PROTOTYPE_SELFTYPING_OFF);
+
+	IcoLib_ReleaseIcon(statusIcon);
+	IcoLib_ReleaseIcon(statusIconBig);
+	if (statusIconOverlay != NULL) DestroyIcon(statusIconOverlay);
+	statusIcon = NULL;
+	statusIconOverlay = NULL;
+	ReleaseSendQueueItems(m_hwnd);
+	if (g_dat.flags & SMF_SAVEDRAFTS) {
+		ptrA szText(GetRichTextUtf(GetDlgItem(m_hwnd, IDC_MESSAGE)));
+		if (szText)
+			db_set_utf(m_hContact, "SRMM", "SavedMsg", szText);
+		else
+			db_unset(m_hContact, "SRMM", "SavedMsg");
+	}
+
+	tcmdlist_free(cmdList);
+	WindowList_Remove(pci->hWindowList, m_hwnd);
+
+	HFONT hFont = (HFONT)SendDlgItemMessage(m_hwnd, IDC_MESSAGE, WM_GETFONT, 0, 0);
+	if (hFont != NULL && hFont != (HFONT)SendDlgItemMessage(m_hwnd, IDOK, WM_GETFONT, 0, 0))
+		DeleteObject(hFont);
+
+	db_set_b(m_hContact, SRMMMOD, "UseRTL", (BYTE)((flags & SMF_RTL) ? 1 : 0));
+	if (m_hContact && (g_dat.flags & SMF_DELTEMP))
+		if (db_get_b(m_hContact, "CList", "NotOnList", 0))
+			db_delete_contact(m_hContact);
+
+	SetWindowLongPtr(m_hwnd, GWLP_USERDATA, 0);
+	SendMessage(m_hwndParent, CM_REMOVECHILD, 0, (LPARAM)m_hwnd);
+	if (hwndIeview != NULL) {
+		IEVIEWWINDOW ieWindow = { sizeof(ieWindow) };
+		ieWindow.iType = IEW_DESTROY;
+		ieWindow.hwnd = hwndIeview;
+		CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
+	}
+	NotifyLocalWinEvent(m_hContact, m_hwnd, MSG_WINDOW_EVT_CLOSE);
+}
+
+INT_PTR CSrmmWindow::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	PARAFORMAT2 pf2;
+	CHARFORMAT2 cf2;
+	LPNMHDR pNmhdr;
+	HCURSOR hCur;
+
+	switch (msg) {
 	case DM_GETCONTEXTMENU:
 		{
-			HMENU hMenu = Menu_BuildContactMenu(dat->hContact);
-			SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)hMenu);
+			HMENU hMenu = Menu_BuildContactMenu(m_hContact);
+			SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, (LONG_PTR)hMenu);
 		}
 		return TRUE;
 
 	case WM_CONTEXTMENU:
-		if (dat->hwndParent == (HWND)wParam) {
+		if (m_hwndParent == (HWND)wParam) {
 			POINT pt;
-			HMENU hMenu = Menu_BuildContactMenu(dat->hContact);
+			HMENU hMenu = Menu_BuildContactMenu(m_hContact);
 			GetCursorPos(&pt);
-			TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hwndDlg, NULL);
+			TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, m_hwnd, NULL);
 			DestroyMenu(hMenu);
 		}
 		break;
 
 	case WM_LBUTTONDBLCLK:
-		SendMessage(dat->hwndParent, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+		SendMessage(m_hwndParent, WM_SYSCOMMAND, SC_MINIMIZE, 0);
 		break;
 
 	case WM_DROPFILES:
-		if (dat->szProto == NULL) break;
-		if (!(CallProtoService(dat->szProto, PS_GETCAPS, PFLAGNUM_1, 0)&PF1_FILESEND)) break;
-		if (dat->wStatus == ID_STATUS_OFFLINE) break;
-		if (dat->hContact != NULL) {
+		if (szProto == NULL) break;
+		if (!(CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0)&PF1_FILESEND)) break;
+		if (wStatus == ID_STATUS_OFFLINE) break;
+		if (m_hContact != NULL) {
 			wchar_t szFilename[MAX_PATH];
 			HDROP hDrop = (HDROP)wParam;
 			int fileCount = DragQueryFile(hDrop, -1, NULL, 0), totalCount = 0, i;
@@ -913,53 +948,53 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 				DragQueryFile(hDrop, i, szFilename, _countof(szFilename));
 				AddToFileList(&ppFiles, &totalCount, szFilename);
 			}
-			CallServiceSync(MS_FILE_SENDSPECIFICFILEST, dat->hContact, (LPARAM)ppFiles);
+			CallServiceSync(MS_FILE_SENDSPECIFICFILEST, m_hContact, (LPARAM)ppFiles);
 			for (i = 0; ppFiles[i]; i++) mir_free(ppFiles[i]);
 			mir_free(ppFiles);
 		}
 		break;
 
 	case DM_AVATARCHANGED:
-		ShowAvatar(hwndDlg, dat);
+		ShowAvatar();
 		break;
 
 	case DM_GETAVATAR:
 		{
 			PROTO_AVATAR_INFORMATION ai = { 0 };
-			ai.hContact = dat->hContact;
-			CallProtoService(dat->szProto, PS_GETAVATARINFO, GAIF_FORCE, (LPARAM)&ai);
-			ShowAvatar(hwndDlg, dat);
+			ai.hContact = m_hContact;
+			CallProtoService(szProto, PS_GETAVATARINFO, GAIF_FORCE, (LPARAM)&ai);
+			ShowAvatar();
 		}
 		break;
 
 	case DM_TYPING:
-		dat->nTypeSecs = (int)lParam > 0 ? (int)lParam : 0;
+		nTypeSecs = (int)lParam > 0 ? (int)lParam : 0;
 		break;
 
 	case DM_CHANGEICONS:
-		SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
-		SetStatusIcon(dat);
+		SendMessage(m_hwnd, GC_UPDATESTATUSBAR, 0, 0);
+		SetStatusIcon();
 
 	case DM_UPDATEICON:
 		{
 			TitleBarData tbd = { 0 };
 			tbd.iFlags = TBDF_ICON;
-			GetTitlebarIcon(dat, &tbd);
-			SendMessage(dat->hwndParent, CM_UPDATETITLEBAR, (WPARAM)&tbd, (LPARAM)hwndDlg);
+			GetTitlebarIcon(&tbd);
+			SendMessage(m_hwndParent, CM_UPDATETITLEBAR, (WPARAM)&tbd, (LPARAM)m_hwnd);
 			TabControlData tcd;
 			tcd.iFlags = TCDF_ICON;
-			tcd.hIcon = GetTabIcon(dat);
-			SendMessage(dat->hwndParent, CM_UPDATETABCONTROL, (WPARAM)&tcd, (LPARAM)hwndDlg);
-			SendDlgItemMessage(hwndDlg, IDC_USERMENU, BM_SETIMAGE, IMAGE_ICON, (LPARAM)dat->statusIcon);
+			tcd.hIcon = GetTabIcon();
+			SendMessage(m_hwndParent, CM_UPDATETABCONTROL, (WPARAM)&tcd, (LPARAM)m_hwnd);
+			SendDlgItemMessage(m_hwnd, IDC_USERMENU, BM_SETIMAGE, IMAGE_ICON, (LPARAM)statusIcon);
 		}
 		break;
 
 	case DM_UPDATETABCONTROL: {
 		TabControlData tcd;
 		tcd.iFlags = TCDF_TEXT | TCDF_ICON;
-		tcd.hIcon = GetTabIcon(dat);
-		tcd.pszText = pcli->pfnGetContactDisplayName(dat->hContact, 0);
-		SendMessage(dat->hwndParent, CM_UPDATETABCONTROL, (WPARAM)&tcd, (LPARAM)hwndDlg);
+		tcd.hIcon = GetTabIcon();
+		tcd.pszText = pcli->pfnGetContactDisplayName(m_hContact, 0);
+		SendMessage(m_hwndParent, CM_UPDATETABCONTROL, (WPARAM)&tcd, (LPARAM)m_hwnd);
 		break;
 	}
 
@@ -967,30 +1002,30 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 		{
 			TitleBarData tbd = { 0 };
 			tbd.iFlags = TBDF_TEXT | TBDF_ICON;
-			GetTitlebarIcon(dat, &tbd);
-			tbd.pszText = GetWindowTitle(dat->hContact, dat->szProto);
-			SendMessage(dat->hwndParent, CM_UPDATETITLEBAR, (WPARAM)&tbd, (LPARAM)hwndDlg);
+			GetTitlebarIcon(&tbd);
+			tbd.pszText = GetWindowTitle(m_hContact, szProto);
+			SendMessage(m_hwndParent, CM_UPDATETITLEBAR, (WPARAM)&tbd, (LPARAM)m_hwnd);
 			mir_free(tbd.pszText);
 		}
 		break;
 
 	case DM_CLISTSETTINGSCHANGED:
-		if (wParam == dat->hContact) {
-			if (dat->hContact && dat->szProto) {
+		if (wParam == m_hContact) {
+			if (m_hContact && szProto) {
 				DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *)lParam;
 				char idbuf[128], buf[128];
-				GetContactUniqueId(dat, idbuf, sizeof(idbuf));
+				GetContactUniqueId(this, idbuf, sizeof(idbuf));
 				mir_snprintf(buf, Translate("User menu - %s"), idbuf);
-				SendDlgItemMessage(hwndDlg, IDC_USERMENU, BUTTONADDTOOLTIP, (WPARAM)buf, 0);
+				SendDlgItemMessage(m_hwnd, IDC_USERMENU, BUTTONADDTOOLTIP, (WPARAM)buf, 0);
 
-				if (cws && !mir_strcmp(cws->szModule, dat->szProto) && !mir_strcmp(cws->szSetting, "Status"))
-					dat->wStatus = cws->value.wVal;
+				if (cws && !mir_strcmp(cws->szModule, szProto) && !mir_strcmp(cws->szSetting, "Status"))
+					wStatus = cws->value.wVal;
 
-				SetStatusIcon(dat);
-				SendMessage(hwndDlg, DM_UPDATEICON, 0, 0);
-				SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0);
-				SendMessage(hwndDlg, DM_UPDATETABCONTROL, 0, 0);
-				ShowAvatar(hwndDlg, dat);
+				SetStatusIcon();
+				SendMessage(m_hwnd, DM_UPDATEICON, 0, 0);
+				SendMessage(m_hwnd, DM_UPDATETITLEBAR, 0, 0);
+				SendMessage(m_hwnd, DM_UPDATETABCONTROL, 0, 0);
+				ShowAvatar();
 			}
 		}
 		break;
@@ -1000,38 +1035,38 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 		memset(&cf2, 0, sizeof(cf2));
 		LOGFONT lf;
 		COLORREF colour;
-		dat->flags &= ~SMF_USEIEVIEW;
-		dat->flags |= g_dat.ieviewInstalled ? g_dat.flags & SMF_USEIEVIEW : 0;
-		if (dat->flags & SMF_USEIEVIEW && dat->hwndLog == NULL) {
+		flags &= ~SMF_USEIEVIEW;
+		flags |= g_dat.ieviewInstalled ? g_dat.flags & SMF_USEIEVIEW : 0;
+		if (flags & SMF_USEIEVIEW && hwndIeview == NULL) {
 			IEVIEWWINDOW ieWindow = { sizeof(ieWindow) };
 			ieWindow.iType = IEW_CREATE;
 			ieWindow.dwMode = IEWM_SCRIVER;
-			ieWindow.parent = hwndDlg;
+			ieWindow.parent = m_hwnd;
 			ieWindow.cx = 200;
 			ieWindow.cy = 300;
 			CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
-			dat->hwndLog = ieWindow.hwnd;
-			if (dat->hwndLog == NULL)
-				dat->flags ^= SMF_USEIEVIEW;
+			hwndIeview = ieWindow.hwnd;
+			if (hwndIeview == NULL)
+				flags ^= SMF_USEIEVIEW;
 		}
-		else if (!(dat->flags & SMF_USEIEVIEW) && dat->hwndLog != NULL) {
-			if (dat->hwndLog != NULL) {
+		else if (!(flags & SMF_USEIEVIEW) && hwndIeview != NULL) {
+			if (hwndIeview != NULL) {
 				IEVIEWWINDOW ieWindow = { sizeof(ieWindow) };
 				ieWindow.iType = IEW_DESTROY;
-				ieWindow.hwnd = dat->hwndLog;
+				ieWindow.hwnd = hwndIeview;
 				CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
 			}
-			dat->hwndLog = NULL;
+			hwndIeview = NULL;
 		}
 
-		SendMessage(hwndDlg, DM_GETAVATAR, 0, 0);
-		SetDialogToType(hwndDlg);
+		SendMessage(m_hwnd, DM_GETAVATAR, 0, 0);
+		SetDialogToType();
 
 		colour = db_get_dw(NULL, SRMMMOD, SRMSGSET_BKGCOLOUR, SRMSGDEFSET_BKGCOLOUR);
-		SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETBKGNDCOLOR, 0, colour);
+		SendDlgItemMessage(m_hwnd, IDC_LOG, EM_SETBKGNDCOLOR, 0, colour);
 		colour = db_get_dw(NULL, SRMMMOD, SRMSGSET_INPUTBKGCOLOUR, SRMSGDEFSET_INPUTBKGCOLOUR);
-		SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETBKGNDCOLOR, 0, colour);
-		InvalidateRect(GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, FALSE);
+		SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_SETBKGNDCOLOR, 0, colour);
+		InvalidateRect(GetDlgItem(m_hwnd, IDC_MESSAGE), NULL, FALSE);
 		LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, &lf, &colour);
 		cf2.cbSize = sizeof(cf2);
 		cf2.dwMask = CFM_COLOR | CFM_FACE | CFM_CHARSET | CFM_SIZE | CFM_WEIGHT | CFM_BOLD | CFM_ITALIC;
@@ -1042,29 +1077,29 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 		cf2.wWeight = (WORD)lf.lfWeight;
 		cf2.bPitchAndFamily = lf.lfPitchAndFamily;
 		cf2.yHeight = abs(lf.lfHeight) * 1440 / g_dat.logPixelSY;
-		SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
-		SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETLANGOPTIONS, 0, (LPARAM)SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
+		SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
+		SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_SETLANGOPTIONS, 0, (LPARAM)SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_GETLANGOPTIONS, 0, 0) & ~IMF_AUTOKEYBOARD);
 
 		pf2.cbSize = sizeof(pf2);
 		pf2.dwMask = PFM_OFFSET;
 		pf2.dxOffset = (g_dat.flags & SMF_INDENTTEXT) ? g_dat.indentSize * 1440 / g_dat.logPixelSX : 0;
-		SetDlgItemText(hwndDlg, IDC_LOG, L"");
-		SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
-		SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETLANGOPTIONS, 0, (LPARAM)SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~(IMF_AUTOKEYBOARD | IMF_AUTOFONTSIZEADJUST));
-
-		SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
-		SendMessage(hwndDlg, DM_UPDATETITLEBAR, 0, 0);
-		SendMessage(hwndDlg, DM_UPDATETABCONTROL, 0, 0);
-		SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
-		SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_REQUESTRESIZE, 0, 0);
-		SetupInfobar(dat->infobarData);
+		SetDlgItemText(m_hwnd, IDC_LOG, L"");
+		SendDlgItemMessage(m_hwnd, IDC_LOG, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+		SendDlgItemMessage(m_hwnd, IDC_LOG, EM_SETLANGOPTIONS, 0, (LPARAM)SendDlgItemMessage(m_hwnd, IDC_LOG, EM_GETLANGOPTIONS, 0, 0) & ~(IMF_AUTOKEYBOARD | IMF_AUTOFONTSIZEADJUST));
+
+		SendMessage(m_hwnd, DM_REMAKELOG, 0, 0);
+		SendMessage(m_hwnd, DM_UPDATETITLEBAR, 0, 0);
+		SendMessage(m_hwnd, DM_UPDATETABCONTROL, 0, 0);
+		SendMessage(m_hwnd, GC_UPDATESTATUSBAR, 0, 0);
+		SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_REQUESTRESIZE, 0, 0);
+		SetupInfobar(infobarData);
 		break;
 
 	case DM_USERNAMETOCLIP:
-		if (dat->hContact) {
+		if (m_hContact) {
 			char buf[128];
-			GetContactUniqueId(dat, buf, sizeof(buf));
-			if (!OpenClipboard(hwndDlg) || !mir_strlen(buf))
+			GetContactUniqueId(this, buf, sizeof(buf));
+			if (!OpenClipboard(m_hwnd) || !mir_strlen(buf))
 				break;
 
 			EmptyClipboard();
@@ -1078,20 +1113,20 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 
 	case DM_SWITCHINFOBAR:
 	case DM_SWITCHTOOLBAR:
-		SetDialogToType(hwndDlg);
+		SetDialogToType();
 		break;
 
 	case DM_SWITCHTYPING:
-		if (IsTypingNotificationSupported(dat)) {
+		if (IsTypingNotificationSupported()) {
 			StatusIconData sid = { sizeof(sid) };
 			sid.szModule = SRMMMOD;
 			sid.dwId = 1;
 
-			BYTE typingNotify = (db_get_b(dat->hContact, SRMMMOD, SRMSGSET_TYPING,
+			BYTE typingNotify = (db_get_b(m_hContact, SRMMMOD, SRMSGSET_TYPING,
 				db_get_b(NULL, SRMMMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW)));
-			db_set_b(dat->hContact, SRMMMOD, SRMSGSET_TYPING, (BYTE)!typingNotify);
+			db_set_b(m_hContact, SRMMMOD, SRMSGSET_TYPING, (BYTE)!typingNotify);
 			sid.flags = typingNotify ? MBF_DISABLED : 0;
-			Srmm_ModifyIcon(dat->hContact, &sid);
+			Srmm_ModifyIcon(m_hContact, &sid);
 		}
 		break;
 
@@ -1099,31 +1134,31 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 		memset(&pf2, 0, sizeof(pf2));
 		pf2.cbSize = sizeof(pf2);
 		pf2.dwMask = PFM_RTLPARA;
-		dat->flags ^= SMF_RTL;
-		if (dat->flags & SMF_RTL) {
+		flags ^= SMF_RTL;
+		if (flags & SMF_RTL) {
 			pf2.wEffects = PFE_RTLPARA;
-			SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR);
-			SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_EXSTYLE) | WS_EX_LEFTSCROLLBAR);
+			SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_MESSAGE), GWL_EXSTYLE) | WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR);
+			SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LOG), GWL_EXSTYLE) | WS_EX_LEFTSCROLLBAR);
 		}
 		else {
 			pf2.wEffects = 0;
-			SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_MESSAGE), GWL_EXSTYLE) &~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR));
-			SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_EXSTYLE) &~(WS_EX_LEFTSCROLLBAR));
+			SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_MESSAGE), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_MESSAGE), GWL_EXSTYLE) &~(WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR));
+			SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LOG), GWL_EXSTYLE, GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LOG), GWL_EXSTYLE) &~(WS_EX_LEFTSCROLLBAR));
 		}
-		SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
-		SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+		SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_SETPARAFORMAT, 0, (LPARAM)&pf2);
+		SendMessage(m_hwnd, DM_REMAKELOG, 0, 0);
 		break;
 
 	case DM_GETWINDOWSTATE:
 		{
 			UINT state = MSG_WINDOW_STATE_EXISTS;
-			if (IsWindowVisible(hwndDlg))
+			if (IsWindowVisible(m_hwnd))
 				state |= MSG_WINDOW_STATE_VISIBLE;
-			if (GetForegroundWindow() == dat->hwndParent)
+			if (GetForegroundWindow() == m_hwndParent)
 				state |= MSG_WINDOW_STATE_FOCUS;
-			if (IsIconic(dat->hwndParent))
+			if (IsIconic(m_hwndParent))
 				state |= MSG_WINDOW_STATE_ICONIC;
-			SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, state);
+			SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, state);
 		}
 		return TRUE;
 
@@ -1134,26 +1169,26 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 
 		//fall through
 	case WM_MOUSEACTIVATE:
-		if (dat->hDbUnreadEventFirst != NULL) {
-			MEVENT hDbEvent = dat->hDbUnreadEventFirst;
-			dat->hDbUnreadEventFirst = NULL;
+		if (hDbUnreadEventFirst != NULL) {
+			MEVENT hDbEvent = hDbUnreadEventFirst;
+			hDbUnreadEventFirst = NULL;
 			while (hDbEvent != NULL) {
 				DBEVENTINFO dbei = {};
 				db_event_get(hDbEvent, &dbei);
 				if (!(dbei.flags & DBEF_SENT) && (DbEventIsMessageOrCustom(&dbei) || dbei.eventType == EVENTTYPE_URL))
-					pcli->pfnRemoveEvent(dat->hContact, hDbEvent);
-				hDbEvent = db_event_next(dat->hContact, hDbEvent);
+					pcli->pfnRemoveEvent(m_hContact, hDbEvent);
+				hDbEvent = db_event_next(m_hContact, hDbEvent);
 			}
 		}
-		if (dat->showUnread) {
-			dat->showUnread = 0;
-			KillTimer(hwndDlg, TIMERID_UNREAD);
-			SendMessage(hwndDlg, DM_UPDATEICON, 0, 0);
+		if (showUnread) {
+			showUnread = 0;
+			KillTimer(m_hwnd, TIMERID_UNREAD);
+			SendMessage(m_hwnd, DM_UPDATEICON, 0, 0);
 		}
 		break;
 
 	case WM_LBUTTONDOWN:
-		SendMessage(dat->hwndParent, WM_LBUTTONDOWN, wParam, lParam);
+		SendMessage(m_hwndParent, WM_LBUTTONDOWN, wParam, lParam);
 		return TRUE;
 
 	case DM_SETFOCUS:
@@ -1161,227 +1196,226 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 			HWND hLog;
 			POINT pt;
 			GetCursorPos(&pt);
-			if (dat->hwndLog != NULL)
-				hLog = dat->hwndLog;
+			if (hwndIeview != NULL)
+				hLog = hwndIeview;
 			else
-				hLog = GetDlgItem(hwndDlg, IDC_LOG);
+				hLog = m_log.GetHwnd();
 
 			RECT rc;
 			GetWindowRect(hLog, &rc);
 			if (pt.x >= rc.left && pt.x <= rc.right && pt.y >= rc.top && pt.y <= rc.bottom)
 				return TRUE;
 		}
-		if (g_dat.hFocusWnd == hwndDlg)
-			SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+		if (g_dat.hFocusWnd == m_hwnd)
+			SetFocus(m_message.GetHwnd());
 		return TRUE;
 
 	case WM_SETFOCUS:
-		SendMessage(dat->hwndParent, CM_ACTIVATECHILD, 0, (LPARAM)hwndDlg);
-		g_dat.hFocusWnd = hwndDlg;
-		PostMessage(hwndDlg, DM_SETFOCUS, 0, 0);
+		SendMessage(m_hwndParent, CM_ACTIVATECHILD, 0, (LPARAM)m_hwnd);
+		g_dat.hFocusWnd = m_hwnd;
+		PostMessage(m_hwnd, DM_SETFOCUS, 0, 0);
 		return TRUE;
 
 	case DM_SETPARENT:
-		dat->hwndParent = (HWND)lParam;
-		dat->parent = (ParentWindowData *)GetWindowLongPtr(dat->hwndParent, GWLP_USERDATA);
-		SetParent(hwndDlg, dat->hwndParent);
+		SetParent((HWND)lParam);
+		parent = (ParentWindowData *)GetWindowLongPtr(m_hwndParent, GWLP_USERDATA);
 		return TRUE;
 
 	case WM_GETMINMAXINFO:
 		{
 			MINMAXINFO *mmi = (MINMAXINFO *)lParam;
-			mmi->ptMinTrackSize.x = dat->toolbarSize.cx + BOTTOM_RIGHT_AVATAR_HEIGHT;
-			mmi->ptMinTrackSize.y = dat->minLogBoxHeight + dat->toolbarSize.cy + dat->minEditBoxHeight + max(INFO_BAR_HEIGHT, BOTTOM_RIGHT_AVATAR_HEIGHT - dat->toolbarSize.cy) + 5;
+			mmi->ptMinTrackSize.x = toolbarSize.cx + BOTTOM_RIGHT_AVATAR_HEIGHT;
+			mmi->ptMinTrackSize.y = minLogBoxHeight + toolbarSize.cy + minEditBoxHeight + max(INFO_BAR_HEIGHT, BOTTOM_RIGHT_AVATAR_HEIGHT - toolbarSize.cy) + 5;
 		}
 		return 0;
 
 	case WM_SIZE:
 		if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) {
 			RECT rc;
-			GetClientRect(hwndDlg, &rc);
-			MessageDialogResize(hwndDlg, dat, rc.right - rc.left, rc.bottom - rc.top);
+			GetClientRect(m_hwnd, &rc);
+			MessageDialogResize(rc.right - rc.left, rc.bottom - rc.top);
 		}
 		return TRUE;
 
 	case DM_SPLITTERMOVED:
-		if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_SPLITTERY)) {
+		if ((HWND)lParam == GetDlgItem(m_hwnd, IDC_SPLITTERY)) {
 			RECT rc, rcLog;
-			GetWindowRect(GetDlgItem(hwndDlg, IDC_LOG), &rcLog);
-			GetClientRect(hwndDlg, &rc);
+			GetWindowRect(GetDlgItem(m_hwnd, IDC_LOG), &rcLog);
+			GetClientRect(m_hwnd, &rc);
 
 			POINT pt = { 0, (int)wParam };
-			ScreenToClient(hwndDlg, &pt);
-			dat->splitterPos = rc.bottom - pt.y;
-			SendMessage(hwndDlg, WM_SIZE, 0, 0);
+			ScreenToClient(m_hwnd, &pt);
+			splitterPos = rc.bottom - pt.y;
+			SendMessage(m_hwnd, WM_SIZE, 0, 0);
 		}
 		break;
 
 	case DM_REMAKELOG:
-		dat->lastEventType = -1;
-		if (wParam == 0 || wParam == dat->hContact)
-			StreamInEvents(hwndDlg, dat->hDbEventFirst, -1, 0);
+		lastEventType = -1;
+		if (wParam == 0 || wParam == m_hContact)
+			StreamInEvents(hDbEventFirst, -1, 0);
 
-		InvalidateRect(GetDlgItem(hwndDlg, IDC_LOG), NULL, FALSE);
+		InvalidateRect(GetDlgItem(m_hwnd, IDC_LOG), NULL, FALSE);
 		break;
 
 	case DM_APPENDTOLOG:   //takes wParam=hDbEvent
-		StreamInEvents(hwndDlg, wParam, 1, 1);
+		StreamInEvents(wParam, 1, 1);
 		break;
 
 	case DM_SCROLLLOGTOBOTTOM:
-		if (dat->hwndLog == NULL) {
-			if ((GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LOG), GWL_STYLE) & WS_VSCROLL) == 0)
+		if (hwndIeview == NULL) {
+			if ((GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_LOG), GWL_STYLE) & WS_VSCROLL) == 0)
 				break;
 
 			SCROLLINFO si = { sizeof(si) };
 			si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
-			if (GetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &si)) {
-				if (GetDlgItem(hwndDlg, IDC_LOG) != GetFocus()) {
+			if (GetScrollInfo(GetDlgItem(m_hwnd, IDC_LOG), SB_VERT, &si)) {
+				if (GetDlgItem(m_hwnd, IDC_LOG) != GetFocus()) {
 					si.fMask = SIF_POS;
 					si.nPos = si.nMax - si.nPage + 1;
-					SetScrollInfo(GetDlgItem(hwndDlg, IDC_LOG), SB_VERT, &si, TRUE);
-					PostMessage(GetDlgItem(hwndDlg, IDC_LOG), WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0);
+					SetScrollInfo(GetDlgItem(m_hwnd, IDC_LOG), SB_VERT, &si, TRUE);
+					PostMessage(GetDlgItem(m_hwnd, IDC_LOG), WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), 0);
 				}
 			}
-			RedrawWindow(GetDlgItem(hwndDlg, IDC_LOG), NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
+			RedrawWindow(GetDlgItem(m_hwnd, IDC_LOG), NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
 		}
 		else {
 			IEVIEWWINDOW ieWindow;
 			ieWindow.cbSize = sizeof(IEVIEWWINDOW);
 			ieWindow.iType = IEW_SCROLLBOTTOM;
-			ieWindow.hwnd = dat->hwndLog;
+			ieWindow.hwnd = hwndIeview;
 			CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
 		}
 		break;
 
 	case HM_DBEVENTADDED:
-		if (wParam == dat->hContact) {
+		if (wParam == m_hContact) {
 			MEVENT hDbEvent = lParam;
 			DBEVENTINFO dbei = {};
 			db_event_get(hDbEvent, &dbei);
-			if (dat->hDbEventFirst == NULL)
-				dat->hDbEventFirst = hDbEvent;
+			if (hDbEventFirst == NULL)
+				hDbEventFirst = hDbEvent;
 			if (DbEventIsShown(dbei)) {
 				if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & (DBEF_SENT))) {
 					/* store the event when the container is hidden so that clist notifications can be removed */
-					if (!IsWindowVisible(GetParent(hwndDlg)) && dat->hDbUnreadEventFirst == NULL)
-						dat->hDbUnreadEventFirst = hDbEvent;
-					dat->lastMessage = dbei.timestamp;
-					SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
-					if (GetForegroundWindow() == dat->hwndParent && dat->parent->hwndActive == hwndDlg)
+					if (!IsWindowVisible(GetParent(m_hwnd)) && hDbUnreadEventFirst == NULL)
+						hDbUnreadEventFirst = hDbEvent;
+					lastMessage = dbei.timestamp;
+					SendMessage(m_hwnd, GC_UPDATESTATUSBAR, 0, 0);
+					if (GetForegroundWindow() == m_hwndParent && parent->hwndActive == m_hwnd)
 						SkinPlaySound("RecvMsgActive");
 					else SkinPlaySound("RecvMsgInactive");
-					if ((g_dat.flags2 & SMF2_SWITCHTOACTIVE) && (IsIconic(dat->hwndParent) || GetActiveWindow() != dat->hwndParent) && IsWindowVisible(dat->hwndParent))
-						SendMessage(dat->hwndParent, CM_ACTIVATECHILD, 0, (LPARAM)hwndDlg);
-					if (IsAutoPopup(dat->hContact))
-						SendMessage(GetParent(hwndDlg), CM_POPUPWINDOW, 1, (LPARAM)hwndDlg);
+					if ((g_dat.flags2 & SMF2_SWITCHTOACTIVE) && (IsIconic(m_hwndParent) || GetActiveWindow() != m_hwndParent) && IsWindowVisible(m_hwndParent))
+						SendMessage(m_hwndParent, CM_ACTIVATECHILD, 0, (LPARAM)m_hwnd);
+					if (IsAutoPopup(m_hContact))
+						SendMessage(GetParent(m_hwnd), CM_POPUPWINDOW, 1, (LPARAM)m_hwnd);
 				}
-				if (hDbEvent != dat->hDbEventFirst && db_event_next(dat->hContact, hDbEvent) == NULL)
-					SendMessage(hwndDlg, DM_APPENDTOLOG, WPARAM(hDbEvent), 0);
+				if (hDbEvent != hDbEventFirst && db_event_next(m_hContact, hDbEvent) == NULL)
+					SendMessage(m_hwnd, DM_APPENDTOLOG, WPARAM(hDbEvent), 0);
 				else
-					SendMessage(hwndDlg, DM_REMAKELOG, 0, 0);
+					SendMessage(m_hwnd, DM_REMAKELOG, 0, 0);
 				if (!(dbei.flags & DBEF_SENT) && !DbEventIsCustomForMsgWindow(&dbei)) {
-					if (GetActiveWindow() != dat->hwndParent || GetForegroundWindow() != dat->hwndParent || dat->parent->hwndActive != hwndDlg) {
-						dat->showUnread = 1;
-						SendMessage(hwndDlg, DM_UPDATEICON, 0, 0);
-						SetTimer(hwndDlg, TIMERID_UNREAD, TIMEOUT_UNREAD, NULL);
+					if (GetActiveWindow() != m_hwndParent || GetForegroundWindow() != m_hwndParent || parent->hwndActive != m_hwnd) {
+						showUnread = 1;
+						SendMessage(m_hwnd, DM_UPDATEICON, 0, 0);
+						SetTimer(m_hwnd, TIMERID_UNREAD, TIMEOUT_UNREAD, NULL);
 					}
-					SendMessage(dat->hwndParent, CM_STARTFLASHING, 0, 0);
+					SendMessage(m_hwndParent, CM_STARTFLASHING, 0, 0);
 				}
 			}
 		}
 		break;
 
 	case GC_UPDATESTATUSBAR:
-		if (dat->parent->hwndActive == hwndDlg) {
+		if (parent->hwndActive == m_hwnd) {
 			wchar_t szText[256];
 			StatusBarData sbd = { 0 };
 			sbd.iFlags = SBDF_TEXT | SBDF_ICON;
-			if (dat->messagesInProgress && (g_dat.flags & SMF_SHOWPROGRESS)) {
+			if (messagesInProgress && (g_dat.flags & SMF_SHOWPROGRESS)) {
 				sbd.hIcon = GetCachedIcon("scriver_DELIVERING");
 				sbd.pszText = szText;
-				mir_snwprintf(szText, TranslateT("Sending in progress: %d message(s) left..."), dat->messagesInProgress);
+				mir_snwprintf(szText, TranslateT("Sending in progress: %d message(s) left..."), messagesInProgress);
 			}
-			else if (dat->nTypeSecs) {
+			else if (nTypeSecs) {
 				sbd.hIcon = GetCachedIcon("scriver_TYPING");
 				sbd.pszText = szText;
-				mir_snwprintf(szText, TranslateT("%s is typing a message..."), pcli->pfnGetContactDisplayName(dat->hContact, 0));
-				dat->nTypeSecs--;
+				mir_snwprintf(szText, TranslateT("%s is typing a message..."), pcli->pfnGetContactDisplayName(m_hContact, 0));
+				nTypeSecs--;
 			}
-			else if (dat->lastMessage) {
+			else if (lastMessage) {
 				wchar_t date[64], time[64];
-				TimeZone_PrintTimeStamp(NULL, dat->lastMessage, L"d", date, _countof(date), 0);
-				TimeZone_PrintTimeStamp(NULL, dat->lastMessage, L"t", time, _countof(time), 0);
+				TimeZone_PrintTimeStamp(NULL, lastMessage, L"d", date, _countof(date), 0);
+				TimeZone_PrintTimeStamp(NULL, lastMessage, L"t", time, _countof(time), 0);
 				mir_snwprintf(szText, TranslateT("Last message received on %s at %s."), date, time);
 				sbd.pszText = szText;
 			}
 			else sbd.pszText = L"";
 
-			SendMessage(dat->hwndParent, CM_UPDATESTATUSBAR, (WPARAM)&sbd, (LPARAM)hwndDlg);
-			UpdateReadChars(hwndDlg, dat);
+			SendMessage(m_hwndParent, CM_UPDATESTATUSBAR, (WPARAM)&sbd, (LPARAM)m_hwnd);
+			UpdateReadChars();
 
 			StatusIconData sid = { sizeof(sid) };
 			sid.szModule = SRMMMOD;
 			sid.flags = MBF_DISABLED;
-			Srmm_ModifyIcon(dat->hContact, &sid);
+			Srmm_ModifyIcon(m_hContact, &sid);
 			sid.dwId = 1;
-			if (IsTypingNotificationSupported(dat) && g_dat.flags2 & SMF2_SHOWTYPINGSWITCH)
-				sid.flags = (db_get_b(dat->hContact, SRMMMOD, SRMSGSET_TYPING,
+			if (IsTypingNotificationSupported() && g_dat.flags2 & SMF2_SHOWTYPINGSWITCH)
+				sid.flags = (db_get_b(m_hContact, SRMMMOD, SRMSGSET_TYPING,
 				db_get_b(NULL, SRMMMOD, SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW))) ? 0 : MBF_DISABLED;
 			else
 				sid.flags = MBF_HIDDEN;
 
-			Srmm_ModifyIcon(dat->hContact, &sid);
+			Srmm_ModifyIcon(m_hContact, &sid);
 		}
 		break;
 
 	case DM_CLEARLOG:
-		if (dat->hwndLog != NULL) {
+		if (hwndIeview != NULL) {
 			IEVIEWEVENT evt = { sizeof(evt) };
 			evt.iType = IEE_CLEAR_LOG;
-			evt.dwFlags = ((dat->flags & SMF_RTL) ? IEEF_RTL : 0);
-			evt.hwnd = dat->hwndLog;
-			evt.hContact = dat->hContact;
-			evt.pszProto = dat->szProto;
+			evt.dwFlags = ((flags & SMF_RTL) ? IEEF_RTL : 0);
+			evt.hwnd = hwndIeview;
+			evt.hContact = m_hContact;
+			evt.pszProto = szProto;
 			CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&evt);
 		}
 
-		SetDlgItemText(hwndDlg, IDC_LOG, L"");
-		dat->hDbEventFirst = NULL;
-		dat->lastEventType = -1;
+		SetDlgItemText(m_hwnd, IDC_LOG, L"");
+		hDbEventFirst = NULL;
+		lastEventType = -1;
 		break;
 
 	case WM_TIMER:
 		if (wParam == TIMERID_MSGSEND)
-			ReportSendQueueTimeouts(hwndDlg);
+			ReportSendQueueTimeouts(m_hwnd);
 		else if (wParam == TIMERID_TYPE) {
-			if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - dat->nLastTyping > TIMEOUT_TYPEOFF)
-				NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+			if (nTypeMode == PROTOTYPE_SELFTYPING_ON && GetTickCount() - nLastTyping > TIMEOUT_TYPEOFF)
+				NotifyTyping(PROTOTYPE_SELFTYPING_OFF);
 
-			if (dat->showTyping) {
-				if (dat->nTypeSecs)
-					dat->nTypeSecs--;
+			if (showTyping) {
+				if (nTypeSecs)
+					nTypeSecs--;
 				else {
-					dat->showTyping = 0;
-					SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
-					SendMessage(hwndDlg, DM_UPDATEICON, 0, 0);
+					showTyping = 0;
+					SendMessage(m_hwnd, GC_UPDATESTATUSBAR, 0, 0);
+					SendMessage(m_hwnd, DM_UPDATEICON, 0, 0);
 				}
 			}
 			else {
-				if (dat->nTypeSecs) {
-					dat->showTyping = 1;
-					SendMessage(hwndDlg, GC_UPDATESTATUSBAR, 0, 0);
-					SendMessage(hwndDlg, DM_UPDATEICON, 0, 0);
+				if (nTypeSecs) {
+					showTyping = 1;
+					SendMessage(m_hwnd, GC_UPDATESTATUSBAR, 0, 0);
+					SendMessage(m_hwnd, DM_UPDATEICON, 0, 0);
 				}
 			}
 		}
 		else if (wParam == TIMERID_UNREAD) {
 			TabControlData tcd;
 			tcd.iFlags = TCDF_ICON;
-			if (!dat->showTyping) {
-				dat->showUnread++;
-				tcd.hIcon = (dat->showUnread & 1) ? dat->statusIconOverlay : dat->statusIcon;
-				SendMessage(dat->hwndParent, CM_UPDATETABCONTROL, (WPARAM)&tcd, (LPARAM)hwndDlg);
+			if (!showTyping) {
+				showUnread++;
+				tcd.hIcon = (showUnread & 1) ? statusIconOverlay : statusIcon;
+				SendMessage(m_hwndParent, CM_UPDATETABCONTROL, (WPARAM)&tcd, (LPARAM)m_hwnd);
 			}
 		}
 		break;
@@ -1389,11 +1423,11 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 	case DM_SENDMESSAGE:
 		if (lParam) {
 			MessageSendQueueItem *msi = (MessageSendQueueItem *)lParam;
-			SendMessage(hwndDlg, DM_STARTMESSAGESENDING, 0, 0);
+			SendMessage(m_hwnd, DM_STARTMESSAGESENDING, 0, 0);
 
-			MessageSendQueueItem *item = CreateSendQueueItem(hwndDlg);
-			item->hContact = dat->hContact;
-			item->proto = mir_strdup(dat->szProto);
+			MessageSendQueueItem *item = CreateSendQueueItem(m_hwnd);
+			item->hContact = m_hContact;
+			item->proto = mir_strdup(szProto);
 			item->flags = msi->flags;
 			item->sendBufferSize = msi->sendBufferSize;
 			item->sendBuffer = mir_strndup(msi->sendBuffer, msi->sendBufferSize);
@@ -1402,28 +1436,28 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 		break;
 
 	case DM_STARTMESSAGESENDING:
-		dat->messagesInProgress++;
+		messagesInProgress++;
 	case DM_SHOWMESSAGESENDING:
-		SetTimer(hwndDlg, TIMERID_MSGSEND, 1000, NULL);
+		SetTimer(m_hwnd, TIMERID_MSGSEND, 1000, NULL);
 		if (g_dat.flags & SMF_SHOWPROGRESS)
-			SendMessage(dat->hwnd, GC_UPDATESTATUSBAR, 0, 0);
+			SendMessage(GetHwnd(), GC_UPDATESTATUSBAR, 0, 0);
 		break;
 
 	case DM_STOPMESSAGESENDING:
-		if (dat->messagesInProgress > 0) {
-			dat->messagesInProgress--;
+		if (messagesInProgress > 0) {
+			messagesInProgress--;
 			if (g_dat.flags & SMF_SHOWPROGRESS)
-				SendMessage(dat->hwnd, GC_UPDATESTATUSBAR, 0, 0);
+				SendMessage(GetHwnd(), GC_UPDATESTATUSBAR, 0, 0);
 		}
-		if (dat->messagesInProgress == 0)
-			KillTimer(hwndDlg, TIMERID_MSGSEND);
+		if (messagesInProgress == 0)
+			KillTimer(m_hwnd, TIMERID_MSGSEND);
 		break;
 
 	case DM_SHOWERRORMESSAGE:
 		if (lParam) {
 			ErrorWindowData *ewd = (ErrorWindowData *)lParam;
-			SendMessage(hwndDlg, DM_STOPMESSAGESENDING, 0, 0);
-			ewd->queueItem->hwndErrorDlg = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSGSENDERROR), hwndDlg, ErrorDlgProc, (LPARAM)ewd);//hwndDlg
+			SendMessage(m_hwnd, DM_STOPMESSAGESENDING, 0, 0);
+			ewd->queueItem->hwndErrorDlg = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSGSENDERROR), m_hwnd, ErrorDlgProc, (LPARAM)ewd);//m_hwnd
 		}
 		break;
 
@@ -1434,10 +1468,10 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 			switch (wParam) {
 			case MSGERROR_CANCEL:
 				RemoveSendQueueItem(item);
-				SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+				SetFocus(GetDlgItem(m_hwnd, IDC_MESSAGE));
 				break;
 			case MSGERROR_RETRY:
-				SendMessage(hwndDlg, DM_STARTMESSAGESENDING, 0, 0);
+				SendMessage(m_hwnd, DM_STARTMESSAGESENDING, 0, 0);
 				SendSendQueueItem(item);
 				break;
 			}
@@ -1452,7 +1486,7 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 	case WM_DRAWITEM:
 		if (!DrawMenuItem(wParam, lParam)) {
 			LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam;
-			if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_AVATAR)) {
+			if (dis->hwndItem == GetDlgItem(m_hwnd, IDC_AVATAR)) {
 				int avatarWidth = 0, avatarHeight = 0;
 				int itemWidth = dis->rcItem.right - dis->rcItem.left + 1, itemHeight = dis->rcItem.bottom - dis->rcItem.top + 1;
 				HDC hdcMem = CreateCompatibleDC(dis->hDC);
@@ -1465,9 +1499,9 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 				rect.bottom = itemHeight - 1;
 				FillRect(hdcMem, &rect, GetSysColorBrush(COLOR_BTNFACE));
 
-				if (dat->avatarPic && (g_dat.flags&SMF_AVATAR)) {
+				if (avatarPic && (g_dat.flags&SMF_AVATAR)) {
 					BITMAP bminfo;
-					GetObject(dat->avatarPic, sizeof(bminfo), &bminfo);
+					GetObject(avatarPic, sizeof(bminfo), &bminfo);
 					if (bminfo.bmWidth != 0 && bminfo.bmHeight != 0) {
 						avatarHeight = itemHeight;
 						avatarWidth = bminfo.bmWidth * avatarHeight / bminfo.bmHeight;
@@ -1477,7 +1511,7 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 						}
 
 						AVATARDRAWREQUEST adr = { sizeof(adr) };
-						adr.hContact = dat->hContact;
+						adr.hContact = m_hContact;
 						adr.hTargetDC = hdcMem;
 						adr.rcDraw.left = (itemWidth - avatarWidth) / 2;
 						adr.rcDraw.top = (itemHeight - avatarHeight) / 2;
@@ -1497,40 +1531,40 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 		return Menu_MeasureItem(lParam);
 
 	case WM_COMMAND:
-		if (!lParam && Clist_MenuProcessCommand(LOWORD(wParam), MPCF_CONTACTMENU, dat->hContact))
+		if (!lParam && Clist_MenuProcessCommand(LOWORD(wParam), MPCF_CONTACTMENU, m_hContact))
 			break;
 
 		if (HIWORD(wParam) == BN_CLICKED)
 			if (LOWORD(wParam) >= MIN_CBUTTONID && LOWORD(wParam) <= MAX_CBUTTONID) {
-				Srmm_ClickToolbarIcon(dat->hContact, LOWORD(wParam), GetDlgItem(hwndDlg, LOWORD(wParam)), 0);
+				Srmm_ClickToolbarIcon(m_hContact, LOWORD(wParam), GetDlgItem(m_hwnd, LOWORD(wParam)), 0);
 				break;
 			}
 
 		switch (LOWORD(wParam)) {
 		case IDC_SENDALL:
 			int result;
-			if (dat->sendAllConfirm == 0) {
-				result = DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_CONFIRM_SENDALL), hwndDlg, ConfirmSendAllDlgProc, (LPARAM)hwndDlg);
+			if (sendAllConfirm == 0) {
+				result = DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_CONFIRM_SENDALL), m_hwnd, ConfirmSendAllDlgProc, (LPARAM)m_hwnd);
 				if (result & 0x10000)
-					dat->sendAllConfirm = result;
+					sendAllConfirm = result;
 			}
-			else result = dat->sendAllConfirm;
+			else result = sendAllConfirm;
 
 			if (LOWORD(result) != IDYES)
 				break;
 
 		case IDOK:
 			// this is a 'send' button
-			if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDOK)))
+			if (!IsWindowEnabled(GetDlgItem(m_hwnd, IDOK)))
 				break;
 
-			if (dat->hContact != NULL) {
+			if (m_hContact != NULL) {
 				memset(&pf2, 0, sizeof(pf2));
 				pf2.cbSize = sizeof(pf2);
 				pf2.dwMask = PFM_RTLPARA;
-				SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETPARAFORMAT, 0, (LPARAM)&pf2);
+				SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_GETPARAFORMAT, 0, (LPARAM)&pf2);
 
-				int bufSize = GetRichTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE), 1200, TRUE) + 2;
+				int bufSize = GetRichTextLength(GetDlgItem(m_hwnd, IDC_MESSAGE), 1200, TRUE) + 2;
 				ptrW ptszUnicode((wchar_t*)mir_alloc(bufSize * sizeof(wchar_t)));
 
 				MessageSendQueueItem msi = { 0 };
@@ -1541,7 +1575,7 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 				gt.flags = GT_USECRLF;
 				gt.cb = bufSize;
 				gt.codepage = 1200; // Unicode
-				SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_GETTEXTEX, (WPARAM)&gt, ptszUnicode);
+				SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_GETTEXTEX, (WPARAM)&gt, ptszUnicode);
 				if (RTL_Detect(ptszUnicode))
 					msi.flags |= PREF_RTL;
 
@@ -1551,119 +1585,119 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 					break;
 
 				/* Store messaging history */
-				TCmdList *cmdListNew = tcmdlist_last(dat->cmdList);
+				TCmdList *cmdListNew = tcmdlist_last(cmdList);
 				while (cmdListNew != NULL && cmdListNew->temporary) {
-					dat->cmdList = tcmdlist_remove(dat->cmdList, cmdListNew);
-					cmdListNew = tcmdlist_last(dat->cmdList);
+					cmdList = tcmdlist_remove(cmdList, cmdListNew);
+					cmdListNew = tcmdlist_last(cmdList);
 				}
 				if (msi.sendBuffer != NULL)
-					dat->cmdList = tcmdlist_append(dat->cmdList, rtrim(msi.sendBuffer), 20, FALSE);
+					cmdList = tcmdlist_append(cmdList, rtrim(msi.sendBuffer), 20, FALSE);
 
-				dat->cmdListCurrent = NULL;
+				cmdListCurrent = NULL;
 
-				if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON)
-					NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+				if (nTypeMode == PROTOTYPE_SELFTYPING_ON)
+					NotifyTyping(PROTOTYPE_SELFTYPING_OFF);
 
-				SetDlgItemText(hwndDlg, IDC_MESSAGE, L"");
-				EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
+				SetDlgItemText(m_hwnd, IDC_MESSAGE, L"");
+				EnableWindow(GetDlgItem(m_hwnd, IDOK), FALSE);
 				if (db_get_b(NULL, SRMMMOD, SRMSGSET_AUTOMIN, SRMSGDEFSET_AUTOMIN))
-					ShowWindow(dat->hwndParent, SW_MINIMIZE);
+					ShowWindow(m_hwndParent, SW_MINIMIZE);
 				if (LOWORD(wParam) == IDC_SENDALL)
-					SendMessage(dat->hwndParent, DM_SENDMESSAGE, 0, (LPARAM)&msi);
+					SendMessage(m_hwndParent, DM_SENDMESSAGE, 0, (LPARAM)&msi);
 				else
-					SendMessage(hwndDlg, DM_SENDMESSAGE, 0, (LPARAM)&msi);
+					SendMessage(m_hwnd, DM_SENDMESSAGE, 0, (LPARAM)&msi);
 			}
 			return TRUE;
 
 		case IDCANCEL:
-			DestroyWindow(hwndDlg);
+			DestroyWindow(m_hwnd);
 			return TRUE;
 
 		case IDC_USERMENU:
 			if (GetKeyState(VK_SHIFT) & 0x8000) // copy user name
-				SendMessage(hwndDlg, DM_USERNAMETOCLIP, 0, 0);
+				SendMessage(m_hwnd, DM_USERNAMETOCLIP, 0, 0);
 			else {
 				RECT rc;
-				HMENU hMenu = Menu_BuildContactMenu(dat->hContact);
-				GetWindowRect(GetDlgItem(hwndDlg, LOWORD(wParam)), &rc);
-				TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, hwndDlg, NULL);
+				HMENU hMenu = Menu_BuildContactMenu(m_hContact);
+				GetWindowRect(GetDlgItem(m_hwnd, LOWORD(wParam)), &rc);
+				TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, m_hwnd, NULL);
 				DestroyMenu(hMenu);
 			}
 			break;
 
 		case IDC_HISTORY:
-			CallService(MS_HISTORY_SHOWCONTACTHISTORY, dat->hContact, 0);
+			CallService(MS_HISTORY_SHOWCONTACTHISTORY, m_hContact, 0);
 			break;
 
 		case IDC_DETAILS:
-			CallService(MS_USERINFO_SHOWDIALOG, dat->hContact, 0);
+			CallService(MS_USERINFO_SHOWDIALOG, m_hContact, 0);
 			break;
 
 		case IDC_QUOTE:
-			if (dat->hDbEventLast != NULL) {
+			if (hDbEventLast != NULL) {
 				SETTEXTEX  st;
 				st.flags = ST_SELECTION;
 				st.codepage = 1200;
 
 				wchar_t *buffer = NULL;
-				if (dat->hwndLog != NULL)
-					buffer = GetIEViewSelection(dat);
+				if (hwndIeview != NULL)
+					buffer = GetIEViewSelection(this);
 				else
-					buffer = GetRichEditSelection(GetDlgItem(hwndDlg, IDC_LOG));
+					buffer = GetRichEditSelection(GetDlgItem(m_hwnd, IDC_LOG));
 
 				if (buffer != NULL) {
 					wchar_t *quotedBuffer = GetQuotedTextW(buffer);
-					SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)quotedBuffer);
+					SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)quotedBuffer);
 					mir_free(quotedBuffer);
 					mir_free(buffer);
 				}
 				else {
 					DBEVENTINFO dbei = {};
-					dbei.cbBlob = db_event_getBlobSize(dat->hDbEventLast);
+					dbei.cbBlob = db_event_getBlobSize(hDbEventLast);
 					if (dbei.cbBlob == 0xFFFFFFFF)
 						break;
 					dbei.pBlob = (PBYTE)mir_alloc(dbei.cbBlob);
-					db_event_get(dat->hDbEventLast, &dbei);
+					db_event_get(hDbEventLast, &dbei);
 					if (DbEventIsMessageOrCustom(&dbei)) {
 						buffer = DbEvent_GetTextW(&dbei, CP_ACP);
 						if (buffer != NULL) {
 							wchar_t *quotedBuffer = GetQuotedTextW(buffer);
-							SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)quotedBuffer);
+							SendDlgItemMessage(m_hwnd, IDC_MESSAGE, EM_SETTEXTEX, (WPARAM)&st, (LPARAM)quotedBuffer);
 							mir_free(quotedBuffer);
 							mir_free(buffer);
 						}
 					}
 					mir_free(dbei.pBlob);
 				}
-				SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
+				SetFocus(GetDlgItem(m_hwnd, IDC_MESSAGE));
 			}
 			break;
 
 		case IDC_ADD:
 			{
 				ADDCONTACTSTRUCT acs = { 0 };
-				acs.hContact = dat->hContact;
+				acs.hContact = m_hContact;
 				acs.handleType = HANDLE_CONTACT;
 				acs.szProto = 0;
-				CallService(MS_ADDCONTACT_SHOW, (WPARAM)hwndDlg, (LPARAM)&acs);
+				CallService(MS_ADDCONTACT_SHOW, (WPARAM)m_hwnd, (LPARAM)&acs);
 			}
-			if (!db_get_b(dat->hContact, "CList", "NotOnList", 0))
-				ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE);
+			if (!db_get_b(m_hContact, "CList", "NotOnList", 0))
+				ShowWindow(GetDlgItem(m_hwnd, IDC_ADD), SW_HIDE);
 
 		case IDC_MESSAGE:
 			if (HIWORD(wParam) == EN_CHANGE) {
-				int len = GetRichTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE), 1200, FALSE);
-				dat->cmdListCurrent = NULL;
-				UpdateReadChars(hwndDlg, dat);
-				EnableWindow(GetDlgItem(hwndDlg, IDOK), len != 0);
+				int len = GetRichTextLength(GetDlgItem(m_hwnd, IDC_MESSAGE), 1200, FALSE);
+				cmdListCurrent = NULL;
+				UpdateReadChars();
+				EnableWindow(GetDlgItem(m_hwnd, IDOK), len != 0);
 				if (!(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000)) {
-					dat->nLastTyping = GetTickCount();
+					nLastTyping = GetTickCount();
 					if (len != 0) {
-						if (dat->nTypeMode == PROTOTYPE_SELFTYPING_OFF)
-							NotifyTyping(dat, PROTOTYPE_SELFTYPING_ON);
+						if (nTypeMode == PROTOTYPE_SELFTYPING_OFF)
+							NotifyTyping(PROTOTYPE_SELFTYPING_ON);
 					}
-					else if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON)
-						NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
+					else if (nTypeMode == PROTOTYPE_SELFTYPING_ON)
+						NotifyTyping(PROTOTYPE_SELFTYPING_OFF);
 				}
 			}
 			break;
@@ -1677,9 +1711,9 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 			switch (pNmhdr->code) {
 			case EN_MSGFILTER:
 				{
-					int result = InputAreaShortcuts(GetDlgItem(hwndDlg, IDC_MESSAGE), ((MSGFILTER *)lParam)->msg, ((MSGFILTER *)lParam)->wParam, ((MSGFILTER *)lParam)->lParam, dat);
+					int result = InputAreaShortcuts(GetDlgItem(m_hwnd, IDC_MESSAGE), ((MSGFILTER *)lParam)->msg, ((MSGFILTER *)lParam)->wParam, ((MSGFILTER *)lParam)->lParam, this);
 					if (result != -1) {
-						SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+						SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE);
 						return TRUE;
 					}
 				}
@@ -1687,16 +1721,16 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 				switch (((MSGFILTER *)lParam)->msg) {
 				case WM_CHAR:
 					if (!(GetKeyState(VK_CONTROL) & 0x8000)) {
-						SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
-						SendDlgItemMessage(hwndDlg, IDC_MESSAGE, ((MSGFILTER *)lParam)->msg, ((MSGFILTER *)lParam)->wParam, ((MSGFILTER *)lParam)->lParam);
-						SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+						SetFocus(GetDlgItem(m_hwnd, IDC_MESSAGE));
+						SendDlgItemMessage(m_hwnd, IDC_MESSAGE, ((MSGFILTER *)lParam)->msg, ((MSGFILTER *)lParam)->wParam, ((MSGFILTER *)lParam)->lParam);
+						SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE);
 					}
 					return TRUE;
 
 				case WM_LBUTTONDOWN:
 					hCur = GetCursor();
 					if (hCur == LoadCursor(NULL, IDC_SIZENS) || hCur == LoadCursor(NULL, IDC_SIZEWE) || hCur == LoadCursor(NULL, IDC_SIZENESW) || hCur == LoadCursor(NULL, IDC_SIZENWSE)) {
-						SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+						SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE);
 						return TRUE;
 					}
 					break;
@@ -1708,26 +1742,10 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 					break;
 
 				case WM_RBUTTONUP:
-					SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+					SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE);
 					return TRUE;
 				}
 				break;
-
-			case EN_LINK:
-				switch (((ENLINK *)lParam)->msg) {
-				case WM_SETCURSOR:
-					SetCursor(hCurHyperlinkHand);
-					SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
-					return TRUE;
-
-				case WM_RBUTTONDOWN:
-				case WM_LBUTTONUP:
-					if (HandleLinkClick(g_hInst, hwndDlg, GetDlgItem(hwndDlg, IDC_MESSAGE), (ENLINK*)lParam)) {
-						SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
-						return TRUE;
-					}
-					break;
-				}
 			}
 			break;
 
@@ -1736,7 +1754,7 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 			case EN_MSGFILTER:
 				switch (((MSGFILTER *)lParam)->msg) {
 				case WM_RBUTTONUP:
-					SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+					SetWindowLongPtr(m_hwnd, DWLP_MSGRESULT, TRUE);
 					return TRUE;
 				}
 				break;
@@ -1746,10 +1764,10 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 				if (height < g_dat.minInputAreaHeight)
 					height = g_dat.minInputAreaHeight;
 
-				if (dat->desiredInputAreaHeight != height) {
-					dat->desiredInputAreaHeight = height;
-					SendMessage(hwndDlg, WM_SIZE, 0, 0);
-					PostMessage(hwndDlg, DM_SCROLLLOGTOBOTTOM, 0, 0);
+				if (desiredInputAreaHeight != height) {
+					desiredInputAreaHeight = height;
+					SendMessage(m_hwnd, WM_SIZE, 0, 0);
+					PostMessage(m_hwnd, DM_SCROLLLOGTOBOTTOM, 0, 0);
 				}
 				break;
 			}
@@ -1757,52 +1775,10 @@ INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP
 		break;
 
 	case WM_CHAR:
-		SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));
-		SendDlgItemMessage(hwndDlg, IDC_MESSAGE, msg, wParam, lParam);
-		break;
-
-	case WM_DESTROY:
-		NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSING);
-		if (dat->nTypeMode == PROTOTYPE_SELFTYPING_ON)
-			NotifyTyping(dat, PROTOTYPE_SELFTYPING_OFF);
-
-		IcoLib_ReleaseIcon(dat->statusIcon);
-		IcoLib_ReleaseIcon(dat->statusIconBig);
-		if (dat->statusIconOverlay != NULL) DestroyIcon(dat->statusIconOverlay);
-		dat->statusIcon = NULL;
-		dat->statusIconOverlay = NULL;
-		ReleaseSendQueueItems(hwndDlg);
-		if (g_dat.flags & SMF_SAVEDRAFTS) {
-			ptrA szText(GetRichTextUtf(GetDlgItem(hwndDlg, IDC_MESSAGE)));
-			if (szText)
-				db_set_utf(dat->hContact, "SRMM", "SavedMsg", szText);
-			else
-				db_unset(dat->hContact, "SRMM", "SavedMsg");
-		}
-
-		tcmdlist_free(dat->cmdList);
-		WindowList_Remove(pci->hWindowList, hwndDlg);
-
-		HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_MESSAGE, WM_GETFONT, 0, 0);
-		if (hFont != NULL && hFont != (HFONT)SendDlgItemMessage(hwndDlg, IDOK, WM_GETFONT, 0, 0))
-			DeleteObject(hFont);
-
-		db_set_b(dat->hContact, SRMMMOD, "UseRTL", (BYTE)((dat->flags & SMF_RTL) ? 1 : 0));
-		if (dat->hContact && (g_dat.flags & SMF_DELTEMP))
-			if (db_get_b(dat->hContact, "CList", "NotOnList", 0))
-				db_delete_contact(dat->hContact);
-
-		SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
-		SendMessage(dat->hwndParent, CM_REMOVECHILD, 0, (LPARAM)hwndDlg);
-		if (dat->hwndLog != NULL) {
-			IEVIEWWINDOW ieWindow = { sizeof(ieWindow) };
-			ieWindow.iType = IEW_DESTROY;
-			ieWindow.hwnd = dat->hwndLog;
-			CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
-		}
-		NotifyLocalWinEvent(dat->hContact, hwndDlg, MSG_WINDOW_EVT_CLOSE);
-		mir_free(dat);
+		SetFocus(GetDlgItem(m_hwnd, IDC_MESSAGE));
+		SendDlgItemMessage(m_hwnd, IDC_MESSAGE, msg, wParam, lParam);
 		break;
 	}
-	return FALSE;
+
+	return CSrmmBaseDialog::DlgProc(msg, wParam, lParam);
 }
diff --git a/plugins/Scriver/src/msglog.cpp b/plugins/Scriver/src/msglog.cpp
index b0b5e673cd..f0b009f737 100644
--- a/plugins/Scriver/src/msglog.cpp
+++ b/plugins/Scriver/src/msglog.cpp
@@ -78,7 +78,7 @@ struct LogStreamData
 	size_t   bufferOffset, bufferLen;
 	int      eventsToInsert;
 	int      isFirst;
-	SrmmWindowData *dlgDat;
+	CSrmmWindow *dlgDat;
 	GlobalMessageData *gdat;
 	EventData *events;
 };
@@ -112,7 +112,7 @@ int DbEventIsShown(DBEVENTINFO &dbei)
 	return DbEventIsCustomForMsgWindow(&dbei);
 }
 
-EventData* getEventFromDB(SrmmWindowData *dat, MCONTACT hContact, MEVENT hDbEvent)
+EventData* getEventFromDB(CSrmmWindow *dat, MCONTACT hContact, MEVENT hDbEvent)
 {
 	DBEVENTINFO dbei = {};
 	dbei.cbBlob = db_event_getBlobSize(hDbEvent);
@@ -476,8 +476,8 @@ static void AppendWithCustomLinks(EventData *evt, int style, CMStringA &buf)
 		mir_free(wText);
 }
 
-//mir_free() the return value
-static char* CreateRTFFromEvent(SrmmWindowData *dat, EventData *evt, GlobalMessageData *gdat, LogStreamData *streamData)
+// mir_free() the return value
+static char* CreateRTFFromEvent(CSrmmWindow *dat, EventData *evt, GlobalMessageData *gdat, LogStreamData *streamData)
 {
 	int style, showColon = 0;
 	int isGroupBreak = TRUE;
@@ -719,13 +719,12 @@ static DWORD CALLBACK LogStreamInEvents(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG
 
 void StreamInTestEvents(HWND hEditWnd, GlobalMessageData *gdat)
 {
-	SrmmWindowData dat;
-	memset(&dat, 0, sizeof(dat));
+	CSrmmWindow *dat = new CSrmmWindow(0);
 
 	LogStreamData streamData = { 0 };
 	streamData.isFirst = TRUE;
 	streamData.events = GetTestEvents();
-	streamData.dlgDat = &dat;
+	streamData.dlgDat = dat;
 	streamData.gdat = gdat;
 
 	EDITSTREAM stream = { 0 };
@@ -733,26 +732,27 @@ void StreamInTestEvents(HWND hEditWnd, GlobalMessageData *gdat)
 	stream.dwCookie = (DWORD_PTR)&streamData;
 	SendMessage(hEditWnd, EM_STREAMIN, SF_RTF, (LPARAM)&stream);
 	SendMessage(hEditWnd, EM_HIDESELECTION, FALSE, 0);
+
+	delete dat;
 }
 
-void StreamInEvents(HWND hwndDlg, MEVENT hDbEventFirst, int count, int fAppend)
+void CSrmmWindow::StreamInEvents(MEVENT hDbEventFirst, int count, int fAppend)
 {
 	FINDTEXTEXA fi;
 	EDITSTREAM stream = { 0 };
 	LogStreamData streamData = { 0 };
-	SrmmWindowData *dat = (SrmmWindowData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
 	CHARRANGE oldSel, sel;
 
 	// IEVIew MOD Begin
-	if (dat->hwndLog != NULL) {
+	if (hwndIeview != NULL) {
 		IEVIEWEVENT evt;
 		IEVIEWWINDOW ieWindow;
 		memset(&evt, 0, sizeof(evt));
 		evt.cbSize = sizeof(evt);
-		evt.dwFlags = ((dat->flags & SMF_RTL) ? IEEF_RTL : 0);
-		evt.hwnd = dat->hwndLog;
-		evt.hContact = dat->hContact;
-		evt.pszProto = dat->szProto;
+		evt.dwFlags = ((flags & SMF_RTL) ? IEEF_RTL : 0);
+		evt.hwnd = hwndIeview;
+		evt.hContact = m_hContact;
+		evt.pszProto = szProto;
 		if (!fAppend) {
 			evt.iType = IEE_CLEAR_LOG;
 			CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&evt);
@@ -761,25 +761,26 @@ void StreamInEvents(HWND hwndDlg, MEVENT hDbEventFirst, int count, int fAppend)
 		evt.hDbEventFirst = hDbEventFirst;
 		evt.count = count;
 		CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&evt);
-		dat->hDbEventLast = evt.hDbEventFirst != NULL ? evt.hDbEventFirst : dat->hDbEventLast;
+		hDbEventLast = evt.hDbEventFirst != NULL ? evt.hDbEventFirst : hDbEventLast;
 
 		memset(&ieWindow, 0, sizeof(ieWindow));
 		ieWindow.cbSize = sizeof(ieWindow);
 		ieWindow.iType = IEW_SCROLLBOTTOM;
-		ieWindow.hwnd = dat->hwndLog;
+		ieWindow.hwnd = hwndIeview;
 		CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
 		return;
 	}
-
 	// IEVIew MOD End
-	SendDlgItemMessage(hwndDlg, IDC_LOG, EM_HIDESELECTION, TRUE, 0);
-	SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXGETSEL, 0, (LPARAM)&oldSel);
-	streamData.hContact = dat->hContact;
+
+	m_log.SendMsg(EM_HIDESELECTION, TRUE, 0);
+	m_log.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldSel);
+
+	streamData.hContact = m_hContact;
 	streamData.hDbEvent = hDbEventFirst;
-	streamData.hDbEventLast = dat->hDbEventLast;
-	streamData.dlgDat = dat;
+	streamData.hDbEventLast = hDbEventLast;
+	streamData.dlgDat = this;
 	streamData.eventsToInsert = count;
-	streamData.isFirst = fAppend ? GetRichTextLength(GetDlgItem(hwndDlg, IDC_LOG), CP_ACP, FALSE) == 0 : 1;
+	streamData.isFirst = fAppend ? GetRichTextLength(m_log.GetHwnd(), CP_ACP, FALSE) == 0 : 1;
 	streamData.gdat = &g_dat;
 	stream.pfnCallback = LogStreamInEvents;
 	stream.dwCookie = (DWORD_PTR)& streamData;
@@ -788,30 +789,31 @@ void StreamInEvents(HWND hwndDlg, MEVENT hDbEventFirst, int count, int fAppend)
 		GETTEXTLENGTHEX gtxl = { 0 };
 		gtxl.flags = GTL_DEFAULT | GTL_PRECISE | GTL_NUMCHARS;
 		gtxl.codepage = 1200;
-		fi.chrg.cpMin = SendDlgItemMessage(hwndDlg, IDC_LOG, EM_GETTEXTLENGTHEX, (WPARAM)&gtxl, 0);
-		sel.cpMin = sel.cpMax = GetRichTextLength(GetDlgItem(hwndDlg, IDC_LOG), 1200, FALSE);
-		SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM)&sel);
+		fi.chrg.cpMin = m_log.SendMsg(EM_GETTEXTLENGTHEX, (WPARAM)&gtxl, 0);
+		sel.cpMin = sel.cpMax = GetRichTextLength(m_log.GetHwnd(), 1200, FALSE);
+		m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
 	}
 	else {
-		SendDlgItemMessage(hwndDlg, IDC_LOG, WM_SETREDRAW, FALSE, 0);
-		SetDlgItemText(hwndDlg, IDC_LOG, L"");
+		m_log.SendMsg(WM_SETREDRAW, FALSE, 0);
+		m_log.SetText(L"");
 		sel.cpMin = 0;
-		sel.cpMax = GetRichTextLength(GetDlgItem(hwndDlg, IDC_LOG), 1200, FALSE);
-		SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM)&sel);
+		sel.cpMax = GetRichTextLength(m_log.GetHwnd(), 1200, FALSE);
+		m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel);
 		fi.chrg.cpMin = 0;
-		dat->isMixed = 0;
+		isMixed = 0;
 	}
 
-	SendDlgItemMessage(hwndDlg, IDC_LOG, EM_STREAMIN, fAppend ? SFF_SELECTION | SF_RTF : SFF_SELECTION | SF_RTF, (LPARAM)&stream);
-	SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXSETSEL, 0, (LPARAM)&oldSel);
-	SendDlgItemMessage(hwndDlg, IDC_LOG, EM_HIDESELECTION, FALSE, 0);
+	m_log.SendMsg(EM_STREAMIN, fAppend ? SFF_SELECTION | SF_RTF : SFF_SELECTION | SF_RTF, (LPARAM)&stream);
+	m_log.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldSel);
+	m_log.SendMsg(EM_HIDESELECTION, FALSE, 0);
+	
 	if (g_dat.smileyAddInstalled) {
 		SMADD_RICHEDIT3 smre;
 		smre.cbSize = sizeof(SMADD_RICHEDIT3);
-		smre.hwndRichEditControl = GetDlgItem(hwndDlg, IDC_LOG);
+		smre.hwndRichEditControl = m_log.GetHwnd();
 
-		MCONTACT hContact = db_mc_getSrmmSub(dat->hContact);
-		smre.Protocolname = (hContact != NULL) ? GetContactProto(hContact) : dat->szProto;
+		MCONTACT hContact = db_mc_getSrmmSub(m_hContact);
+		smre.Protocolname = (hContact != NULL) ? GetContactProto(hContact) : szProto;
 
 		if (fi.chrg.cpMin > 0) {
 			sel.cpMin = fi.chrg.cpMin;
@@ -821,19 +823,19 @@ void StreamInEvents(HWND hwndDlg, MEVENT hDbEventFirst, int count, int fAppend)
 		else smre.rangeToReplace = NULL;
 
 		smre.disableRedraw = TRUE;
-		smre.hContact = dat->hContact;
+		smre.hContact = m_hContact;
 		smre.flags = 0;
 		CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&smre);
 	}
 
-	int len = GetRichTextLength(GetDlgItem(hwndDlg, IDC_LOG), 1200, FALSE);
-	SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETSEL, len - 1, len - 1);
+	int len = GetRichTextLength(m_log.GetHwnd(), 1200, FALSE);
+	m_log.SendMsg(EM_SETSEL, len - 1, len - 1);
 
 	if (!fAppend)
-		SendDlgItemMessage(hwndDlg, IDC_LOG, WM_SETREDRAW, TRUE, 0);
+		m_log.SendMsg(WM_SETREDRAW, TRUE, 0);
 
-	dat->hDbEventLast = streamData.hDbEventLast;
-	PostMessage(hwndDlg, DM_SCROLLLOGTOBOTTOM, 0, 0);
+	hDbEventLast = streamData.hDbEventLast;
+	PostMessage(m_hwnd, DM_SCROLLLOGTOBOTTOM, 0, 0);
 }
 
 #define RTFPICTHEADERMAXSIZE   78
diff --git a/plugins/Scriver/src/msgs.cpp b/plugins/Scriver/src/msgs.cpp
index aed59ba130..5197599dce 100644
--- a/plugins/Scriver/src/msgs.cpp
+++ b/plugins/Scriver/src/msgs.cpp
@@ -79,12 +79,10 @@ static INT_PTR ReadMessageCommand(WPARAM, LPARAM lParam)
 	MCONTACT hContact = db_mc_tryMeta(pcle->hContact);
 
 	HWND hwndExisting = WindowList_Find(pci->hWindowList, hContact);
-	if (hwndExisting == NULL) {
-		NewMessageWindowLParam newData = { 0 };
-		newData.hContact = hContact;
-		CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), GetParentWindow(hContact, FALSE), DlgProcMessage, (LPARAM)&newData);
-	}
-	else SendMessage(GetParent(hwndExisting), CM_POPUPWINDOW, 0, (LPARAM)hwndExisting);
+	if (hwndExisting == NULL)
+		(new CSrmmWindow(hContact))->Show();
+	else
+		SendMessage(GetParent(hwndExisting), CM_POPUPWINDOW, 0, (LPARAM)hwndExisting);
 	return 0;
 }
 
@@ -111,11 +109,7 @@ static int MessageEventAdded(WPARAM hContact, LPARAM lParam)
 		/* new message */
 		SkinPlaySound("AlertMsg");
 		if (IsAutoPopup(hContact)) {
-			NewMessageWindowLParam newData = { 0 };
-			newData.hContact = hContact;
-			HWND hParent = GetParentWindow(newData.hContact, FALSE);
-			newData.flags = NMWLP_INCOMING;
-			CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), hParent, DlgProcMessage, (LPARAM)&newData);
+			(new CSrmmWindow(hContact, true))->Show();
 			return 0;
 		}
 	}
@@ -161,14 +155,8 @@ static INT_PTR SendMessageCommandWorker(MCONTACT hContact, LPCSTR pszMsg, bool i
 		}
 		SendMessage(GetParent(hwnd), CM_POPUPWINDOW, 0, (LPARAM)hwnd);
 	}
-	else {
-		NewMessageWindowLParam newData = { 0 };
-		newData.hContact = hContact;
-		newData.szInitialText = pszMsg;
-		newData.isWchar = isWchar;
-		HWND hParent = GetParentWindow(newData.hContact, FALSE);
-		CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), hParent, DlgProcMessage, (LPARAM)&newData);
-	}
+	else (new CSrmmWindow(hContact, false, pszMsg, isWchar))->Show();
+
 	return 0;
 }
 
@@ -259,14 +247,10 @@ static void RestoreUnreadMessageAlerts(void)
 			if (windowAlreadyExists)
 				continue;
 
-			if (IsAutoPopup(hContact) && !windowAlreadyExists) {
-				NewMessageWindowLParam newData = { 0 };
-				newData.hContact = hContact;
-				newData.flags = NMWLP_INCOMING;
-				HWND hParent = GetParentWindow(newData.hContact, FALSE);
-				CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), hParent, DlgProcMessage, (LPARAM)&newData);
-			}
-			else arEvents.insert(new MSavedEvent(hContact, hDbEvent));
+			if (IsAutoPopup(hContact) && !windowAlreadyExists)
+				(new CSrmmWindow(hContact, true))->Show();
+			else
+				arEvents.insert(new MSavedEvent(hContact, hDbEvent));
 		}
 	}
 
@@ -340,7 +324,7 @@ static INT_PTR SetStatusText(WPARAM hContact, LPARAM lParam)
 		pdat = si->parent;
 	}
 	else {
-		SrmmWindowData *dat = (SrmmWindowData*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+		CSrmmWindow *dat = (CSrmmWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
 		if (dat == NULL || dat->parent == NULL)
 			return 1;
 
diff --git a/plugins/Scriver/src/msgs.h b/plugins/Scriver/src/msgs.h
index e3620340f7..70ee0f9704 100644
--- a/plugins/Scriver/src/msgs.h
+++ b/plugins/Scriver/src/msgs.h
@@ -92,97 +92,108 @@ struct MessageWindowTabData
 
 #define NMWLP_INCOMING 1
 
-struct NewMessageWindowLParam
-{
-	MCONTACT hContact;
-	BOOL isChat;
-	int isWchar;
-	LPCSTR szInitialText;
-	int flags;
-};
-
 struct CommonWindowData
 {
 	ParentWindowData *parent;
-	HWND hwndLog;
 	int minLogBoxHeight, minEditBoxHeight;
+	HWND hwndIeview;
 	TCmdList *cmdList, *cmdListCurrent;
 };
 
-struct SrmmWindowData : public CommonWindowData
+class CSrmmWindow : public CSrmmBaseDialog, public MZeroedObject, public CommonWindowData
 {
-	HWND hwnd;
-	MCONTACT hContact;
-	int tabId;
-	HWND hwndParent;
+	CCtrlEdit m_log, m_message;
+	
+	wchar_t *m_wszInitialText;
+	bool   m_bIncoming;
+	
 	MEVENT hDbEventFirst, hDbEventLast, hDbUnreadEventFirst;
-	int splitterPos;
-	int desiredInputAreaHeight;
-	SIZE toolbarSize;
-	int windowWasCascaded;
-	int nTypeSecs;
-	int nTypeMode;
-	HBITMAP avatarPic;
-	DWORD nLastTyping;
-	int showTyping;
-	int showUnread;
-	DWORD lastMessage;
+	int    splitterPos;
+	int    desiredInputAreaHeight;
+	SIZE   toolbarSize;
+	int    windowWasCascaded;
+	int    nTypeSecs, nTypeMode, nLastTyping;
+	int    showTyping, showUnread;
+	WORD   wStatus;
+	DWORD  lastMessage;
+	int    messagesInProgress;
+	int    sendAllConfirm;
+	HICON  statusIcon, statusIconBig, statusIconOverlay;
+
+	InfobarWindowData *infobarData;
+
+	HICON GetTabIcon();
+	void GetTitlebarIcon(struct TitleBarData *tbd);
+	void MessageDialogResize(int w, int h);
+	void ShowAvatar();
+	void SetDialogToType();
+	void SetStatusIcon();
+	void StreamInEvents(MEVENT hDbEventFirst, int count, int fAppend);
+	void UpdateReadChars();
+
+	bool IsTypingNotificationEnabled();
+	bool IsTypingNotificationSupported();
+	void NotifyTyping(int mode);
+
+public:
+	MCONTACT m_hContact;
 	char *szProto;
-	WORD wStatus;
-	time_t startTime;
-	time_t lastEventTime;
+	time_t startTime, lastEventTime;
 	int lastEventType;
-	DWORD flags;
-	int messagesInProgress;
-	struct AVATARCACHEENTRY *ace;
 	int isMixed;
-	int sendAllConfirm;
-	HICON statusIcon;
-	HICON statusIconBig;
-	HICON statusIconOverlay;
-	InfobarWindowData *infobarData;
-};
+	DWORD flags;
+
+	HBITMAP avatarPic;
+	AVATARCACHEENTRY *ace;
 
+public:
+	CSrmmWindow(MCONTACT hContact, bool bIncoming = false, const char *szInitialText = NULL, bool bIsUnicode = false);
+
+	virtual void OnInitDialog() override;
+	virtual void OnDestroy() override;
+
+	virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override;
+};
 
-#define HM_DBEVENTADDED			(WM_USER+10)
-#define DM_REMAKELOG			(WM_USER+11)
-#define DM_CASCADENEWWINDOW		(WM_USER+13)
-#define DM_OPTIONSAPPLIED		(WM_USER+14)
-#define DM_SPLITTERMOVED		(WM_USER+15)
-#define DM_APPENDTOLOG			(WM_USER+17)
-#define DM_ERRORDECIDED			(WM_USER+18)
-#define DM_SCROLLLOGTOBOTTOM	(WM_USER+19)
-#define DM_TYPING				(WM_USER+20)
-#define DM_UPDATELASTMESSAGE	(WM_USER+22)
-#define DM_USERNAMETOCLIP		(WM_USER+23)
-#define DM_CHANGEICONS			(WM_USER+24)
-#define DM_UPDATEICON			(WM_USER+25)
-#define DM_GETAVATAR			(WM_USER+27)
-#define HM_ACKEVENT				(WM_USER+29)
-
-#define DM_SENDMESSAGE			(WM_USER+30)
-#define DM_STARTMESSAGESENDING	(WM_USER+31)
-#define DM_SHOWMESSAGESENDING	(WM_USER+32)
-#define DM_STOPMESSAGESENDING	(WM_USER+33)
-#define DM_SHOWERRORMESSAGE		(WM_USER+34)
-
-#define DM_CLEARLOG				(WM_USER+46)
-#define DM_SWITCHSTATUSBAR		(WM_USER+47)
-#define DM_SWITCHTOOLBAR		(WM_USER+48)
-#define DM_SWITCHTITLEBAR		(WM_USER+49)
-#define DM_SWITCHINFOBAR		(WM_USER+50)
-#define DM_SWITCHRTL			(WM_USER+51)
-#define DM_SWITCHTYPING			(WM_USER+53)
-#define DM_MESSAGESENDING		(WM_USER+54)
-#define DM_GETWINDOWSTATE		(WM_USER+55)
-#define DM_STATUSICONCHANGE		(WM_USER+56)
-
-#define DM_MYAVATARCHANGED		(WM_USER+62)
-#define DM_PROTOAVATARCHANGED	(WM_USER+63)
-#define DM_AVATARCHANGED		(WM_USER+64)
-
-#define EM_SUBCLASSED			(WM_USER+0x101)
-#define EM_UNSUBCLASSED			(WM_USER+0x102)
+#define HM_DBEVENTADDED        (WM_USER+10)
+#define DM_REMAKELOG           (WM_USER+11)
+#define DM_CASCADENEWWINDOW    (WM_USER+13)
+#define DM_OPTIONSAPPLIED      (WM_USER+14)
+#define DM_SPLITTERMOVED       (WM_USER+15)
+#define DM_APPENDTOLOG         (WM_USER+17)
+#define DM_ERRORDECIDED        (WM_USER+18)
+#define DM_SCROLLLOGTOBOTTOM   (WM_USER+19)
+#define DM_TYPING              (WM_USER+20)
+#define DM_UPDATELASTMESSAGE   (WM_USER+22)
+#define DM_USERNAMETOCLIP      (WM_USER+23)
+#define DM_CHANGEICONS         (WM_USER+24)
+#define DM_UPDATEICON          (WM_USER+25)
+#define DM_GETAVATAR           (WM_USER+27)
+#define HM_ACKEVENT            (WM_USER+29)
+
+#define DM_SENDMESSAGE         (WM_USER+30)
+#define DM_STARTMESSAGESENDING (WM_USER+31)
+#define DM_SHOWMESSAGESENDING  (WM_USER+32)
+#define DM_STOPMESSAGESENDING  (WM_USER+33)
+#define DM_SHOWERRORMESSAGE    (WM_USER+34)
+
+#define DM_CLEARLOG            (WM_USER+46)
+#define DM_SWITCHSTATUSBAR     (WM_USER+47)
+#define DM_SWITCHTOOLBAR       (WM_USER+48)
+#define DM_SWITCHTITLEBAR      (WM_USER+49)
+#define DM_SWITCHINFOBAR       (WM_USER+50)
+#define DM_SWITCHRTL           (WM_USER+51)
+#define DM_SWITCHTYPING        (WM_USER+53)
+#define DM_MESSAGESENDING      (WM_USER+54)
+#define DM_GETWINDOWSTATE      (WM_USER+55)
+#define DM_STATUSICONCHANGE    (WM_USER+56)
+
+#define DM_MYAVATARCHANGED     (WM_USER+62)
+#define DM_PROTOAVATARCHANGED  (WM_USER+63)
+#define DM_AVATARCHANGED       (WM_USER+64)
+
+#define EM_SUBCLASSED          (WM_USER+0x101)
+#define EM_UNSUBCLASSED        (WM_USER+0x102)
 
 #define EVENTTYPE_JABBER_CHATSTATES	2000
 #define EVENTTYPE_JABBER_PRESENCE	2001
@@ -215,29 +226,27 @@ struct CREOleCallback2 : public CREOleCallback
 	STDMETHOD(QueryAcceptData) (LPDATAOBJECT lpdataobj, CLIPFORMAT FAR *lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict);
 };
 
-INT_PTR CALLBACK DlgProcMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
 INT_PTR CALLBACK ErrorDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
 int DbEventIsShown(DBEVENTINFO &dbei);
 int DbEventIsCustomForMsgWindow(DBEVENTINFO *dbei);
 int DbEventIsMessageOrCustom(DBEVENTINFO *dbei);
-void StreamInEvents(HWND hwndDlg, MEVENT hDbEventFirst, int count, int fAppend);
 void LoadMsgLogIcons(void);
 void FreeMsgLogIcons(void);
 int IsAutoPopup(MCONTACT hContact);
 
-#define MSGFONTID_MYMSG			0
-#define MSGFONTID_YOURMSG		1
-#define MSGFONTID_MYNAME		2
-#define MSGFONTID_MYTIME		3
-#define MSGFONTID_MYCOLON		4
-#define MSGFONTID_YOURNAME		5
-#define MSGFONTID_YOURTIME		6
-#define MSGFONTID_YOURCOLON		7
-#define MSGFONTID_MESSAGEAREA	8
-#define MSGFONTID_NOTICE		9
-#define MSGFONTID_MYURL			10
-#define MSGFONTID_YOURURL		11
-#define MSGFONTID_INFOBAR_NAME	12
+#define MSGFONTID_MYMSG           0
+#define MSGFONTID_YOURMSG         1
+#define MSGFONTID_MYNAME          2
+#define MSGFONTID_MYTIME          3
+#define MSGFONTID_MYCOLON         4
+#define MSGFONTID_YOURNAME        5
+#define MSGFONTID_YOURTIME        6
+#define MSGFONTID_YOURCOLON       7
+#define MSGFONTID_MESSAGEAREA     8
+#define MSGFONTID_NOTICE          9
+#define MSGFONTID_MYURL          10
+#define MSGFONTID_YOURURL        11
+#define MSGFONTID_INFOBAR_NAME   12
 #define MSGFONTID_INFOBAR_STATUS 13
 
 void LoadMsgDlgFont(int i, LOGFONT *lf, COLORREF *colour);
diff --git a/plugins/Scriver/src/stdafx.h b/plugins/Scriver/src/stdafx.h
index 45b704105c..3a2a74d140 100644
--- a/plugins/Scriver/src/stdafx.h
+++ b/plugins/Scriver/src/stdafx.h
@@ -61,6 +61,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <m_timezones.h>
 #include <m_string.h>
 #include <m_xstatus.h>
+#include <m_chat_int.h>
 #include <win2k.h>
 
 #include <m_ieview.h>
diff --git a/plugins/Scriver/src/tabs.cpp b/plugins/Scriver/src/tabs.cpp
index 9c18edc424..c3d6c11947 100644
--- a/plugins/Scriver/src/tabs.cpp
+++ b/plugins/Scriver/src/tabs.cpp
@@ -719,6 +719,12 @@ static int ScriverRestoreWindowPosition(HWND hwnd, MCONTACT hContact, const char
 	return 0;
 }
 
+struct NewMessageWindowLParam
+{
+	MCONTACT hContact;
+	BOOL isChat;
+};
+
 static INT_PTR CALLBACK DlgProcParentWindow(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 {
 	ParentWindowData *dat = (ParentWindowData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
diff --git a/plugins/Scriver/src/utils.cpp b/plugins/Scriver/src/utils.cpp
index 46d2874758..6f6b20209d 100644
--- a/plugins/Scriver/src/utils.cpp
+++ b/plugins/Scriver/src/utils.cpp
@@ -385,9 +385,9 @@ void SetSearchEngineIcons(HMENU hMenu, HIMAGELIST hImageList)
 	}
 }
 
-void GetContactUniqueId(SrmmWindowData *dat, char *buf, int maxlen)
+void GetContactUniqueId(CSrmmWindow *dat, char *buf, int maxlen)
 {
-	ptrW id(Contact_GetInfo(CNF_UNIQUEID, dat->hContact, dat->szProto));
+	ptrW id(Contact_GetInfo(CNF_UNIQUEID, dat->m_hContact, dat->szProto));
 	if (id != NULL)
 		strncpy_s(buf, maxlen, _T2A(id), _TRUNCATE);
 }
diff --git a/plugins/Scriver/src/utils.h b/plugins/Scriver/src/utils.h
index ddc50a9b27..12f668969a 100644
--- a/plugins/Scriver/src/utils.h
+++ b/plugins/Scriver/src/utils.h
@@ -48,7 +48,7 @@ void AppendToBuffer(char *&buffer, size_t &cbBufferEnd, size_t &cbBufferAlloced,
 int MeasureMenuItem(WPARAM wParam, LPARAM lParam);
 int DrawMenuItem(WPARAM wParam, LPARAM lParam);
 void SetSearchEngineIcons(HMENU hMenu, HIMAGELIST hImageList);
-void GetContactUniqueId(SrmmWindowData *dat, char *buf, int maxlen);
+void GetContactUniqueId(class CSrmmWindow *dat, char *buf, int maxlen);
 HWND CreateToolTip(HWND hwndParent, LPTSTR ptszText, LPTSTR ptszTitle, RECT *rect);
 void SetToolTipText(HWND hwndParent, HWND hwndTT, LPTSTR ptszText, LPTSTR ptszTitle);
 void SetToolTipRect(HWND hwndParent, HWND hwndTT, RECT* rect);
diff --git a/plugins/Scriver/src/version.h b/plugins/Scriver/src/version.h
index 4ee4aed656..8da9620ec9 100644
--- a/plugins/Scriver/src/version.h
+++ b/plugins/Scriver/src/version.h
@@ -1,6 +1,6 @@
-#define __MAJOR_VERSION          2
-#define __MINOR_VERSION          12
-#define __RELEASE_NUM            2
+#define __MAJOR_VERSION          3
+#define __MINOR_VERSION          0
+#define __RELEASE_NUM            1
 #define __BUILD_NUM              1
 
 #include <stdver.h>
-- 
cgit v1.2.3