/* oscarclientstream.cpp - Kopete Oscar Protocol Copyright (c) 2004 Matt Rogers <matt.rogers@kdemail.net> Based on code Copyright (c) 2004 SuSE Linux AG <http://www.suse.com> Based on Iris, Copyright (C) 2003 Justin Karneges <justin@affinix.com> Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org> ************************************************************************* * * * 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 <tqapplication.h> // for qdebug #include <tqguardedptr.h> #include <tqobject.h> #include <tqptrqueue.h> #include <tqtimer.h> #include <kdebug.h> #include "bytestream.h" #include "connector.h" #include "coreprotocol.h" #include "transfer.h" #include "yahooclientstream.h" #include "yahootypes.h" void cs_dump( const TQByteArray &bytes ); enum { Idle, Connecting, Active, Closing }; enum { Client, Server }; class ClientStream::Private { public: Private() { conn = 0; bs = 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; TQString defRealm; int mode; int state; int notify; bool newTransfers; int errCond; TQString errText; TQPtrQueue<Transfer> in; TQTimer noopTimer; // used to send icq keepalive int noop_time; }; ClientStream::ClientStream(Connector *conn, TQObject *tqparent) :Stream(tqparent), d(new Private()) { kdDebug(YAHOO_RAW_DEBUG) ; d->mode = Client; d->conn = conn; connect( d->conn, TQT_SIGNAL(connected()), TQT_SLOT(cr_connected()) ); connect( d->conn, TQT_SIGNAL(error()), TQT_SLOT(cr_error()) ); connect( &d->client, TQT_SIGNAL( outgoingData( const TQByteArray& ) ), TQT_SLOT ( cp_outgoingData( const TQByteArray & ) ) ); connect( &d->client, TQT_SIGNAL( incomingData() ), TQT_SLOT ( cp_incomingData() ) ); d->noop_time = 0; connect(&d->noopTimer, TQT_SIGNAL(timeout()), TQT_SLOT(doNoop())); } ClientStream::~ClientStream() { reset(); delete d; } void ClientStream::reset(bool all) { kdDebug(YAHOO_RAW_DEBUG) ; d->reset(); d->noopTimer.stop(); // client if(d->mode == Client) { // reset connector if(d->bs) { disconnect(d->bs, 0, this, 0); d->bs->close(); d->bs = 0; } d->conn->done(); // reset state machine d->client.reset(); } if(all) d->in.clear(); } void ClientStream::connectToServer(const TQString& server, bool auth) { kdDebug(YAHOO_RAW_DEBUG) ; reset(true); d->state = Connecting; d->doAuth = auth; d->server = server; d->conn->connectToServer( d->server ); } void ClientStream::continueAfterWarning() { kdDebug(YAHOO_RAW_DEBUG) ; /* 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->state != Active) return; if(d->noop_time == 0) { d->noopTimer.stop(); 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(); } } bool ClientStream::transfersAvailable() const { kdDebug(YAHOO_RAW_DEBUG) ; 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 ) { kdDebug(YAHOO_RAW_DEBUG) ; // pass to CoreProtocol for transformation into wire format d->client.outgoingTransfer( request ); } void cs_dump( const TQByteArray &bytes ) { #if 0 qDebug( "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 ) { if ( !d->bs ) return; // take formatted bytes from CoreProtocol and put them on the wire kdDebug(YAHOO_RAW_DEBUG) << "[data size: " << outgoingBytes.size() << "]" << endl; //cs_dump( outgoingBytes ); d->bs->write( outgoingBytes ); } void ClientStream::cp_incomingData() { // kdDebug(YAHOO_RAW_DEBUG) ; Transfer * incoming = d->client.incomingTransfer(); if ( incoming ) { // kdDebug(YAHOO_RAW_DEBUG) << " - got a new transfer"; d->in.enqueue( incoming ); d->newTransfers = true; emit doReadyRead(); } else kdDebug(YAHOO_RAW_DEBUG) << " - client signalled incomingData but none was available, state is: "<< d->client.state() << endl; } /* Connector connected */ void ClientStream::cr_connected() { kdDebug(YAHOO_RAW_DEBUG) ; d->bs = d->conn->stream(); connect(d->bs, TQT_SIGNAL(connectionClosed()), TQT_SLOT(bs_connectionClosed())); connect(d->bs, TQT_SIGNAL(delayedCloseFinished()), TQT_SLOT(bs_delayedCloseFinished())); connect(d->bs, TQT_SIGNAL(readyRead()), TQT_SLOT(bs_readyRead())); connect(d->bs, TQT_SIGNAL(bytesWritten(int)), TQT_SLOT(bs_bytesWritten(int))); connect(d->bs, TQT_SIGNAL(error(int)), TQT_SLOT(bs_error(int))); TQByteArray spare = d->bs->read(); TQGuardedPtr<TQObject> self = this; emit connected(); if(!self) return; } void ClientStream::cr_error() { kdDebug(YAHOO_RAW_DEBUG) ; 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) { kdDebug(YAHOO_RAW_DEBUG) ; // TODO } void ClientStream::bs_readyRead() { // kdDebug(YAHOO_RAW_DEBUG) ; TQByteArray a; //qDebug( "size of storage for incoming data is %i bytes.", a.size() ); a = d->bs->read(); //TQCString cs(a.data(), a.size()+1); //qDebug("ClientStream: recv: %d [%s]\n", a.size(), cs.data()); //kdDebug(YAHOO_RAW_DEBUG) << " recv: " << a.size() <<" bytes"; //cs_dump( a ); d->client.addIncomingData(a); } void ClientStream::bs_bytesWritten(int bytes) { kdDebug(YAHOO_RAW_DEBUG) << " written: " << bytes <<" bytes" << endl; } void ClientStream::srvProcessNext() { } void ClientStream::doReadyRead() { // kdDebug(YAHOO_RAW_DEBUG) ; emit readyRead(); } void ClientStream::processNext() { if( !d->in.isEmpty() ) { TQTimer::singleShot(0, this, TQT_SLOT(doReadyRead())); } } bool ClientStream::handleNeed() { return false; } void ClientStream::doNoop() { } void ClientStream::handleError() { } #include "yahooclientstream.moc"