
/***************************************************************************
                jabberclient.cpp - Generic Jabber Client Class
                             -------------------
    begin                : Sat May 25 2005
    copyright            : (C) 2005 by Till Gerken <till@tantalo.net>
                           (C) 2006 by Michaël Larouche <michael.larouche@kdemail.net>

			   Kopete (C) 2001-2006 Kopete developers
			   <kopete-devel@kde.org>.
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "jabberclient.h"

#include <tqtimer.h>
#include <tqregexp.h>

#include <tqca.h>
#include <bsocket.h>
#include <filetransfer.h>
#include <xmpp_tasks.h>

#include "jabberconnector.h"

#define JABBER_PENALTY_TIME	2

class JabberClient::Private
{
public:
	Private()
	 : jabberClient(0L), jabberClientStream(0L), jabberClientConnector(0L), jabberTLS(0L), jabberTLSHandler(0L)
	{}
	~Private()
	{
		if ( jabberClient )
		{
			jabberClient->close ();
		}
		
		delete jabberClient;
		delete jabberClientStream;
		delete jabberClientConnector;
		delete jabberTLSHandler;
		delete jabberTLS;
	}

	// connection details
	XMPP::Jid jid;
	TQString password;

	// XMPP backend
	XMPP::Client *jabberClient;
	XMPP::ClientStream *jabberClientStream;
	JabberConnector *jabberClientConnector;
	TQCA::TLS *jabberTLS;
	XMPP::TQCATLSHandler *jabberTLSHandler;

	// ignore TLS warnings
	bool ignoreTLSWarnings;

	// current S5B server instance
	static XMPP::S5BServer *s5bServer;
	// address list being handled by the S5B server instance
	static TQStringList s5bAddressList;
	// port of S5B server
	static int s5bServerPort;

	// local IP address
	TQString localAddress;

	// whether TLS (or direct SSL in case of the old protocol) should be used
	bool forceTLS;

	// whether direct SSL connections should be used
	bool useSSL;

	// use XMPP 1.0 or the older protocol version
	bool useXMPP09;

	// whether SSL support should be probed in case the old protocol is used
	bool probeSSL;

	// override the default server name and port (only pre-XMPP 1.0)
	bool overrideHost;
	TQString server;
	int port;

	// allow transmission of plaintext passwords
	bool allowPlainTextPassword;

	// enable file transfers
	bool fileTransfersEnabled;

	// current penalty time
	int currentPenaltyTime;

	// client information
	TQString clientName, clientVersion, osName;

	// timezone information
	TQString timeZoneName;
	int timeZoneOffset;

	// Caps(JEP-0115: Entity Capabilities) information
	TQString capsNode, capsVersion;
	DiscoItem::Identity discoIdentity;
};

XMPP::S5BServer *JabberClient::Private::s5bServer = 0L;
TQStringList JabberClient::Private::s5bAddressList;
int JabberClient::Private::s5bServerPort = 8010;

JabberClient::JabberClient ()
{
	d = new Private();

	cleanUp ();

	// initiate penalty timer
	TQTimer::singleShot ( JABBER_PENALTY_TIME * 1000, this, TQ_SLOT ( slotUpdatePenaltyTime () ) );

}

JabberClient::~JabberClient ()
{
	delete d;
}

void JabberClient::cleanUp ()
{
	if ( d->jabberClient )
	{
		d->jabberClient->close ();
	}
	
	delete d->jabberClient;
	delete d->jabberClientStream;
	delete d->jabberClientConnector;
	delete d->jabberTLSHandler;
	delete d->jabberTLS;

	d->jabberClient = 0L;
	d->jabberClientStream = 0L;
	d->jabberClientConnector = 0L;
	d->jabberTLSHandler = 0L;
	d->jabberTLS = 0L;

	d->currentPenaltyTime = 0;

	d->jid = XMPP::Jid ();
	d->password = TQString();

	setForceTLS ( false );
	setUseSSL ( false );
	setUseXMPP09 ( false );
	setProbeSSL ( false );

	setOverrideHost ( false );

	setAllowPlainTextPassword ( true );

	setFileTransfersEnabled ( false );
	setS5BServerPort ( 8010 );

	setClientName ( TQString() );
	setClientVersion ( TQString() );
	setOSName ( TQString() );

	setTimeZone ( "UTC", 0 );

	setIgnoreTLSWarnings ( false );

}

void JabberClient::slotUpdatePenaltyTime ()
{

	if ( d->currentPenaltyTime >= JABBER_PENALTY_TIME )
		d->currentPenaltyTime -= JABBER_PENALTY_TIME;
	else
		d->currentPenaltyTime = 0;

	TQTimer::singleShot ( JABBER_PENALTY_TIME * 1000, this, TQ_SLOT ( slotUpdatePenaltyTime () ) );

}

void JabberClient::setIgnoreTLSWarnings ( bool flag )
{

	d->ignoreTLSWarnings = flag;

}

bool JabberClient::ignoreTLSWarnings ()
{

	return d->ignoreTLSWarnings;

}

bool JabberClient::setS5BServerPort ( int port )
{

	d->s5bServerPort = port;

	if ( fileTransfersEnabled () )
	{
		return s5bServer()->start ( port );
	}

	return true;

}

int JabberClient::s5bServerPort () const
{

	return d->s5bServerPort;

}

XMPP::S5BServer *JabberClient::s5bServer ()
{

	if ( !d->s5bServer )
	{
		d->s5bServer = new XMPP::S5BServer ();
		TQObject::connect ( d->s5bServer, TQ_SIGNAL ( destroyed () ), this, TQ_SLOT ( slotS5BServerGone () ) );

		/*
		 * Try to start the server at the default port here.
		 * We have no way of notifying the caller of an error.
		 * However, since the caller will usually also
		 * use setS5BServerPort() to ensure the correct
		 * port, we can return an error code there.
		 */
		if ( fileTransfersEnabled () )
		{
			s5bServer()->start ( d->s5bServerPort );
		}
	}

	return d->s5bServer;

}

