/*

MUCC Group Chat GUI Plugin for Miranda IM
Copyright (C) 2004  Piotr Piastucki

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "ChatWindow.h"
#include "HelperDialog.h"
#include "Utils.h"
#include "Options.h"
#include "m_smileyadd.h"
#include "m_ieview.h"
//#include "m_chat.h"

static int logPixelSY;
static INT_PTR CALLBACK LogDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
static void JabberStringAppend(char **str, int *sizeAlloced, const char *fmt, ...);
static char *JabberRtfEscape(char *str);
//static DWORD CALLBACK Log_StreamCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb);

COLORREF ChatWindow::colorListBg, ChatWindow::colorListText, ChatWindow::colorListGroupText;
HFONT ChatWindow::hListGroupFont=NULL;
HFONT ChatWindow::hListFont=NULL;

ChatWindow *	ChatWindow::list = NULL;
bool ChatWindow::released = false;
CRITICAL_SECTION ChatWindow::mutex;

static	WNDPROC	oldSplitterWndProc, oldEditWndProc;
static  HCURSOR hCurSplitNS, hCurSplitWE, hCurHyperlinkHand;

void ChatWindow::release() {
	released = true;
	for (ChatWindow *ptr2, *ptr = list; ptr!=NULL; ptr=ptr2) {
		ptr2 = ptr->getNext();
		//SendMessage(ptr->getHWND(), WM_CLOSE, 0, 0);
	}
	DeleteCriticalSection(&mutex);
	DestroyCursor(hCurSplitNS);
	DestroyCursor(hCurSplitWE);
	DestroyCursor(hCurHyperlinkHand);
}

void ChatWindow::init() {
	hCurSplitNS = LoadCursor(NULL, IDC_SIZENS);
	hCurSplitWE = LoadCursor(NULL, IDC_SIZEWE);
	hCurHyperlinkHand = LoadCursor(NULL, IDC_HAND);
	if (hCurHyperlinkHand == NULL) {
		hCurHyperlinkHand = LoadCursor(NULL, IDC_ARROW);
	}
	released = false;
	InitializeCriticalSection(&mutex);
}

/* chat.dll mod*/
/*
static bool gcRegistered = false;

static void __stdcall StartThread(void *vChat) { //__cdecl
	ChatWindow *chat = (ChatWindow *)vChat;
	if (!gcRegistered) {
		gcRegistered = true;
		GCREGISTER gcr = {0};
		gcr.cbSize = sizeof(GCREGISTER);
		gcr.dwFlags = 0;
		gcr.iMaxText = 0;
		gcr.nColors = 0;
		gcr.pColors = 0;
		gcr.pszModuleDispName = chat->getModule();
		gcr.pszModule = chat->getModule();
		if (CallService(MS_GC_REGISTER, 0, (LPARAM)&gcr)) {
			MessageBox(NULL, "cannot register", "CHAT", MB_OK);
		}
	}
	GCWINDOW gcw = {0};
	gcw.cbSize = sizeof(GCWINDOW);
	gcw.iType = GCW_CHATROOM;
	gcw.pszModule = chat->getModule();
	gcw.pszName = chat->getRoomName();
	gcw.pszID = chat->getRoomId();
	gcw.pszStatusbarText =  "status";
	gcw.bDisableNickList = FALSE;
	gcw.dwItemData = (DWORD) chat;
	if(CallService(MS_GC_NEWCHAT, 0, (LPARAM) &gcw)) {
		MessageBox(NULL, "cannot create", "CHAT", MB_OK);
	}

	GCDEST gcdest;
	GCEVENT gcevent = {sizeof(GCEVENT), &gcdest};
	const char *groupNames[] = {"Global Owners", "Owners", "Admins", "Moderators", "Users"};
	gcdest.pszModule = (char *)chat->getModule();
	gcdest.pszID = (char *)chat->getRoomId();
	gcevent.bAddToLog = FALSE;
    gcevent.time = 0;
	gcdest.iType = GC_EVENT_ADDGROUP;
	for (int i=0;i<5;i++) {
		gcevent.pszStatus = Translate(groupNames[i]);
		CallService(MS_GC_EVENT, 0, (LPARAM)&gcevent);
	}


	gcdest.iType = GC_EVENT_CONTROL;
	CallService(MS_GC_EVENT, WINDOW_INITDONE, (LPARAM)&gcevent);
	CallService(MS_GC_EVENT, WINDOW_ONLINE, (LPARAM)&gcevent);
}
*/

ChatWindow::ChatWindow(MUCCWINDOW *mucw)  {
	prev = next = NULL;
	adminWindow = NULL;
	hWnd = NULL;
	hWndLog = NULL;
	module = roomId = roomName = topic = NULL;
	hSplitterPos = 0;
	vSplitterPos = 0;
	wasFirstMessage = 0;
	isEmpty = true;
	isStarted = 0;
	options = Options::getChatWindowOptions();
	bBold = bItalic = bUnderline = 0;
	hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	hEditFont = NULL;
	userMe = NULL;
	users = NULL;
	for (int i=0;i<5;i++) {
		hUserGroups[i] = NULL;
	}
	setModule(mucw->pszModule);
	setRoomId(mucw->pszID);
	setRoomName(mucw->pszName);
	EnterCriticalSection(&mutex);
	setNext(list);
	if (next!=NULL) {
		next->setPrev(this);
	}
	list = this;
	LeaveCriticalSection(&mutex);
	container = ChatContainer::getWindow();
	hWnd = container->remoteCreateChild(LogDlgProc, this);
	container->remoteAddChild(this);
	/* chat.dll mod*/
/*	CallFunctionAsync(StartThread, (void *)this);*/
}

ChatWindow::~ChatWindow () {
	if (!released) {
		EnterCriticalSection(&mutex);
		if (getPrev()!=NULL) {
			getPrev()->setNext(next);
		} else if (list==this) {
			list = getNext();
		}
		if (getNext()!=NULL) {
			getNext()->setPrev(prev);
		}
		LeaveCriticalSection(&mutex);
	}
	if (adminWindow!=NULL) {
		delete adminWindow;
	}
	if (hEvent!=NULL) {
		CloseHandle(hEvent);
	}
	while (users!=NULL) {
		ChatUser *user = users;
		users = users->getNext();
		delete user;
	}
	if (module!=NULL) {
		delete module;
	}
	if (roomId!=NULL) {
		delete roomId;
	}
	if (roomName!=NULL) {
		delete roomName;
	}
	if (topic!=NULL) {
		delete topic;
	}
	container->remoteRemoveChild(this);
};


void ChatWindow::setPrev(ChatWindow *prev) {
	this->prev = prev;
}

ChatWindow * ChatWindow::getPrev() {
	return prev;
}

void ChatWindow::setNext(ChatWindow *next) {
	this->next = next;
}

ChatWindow * ChatWindow::getNext() {
	return next;
}

void ChatWindow::setHWND(HWND hWnd) {
	this->hWnd = hWnd;
}

HWND ChatWindow::getHWND() {
	return hWnd;
}

void ChatWindow::setHWNDLog(HWND hWnd) {
	this->hWndLog = hWnd;
}

HWND ChatWindow::getHWNDLog() {
	return hWndLog;
}

HANDLE ChatWindow::getEvent() {
	return hEvent;
}

ChatContainer * ChatWindow::getContainer() {
	return container;
}

void ChatWindow::setAdminWindow(AdminWindow *aw) {
	this->adminWindow = aw;
}

AdminWindow* ChatWindow::getAdminWindow() {
	return adminWindow;
}

void ChatWindow::setModule(const char *module) {
	Utils::copyString(&this->module, module);
}

const char * ChatWindow::getModule() {
	return module;
}

void ChatWindow::setRoomId(const char *roomId) {
	Utils::copyString(&this->roomId, roomId);
}

const char * ChatWindow::getRoomId() {
	return roomId;
}

void ChatWindow::setRoomName(const char *roomName) {
//	char str[300];
	Utils::copyString(&this->roomName, roomName);
//	sprintf(str, "%s %08X", roomName, roomFlags);
//	SetWindowText(hWnd, str);
	SetWindowTextA(hWnd, roomName);
}

void ChatWindow::setRoomFlags(int flags) {
//	char str[300];
	roomFlags = flags;
//	sprintf(str, "%s %08X", roomName, roomFlags);
//	SetWindowText(hWnd, str);
}

int ChatWindow::getRoomFlags() {
	return roomFlags;
}

const char * ChatWindow::getRoomName() {
	return roomName;
}

void ChatWindow::setOptions(int options) {
	if (options != this->options) {
		this->options = options;
		rebuildLog();
	}
}

int ChatWindow::getOptions() {
	return options;
}

static void __cdecl StartAdminThread(void *vChat) {
	ChatWindow *chat = (ChatWindow *)vChat;
	chat->getAdminWindow()->start();
}

void ChatWindow::startAdminDialog(int mode) {
	if (adminWindow==NULL) {
		ChatUser *user = getSelectedUser();
		if (user != NULL) {
			adminWindow = new AdminWindow(this, user->getId(), mode);
		} else {
			adminWindow = new AdminWindow(this, "", mode);
		}
		Utils::forkThread((void (__cdecl *)(void *))StartAdminThread, 0, (void *) this);
	}
}
void ChatWindow::addUser(ChatUser *user) {
	user->setNext(users);
	users = user;
}
void ChatWindow::removeUser(ChatUser *user) {
	ChatUser *user2;
	for (user2=users;user2!=NULL;user2=user2->getNext()) {
		if (user2->getNext()==user) break;
	}
	if (user2!=NULL) {
		user2->setNext(user->getNext());
	} else if (users==user) {
		users = user->getNext();
	}
}

ChatUser * ChatWindow::getMe() {
	return userMe;
}

ChatUser * ChatWindow::findUser(const char *userId) {
	ChatUser *user;
	for (user=users;user!=NULL;user=user->getNext()) {
		if (!(strcmp(user->getId(), userId))) break;
	}
	return user;
}

ChatUser * ChatWindow::findUserByNick(const char *nick) {
	ChatUser *user;
	for (user=users;user!=NULL;user=user->getNext()) {
		if (!(strcmp(user->getNick(), nick))) break;
	}
	return user;
}

ChatUser *ChatWindow::getSelectedUser() {
	HTREEITEM hTreeItem = TreeView_GetSelection(GetDlgItem(hWnd, IDC_TREELIST));
	if (hTreeItem!=NULL) {
		TVITEM tvi;
		tvi.mask = TVIF_PARAM;
		tvi.hItem = hTreeItem;
		TreeView_GetItem(GetDlgItem(hWnd, IDC_TREELIST), &tvi);
		return (ChatUser *) tvi.lParam;
	}
	return NULL;
}

int ChatWindow::startPriv() {
	ChatUser *user = getSelectedUser();
	if (user!=NULL) {
		MUCCEVENT mucce;
		mucce.cbSize = sizeof(MUCCEVENT);
		mucce.iType = MUCC_EVENT_START_PRIV;
		mucce.pszModule =  getModule();
		mucce.pszID = getRoomId();
		mucce.pszUID = user->getId();
		NotifyEventHooks(hHookEvent, 0,(WPARAM)&mucce);
	}
	return 0;
}

int ChatWindow::unban(const char *id) {
	if (id!=NULL) {
		MUCCEVENT mucce;
		mucce.cbSize = sizeof(MUCCEVENT);
		mucce.iType = MUCC_EVENT_UNBAN;
		mucce.pszModule =  getModule();
		mucce.pszID = getRoomId();
		mucce.pszUID = id;
		NotifyEventHooks(hHookEvent, 0,(WPARAM)&mucce);
	}
	return 0;
}


