/***************************************************************************
                          dcclient.cpp  -  description
                             -------------------
    begin                : Thu Oct 4 2001
    copyright            : (C) 2001-2005 by Mathias Küster
    email                : mathen@users.berlios.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdlib.h>

#include <qapplication.h>
#include <qlineedit.h>
#include <qcheckbox.h>
#include <qregexp.h>
#include <qcombobox.h>
#include <qcursor.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <QListWidgetItem>
#include <qtabwidget.h>
#include <qinputdialog.h>
#include <qclipboard.h>
#include <qlayout.h>
#include <qsplitter.h>
#include <qtoolbutton.h>
#include <qtooltip.h>
//Added by qt3to4:
#include <QResizeEvent>
#include <QStringList>
#include <QPixmap>
#include <QMouseEvent>
#include <QCloseEvent>
#include <QList>
#include <QKeyEvent>
#include <QEvent>
#include <QHeaderView>
#include <QStyle>
#include <QDateTime>

#include "dcevent.h"
#include "dcspy.h"
#include "dctransferview.h"
#include "dcconfig.h"
#include "dcchat.h"
#include "dcmenuhandler.h"
#include "dcuserslist.h"
#include "dciconloader.h"

#include "dcconnectionmanager.h"
#include "dcclient.h"

#include <dclib/cfilemanager.h>
#include <dclib/dcos.h>
#include <dclib/cutils.h>

/** */
DCClient::DCClient(QWidget* parent, const char *name, Qt::WindowFlags wflags) : QWidget(parent, name, wflags)
{
	int idx;
	
	setupUi(this);
	
	m_pMdiArea = qobject_cast<QMdiArea*>(parent);
	
	if (m_pMdiArea != 0)
	{
		m_pContainerWindow = m_pMdiArea->addSubWindow(this);
	}
	else
	{
		m_pContainerWindow = 0;
	}

	// set default icon
	setIcon( g_pIconLoader->GetPixmap(eiNOTCONNECTED) );
	if ( m_pContainerWindow != 0 )
	{
		m_pContainerWindow->setIcon( g_pIconLoader->GetPixmap(eiNOTCONNECTED) );
	}

	m_pUserListModel = new UserListModel();
	TreeView_USERLIST->setModel( m_pUserListModel );

	// QT3 set the ColumnWidthMode to manual, we will take care of this task
	// in QT4, QHeaderView::Interactive is default anyway
	// QHeaderView::Fixed would disable user resizing
	for( idx = 0; idx < TreeView_USERLIST->header()->count(); idx++ )
	{
		TreeView_USERLIST->header()->setResizeMode( idx, QHeaderView::Interactive );
	}

	m_pMessageList = new CList<CObject>();
	m_pMyInfoHash  = new QHash<QString, CMessageMyInfo>();
	m_pChatList    = new CStringList();

	m_bUseTabWidget = g_pConfig->GetShowChatInTab();

	m_nChatFloodCounter = 0;

	InitDocument();
}

/** */
DCClient::~DCClient()
{
	CObject * Object;

	m_Timer.stop();

	m_pHubChat->removeEventFilter(this);
	delete m_pHubChat;

	if ( g_pUsersList )
	{
		// force recheck all friend state
		DCFriendObject m_pFriendObject;
		QApplication::postEvent( g_pUsersList, new DC_FriendEvent( EVENT_UPDATE_FRIEND, &m_pFriendObject ) );
	}

	Disconnect();

	m_Thread.Lock();

	if ( m_pMessageList )
	{
		while ( (Object = m_pMessageList->Next(0)) != 0 )
		{
			m_pMessageList->Del(Object);
		}

		delete m_pMessageList;
		m_pMessageList = 0;
	}

	m_Thread.UnLock();

	if ( m_pChatList )
	{
		CString s;
		DCChat * chat = 0;

		while( m_pChatList->Next( s, (CObject *&)chat ) )
		{
			m_pChatList->Remove(s);
			chat = 0;
		}

		delete m_pChatList;
		m_pChatList = 0;
	}

	delete m_pMyInfoHash;
	m_pMyInfoHash = 0;
	
	delete m_pUserListModel;
	m_pUserListModel = 0;
}

/** */
void DCClient::InitDocument()
{
	SetCrypt(FALSE);

	// add hubchat widget
	m_pHubChat = new DCChat( TabWidget_CHAT, "HUB-Chat", 0, this, FALSE );
	m_pHubChat->setAttribute(Qt::WA_DeleteOnClose);
	m_pHubChat->installEventFilter(this);
	m_pHubChat->SetNick("",tr("Hub").toAscii().data());

	TabWidget_CHAT->insertTab( m_pHubChat, tr("Hub") );

	// remove chat list tab
	if ( m_bUseTabWidget )
	{
		QWidget * page = TabWidget_CHAT->page(0);
		TabWidget_CHAT->removePage(page);
		delete page;

		TabWidget_CHAT->setCurrentPage(0);
		
		TabWidget_CHAT->setCornerWidget( new QPushButton( QIcon( g_pIconLoader->GetPixmap(eiFILECLOSE) ), "", TabWidget_CHAT ) );
		QToolTip::add( TabWidget_CHAT->cornerWidget(), tr("Close chat tab") );
		TabWidget_CHAT->cornerWidget()->setEnabled(FALSE);
	}
	else
	{
		connect( ListWidget_CHATUSERLIST,SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(slotDoubleClickedChatUserList(QListWidgetItem*)) );

		TabWidget_CHAT->setTabLabel( TabWidget_CHAT->page(0), tr("Chat List")+" ("+QString().setNum(ListWidget_CHATUSERLIST->count())+")" );

		TabWidget_CHAT->setCurrentPage(1);
	}

	connect( TreeView_USERLIST,SIGNAL(doubleClicked( const QModelIndex & )), this, SLOT(slotDoubleClickedUserList( const QModelIndex & )) );
	connect( TreeView_USERLIST,SIGNAL(customContextMenuRequested( const QPoint & )), this, SLOT(slotContextMenuUserList( const QPoint & )) );
	connect( TreeView_USERLIST->header(),SIGNAL(sectionResized(int, int, int)), this, SLOT(slotSaveColumnWidth(int, int, int)) );
	connect( TabWidget_CHAT,SIGNAL(currentChanged(QWidget*)), this, SLOT(slotTabWidgetChatCurrentChange(QWidget*)) );
	connect( ToolButton_CONNECT,SIGNAL(clicked()), this, SLOT(slotHubConnect()) );
	/* connect( ToolButton_SSL,SIGNAL(clicked()), this, SLOT(slotSSLInfo()) ); */
	
	if (m_bUseTabWidget)
	{
		connect( TabWidget_CHAT->cornerWidget(), SIGNAL(clicked()), this, SLOT(slotTabCornerCloseWidgetClicked()) );
	}

	// set connect disconnect button pixmap
	SetConnection(FALSE);

	TabWidget_CHAT->installEventFilter(this);
	TreeView_USERLIST->installEventFilter(this);
	
	connect( &m_Timer, SIGNAL(timeout()), this, SLOT(timerDone()) );
	
	m_Timer.start( 500, TRUE );
}

/** */
void DCClient::InitSizes()
{
	StringMap * map;
	QList<int> frames;
	
	// restore settings
	if ( g_pConfig->GetMap("CLIENTVIEW",map) == TRUE )
	{
		if ( ((*map)["WIDTH"].toInt() > 0) && ((*map)["HEIGHT"].toInt() > 0) )
		{
			if ( (m_pContainerWindow != 0) && (!isMinimized()) )
			{
				m_pContainerWindow->setGeometry( m_pContainerWindow->x(), m_pContainerWindow->y(), (*map)["WIDTH"].toInt(), (*map)["HEIGHT"].toInt() );
			}
		}

		Qt::SortOrder order = Qt::AscendingOrder;
		if ( (*map)["SORTORDER"] == "Descending" )
		{
			order = Qt::DescendingOrder;
		}
		TreeView_USERLIST->sortByColumn( (*map)["SORTCOLUMN"].toInt(), order );
	}

	if ( g_pConfig->GetUserListRightAlignment() == TRUE )
	{
		Splitter_CLIENT->moveToFirst(Frame_CHATLIST);

		Frame_CHATLIST->adjustSize();
		Frame_USERLIST->adjustSize();
	}

	if ( g_pConfig->GetMap("USERLISTVIEW",map) == TRUE )
	{
		if ( (*map)[QString().setNum(eclcNICK)].toInt() > 0 )
			g_pConfig->SetClientColumnWidth( eclcNICK, (*map)[QString().setNum(eclcNICK)].toInt() );
		if ( (*map)[QString().setNum(eclcCOMMENT)].toInt() > 0 )
			g_pConfig->SetClientColumnWidth( eclcCOMMENT, (*map)[QString().setNum(eclcCOMMENT)].toInt() );
		if ( (*map)[QString().setNum(eclcTAG)].toInt() > 0 )
			g_pConfig->SetClientColumnWidth( eclcTAG, (*map)[QString().setNum(eclcTAG)].toInt() );
		if ( (*map)[QString().setNum(eclcEMAIL)].toInt() > 0 )
			g_pConfig->SetClientColumnWidth( eclcEMAIL, (*map)[QString().setNum(eclcEMAIL)].toInt() );
		if ( (*map)[QString().setNum(eclcSPEED)].toInt() > 0 )
			g_pConfig->SetClientColumnWidth( eclcSPEED, (*map)[QString().setNum(eclcSPEED)].toInt() );
		if ( (*map)[QString().setNum(eclcSHARE)].toInt() > 0 )
			g_pConfig->SetClientColumnWidth( eclcSHARE, (*map)[QString().setNum(eclcSHARE)].toInt() );
		if ( (*map)[QString().setNum(eclcIP)].toInt() > 0 )
			g_pConfig->SetClientColumnWidth( eclcIP, (*map)[QString().setNum(eclcIP)].toInt() );
		if ( (*map)[QString().setNum(eclcLOCKPK)].toInt() > 0 )
			g_pConfig->SetClientColumnWidth( eclcLOCKPK, (*map)[QString().setNum(eclcLOCKPK)].toInt() );
		if ( (*map)[QString().setNum(eclcSUPPORTS)].toInt() > 0 )
			g_pConfig->SetClientColumnWidth( eclcSUPPORTS, (*map)[QString().setNum(eclcSUPPORTS)].toInt() );
		if ( ((*map)["WIDTH"].toInt() > 0) && (!isMinimized()) )
		{
			frames = Splitter_CLIENT->sizes();
			if (frames.size() == 2)
			{
				if ( g_pConfig->GetUserListRightAlignment() == TRUE )
				{
					frames[0] = (width() - Splitter_CLIENT->handleWidth() - 1) - (*map)["WIDTH"].toInt();
					frames[1] = (*map)["WIDTH"].toInt() + 1;
				} else {
					frames[0] = (*map)["WIDTH"].toInt() + 1;
					frames[1] = (width() - Splitter_CLIENT->handleWidth() - 1) - (*map)["WIDTH"].toInt();
				}
				Splitter_CLIENT->setSizes(frames);
			}
		}
	}

	// set viewable columns
	ResizeListViewColumn();

	// load column order from config
	if ( g_pConfig->GetMap("USERLISTCOLUMNORDER",map) == TRUE)
	{
		QByteArray ba = QByteArray::fromBase64(map->value(QString("USERLISTHEADERSTATE")).toAscii().data());
		TreeView_USERLIST->header()->restoreState(ba);
		
		/* for ( int i = 0; i < TreeView_USERLIST->header()->count(); i++ )
		{
			int newpos = (*map)[QString().setNum(i)].toInt();
			printf( "column %d is at %d\n", i, newpos );
			
			if ( newpos >= 0 )
			{
				TreeView_USERLIST->header()->moveSection( i, newpos );
			}
		} */
	}
}