void JabberClient::slotS5BServerGone ()
{

	d->s5bServer = 0L;

	if ( d->jabberClient )
		d->jabberClient->s5bManager()->setServer( 0L );

}

void JabberClient::addS5BServerAddress ( const TQString &address )
{
	TQStringList newList;

	d->s5bAddressList.append ( address );

	// now filter the list without dupes
	for ( TQStringList::Iterator it = d->s5bAddressList.begin (); it != d->s5bAddressList.end (); ++it )
	{
		if ( !newList.contains ( *it ) )
			newList.append ( *it );
	}

	s5bServer()->setHostList ( newList );

}

void JabberClient::removeS5BServerAddress ( const TQString &address )
{
	TQStringList newList;

	TQStringList::iterator it = d->s5bAddressList.find ( address );
	if ( it != d->s5bAddressList.end () )
	{
		d->s5bAddressList.remove ( it );
	}

	if ( d->s5bAddressList.isEmpty () )
	{
		delete d->s5bServer;
		d->s5bServer = 0L;
	}
	else
	{
		// now filter the list without dupes
		for ( TQStringList::Iterator it = d->s5bAddressList.begin (); it != d->s5bAddressList.end (); ++it )
		{
			if ( !newList.contains ( *it ) )
				newList.append ( *it );
		}

		s5bServer()->setHostList ( newList );
	}

}

void JabberClient::setForceTLS ( bool flag )
{

	d->forceTLS = flag;

}

bool JabberClient::forceTLS () const
{

	return d->forceTLS;

}

void JabberClient::setUseSSL ( bool flag )
{

	d->useSSL = flag;

}

bool JabberClient::useSSL () const
{

	return d->useSSL;

}

void JabberClient::setUseXMPP09 ( bool flag )
{

	d->useXMPP09 = flag;

}