int ChatWindow::kickAndBan(const char *id, int time, const char *reason) {
	if (id!=NULL) {
		MUCCEVENT mucce;
		mucce.cbSize = sizeof(MUCCEVENT);
		mucce.iType = MUCC_EVENT_KICK_BAN;
		mucce.pszModule =  getModule();
		mucce.pszID = getRoomId();
		mucce.pszUID = id;
		mucce.dwData = time;
		mucce.pszText = reason;
		NotifyEventHooks(hHookEvent, 0,(WPARAM)&mucce);
	}
	return 0;
}

int ChatWindow::kickAndBan(int time) {
	ChatUser *user = getSelectedUser();
	if (user!=NULL) {
		kickAndBan(user->getId(), time, "");
	}
	return 0;
}

int ChatWindow::setRights(const char *id, int flags) {
	if (id!=NULL) {
		MUCCEVENT mucce;
		mucce.cbSize = sizeof(MUCCEVENT);
		mucce.iType = MUCC_EVENT_SET_USER_ROLE;
		mucce.pszModule =  getModule();
		mucce.pszID = getRoomId();
		mucce.pszUID = id;
		mucce.dwFlags = flags;
		NotifyEventHooks(hHookEvent, 0,(WPARAM)&mucce);
	}
	return 0;
}

int ChatWindow::setRights(int flags) {
	ChatUser *user = getSelectedUser();
	if (user!=NULL) {
		setRights(user->getId(), flags);
	}
	return 0;
}

int ChatWindow::getUserGroup(ChatUser *user) {
	int group = 4;
	if (user->getFlags()&MUCC_EF_USER_GLOBALOWNER) {
		group = 0;
	} else if (user->getFlags()&MUCC_EF_USER_OWNER) {
		group = 1;
	} else if (user->getFlags()&MUCC_EF_USER_ADMIN) {
		group = 2;
	} else if (user->getFlags()&MUCC_EF_USER_MODERATOR) {
		group = 3;
	}
	return group;
}

int ChatWindow::changePresence(const MUCCEVENT *event) {
	int i, group, bLogEvent = FALSE;
	const char *groupNames[] = {"Global Owners", "Owners", "Admins", "Moderators", "Users"};
	ChatUser *user = findUser(event->pszUID);
	if (event->dwData == ID_STATUS_ONLINE || (user!=NULL && event->dwData!=ID_STATUS_OFFLINE)) {
		if (user == NULL) {
			user = new ChatUser();
			user->setId(event->pszUID);
			user->setNick(event->pszNick);
			user->setFlags(event->dwFlags);
			user->setMe(event->bIsMe);
			addUser(user);
			if (user->isMe()) {
				userMe = user;
			}
			bLogEvent = TRUE;
		} else {
			group = getUserGroup(user);
			user->setFlags(event->dwFlags);
			TreeView_DeleteItem(GetDlgItem(hWnd, IDC_TREELIST), user->getHTreeItem());
			if (TreeView_GetChild(GetDlgItem(hWnd, IDC_TREELIST), getTreeItem(group))==NULL) {
				TreeView_DeleteItem(GetDlgItem(hWnd, IDC_TREELIST), getTreeItem(group));
				setTreeItem(group, NULL);
			}
		}
		if (user->isMe()) {
			if (user->getFlags() & MUCC_EF_USER_OWNER || user->getFlags() & MUCC_EF_USER_ADMIN) {
				EnableWindow(GetDlgItem(hWnd, IDC_TOPIC_BUTTON), TRUE);
			} else {
				EnableWindow(GetDlgItem(hWnd, IDC_TOPIC_BUTTON), FALSE);
			}
		}
		group = getUserGroup(user);
		TVINSERTSTRUCT tvis;
		if (getTreeItem(group)==NULL) {
			for (i=group-1;i>=0;i--) {
				if (getTreeItem(i)!=NULL) break;
			}
			tvis.hParent = NULL;
			if (i>=0) {
				tvis.hInsertAfter = getTreeItem(i);
			} else {
				tvis.hInsertAfter = TVI_FIRST;
			}
			tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN;
			tvis.item.lParam = (LPARAM) NULL;
			tvis.item.cChildren = 1;
			LPTSTR lps1 = Utils::mucc_mir_a2t(Translate(groupNames[group]));
			tvis.item.pszText = lps1;
			//tvis.item.state = INDEXTOSTATEIMAGEMASK(1);
			//tvis.item.stateMask = TVIS_STATEIMAGEMASK ;
			setTreeItem(group, TreeView_InsertItem(GetDlgItem(hWnd, IDC_TREELIST), &tvis));
			Utils::mucc_mir_free(lps1);
		}
		tvis.hParent = getTreeItem(group);
		tvis.hInsertAfter = TVI_SORT;
		tvis.item.mask = TVIF_TEXT  | TVIF_PARAM;
		LPTSTR lps2 = Utils::mucc_mir_a2t(user->getNick());
		tvis.item.pszText = lps2;
		tvis.item.lParam = (LPARAM) user;
		user->setHTreeItem(TreeView_InsertItem(GetDlgItem(hWnd, IDC_TREELIST), &tvis));
		TreeView_Expand(GetDlgItem(hWnd, IDC_TREELIST), getTreeItem(group), TVE_EXPAND);
		Utils::mucc_mir_free(lps2);
	}
	else {
		if (user != NULL) {
			group = getUserGroup(user);
			TreeView_DeleteItem(GetDlgItem(hWnd, IDC_TREELIST), user->getHTreeItem());
			if (TreeView_GetChild(GetDlgItem(hWnd, IDC_TREELIST), getTreeItem(group))==NULL) {
				TreeView_DeleteItem(GetDlgItem(hWnd, IDC_TREELIST), getTreeItem(group));
				setTreeItem(group, NULL);
			}
			removeUser(user);
			delete user;
			bLogEvent = TRUE;
		}
	}
	if (bLogEvent && wasFirstMessage) {
		logEvent(event);
	}
	return 1;
}
int ChatWindow::changeTopic(const MUCCEVENT *event) {

	SetDlgItemTextA(hWnd, IDC_TOPIC, event->pszText);
//if (wasFirstMessage) {
		logEvent(event);
//	}
	return 1;
}

int ChatWindow::changeRoomInfo(const MUCCEVENT *event) {

	Utils::log("setting room info !");
	setRoomName(event->pszName);
	setRoomFlags(event->dwFlags);
	return 1;
}

const char * ChatWindow::getFontName(int index) {
	const char *fontNames[] = {"Arial",
							   "Comic Sans MS",
							   "Courier New",
							   "Impact",
							   "Lucida Console",
							   "MS Sans Serif",
							   "Tahoma",
							   "Times New Roman",
							   "Trebuchet MS",
							   "Verdana"};
	if (index>9 || index<0) index = 0;
	return fontNames[index];
}
int	ChatWindow::getFontNameNum() {
	return 10;
}
int ChatWindow::getFontSize(int index) {
	return index+7;
}
int ChatWindow::getFontSizeNum() {
	return 10;
}

void ChatWindow::refreshSettings() {
	SendDlgItemMessage(hWnd, IDC_LOG, EM_SETBKGNDCOLOR , 0, Options::getLogBgColor());
	SendDlgItemMessage(hWnd, IDC_TREELIST, TVM_SETBKCOLOR, 0, Options::getListBgColor());
	eventList.setMaxSize(Options::getLogLimit());
}

void ChatWindow::refreshSettings(int force) {

	if (hListFont!=NULL && !force) {
		return;
	}
	EnterCriticalSection(&mutex);
	if (hListFont!=NULL) {
		DeleteObject(hListFont);
	}
	if (hListGroupFont!=NULL) {
		DeleteObject(hListGroupFont);
	}
	Font * font = Options::getFont(Options::FONT_USERLIST);
	colorListText = font->getColor();
	hListFont = CreateFontA(font->getSize(), 0, 0, 0,
							font->getStyle() & Font::BOLD ? FW_BOLD : FW_NORMAL,
							font->getStyle() & Font::ITALIC ? 1 : 0,
							font->getStyle() & Font::UNDERLINE ? 1 : 0, 0,
							font->getCharSet(),
							OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_ROMAN,
                            font->getFace());
	font = Options::getFont(Options::FONT_USERLISTGROUP);
	colorListGroupText = font->getColor();
	hListGroupFont = CreateFontA(font->getSize(), 0, 0, 0,
								 font->getStyle() & Font::BOLD ? FW_BOLD : FW_NORMAL,
								 font->getStyle() & Font::ITALIC ? 1 : 0,
								 font->getStyle() & Font::UNDERLINE ? 1 : 0, 0,
								 font->getCharSet(),
								 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_ROMAN,
                                 font->getFace());

	for (ChatWindow *ptr=list;ptr!=NULL;ptr=ptr->getNext()) {
		ptr->refreshSettings();
		InvalidateRect(ptr->getHWND(), NULL, FALSE);
	}
	LeaveCriticalSection(&mutex);
}
HFONT ChatWindow::getListFont() {
	return hListFont;
}

HFONT ChatWindow::getListGroupFont() {
	return hListGroupFont;
}

COLORREF ChatWindow::getListTextColor() {
	return colorListText;
}

COLORREF ChatWindow::getListGroupTextColor() {
	return colorListGroupText;
}

HTREEITEM ChatWindow::getTreeItem(int index) {
	return hUserGroups[index];
}

void ChatWindow::setTreeItem(int index, HTREEITEM hTreeItem) {
	hUserGroups[index]=hTreeItem;
}

int ChatWindow::getDefaultOptions() {
	return FLAG_SHOW_NICKNAMES | FLAG_SHOW_TIMESTAMP | FLAG_FORMAT_ALL | FLAG_LOG_MESSAGES | FLAG_OPT_SENDONENTER;
}

void ChatWindow::clearLog() {
	if (getHWNDLog()!=NULL) {
		IEVIEWEVENT iee;
		ZeroMemory(&iee, sizeof(iee));
		iee.cbSize = sizeof(iee);
		iee.iType = IEE_CLEAR_LOG;
		iee.dwFlags = IEEF_NO_UNICODE;
		iee.hwnd = hWndLog;
		iee.hContact = NULL;
		iee.codepage = CP_ACP;
		iee.pszProto = getModule();
		CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&iee);
	} else {
		SetDlgItemTextA(getHWND(), IDC_LOG, "");
	}
	isEmpty = true;
	eventList.clear();
}

void ChatWindow::rebuildLog() {
	int	nMin, nMax;
	HWND hwndLog;
	if (getHWNDLog()!=NULL) {
		IEVIEWEVENT iee;
		ZeroMemory(&iee, sizeof(iee));
		iee.cbSize = sizeof(iee);
		iee.iType = IEE_CLEAR_LOG;
		iee.dwFlags = IEEF_NO_UNICODE;
		iee.hwnd = hWndLog;
		iee.hContact = NULL;
		iee.codepage = CP_ACP;
		iee.pszProto = getModule();
		CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&iee);
	} else {
		SetDlgItemTextA(getHWND(), IDC_LOG, "");
	}
	isEmpty = true;
	for (ChatEvent* event=eventList.getEvents();event!=NULL;event=event->getNext()) {
		appendMessage(event->getEvent());
	}
	if (getHWNDLog()==NULL) {
		if (ServiceExists(MS_SMILEYADD_REPLACESMILEYS)) PostMessage(getHWND(), WM_TLEN_SMILEY, 0, 0);
		hwndLog = GetDlgItem(getHWND(), IDC_LOG);
		int len = GetWindowTextLengthA(hwndLog);
		SendMessage(hwndLog, EM_SETSEL, len - 1, len - 1);
		GetScrollRange(hwndLog, SB_VERT, &nMin, &nMax);
		SetScrollPos(hwndLog, SB_VERT, nMax, TRUE);
		PostMessage(hwndLog, WM_VSCROLL, MAKEWPARAM(SB_THUMBPOSITION, nMax), (LPARAM) NULL);
	}
}