/** */
void DCClient::DeInitDocument()
{
	DCChat * chat = 0;
	StringMap * map;

	// save client view settings
	g_pConfig->GetMap("CLIENTVIEW",map);
	
	if ( m_pContainerWindow != 0 )
	{
		(*map)["WIDTH"]      = QString().setNum(m_pContainerWindow->width());
		(*map)["HEIGHT"]     = QString().setNum(m_pContainerWindow->height());
	}
	
	(*map)["SORTCOLUMN"] = QString().setNum(m_pUserListModel->getSortColumn());
	if ( m_pUserListModel->getSortOrder() == Qt::AscendingOrder )
	{
		(*map)["SORTORDER"]  = "Ascending";
	}
	else if ( m_pUserListModel->getSortOrder() == Qt::DescendingOrder )
	{
		(*map)["SORTORDER"]  = "Descending";
	}

	SaveClientColumn();

	// save column order to config
	//for (int i = 0; i < TreeView_USERLIST->header()->count(); i++ )
	//{
	//	printf("Column %d is at position %d\n", i, TreeView_USERLIST->header()->visualIndex(i) );
	//}
	
	g_pConfig->GetMap("USERLISTCOLUMNORDER",map);
	//printf("TreeView_USERLIST->header()->saveState().size()=%d\n", TreeView_USERLIST->header()->saveState().size());
	//printf("TreeView_USERLIST->header()->saveState().toBase64().data()=%s\n", TreeView_USERLIST->header()->saveState().toBase64().data());
	(*map)[QString("USERLISTHEADERSTATE")] = QString(TreeView_USERLIST->header()->saveState().toBase64().data());
	
	// kept for backwards compatibility with QT3 client
	for ( int i = 0; i < TreeView_USERLIST->header()->count(); i++ )
	{
		(*map)[QString().setNum(i)]     = QString().setNum(TreeView_USERLIST->header()->visualIndex(i));
	}
	
	if ( m_pChatList )
	{
		while( m_pChatList->Next( (CObject *&)chat ) )
		{
			chat->removeEventFilter(this);
			chat->close();
		}
	}
}

/** */
void DCClient::SaveClientColumn()
{
	StringMap * map;

	g_pConfig->GetMap("USERLISTVIEW",map);
	(*map)[QString().setNum(eclcNICK)] = QString().setNum(g_pConfig->GetClientColumnWidth( eclcNICK ));
	(*map)[QString().setNum(eclcCOMMENT)] = QString().setNum(g_pConfig->GetClientColumnWidth( eclcCOMMENT ));
	(*map)[QString().setNum(eclcTAG)] = QString().setNum(g_pConfig->GetClientColumnWidth( eclcTAG ));
	(*map)[QString().setNum(eclcEMAIL)] = QString().setNum(g_pConfig->GetClientColumnWidth( eclcEMAIL ));
	(*map)[QString().setNum(eclcSPEED)] = QString().setNum(g_pConfig->GetClientColumnWidth( eclcSPEED ));
	(*map)[QString().setNum(eclcSHARE)] = QString().setNum(g_pConfig->GetClientColumnWidth( eclcSHARE ));
	(*map)[QString().setNum(eclcIP)] = QString().setNum(g_pConfig->GetClientColumnWidth( eclcIP ));
	(*map)[QString().setNum(eclcLOCKPK)] = QString().setNum(g_pConfig->GetClientColumnWidth( eclcLOCKPK ));
	(*map)[QString().setNum(eclcSUPPORTS)] = QString().setNum(g_pConfig->GetClientColumnWidth( eclcSUPPORTS ));
	(*map)["WIDTH"] = QString().setNum(Frame_USERLIST->width());
}

/** */
void DCClient::SetCrypt( bool b )
{
	QToolTip::remove(ToolButton_SSL);
	ToolButton_SSL->setEnabled(b);

	if ( b )
	{
		QToolTip::add(ToolButton_SSL, tr("Line is encrypted."));
		ToolButton_SSL->setPixmap( g_pIconLoader->GetPixmap(eiSSL_YES));
	}
	else
	{
		QToolTip::add(ToolButton_SSL, tr("Line is not encrypted."));
		ToolButton_SSL->setPixmap( g_pIconLoader->GetPixmap(eiSSL_NO));
	}
}

/** */
void DCClient::SetConnection( bool b )
{
	QToolTip::remove(ToolButton_CONNECT);

	if ( b )
	{
		QToolTip::add(ToolButton_CONNECT, tr("Disconnect."));
		ToolButton_CONNECT->setPixmap( g_pIconLoader->GetPixmap(eiCONNECT_NO));
	}
	else
	{
		QToolTip::add(ToolButton_CONNECT, tr("Connect."));
		ToolButton_CONNECT->setPixmap( g_pIconLoader->GetPixmap(eiCONNECT_CREATING));
	}
}

/** */
/* void DCClient::slotSSLInfo()
{
} */

/** event filter */
bool DCClient::eventFilter(QObject* object, QEvent* event)
{
	if((event->type() == QEvent::Close)&&((DCClient*)object!=this))
	{
		QCloseEvent* e=(QCloseEvent*)event;

		if ( m_pHubChat == object )
		{
			e->ignore();
			return TRUE;
		}

		DCChat* pView=(DCChat*)object;

		CloseChat(pView);
	}
	else if ( event->type() == QEvent::KeyPress )
	{
		QKeyEvent * e = (QKeyEvent*)event;

		// reconnect
		if ( (e->state() == Qt::AltModifier) && (e->key() == Qt::Key_R) )
		{
			slotHubConnect();
		}
		
		if ( TreeView_USERLIST->hasFocus() )
		{
			// TODO: add userlist shortcuts
		}
	}
	else if ( (event->type() == QEvent::MouseButtonPress) && (object == TabWidget_CHAT) )
	{
		QMouseEvent * e = (QMouseEvent*)event;

		if ( e->button() == Qt::RightButton )
		{
			if ( (TabWidget_CHAT->currentPage() != 0) &&
			     (TabWidget_CHAT->currentPage() != ListWidget_CHATUSERLIST) )
			{
                                 ((DCChat*)TabWidget_CHAT->currentPage())->slotRightButtonClickedChatOutput(QPoint());
			}
		}
	}

	return QWidget::eventFilter( object, event );    // standard event processing
}

/** current tab widget change slot */
void DCClient::slotTabWidgetChatCurrentChange( QWidget * w )
{
	DCChat * chat = (DCChat*)w;
	
	if ( ! TabWidget_CHAT->tabIconSet(w).isNull() )
	{
		TabWidget_CHAT->setTabIconSet( w, QIcon() );
		
		// reset nick color
		m_pUserListModel->setHighlight( QString::fromAscii(chat->GetNick().Data()), FALSE );
	}
	
	if (m_bUseTabWidget)
	{
		if (TabWidget_CHAT->currentPage() == m_pHubChat)
		{
			TabWidget_CHAT->cornerWidget()->setEnabled(FALSE);
		}
		else
		{
			TabWidget_CHAT->cornerWidget()->setEnabled(TRUE);
		}
	}
}

/** overridden so that the columns are resized on show() */
void DCClient::show()
{
	QWidget::show();

	ResizeListViewColumn();
	
	m_pHubChat->InitView();
}

/** resize event handler */
void DCClient::resizeEvent( QResizeEvent * event )
{
	ResizeListViewColumn();
}

/** */
void DCClient::UpdateClientColumn( bool enabled, int index, int width )
{
	if ( enabled == FALSE )
	{
		// TreeView_USERLIST->setColumnWidth( index, 0 );
		// TreeView_USERLIST->header()->setResizeMode( index, QHeaderView::Fixed );
		TreeView_USERLIST->hideColumn( index );
	}
	else
	{
		if ( width < 10 ) { width = 10; } // otherwise newly-enabled columns remain hidden
		TreeView_USERLIST->showColumn( index );
		TreeView_USERLIST->setColumnWidth( index, width );
	}
}

