/*
 * This file is a part of VyQChat.
 *
 * Copyright (C) 2002-2004 Pawel Stolowski <yogin@linux.bydg.org>
 *
 * VyQChat is free software; you can redestribute it and/or modify it
 * under terms of GNU General Public License by Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY. See GPL for more details.
 */

#include "config.h"

#include "global.h"
#include "regexp.h"
#include "aboutdialog.h"
#include "appwin.h"
#include "msgsndwin.h"
#include "msgrcvwin.h"
#include "chlist.h"
#include "channelsdlg.h"
#include "ulist.h"
#include "chattab.h"
#include "chatline.h"
#include "status.h"
#include "settings.h"
#include "settingsdlg.h"
#include "topicwin.h"
#include "sound.h"
#include "icons.h"
#include "massmsgwin.h"
#include "history.h"
#include "vcprotocol.h"
#include "nickcombo.h"
#include "chatlinehist.h"
#include "scripting.h"
#include "trayicon.h"
#include <qsettings.h>
#include <qdatetime.h>
#include <qtoolbar.h>
#include <qtoolbutton.h>
#include <qtimer.h>
#include <qmessagebox.h>
#include <qapplication.h>
#include <qtextcodec.h>
#include <qaccel.h>
#include <qmenubar.h>
#include <qsocketnotifier.h>
#include <qcombobox.h>
#include <qpushbutton.h>
#include <qsplitter.h>
#include <qhbox.h>
#include <qvbox.h>
#include <qvaluelist.h>

#include <iostream>

const char *MainWindow::status_lut[] = {"Normal", "DND", "Away", "Offline"};