int ChatWindow::logEvent(const MUCCEVENT *event) {
	/* chat.dll mod*/
	/*
	if (event->iType == MUCC_EVENT_MESSAGE) {
		GCDEST gcdest;
		GCEVENT gcevent = {sizeof(GCEVENT), &gcdest};
		gcdest.pszModule = (char *)this->getModule();
		gcdest.pszID = (char *)this->getRoomId();
		gcdest.iType = GC_EVENT_MESSAGE;
		gcevent.pszText = event->pszText;
		gcevent.pszNick = event->pszNick;
		gcevent.pszUID = event->pszUID;
		gcevent.bIsMe = event->bIsMe;
		gcevent.bAddToLog = TRUE;
		gcevent.time = event->time;
		CallService(MS_GC_EVENT, 0, (LPARAM)&gcevent);

	}
	if (event->iType == MUCC_EVENT_STATUS) {
		const char *groupNames[] = {"Global Owners", "Owners", "Admins", "Moderators", "Users"};
		GCDEST gcdest;
		GCEVENT gcevent = {sizeof(GCEVENT), &gcdest};
		gcdest.pszModule = (char *)this->getModule();
		gcdest.pszID = (char *)this->getRoomId();
		gcevent.pszText = event->pszText;
		gcevent.pszNick = event->pszNick;
		int group = 4;
		if (event->dwFlags&MUCC_EF_USER_GLOBALOWNER) {
			group = 0;
		} else if (event->dwFlags&MUCC_EF_USER_OWNER) {
			group = 1;
		} else if (event->dwFlags&MUCC_EF_USER_ADMIN) {
			group = 2;
		} else if (event->dwFlags&MUCC_EF_USER_MODERATOR) {
			group = 3;
		}
		gcevent.pszStatus = Translate(groupNames[group]);
		gcevent.pszUID = event->pszUID;
		gcevent.bIsMe = event->bIsMe;
		gcevent.bAddToLog = TRUE;
		gcevent.time = event->time;
		if (event->dwData == ID_STATUS_ONLINE) {
			gcdest.iType = GC_EVENT_JOIN;
		} else {
			gcdest.iType = GC_EVENT_PART;
		}
		CallService(MS_GC_EVENT, 0, (LPARAM)&gcevent);
	}
	*/
	/* chat.dll mod*/

	int	nMin, nMax;
	HWND hwndLog;
	if (event->iType != MUCC_EVENT_ERROR) {
		if (eventList.addEvent(event)) {
			rebuildLog();
			return 1;
		}
	}
	if (event->iType == MUCC_EVENT_MESSAGE) {
		wasFirstMessage = 1;
		appendMessage(event);
		container->remoteSetUnread(this, 1);
	} else {
		appendMessage(event);
	}
	if (event->iType==MUCC_EVENT_MESSAGE && getOptions() & FLAG_FLASH_MESSAGES) {
		container->remoteFlashWindow();
	} else if (event->iType==MUCC_EVENT_STATUS && event->dwData==ID_STATUS_ONLINE && getOptions() & FLAG_FLASH_JOINED) {
		container->remoteFlashWindow();
	} else if (event->iType==MUCC_EVENT_STATUS && event->dwData==ID_STATUS_OFFLINE && getOptions() & FLAG_FLASH_LEFT) {
		container->remoteFlashWindow();
	} else if (event->iType==MUCC_EVENT_TOPIC && getOptions() & FLAG_FLASH_TOPIC) {
		container->remoteFlashWindow();
	}
	if (getHWNDLog()==NULL) {
		if (ServiceExists(MS_SMILEYADD_REPLACESMILEYS)) PostMessage(getHWND(), WM_TLEN_SMILEY, 0, 0);
		hwndLog = GetDlgItem(getHWND(), IDC_LOG);
		int len = GetWindowTextLengthA(hwndLog);
		SendMessage(hwndLog, EM_SETSEL, len - 1, len - 1);
		GetScrollRange(hwndLog, SB_VERT, &nMin, &nMax);
		SetScrollPos(hwndLog, SB_VERT, nMax, TRUE);
		PostMessage(hwndLog, WM_VSCROLL, MAKEWPARAM(SB_THUMBPOSITION, nMax), (LPARAM) NULL);
	}
	return 1;
}

void ChatWindow::createRTFHeader() {
	char *rtf;
	int i, msgSize;
	//, , iFontSize, bItalic, bBold, bUnderline;
	rtf = NULL;
	JabberStringAppend(&rtf, &msgSize, "{\\rtf1\\ansi\\deff0{\\fonttbl");

	for (i=0;i<FontList::getFontNum();i++) {
		Font *font = FontList::getFont(i);
		JabberStringAppend(&rtf, &msgSize, "{\\f%u\\fnil\\fcharset%u %s;}", font->getCharSet(), font->getFace());
	}
	JabberStringAppend(&rtf, &msgSize, "}{\\colortbl ");
	for (i=0;i<FontList::getFontNum();i++) {
		Font *font = FontList::getFont(i);
		DWORD color = font->getColor();
		JabberStringAppend(&rtf, &msgSize, "\\red%d\\green%d\\blue%d;", color&0xFF, (color>>8)&0xFF, (color>>16)&0xFF);
	}
	JabberStringAppend(&rtf, &msgSize, "}");
}


int ChatWindow::appendMessage(const MUCCEVENT *event) {
	char timestampStr[100], str[512];
	char *rtf, *escapedStr = NULL, *escapedNick = NULL;
	Font *fontTimestamp, *fontName, *fontMessage; //*fontColon,
	int msgSize;
	DWORD color;
	int iFontSize, bItalic, bBold, bUnderline;
	HWND hwndLog;
	DBTIMETOSTRING dbtts;
	CHARRANGE sel;
	SETTEXTEX stt;
	//tm *ltime;

	if (event->iType!=MUCC_EVENT_STATUS && event->iType!=MUCC_EVENT_STATUS && event->iType!=MUCC_EVENT_ERROR
		&& event->iType!=MUCC_EVENT_TOPIC && event->iType != MUCC_EVENT_MESSAGE) {
		return 0;
	}
	if (event->iType==MUCC_EVENT_MESSAGE && !(getOptions() & FLAG_LOG_MESSAGES)) {
		return 0;
	} else if (event->iType==MUCC_EVENT_STATUS && event->dwData==ID_STATUS_ONLINE && !(getOptions() & FLAG_LOG_JOINED)) {
		return 0;
	} else if (event->iType==MUCC_EVENT_STATUS && event->dwData==ID_STATUS_OFFLINE && !(getOptions() & FLAG_LOG_LEFT)) {
		return 0;
	} else if (event->iType==MUCC_EVENT_TOPIC && !(getOptions() & FLAG_LOG_TOPIC)) {
		return 0;
	}

	if (getHWNDLog()!=NULL) {
		IEVIEWEVENTDATA ied;
		IEVIEWEVENT iee;
		IEVIEWWINDOW iew;
		ZeroMemory(&iee, sizeof(iee));
		iee.cbSize = sizeof(iee);
		iee.dwFlags = IEEF_NO_UNICODE;
		iee.hwnd = hWndLog;
		iee.hContact = NULL;
		iee.iType = IEE_LOG_MEM_EVENTS;
		iee.codepage = CP_ACP;
		iee.pszProto = getModule();
		iee.eventData = &ied;
		iee.count = 1;

		ied.cbSize = sizeof(IEVIEWEVENTDATA);
		if (event->iType==MUCC_EVENT_MESSAGE) {
			ied.iType = IEED_MUCC_EVENT_MESSAGE;
		} else if (event->iType==MUCC_EVENT_STATUS && event->dwData==ID_STATUS_ONLINE) {
			ied.iType = IEED_MUCC_EVENT_JOINED;
		} else if (event->iType==MUCC_EVENT_STATUS && event->dwData==ID_STATUS_OFFLINE) {
			ied.iType = IEED_MUCC_EVENT_LEFT;
		} else if (event->iType==MUCC_EVENT_TOPIC) {
			ied.iType = IEED_MUCC_EVENT_TOPIC;
		} else if (event->iType==MUCC_EVENT_ERROR) {
			ied.iType = IEED_MUCC_EVENT_ERROR;
		}
		ied.dwFlags = getOptions() & FLAG_FORMAT_ALL;
		ied.next = NULL;
		ied.color = event->color;
		ied.fontSize = event->iFontSize;
		ied.fontStyle = event->dwFlags;
		ied.fontName = getFontName(event->iFont);
		ied.pszNick = event->pszNick;
		ied.pszText = event->pszText;
		ied.time = event->time;
		ied.dwData = getOptions(); // event->dwData;
		ied.bIsMe = event->bIsMe;
		CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&iee);

		iew.cbSize = sizeof(IEVIEWWINDOW);
		iew.iType = IEW_SCROLLBOTTOM;
		iew.hwnd = hWndLog;
		CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&iew);
		return 1;
	}
	rtf = NULL;
	fontTimestamp = FontList::getFont(FontList::FONT_TIMESTAMP);