/** resize the ListView columns */
void DCClient::ResizeListViewColumn()
{
	int width,i;

//	printf("%d\n",g_pConfig->GetClientColumnWidth( eclcNICK ));
	if ( g_pConfig->GetClientColumnWidth( eclcNICK ) < 30 )
	{
		i     = 36;
		width = TreeView_USERLIST->width();

		if ( TreeView_USERLIST->verticalScrollBar()->isVisible() )
			width -= (TreeView_USERLIST->verticalScrollBar()->size().width()+4);

		if ( width > 0 )
		{
			if ( g_pConfig->GetClientColumn( eclcCOMMENT ) == FALSE )
				i -= 5;
			if ( g_pConfig->GetClientColumn( eclcTAG ) == FALSE )
				i -= 4;
			if ( g_pConfig->GetClientColumn( eclcSPEED ) == FALSE )
				i -= 2;
			if ( g_pConfig->GetClientColumn( eclcEMAIL ) == FALSE )
				i -= 3;
			if ( g_pConfig->GetClientColumn( eclcSHARE ) == FALSE )
				i -= 4;
			if ( g_pConfig->GetClientColumn( eclcIP ) == FALSE )
				i -= 4;
			if ( g_pConfig->GetClientColumn( eclcLOCKPK ) == FALSE )
				i -= 4;
			if ( g_pConfig->GetClientColumn( eclcSUPPORTS ) == FALSE )
				i -= 4;

			g_pConfig->SetClientColumnWidth( eclcCOMMENT,  (width*5)/i );
			g_pConfig->SetClientColumnWidth( eclcTAG,      (width*4)/i );
			g_pConfig->SetClientColumnWidth( eclcSPEED,    (width*2)/i );
			g_pConfig->SetClientColumnWidth( eclcEMAIL,    (width*3)/i );
			g_pConfig->SetClientColumnWidth( eclcSHARE,    (width*4)/i );
			g_pConfig->SetClientColumnWidth( eclcIP,       (width*4)/i );
			g_pConfig->SetClientColumnWidth( eclcLOCKPK,   (width*4)/i );
			g_pConfig->SetClientColumnWidth( eclcSUPPORTS, (width*4)/i );
			g_pConfig->SetClientColumnWidth( eclcNICK,     (width*6)/i );
		}
	}

	if ( g_pConfig->GetClientColumnWidth( eclcNICK ) > 0 )
	{
		UpdateClientColumn( TRUE,                                       0, g_pConfig->GetClientColumnWidth( eclcNICK ) );
		UpdateClientColumn( g_pConfig->GetClientColumn( eclcCOMMENT ),  1, g_pConfig->GetClientColumnWidth( eclcCOMMENT ) );
		UpdateClientColumn( g_pConfig->GetClientColumn( eclcTAG ),      2, g_pConfig->GetClientColumnWidth( eclcTAG ) );
		UpdateClientColumn( g_pConfig->GetClientColumn( eclcSPEED ),    3, g_pConfig->GetClientColumnWidth( eclcSPEED ) );
		UpdateClientColumn( g_pConfig->GetClientColumn( eclcEMAIL ),    4, g_pConfig->GetClientColumnWidth( eclcEMAIL ) );
		UpdateClientColumn( g_pConfig->GetClientColumn( eclcSHARE ),    5, g_pConfig->GetClientColumnWidth( eclcSHARE ) );
		UpdateClientColumn( g_pConfig->GetClientColumn( eclcIP ),       6, g_pConfig->GetClientColumnWidth( eclcIP ) );
		UpdateClientColumn( g_pConfig->GetClientColumn( eclcLOCKPK ),   7, g_pConfig->GetClientColumnWidth( eclcLOCKPK ) );
		UpdateClientColumn( g_pConfig->GetClientColumn( eclcSUPPORTS ), 8, g_pConfig->GetClientColumnWidth( eclcSUPPORTS ) );
	}
}

/** */
void DCClient::UpdateCaption()
{
	QString s;

	switch(GetConnectionState())
	{
		case estCONNECTED:
				s = "[+]";
				break;
		default:
				s = "[-]";
				break;
	}

	s += " ";
	s += QString::fromAscii(GetHubName().Data());

	if ( GetHubTopic() != "" )
	{
		s += " (";
		s += QString::fromAscii(GetHubTopic().Data());
		s += ")";
	}
	
	if (s.length() > 50)
	{
		s = s.left(50) + "...";
	}

	setCaption(s);
}

/** */
void DCClient::UpdateStatusBar()
{
	TextLabel_USERCOUNT->setText( QString().setNum(m_pUserListModel->rowCount( QModelIndex() )) );
	TextLabel_SHARESIZE->setText( CUtils::GetSizeString(UserList()->ShareSize(),g_pConfig->GetUnit()).Data() );
}

/** */
void DCClient::timerDone()
{
	CObject * Object;
	CDCMessage *DCMsg;
	int i;

	for(i=0;i<200;i++)
	{
		if ( m_Thread.TryLock() == FALSE )
		{
			break;
		}

		if ( m_pMessageList != 0 )
		{
			Object = m_pMessageList->Next(0);

			if ( Object != 0 )
			{
				m_pMessageList->Remove(Object);
			}
		}
		else
		{
			Object = 0;
		}

		m_Thread.UnLock();

		if ( Object == 0 )
		{
			break;
		}

		DCMsg = (CDCMessage*) Object;

		switch ( DCMsg->m_eType )
		{
			case DC_MESSAGE_CONNECTION_STATE:
			{
				CMessageConnectionState *msg = (CMessageConnectionState*) Object;

				if ( msg->m_eState == estCONNECTED )
				{
					m_nChatFloodCounter = 0;
					m_bUserPassword     = FALSE;

					UpdateCaption();
					setIcon( g_pIconLoader->GetPixmap(eiCONNECTED) );
					if ( m_pContainerWindow )
						m_pContainerWindow->setIcon( g_pIconLoader->GetPixmap(eiCONNECTED) );
					// repaint new icon in minimized mode
					if ( isMinimized() )
						showMinimized();

					m_pHubChat->AddStatus(tr("Connected").toAscii().data());

					// init userlist
					DC_NickList(0);

					g_pConfig->PlaySound(eusCONNECT);

					SetConnection(TRUE);

					SetCrypt(FALSE);
				}
				if ( msg->m_eState == estSSLCONNECTED )
				{
					SetCrypt(TRUE);
				}
				else if ( msg->m_eState == estCONNECTIONTIMEOUT )
				{
					m_pHubChat->AddStatus(tr("Connection timeout").toAscii().data());

					SetConnection(FALSE);

					SetCrypt(FALSE);
				}
				else if ( msg->m_eState == estSOCKETERROR )
				{
					QString s;
					s = tr("Error: '") + QString(msg->m_sMessage.Data()) + QString("'");
					m_pHubChat->AddStatus(s.toAscii().data());

					SetConnection(FALSE);

					SetCrypt(FALSE);
				}
				else if ( msg->m_eState == estDISCONNECTED )
				{
					m_nChatFloodCounter = 0;

					UpdateCaption();
					setIcon( g_pIconLoader->GetPixmap(eiNOTCONNECTED) );
					if ( m_pContainerWindow )
						m_pContainerWindow->setIcon( g_pIconLoader->GetPixmap(eiNOTCONNECTED) );

					// repaint new icon in minimized mode
					if ( isMinimized() )
						showMinimized();

					m_pHubChat->AddStatus(tr("Disconnected").toAscii().data());
					g_pConfig->PlaySound(eusDISCONNECT);

					if ( g_pUsersList )
					{
						// force recheck all friend state
						DCFriendObject m_pFriendObject;
						QApplication::postEvent( g_pUsersList, new DC_FriendEvent( EVENT_UPDATE_FRIEND, &m_pFriendObject ) );
					}

					// reset all chats
					DCChat * chat = 0;
					while ( m_pChatList->Next( (CObject*&)chat ) == 1 )
					{
						chat->SetCrypt(esecsNONE);
						chat->AddStatus(tr("We left the hub.").toAscii().data());
        				}

					SetConnection(FALSE);

					SetCrypt(FALSE);
				}

				break;
			}

			case DC_MESSAGE_VALIDATEDENIDE:
			{
				m_pHubChat->AddStatus(tr("Your Nick is already in use.").toAscii().data());
				Disconnect();
				break;
			}

			case DC_MESSAGE_NICKLIST:
			{
				DC_NickList( (CMessageNickList *) Object );
				break;
			}

			case DC_MESSAGE_OPLIST:
			{
				DC_OpList( (CMessageNickList *) Object );
				break;
			}

			case DC_MESSAGE_REVCONNECTTOME:
			{
				CMessageRevConnectToMe * msg = (CMessageRevConnectToMe*) Object;

				if ( GetMode() == ecmPASSIVE )
				{
					if ( g_pConfig->GetSendMessageOnActiveModeRequest() == TRUE )
					{
						SendPrivateMessage( GetNick(), msg->m_sDstNick, tr("Sorry, you will not be able to download from me, because we are both in passive mode. (automated message)").toAscii().data() );
					}
				}

				break;
			}

			case DC_MESSAGE_CHAT:
			{
				CMessageChat * msg = (CMessageChat *) Object;
				
				if ( m_ChatFloodMessage.m_sMessage == msg->m_sMessage && m_ChatFloodMessage.m_sNick == msg->m_sNick )
				{
					// increment flood counter
					m_nChatFloodCounter++;
				}
				else
				{
					// update message and reset counter
					m_ChatFloodMessage.m_sMessage = msg->m_sMessage;
					m_ChatFloodMessage.m_sNick    = msg->m_sNick;
					m_nChatFloodCounter = 0;
				}

				// if flood detect enabled ?
				if ( g_pConfig->GetFloodCount() > 0 )
				{
					if ( m_nChatFloodCounter >= g_pConfig->GetFloodCount() )
					{
						// only one flood message
						if ( m_nChatFloodCounter == g_pConfig->GetFloodCount() )
						{
							m_pHubChat->AddStatus(tr("Flood Detected ("+QString().setNum(m_nChatFloodCounter)+")").toAscii().data());

							// now the admin kick the user if enabled
							if ( (g_pConfig->GetFloodOpKick() == TRUE) && (!UserList()->IsAdmin(msg->m_sNick)) && (UserList()->IsAdmin(GetNick())) )
							{
								//if OP kick the user for Flooding
								CString kickmessage=g_pConfig->GetFloodOpKickMessage();
								SendPrivateMessage( GetNick(), msg->m_sNick.Data(), ("You are being kicked because: " + kickmessage));
								SendChat( GetNick(), GetNick() + " is kicking " + msg->m_sNick.Data() + " because: " + kickmessage );
								SendKick(msg->m_sNick.Data());
							}
						}

						// don't show the flood messages
						msg = 0;
					}
				}

				if ( msg )
				{
					DC_Chat( msg );
				}

				break;
			}

			case DC_MESSAGE_MYINFO:
			{
				DC_MyInfo( (CMessageMyInfo *) Object );
				break;
			}

			case DC_MESSAGE_QUIT:
			{
				DC_Quit( (CMessageQuit *) Object );
				break;
			}

			case DC_MESSAGE_SEARCH:
			{
				if ( g_pSpy )
					g_pSpy->DC_Search( (CMessageSearch *) Object );
				break;
			}

			case DC_MESSAGE_HELLO:
			{
				CMessageHello * msg = (CMessageHello *) Object;

				DC_Hello(msg);

				break;
			}

			case DC_MESSAGE_FORCEMOVE:
			{
				CMessageForceMove * msg = (CMessageForceMove*) Object;

				if ( g_pConfig->GetForceMoveEnabled() == TRUE )
				{
					UpdateCaption();

					m_pHubChat->AddStatus( (tr("Redirect to ")+ QString(msg->m_sHost.Data()) + QString(":") + QString().setNum(msg->m_nPort)).toAscii().data() );
				}
				else
				{
					m_pHubChat->AddStatus( (tr("Redirect disabled ")+ QString(msg->m_sHost.Data()) + QString(":") + QString().setNum(msg->m_nPort)).toAscii().data() );
				}

				break;
			}

			case DC_MESSAGE_HUBNAME:
			{
				CMessageHubName * msg = (CMessageHubName*) Object;

				if ( (msg->m_sOldHubName != "") && (msg->m_sOldHubName != msg->m_sHubName) )
				{
					m_pHubChat->AddStatus( (tr("Hubname change:")+QString(" '")+QString(msg->m_sOldHubName.Data())+QString("' -> '")+QString(msg->m_sHubName.Data())+QString("'")).toAscii().data() );
				}

				UpdateCaption();

				// update caption from the main chat
				m_pHubChat->SetNick("",msg->m_sHubName.Data());

				// update caption from all private chats
				if ( m_pChatList )
				{
					DCChat * chat = 0;

					while( m_pChatList->Next( (CObject *&)chat ) )
					{
						chat->SetNick( chat->GetNick(), msg->m_sHubName.Data() );
					}
				}

				break;
			}

			case DC_MESSAGE_HUB_TOPIC:
			{
				UpdateCaption();
				break;
			}

			case DC_MESSAGE_PRIVATECHAT:
			{
				CMessagePrivateChat * msg = (CMessagePrivateChat*) Object;

				DC_PrivateChat( msg );

				break;
			}

			case DC_MESSAGE_GETPASS:
			{
				bool ok = FALSE;
				DCConfigHubProfile pConfigHubProfile;

				if ( m_bUserPassword == FALSE )
				{
					// get password from profile
					if ( g_pConfig->GetBookmarkHubProfile( GetHubName(), GetHost(), &pConfigHubProfile ) == TRUE )
					{
						if ( pConfigHubProfile.m_sPassword != "" )
						{
							m_pHubChat->AddStatus(tr("Use password from profile").toAscii().data());
							SendPass(pConfigHubProfile.m_sPassword);
							SetUsedPassword(TRUE);
							m_bUserPassword = TRUE;
							break;
						}
						else
						{
							m_pHubChat->AddStatus(tr("Password from profile is empty").toAscii().data());
						}
					}
					else
					{
						m_pHubChat->AddStatus(tr("No profile found for this hub").toAscii().data());
					}
				}

				QString text = QInputDialog::getText(
					tr( "Password - ")+QString(GetHubName().Data()),
					tr( "Please enter your password" ),
					QLineEdit::Password, QString::null, &ok, this );

				if ( ok && !text.isEmpty() )
				{
					SendPass(text.toAscii().data());
					SetUsedPassword(TRUE);
				}
				else
				{
					Disconnect();
				}

				break;
			}

			case DC_MESSAGE_BADPASS:
			{
				m_pHubChat->AddStatus(tr("Wrong password").toAscii().data());
				SetUsedPassword(FALSE);
				break;
			}

			case DC_MESSAGE_USERIP:
			{
				CMessageUserIP * msg = (CMessageUserIP*) Object;
				
				// fill in the IP address column for the given nick
				m_pUserListModel->updateIP( msg->m_sNick.Data(), msg->m_sIP.Data() );
				
				break;
			}

			default:
			{
				break;
			}
		}

		if ( Object )
			delete Object;
	}

	m_Timer.start( 500, TRUE );
}