MainWindow::MainWindow(QWidget *parent, Settings *s): QMainWindow(parent), settings(s), exit_called(false) /*{{{*/
{
	setUsesBigPixmaps(false);
	setCaption("VyQchat");
	//setIcon(Icons::icon_user.pixmap(QIconSet::Small, true));
	setIcon(Icons::getIcon(Icons::User).pixmap(QIconSet::Small, true));
	
	QVBox *vb1 = new QVBox(this);
	QSplitter *spl = new QSplitter(vb1);
	QHBox *hb2 = new QHBox(vb1);
	hb2->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed));

	chattab = new ChatTab(spl);
	QVBox *vb2 = new QVBox(spl);

	//
	// combobox for entering nick
	nickcmb = new NickCombo(vb2);

	userslist = new UsersList(vb2);
	chatline = new ChatLine(hb2);

	connect(chattab, SIGNAL(leave(const QString&)), this, SLOT(leaveChannel(const QString&)));
	connect(nickcmb, SIGNAL(activated(const QString&)), this, SLOT(changeNick(const QString&)));
	
	//
	// enter button
	QPushButton *b_enter = new QPushButton(Icons::icon_enter, "", hb2);
	b_enter->setFixedWidth(Icons::icon_enter.pixmap(QIconSet::Large, true).width());
	connect(b_enter, SIGNAL(clicked()), this, SLOT(simulateEnter()));

	setCentralWidget(vb1);
			 
	//
	// set up menus
	// ------------

	connect(userslist, SIGNAL(sendMessage(const QString &)), this, SLOT(openSendMessage(const QString &)));
	connect(userslist, SIGNAL(requestInfo(const QString &)), this, SLOT(requestInfo(const QString &)));
	connect(userslist, SIGNAL(privateChat(const QString &)), this, SLOT(openPrivate(const QString &)));
	connect(userslist, SIGNAL(beep(const QString &)), this, SLOT(beep(const QString &)));
	connect(userslist, SIGNAL(sayNick(const QString &)), chatline, SLOT(sayNick(const QString &)));
	connect(userslist, SIGNAL(sendMassMessage(const QStringList &)), this, SLOT(openSendMassMessage(const QStringList &)));
	connect(userslist, SIGNAL(refresh()), this, SLOT(forceRefresh()));
	
	//
	// main menu
	QPopupMenu *status_menu = new QPopupMenu(this);
	QPopupMenu *chat_menu = new QPopupMenu(this);
	QPopupMenu *comm_menu = new QPopupMenu(this);
	chat_menu->insertItem(tr("Status"), status_menu);
	chat_menu->insertItem(Icons::icon_channel, tr("Channels"), this, SLOT(openChannelsDialog()));
	chat_menu->insertItem(tr("Change Topic"), this, SLOT(openTopicDialog()));
	chat_menu->insertItem(Icons::icon_comm, tr("Commands"), comm_menu);
	chat_menu->insertSeparator();
	chat_menu->insertItem(tr("Quit"), this, SLOT(exit()));

	//
	// chat -> commands menu 
	comm_menu->insertItem("/me <text>", ID_ENTER_ME);
	comm_menu->insertItem("/nick <new nick>", ID_ENTER_NICK);
	comm_menu->insertItem("/join <channel>", ID_ENTER_JOIN);
	comm_menu->insertItem("/leave", ID_ENTER_LEAVE);
	comm_menu->insertItem("/chat <nick>", ID_ENTER_CHAT);
	comm_menu->insertItem("/topic <text>", ID_ENTER_TOPIC);
	comm_menu->insertItem("/info <nick>", ID_ENTER_INFO);
	comm_menu->insertItem("/beep <nick>", ID_ENTER_BEEP);
	comm_menu->insertItem("/mass <text>", ID_ENTER_MASS);
	comm_menu->insertItem("/here", ID_ENTER_HERE);
	comm_menu->insertItem("/normal", ID_ENTER_NORMAL);
	comm_menu->insertItem("/dnd <text>", ID_ENTER_DND);
	comm_menu->insertItem("/away <text>", ID_ENTER_AWAY);
	comm_menu->insertItem("/offline <text>", ID_ENTER_OFFLINE);
	comm_menu->insertItem("/help", ID_ENTER_HELP);
	connect(comm_menu, SIGNAL(activated(int)), this, SLOT(commandMenuAction(int)));

	//
	// chat -> status menu
	status_menu->insertItem(Icons::icon_user, tr("Available"), this, SLOT(goNORMAL()));
	status_menu->insertItem(Icons::icon_user_dnd, tr("DND"), this, SLOT(openDNDdialog()));
	status_menu->insertItem(Icons::icon_user_away, tr("Away"), this, SLOT(openAWAYdialog()));
	status_menu->insertItem(Icons::icon_user_offline, tr("Offline"), this, SLOT(openOFFLINEdialog()));
	
	//
	// edit menu
	QPopupMenu *edit_menu = new QPopupMenu(this);
	edit_menu->insertItem(tr("Commands history"), this, SLOT(openChatLineHistory()));
	edit_menu->insertSeparator();
	edit_menu->insertItem(tr("Clear Chat"), chattab, SLOT(clearCurrent()));
	edit_menu->insertItem(tr("Clear Line"), chatline, SLOT(clear()));

	//
	// view menu
	view_menu = new QPopupMenu(this);
	view_menu->setCheckable(true);
	tbar_id = view_menu->insertItem(tr("Toolbar"), this, SLOT(toggleToolbar()));
	ulist_id = view_menu->insertItem(tr("Users list"), this, SLOT(toggleUsersList()));
	nickcmb_id = view_menu->insertItem(tr("Nick dialog"), this, SLOT(toggleNickCombo()));
		
	//
	// Options menu
        QPopupMenu *options_menu = new QPopupMenu(this);
	options_menu->insertItem(Icons::icon_settings, tr("Settings"), this, SLOT(openSettingsDialog()));
	options_menu->insertItem(tr("Regexp matching"), this, SLOT(openRegexpDialog()));
	
	//
	// help menu
	QPopupMenu *help_menu = new QPopupMenu(this);
	help_menu->insertItem(tr("About"), this, SLOT(popupAbout()));
	
	main_menu = menuBar();
	main_menu->insertItem(tr("&Chat"), chat_menu);
	main_menu->insertItem(tr("&Edit"), edit_menu);
	main_menu->insertItem(tr("&View"), view_menu);
	main_menu->insertItem(tr("&Options"), options_menu);
	main_menu->insertSeparator();
	main_menu->insertItem(tr("&Help"), help_menu);
	
	//
	// toolbar
	main_toolbar = new QToolBar(this, "Main toolbar");
	status_combo = new QComboBox(main_toolbar);
	status_combo->insertItem(Icons::icon_user.pixmap(QIconSet::Small, true), "Available");
	status_combo->insertItem(Icons::icon_user_dnd.pixmap(QIconSet::Small, true), "DND");
	status_combo->insertItem(Icons::icon_user_away.pixmap(QIconSet::Small, true), "Away");
	status_combo->insertItem(Icons::icon_user_offline.pixmap(QIconSet::Small, true), "Offline");
	connect(status_combo, SIGNAL(activated(int)), this, SLOT(statusComboActivated(int)));

	QToolButton *comm_button  = new QToolButton(Icons::icon_comm, tr("Commands"), QString::null, this, SLOT(menuDummy()), main_toolbar);
	comm_button->setPopup(comm_menu);
	comm_button->setPopupDelay(0);
	QToolButton *channels_button  = new QToolButton(Icons::icon_channel, "Channels", QString::null, this, SLOT(openChannelsDialog()), main_toolbar);
	QToolButton *conf_button  = new QToolButton(Icons::icon_settings, "Settings", QString::null, this, SLOT(openSettingsDialog()), main_toolbar);

	//
	// keyboard shortcuts
	
	//
	// userlist menu shortcuts
	QAccel *a1 = new QAccel(this);
	a1->insertItem(Key_F5, UsersList::ID_REFRESH);
        a1->insertItem(Key_F6, UsersList::ID_MASSMESSAGE);
	a1->insertItem(Key_Insert, UsersList::ID_MESSAGE);
	a1->insertItem(CTRL+Key_H, UsersList::ID_PRVCHAT);
	a1->insertItem(CTRL+Key_B, UsersList::ID_BEEP);
	a1->insertItem(CTRL+Key_Y, UsersList::ID_SAYNICK);
	connect(a1, SIGNAL(activated(int)), userslist, SLOT(menuAction(int)));

	//
	// command menu shortcuts
	QAccel *a2 = new QAccel(this);
	a2->insertItem(CTRL+Key_1, ID_ENTER_ME);
	a2->insertItem(CTRL+Key_2, ID_ENTER_NICK);
	a2->insertItem(CTRL+Key_3, ID_ENTER_JOIN);
	a2->insertItem(CTRL+Key_4, ID_ENTER_CHAT);
	a2->insertItem(CTRL+Key_5, ID_ENTER_TOPIC);
	a2->insertItem(CTRL+Key_7, ID_ENTER_INFO);
	a2->insertItem(CTRL+Key_8, ID_ENTER_MASS);
	a2->insertItem(CTRL+Key_9, ID_ENTER_HERE);
	connect(a2, SIGNAL(activated(int)), this, SLOT(commandMenuAction(int)));
	
	QAccel *a3 = new QAccel(this);
	a3->connectItem(a3->insertItem(CTRL+Key_S), this, SLOT(goNORMAL()));
	a3->connectItem(a3->insertItem(CTRL+Key_D), this, SLOT(openDNDdialog()));
	a3->connectItem(a3->insertItem(CTRL+Key_A), this, SLOT(openAWAYdialog()));
	a3->connectItem(a3->insertItem(CTRL+Key_F), this, SLOT(openOFFLINEdialog()));
	
	connect(chatline, SIGNAL(returnPressed()), this, SLOT(sendLine()));
	chatline->setFocus();

	availchannels = new ChannelList();

	dnd_list = settings->getDNDhistory();
	away_list = settings->getAwayHistory();
	offline_list =settings->getOfflineHistory();
	regexp_list = settings->getRegexpHistory();
	nick_list = settings->getNicksHistory();

	regexp = QRegExp(regexp_list.first());
	
	if (settings->getKeepStatus())
	{
		status = settings->getStatus();
		cancelStatusChange();
	}
	else
		status = STATUS_NORMAL;
	
	nick = settings->getNick();
	regexp_on = settings->getRegexpOn();
	gender = settings->getGender();
	remoteactive = RA_ACTIVE; 
	special_color = QColor(0xff, 0x00, 0x00);
	normal_color = QColor(0x00, 0x00, 0xff);
	own_color = QColor(0x00, 0x00, 0x00);
	
	view_menu->setItemChecked(tbar_id, settings->getTooolbarOn());
	view_menu->setItemChecked(ulist_id, settings->getUsersListOn());
	view_menu->setItemChecked(nickcmb_id, settings->getNickComboOn());
	main_toolbar->setShown(settings->getTooolbarOn());
	userslist->setShown(settings->getUsersListOn());
	nickcmb->setShown(settings->getNickComboOn());

	//
	// restore window geometry
	userslist->resize(settings->getUsersListWidth(), userslist->height());
	//spl->setResizeMode(userslist, QSplitter::KeepSize);
	spl->setResizeMode(vb2, QSplitter::KeepSize);
	
	resize(settings->getWidth(), settings->getHeight());
	if ((settings->getX() >= 0) && (settings->getY() >= 0))
		move(settings->getX(), settings->getY());

	//
	// systray icon
	if (settings->getUseSystray())
	{
		setupSystray();
		if (!settings->getWindowVisible())
			setShown(false);
	}
	
	//
	// set-up Timer for users-list refresh
	if (settings->getRefresh())
	{
		QTimer *timer = new QTimer(this);
		connect(timer, SIGNAL(timeout()), this, SLOT(usersListUpdate()));
		timer->start(settings->getRefresh() * 1000, false);
	}
	
	if (settings->getVersion() != VYQCHAT_VERSION)
	{
		QMessageBox::warning(this, "VyQChat", tr("You are running this version of"
				     " VyQChat for the first time. Please review your settings."));
		settings->setVersion();
	}
	
	if (!Sound::init(settings))
		QMessageBox::warning(this, "VyQChat", Sound::error(), "OK");
	
	//QString baddr(settings->getBroadcast());
	vc = new VCProtocol((settings->getEncoding() != "") ?
			QTextCodec::codecForName(settings->getEncoding()) :
			QTextCodec::codecForLocale(), settings->getUUID(),
			settings->getUseUTF());
	
	startChat();

	connect(vc, SIGNAL(sig_vc_say(const QString &, const QString &, const QString &)),
		this, SLOT(on_vc_say(const QString &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_me(const QString &, const QString &, const QString &)),
		this, SLOT(on_vc_me(const QString &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_whohere(const QHostAddress &, const QString &)),
		this, SLOT(on_vc_whohere(const QHostAddress &, const QString &)));
	connect(vc, SIGNAL(sig_vc_imhere(const QHostAddress &, const QString &, const QString &, char, char)),
		this, SLOT(on_vc_imhere(const QHostAddress &, const QString &, const QString &, char, char)));
	connect(vc, SIGNAL(sig_vc_imhere(const QHostAddress &, const QString &, const QString &, char, char, char, Q_INT16)),
		this, SLOT(on_vc_imhere(const QHostAddress &, const QString &, const QString &, char, char, char, Q_INT16)));
	connect(vc, SIGNAL(sig_vc_beep(const QHostAddress &, const QString &, const QString &)),
		this, SLOT(on_vc_beep(const QHostAddress &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_beepack(const QString &, const QString &, char)),
		this, SLOT(on_vc_beepack(const QString &, const QString &, char)));
	connect(vc, SIGNAL(sig_vc_join(const QHostAddress &, const QString &, const QString &, char, char)),
		this, SLOT(on_vc_join(const QHostAddress &, const QString &, const QString &, char, char)));
	connect(vc, SIGNAL(sig_vc_leave(const QString &, const QString &, char)),
		this, SLOT(on_vc_leave(const QString &, const QString &, char)));
	connect(vc, SIGNAL(sig_vc_private_join(const QString &, const QString &, char)),
		this, SLOT(on_vc_private_join(const QString &, const QString &, char)));
	connect(vc, SIGNAL(sig_vc_private_leave(const QString &, const QString &, char)),
		this, SLOT(on_vc_private_leave(const QString &, const QString &, char)));
	connect(vc, SIGNAL(sig_vc_private_say(const QString &, const QString &, const QString &)),
		this, SLOT(on_vc_private_say(const QString &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_private_me(const QString &, const QString &, const QString &)),
		this, SLOT(on_vc_private_me(const QString &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_message(const QHostAddress &, const QCString &, const QString &, const QString &, const QString &)),
		this, SLOT(on_vc_message(const QHostAddress &, const QCString &, const QString &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_massmessage(const QHostAddress &, const QCString &, const QString &, const QString &, const QString &)),
		this, SLOT(on_vc_massmessage(const QHostAddress &, const QCString &, const QString &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_messageack(char, const QString &, const QString &, char, const QString &)),
		this, SLOT(on_vc_messageack(char, const QString &, const QString &, char, const QString &)));
	connect(vc, SIGNAL(sig_vc_messageack(const QCString &, char, const QString &, const QString &, char, const QString &)),
		this, SLOT(on_vc_messageack(const QCString &, char, const QString &, const QString &, char, const QString &)));

	connect(vc, SIGNAL(sig_vc_herereq(const QHostAddress &, const QString &, const QString &)),
		this, SLOT(on_vc_herereq(const QHostAddress &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_hereack(const QString &, const QString &, const QString &, char )),
		this, SLOT(on_vc_hereack(const QString &, const QString &, const QString &, char)));
	connect(vc, SIGNAL(sig_vc_inforeq(const QString &, const QString &)), 
		this, SLOT(on_vc_inforeq(const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_inforeqack(const QHostAddress &, const QString &, const QString &, const QString &, const QString &, const QString &, const QString &, const QString &, const QString &, const QString &, bool)),
		this, SLOT(on_vc_inforeqack(const QHostAddress &, const QString &, const QString &, const QString &, const QString &, const QString &, const QString &, const QString &, const QString &, const QString &, bool)));
	connect(vc, SIGNAL(sig_vc_nickchange(const QString &, const QString &, char)),
		this, SLOT(on_vc_nickchange(const QString &, const QString &, char)));
	connect(vc, SIGNAL(sig_vc_changestatus(const QString &, char, char, const QString &)),
		this, SLOT(on_vc_changestatus(const QString &, char, char, const QString &)));
	connect(vc, SIGNAL(sig_vc_currenttopic(const QString &, const QString &, const QString &)),
		this, SLOT(on_vc_currenttopic(const QString &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_newtopic(const QString &, const QString &)),
		this, SLOT(on_vc_newtopic(const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_ping(const QHostAddress &, const QString &, const QString &, const QString &)),
		this, SLOT(on_vc_ping(const QHostAddress &, const QString &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_pong(const QString &, const QString &, const QString &)),
		this, SLOT(on_vc_pong(const QString &, const QString &, const QString &)));
	connect(vc, SIGNAL(sig_vc_floodnotify(const QString &, const QString &, const QString &)),
		this, SLOT(on_vc_floodnotify(const QString &, const QString &, const QString &)));
	
	reconfigureNetwork();
}/*}}}*/

MainWindow::~MainWindow()/*{{{*/
{
	Sound::close();

	vc->vc_leave(nick, MAIN_CHANNEL, gender);

	settings->setStatus(status);
	settings->setGeometry(x(), y(), width(), height());
	settings->setUsersListWidth(userslist->width());
	settings->setDNDhistory(dnd_list);
	settings->setAwayHistory(away_list);
	settings->setOfflineHistory(offline_list);
	settings->setRegexpHistory(regexp_list);
	settings->setNicksHistory(nick_list);
	
	delete availchannels;
	delete chattab;
	delete chatline;
	delete userslist;
	//delete settings;
}/*}}}*/

void MainWindow::setupSystray()/*{{{*/
{
	systraymenu = new QPopupMenu(this);
	systraymenu->insertItem(Icons::icon_user, tr("Available"), this, SLOT(goNORMAL()));
	systraymenu->insertItem(Icons::icon_user_dnd, tr("DND"), this, SLOT(openDNDdialog()));
	systraymenu->insertItem(Icons::icon_user_away, tr("Away"), this, SLOT(openAWAYdialog()));
	systraymenu->insertItem(Icons::icon_user_offline, tr("Offline"), this, SLOT(openOFFLINEdialog()));
	systraymenu->insertSeparator();
	systraymenu->insertItem(tr("Quit"), this, SLOT(exit()));
	systraymenu->insertSeparator();
	systraymenu->insertItem(tr("Restore"), this, SLOT(showNormal()));
	tray = new TrayIcon(this);
	switch (status)
	{
		case STATUS_NORMAL:  tray->setIcon(Icons::icon_user.pixmap()); break;
		case STATUS_DND:     tray->setIcon(Icons::icon_user_dnd.pixmap()); break;
		case STATUS_AWAY:    tray->setIcon(Icons::icon_user_away.pixmap()); break;
		case STATUS_OFFLINE: tray->setIcon(Icons::icon_user_offline.pixmap()); break;
		default: break;
	}
	tray->setPopup(systraymenu);
	connect(tray, SIGNAL(clicked(const QPoint&,int)), this, SLOT(systrayClicked()));
	tray->show();
	tray->setWMDock(true);
}/*}}}*/

void MainWindow::reconfigureSystray()/*{{{*/
{
	if (settings->getUseSystray())
		setupSystray();
	else if (tray)
	{
		delete tray;
		delete systraymenu;
		tray = NULL;
	}
}/*}}}*/

void MainWindow::systrayClicked()/*{{{*/
{
	if (isMinimized())
		showNormal();	
	else
		setShown(!isShown());
}/*}}}*/

void MainWindow::startChat()/*{{{*/
{
	//
	// chat session begins
	chattab->addChannel(MAIN_CHANNEL, settings->getTopic());
	chattab->write(MAIN_CHANNEL, "// Welcome to vyqchat v"  
				+ QString(VYQCHAT_VERSION) + ", " + nick + "!\n"
				"// (w)by Pawel Stolowski\n"
				"// released under terms of GNU General Public License (GPL)\n"
				"// send comments to pawel.stolowski@wp.pl\n"
				"//\n", QColor(0xf4, 0x09, 0x15));
}/*}}}*/

//
// returns current time in form [hh:mm]
const QString timestring()/*{{{*/
{
	QTime current = QTime::currentTime();
	return QString("[") + current.toString("hh:mm") + QString("] ");
}/*}}}*/

const QString timestring(const QTime &t)/*{{{*/
{
	return t.toString("hh:mm");
}/*}}}*/

//
// parses keyboard-commands
bool MainWindow::parse(QString &str)/*{{{*/
{
	enum {
		CMD_ME,
		CMD_NORMAL,
		CMD_AWAY,
		CMD_OFFLINE,
		CMD_BEEP,
		CMD_DND,
		CMD_HERE,
		CMD_INFO,
		CMD_JOIN,
		CMD_LEAVE,
		CMD_LIST,
		CMD_MESSAGE,
		CMD_MASSMESSAGE,
		CMD_NICK,
		CMD_TOPIC,
		CMD_CHAT,
		CMD_HELP,
		CMD_QUIT
	};
	const struct 
	{
		const QString command;
		char id;
		int argnum; 
	} cmdlut[] = {
		{"normal", CMD_NORMAL,	    0},
		{"away",   CMD_AWAY,	    1},
		{"offline",CMD_OFFLINE,	    1},
		{"beep",   CMD_BEEP,	    1},
		{"dnd",    CMD_DND,	    1},
		{"here",   CMD_HERE,	    0},
		{"info",   CMD_INFO,	    1},
		{"join",   CMD_JOIN,	    1},
		{"j",      CMD_JOIN,	    1},
		{"leave",  CMD_LEAVE,	    1},
		{"list",   CMD_LIST,        0},
		{"mesg",   CMD_MESSAGE,	    2},
		{"m",      CMD_MESSAGE,	    2},
		{"mass",   CMD_MASSMESSAGE, 1},
		{"nick",   CMD_NICK,	    1},
		{"topic",  CMD_TOPIC,	    1},
		{"chat",   CMD_CHAT,	    1},
		{"me",     CMD_ME,	    1},
		{"help",   CMD_HELP,	    0},
		{"?",      CMD_HELP,	    0},
		{"quit",   CMD_QUIT,        0},
		{NULL,	   0,		    0}
	};
	
	str = str.right(str.length() - 1); //cut the leading slash
	QString cmd = str.section(' ', 0, 0); //take the command name

	for (int i=0; cmdlut[i].command; i++)
		if (cmdlut[i].command == cmd)
		{
			QString tmp;
			QString channel = chattab->current();
			QString arg[2];
			if (cmdlut[i].argnum==1)
				arg[0] = str.section(' ', 1);
			else
				if (cmdlut[i].argnum==2)
				{
					arg[0] = str.section(' ', 1, 1);
					arg[1] = str.section(' ', 2);
				}
			switch (cmdlut[i].id)
			{
				case CMD_ME:
					if (chattab->isPrivate())
						vc->vc_private_me(userslist->getIP(channel), nick, channel, arg[0]);
					else
						vc->vc_me(channel, nick, arg[0]);
					break;
				case CMD_HERE:
					vc->vc_herereq(nick, channel);
					break;
				case CMD_INFO:
					requestInfo(arg[0]);
					break;
				case CMD_BEEP:
					beep(arg[0]);
					break;
				case CMD_MESSAGE:
					if (userslist->exists(arg[0]) && (!arg[1].isEmpty()))
						 vc->vc_message(userslist->getIP(arg[0]), nick, arg[0], arg[1]);
					break;
				case CMD_MASSMESSAGE:
					if (!arg[0].isEmpty())
					{
						QStringList nicks = userslist->getAllUsers();
						nicks.remove(nick);
						sendMassMessage(nicks, arg[0]);
					}
					break;
				case CMD_NICK:
					if ((!arg[0].isNull()) && (!userslist->exists(arg[0])))
						changeNick(arg[0]);
					break;
				case CMD_TOPIC:
					if (!arg[0].isNull())
						newTopic(channel, arg[0]);
					else
					{
						tmp.sprintf("%s Current topic on %s:\n%s",
								timestring().latin1(),
								static_cast<const char*>(channel.utf8()),
								static_cast<const char*>(chattab->getTopic(channel).utf8()));
						chattab->write(channel, tmp, special_color);
					}
					break;
				case CMD_JOIN:	
					joinChannel(arg[0]);
					break;
				case CMD_LEAVE:
					leaveChannel(channel);
					break;
				case CMD_CHAT:
					if (userslist->exists(arg[0]))
						openPrivate(arg[0]);
					break;
				case CMD_NORMAL:
					goNORMAL();
					break;
				case CMD_DND:
					goDND(arg[0]);
					break;
				case CMD_AWAY:
					goAWAY(arg[0]);
					break;
				case CMD_OFFLINE:
					goOFFLINE(arg[0]);
					break;
				case CMD_LIST:
					str  = tr("Available channels:") + "\n" + availchannels->list().join(" ");
					chattab->write(channel, str, special_color);
					break;
				case CMD_HELP:
					str = tr("Available commands:") + "\n";
					for (int i=0; cmdlut[i].command; i++)
					{
						str.append(cmdlut[i].command);
						str.append(' ');
					}
					chattab->write(channel, str, special_color);
					break;
				case CMD_QUIT:
					exit();
					break;
				default: break;
			}
			return true;
		}
	return false;
}/*}}}*/

void MainWindow::sendLine()/*{{{*/
{
	QString str = chatline->text();
	if (!str.isEmpty())
	{
		if (str[0]=='/')
		{
			if (!parse(str))
				chattab->write(MAIN_CHANNEL, tr("unknown command"), special_color);
		}
		else
		{
			if (chattab->isPrivate())
			{
				QString tmp;
				const QString to = chattab->current();
				vc->vc_private_say(userslist->getIP(to), nick, to, str);
				//
				// if reciever is not me, write message directly to widget
				// (because we won't get it back from socket)
				if (to!=nick)
				{
					tmp.sprintf("<%s> %s",
						static_cast<const char*>(nick.utf8()), 
						static_cast<const char*>(str.utf8()));
					chattab->write(to, tmp, own_color);
				}
			}
			else
				vc->vc_say(chattab->current(), nick, str);
		}
		chatline->clear();
	}
}/*}}}*/

void MainWindow::sendMessage(const QString &to, const QString &msg)/*{{{*/
{
	if (userslist->exists(to))
		vc->vc_message(userslist->getIP(to), nick, to, msg);
}/*}}}*/

void MainWindow::sendMassMessage(const QStringList &nicks, const QString &msg)/*{{{*/
{
	QStringList nl = nicks;
	for (QStringList::Iterator it = nl.begin(); it!=nl.end(); ++it)
	{
		User *user;
		if (user = userslist->getUser(*it))
			vc->vc_massmessage(user->getIP(), nick, *it, msg);
	}
}/*}}}*/

bool MainWindow::confirmExit()/*{{{*/
{
	return ((!settings->getConfirmExit()) || (QMessageBox::warning(this, tr("Quit VyQChat"), tr("Are you sure?"),
	    QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes));
}/*}}}*/

void MainWindow::forceRefresh()/*{{{*/
{
	userslist->clear();
	vc->vc_whohere(nick);
}/*}}}*/

void MainWindow::menuDummy()/*{{{*/
{
	qWarning("dummy");
}/*}}}*/

void MainWindow::openSendMessage(const QString &to)/*{{{*/
{
	if (!to.isEmpty())
	{
		MessageSndWindow *msgwin = new MessageSndWindow(to);
		connect(msgwin, SIGNAL(send(const QString &, const QString &)), this, SLOT(sendMessage(const QString &, const QString &)));
		msgwin->show();
	}
}/*}}}*/

void MainWindow::openSendMassMessage(const QStringList &nicks)/*{{{*/
{
	if (!nicks.isEmpty())
	{
		MassMessageWindow *msgwin = new MassMessageWindow(nick, nicks);
		connect(msgwin, SIGNAL(send(const QStringList&, const QString&)), this, SLOT(sendMassMessage(const QStringList&, const QString&)));
		msgwin->show();
	}
}/*}}}*/

void MainWindow::requestInfo(const QString &who)/*{{{*/
{
	vc->vc_inforeq(userslist->getIP(who), who, nick);
}/*}}}*/

void MainWindow::beep(const QString &who)/*{{{*/
{
	vc->vc_beep(userslist->getIP(who), who, nick);
}/*}}}*/

void MainWindow::changeNick(const QString &newnick)/*{{{*/
{
	if (!userslist->exists(newnick))
	{
		vc->vc_nickchange(nick, newnick, gender);
		nick = newnick;
	}
}/*}}}*/

void MainWindow::joinChannel(const QString &channel)/*{{{*/
{
	if (channel.isEmpty())
		return;
	
	const QString name = (channel[0]=='#') ? channel : '#' + channel;

	if (!chattab->exists(name))
	{
		chattab->addChannel(name, settings->getTopic());
		vc->vc_join(nick, name, status, gender);
	}
}/*}}}*/

void MainWindow::leaveChannel(const QString &channel)/*{{{*/
{
	if (chattab->isPrivate(channel))
	{
		chattab->delPrivate(channel);
		vc->vc_private_leave(userslist->getIP(channel), nick, channel, gender);
	}
	else
	{
		if (channel == MAIN_CHANNEL)
		{
			exit(); //not real exit, it asks for confirmation first
		}
		else
		{
			chattab->delChannel(channel);
			vc->vc_leave(nick, channel, gender);
		}
	}
}/*}}}*/

void MainWindow::openTopicDialog()/*{{{*/
{
	QString channel = chattab->current();
	if (!chattab->isPrivate(channel))
	{
		QString topic = chattab->getTopic(channel);
		topic = topic.left(topic.findRev('(')-1);
		TopicWin *w = new TopicWin(this, channel, topic);
		connect(w, SIGNAL(newTopic(const QString &, const QString &)), this, SLOT(newTopic(const QString &, const QString &)));
		w->show();
	}
}/*}}}*/

void MainWindow::openSettingsDialog()/*{{{*/
{
	SettingsDialog *s = new SettingsDialog(this, settings);
	connect(s, SIGNAL(networkSettingsChanged()), this, SLOT(reconfigureNetwork()));
	connect(s, SIGNAL(systraySettingsChanged()), this, SLOT(reconfigureSystray()));
	s->show();
}/*}}}*/

void MainWindow::goNORMAL()/*{{{*/
{
	status_combo->setCurrentItem(0);
	tray->setIcon(Icons::icon_user.pixmap());
	vc->vc_changestatus(nick, status=STATUS_NORMAL, gender, "" /*QString::null*/);
}/*}}}*/

void MainWindow::goDND(const QString &txt)/*{{{*/
{
	status_combo->setCurrentItem(1);
	dnd_list.append(txt);
	tray->setIcon(Icons::icon_user_dnd.pixmap());
	vc->vc_changestatus(nick, status=STATUS_DND, gender, autoanswer=txt);
}/*}}}*/

void MainWindow::goAWAY(const QString &txt)/*{{{*/
{
	status_combo->setCurrentItem(2);
	away_list.append(txt);
	tray->setIcon(Icons::icon_user_away.pixmap());
	vc->vc_changestatus(nick, status=STATUS_AWAY, gender, autoanswer=txt);
}/*}}}*/

void MainWindow::goOFFLINE(const QString &txt)/*{{{*/
{
	status_combo->setCurrentItem(3);
	offline_list.append(txt);
	tray->setIcon(Icons::icon_user_offline.pixmap());
	vc->vc_changestatus(nick, status=STATUS_OFFLINE, gender, autoanswer=txt);
}/*}}}*/

void MainWindow::openRegexpDialog()/*{{{*/
{
	RegexpWin *s = new RegexpWin(this, regexp_list, regexp_on);
	connect(s, SIGNAL(changeRegexp(const QString &, bool)), this, SLOT(changeRegexp(const QString &, bool)));
	s->show();
}/*}}}*/

void MainWindow::openDNDdialog()/*{{{*/
{
	StatusWin *s = new StatusWin(this, "Enter DND mode....", dnd_list);
	connect(s, SIGNAL(changeStatus(const QString &)), this, SLOT(goDND(const QString &)));
	connect(s, SIGNAL(canceled()), this, SLOT(cancelStatusChange()));
	s->show();
}/*}}}*/

void MainWindow::openAWAYdialog()/*{{{*/
{
	StatusWin *s = new StatusWin(this, "Enter Away mode....", away_list);
	connect(s, SIGNAL(changeStatus(const QString &)), this, SLOT(goAWAY(const QString &)));
	connect(s, SIGNAL(canceled()), this, SLOT(cancelStatusChange()));
	s->show();
}/*}}}*/

void MainWindow::openOFFLINEdialog()/*{{{*/
{
	StatusWin *s = new StatusWin(this, "Enter Offline mode....", offline_list);
	connect(s, SIGNAL(changeStatus(const QString &)), this, SLOT(goOFFLINE(const QString &)));
	connect(s, SIGNAL(canceled()), this, SLOT(cancelStatusChange()));
	s->show();
}/*}}}*/

void MainWindow::newTopic(const QString &channel, const QString &txt)/*{{{*/
{
	vc->vc_newtopic(channel, txt, nick);
}/*}}}*/

void MainWindow::changeRegexp(const QString &txt, bool on)/*{{{*/
{
	regexp_list.append(txt);
	regexp = QRegExp(txt);
	regexp_on = (regexp.isValid() && on); 
	settings->setRegexpOn(regexp_on);
}/*}}}*/

void MainWindow::statusComboActivated(int item)/*{{{*/
{
	switch (item)
	{
		case 0: goNORMAL(); break;
		case 1: openDNDdialog(); break;
		case 2: openAWAYdialog(); break;
		case 3: openOFFLINEdialog(); break;
		default: break;
	}
}/*}}}*/

void MainWindow::usersListUpdate()/*{{{*/
{
	userslist->decDeadCounters();
	vc->vc_whohere(nick);
}/*}}}*/

void MainWindow::popupAbout()/*{{{*/
{
	AboutDialog *about = new AboutDialog(this, tr("About VyQChat"),
			"<b>VyQChat v" + QString(VYQCHAT_VERSION) + "</b><br>by "
			"Pawel Stolowski<br>&lt yogin@linux.bydg.org&gt <br>"
			"http://linux.bydg.org/~yogin");
	about->show();
}/*}}}*/

void MainWindow::openChannelsDialog()/*{{{*/
{
	ChannelsDialog *c = new ChannelsDialog(this, availchannels);
	connect(c, SIGNAL(joinChannel(const QString &)), this, SLOT(joinChannel(const QString &)));
	c->show();
}/*}}}*/

void MainWindow::openPrivate(const QString &who)/*{{{*/
{
	chattab->addPrivate(who);
	vc->vc_private_join(userslist->getIP(who), nick, who, gender);
}/*}}}*/

void MainWindow::commandMenuAction(int option)/*{{{*/
{	
	const char* cmdtxt[] = {"me", "nick", "join", "leave",
		"chat", "topic", "info ", "beep ", "mass ", 
		"here", "normal", "dnd ", "away ", "offline ", "help"};
	
	chatline->setText('/' + QString(cmdtxt[option - ID_COMMAND_MENU]));	
}/*}}}*/

void MainWindow::toggleToolbar()/*{{{*/
{
	const bool s = !view_menu->isItemChecked(tbar_id);
	view_menu->setItemChecked(tbar_id, s);
	main_toolbar->setShown(s);
	settings->setToobarOn(s);
}/*}}}*/

void MainWindow::toggleUsersList()/*{{{*/
{
	const bool s = !view_menu->isItemChecked(ulist_id);
	view_menu->setItemChecked(ulist_id, s);
	userslist->setShown(s);
	settings->setUsersListOn(s);
}/*}}}*/

void MainWindow::toggleNickCombo()/*{{{*/
{
	const bool s = !view_menu->isItemChecked(nickcmb_id);
	view_menu->setItemChecked(nickcmb_id, s);
	nickcmb->setShown(s);
	settings->setNickComboOn(s);
}/*}}}*/

void MainWindow::exit()/*{{{*/
{
	exit_called = true;
	close();
}/*}}}*/

void MainWindow::simulateEnter()/*{{{*/
{
	QKeyEvent key(QEvent::KeyPress, Qt::Key_Return, '\n', 0);
	QApplication::sendEvent(chatline, &key);
}/*}}}*/

void MainWindow::closeEvent(QCloseEvent *e)/*{{{*/
{
	if (exit_called || !settings->getUseSystray())
	{
		if (confirmExit())
		{
			settings->setWindowVisible(isShown()); //store window state now, it will be too late later
			e->accept();
		}
		else
		{
			exit_called = false;
			e->ignore();
		}
	}
	else
	{
		e->ignore();
		setShown(false);
	}
}/*}}}*/

void MainWindow::openChatLineHistory()/*{{{*/
{
	ChatLineHistory *histwin = new ChatLineHistory(NULL, chatline->getHistory());
	connect(histwin, SIGNAL(clicked(const QString&)), chatline, SLOT(setText(const QString&)));
	histwin->show();
}/*}}}*/

void MainWindow::cancelStatusChange()/*{{{*/
{
	//
	// update status combo just for sure
	
	status_combo->setCurrentItem(status - STATUS_NORMAL);
	/*
	switch (status)
	{
		case STATUS_NORMAL:  status_combo->setCurrentItem(0); break;
		case STATUS_DND:     status_combo->setCurrentItem(1); break;
		case STATUS_AWAY:    status_combo->setCurrentItem(2); break;
		case STATUS_OFFLINE: status_combo->setCurrentItem(3); break;
		default: break;
	}*/
}/*}}}*/

void MainWindow::reconfigureNetwork()/*{{{*/
{
	bool res;

	vc->closeSockets();

	if (settings->getNetworkMethod() == NET_BROADCAST)
	{
		res = vc->setupBroadcastSockets(settings->getIP(), settings->getBroadcast());
	}
	else
	{
		res = vc->setupMulticastSockets(settings->getIP(), settings->getMulticastGroup());
	}
	
	if (res)
	{
		vc->vc_join(nick, MAIN_CHANNEL, status, gender);
		vc->vc_changeactivity(nick, WIN_ACTIVE);
		vc->vc_whohere(nick);
	}
	else
	{
		std::cerr << "network problem?!" << std::endl;
	}
}/*}}}*/

void MainWindow::on_vc_say(const QString &channel, const QString &from, const QString &text)/*{{{*/
{
      if (chattab->exists(channel))
      {
	     tmp.sprintf("<%s> %s",
		static_cast<const char*>(from.utf8()), 
		static_cast<const char*>(text.utf8()));
	      chattab->write(channel, tmp, (from == nick) ? own_color : normal_color);
	      
	      //
	      // regexps are mateched for any channel you are on
	      // play regexpmatch-sound
	      // write alert message on current channel
	      if (regexp_on && QString(text).contains(regexp))
	      {
		      if (settings->isSoundEnabled(EventRegexpMatch))
			      Sound::play(EventRegexpMatch);
		      if (settings->getScriptEnabled(EventRegexpMatch))
			      Scripting::executeRegexpMatch(settings->getScriptFileName(EventRegexpMatch), QDateTime::currentDateTime(), channel, from, text);
		      chattab->write(chattab->current(), "Regular expression matched on " + QString(channel), special_color);
	      }
	      else
	      {
		      //
		      // play chatline-sound if current channel
		      if ((status == STATUS_NORMAL) && (from != nick) && settings->isSoundEnabled(EventChatline) && (QString::compare(chattab->current(), channel)==0))
			      Sound::play(EventChatline);
		      if (settings->getScriptEnabled(EventChatline))
			      Scripting::executeChatline(settings->getScriptFileName(EventChatline), QDateTime::currentDateTime(), channel, from, text);
	      }
      }
}/*}}}*/

void MainWindow::on_vc_me(const QString &channel, const QString &from, const QString &text)/*{{{*/
{
	tmp.sprintf("*%s* %s", static_cast<const char*>(from.utf8()),
			static_cast<const char*>(text.utf8()));
	chattab->write(channel, tmp, special_color);
}/*}}}*/

void MainWindow::on_vc_whohere(const QHostAddress &source, const QString &updater)/*{{{*/
{
	vc->vc_imhere(source, updater, nick, status, gender, winstate);
}/*}}}*/

void MainWindow::on_vc_imhere(const QHostAddress &source, const QString &updater, const QString &responder, char status, char winstate)/*{{{*/
{
	std::cout << responder << std::endl;
	if (!userslist->exists(responder))
	{
		userslist->addUser(responder, status, source);
	}
	else
		userslist->incDeadCounter(responder);
}/*}}}*/

void MainWindow::on_vc_imhere(const QHostAddress &source, const QString &updater, const QString &responder, char status, char winstate, char gender, Q_INT16 color)/*{{{*/
{
	std::cout << responder << std::endl;
	if (!userslist->exists(responder))
		userslist->addUser(responder, status, source, gender);
	else
		userslist->incDeadCounter(responder);
}/*}}}*/

void MainWindow::on_vc_beep(const QHostAddress &source, const QString &to, const QString &from)/*{{{*/
{
	if (to == nick)
	{
		if (settings->getScriptEnabled(EventBeep))
			Scripting::executeBeep(settings->getScriptFileName(EventBeep), QDateTime::currentDateTime(), from);
		tmp.sprintf("Beep from %s received",
				static_cast<const char*>(from.utf8()));
		chattab->write(MAIN_CHANNEL, tmp, special_color);
		vc->vc_beepack(source, from, nick, gender);
		if (settings->isSoundEnabled(EventBeep))
			Sound::play(EventBeep);
	}
}/*}}}*/

void MainWindow::on_vc_beepack(const QString &to, const QString &from, char gender)/*{{{*/
{
	if (to == nick)
	{
		tmp.sprintf("%s received your beep",  
				static_cast<const char*>(from.utf8()));
		chattab->write(MAIN_CHANNEL, tmp, special_color);
	}
}/*}}}*/

void MainWindow::on_vc_join(const QHostAddress &source, const QString &who, const QString &channel, char status, char gender)/*{{{*/
{
	User *user;

	if ((user = userslist->getUser(who))==NULL)
	      user = userslist->addUser(who, status, source, gender);
	if (chattab->exists(channel))
	{
	      //
	      // send current topic to new user (if it's not me)
	      // and "i'm here" info
	      if (who != nick)
	      {
			vc->vc_imhere(source, who, nick, status, gender, winstate);
			vc->vc_currenttopic(source, who, channel, chattab->getTopic(channel));
	      }
	      tmp.sprintf("%s%s joins channel %s (%s mode)", 
			      timestring().latin1(), 
			      static_cast<const char*>(who.utf8()), 
			      static_cast<const char*>(channel.utf8()),
			      status_lut[user->getStatus()-STATUS_NORMAL]);
	      chattab->write(channel, tmp, special_color);
	}
	if (who != nick)
	{
		if ((this->status==STATUS_NORMAL) && (channel==chattab->current()) && settings->isSoundEnabled(EventJoin))
		      Sound::play(EventJoin);
		if (settings->getScriptEnabled(EventJoin))
			Scripting::executeJoin(settings->getScriptFileName(EventJoin), QDateTime::currentDateTime(), channel, who); 
	}
	availchannels->add(channel);
}/*}}}*/

void MainWindow::on_vc_leave(const QString &who, const QString &channel, char gender)/*{{{*/
{
	if (chattab->exists(channel))
	{
		tmp.sprintf("%s%s leaves channel %s", timestring().latin1(), static_cast<const char*>(who.utf8()),
			static_cast<const char*>(channel.utf8()));
		chattab->write(channel, tmp, special_color);
		
		if (QString::compare(channel, MAIN_CHANNEL)==0)
			userslist->delUser(who);
		if (who != nick)
		{
			if ((status==STATUS_NORMAL) && settings->isSoundEnabled(EventLeave))
				Sound::play(EventLeave);
			if (settings->getScriptEnabled(EventLeave))
				Scripting::executeLeave(settings->getScriptFileName(EventLeave), QDateTime::currentDateTime(), channel, who);
		}
	}
}/*}}}*/

void MainWindow::on_vc_private_join(const QString &from, const QString &to, char gender)/*{{{*/
{
	const QString prvname = (from == nick) ? to : from;
	if (!chattab->exists(prvname))
		chattab->addPrivate(prvname);
	tmp.sprintf("%s%s joins private", timestring().latin1(),
			static_cast<const char*>(from.utf8()));
	chattab->write(prvname, tmp, special_color);
}/*}}}*/

void MainWindow::on_vc_private_leave(const QString &from, const QString &to, char gender)/*{{{*/
{
	const QString prvname = (from==nick) ? to : from;
	tmp.sprintf("%s%s leaves private",
			timestring().latin1(),
			static_cast<const char*>(from.utf8()));
	chattab->write(prvname, tmp, special_color);
}/*}}}*/

void MainWindow::on_vc_private_say(const QString &from, const QString &to, const QString &text)/*{{{*/
{
	const QString prvname = (from == nick) ? to : from;
	tmp.sprintf("<%s> %s", static_cast<const char*>(from.utf8()),
			static_cast<const char*>(text.utf8()));
	chattab->write(prvname, tmp, (from == nick) ? own_color : normal_color); 
	if ((status == STATUS_NORMAL) && (from != nick) && settings->isSoundEnabled(EventChatline) && (QString::compare(chattab->current(), prvname)==0))
		Sound::play(EventChatline);				       
}/*}}}*/

void MainWindow::on_vc_private_me(const QString &from, const QString &to, const QString &text)/*{{{*/
{
	const QString prvname = (from ==nick) ? to : from;
	tmp.sprintf("*%s* %s", static_cast<const char*>(from.utf8()),
			static_cast<const char*>(text.utf8()));
	chattab->write(prvname, tmp, special_color); 
	if (regexp_on && settings->isSoundEnabled(EventRegexpMatch) && QString(text).contains(regexp))
	{
		Sound::play(EventRegexpMatch);
		chattab->write(chattab->current(), "Regular expression matched on " + QString(prvname), special_color);
	}
}/*}}}*/

void MainWindow::on_vc_message(const QHostAddress &source, const QCString &sig, const QString &from, const QString &to, const QString &text)/*{{{*/
{
	if ((status==STATUS_OFFLINE) || (to!=nick))
		return;
	vc->vc_messageack(source, sig, status, from, nick, gender, autoanswer);
	if ((status!=STATUS_AWAY) && settings->isSoundEnabled(EventMessage))
		Sound::play(EventMessage);
	if (settings->getPopupsOn() && !(settings->getNoDNDpopups() && (status!=STATUS_NORMAL)))
	{
		MessageRcvWindow *msgwin = new MessageRcvWindow(from, text);
		connect(msgwin, SIGNAL(reply(const QString &, const QString &)), this, SLOT(sendMessage(const QString &, const QString &)));
		connect(msgwin, SIGNAL(chat(const QString &)), this, SLOT(openPrivate(const QString &)));
		msgwin->show();
	}
	tmp.sprintf("%sMessage from %s:\n%s", timestring().latin1(),
			static_cast<const char*>(from.utf8()),
			static_cast<const char*>(text.utf8()));
	chattab->write(MAIN_CHANNEL, tmp, special_color);
}/*}}}*/

void MainWindow::on_vc_massmessage(const QHostAddress &source, const QCString &sig, const QString &from, const QString &to, const QString &text)/*{{{*/
{
	on_vc_message(source, sig, from, to, text);
}/*}}}*/

void MainWindow::on_vc_messageack(char status, const QString &to, const QString &from, char gender, const QString &answer)/*{{{*/
{
	if (to == nick)
	{
		tmp.sprintf("%s%s received your message", timestring().latin1(),
			static_cast<const char*>(from.utf8()));
		chattab->write(MAIN_CHANNEL, tmp, special_color);
	}
}/*}}}*/

void MainWindow::on_vc_messageack(const QCString &sig, char status, const QString &to, const QString &from, char gender, const QString &answer)/*{{{*/
{
	on_vc_messageack(status, to, from, gender, answer);
}/*}}}*/

void MainWindow::on_vc_herereq(const QHostAddress &source, const QString &from, const QString &channel)/*{{{*/
{
	vc->vc_hereack(source, from, channel, nick, remoteactive);
}/*}}}*/

void MainWindow::on_vc_hereack(const QString &to, const QString &channel, const QString &from, char ra)/*{{{*/
{
	tmp.sprintf("%sHere %s (%s)", timestring().latin1(),
			static_cast<const char*>(from.utf8()),
			remoteactive==WIN_ACTIVE ? "active":"not active");
	chattab->write(channel, tmp, special_color);
}/*}}}*/

void MainWindow::on_vc_inforeq(const QString &to, const QString &from)/*{{{*/
{
	tmp.sprintf("%s Info requested from %s", timestring().latin1(),
			static_cast<const char*>(from.utf8()));
	chattab->write(MAIN_CHANNEL, tmp, special_color);
	if (settings->getScriptEnabled(EventInfo))
		Scripting::executeInfoRequest(settings->getScriptFileName(EventInfo), QDateTime::currentDateTime(), from);
	vc->vc_inforeqack(userslist->getIP(from), from, nick, settings->getHostname(), nick, settings->getIP().toString(), settings->getHideChannels() ? QString(MAIN_CHANNEL): chattab->channelsList(), (status!=STATUS_NORMAL) ? autoanswer : QString(""));
}/*}}}*/

void MainWindow::on_vc_inforeqack(const QHostAddress &source, const QString &to, const QString &from, const QString &host, const QString &name, const QString &ip, const QString &channels, const QString &answer, const QString &computer, const QString &software, bool utf)/*{{{*/
{
	/*tmp << timestring << " Info on " << from << "\nName: " << name 
		<< "\nHost: " << host << '[' << source.toString() << "]\nPlatform: " << computer
		<< " Software: " << software << "\nChannels: " << channels;*/
	tmp.sprintf("%s Info on %s:\nName: %s Host: %s [%s]\nPlatform: %s Software: %s%s\nChannels: %s",
			timestring().latin1(),
			static_cast<const char*>(from.utf8()),
			static_cast<const char*>(name.utf8()),
			static_cast<const char*>(host.utf8()),
			source.toString().latin1(),
			static_cast<const char*>(computer.utf8()),
			static_cast<const char*>(software.utf8()),
			utf ? " (UNICODE)" : " (ANSI)",
			static_cast<const char*>(channels.utf8()));
	chattab->write(chattab->current(), tmp, special_color);
	if (!answer.isEmpty())
	{
		tmp.sprintf("%s", static_cast<const char*>(answer.utf8()));
		chattab->write(chattab->current(), tmp, special_color);
		//User *user = userslist->getUser(vp.from);
		////if (user)
		////user->setToolTipInfo(vp.from);
	}
    QStringList list = QStringList::split("#", channels);
    availchannels->add(list);
}/*}}}*/

void MainWindow::on_vc_nickchange(const QString &from, const QString &to, char gender)/*{{{*/
{
	tmp.sprintf("%s<%s> is known as <%s> from now",
			timestring().latin1(), 
			static_cast<const char*>(from.utf8()),
			static_cast<const char*>(to.utf8()));
	chattab->write(MAIN_CHANNEL, tmp, special_color);
	userslist->newNick(from, to);
}/*}}}*/

void MainWindow::on_vc_changestatus(const QString &who, char status, char gender, const QString &answer)/*{{{*/
{
	if (userslist->setStatus(who, status))
	{
		tmp.sprintf("%s%s enters %s mode", timestring().latin1(),
				static_cast<const char*>(who.utf8()),
				status_lut[status - STATUS_NORMAL]);
		chattab->write(MAIN_CHANNEL, tmp, special_color);
		if ((status!=STATUS_NORMAL) && !answer.isEmpty())
		{
			tmp.sprintf("%s", static_cast<const char*>(answer.utf8()));
			chattab->write(MAIN_CHANNEL, tmp, special_color);
		}
	}
}/*}}}*/

void MainWindow::on_vc_currenttopic(const QString &to, const QString &channel, const QString &topic)/*{{{*/
{
	if (chattab->getTopic(channel).isEmpty() && !topic.isEmpty())
	{
		tmp.sprintf("%s Current topic on %s:\n%s", timestring().latin1(),
				static_cast<const char*>(channel.utf8()),
				static_cast<const char*>(topic.utf8()));
		chattab->setTopic(channel, topic);
		chattab->write(channel, tmp, special_color);
	}
}/*}}}*/

void MainWindow::on_vc_newtopic(const QString &channel, const QString &topic)/*{{{*/
{
	if (chattab->setTopic(channel, topic))
	{
		tmp.sprintf("%s New topic:\n%s", timestring().latin1(),
				static_cast<const char*>(topic.utf8()));
		chattab->write(channel, tmp, special_color);
	}
}/*}}}*/

void MainWindow::on_vc_ping(const QHostAddress &source, const QString &to, const QString &from, const QString &time)/*{{{*/
{
	if (to == nick)
	{
		QTime current = QTime::currentTime();
		vc->vc_pong(source, from, nick, current.toString("hh:mm:ss"));
	}
}/*}}}*/

void MainWindow::on_vc_pong(const QString &to, const QString &from, const QString &time)/*{{{*/
{
}/*}}}*/

void MainWindow::on_vc_floodnotify(const QString &to, const QString &from, const QString &seconds)/*{{{*/
{
	if (nick == to)
	{
		tmp.sprintf("%s You have been blocked for flooding by %s (%s seconds)\n", timestring().latin1(),
				static_cast<const char*>(from.utf8()),
				static_cast<const char*>(seconds.utf8()));
		chattab->write(MAIN_CHANNEL, tmp, special_color);
	}
}/*}}}*/



syntax highlighted by Code2HTML, v. 0.9.1