//	fontColon = FontList::getFont(FontList::FONT_COLON);
	if (event->iType == MUCC_EVENT_MESSAGE) {
		escapedStr=JabberRtfEscape((char *)event->pszText);
		escapedNick=JabberRtfEscape((char *)event->pszNick);
		if (event->bIsMe) {
			fontName = FontList::getFont(FontList::FONT_MYNAME);
			fontMessage = FontList::getFont(FontList::FONT_OUTMESSAGE);
		} else {
			fontName = FontList::getFont(FontList::FONT_OTHERSNAMES);
			fontMessage = FontList::getFont(FontList::FONT_INMESSAGE);
		}
	} else {
		fontName = FontList::getFont(FontList::FONT_ERROR);
		if (event->iType == MUCC_EVENT_ERROR) {
			escapedStr = JabberRtfEscape((char *)event->pszText);
			fontMessage = FontList::getFont(FontList::FONT_ERROR);
		} else if (event->iType == MUCC_EVENT_STATUS) {
			if (event->dwData == ID_STATUS_ONLINE) {
				fontMessage = FontList::getFont(FontList::FONT_JOINED);
				_snprintf(str, sizeof(str), Translate("%s has joined."), event->pszNick);
			} else {
				fontMessage = FontList::getFont(FontList::FONT_LEFT);
				_snprintf(str, sizeof(str), Translate("%s has left."), event->pszNick);
			}
			escapedStr = JabberRtfEscape(str);
		} else if (event->iType == MUCC_EVENT_TOPIC) {
			fontMessage = FontList::getFont(FontList::FONT_TOPIC);
			_snprintf(str, sizeof(str), Translate("The topic is %s."), event->pszText);
			escapedStr = JabberRtfEscape(str);
		}
	}
	//ltime = localtime(&event->time);
	JabberStringAppend(&rtf, &msgSize, "{\\rtf1\\ansi\\deff0{\\fonttbl");
	JabberStringAppend(&rtf, &msgSize, "{\\f0\\fnil\\fcharset%u %s;}", fontTimestamp->getCharSet(), fontTimestamp->getFace());
	JabberStringAppend(&rtf, &msgSize, "{\\f1\\fnil\\fcharset%u %s;}", fontName->getCharSet(), fontName->getFace());
	if (event->iType == MUCC_EVENT_MESSAGE && getOptions()&FLAG_FORMAT_FONT) {
		JabberStringAppend(&rtf, &msgSize, "{\\f2\\fnil\\fcharset%u %s;}", fontMessage->getCharSet(), getFontName(event->iFont));
	} else {
		JabberStringAppend(&rtf, &msgSize, "{\\f2\\fnil\\fcharset%u %s;}", fontMessage->getCharSet(), fontMessage->getFace());
	}
	JabberStringAppend(&rtf, &msgSize, "}{\\colortbl ");
	color = fontTimestamp->getColor();
	JabberStringAppend(&rtf, &msgSize, "\\red%d\\green%d\\blue%d;", color&0xFF, (color>>8)&0xFF, (color>>16)&0xFF);
	color = fontName->getColor();
	JabberStringAppend(&rtf, &msgSize, "\\red%d\\green%d\\blue%d;", color&0xFF, (color>>8)&0xFF, (color>>16)&0xFF);
	if (event->iType == MUCC_EVENT_MESSAGE && getOptions()&FLAG_FORMAT_COLOR && event->color!=0xFFFFFFFF) {
		color = event->color;
	} else {
		color = fontMessage->getColor();
	}
	JabberStringAppend(&rtf, &msgSize, "\\red%d\\green%d\\blue%d;", color&0xFF, (color>>8)&0xFF, (color>>16)&0xFF);
	JabberStringAppend(&rtf, &msgSize, "}\\pard");
	if (!isEmpty) {
		JabberStringAppend(&rtf, &msgSize, "\\par");
	}
	isEmpty = false;
	if (event->iType == MUCC_EVENT_MESSAGE) {
		if (getOptions()&FLAG_SHOW_DATE || getOptions()&FLAG_SHOW_TIMESTAMP) {
			bBold = fontTimestamp->getStyle() & Font::BOLD ? 1 : 0;
			bItalic = fontTimestamp->getStyle() & Font::ITALIC ? 1 : 0;
			bUnderline = fontTimestamp->getStyle() & Font::UNDERLINE ? 1 : 0;
			iFontSize = fontTimestamp->getSize();
			iFontSize = 2 * abs((signed char)iFontSize) * 74 / logPixelSY;
			dbtts.cbDest = 90;
			dbtts.szDest = timestampStr;
			timestampStr[0]='\0';
			//time_t time = time
			if (getOptions()&FLAG_SHOW_DATE && getOptions()&FLAG_SHOW_TIMESTAMP) {
				if (getOptions()&FLAG_LONG_DATE) {
					dbtts.szFormat = getOptions()&FLAG_SHOW_SECONDS ? (char *)"D s" : (char *)"D t";
				} else {
					dbtts.szFormat = getOptions()&FLAG_SHOW_SECONDS ? (char *)"d s" : (char *)"d t";
				}
			} else if (getOptions()&FLAG_SHOW_DATE) {
				dbtts.szFormat = getOptions()&FLAG_LONG_DATE ? (char *)"D" : (char *)"d";
			} else if (getOptions()&FLAG_SHOW_TIMESTAMP) {
				dbtts.szFormat = getOptions()&FLAG_SHOW_SECONDS ? (char *)"s" : (char *)"t";
			} else {
				dbtts.szFormat = (char *)"";
			}
			CallService(MS_DB_TIME_TIMESTAMPTOSTRING, (WPARAM)event->time, (LPARAM) & dbtts);
			JabberStringAppend(&rtf, &msgSize, "\\f0\\cf0\\fs%d\\b%d\\i%d%s %s ",
									iFontSize,
									bBold,
									bItalic,
									bUnderline?"\\ul":"",
									timestampStr);
		}
		bBold = fontName->getStyle() & Font::BOLD ? 1 : 0;
		bItalic = fontName->getStyle() & Font::ITALIC ? 1 : 0;
		bUnderline = fontName->getStyle() & Font::UNDERLINE ? 1 : 0;
		iFontSize = fontName->getSize();
		iFontSize = 2 * abs((signed char)iFontSize) * 74 / logPixelSY;
		if (getOptions()&FLAG_SHOW_NICKNAMES) {
			JabberStringAppend(&rtf, &msgSize, "\\f1\\cf1\\fs%d\\b%d\\i%d%s %s: ",
								iFontSize,
								bBold,
								bItalic,
								bUnderline?"\\ul":"",
								escapedNick);
		}
		bBold = fontMessage->getStyle() & Font::BOLD ? 1 : 0;
		bItalic = fontMessage->getStyle() & Font::ITALIC ? 1 : 0;
		bUnderline = fontMessage->getStyle() & Font::UNDERLINE ? 1 : 0;
		iFontSize = fontMessage->getSize();
		iFontSize = 2 * abs((signed char)iFontSize) * 74 / logPixelSY;
		if (getOptions()&FLAG_FORMAT_STYLE) {
			bBold = bItalic = bUnderline = 0;
			if (event->dwFlags & MUCC_EF_FONT_BOLD) bBold = 1;
			if (event->dwFlags & MUCC_EF_FONT_ITALIC) bItalic = 1;
			if (event->dwFlags & MUCC_EF_FONT_UNDERLINE) bUnderline = 1;
		}
		if (getOptions()&FLAG_FORMAT_SIZE) {
			if (event->iFontSize != 0) iFontSize = 2 * event->iFontSize;
		}
		if (getOptions()&FLAG_MSGINNEWLINE) {
			JabberStringAppend(&rtf, &msgSize, "\\line");
		}
		JabberStringAppend(&rtf, &msgSize, "\\f2\\cf2\\fs%d\\b%d\\i%d%s %s",
								iFontSize,
								bBold,
								bItalic,
								bUnderline?"\\ul":"",
								escapedStr);
	} else {
		if (event->iType == MUCC_EVENT_ERROR) {
			bBold = fontName->getStyle() & Font::BOLD ? 1 : 0;
			bItalic = fontName->getStyle() & Font::ITALIC ? 1 : 0;
			bUnderline = fontName->getStyle() & Font::UNDERLINE ? 1 : 0;
			iFontSize = fontName->getSize();
			iFontSize = 2 * abs((signed char)iFontSize) * 74 / logPixelSY;
			JabberStringAppend(&rtf, &msgSize, "\\f1\\cf1\\fs%d\\b%d\\i%d%s %s: ",
									iFontSize,
									bBold,
									bItalic,
									bUnderline?"\\ul":"",
									Translate("Error"));
		} else {
			if (getOptions()&FLAG_SHOW_DATE || getOptions()&FLAG_SHOW_TIMESTAMP) {
				bBold = fontTimestamp->getStyle() & Font::BOLD ? 1 : 0;
				bItalic = fontTimestamp->getStyle() & Font::ITALIC ? 1 : 0;
				bUnderline = fontTimestamp->getStyle() & Font::UNDERLINE ? 1 : 0;
				iFontSize = fontTimestamp->getSize();
				iFontSize = 2 * abs((signed char)iFontSize) * 74 / logPixelSY;
				dbtts.cbDest = 90;
				dbtts.szDest = timestampStr;
				timestampStr[0]='\0';
				//time_t time = time
				if (getOptions()&FLAG_SHOW_DATE && getOptions()&FLAG_SHOW_TIMESTAMP) {
					if (getOptions()&FLAG_LONG_DATE) {
						dbtts.szFormat = getOptions()&FLAG_SHOW_SECONDS ? (char *)"D s" : (char *)"D t";
					} else {
						dbtts.szFormat = getOptions()&FLAG_SHOW_SECONDS ? (char *)"d s" : (char *)"d t";
					}
				} else if (getOptions()&FLAG_SHOW_DATE) {
					dbtts.szFormat = getOptions()&FLAG_LONG_DATE ? (char *)"D" : (char *)"d";
				} else if (getOptions()&FLAG_SHOW_TIMESTAMP) {
					dbtts.szFormat = getOptions()&FLAG_SHOW_SECONDS ? (char *)"s" : (char *)"t";
				} else {
					dbtts.szFormat = (char *)"";
				}
				CallService(MS_DB_TIME_TIMESTAMPTOSTRING, (WPARAM)event->time, (LPARAM) & dbtts);
				JabberStringAppend(&rtf, &msgSize, "\\f0\\cf0\\fs%d\\b%d\\i%d%s %s ",
										iFontSize,
										bBold,
										bItalic,
										bUnderline?"\\ul":"",
										timestampStr);
			}
		}
		bBold = fontMessage->getStyle() & Font::BOLD ? 1 : 0;
		bItalic = fontMessage->getStyle() & Font::ITALIC ? 1 : 0;
		bUnderline = fontMessage->getStyle() & Font::UNDERLINE ? 1 : 0;
		iFontSize = fontMessage->getSize();
		iFontSize = 2 * abs((signed char)iFontSize) * 74 / logPixelSY;
		JabberStringAppend(&rtf, &msgSize, "\\f2\\cf2\\fs%d\\b%d\\i%d%s %s",
								iFontSize,
								bBold,
								bItalic,
								bUnderline?"\\ul":"",
								escapedStr);
	}
	JabberStringAppend(&rtf, &msgSize, "}");
	hwndLog = GetDlgItem(getHWND(), IDC_LOG);
	sel.cpMin = sel.cpMax = GetWindowTextLength(hwndLog);
	SendMessage(hwndLog, EM_EXSETSEL, 0, (LPARAM) &sel);
	stt.flags = ST_SELECTION;
	stt.codepage = CP_ACP;
	SendMessage(hwndLog, EM_SETTEXTEX, (WPARAM) &stt, (LPARAM) rtf);
	free(rtf);
	if (escapedStr!=NULL) free(escapedStr);
	if (escapedNick!=NULL) free(escapedNick);
	return 1;
}

void ChatWindow::setFont(int font, int size, int bBold, int bItalic, int bUnderline, COLORREF color) {
	if (hEditFont!=NULL) {
		DeleteObject(hEditFont);
	}
	hEditFont = CreateFontA(MulDiv(-size, logPixelSY, 74), 0, 0, 0, bBold?FW_BOLD:FW_NORMAL,
                                    bItalic, bUnderline, 0, 238, OUT_DEFAULT_PRECIS,
                                    CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
                                    FIXED_PITCH | FF_ROMAN,
                                    getFontName(font));
	SendDlgItemMessage(hWnd, IDC_EDIT, WM_SETFONT, (WPARAM) hEditFont, TRUE);
	this->font = font;
	this->fontSize = size;
	this->bBold = bBold;
	this->bItalic = bItalic;
	this->bUnderline = bUnderline;
	this->fontColor = color;
}

int ChatWindow::getFontStyle() {
	int style = 0;
	if (bBold) style |= MUCC_EF_FONT_BOLD;
	if (bItalic) style |= MUCC_EF_FONT_ITALIC;
	if (bUnderline) style |= MUCC_EF_FONT_UNDERLINE;
	return style;
}

int ChatWindow::getFont() {
	return font;
}

int ChatWindow::getFontSize() {
	return fontSize;
}

COLORREF ChatWindow::getFontColor() {
	return fontColor;
}

void ChatWindow ::queryResultContacts(MUCCQUERYRESULT *queryResult) {
	HelperDialog::inviteDlg(this, queryResult);
}

void ChatWindow ::queryResultUsers(MUCCQUERYRESULT *queryResult) {
	if (adminWindow!=NULL) {
		adminWindow->queryResultUsers(queryResult);
	}
}

ChatWindow * ChatWindow::getWindow(const char *module, const char *roomId) {
	ChatWindow *ptr;
	EnterCriticalSection(&mutex);
	for (ptr=list;ptr!=NULL;ptr=ptr->getNext()) {
		if (strcmp(ptr->getRoomId(), roomId)==0 && strcmp(ptr->getModule(), module)==0) {
			break;
		}
	}
	LeaveCriticalSection(&mutex);
	return ptr;
}


static DWORD CALLBACK EditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
{
    char *szFilename = (char *)dwCookie;
    FILE *file;
	file = fopen(szFilename, "ab");
	if (file != NULL) {
		*pcb = (LONG)fwrite(pbBuff, (size_t)cb, (size_t)1, file);
		fclose(file);
		return 0;
	}
    return 1;
}