bool JabberClient::useXMPP09 () const
{

	return d->useXMPP09;

}

void JabberClient::setProbeSSL ( bool flag )
{

	d->probeSSL = flag;

}

bool JabberClient::probeSSL () const
{

	return d->probeSSL;

}

void JabberClient::setOverrideHost ( bool flag, const TQString &server, int port )
{

	d->overrideHost = flag;
	d->server = server;
	d->port = port;

}

bool JabberClient::overrideHost () const
{

	return d->overrideHost;

}

void JabberClient::setAllowPlainTextPassword ( bool flag )
{

	d->allowPlainTextPassword = flag;

}

bool JabberClient::allowPlainTextPassword () const
{

	return d->allowPlainTextPassword;

}

void JabberClient::setFileTransfersEnabled ( bool flag, const TQString &localAddress )
{

	d->fileTransfersEnabled = flag;
	d->localAddress = localAddress;

}

TQString JabberClient::localAddress () const
{

	return d->localAddress;

}

bool JabberClient::fileTransfersEnabled () const
{

	return d->fileTransfersEnabled;

}

void JabberClient::setClientName ( const TQString &clientName )
{

	d->clientName = clientName;

}

TQString JabberClient::clientName () const
{

	return d->clientName;

}

void JabberClient::setClientVersion ( const TQString &clientVersion )
{

	d->clientVersion = clientVersion;

}

TQString JabberClient::clientVersion () const
{

	return d->clientVersion;

}

void JabberClient::setOSName ( const TQString &osName )
{

	d->osName = osName;

}

TQString JabberClient::osName () const
{

	return d->osName;

}

void JabberClient::setCapsNode( const TQString &capsNode )
{
	d->capsNode = capsNode;
}

TQString JabberClient::capsNode() const
{
	return d->capsNode;
}

void JabberClient::setCapsVersion( const TQString &capsVersion )
{
	d->capsVersion = capsVersion;
}

TQString JabberClient::capsVersion() const
{
	return d->capsVersion;
}

TQString JabberClient::capsExt() const
{
	if(d->jabberClient)
	{
		return d->jabberClient->capsExt();
	}

	return TQString();
}
void JabberClient::setDiscoIdentity( DiscoItem::Identity identity )
{
	d->discoIdentity = identity;
}

DiscoItem::Identity JabberClient::discoIdentity() const
{
	return d->discoIdentity;
}

void JabberClient::setTimeZone ( const TQString &timeZoneName, int timeZoneOffset )
{

	d->timeZoneName = timeZoneName;
	d->timeZoneOffset = timeZoneOffset;

}

TQString JabberClient::timeZoneName () const
{

	return d->timeZoneName;

}

int JabberClient::timeZoneOffset () const
{

	return d->timeZoneOffset;

}

int JabberClient::getPenaltyTime ()
{

	int currentTime = d->currentPenaltyTime;

	d->currentPenaltyTime += JABBER_PENALTY_TIME;

	return currentTime;

}

XMPP::Client *JabberClient::client () const
{

	return d->jabberClient;

}

XMPP::ClientStream *JabberClient::clientStream () const
{

	return d->jabberClientStream;

}

JabberConnector *JabberClient::clientConnector () const
{

	return d->jabberClientConnector;

}

XMPP::Task *JabberClient::rootTask () const
{

	if ( client () )
	{
		return client()->rootTask ();
	}
	else
	{
		return 0l;
	}

}

XMPP::FileTransferManager *JabberClient::fileTransferManager () const
{

	if ( client () )
	{
		return client()->fileTransferManager ();
	}
	else
	{
		return 0L;
	}

}

XMPP::Jid JabberClient::jid () const
{

	return d->jid;

}