/** */
int DCClient::DC_CallBack( CObject * Object )
{
	int err;

	m_Thread.Lock();

	if ( Object != NULL )
	{
		if ( m_pMessageList != NULL )
		{
			m_pMessageList->Add(Object);
			err = 0;
		}
		else
		{
			err = -1;
		}
	}
	else
	{
		err = -1;
	}

	m_Thread.UnLock();

	return err;
}

/** chat */
void DCClient::DC_Chat( CMessageChat * MessageChat )
{
	// check for ignored nick
	if ( g_pUsersList->ignoreNick( MessageChat->m_sNick ) == TRUE )
	{
		//printf("Ignoring \"%s\" from \"%s\"\n", MessageChat->m_sMessage.Data(), MessageChat->m_sNick.Data());
		return;
	}
	
	m_pHubChat->AddMessage(MessageChat->m_sNick.Data(),MessageChat->m_sMessage.Data(),TRUE);

	if ( !m_pHubChat->isVisible() )
	{
		TabWidget_CHAT->setTabIconSet( m_pHubChat, QIcon( g_pIconLoader->GetPixmap(eiMESSAGE) ) );
	}
	
	// send chat event
	g_pConnectionManager->HubEvent(this);
	
	// check for auto responses
	if (g_pConfig->GetAutoResponderEnabled() == TRUE)
	{
		this->doAutoResponse( MessageChat->m_sNick.Data(), MessageChat->m_sMessage.Data(), m_pHubChat );
	}
}

/** myinfo */
void DCClient::DC_MyInfo( CMessageMyInfo * MessageMyInfo )
{
	QPixmap pm;
	QString nick = QString::fromAscii(MessageMyInfo->m_sNick.Data());

	CMessageMyInfo existingMyInfo;

	if ( m_pMyInfoHash->contains( nick ) == FALSE )
	{
		m_pMyInfoHash->insert( nick, *MessageMyInfo );

		pm = *g_pConfig->GetUserIcon(MessageMyInfo->m_bOperator,MessageMyInfo->m_eClientMode,MessageMyInfo->m_eAwayMode,MessageMyInfo->m_eUserSpeed,MessageMyInfo->m_eClientVersion);
		m_pUserListModel->addUser(
			nick,
			pm,
			MessageMyInfo->m_sComment.Data(),
			QString::fromAscii(MessageMyInfo->m_sVerComment.Data()),
			MessageMyInfo->m_sUserSpeed.Data(),
			QString::fromAscii(MessageMyInfo->m_sEMail.Data()),
			MessageMyInfo->m_nShared,
			MessageMyInfo->m_sTransferHost.Data(),
			MessageMyInfo->m_MessageLock.m_sData.Data(),
			MessageMyInfo->m_MessageSupports.m_sContent.Data()
		);
		
		// user not in the list, add it
		addUser( nick );
	}
	else
	{
		existingMyInfo = m_pMyInfoHash->value( nick );
		m_pMyInfoHash->insert( nick, *MessageMyInfo );
		
		if ( (existingMyInfo.m_eAwayMode != MessageMyInfo->m_eAwayMode) ||
		     (existingMyInfo.m_eUserSpeed != MessageMyInfo->m_eUserSpeed) ||
		     (existingMyInfo.m_bOperator != MessageMyInfo->m_bOperator) ||
		     (existingMyInfo.m_eClientMode != MessageMyInfo->m_eClientMode) ||
		     (existingMyInfo.m_eClientVersion != MessageMyInfo->m_eClientVersion) )
		{
			pm = *g_pConfig->GetUserIcon(MessageMyInfo->m_bOperator,MessageMyInfo->m_eClientMode,MessageMyInfo->m_eAwayMode,MessageMyInfo->m_eUserSpeed,MessageMyInfo->m_eClientVersion);
			m_pUserListModel->updateIcon( nick, pm);
		}
		
		if ( existingMyInfo.m_sComment != MessageMyInfo->m_sComment )
		{
			m_pUserListModel->updateComment( nick, QString::fromAscii(MessageMyInfo->m_sComment.Data()) );
		}
		
		if ( existingMyInfo.m_sVerComment != MessageMyInfo->m_sVerComment )
		{
			m_pUserListModel->updateTag( nick, MessageMyInfo->m_sVerComment.Data() );
		}
		
		if ( existingMyInfo.m_sUserSpeed != MessageMyInfo->m_sUserSpeed )
		{
			m_pUserListModel->updateSpeed( nick, MessageMyInfo->m_sUserSpeed.Data() );
		}
		
		if ( existingMyInfo.m_sEMail != MessageMyInfo->m_sUserSpeed )
		{
			m_pUserListModel->updateEmail( nick, QString::fromAscii(MessageMyInfo->m_sEMail.Data()) );
		}
		
		if ( existingMyInfo.m_nShared != MessageMyInfo->m_nShared )
		{
			m_pUserListModel->updateShare( nick, MessageMyInfo->m_nShared );
		}
		
		if ( existingMyInfo.m_sTransferHost != MessageMyInfo->m_sTransferHost )
		{
			m_pUserListModel->updateIP( nick, MessageMyInfo->m_sTransferHost.Data() );
		}
		
		if ( existingMyInfo.m_MessageLock.m_sData != MessageMyInfo->m_MessageLock.m_sData )
		{
			m_pUserListModel->updateLockPK( nick, MessageMyInfo->m_MessageLock.m_sData.Data() );
		}
		
		if ( existingMyInfo.m_MessageSupports.m_sContent != MessageMyInfo->m_MessageSupports.m_sContent )
		{
			m_pUserListModel->updateSupports( nick, MessageMyInfo->m_MessageSupports.m_sContent.Data() );
		}
	}

	// send friend event
	if ( g_pUsersList )
	{
		DCFriendObject m_pFriendObject;

		m_pFriendObject.m_sName        = MessageMyInfo->m_sNick;
		m_pFriendObject.m_sDescription = MessageMyInfo->m_sComment;
		m_pFriendObject.m_eAwayMode    = MessageMyInfo->m_eAwayMode;
		m_pFriendObject.m_sHubName     = GetHubName();
		m_pFriendObject.m_sHubHost     = GetHost();
		QApplication::postEvent( g_pUsersList, new DC_FriendEvent( EVENT_UPDATE_FRIEND, &m_pFriendObject ) );
	}
	
	UpdateStatusBar();
}