static BOOL CALLBACK EditWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	ChatWindow *chat;
	chat = (ChatWindow *) GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
	switch (msg) {
//	case WM_GETDLGCODE:
//		return DLGC_WANTALLKEYS; //DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTALLKEYS;
	case WM_CHAR:
		if (wParam=='\r' || wParam=='\n') {
			if (((GetKeyState(VK_CONTROL)&0x8000)==0) == ((Options::getChatWindowOptions() & ChatWindow::FLAG_OPT_SENDONENTER) != 0)) {
				PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0);
				return FALSE;
			}
		}
		if (wParam == 1 && GetKeyState(VK_CONTROL) & 0x8000) {      //ctrl-a
			SendMessage(hwnd, EM_SETSEL, 0, -1);
			return 0;
		}
		if (wParam == 23 && GetKeyState(VK_CONTROL) & 0x8000) {     // ctrl-w
			SendMessage(GetParent(hwnd), WM_CLOSE, 0, 0);
			return 0;
		}
		break;
	}
	return CallWindowProc(oldEditWndProc, hwnd, msg, wParam, lParam);
}

static BOOL CALLBACK SplitterWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	ChatWindow *chat;
	chat = (ChatWindow *) GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
	switch (msg) {
	case WM_NCHITTEST:
		return HTCLIENT;
	case WM_SETCURSOR:
		RECT rc;
		GetClientRect(hwnd, &rc);
		SetCursor(rc.right > rc.bottom ? hCurSplitNS : hCurSplitWE);
		return TRUE;
	case WM_LBUTTONDOWN:
		SetCapture(hwnd);
		return 0;
	case WM_MOUSEMOVE:
		if (GetCapture() == hwnd) {
			HWND hParent;
			RECT rc;
			POINT pt;
			hParent = GetParent(hwnd);
			GetClientRect(hwnd, &rc);
			if (rc.right < rc.bottom) {
				pt.x = LOWORD(GetMessagePos());
				GetClientRect(hParent, &rc);
				ScreenToClient(hParent, &pt);
				if (pt.x < chat->vSplitterMinLeft)
					pt.x = chat->vSplitterMinLeft;
				if (rc.right-pt.x < chat->vSplitterMinRight)
					pt.x = rc.right-chat->vSplitterMinRight;
				if (chat->vSplitterPos != rc.right-pt.x) {
					chat->vSplitterPos = rc.right-pt.x;
					SendMessage(hParent, WM_SIZE, SIZE_RESTORED, (rc.bottom<<16)+rc.right);
				}
			} else {
				pt.y = HIWORD(GetMessagePos());
				GetClientRect(hParent, &rc);
				ScreenToClient(hParent, &pt);
				if (pt.y < chat->hSplitterMinTop)
					pt.y = chat->hSplitterMinTop;
				if (rc.bottom-pt.y < chat->hSplitterMinBottom)
					pt.y = rc.bottom-chat->hSplitterMinBottom;
				if (chat->hSplitterPos != rc.bottom-pt.y) {
					chat->hSplitterPos = rc.bottom-pt.y;
					SendMessage(hParent, WM_SIZE, SIZE_RESTORED, (rc.bottom<<16)+rc.right);
				}
			}
		}
		return 0;
	case WM_LBUTTONUP:
		ReleaseCapture();
		return 0;
	}
	return CallWindowProc(oldSplitterWndProc, hwnd, msg, wParam, lParam);
}