JabberClient::ErrorCode JabberClient::connect ( const XMPP::Jid &jid, const TQString &password, bool auth )
{
	/*
	 * Close any existing connection.
	 */
	if ( d->jabberClient )
	{
		d->jabberClient->close ();
	}

	d->jid = jid;
	d->password = password;

	/*
	 * Return an error if we should force TLS but it's not available.
	 */
	if ( ( forceTLS () || useSSL () || probeSSL () ) && !TQCA::isSupported ( TQCA::CAP_TLS ) )
	{
		return NoTLS;
	}

	/*
	 * Instantiate connector, responsible for dealing with the socket.
	 * This class uses KDE's socket code, which in turn makes use of
	 * the global proxy settings.
	 */
	d->jabberClientConnector = new JabberConnector;

	d->jabberClientConnector->setOptSSL ( useSSL () );

	if ( useXMPP09 () )
	{
		if ( overrideHost () )
		{
			d->jabberClientConnector->setOptHostPort ( d->server, d->port );
		}

		d->jabberClientConnector->setOptProbe ( probeSSL () );

	}

	/*
	 * Setup authentication layer
	 */
	if ( TQCA::isSupported ( TQCA::CAP_TLS ) )
	{
		d->jabberTLS = new TQCA::TLS;
		d->jabberTLSHandler = new XMPP::TQCATLSHandler ( d->jabberTLS );

		{
			using namespace XMPP;
			TQObject::connect ( d->jabberTLSHandler, TQ_SIGNAL ( tlsHandshaken() ), this, TQ_SLOT ( slotTLSHandshaken () ) );
		}

		TQPtrList<TQCA::Cert> certStore;
		d->jabberTLS->setCertificateStore ( certStore );
	}

	/*
	 * Instantiate client stream which handles the network communication by referring
	 * to a connector (proxying etc.) and a TLS handler (security layer)
	 */
	d->jabberClientStream = new XMPP::ClientStream ( d->jabberClientConnector, d->jabberTLSHandler );

	{
		using namespace XMPP;
		TQObject::connect ( d->jabberClientStream, TQ_SIGNAL ( needAuthParams(bool, bool, bool) ),
				   this, TQ_SLOT ( slotCSNeedAuthParams (bool, bool, bool) ) );
		TQObject::connect ( d->jabberClientStream, TQ_SIGNAL ( authenticated () ),
				   this, TQ_SLOT ( slotCSAuthenticated () ) );
		TQObject::connect ( d->jabberClientStream, TQ_SIGNAL ( connectionClosed () ),
				   this, TQ_SLOT ( slotCSDisconnected () ) );
		TQObject::connect ( d->jabberClientStream, TQ_SIGNAL ( delayedCloseFinished () ),
				   this, TQ_SLOT ( slotCSDisconnected () ) );
		TQObject::connect ( d->jabberClientStream, TQ_SIGNAL ( warning (int) ),
				   this, TQ_SLOT ( slotCSWarning (int) ) );
		TQObject::connect ( d->jabberClientStream, TQ_SIGNAL ( error (int) ),
				   this, TQ_SLOT ( slotCSError (int) ) );
	}

	d->jabberClientStream->setOldOnly ( useXMPP09 () );

	/*
	 * Initiate anti-idle timer (will be triggered every 55 seconds).
	 */
	d->jabberClientStream->setNoopTime ( 55000 );

	/*
	 * Allow plaintext password authentication or not?
	 */
	d->jabberClientStream->setAllowPlain( allowPlainTextPassword () );

	/*
	 * Setup client layer.
	 */
	d->jabberClient = new XMPP::Client ( this );

	/*
	 * Enable file transfer (IP and server will be set after connection
	 * has been established.
	 */
	if ( fileTransfersEnabled () )
	{
		d->jabberClient->setFileTransferEnabled ( true );

		{
			using namespace XMPP;
			TQObject::connect ( d->jabberClient->fileTransferManager(), TQ_SIGNAL ( incomingReady() ),
					   this, TQ_SLOT ( slotIncomingFileTransfer () ) );
		}
	}

	/* This should only be done here to connect the signals, otherwise it is a
	 * bad idea.
	 */
	{
		using namespace XMPP;
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( subscription (const Jid &, const TQString &) ),
				   this, TQ_SLOT ( slotSubscription (const Jid &, const TQString &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( rosterRequestFinished ( bool, int, const TQString & ) ),
				   this, TQ_SLOT ( slotRosterRequestFinished ( bool, int, const TQString & ) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( rosterItemAdded (const RosterItem &) ),
				   this, TQ_SLOT ( slotNewContact (const RosterItem &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( rosterItemUpdated (const RosterItem &) ),
				   this, TQ_SLOT ( slotContactUpdated (const RosterItem &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( rosterItemRemoved (const RosterItem &) ),
				   this, TQ_SLOT ( slotContactDeleted (const RosterItem &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( resourceAvailable (const Jid &, const Resource &) ),
				   this, TQ_SLOT ( slotResourceAvailable (const Jid &, const Resource &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( resourceUnavailable (const Jid &, const Resource &) ),
				   this, TQ_SLOT ( slotResourceUnavailable (const Jid &, const Resource &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( messageReceived (const Message &) ),
				   this, TQ_SLOT ( slotReceivedMessage (const Message &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( groupChatJoined (const Jid &) ),
				   this, TQ_SLOT ( slotGroupChatJoined (const Jid &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( groupChatLeft (const Jid &) ),
				   this, TQ_SLOT ( slotGroupChatLeft (const Jid &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( groupChatPresence (const Jid &, const Status &) ),
				   this, TQ_SLOT ( slotGroupChatPresence (const Jid &, const Status &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( groupChatError (const Jid &, int, const TQString &) ),
				   this, TQ_SLOT ( slotGroupChatError (const Jid &, int, const TQString &) ) );
		//TQObject::connect ( d->jabberClient, TQ_SIGNAL (debugText (const TQString &) ),
		//		   this, TQ_SLOT ( slotPsiDebug (const TQString &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( xmlIncoming(const TQString& ) ),
				   this, TQ_SLOT ( slotIncomingXML (const TQString &) ) );
		TQObject::connect ( d->jabberClient, TQ_SIGNAL ( xmlOutgoing(const TQString& ) ),
				   this, TQ_SLOT ( slotOutgoingXML (const TQString &) ) );
	}

	d->jabberClient->setClientName ( clientName () );
	d->jabberClient->setClientVersion ( clientVersion () );
	d->jabberClient->setOSName ( osName () );

	// Set caps information
	d->jabberClient->setCapsNode( capsNode() );
	d->jabberClient->setCapsVersion( capsVersion() );
	
	// Set Disco Identity
	d->jabberClient->setIdentity( discoIdentity() );

	d->jabberClient->setTimeZone ( timeZoneName (), timeZoneOffset () );

	d->jabberClient->connectToServer ( d->jabberClientStream, jid, auth );

	return Ok;

}

void JabberClient::disconnect ()
{

	if ( d->jabberClient )
	{
		d->jabberClient->close ();
	}
	else
	{
		cleanUp ();
	}

}

void JabberClient::disconnect( XMPP::Status &reason )
{
    if ( d->jabberClient )
    {
        if ( d->jabberClientStream->isActive() )
        {
            XMPP::JT_Presence *pres = new JT_Presence(rootTask());
            reason.setIsAvailable( false );
            pres->pres( reason );
            pres->go();
            
            d->jabberClientStream->close();
            d->jabberClient->close();
        }
    }
    else
    {
        cleanUp();
    }
}

bool JabberClient::isConnected () const
{

	if ( d->jabberClient )
	{
		return d->jabberClient->isActive ();
	}

	return false;

}

void JabberClient::joinGroupChat ( const TQString &host, const TQString &room, const TQString &nick )
{

	client()->groupChatJoin ( host, room, nick );

}

void JabberClient::joinGroupChat ( const TQString &host, const TQString &room, const TQString &nick, const TQString &password )
{

	client()->groupChatJoin ( host, room, nick, password );

}

void JabberClient::leaveGroupChat ( const TQString &host, const TQString &room )
{

	client()->groupChatLeave ( host, room );

}

void JabberClient::setGroupChatStatus( const TQString & host, const TQString & room, const XMPP::Status & status )
{
	client()->groupChatSetStatus( host, room, status);
}

void JabberClient::changeGroupChatNick( const TQString & host, const TQString & room, const TQString & nick, const XMPP::Status & status )
{
	client()->groupChatChangeNick( host, room, nick, status );
}


void JabberClient::sendMessage ( const XMPP::Message &message )
{

	client()->sendMessage ( message );

}

void JabberClient::send ( const TQString &packet )
{

	client()->send ( packet );

}

void JabberClient::requestRoster ()
{

	client()->rosterRequest ();

}

void JabberClient::slotPsiDebug ( const TQString & _msg )
{
	TQString msg = _msg;

	msg = msg.replace( TQRegExp( "<password>[^<]*</password>\n" ), "<password>[Filtered]</password>\n" );
	msg = msg.replace( TQRegExp( "<digest>[^<]*</digest>\n" ), "<digest>[Filtered]</digest>\n" );

	emit debugMessage ( "Psi: " + msg );

}

void JabberClient::slotIncomingXML ( const TQString & _msg )
{
	TQString msg = _msg;

	msg = msg.replace( TQRegExp( "<password>[^<]*</password>\n" ), "<password>[Filtered]</password>\n" );
	msg = msg.replace( TQRegExp( "<digest>[^<]*</digest>\n" ), "<digest>[Filtered]</digest>\n" );

	emit debugMessage ( "XML IN: " + msg );

}

void JabberClient::slotOutgoingXML ( const TQString & _msg )
{
	TQString msg = _msg;

	msg = msg.replace( TQRegExp( "<password>[^<]*</password>\n" ), "<password>[Filtered]</password>\n" );
	msg = msg.replace( TQRegExp( "<digest>[^<]*</digest>\n" ), "<digest>[Filtered]</digest>\n" );

	emit debugMessage ( "XML OUT: " + msg );

}

void JabberClient::slotTLSHandshaken ()
{

	emit debugMessage ( "TLS handshake done, testing certificate validity..." );

	// FIXME: in the future, this should be handled by KDE, not TQCA
	int validityResult = d->jabberTLS->certificateValidityResult ();

	if ( validityResult == TQCA::TLS::Valid )
	{
		emit debugMessage ( "Certificate is valid, continuing." );

		// valid certificate, continue
		d->jabberTLSHandler->continueAfterHandshake ();
	}
	else
	{
		emit debugMessage ( "Certificate is not valid, asking user what to do next." );

		// certificate is not valid, query the user
		if ( ignoreTLSWarnings () )
		{
			emit debugMessage ( "We are supposed to ignore TLS warnings, continuing." );
			d->jabberTLSHandler->continueAfterHandshake ();
		}

		emit tlsWarning ( validityResult );
	}

}

void JabberClient::continueAfterTLSWarning ()
{

	if ( d->jabberTLSHandler )
	{
		d->jabberTLSHandler->continueAfterHandshake ();
	}

}

void JabberClient::slotCSNeedAuthParams ( bool user, bool pass, bool realm )
{
	emit debugMessage ( "Sending auth credentials..." );

	if ( user )
	{
		d->jabberClientStream->setUsername ( jid().node () );
	}

	if ( pass )
	{
		d->jabberClientStream->setPassword ( d->password );
	}

	if ( realm )
	{
		d->jabberClientStream->setRealm ( jid().domain () );
	}

	d->jabberClientStream->continueAfterParams ();

}

void JabberClient::slotCSAuthenticated ()
{
	emit debugMessage ( "Connected to Jabber server." );

	/*
	 * Determine local IP address.
	 * FIXME: This is ugly!
	 */
	if ( localAddress().isEmpty () )
	{
		// code for Iris-type bytestreams
		ByteStream *irisByteStream = d->jabberClientConnector->stream();
		if ( irisByteStream->inherits ( "BSocket" ) || irisByteStream->inherits ( "XMPP::BSocket" ) )
		{
			d->localAddress = ( (BSocket *)irisByteStream )->address().toString ();
		}

		// code for the KDE-type bytestream
		JabberByteStream *kdeByteStream = dynamic_cast<JabberByteStream*>(d->jabberClientConnector->stream());
		if ( kdeByteStream )
		{
			d->localAddress = kdeByteStream->socket()->localAddress().nodeName ();
		}
	}

	if ( fileTransfersEnabled () )
	{
		// setup file transfer
		addS5BServerAddress ( localAddress () );
		d->jabberClient->s5bManager()->setServer ( s5bServer () );
	}

	// start the client operation
	d->jabberClient->start ( jid().domain (), jid().node (), d->password, jid().resource () );

	emit connected ();
}

void JabberClient::slotCSDisconnected ()
{

	/* FIXME:
	 * We should delete the XMPP::Client instance here,
	 * but timers etc prevent us from doing so. (Psi does
	 * not like to be deleted from a slot).
	 */

	emit debugMessage ( "Disconnected, freeing up file transfer port..." );

	// delete local address from S5B server
	removeS5BServerAddress ( localAddress () );

	emit csDisconnected ();

}

void JabberClient::slotCSWarning ( int warning )
{

	emit debugMessage ( "Client stream warning." );

	/*
	 * FIXME: process all other warnings
	 */
	switch ( warning )
	{
		//case XMPP::ClientStream::WarnOldVersion:
		case XMPP::ClientStream::WarnNoTLS:
			if ( forceTLS () )
			{
				disconnect ();
				emit error ( NoTLS );
				return;
			}
			break;
	}

	d->jabberClientStream->continueAfterWarning ();

}

void JabberClient::slotCSError ( int error )
{

	emit debugMessage ( "Client stream error." );

	emit csError ( error );

}

void JabberClient::slotRosterRequestFinished ( bool success, int /*statusCode*/, const TQString &/*statusString*/ )
{

	emit rosterRequestFinished ( success );

}

void JabberClient::slotIncomingFileTransfer ()
{

	emit incomingFileTransfer ();

}

void JabberClient::slotNewContact ( const XMPP::RosterItem &item )
{

	emit newContact ( item );

}

void JabberClient::slotContactDeleted ( const RosterItem &item )
{

	emit contactDeleted ( item );

}

void JabberClient::slotContactUpdated ( const RosterItem &item )
{

	emit contactUpdated ( item );

}

void JabberClient::slotResourceAvailable ( const Jid &jid, const Resource &resource )
{

	emit resourceAvailable ( jid, resource );

}

void JabberClient::slotResourceUnavailable ( const Jid &jid, const Resource &resource )
{

	emit resourceUnavailable ( jid, resource );

}

void JabberClient::slotReceivedMessage ( const Message &message )
{

	emit messageReceived ( message );

}

void JabberClient::slotGroupChatJoined ( const Jid &jid )
{

	emit groupChatJoined ( jid );

}

void JabberClient::slotGroupChatLeft ( const Jid &jid )
{

	emit groupChatLeft ( jid );

}

void JabberClient::slotGroupChatPresence ( const Jid &jid, const Status &status)
{

	emit groupChatPresence ( jid, status );

}

void JabberClient::slotGroupChatError ( const Jid &jid, int error, const TQString &reason)
{

	emit groupChatError ( jid, error, reason );

}

void JabberClient::slotSubscription ( const Jid &jid, const TQString &type )
{

	emit subscription ( jid, type );

}


#include "jabberclient.moc"