/** hello */
void DCClient::DC_Hello( CMessageHello * MessageHello )
{
	QPixmap pm;
	QString nick = QString::fromAscii(MessageHello->m_sNick.Data());
	
	if ( m_pMyInfoHash->contains( nick ) == FALSE )
	{
		CMessageMyInfo myinfo;
		myinfo.m_sNick = MessageHello->m_sNick;
		myinfo.m_bOperator = FALSE;
		myinfo.m_eAwayMode = euamNORMAL;
		
		m_pMyInfoHash->insert( nick, myinfo );

		pm = *g_pConfig->GetUserIcon(FALSE,ecmNONE,euamNONE,eusUNKNOWN,eucvNONE);

		m_pUserListModel->addUser(
			nick,
			pm
		);
				
		addUser( nick );
	}

	UpdateStatusBar();
}

/** quit */
void DCClient::DC_Quit( CMessageQuit * MessageQuit )
{
	DCChat * chat;
	QString nick = QString::fromAscii(MessageQuit->m_sNick.Data());
	
	if ( m_pMyInfoHash->contains( nick ) == TRUE )
	{
		m_pUserListModel->removeUser( nick );
		m_pMyInfoHash->remove( nick );
	}

	if ( m_pChatList->Get( MessageQuit->m_sNick, (CObject*&)chat ) == 0 )
	{
		chat->SetCrypt(esecsNONE);
		chat->AddStatus(tr("User left the hub.").toAscii().data());
        }

	// send friend event
	if ( g_pUsersList )
	{
		DCFriendObject m_pFriendObject;

		m_pFriendObject.m_sName     = MessageQuit->m_sNick;
		m_pFriendObject.m_eAwayMode = euamOFFLINE;
		m_pFriendObject.m_sHubName  = GetHubName();
		m_pFriendObject.m_sHubHost  = GetHost();
		QApplication::postEvent( g_pUsersList, new DC_FriendEvent( EVENT_UPDATE_FRIEND, &m_pFriendObject ) );
	}

	if ( g_pConfig->GetChatShowJoinsAndParts() == TRUE )
	{
		if ( g_pConfig->GetChatShowJoinsAndPartsOnlyFav() == TRUE )
		{
			if ( g_pUsersList->isNickInList( MessageQuit->m_sNick ) )
			{
				m_pHubChat->AddStatus(tr("Parts: ") + MessageQuit->m_sNick);
			}
		}
		else
		{
			m_pHubChat->AddStatus(tr("Parts: ") + MessageQuit->m_sNick);
		}
	}

	UpdateStatusBar();
}

/** nicklist */
void DCClient::DC_NickList( CMessageNickList * MessageNickList )
{
	CString * Nick = 0;
	QPixmap pm;
	QString nick;

	TreeView_USERLIST->setUpdatesEnabled(FALSE);
	m_pUserListModel->clear();

	m_pMyInfoHash->clear();

	if ( MessageNickList )
	{
		while ( (Nick=MessageNickList->m_NickList.Next(Nick)) != 0 )
		{
			nick = QString::fromAscii((*Nick).Data());
			
			if ( m_pMyInfoHash->contains( nick ) == FALSE )
			{
				CMessageMyInfo myinfo;
				myinfo.m_sNick = (*Nick);
				myinfo.m_bOperator = FALSE;
				myinfo.m_eAwayMode = euamNORMAL;
				
				m_pMyInfoHash->insert( nick, myinfo );
	
				pm = *g_pConfig->GetUserIcon(FALSE,ecmNONE,euamNONE,eusUNKNOWN,eucvNONE);
				
				m_pUserListModel->addUser(
					nick,
					pm
				);
			}

			// send friend event
			if ( g_pUsersList )
			{
				DCFriendObject m_pFriendObject;

				m_pFriendObject.m_sName     = *Nick;
				m_pFriendObject.m_eAwayMode = euamONLINE;
				m_pFriendObject.m_sHubName  = GetHubName();
				m_pFriendObject.m_sHubHost  = GetHost();
				QApplication::postEvent( g_pUsersList, new DC_FriendEvent( EVENT_UPDATE_FRIEND, &m_pFriendObject ) );
			}
		}
	}

	TreeView_USERLIST->setUpdatesEnabled(TRUE);
	TreeView_USERLIST->update();

	UpdateStatusBar();
}

/** oplist */
void DCClient::DC_OpList( CMessageNickList * MessageOpList )
{
	CString * Nick = 0;
	QPixmap pm;
	QString nick;
	
	TreeView_USERLIST->setUpdatesEnabled(FALSE);

	while ( (Nick=MessageOpList->m_NickList.Next(Nick)) != 0 )
	{
		nick = QString::fromAscii((*Nick).Data());
		
		if ( m_pMyInfoHash->contains( nick ) == FALSE )
		{
			CMessageMyInfo myinfo;
			myinfo.m_sNick = (*Nick);
			myinfo.m_bOperator = TRUE;
			myinfo.m_eAwayMode = euamNORMAL;
			
			m_pMyInfoHash->insert( nick, myinfo );

			// user not in the list, add it
			addUser( Nick->Data() );

			pm = *g_pConfig->GetUserIcon(TRUE,ecmNONE,euamNONE,eusUNKNOWN,eucvNONE);
			
			m_pUserListModel->addUser(
				nick,
				pm
			);
			
			m_pUserListModel->setSortTop( QString::fromAscii((*Nick).Data()), TRUE );
		}
		else
		{
			CMessageMyInfo myinfo = m_pMyInfoHash->value( nick );
			
			if ( myinfo.m_bOperator == FALSE )
			{
				pm = *g_pConfig->GetUserIcon(TRUE,myinfo.m_eClientMode,myinfo.m_eAwayMode,myinfo.m_eUserSpeed,myinfo.m_eClientVersion);
				
				m_pUserListModel->updateIcon( nick, pm );
				
				m_pUserListModel->setSortTop( nick, TRUE );
				
				myinfo.m_bOperator = TRUE;
				m_pMyInfoHash->insert( nick, myinfo );
			}
		}
	}

	TreeView_USERLIST->setUpdatesEnabled(TRUE);
	TreeView_USERLIST->update();

	UpdateStatusBar();
}

void DCClient::DC_PrivateChat( QString nick, QString fromnick, QString message, bool bLocal )
{
	CMessagePrivateChat msg;

	msg.m_sSrcNick      = nick.toAscii().data();
	msg.m_sMultiSrcNick = fromnick.toAscii().data();
	msg.m_sMessage      = message.toAscii().data();

	DC_PrivateChat( &msg, bLocal );
}