static INT_PTR CALLBACK LogDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	int i;
	ChatWindow *chatWindow;
	chatWindow = (ChatWindow *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
	if (msg!=WM_INITDIALOG && chatWindow==NULL) {
		return FALSE;
	}
	switch (msg) {
		case WM_INITDIALOG:
			HDC hdc;
			TranslateDialogDefault(hwndDlg);
			hdc = GetDC(NULL);
		    logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
		    ReleaseDC(NULL, hdc);
			SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM) muccIcon[MUCC_IDI_CHAT]);

			chatWindow = (ChatWindow *) lParam;
			chatWindow->setHWND(hwndDlg);
			ChatWindow::refreshSettings(0);
			oldSplitterWndProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_HSPLIT), GWLP_WNDPROC, (LONG_PTR) SplitterWndProc);
			oldSplitterWndProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_VSPLIT), GWLP_WNDPROC, (LONG_PTR) SplitterWndProc);
			oldEditWndProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EDIT), GWLP_WNDPROC, (LONG_PTR) EditWndProc);
			ShowWindow(GetDlgItem(hwndDlg, IDC_LIST), SW_HIDE);
			chatWindow->hSplitterMinTop = 90;
			chatWindow->hSplitterMinBottom = 40;
			chatWindow->hSplitterPos=50;
			chatWindow->vSplitterMinLeft = 100;
			chatWindow->vSplitterMinRight = 80;
			chatWindow->vSplitterPos=110;
			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) chatWindow);
			SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EDIT), GWLP_USERDATA, (LONG_PTR) chatWindow);
			chatWindow->refreshSettings();

			SetWindowTextA(hwndDlg, chatWindow->getRoomName());
			SendDlgItemMessage(hwndDlg, IDC_BOLD, BM_SETIMAGE, IMAGE_ICON, (LPARAM) muccIcon[MUCC_IDI_BOLD]);
			SendDlgItemMessage(hwndDlg, IDC_ITALIC, BM_SETIMAGE, IMAGE_ICON, (LPARAM) muccIcon[MUCC_IDI_ITALIC]);
			SendDlgItemMessage(hwndDlg, IDC_UNDERLINE, BM_SETIMAGE, IMAGE_ICON, (LPARAM) muccIcon[MUCC_IDI_UNDERLINE]);
			SendDlgItemMessage(hwndDlg, IDC_SMILEYBTN, BM_SETIMAGE, IMAGE_ICON, (LPARAM) muccIcon[MUCC_IDI_SMILEY]);

			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETEVENTMASK, 0, ENM_MOUSEEVENTS | ENM_LINK);
			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_SETUNDOLIMIT, 0, 0);
			SendDlgItemMessage(hwndDlg, IDC_LOG, EM_AUTOURLDETECT, (WPARAM) TRUE, 0);

			//	LoadImage(hInst, smadd_iconinfo.SmileyIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0));
			SendDlgItemMessage(hwndDlg, IDC_OPTIONS, BM_SETIMAGE, IMAGE_ICON, (LPARAM) muccIcon[MUCC_IDI_OPTIONS]);
			SendDlgItemMessage(hwndDlg, IDC_INVITE, BM_SETIMAGE, IMAGE_ICON, (LPARAM) muccIcon[MUCC_IDI_INVITE]);

			SendDlgItemMessage(hwndDlg, IDC_TOPIC_BUTTON, BUTTONSETASFLATBTN, 0, 0);
			SendDlgItemMessage(hwndDlg, IDC_INVITE, BUTTONSETASFLATBTN, 0, 0);
			SendDlgItemMessage(hwndDlg, IDC_BOLD, BUTTONSETASFLATBTN, 0, 0);
			SendDlgItemMessage(hwndDlg, IDC_BOLD, BUTTONSETASPUSHBTN, 0, 0);
			SendDlgItemMessage(hwndDlg, IDC_ITALIC, BUTTONSETASFLATBTN, 0, 0);
			SendDlgItemMessage(hwndDlg, IDC_ITALIC, BUTTONSETASPUSHBTN, 0, 0);
			SendDlgItemMessage(hwndDlg, IDC_UNDERLINE, BUTTONSETASFLATBTN, 0, 0);
			SendDlgItemMessage(hwndDlg, IDC_UNDERLINE, BUTTONSETASPUSHBTN, 0, 0);
			SendDlgItemMessage(hwndDlg, IDC_OPTIONS, BUTTONSETASFLATBTN, 0, 0);
			SendDlgItemMessage(hwndDlg, IDC_SMILEYBTN, BUTTONSETASFLATBTN, 0, 0);

			SetWindowLong(GetDlgItem(hwndDlg,IDC_TREELIST),GWL_STYLE,GetWindowLong(GetDlgItem(hwndDlg,IDC_TREELIST),GWL_STYLE)|TVS_NOHSCROLL);
			SendDlgItemMessage(hwndDlg,IDC_TREELIST, CCM_SETVERSION,(WPARAM)5,0);
			//TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TREELIST), hImageList, TVSIL_STATE);
			TreeView_SetItemHeight(GetDlgItem(hwndDlg, IDC_TREELIST), 16);
			TreeView_SetIndent(GetDlgItem(hwndDlg, IDC_TREELIST), 16);
			for(i=0;i<chatWindow->getFontSizeNum();i++) {
				char str[10];
				sprintf(str, "%d", chatWindow->getFontSize(i));
				int n = SendDlgItemMessageA(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM) str);
				SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_SETITEMDATA, n, chatWindow->getFontSize(i));
			}
			SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_SETCURSEL, Options::getChatWindowFontSize(), 0);
			for(i=0;i<chatWindow->getFontNameNum();i++) {
				int n = SendDlgItemMessageA(hwndDlg, IDC_FONT, CB_ADDSTRING, 0, (LPARAM) chatWindow->getFontName(i));
				SendDlgItemMessage(hwndDlg, IDC_FONT, CB_SETITEMDATA, n, i);
			}
			SendDlgItemMessage(hwndDlg, IDC_FONT, CB_SETCURSEL, Options::getChatWindowFont(), 0);
			CheckDlgButton(hwndDlg, IDC_BOLD, Options::getChatWindowFontStyle()&Font::BOLD ? TRUE : FALSE);
			CheckDlgButton(hwndDlg, IDC_ITALIC, Options::getChatWindowFontStyle()&Font::ITALIC ? TRUE : FALSE);
			CheckDlgButton(hwndDlg, IDC_UNDERLINE, Options::getChatWindowFontStyle()&Font::UNDERLINE ? TRUE : FALSE);
			SendDlgItemMessage(hwndDlg, IDC_COLOR, CPM_SETCOLOUR, 0, (LPARAM)Options::getChatWindowFontColor());
			chatWindow->setFont(Options::getChatWindowFont(),
								chatWindow->getFontSize(Options::getChatWindowFontSize()),
								Options::getChatWindowFontStyle()&Font::BOLD ? 1 : 0,
								Options::getChatWindowFontStyle()&Font::ITALIC ? 1 : 0,
								Options::getChatWindowFontStyle()&Font::UNDERLINE ? 1 : 0,
								Options::getChatWindowFontColor());
			if (ServiceExists(MS_IEVIEW_WINDOW) && Options::getChatWindowOptions() & ChatWindow::FLAG_OPT_ENABLEIEVIEW) {
				IEVIEWWINDOW ieWindow;
				ieWindow.cbSize = sizeof(IEVIEWWINDOW);
				ieWindow.iType = IEW_CREATE;
				ieWindow.dwFlags = 0;
				ieWindow.dwMode = IEWM_MUCC;
				ieWindow.parent = hwndDlg;
				ieWindow.x = 0;
				ieWindow.y = 0;
				ieWindow.cx = 200;
				ieWindow.cy = 300;
				CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
				chatWindow->setHWNDLog(ieWindow.hwnd);
				ShowWindow(GetDlgItem(hwndDlg, IDC_LOG), SW_HIDE);
			}
			SetWindowPos(hwndDlg, HWND_TOP, 0, 0, 540, 370, SWP_NOMOVE | SWP_SHOWWINDOW);
			SetFocus(GetDlgItem(hwndDlg, IDC_EDIT));
			chatWindow->clearLog();
			SetEvent(chatWindow->getEvent());
			return TRUE;
		break;
		case DM_CHAT_EVENT:
			MUCCEVENT *mucEvent;
			mucEvent = (MUCCEVENT *) lParam;
			switch (mucEvent->iType) {
				case MUCC_EVENT_MESSAGE:
					chatWindow->logEvent(mucEvent);
					break;
				case MUCC_EVENT_TOPIC:
					chatWindow->changeTopic(mucEvent);
					break;
				case MUCC_EVENT_STATUS:
					chatWindow->changePresence(mucEvent);
					break;
				case MUCC_EVENT_ERROR:
					chatWindow->logEvent(mucEvent);
					break;
				//case MUCC_EVENT_LEAVE:
			//		DestroyWindow(hwndDlg);
			//		break;
				case MUCC_EVENT_ROOM_INFO:
					chatWindow->changeRoomInfo(mucEvent);
					break;
			}
			return TRUE;
		case DM_CHAT_QUERY:
			MUCCQUERYRESULT *queryResult;
			queryResult = (MUCCQUERYRESULT *)lParam;
			switch (queryResult->iType) {
				case MUCC_EVENT_QUERY_CONTACTS:
					chatWindow->queryResultContacts(queryResult);
					break;
				case MUCC_EVENT_QUERY_USERS:
					chatWindow->queryResultUsers(queryResult);
					break;

			}
			return TRUE;
		case WM_SETFOCUS:
			SetFocus(GetDlgItem(hwndDlg, IDC_EDIT));
			return TRUE;
		case WM_GETMINMAXINFO:
			MINMAXINFO *mmi;
			mmi = (MINMAXINFO *) lParam;
			mmi->ptMinTrackSize.x = 370;
			mmi->ptMinTrackSize.y = 130;
			return FALSE;
		case WM_SIZE:
			if (wParam!=SIZE_MINIMIZED) {
				int dlgWidth, dlgHeight;
				RECT rc;
				HDWP hdwp;
				GetClientRect(hwndDlg, &rc);
				dlgWidth = rc.right-rc.left;
				dlgHeight = rc.bottom-rc.top;
				if (dlgHeight-chatWindow->hSplitterPos < chatWindow->hSplitterMinTop) {
					chatWindow->hSplitterPos = dlgHeight-chatWindow->hSplitterMinTop;
				}
				if (chatWindow->hSplitterPos < chatWindow->hSplitterMinBottom) {
					chatWindow->hSplitterPos = chatWindow->hSplitterMinBottom;
				}
				if (dlgWidth-chatWindow->vSplitterPos < chatWindow->vSplitterMinLeft) {
					chatWindow->vSplitterPos = dlgWidth-chatWindow->vSplitterMinLeft;
				}
				if (chatWindow->vSplitterPos < chatWindow->vSplitterMinRight) {
					chatWindow->vSplitterPos = chatWindow->vSplitterMinRight;
				}

				hdwp = BeginDeferWindowPos(15);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_TOPIC), 0, 70, 7, dlgWidth-140, 18, SWP_NOZORDER);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_LOG), 0, 0, 30, dlgWidth-(chatWindow->vSplitterPos)-2, dlgHeight-(chatWindow->hSplitterPos)-30-26-2, SWP_NOZORDER);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_TREELIST), 0, dlgWidth-(chatWindow->vSplitterPos)+2, 30, (chatWindow->vSplitterPos)-2, dlgHeight-(chatWindow->hSplitterPos)-30-26-2, SWP_NOZORDER);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_EDIT), 0, 0, dlgHeight-(chatWindow->hSplitterPos)+2, dlgWidth, (chatWindow->hSplitterPos)-5, SWP_NOZORDER);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_INVITE), 0, dlgWidth-31, dlgHeight-(chatWindow->hSplitterPos)-26, 31, 24, SWP_NOZORDER);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_BOLD), 0, 0, dlgHeight-(chatWindow->hSplitterPos)-26, 24, 24, SWP_NOZORDER );
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_ITALIC), 0, 24, dlgHeight-(chatWindow->hSplitterPos)-26, 24, 24, SWP_NOZORDER );
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_UNDERLINE), 0, 48, dlgHeight-(chatWindow->hSplitterPos)-26, 24, 24, SWP_NOZORDER );
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_COLOR), 0, 73, dlgHeight-(chatWindow->hSplitterPos)-25, 22, 22, SWP_NOZORDER );
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_FONT), 0, 98, dlgHeight-(chatWindow->hSplitterPos)-24, 110, 13, SWP_NOZORDER);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_FONTSIZE), 0, 213, dlgHeight-(chatWindow->hSplitterPos)-24, 38, 13, SWP_NOZORDER);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_SMILEYBTN), 0, 265, dlgHeight-(chatWindow->hSplitterPos)-26, 24, 24, SWP_NOZORDER);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_OPTIONS), 0, dlgWidth-79, dlgHeight-(chatWindow->hSplitterPos)-26, 24, 24, SWP_NOZORDER);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_VSPLIT), 0, dlgWidth-(chatWindow->vSplitterPos)-2, 30, 4, dlgHeight-(chatWindow->hSplitterPos)-30-26-2, SWP_NOZORDER);
				hdwp = DeferWindowPos(hdwp, GetDlgItem(hwndDlg, IDC_HSPLIT), 0, 0, dlgHeight-(chatWindow->hSplitterPos)-2, dlgWidth-8, 4, SWP_NOZORDER);
				EndDeferWindowPos(hdwp);
				if (chatWindow->getHWNDLog()!=NULL) {
					IEVIEWWINDOW ieWindow;
					ieWindow.cbSize = sizeof(IEVIEWWINDOW);
					ieWindow.iType = IEW_SETPOS;
					ieWindow.parent = hwndDlg;
					ieWindow.hwnd = chatWindow->getHWNDLog();
					ieWindow.x = 0;
					ieWindow.y = 30;
					ieWindow.cx = dlgWidth-(chatWindow->vSplitterPos)-2;
					ieWindow.cy = dlgHeight-(chatWindow->hSplitterPos)-30-26-2;
					CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
				}
			}
		break;
		/*
		case WM_SYSCOMMAND:
			if (wParam == SC_CLOSE) {
				SendMessage(hwndDlg, WM_CLOSE, 1, 0);
//				muce.iType = MUCC_EVENT_LEAVE;
//				muce.pszModule =  chatWindow->getModule();
//				muce.pszID = chatWindow->getRoomId();
//				NotifyEventHooks(hHookEvent, 0,(WPARAM)&muce);
//				delete chatWindow;
				return TRUE;
			}
			break;
			*/
		case WM_CLOSE:
			//if (wParam != 1) { // esc
				//return FALSE;
			//}
			DestroyWindow(hwndDlg);
			return TRUE;
		case WM_DESTROY:
			{
				MUCCEVENT muce;
				muce.cbSize = sizeof(MUCCEVENT);
				muce.iType = MUCC_EVENT_LEAVE;
				muce.pszModule =  chatWindow->getModule();
				muce.pszID = chatWindow->getRoomId();
				NotifyEventHooks(hHookEvent, 0,(WPARAM)&muce);
				if (chatWindow->getHWNDLog()!=NULL) {
					IEVIEWWINDOW ieWindow;
					ieWindow.cbSize = sizeof(IEVIEWWINDOW);
					ieWindow.iType = IEW_DESTROY;
					ieWindow.hwnd = chatWindow->getHWNDLog();
					CallService(MS_IEVIEW_WINDOW, 0, (LPARAM)&ieWindow);
				}
				SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) NULL);
				SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_HSPLIT), GWLP_WNDPROC, (LONG_PTR) oldSplitterWndProc);
				SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_VSPLIT), GWLP_WNDPROC, (LONG_PTR) oldSplitterWndProc);
				SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_EDIT), GWLP_WNDPROC, (LONG_PTR) oldEditWndProc);
				delete chatWindow;
				break;
			}
		case WM_TLEN_SMILEY:
			if (ServiceExists(MS_SMILEYADD_REPLACESMILEYS)) {
				SMADD_RICHEDIT2 smre;
				smre.cbSize = sizeof(SMADD_RICHEDIT2);
				smre.hwndRichEditControl = GetDlgItem(hwndDlg, IDC_LOG);
				smre.Protocolname = (char *)chatWindow->getModule();
				smre.rangeToReplace = NULL;
				smre.useSounds = FALSE;
				smre.disableRedraw = FALSE;
				CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM) &smre);
			}
			break;

		case WM_COMMAND:
			switch (LOWORD(wParam)) {
				case IDC_OPTIONS:
					{
						MUCCEVENT muce;
						HMENU hMenu;
						RECT rc;
						int iSelection;
						hMenu=GetSubMenu(LoadMenu(hInst, MAKEINTRESOURCE(IDR_CHATOPTIONS)),0);
						CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hMenu,0);
						GetWindowRect(GetDlgItem(hwndDlg, IDC_OPTIONS), &rc);
						CheckMenuItem(hMenu, ID_OPTIONMENU_SHOWNICKNAMES, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_SHOW_NICKNAMES ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_MSGINNEWLINE, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_MSGINNEWLINE ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_SHOWDATE, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_SHOW_DATE ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_SHOWTIMESTAMP, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_SHOW_TIMESTAMP ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_SHOWSECONDS, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_SHOW_SECONDS ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_USELONGDATE, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_LONG_DATE ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_FORMATFONT, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_FORMAT_FONT ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_FORMATSIZE, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_FORMAT_SIZE  ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_FORMATCOLOR, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_FORMAT_COLOR ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_FORMATSTYLE, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_FORMAT_STYLE ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_LOGMESSAGES, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_LOG_MESSAGES  ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_LOGJOINED, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_LOG_JOINED ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_LOGLEFT, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_LOG_LEFT ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_LOGTOPIC, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_LOG_TOPIC ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_FLASHMESSAGES, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_FLASH_MESSAGES  ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_FLASHJOINED, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_FLASH_JOINED ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_FLASHLEFT, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_FLASH_LEFT ? MF_CHECKED : MF_UNCHECKED);
						CheckMenuItem(hMenu, ID_OPTIONMENU_FLASHTOPIC, MF_BYCOMMAND | chatWindow->getOptions()&ChatWindow::FLAG_FLASH_TOPIC ? MF_CHECKED : MF_UNCHECKED);
						if (chatWindow->getMe()!=NULL) {
							if (chatWindow->getMe()->getFlags() & (MUCC_EF_USER_OWNER | MUCC_EF_USER_ADMIN)) {
								EnableMenuItem(hMenu, ID_ADMINMENU_ADMIN, MF_BYCOMMAND | MF_ENABLED);
								EnableMenuItem(hMenu, ID_ADMINMENU_BROWSE, MF_BYCOMMAND | MF_ENABLED);
							}
							if (chatWindow->getMe()->getFlags() & MUCC_EF_USER_OWNER) {
								EnableMenuItem(hMenu, ID_ADMINMENU_DESTROY, MF_BYCOMMAND | MF_ENABLED);
							}
						}
						iSelection = TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_TOPALIGN | TPM_LEFTALIGN, rc.left, rc.bottom, 0, hwndDlg, NULL);
						DestroyMenu(hMenu);
						switch (iSelection) {
							case ID_OPTIONMENU_SHOWNICKNAMES:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_SHOW_NICKNAMES);
								break;
							case ID_OPTIONMENU_MSGINNEWLINE:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_MSGINNEWLINE);
								break;
							case ID_OPTIONMENU_SHOWDATE:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_SHOW_DATE);
								break;
							case ID_OPTIONMENU_SHOWTIMESTAMP:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_SHOW_TIMESTAMP);
								break;
							case ID_OPTIONMENU_SHOWSECONDS:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_SHOW_SECONDS);
								break;
							case ID_OPTIONMENU_USELONGDATE:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_LONG_DATE);
								break;
							case ID_OPTIONMENU_FORMATFONT:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_FORMAT_FONT);
								break;
							case ID_OPTIONMENU_FORMATSIZE:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_FORMAT_SIZE);
								break;
							case ID_OPTIONMENU_FORMATCOLOR:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_FORMAT_COLOR);
								break;
							case ID_OPTIONMENU_FORMATSTYLE:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_FORMAT_STYLE);
								break;
							case ID_OPTIONMENU_LOGMESSAGES:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_LOG_MESSAGES);
								break;
							case ID_OPTIONMENU_LOGJOINED:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_LOG_JOINED);
								break;
							case ID_OPTIONMENU_LOGLEFT:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_LOG_LEFT);
								break;
							case ID_OPTIONMENU_LOGTOPIC:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_LOG_TOPIC);
								break;
							case ID_OPTIONMENU_FLASHMESSAGES:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_FLASH_MESSAGES);
								break;
							case ID_OPTIONMENU_FLASHJOINED:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_FLASH_JOINED);
								break;
							case ID_OPTIONMENU_FLASHLEFT:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_FLASH_LEFT);
								break;
							case ID_OPTIONMENU_FLASHTOPIC:
								chatWindow->setOptions(chatWindow->getOptions()^ChatWindow::FLAG_FLASH_TOPIC);
								break;
							case ID_OPTIONMENU_SAVEDEFAULT:
								Options::setChatWindowOptions(chatWindow->getOptions());
								Options::setChatWindowFont((int)SendDlgItemMessage(hwndDlg, IDC_FONT, CB_GETCURSEL, 0, 0));
								Options::setChatWindowFontSize((int)SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETCURSEL, 0, 0));
								Options::setChatWindowFontStyle(
									(IsDlgButtonChecked(hwndDlg, IDC_BOLD) ? Font::BOLD : 0) |
									(IsDlgButtonChecked(hwndDlg, IDC_ITALIC) ? Font::ITALIC : 0) |
									(IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE) ? Font::UNDERLINE : 0)
									);
								Options::setChatWindowFontColor((COLORREF) SendDlgItemMessage(hwndDlg, IDC_COLOR, CPM_GETCOLOUR,0,0));
								Options::saveSettings();
								break;
							case ID_ADMINMENU_DESTROY:
								muce.cbSize = sizeof(MUCCEVENT);
								muce.iType = MUCC_EVENT_REMOVE_ROOM;
								muce.pszModule = chatWindow->getModule();
								muce.pszID = chatWindow->getRoomId();
								NotifyEventHooks(hHookEvent, 0,(WPARAM)&muce);
								DestroyWindow(hwndDlg);
								break;
							case ID_ADMINMENU_ADMIN:
								chatWindow->startAdminDialog(ChatWindow::ADMIN_MODE_KICK);
								break;
							case ID_ADMINMENU_BROWSE:
								chatWindow->startAdminDialog(ChatWindow::ADMIN_MODE_ROLE);
								break;
							case ID_ADMINMENU_SAVELOG:
								if (chatWindow->getHWNDLog()!=NULL) {
									IEVIEWEVENT iee;
									ZeroMemory(&iee, sizeof(iee));
									iee.cbSize = sizeof(iee);
									iee.dwFlags = 0;
									iee.hwnd = chatWindow->getHWNDLog();
									iee.hContact = NULL;
									iee.iType = IEE_SAVE_DOCUMENT;
									CallService(MS_IEVIEW_EVENT, 0, (LPARAM)&iee);
								} else {
									char szFilename[MAX_PATH];
									strcpy(szFilename, "");
									OPENFILENAMEA ofn={0};
									ofn.lStructSize=sizeof(OPENFILENAME);
									ofn.hwndOwner=hwndDlg;
									ofn.lpstrFile = szFilename;
									ofn.lpstrFilter = "Rich Text File\0*.rtf\0\0";
									ofn.nMaxFile = MAX_PATH;
									ofn.nMaxFileTitle = MAX_PATH;
									ofn.Flags = OFN_HIDEREADONLY;
									ofn.lpstrDefExt = "rtf";
									if (GetSaveFileNameA(&ofn)) {
										//remove(szFilename);
										EDITSTREAM stream = { 0 };
										stream.dwCookie = (DWORD_PTR)szFilename;
										stream.dwError = 0;
										stream.pfnCallback = EditStreamCallback;
										SendDlgItemMessage(hwndDlg, IDC_LOG, EM_STREAMOUT, SF_RTF | SF_USECODEPAGE, (LPARAM) & stream);
									}
								}
								break;
						}
					}
					break;
				case IDC_SMILEYBTN:
					SMADD_SHOWSEL smaddInfo;
					RECT rc;
					smaddInfo.cbSize = sizeof(SMADD_SHOWSEL);
					smaddInfo.hwndTarget = GetDlgItem(hwndDlg, IDC_EDIT);
					smaddInfo.targetMessage = EM_REPLACESEL;
					smaddInfo.targetWParam = TRUE;
					smaddInfo.Protocolname = chatWindow->getModule();
					GetWindowRect(GetDlgItem(hwndDlg, IDC_SMILEYBTN), &rc);
					smaddInfo.Direction = 0;
					smaddInfo.xPosition = rc.left;
					smaddInfo.yPosition = rc.top + 24;
					if (chatWindow->getHWNDLog() != NULL) {
						CallService(MS_IEVIEW_SHOWSMILEYSELECTION, 0, (LPARAM) &smaddInfo);
					} else {
						CallService(MS_SMILEYADD_SHOWSELECTION, 0, (LPARAM) &smaddInfo);
					}
					break;
				case IDC_INVITE:
					{
						MUCCEVENT muce;
						muce.cbSize = sizeof(MUCCEVENT);
						muce.iType = MUCC_EVENT_QUERY_CONTACTS;
						muce.pszModule = chatWindow->getModule();
						muce.pszID = chatWindow->getRoomId();
						NotifyEventHooks(hHookEvent, 0,(WPARAM)&muce);
					}
					break;
				case IDC_TOPIC_BUTTON:
					HelperDialog::topicDlg(chatWindow);
					break;
				case IDCANCEL:
					DestroyWindow(hwndDlg);
					return TRUE;
				case IDOK:
					{
						MUCCEVENT muce;
						char text[2048];
						GetDlgItemTextA(hwndDlg, IDC_EDIT, text, sizeof(text));
						SetDlgItemTextA(hwndDlg, IDC_EDIT, "");
						muce.cbSize = sizeof(MUCCEVENT);
						muce.iType = MUCC_EVENT_MESSAGE;
						muce.pszModule =  chatWindow->getModule();
						muce.pszID = chatWindow->getRoomId();
						muce.pszText = text;
						muce.iFont = chatWindow->getFont();
						muce.iFontSize = chatWindow->getFontSize();
						muce.dwFlags = chatWindow->getFontStyle();
						muce.color = chatWindow->getFontColor();
						NotifyEventHooks(hHookEvent, 0,(WPARAM)&muce);
					}
					break;
				case IDC_BOLD:
				case IDC_ITALIC:
				case IDC_UNDERLINE:
					if (HIWORD(wParam)==BN_CLICKED) {
						chatWindow->setFont((int) SendDlgItemMessage(hwndDlg, IDC_FONT, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_FONT, CB_GETCURSEL, 0, 0), 0),
												(int) SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETCURSEL, 0, 0), 0),
												IsDlgButtonChecked(hwndDlg, IDC_BOLD),
												IsDlgButtonChecked(hwndDlg, IDC_ITALIC),
												IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE),
												(COLORREF) SendDlgItemMessage(hwndDlg, IDC_COLOR, CPM_GETCOLOUR,0,0));
					}
				case IDC_FONT:
				case IDC_FONTSIZE:
					if (HIWORD(wParam)==CBN_SELCHANGE) {
						chatWindow->setFont((int) SendDlgItemMessage(hwndDlg, IDC_FONT, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_FONT, CB_GETCURSEL, 0, 0), 0),
												(int) SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETCURSEL, 0, 0), 0),
												IsDlgButtonChecked(hwndDlg, IDC_BOLD),
												IsDlgButtonChecked(hwndDlg, IDC_ITALIC),
												IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE),
												(COLORREF) SendDlgItemMessage(hwndDlg, IDC_COLOR, CPM_GETCOLOUR,0,0));
					}
					break;
				case IDC_COLOR:
					if (HIWORD(wParam)==CPN_COLOURCHANGED) {
						InvalidateRect(GetDlgItem(hwndDlg, IDC_EDIT), NULL, FALSE);
						chatWindow->setFont((int) SendDlgItemMessage(hwndDlg, IDC_FONT, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_FONT, CB_GETCURSEL, 0, 0), 0),
												(int) SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETITEMDATA, SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETCURSEL, 0, 0), 0),
												IsDlgButtonChecked(hwndDlg, IDC_BOLD),
												IsDlgButtonChecked(hwndDlg, IDC_ITALIC),
												IsDlgButtonChecked(hwndDlg, IDC_UNDERLINE),
												(COLORREF) SendDlgItemMessage(hwndDlg, IDC_COLOR, CPM_GETCOLOUR,0,0));
					}
					break;

			}
			break;
		case WM_CTLCOLOREDIT:
			if ((HWND) lParam == GetDlgItem(hwndDlg, IDC_EDIT)) {
				SetTextColor((HDC) wParam, (COLORREF) SendDlgItemMessage(hwndDlg, IDC_COLOR, CPM_GETCOLOUR,0,0));
				SetBkColor((HDC) wParam, Options::getInputBgColor());
				//SelectObject((HDC) wParam, Options::getInputBgBrush());
				return (BOOL) Options::getInputBgBrush();
			}

			break;
		case WM_NOTIFY:
			LPNMHDR pNmhdr;
			pNmhdr = (LPNMHDR)lParam;
			if (pNmhdr->idFrom == IDC_TREELIST) {
				switch (pNmhdr->code) {
				case TVN_ITEMEXPANDING:
					{
						LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lParam;
						if (pnmtv->action==TVE_COLLAPSE) {
							SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT, TRUE);
							return TRUE;
						}
					}
				break;
				case NM_RCLICK:
					{
						TVHITTESTINFO hti;
						hti.pt.x=(short)LOWORD(GetMessagePos());
						hti.pt.y=(short)HIWORD(GetMessagePos());
						ScreenToClient(pNmhdr->hwndFrom,&hti.pt);
						if(TreeView_HitTest(pNmhdr->hwndFrom, &hti) && hti.flags&TVHT_ONITEM) {
							TVITEM tvi = {0};
							tvi.mask = TVIF_PARAM|TVIF_HANDLE;
							tvi.hItem = hti.hItem;
							TreeView_GetItem(pNmhdr->hwndFrom, &tvi);
							ChatUser *user = (ChatUser *) tvi.lParam;
							if (user!=NULL) {
								TreeView_Select(pNmhdr->hwndFrom, tvi.hItem, TVGN_CARET);
								if (!user->isMe()) {
									HMENU hMenu;
									int iSelection;
									hMenu = GetSubMenu(LoadMenu(hInst, MAKEINTRESOURCE(IDR_CHATOPTIONS)),1);
									CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hMenu,0);
									if (chatWindow->getMe()!=NULL) {
										if (chatWindow->getMe()->getFlags() & MUCC_EF_USER_OWNER) {
											EnableMenuItem(hMenu, 2, MF_BYPOSITION | MF_ENABLED);
											EnableMenuItem(hMenu, 3, MF_BYPOSITION | MF_ENABLED);
											EnableMenuItem(hMenu, ID_USERMENU_ADMINISTRATION, MF_BYCOMMAND | MF_ENABLED);

										} else if (chatWindow->getMe()->getFlags() & MUCC_EF_USER_ADMIN) {
											if (!(user->getFlags() & (MUCC_EF_USER_OWNER | MUCC_EF_USER_OWNER))) {
												EnableMenuItem(hMenu, 2, MF_BYPOSITION | MF_ENABLED);
												//EnableMenuItem(hMenu, 3, MF_BYPOSITION | MF_ENABLED);
												EnableMenuItem(hMenu, ID_USERMENU_ADMINISTRATION, MF_BYCOMMAND | MF_ENABLED);
											}
										}
									}
									//CheckMenuItem(hMenu, ID_USERMENU_MESSAGE, MF_BYCOMMAND | MF_CHECKED : MF_UNCHECKED);
									//EnableMenuItem(hMenu, ID_USERMENU_MESSAGE, MF_BYCOMMAND | MF_GRAYED);
									iSelection = TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_TOPALIGN | TPM_LEFTALIGN, (short)LOWORD(GetMessagePos()), (short)HIWORD(GetMessagePos()), 0, hwndDlg, NULL);
									DestroyMenu(hMenu);
									if (iSelection == ID_USERMENU_MESSAGE) {
										chatWindow->startPriv();
									} else if (iSelection >= ID_USERMENU_KICK_NO_BAN && iSelection <= ID_USERMENU_KICK_BAN_4_W) {
										int banTime[] = {0, 1, 5, 15, 30, 60, 360, 1440, 4320, 10080, 20160, 40320};
										chatWindow->kickAndBan(banTime[iSelection-ID_USERMENU_KICK_NO_BAN] *60);
									} else if (iSelection == ID_USERMENU_RIGHTS_MEMBER) {
										chatWindow->setRights(MUCC_EF_USER_MEMBER);
									} else if (iSelection == ID_USERMENU_RIGHTS_ADMIN) {
										chatWindow->setRights(MUCC_EF_USER_ADMIN);
									} else if (iSelection == ID_USERMENU_RIGHTS_NO) {
										chatWindow->setRights(0);
									} else if (iSelection == ID_USERMENU_ADMINISTRATION) {
										chatWindow->startAdminDialog(ChatWindow::ADMIN_MODE_KICK);
									}
								}
							}
						}

					}
					break;
				case NM_CUSTOMDRAW:
					LPNMTVCUSTOMDRAW pCustomDraw = (LPNMTVCUSTOMDRAW)lParam;
					switch (pCustomDraw->nmcd.dwDrawStage) {
						case CDDS_PREPAINT:
							SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,CDRF_NOTIFYITEMDRAW);
							return TRUE;
						case CDDS_ITEMPREPAINT:
							{
								TVITEM tvi;;
								HICON hIcon;
								TCHAR str[200];
								RECT rc = pCustomDraw->nmcd.rc;
								tvi.mask = TVIF_HANDLE | TVIF_STATE | TVIF_TEXT | TVIF_PARAM;
								tvi.pszText = str;
								tvi.cchTextMax = sizeof(str)/sizeof(TCHAR);
								tvi.hItem = (HTREEITEM)pCustomDraw->nmcd.dwItemSpec;
								TreeView_GetItem(pCustomDraw->nmcd.hdr.hwndFrom, &tvi);
								ChatUser * user= (ChatUser *)pCustomDraw->nmcd.lItemlParam;
								hIcon = NULL;
								pCustomDraw->clrTextBk = Options::getListBgColor();
								switch (pCustomDraw->iLevel) {
									case 0:
										pCustomDraw->clrText = ChatWindow::getListGroupTextColor();
										SelectObject(pCustomDraw->nmcd.hdc, ChatWindow::getListGroupFont());
										break;
									case 1:
										pCustomDraw->clrText = ChatWindow::getListTextColor();
										if (pCustomDraw->nmcd.uItemState & CDIS_SELECTED) { // selected (CDIS_FOCUS |
											pCustomDraw->clrTextBk = 0xDAC8C2;
										} else {
											pCustomDraw->clrTextBk = Options::getListBgColor();
										}
										if (user!=NULL) {
											if (user->getFlags()&MUCC_EF_USER_GLOBALOWNER) {
												hIcon = muccIcon[MUCC_IDI_U_GLOBALOWNER];
											} else if (user->getFlags()&MUCC_EF_USER_OWNER) {
												hIcon = muccIcon[MUCC_IDI_U_OWNER];
											} else if (user->getFlags()&MUCC_EF_USER_ADMIN) {
												hIcon = muccIcon[MUCC_IDI_U_ADMIN];
											} else if (user->getFlags()&MUCC_EF_USER_REGISTERED) {
												hIcon = muccIcon[MUCC_IDI_U_REGISTERED];
											}
										}
										SelectObject(pCustomDraw->nmcd.hdc, ChatWindow::getListFont());
										break;
								}
								if (rc.bottom-rc.top!=0 && rc.right-rc.left!=0) {
									HBRUSH hBr;
									hBr = CreateSolidBrush(pCustomDraw->clrTextBk);
									FillRect(pCustomDraw->nmcd.hdc, &rc, hBr);
									DeleteObject(hBr);
									if (hIcon!=NULL) {
										DrawIconEx(pCustomDraw->nmcd.hdc, rc.left, rc.top, hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL);
									}
									SetBkMode(pCustomDraw->nmcd.hdc, TRANSPARENT);
									SetTextColor(pCustomDraw->nmcd.hdc, pCustomDraw->clrText);
									TextOut(pCustomDraw->nmcd.hdc,
											rc.left+pCustomDraw->iLevel*GetSystemMetrics(SM_CXSMICON)+2,
											rc.top, tvi.pszText, (int)_tcslen(tvi.pszText));
								}
								SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT, CDRF_SKIPDEFAULT );
								return TRUE;
							}
						}
					break;
				}
			} else if (pNmhdr->idFrom == IDC_LOG) {
				switch (((NMHDR *) lParam)->code) {
				case EN_MSGFILTER:
					switch (((MSGFILTER *) lParam)->msg) {
						/*
					case WM_LBUTTONDOWN:
						{
							HCURSOR hCur = GetCursor();
							if (hCur == LoadCursor(NULL, IDC_SIZENS) || hCur == LoadCursor(NULL, IDC_SIZEWE)
								|| hCur == LoadCursor(NULL, IDC_SIZENESW) || hCur == LoadCursor(NULL, IDC_SIZENWSE)) {
									SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
									return TRUE;
								}
								break;
						}
					case WM_MOUSEMOVE:
						{
							HCURSOR hCur = GetCursor();
							if (hCur == LoadCursor(NULL, IDC_SIZENS) || hCur == LoadCursor(NULL, IDC_SIZEWE)
								|| hCur == LoadCursor(NULL, IDC_SIZENESW) || hCur == LoadCursor(NULL, IDC_SIZENWSE))
								SetCursor(LoadCursor(NULL, IDC_ARROW));
							break;
						}
						*/
					case WM_RBUTTONUP:
						{
							HMENU hMenu, hSubMenu;
							POINT pt;
							CHARRANGE sel, all = { 0, -1 };

							hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT));
							hSubMenu = GetSubMenu(hMenu, 0);
							CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hSubMenu, 0);
							SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXGETSEL, 0, (LPARAM) & sel);
							if (sel.cpMin == sel.cpMax)
								EnableMenuItem(hSubMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED);
							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_COPY:
								SendMessage(((NMHDR *) lParam)->hwndFrom, WM_COPY, 0, 0);
								break;
							case IDM_COPYALL:
								SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & all);
								SendMessage(((NMHDR *) lParam)->hwndFrom, WM_COPY, 0, 0);
								SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & sel);
								break;
							case IDM_SELECTALL:
								SendMessage(((NMHDR *) lParam)->hwndFrom, EM_EXSETSEL, 0, (LPARAM) & all);
								break;
							case IDM_CLEAR:
								chatWindow->clearLog();
								break;
							}
							DestroyMenu(hMenu);
							SetWindowLongPtr(hwndDlg, 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:
						{
							TEXTRANGEA tr;
							CHARRANGE sel;

							SendDlgItemMessage(hwndDlg, IDC_LOG, EM_EXGETSEL, 0, (LPARAM) & sel);
							if (sel.cpMin != sel.cpMax)
								break;
							tr.chrg = ((ENLINK *) lParam)->chrg;
							tr.lpstrText = (char *)malloc(tr.chrg.cpMax - tr.chrg.cpMin + 8);
							SendDlgItemMessageA(hwndDlg, IDC_LOG, EM_GETTEXTRANGE, 0, (LPARAM) & tr);
							if (strchr(tr.lpstrText, '@') != NULL && strchr(tr.lpstrText, ':') == NULL && strchr(tr.lpstrText, '/') == NULL) {
								MoveMemory(tr.lpstrText + 7, tr.lpstrText, tr.chrg.cpMax - tr.chrg.cpMin + 1);
								CopyMemory(tr.lpstrText, "mailto:", 7);
							}
							if (((ENLINK *) lParam)->msg == WM_RBUTTONDOWN) {
								HMENU hMenu, hSubMenu;
								POINT pt;

								hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT));
								hSubMenu = GetSubMenu(hMenu, 1);
								CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hSubMenu, 0);
								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_OPENNEW:
									CallService(MS_UTILS_OPENURL, 1, (LPARAM) tr.lpstrText);
									break;
								case IDM_OPENEXISTING:
									CallService(MS_UTILS_OPENURL, 0, (LPARAM) tr.lpstrText);
									break;
								case IDM_COPYLINK:
									{
										HGLOBAL hData;
										if (!OpenClipboard(hwndDlg))
											break;
										EmptyClipboard();
										hData = GlobalAlloc(GMEM_MOVEABLE, lstrlenA(tr.lpstrText) + 1);
										lstrcpyA((char *)GlobalLock(hData), tr.lpstrText);
										GlobalUnlock(hData);
										SetClipboardData(CF_TEXT, hData);
										CloseClipboard();
										break;
									}
								}
								free(tr.lpstrText);
								DestroyMenu(hMenu);
								SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
								return TRUE;
							}
							else {
								CallService(MS_UTILS_OPENURL, 1, (LPARAM) tr.lpstrText);
								SetFocus(GetDlgItem(hwndDlg, IDC_EDIT));
							}
							free(tr.lpstrText);
							break;
						}
					}
					break;
				}
			}
		break;
	}
	return FALSE;
}

