diff options
Diffstat (limited to 'kopete/protocols/groupwise/libgroupwise/gwclientstream.cpp')
-rw-r--r-- | kopete/protocols/groupwise/libgroupwise/gwclientstream.cpp | 606 |
1 files changed, 606 insertions, 0 deletions
diff --git a/kopete/protocols/groupwise/libgroupwise/gwclientstream.cpp b/kopete/protocols/groupwise/libgroupwise/gwclientstream.cpp new file mode 100644 index 00000000..7d58de93 --- /dev/null +++ b/kopete/protocols/groupwise/libgroupwise/gwclientstream.cpp @@ -0,0 +1,606 @@ +/* + gwclientstream.cpp - Kopete Groupwise Protocol + + Copyright (c) 2004 SUSE Linux AG http://www.suse.com + + Based on Iris, Copyright (C) 2003 Justin Karneges + encode_method from Gaim src/protocols/novell/nmconn.c + Copyright (c) 2004 Novell, Inc. All Rights Reserved + + 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<qtextstream.h> +//#include<qguardedptr.h> +// #include<qca.h> +// #include<stdlib.h> +// #include"bytestream.h" +// #include"base64.h" +// #include"hash.h" +// #include"simplesasl.h" +// #include"securestream.h" +// #include"protocol.h" + +#include <qapplication.h> // for qdebug +#include <qguardedptr.h> +#include <qobject.h> +#include <qptrqueue.h> +#include <qtimer.h> + +#include "bytestream.h" +#include "connector.h" +#include "coreprotocol.h" +#include "request.h" +#include "securestream.h" +#include "tlshandler.h" + +//#include "iostream.h" + +#include "gwclientstream.h" + +//#define LIBGW_DEBUG 1 + +void cs_dump( const QByteArray &bytes ); + +enum { + Idle, + Connecting, + WaitVersion, + WaitTLS, + NeedParams, + Active, + Closing +}; + +enum { + Client, + Server +}; + +class ClientStream::Private +{ +public: + Private() + { + conn = 0; + bs = 0; + ss = 0; + tlsHandler = 0; + tls = 0; +// sasl = 0; + in.setAutoDelete(true); + + allowPlain = false; + mutualAuth = false; + haveLocalAddr = false; +/* minimumSSF = 0; + maximumSSF = 0;*/ + doBinding = true; + + in_rrsig = false; + + reset(); + } + void reset() + { + state = Idle; + notify = 0; + newTransfers = false; +// sasl_ssf = 0; + tls_warned = false; + using_tls = false; + } + + NovellDN id; + QString server; + bool oldOnly; + bool allowPlain, mutualAuth; + bool haveLocalAddr; + QHostAddress localAddr; + Q_UINT16 localPort; +// int minimumSSF, maximumSSF; +// QString sasl_mech; + bool doBinding; + + bool in_rrsig; + + Connector *conn; + ByteStream *bs; + TLSHandler *tlsHandler; + QCA::TLS *tls; +// QCA::SASL *sasl; + SecureStream *ss; + CoreProtocol client; + //CoreProtocol srv; + + QString defRealm; + + int mode; + int state; + int notify; + bool newTransfers; +// int sasl_ssf; + bool tls_warned, using_tls; + bool doAuth; + +// QStringList sasl_mechlist; + + int errCond; + QString errText; + + QPtrQueue<Transfer> in; + + QTimer noopTimer; // probably not needed + int noop_time; +}; + +ClientStream::ClientStream(Connector *conn, TLSHandler *tlsHandler, QObject *parent) +:Stream(parent) +{ + d = new Private; + d->mode = Client; + d->conn = conn; + connect( d->conn, SIGNAL(connected()), SLOT(cr_connected()) ); + connect( d->conn, SIGNAL(error()), SLOT(cr_error()) ); + connect( &d->client, SIGNAL( outgoingData( const QByteArray& ) ), SLOT ( cp_outgoingData( const QByteArray & ) ) ); + connect( &d->client, SIGNAL( incomingData() ), SLOT ( cp_incomingData() ) ); + + d->noop_time = 0; + connect(&d->noopTimer, SIGNAL(timeout()), SLOT(doNoop())); + + d->tlsHandler = tlsHandler; // all the extra stuff happening in the larger ctor happens at connect time :) +} + +ClientStream::~ClientStream() +{ + reset(); + delete d; +} + +void ClientStream::reset(bool all) +{ + d->reset(); + d->noopTimer.stop(); + + // delete securestream + delete d->ss; + d->ss = 0; + + // reset sasl +// delete d->sasl; +// d->sasl = 0; + + // client + if(d->mode == Client) { + // reset tls + if(d->tlsHandler) + d->tlsHandler->reset(); + + // reset connector + if(d->bs) { + d->bs->close(); + d->bs = 0; + } + d->conn->done(); + + // reset state machine + d->client.reset(); + } + if(all) + d->in.clear(); +} + +// Jid ClientStream::jid() const +// { +// return d->jid; +// } + +void ClientStream::connectToServer(const NovellDN &id, bool auth) +{ + reset(true); + d->state = Connecting; + d->id = id; + d->doAuth = auth; + d->server = d->id.server; + + d->conn->connectToServer( d->server ); +} + +void ClientStream::continueAfterWarning() +{ + if(d->state == WaitVersion) { + // if we don't have TLS yet, then we're never going to get it + if(!d->tls_warned && !d->using_tls) { + d->tls_warned = true; + d->state = WaitTLS; + emit warning(WarnNoTLS); + return; + } + d->state = Connecting; + processNext(); + } + else if(d->state == WaitTLS) { + d->state = Connecting; + processNext(); + } +} + +void ClientStream::accept() +{ +/* d->srv.host = d->server; + processNext();*/ +} + +bool ClientStream::isActive() const +{ + return (d->state != Idle); +} + +bool ClientStream::isAuthenticated() const +{ + return (d->state == Active); +} + +// void ClientStream::setPassword(const QString &s) +// { +// if(d->client.old) { +// d->client.setPassword(s); +// } +// else { +// if(d->sasl) +// d->sasl->setPassword(s); +// } +// } + +// void ClientStream::setRealm(const QString &s) +// { +// if(d->sasl) +// d->sasl->setRealm(s); +// } + +void ClientStream::continueAfterParams() +{ +/* if(d->state == NeedParams) { + d->state = Connecting; + if(d->client.old) { + processNext(); + } + else { + if(d->sasl) + d->sasl->continueAfterParams(); + } + }*/ +} + +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 QHostAddress &addr, Q_UINT16 port) +{ + d->haveLocalAddr = true; + d->localAddr = addr; + d->localPort = port; +} + +int ClientStream::errorCondition() const +{ + return d->errCond; +} + +QString ClientStream::errorText() const +{ + return d->errText; +} + +// QDomElement ClientStream::errorAppSpec() const +// { +// return d->errAppSpec;cr_error +// } + +// bool ClientStream::old() const +// { +// return d->client.old; +// } + +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::setAllowPlain(bool b) +{ + d->allowPlain = b; +} + +void ClientStream::setRequireMutualAuth(bool b) +{ + d->mutualAuth = b; +} + +// void ClientStream::setSSFRange(int low, int high) +// { +// d->minimumSSF = low; +// d->maximumSSF = high; +// } + +// void ClientStream::setOldOnly(bool b) +// { +// d->oldOnly = b; +// } + +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( Request *request ) +{ + // pass to CoreProtocol for transformation into wire format + d->client.outgoingTransfer( request ); +} + +void cs_dump( const QByteArray &bytes ) +{ +//#define GW_CLIENTSTREAM_DEBUG 1 +#ifdef GW_CLIENTSTREAM_DEBUG + CoreProtocol::debug( QString( "contains: %1 bytes " ).arg( 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" ); +#else + Q_UNUSED( bytes ); +#endif +} + +void ClientStream::cp_outgoingData( const QByteArray& outgoingBytes ) +{ + // take formatted bytes from CoreProtocol and put them on the wire +#ifdef LIBGW_DEBUG + CoreProtocol::debug( "ClientStream::cp_outgoingData:" ); + cs_dump( outgoingBytes ); +#endif + d->ss->write( outgoingBytes ); +} + +void ClientStream::cp_incomingData() +{ + CoreProtocol::debug( "ClientStream::cp_incomingData:" ); + Transfer * incoming = d->client.incomingTransfer(); + if ( incoming ) + { + CoreProtocol::debug( " - got a new transfer" ); + d->in.enqueue( incoming ); + d->newTransfers = true; + emit doReadyRead(); + } + else + CoreProtocol::debug( QString( " - client signalled incomingData but none was available, state is: %1" ).arg( d->client.state() ) ); +} + +void ClientStream::cr_connected() +{ + d->bs = d->conn->stream(); + connect(d->bs, SIGNAL(connectionClosed()), SLOT(bs_connectionClosed())); + connect(d->bs, SIGNAL(delayedCloseFinished()), SLOT(bs_delayedCloseFinished())); + + QByteArray spare = d->bs->read(); + + d->ss = new SecureStream(d->bs); + connect(d->ss, SIGNAL(readyRead()), SLOT(ss_readyRead())); + connect(d->ss, SIGNAL(bytesWritten(int)), SLOT(ss_bytesWritten(int))); + connect(d->ss, SIGNAL(tlsHandshaken()), SLOT(ss_tlsHandshaken())); + connect(d->ss, SIGNAL(tlsClosed()), SLOT(ss_tlsClosed())); + connect(d->ss, SIGNAL(error(int)), SLOT(ss_error(int))); + + //d->client.startDialbackOut("andbit.net", "im.pyxa.org"); + //d->client.startServerOut(d->server); + +// d->client.startClientOut(d->jid, d->oldOnly, d->conn->useSSL(), d->doAuth); +// d->client.setAllowTLS(d->tlsHandler ? true: false); +// d->client.setAllowBind(d->doBinding); +// d->client.setAllowPlain(d->allowPlain); + + /*d->client.jid = d->jid; + d->client.server = d->server; + d->client.allowPlain = d->allowPlain; + d->client.oldOnly = d->oldOnly; + d->client.sasl_mech = d->sasl_mech; + d->client.doTLS = d->tlsHandler ? true: false; + d->client.doBinding = d->doBinding;*/ + + QGuardedPtr<QObject> self = this; + emit connected(); + if(!self) + return; + + // immediate SSL? + if(d->conn->useSSL()) { + CoreProtocol::debug( "CLIENTSTREAM: cr_connected(), starting TLS" ); + d->using_tls = true; + d->ss->startTLSClient(d->tlsHandler, d->server, spare); + } + else { +/* d->client.addIncomingData(spare); + processNext();*/ + } +} + +void ClientStream::cr_error() +{ + 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::ss_readyRead() +{ + QByteArray a; + a = d->ss->read(); + +#ifdef LIBGW_DEBUG + QCString cs(a.data(), a.size()+1); + CoreProtocol::debug( QString( "ClientStream: ss_readyRead() recv: %1 bytes" ).arg( a.size() ) ); + cs_dump( a ); +#endif + + d->client.addIncomingData(a); +/* if(d->notify & CoreProtocol::NRecv) { */ + //processNext(); +} + +void ClientStream::ss_bytesWritten(int bytes) +{ +#ifdef LIBGW_DEBUG + CoreProtocol::debug( QString( "ClientStream::ss_bytesWritten: %1 bytes written" ).arg( bytes ) ); +#else + Q_UNUSED( bytes ); +#endif +} + +void ClientStream::ss_tlsHandshaken() +{ + QGuardedPtr<QObject> self = this; + emit securityLayerActivated(LayerTLS); + if(!self) + return; + processNext(); +} + +void ClientStream::ss_tlsClosed() +{ + CoreProtocol::debug( "ClientStream::ss_tlsClosed()" ); + reset(); + emit connectionClosed(); +} + +void ClientStream::ss_error(int x) +{ + CoreProtocol::debug( QString( "ClientStream::ss_error() x=%1 ").arg( x ) ); + if(x == SecureStream::ErrTLS) { + reset(); + d->errCond = TLSFail; + emit error(ErrTLS); + } + else { + reset(); + emit error(ErrSecurityLayer); + } +} + +void ClientStream::srvProcessNext() +{ +} + +void ClientStream::doReadyRead() +{ + //QGuardedPtr<QObject> self = this; + emit readyRead(); + //if(!self) + // return; + //d->in_rrsig = false; +} + +void ClientStream::processNext() +{ + if( !d->in.isEmpty() ) { + //d->in_rrsig = true; + QTimer::singleShot(0, this, SLOT(doReadyRead())); + } +} + +bool ClientStream::handleNeed() +{ + return false; +} + + +void ClientStream::doNoop() +{ +} + +void ClientStream::handleError() +{ +} + +#include "gwclientstream.moc" |