/* oscarclientstream.cpp - Kopete Oscar Protocol Copyright (c) 2004 Matt Rogers Based on code Copyright (c) 2004 SuSE Linux AG Based on Iris, Copyright (C) 2003 Justin Karneges Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ #include "oscarclientstream.h" #include #include #include #include #include #include "bytestream.h" #include "connection.h" #include "connector.h" #include "coreprotocol.h" #include "rateclassmanager.h" #include "transfer.h" #define LIBOSCAR_DEBUG 0 void cs_dump( const TQByteArray &bytes ); enum { Idle, Connecting, Active, Closing }; enum { ClientMode, ServerMode }; class ClientStream::Private { public: Private() { conn = 0; bs = 0; connection = 0; username = TQString(); password = TQString(); server = TQString(); haveLocalAddr = false; doBinding = true; reset(); } void reset() { state = Idle; notify = 0; newTransfers = false; } TQString username; TQString password; TQString server; bool doAuth; //send the initial login sequences to get the cookie bool haveLocalAddr; TQHostAddress localAddr; TQ_UINT16 localPort; bool doBinding; Connector *conn; ByteStream *bs; CoreProtocol client; Connection* connection; TQString defRealm; int mode; int state; int notify; bool newTransfers; int errCond; TQString errText; TQPtrQueue in; TQTimer noopTimer; // used to send icq keepalive int noop_time; }; ClientStream::ClientStream(Connector *conn, TQObject *parent) :Stream(parent) { //tqDebug("CLIENTSTREAM::ClientStream"); d = new Private; d->mode = ClientMode; d->conn = conn; connect( d->conn, TQ_SIGNAL(connected()), TQ_SLOT(cr_connected()) ); connect( d->conn, TQ_SIGNAL(error()), TQ_SLOT(cr_error()) ); connect( &d->client, TQ_SIGNAL( outgoingData( const TQByteArray& ) ), TQ_SLOT ( cp_outgoingData( const TQByteArray & ) ) ); connect( &d->client, TQ_SIGNAL( incomingData() ), TQ_SLOT ( cp_incomingData() ) ); d->noop_time = 0; connect(&d->noopTimer, TQ_SIGNAL(timeout()), TQ_SLOT(doNoop())); } ClientStream::~ClientStream() { reset(); delete d; } void ClientStream::reset(bool all) { d->reset(); d->noopTimer.stop(); // client if(d->mode == ClientMode) { // reset connector if ( d->bs ) { d->bs->close(); d->bs = 0; } if ( d->conn ) d->conn->done(); // reset state machine d->client.reset(); } if(all) d->in.clear(); } void ClientStream::connectToServer(const TQString& server, bool auth) { reset(true); d->state = Connecting; d->doAuth = auth; d->server = server; d->conn->connectToServer( d->server ); } void ClientStream::continueAfterWarning() { /* unneeded? if(d->state == WaitVersion) { d->state = Connecting; processNext(); } else if(d->state == WaitTLS) { d->state = Connecting; processNext(); } */ } void ClientStream::accept() { } bool ClientStream::isActive() const { return (d->state != Idle); } bool ClientStream::isAuthenticated() const { return (d->state == Active); } void ClientStream::setNoopTime(int mills) { d->noop_time = mills; if(d->noop_time == 0) { d->noopTimer.stop(); return; } if( d->state != Active ) return; d->noopTimer.start( d->noop_time ); } void ClientStream::setLocalAddr(const TQHostAddress &addr, TQ_UINT16 port) { d->haveLocalAddr = true; d->localAddr = addr; d->localPort = port; } int ClientStream::errorCondition() const { return d->errCond; } TQString ClientStream::errorText() const { return d->errText; } void ClientStream::close() { if(d->state == Active) { d->state = Closing; // d->client.shutdown(); processNext(); } else if(d->state != Idle && d->state != Closing) { reset(); } } void ClientStream::setConnection( Connection *c ) { d->connection = c; } Connection* ClientStream::connection() const { return d->connection; } bool ClientStream::transfersAvailable() const { return ( !d->in.isEmpty() ); } Transfer* ClientStream::read() { if(d->in.isEmpty()) return 0; //first from queue... else return d->in.dequeue(); } void ClientStream::write( Transfer *request ) { d->client.outgoingTransfer( request ); } void cs_dump( const TQByteArray &bytes ) { #if 0 tqDebug( "contains: %i bytes ", bytes.count() ); uint count = 0; while ( count < bytes.count() ) { int dword = 0; for ( int i = 0; i < 8; ++i ) { if ( count + i < bytes.count() ) printf( "%02x ", bytes[ count + i ] ); else printf( " " ); if ( i == 3 ) printf( " " ); } printf(" | "); dword = 0; for ( int i = 0; i < 8; ++i ) { if ( count + i < bytes.count() ) { int j = bytes [ count + i ]; if ( j >= 0x20 && j <= 0x7e ) printf( "%2c ", j ); else printf( "%2c ", '.' ); } else printf( " " ); if ( i == 3 ) printf( " " ); } printf( "\n" ); count += 8; } printf( "\n" ); #endif Q_UNUSED( bytes ); } void ClientStream::cp_outgoingData( const TQByteArray& outgoingBytes ) { // take formatted bytes from CoreProtocol and put them on the wire d->bs->write( outgoingBytes ); } void ClientStream::cp_incomingData() { Transfer * incoming = d->client.incomingTransfer(); if ( incoming ) { d->in.enqueue( incoming ); d->newTransfers = true; doReadyRead(); } else kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "client signalled incomingData but none was available, state is: " << d->client.state() << endl; } void ClientStream::cr_connected() { d->bs = d->conn->stream(); connect(d->bs, TQ_SIGNAL(connectionClosed()), TQ_SLOT(bs_connectionClosed())); connect(d->bs, TQ_SIGNAL(delayedCloseFinished()), TQ_SLOT(bs_delayedCloseFinished())); connect(d->bs, TQ_SIGNAL(readyRead()), TQ_SLOT(bs_readyRead())); connect(d->bs, TQ_SIGNAL(bytesWritten(int)), TQ_SLOT(bs_bytesWritten(int))); connect(d->bs, TQ_SIGNAL(error(int)), TQ_SLOT(bs_error(int))); d->state = Active; if ( d->noop_time ) d->noopTimer.start( d->noop_time ); TQByteArray spare = d->bs->read(); TQGuardedPtr self = this; emit connected(); if(!self) return; } void ClientStream::cr_error() { kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << endl; reset(); emit error(ErrConnection); } void ClientStream::bs_connectionClosed() { reset(); emit connectionClosed(); } void ClientStream::bs_delayedCloseFinished() { // we don't care about this (we track all important data ourself) } void ClientStream::bs_error(int) { // TODO } void ClientStream::bs_readyRead() { TQByteArray a; //tqDebug( "size of storage for incoming data is %i bytes.", a.size() ); a = d->bs->read(); #if LIBOSCAR_DEBUG TQCString cs(a.data(), a.size()+1); kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "recv: " << a.size() << "bytes" << endl; cs_dump( a ); #endif d->client.addIncomingData(a); } void ClientStream::bs_bytesWritten(int bytes) { #if LIBOSCAR_DEBUG kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << bytes << " bytes written" << endl; Q_UNUSED( bytes ); #else Q_UNUSED( bytes ); #endif } void ClientStream::srvProcessNext() { } void ClientStream::doReadyRead() { emit readyRead(); } void ClientStream::processNext() { if( !d->in.isEmpty() ) { TQTimer::singleShot(0, this, TQ_SLOT(doReadyRead())); } } bool ClientStream::handleNeed() { return false; } void ClientStream::doNoop() { if ( d->state != Active ) return; FLAP f = { 0x05, d->connection->flapSequence(), 0 }; Buffer* b = new Buffer(); //deleted in Transfer destructor Transfer* t = new FlapTransfer( f, b ); //deleted after being sent write( t ); } void ClientStream::handleError() { } #include "oscarclientstream.moc"