static char *JabberRtfEscape(char *str) {
	char *escapedStr;
	int size;
	char *p, *q;

	if (str == NULL)
		return NULL;

	for (p=str,size=0; *p!='\0'; p++) {
		if (*p=='\\' || *p=='{' || *p=='}')
			size += 2;
		else if (*p=='\n' || *p=='\t')
			size += 5;
		else
			size++;
	}

	if ((escapedStr=(char *)malloc(size+1)) == NULL)
		return NULL;

	for (p=str,q=escapedStr; *p!='\0'; p++) {
		if (strchr("\\{}", *p) != NULL) {
			*q++ = '\\';
			*q++ = *p;
		}
		else if (*p == '\n') {
			strcpy(q, "\\par ");
			q += 5;
		}
		else if (*p == '\t') {
			strcpy(q, "\\tab ");
			q += 5;
		}
		else {
			*q++ = *p;
		}
	}
	*q = '\0';

	return escapedStr;
}

static void JabberStringAppend(char **str, int *sizeAlloced, const char *fmt, ...) {
	va_list vararg;
	char *p;
	int size, len;

	if (str == NULL) return;

	if (*str==NULL || *sizeAlloced<=0) {
		*sizeAlloced = size = 2048;
		*str = (char *) malloc(size);
		len = 0;
	}
	else {
		len = (int)strlen(*str);
		size = *sizeAlloced - (int)strlen(*str);
	}

	p = *str + len;
	va_start(vararg, fmt);
	while (_vsnprintf(p, size, fmt, vararg) == -1) {
		size += 2048;
		(*sizeAlloced) += 2048;
		*str = (char *) realloc(*str, *sizeAlloced);
		p = *str + len;
	}
	va_end(vararg);
}


//static DWORD CALLBACK Log_StreamCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG * pcb)
//{
//    StreamData *stream = (StreamData *) dwCookie;
/*
	if (lstrdat->buffer == NULL)
	{
		lstrdat->iColCount = 4;
        lstrdat->bufferOffset = 0;
		lstrdat->buffer = Log_CreateBody(lstrdat);
        lstrdat->bufferLen = lstrlen(lstrdat->buffer);
    }
    *pcb = min(cb, lstrdat->bufferLen - lstrdat->bufferOffset);
    CopyMemory(pbBuff, lstrdat->buffer + lstrdat->bufferOffset, *pcb);
    lstrdat->bufferOffset += *pcb;
    if (lstrdat->bufferOffset == lstrdat->bufferLen)
	{
	    free(lstrdat->buffer);
        lstrdat->buffer = NULL;
    }
*/
//    return 0;
//}