/** */
void DCClient::DC_PrivateChat( CMessagePrivateChat * msg, bool bLocal )
{
	QWidget * focuswidget = 0;
	bool bShowChat = TRUE;

	DCChat * chat;

	if ( msg->m_sSrcNick == "" )
	{
		return;
	}
	
	// also check for ignored nick for PMs
	if ( g_pUsersList->ignoreNick( msg->m_sSrcNick ) == TRUE )
	{
		//printf("Ignoring PM \"%s\" from \"%s\"\n", msg->m_sMessage.Data(), msg->m_sSrcNick.Data() );
		return;
	}

	// create a new chat window
	if( m_pChatList->Get( msg->m_sSrcNick, (CObject*&)chat ) != 0 )
	{
		focuswidget = qApp->focusWidget();

		if ( m_bUseTabWidget )
		{
			chat = new DCChat( TabWidget_CHAT, "chat", Qt::WDestructiveClose, this );
		}
		else
		{
			chat = new DCChat( m_pMdiArea, "chat", Qt::WDestructiveClose, this );
			m_pMdiArea->addSubWindow(chat);
			new QListWidgetItem( QString::fromAscii(msg->m_sSrcNick.Data()), ListWidget_CHATUSERLIST );
			TabWidget_CHAT->setTabLabel( TabWidget_CHAT->page(0), tr("Chat List")+" ("+QString().setNum(ListWidget_CHATUSERLIST->count())+")" );
		}

		// fix hide if chat maximized
		chat->show();
		chat->hide();

		chat->installEventFilter(this);
		chat->SetNick(msg->m_sSrcNick.Data(),GetHubName().Data());

		m_pChatList->Add( msg->m_sSrcNick, (CObject*)chat );

		if ( (g_pConfig->GetOpenPrivateChatWindow() == FALSE) && (bLocal == FALSE) )
		{
			bShowChat = FALSE;
		}
		// check for max lines and set chat invisible
		else if ( (g_pConfig->GetChatMessageMaxLines() > 0) &&
			  (QString(msg->m_sMessage.Data()).count("\n") > g_pConfig->GetChatMessageMaxLines()) )
		{
			bShowChat = FALSE;
		}
		
		// check for nicks to not open chat windows
		DCConfigHubProfile pConfigHubProfile;
		QString nickregexp = "";
		
		if ( g_pConfig->GetBookmarkHubProfile( GetHubName(), GetHost(), &pConfigHubProfile ) == TRUE )
		{
			nickregexp = pConfigHubProfile.m_sSuppressedNicks.Data();
		}
		
		if (nickregexp == "")
		{
			nickregexp = g_pConfig->GetSuppressedNicks();
		}
		
		if (nickregexp != "")
		{
			QRegExp rx(nickregexp);
			rx.setCaseSensitive(FALSE);
			if (rx.search(msg->m_sSrcNick.Data()) != -1)
			{
				bShowChat = FALSE;
			}
		}
		
		if ( m_bUseTabWidget )
		{
			TabWidget_CHAT->insertTab( chat, msg->m_sSrcNick.Data() );
		}

		if ( bShowChat || bLocal )
		{
			if ( m_bUseTabWidget )
				TabWidget_CHAT->showPage(chat);
			else
				chat->setEnabled(TRUE);
			chat->show();
		}
		else
		{
			if ( !m_bUseTabWidget )
			{
				chat->setEnabled(FALSE);
				chat->hide();
			}

			// restore focus
			if ( focuswidget )
				focuswidget->setFocus();
		}

		g_pConfig->PlaySound(eusFIRSTRECEIVE);
	}
	// enable all local (user input)
	else if ( bLocal == TRUE )
	{
		if ( chat->isVisible() == FALSE )
		{
			if ( m_bUseTabWidget )
				TabWidget_CHAT->showPage(chat);
			else
				chat->setEnabled(TRUE);
			chat->show();
		}
		
		m_pUserListModel->setHighlight( msg->m_sSrcNick.Data(), FALSE );
	}

	if ( msg->m_sMessage != "" )
	{
		chat->AddMessage( msg );

		if ( chat->isVisible() == FALSE )
		{
			m_pUserListModel->setHighlight( msg->m_sSrcNick.Data(), TRUE );

			if ( m_bUseTabWidget )
				TabWidget_CHAT->setTabIconSet( chat, QIcon( g_pIconLoader->GetPixmap(eiMESSAGE) ) );
		}
		else
		{
			m_pUserListModel->setHighlight( msg->m_sSrcNick.Data(), FALSE );
		}
	}

	if ( (chat->isVisible() == FALSE) &&
	     (g_pConfig->GetSendHidePrivateChatToPublicChat() == TRUE) )
	{
		CString nick;

		// send private chat to public chat
		if ( (msg->m_sSrcNick != msg->m_sMultiSrcNick) && (msg->m_sMultiSrcNick != "") )
			nick = msg->m_sSrcNick + "::" + msg->m_sMultiSrcNick;
		else
			nick = msg->m_sSrcNick;
		m_pHubChat->AddMessage( nick.Data(), msg->m_sMessage.Data(), TRUE, TRUE );
	}
	
	// init chat view
	chat->InitView();
	
	// send chat event
	g_pConnectionManager->HubEvent(this);
	
	if (g_pConfig->GetAutoResponderEnabledForPM() == TRUE)
	{
		this->doAutoResponse( msg->m_sSrcNick.Data(), msg->m_sMessage.Data(), chat );
	}	
}

/** handling if user join the hub */
void DCClient::addUser( QString nick )
{
	DCChat * chat;

	// show joins
	if ( g_pConfig->GetChatShowJoinsAndParts() == TRUE )
	{
		if ( g_pConfig->GetChatShowJoinsAndPartsOnlyFav() == TRUE )
		{
			if ( g_pUsersList->isNickInList( nick.toAscii().data() ) == TRUE )
			{
				m_pHubChat->AddStatus( tr("Joins: ") + CString(nick.toAscii().data()) );
			}
		}
		else
		{
			m_pHubChat->AddStatus( tr("Joins: ") + CString(nick.toAscii().data()) );
		}
	}

	// show rejoin on private chat
	if ( m_pChatList->Get( nick.toAscii().data(), (CObject*&)chat ) == 0 )
	{
		chat->AddStatus(tr("User rejoin the hub.").toAscii().data());
	}

	// send event to friendlist
	if ( g_pUsersList )
	{
		DCFriendObject m_pFriendObject;

		m_pFriendObject.m_sName     = nick.toAscii().data();
		m_pFriendObject.m_eAwayMode = euamONLINE;
		m_pFriendObject.m_sHubName  = GetHubName();
		m_pFriendObject.m_sHubHost  = GetHost();
		QApplication::postEvent( g_pUsersList, new DC_FriendEvent( EVENT_UPDATE_FRIEND, &m_pFriendObject ) );
	}
}

/** */
void DCClient::CloseChat( DCChat * chat )
{
	chat->removeEventFilter(this);

	if ( m_pChatList != 0 )
	{
		m_pChatList->Remove(chat->GetNick());
	}

	if ( m_bUseTabWidget )
	{
		TabWidget_CHAT->removePage(chat);
	}
	else
	{
		QList<QListWidgetItem*> list = ListWidget_CHATUSERLIST->findItems( chat->GetNick().Data(), Qt::MatchExactly );
		for ( int i = 0; i < list.size(); i++ )
		{
			ListWidget_CHATUSERLIST->removeItemWidget( list.at(i) );
			delete list.at(i);
			TabWidget_CHAT->setTabLabel( TabWidget_CHAT->page(0), tr("Chat List")+" ("+QString().setNum(ListWidget_CHATUSERLIST->count())+")" );
		}
	}

	chat->close();
}

/** */
void DCClient::CloseAllChats()
{
	DCChat * chat=0;

	while( m_pChatList->Next((CObject*&)chat) )
	{
		CloseChat(chat);
		chat = 0;
        }
}

/** */
void DCClient::slotDoubleClickedUserList( const QModelIndex & index )
{
	if ( !index.isValid() )
	{
		return;
	}
	
	QModelIndex nickindex = m_pUserListModel->index( index.row(), COLUMN_NICK, QModelIndex() );
	QString nick = m_pUserListModel->data( nickindex ).toString();
	
	if ( g_pConfig->GetDoubleClickAction() == tr("Downloads filelist") )
	{
		g_pTransferView->DLM_QueueAdd(
			nick.toAscii().data(),
			GetHubName(),
			GetIP() + ":" + QString().setNum(GetPort()).toAscii().data(),
			DC_USER_FILELIST_HE3,
			DC_USER_FILELIST_HE3,
			"",
			"",
			eltBUFFER,
			0,
			0,
			0,
			""
		);
	}
	else
	{
		DC_PrivateChat( nick, "", "", TRUE );
	}
}

/** */
void DCClient::slotDoubleClickedChatUserList( QListWidgetItem * item )
{
	DCChat * chat = 0;
	QString nick;

	if ( item == 0 )
	{
		return;
	}

	nick = item->text();

	if ( nick == "" )
	{
		return;
	}

	if ( m_pChatList->Get( nick.toAscii().data(), (CObject*&)chat ) == 0 )
	{
		if ( !m_bUseTabWidget )
			chat->setEnabled(TRUE);

		// take widget to top
		if ( chat->isMinimized() )
		{
			chat->showNormal();
		}
		else if ( chat->isVisible() )
		{
			// TODO: dont work fix it
			chat->show();
			chat->raise();
		}
		else
		{
			chat->show();
		}

		m_pUserListModel->setHighlight( nick, FALSE );
	}
}

/** */
int DCClient::selectedItems( CList<CString> * lst )
{
	QModelIndexList list = TreeView_USERLIST->selectionModel()->selectedRows( COLUMN_NICK );

	for ( int i = 0; i < list.size(); i++ )
	{
		lst->Add(new CString((m_pUserListModel->data( list.at(i) )).toString().toAscii().data() ));
	}

	return lst->Count();
}

/** */
void DCClient::slotHubConnect()
{
	if ( GetConnectionState() == estNONE )
	{
		SetConnection(TRUE);
		Connect();
		UpdateReconnect( ersNONE, 0 );
	}
	else if ( GetConnectionState() == estCONNECTED )
	{
		SetConnection(FALSE);
		Disconnect();
	}
}

/** */
void DCClient::slotContextMenuUserList( const QPoint & )
{
	QAction * chosen = 0;
	QMenu *m,*mslot;
	DCMenuHandler mhandler;
	QString username;
	CList<CString> selitems;
	CList<DC_UserMenuCommand> usercommands;
	DC_UserMenuCommand * umc = 0; 
	CString * ps;
	int numSelected;
	QString usercommand, origUserCommand;

	numSelected = selectedItems(&selitems);

	m = new QMenu(this);

	if ( numSelected == 1 )
	{
		ps = 0;
		ps=selitems.Next(ps);
		
		username = QString::fromAscii(ps->Data());
		mhandler.addAction( m, emiUSER_CAPTION, FALSE, tr("User: ") + username );
	}
	else
	{
		QString numUsers;
		numUsers.setNum(numSelected);
		mhandler.addAction( m, emiUSER_CAPTION, FALSE, numUsers + tr(" users") );
	}

	mhandler.addAction( m, emiSEPARATOR );
	QAction * privchat = mhandler.addAction( m, emiPRIVATE_CHAT, (numSelected > 0) );
	QAction * addfriend = mhandler.addAction( m, emiADD_FRIEND, (numSelected > 0) );
	QAction * browse = mhandler.addAction( m, emiBROWSE_USER_FILES, (numSelected > 0) );
	mhandler.addAction( m, emiSEPARATOR );
	
	mslot = mhandler.addMenu( m, emiUPLOAD_SLOT, TRUE );
	QAction * addslot = mhandler.addAction( mslot, emiADD, (numSelected > 0) );
	QAction * addperm = mhandler.addAction( mslot, emiADD_PERMANENT, (numSelected > 0) );
	QAction * remslot = mhandler.addAction( mslot, emiREMOVE, (numSelected > 0) );

	mhandler.addAction( m, emiSEPARATOR );
	QAction * upduser = mhandler.addAction( m, emiUPDATE_USER, (numSelected > 0) );
	QAction * reloadlist = mhandler.addAction( m, emiRELOAD_USERLIST, (GetConnectionState() == estCONNECTED) );
	mhandler.addAction( m, emiSEPARATOR );
	QAction * copycol = mhandler.addAction( m, emiCOPY_COLUMN_TO_CLIPBOARD, (numSelected == 1) );
	QAction * copyrow = mhandler.addAction( m, emiCOPY_ROW_TO_CLIPBOARD, (numSelected > 0) );

	mhandler.addAction( m, emiSEPARATOR );
	QAction * checkver = mhandler.addAction( m, emiCHECK_CLIENT_VERSION, numSelected > 0 );

	QAction * kick = 0;
	QAction * forcemove = 0;
	QAction * getip = 0;
	
	if ( UserList()->IsAdmin(GetNick()) )
	{
		kick = mhandler.addAction( m, emiKICK, UserList()->IsAdmin(GetNick()) && (numSelected > 0) );
		forcemove = mhandler.addAction( m, emiFORCE_MOVE, UserList()->IsAdmin(GetNick()) && (numSelected > 0) );
		getip = mhandler.addAction( m, emiGET_USER_IP, UserList()->IsAdmin(GetNick()) && (numSelected > 0) && GetSupportsUserIP2() );
	}
	
	mhandler.addAction( m, emiSEPARATOR );

	g_pConfig->GetUserMenuCommands(&usercommands);
	
	while( (umc=usercommands.Next(umc)) != 0 )
	{
		if ( (umc->m_nContext & 2) == 2 )
		{
			umc->m_pAction = m->addAction( umc->m_sName.Data() );
			umc->m_pAction->setEnabled( numSelected > 0 );
		}
	}
	
	chosen = m->exec(QCursor::pos());

	delete m;

	if ( chosen == 0 )
	{
		return;
	}
	else if ( chosen == privchat )
	{
		for(ps=0;(ps=selitems.Next(ps)) != 0;)
		{
			DC_PrivateChat( QString::fromAscii(ps->Data()), "", "", TRUE );
		}
	}
	else if ( chosen == addfriend )
	{
		for(ps=0;(ps=selitems.Next(ps)) != 0;)
		{
			g_pUsersList->AddFriend( ps->Data(), GetHubName(), GetHost(), "" );
		}
	}
	else if ( chosen == browse )
	{
		if ( GetMode() == ecmNONE )
		{
			return;
		}

		for(ps=0;(ps=selitems.Next(ps)) != 0;)
		{
			/** add transfer to the waitlist */
			g_pTransferView->DLM_QueueAdd( ps->Data(), GetHubName(), GetIP()+":"+QString().setNum(GetPort()).toAscii().data(),
						DC_USER_FILELIST_HE3, DC_USER_FILELIST_HE3, "", "", eltBUFFER,
						0, 0, 0, "" );
		}
	}
	else if ( chosen == checkver )
	{
		if ( GetMode() == ecmNONE )
		{
			return;
		}

		for(ps=0;(ps=selitems.Next(ps)) != 0;)
		{
			/** add transfer to the waitlist */
			g_pTransferView->DLM_QueueAdd( ps->Data(), GetHubName(), GetIP()+":"+QString().setNum(GetPort()).toAscii().data(),
						"client check", "client check", "", "", eltCLIENTVERSION,
						0, 0, 0, "" );
		}
	}
	else if ( chosen == upduser )
	{
		for(ps=0;(ps=selitems.Next(ps)) != 0;)
		{
			SendGetInfo( *ps, GetNick() );
		}
	}
	else if ( chosen == copycol )
	{
		QModelIndex index = TreeView_USERLIST->selectionModel()->currentIndex();
		
		QApplication::clipboard()->setText( m_pUserListModel->data( index ).toString() );
	}
	else if ( chosen == copyrow )
	{
		QString s = "";
		
		QModelIndexList indexes = TreeView_USERLIST->selectionModel()->selectedRows( COLUMN_NICK );
		
		for ( int i = 0; i < indexes.size(); i++ )
		{
			for ( int j = 0; j <= COLUMN_SUPPORTS; j++ )
			{
				if ( TreeView_USERLIST->isColumnHidden(j) == FALSE )
				{
					QModelIndex index = m_pUserListModel->index( indexes.at(i).row(), j, QModelIndex() );
					s += m_pUserListModel->data( index ).toString();
					s += " ";
				}
			}
			
			s += "\n";
		}
		
		QApplication::clipboard()->setText(s);
	}
	else if ( chosen == addslot )
	{
		for(ps=0;(ps=selitems.Next(ps)) != 0;)
		{
			g_pTransferView->DLM_AddUserSlot(*ps, GetHubName(), 1);
		}
	}
	else if ( chosen == addperm )
	{
		for(ps=0;(ps=selitems.Next(ps)) != 0;)
		{
			g_pTransferView->DLM_AddUserSlot(*ps, GetHubName(), 0);
			g_pTransferView->DLM_AddUserSlot(*ps, GetHubName(), 0, TRUE);
		}
	}
	else if ( chosen == remslot )
	{
		for(ps=0;(ps=selitems.Next(ps)) != 0;)
		{
			g_pTransferView->DLM_AddUserSlot(*ps, GetHubName(), 0);
		}
	}
	else if ( chosen == kick )
	{
		QString kickmessage;

		if ( !GetOPKickMessage(kickmessage) )
		{
			return;
		}
		
		for(ps=0;(ps=selitems.Next(ps)) != 0;)
		{
			OPKick( ps->Data(), kickmessage );
		}
	}
	else if ( chosen == forcemove )
	{
		QString host,message;

		if ( !GetOPForceMoveMessage(message,host) )
		{
			return;
		}
				
		for(ps=0;(ps=selitems.Next(ps)) != 0;)
		{
			OPForceMove( ps->Data(), message, host );
		}
	}
	else if ( chosen == getip )
	{
		for( ps=0; (ps=selitems.Next(ps)) != 0; )
		{
			SendString( CString("$UserIP ") + ps->Data() + CString("|") );
		}
	}
	else if ( chosen == reloadlist )
	{
		RequestNickList();
	}
	else
	{
		umc = 0;
		while( (umc=usercommands.Next(umc)) != 0 )
		{
			if ( (umc->m_pAction != 0) && (chosen == umc->m_pAction) )
			{
				usercommand = umc->m_sCommand.Data();
				
				origUserCommand = usercommand;
				
				for(ps=0;(ps=selitems.Next(ps)) != 0;)
				{
					usercommand = replaceCommandTags( origUserCommand, ps->Data() );
					
					m_pHubChat->AddStatus(usercommand.toAscii().data());
					SendString(usercommand.toAscii().data());
				}
			}
		}
	}
}

void DCClient::slotSaveColumnWidth(int section, int /*oldSize*/, int newSize)
{
	eClientColumn mapped_section;

	if (section == 0)
		mapped_section = eclcNICK;
	else
		mapped_section = eClientColumn(section - 1);
	g_pConfig->SetClientColumnWidth( mapped_section, newSize );
}

/** */
bool DCClient::GetOPKickMessage( QString & message )
{
	bool ok = FALSE;

	message = QInputDialog::getText(
		tr("OP Kick"),
		tr("Please enter a reason"),
		QLineEdit::Normal, QString::null, &ok, 0 );

	return ok;
}

/** */
bool DCClient::GetOPForceMoveMessage( QString & message, QString & host )
{
	bool ret = FALSE;
	
	QDialog * dialog = new QDialog();
	dialog->setCaption(tr("OP Force Move"));
	
	QVBoxLayout * vbl = new QVBoxLayout(dialog);
	
	QLabel * label1 = new QLabel(tr("Please enter host"),dialog);
	QLineEdit * edit1 = new QLineEdit(dialog);
	QLabel * label2 = new QLabel(tr("Please enter a message"),dialog);
	QLineEdit * edit2 = new QLineEdit(dialog);
	
	vbl->addWidget(label1);
	vbl->addWidget(edit1);
	vbl->addWidget(label2);
	vbl->addWidget(edit2);
	
	QHBoxLayout * hbl = new QHBoxLayout(vbl);
	QPushButton * confirm = new QPushButton(tr("OK"),dialog);
	confirm->setIcon(qApp->style()->standardIcon(QStyle::SP_DialogOkButton,0,confirm));
	confirm->setDefault(TRUE);
	QPushButton * cancel = new QPushButton(tr("Cancel"),dialog);
	cancel->setIcon(qApp->style()->standardIcon(QStyle::SP_DialogCancelButton,0,cancel));
	
	connect( confirm, SIGNAL(clicked()), dialog, SLOT(accept()) );
	connect( cancel, SIGNAL(clicked()), dialog, SLOT(reject()) );
	
	hbl->addWidget(confirm);
	hbl->addWidget(cancel);
	
	if ( dialog->exec() == QDialog::Accepted )
	{
		host = edit1->text();
		message = edit2->text();
		ret = TRUE;
	}
	
	delete dialog;
	
	return ret;
}

/** */
bool DCClient::OPKick( QString nick, QString message )
{
	bool res = FALSE;

	SendPrivateMessage( GetNick(), nick.toAscii().data(), ("You are being kicked because: " + message).toAscii().data());
	SendChat( GetNick(), GetNick() + " is kicking " + nick.toAscii().data() + " because: " + message.toAscii().data() );
	SendKick(nick.toAscii().data());

	return res;
}

/** */
bool DCClient::OPForceMove( QString nick, QString message, QString host )
{
	bool res = FALSE;

	SendOpForceMove( nick.toAscii().data(), host.toAscii().data(), message.toAscii().data() );

	return res;
}

/** */
void DCClient::slotDoubleClickedUserChat( QListWidgetItem * item )
{
	DCChat * chat;
	QString nick;

	if ( item == 0 )
	{
		return;
	}

	nick = item->text();

	if ( nick == "" )
	{
		return;
	}

	if ( m_pChatList->Get( nick.toAscii().data(), (CObject*&)chat ) == 0 )
	{
		if ( !m_bUseTabWidget )
			chat->setEnabled(TRUE);
		chat->show();
		m_pUserListModel->setHighlight( nick, FALSE );
        }
}

/** */
QString DCClient::findNick( QString part, uint which )
{
/*
	for(uint i=0; i < nicks->count(); i++)
	{
		if (matches.contains(nicks->text(i)))
			continue;
		if(qstrlen(nicks->text(i)) >= part.length())
		{
			if(qstrnicmp(part, nicks->text(i), part.length()) == 0)
			{
				QString qsNick = ksopts->nick;
				if(qstrcmp(nicks->text(i), qsNick) != 0)
				{ // Don't match your own nick
					matches.append(nicks->text(i));
				}
			}
		}
	}
*/
	QStringList matches;
	
	if ( part.lower() == lastPart )
	{
		matches = lastMatches;
	}
	else
	{
		if ( g_pConfig->GetTabCompleteMatchMode() == 0 )
		{
			matches = m_pUserListModel->matchNicksContaining(part.lower(), g_pConfig->GetTabCompleteStripTags());
		}
		else
		{
			matches = m_pUserListModel->matchNicksStartingWith(part.lower(), g_pConfig->GetTabCompleteStripTags());
		}
		
		lastMatches = matches;
		lastPart = part.lower();
	}

	//printf("matches='%s'\n", matches.join(",").toAscii().data());

	if(matches.count() > 0)
	{
		if(which < matches.count())
			return matches.at(which);
		else
			return QString::null;
	}

	return part;
}

void DCClient::slotTabCornerCloseWidgetClicked()
{
	CloseChat( (DCChat*) TabWidget_CHAT->currentPage() );
}

/** Replaces the %[tag] s in the command with the proper values */
QString DCClient::replaceCommandTags(QString command, QString remotenick)
{
	QString usercommand = command;
	
	usercommand.replace( "%[mynick]", GetNick().Data() );
	usercommand.replace( "%[myNI]", GetNick().Data() );
	
	QString comtag = GetComment().Data();
	QString comment = comtag.mid(0, comtag.find('<'));
	QString tag = comtag.mid(comtag.find('<'));
	
	usercommand.replace( "%[mytag]", tag );
	usercommand.replace( "%[myTAG]", tag );
	
	usercommand.replace( "%[mydescription]", comment );
	usercommand.replace( "%[myDE]", comment );
	
	usercommand.replace( "%[myemail]", GetEMail().Data() );
	usercommand.replace( "%[myEM]", GetEMail().Data() );
	
	usercommand.replace( "%[myshare]", GetShareSize().Data() );
	usercommand.replace( "%[mySS]", GetShareSize().Data() );
	
	usercommand.replace( "%[myshareshort]", CUtils::GetSizeString(GetShareSize().asULL(), euAUTO).Data() );
	usercommand.replace( "%[mySSshort]", CUtils::GetSizeString(GetShareSize().asULL(), euAUTO).Data() );
	
	usercommand.replace( "%[myip]", g_pConfig->GetTCPHostString( FALSE ).Data() );
	usercommand.replace( "%[myI4]", g_pConfig->GetTCPHostString( FALSE ).Data() );
	
	usercommand.replace( "%[nick]", remotenick );
	usercommand.replace( "%[userNI]", remotenick );
	
	if ( m_pMyInfoHash->contains( remotenick ) == FALSE )
	{
		//printf("Warning: nick \"%s\" not found in userlist.\n", remotenick.toAscii().data());
	}
	else
	{
		CMessageMyInfo myinfo = m_pMyInfoHash->value( remotenick );
		
		usercommand.replace( "%[userTAG]", myinfo.m_sVerComment.Data() );
		usercommand.replace( "%[tag]", myinfo.m_sVerComment.Data() );
		
		usercommand.replace( "%[userDE]", myinfo.m_sComment.Data() );
		usercommand.replace( "%[description]", myinfo.m_sComment.Data() );
		
		usercommand.replace( "%[userSS]", QString::number(myinfo.m_nShared) );
		usercommand.replace( "%[share]", QString::number(myinfo.m_nShared) );
		
		QString ss = CUtils::GetSizeString( myinfo.m_nShared, g_pConfig->GetUnit() ).Data();
		usercommand.replace( "%[userSSshort]", ss );
		usercommand.replace( "%[shareshort]", ss );
		
		usercommand.replace( "%[userEM]", myinfo.m_sEMail.Data() );
		usercommand.replace( "%[email]", myinfo.m_sEMail.Data() );
		
		usercommand.replace( "%[userI4]", myinfo.m_sTransferHost.Data() );
		usercommand.replace( "%[ip]", myinfo.m_sTransferHost.Data() );
	}
	
	while ( usercommand.find("%[line:") != -1 )
	{
		bool ok;
		int loc = usercommand.find("%[line:");
		int end = usercommand.find("]", loc);
		
		// 7 is length of "%[line:"
		QString reason = usercommand.mid(loc + 7, end - (loc + 7));
		
		QString text = QInputDialog::getText(
		tr("User command for ") + remotenick,
		reason,
		QLineEdit::Normal,
		QString::null,
		&ok,
		this
		);
	
		//if ( ok && !text.isEmpty() )
		//{
			usercommand.replace( "%[line:" + reason + "]", text );
		//}
	}
					
	{
		struct tm * t;
		time_t ti;
		char timed[2048];
						
		ti = time(0);
		t  = localtime(&ti);
		strftime(timed, sizeof(timed), usercommand.toAscii().data(), t);
		usercommand = timed;
	}
	
	return usercommand;
}

void DCClient::doAutoResponse( QString nick, QString message, DCChat * chatobject )
{
	long delay = g_pConfig->GetAutoResponseDelay();
	long now = QDateTime::currentDateTime().toTime_t();
	
	if ( (delay > 0) &&
	     (nick == lastAutoNick) &&
	     (now < delay + lastAutoResponseTime)
	   )
	{
		// avoid spamming
		//printf("Auto response spam protection!\n");
		return;
	}
	
	// null pointer check
	if (chatobject == 0)
	{
		printf("Error: DCClient::doAutoResponse called with NULL chatobject!\n");
		return;
	}
	
	// do not respond to ourself
	if (nick == this->GetNick())
	{
		//printf("Not auto-responding to ourself.\n");
		return;
	}
	
	// check for ignored nicks
	CString ignores = g_pConfig->GetAutoResponseIgnores();
	if (ignores != "")
	{
		QRegExp ignore_re;
		ignore_re.setPattern(ignores.Data());
		ignore_re.setCaseSensitive(FALSE);
		if (ignore_re.search(nick) != -1)
		{
			//printf("Not auto responding to %s\n", nick.toAscii().data());
			return;
		}
	}
	
	CList<DC_AutoResponseObject> arlist;
	DC_AutoResponseObject * aro = 0;
	
	g_pConfig->GetAutoResponses(&arlist);
	
	QRegExp re;
	
	while ((aro=arlist.Next(aro)) != 0)
	{
		re.setPattern(aro->m_sTrigger.Data());
		re.setCaseSensitive(aro->m_bCaseSensitive);
		if (re.search(message) != -1) // pattern matches
		{
			QString chat = this->replaceCommandTags( aro->m_sResponse.Data(), nick );
			//this->SendChat( this->GetNick(), chat.toAscii().data() );
			chatobject->TextEdit_CHATINPUT->setPlainText(chat);
			chatobject->SendMessage( "" );
			
			// update last nick and time for anti-spam
			lastAutoNick = nick;
			lastAutoResponseTime = QDateTime::currentDateTime().toTime_t();
			
			// stop searching list of triggers
			break;
		}
	}
}

/** */
void DCClient::jumpToNick( const QString & nick )
{
	QModelIndex topLeft = m_pUserListModel->indexForNick( nick );
	QModelIndex bottomRight = m_pUserListModel->index( topLeft.row(), COLUMN_SUPPORTS, QModelIndex() );
	QItemSelection sel( topLeft, bottomRight );
	TreeView_USERLIST->selectionModel()->select( sel, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current );
	TreeView_USERLIST->scrollTo( topLeft, QAbstractItemView::EnsureVisible );
}

/** */
void DCClient::disableUserListSorting()
{
	TreeView_USERLIST->setSortingEnabled( FALSE );
	m_pUserListModel->sort( -1 );
}

/** */
void DCClient::enableUserListSorting()
{
	TreeView_USERLIST->setSortingEnabled( TRUE );
	TreeView_USERLIST->sortByColumn( COLUMN_NICK, Qt::AscendingOrder );
}

/** */
void DCClient::centreOnMdiArea()
{
	// centre window within workspace otherwise the top left corner
	// ends up in the centre so most of it is off the screen
	if ( (m_pMdiArea != 0) &&
	     (m_pContainerWindow != 0) &&
	     (m_pContainerWindow->isMinimized() == FALSE) &&
	     (m_pContainerWindow->isMaximized() == FALSE)
	   )
	{
		int newx = (m_pMdiArea->width() - m_pContainerWindow->width())/2;
		int newy = (m_pMdiArea->height() - m_pContainerWindow->height())/2;
		
		if ( newx < 0 )
		{
			newx = 0;
		}
		
		if ( newy < 0 )
		{
			newy = 0;
		}
		
		m_pContainerWindow->move(newx,newy);
	}
}
