Port things from MSN to WLM plugin:
[kdenetwork.git] / kopete / protocols / groupwise / libgroupwise / gwclientstream.cpp
blob678015fa536a2b3eccb33400a890e5aabf2ea4af
1 /*
2 gwclientstream.cpp - Kopete Groupwise Protocol
4 Copyright (c) 2006 Novell, Inc http://www.opensuse.org
5 Copyright (c) 2004 SUSE Linux AG http://www.suse.com
7 Based on Iris, Copyright (C) 2003 Justin Karneges <justin@affinix.com>
8 encode_method from Gaim src/protocols/novell/nmconn.c
9 Copyright (c) 2004 Novell, Inc. All Rights Reserved
11 Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
13 *************************************************************************
14 * *
15 * This library is free software; you can redistribute it and/or *
16 * modify it under the terms of the GNU Lesser General Public *
17 * License as published by the Free Software Foundation; either *
18 * version 2 of the License, or (at your option) any later version. *
19 * *
20 *************************************************************************
23 //#include<qtextstream.h>
24 //#include<qguardedptr.h>
25 // #include<qca.h>
26 // #include<stdlib.h>
27 // #include"bytestream.h"
28 // #include"base64.h"
29 // #include"hash.h"
30 // #include"simplesasl.h"
31 // #include"securestream.h"
32 // #include"protocol.h"
34 #include <qapplication.h> // for qdebug
35 #include <qpointer.h>
36 #include <qobject.h>
37 #include <QQueue>
38 #include <qtimer.h>
39 //Added by qt3to4:
40 #include <QByteArray>
42 #include "bytestream.h"
43 #include "connector.h"
44 #include "coreprotocol.h"
45 #include "request.h"
46 #include "securestream.h"
47 #include "tlshandler.h"
49 //#include "iostream.h"
51 #include "gwclientstream.h"
53 //#define LIBGW_DEBUG 1
55 void cs_dump( const QByteArray &bytes );
57 enum {
58 Idle,
59 Connecting,
60 WaitVersion,
61 WaitTLS,
62 NeedParams,
63 Active,
64 Closing
67 enum {
68 Client,
69 Server
72 class ClientStream::Private
74 public:
75 Private()
77 conn = 0;
78 bs = 0;
79 ss = 0;
80 tlsHandler = 0;
81 tls = 0;
82 // sasl = 0;
84 allowPlain = false;
85 mutualAuth = false;
86 haveLocalAddr = false;
87 /* minimumSSF = 0;
88 maximumSSF = 0;*/
89 doBinding = true;
91 in_rrsig = false;
93 reset();
95 void reset()
97 state = Idle;
98 notify = 0;
99 newTransfers = false;
100 // sasl_ssf = 0;
101 tls_warned = false;
102 using_tls = false;
105 NovellDN id;
106 QString server;
107 bool oldOnly;
108 bool allowPlain, mutualAuth;
109 bool haveLocalAddr;
110 QHostAddress localAddr;
111 quint16 localPort;
112 // int minimumSSF, maximumSSF;
113 // QString sasl_mech;
114 bool doBinding;
116 bool in_rrsig;
118 Connector *conn;
119 ByteStream *bs;
120 TLSHandler *tlsHandler;
121 QCA::TLS *tls;
122 // QCA::SASL *sasl;
123 SecureStream *ss;
124 CoreProtocol client;
125 //CoreProtocol srv;
127 QString defRealm;
129 int mode;
130 int state;
131 int notify;
132 bool newTransfers;
133 // int sasl_ssf;
134 bool tls_warned, using_tls;
135 bool doAuth;
137 // QStringList sasl_mechlist;
139 int errCond;
140 QString errText;
142 QQueue<Transfer *> in;
144 QTimer noopTimer; // probably not needed
145 int noop_time;
148 ClientStream::ClientStream(Connector *conn, TLSHandler *tlsHandler, QObject *parent)
149 :Stream(parent), d(new Private())
151 d->mode = Client;
152 d->conn = conn;
153 connect( d->conn, SIGNAL(connected()), SLOT(cr_connected()) );
154 connect( d->conn, SIGNAL(error()), SLOT(cr_error()) );
155 connect( &d->client, SIGNAL( outgoingData( const QByteArray& ) ), SLOT ( cp_outgoingData( const QByteArray & ) ) );
156 connect( &d->client, SIGNAL( incomingData() ), SLOT ( cp_incomingData() ) );
158 d->noop_time = 0;
159 connect(&d->noopTimer, SIGNAL(timeout()), SLOT(doNoop()));
161 d->tlsHandler = tlsHandler; // all the extra stuff happening in the larger ctor happens at connect time :)
164 ClientStream::~ClientStream()
166 reset( true );
167 delete d;
170 void ClientStream::reset(bool all)
172 d->reset();
173 d->noopTimer.stop();
175 // delete securestream
176 delete d->ss;
177 d->ss = 0;
179 // reset sasl
180 // delete d->sasl;
181 // d->sasl = 0;
183 // client
184 if(d->mode == Client) {
185 // reset tls
186 if(d->tlsHandler)
187 d->tlsHandler->reset();
189 // reset connector
190 if(d->bs) {
191 d->bs->close();
192 d->bs = 0;
194 d->conn->done();
196 // reset state machine
197 d->client.reset();
199 if(all)
200 while (!d->in.isEmpty())
201 delete d->in.dequeue();
204 // Jid ClientStream::jid() const
205 // {
206 // return d->jid;
207 // }
209 void ClientStream::connectToServer(const NovellDN &id, bool auth)
211 reset(true);
212 d->state = Connecting;
213 d->id = id;
214 d->doAuth = auth;
215 d->server = d->id.server;
217 d->conn->connectToServer( d->server );
220 void ClientStream::continueAfterWarning()
222 if(d->state == WaitVersion) {
223 // if we don't have TLS yet, then we're never going to get it
224 if(!d->tls_warned && !d->using_tls) {
225 d->tls_warned = true;
226 d->state = WaitTLS;
227 emit warning(WarnNoTLS);
228 return;
230 d->state = Connecting;
231 processNext();
233 else if(d->state == WaitTLS) {
234 d->state = Connecting;
235 processNext();
239 void ClientStream::accept()
241 /* d->srv.host = d->server;
242 processNext();*/
245 bool ClientStream::isActive() const
247 return (d->state != Idle);
250 bool ClientStream::isAuthenticated() const
252 return (d->state == Active);
255 // void ClientStream::setPassword(const QString &s)
256 // {
257 // if(d->client.old) {
258 // d->client.setPassword(s);
259 // }
260 // else {
261 // if(d->sasl)
262 // d->sasl->setPassword(s);
263 // }
264 // }
266 // void ClientStream::setRealm(const QString &s)
267 // {
268 // if(d->sasl)
269 // d->sasl->setRealm(s);
270 // }
272 void ClientStream::continueAfterParams()
274 /* if(d->state == NeedParams) {
275 d->state = Connecting;
276 if(d->client.old) {
277 processNext();
279 else {
280 if(d->sasl)
281 d->sasl->continueAfterParams();
286 void ClientStream::setNoopTime(int mills)
288 d->noop_time = mills;
290 if(d->state != Active)
291 return;
293 if(d->noop_time == 0) {
294 d->noopTimer.stop();
295 return;
297 d->noopTimer.start(d->noop_time);
300 void ClientStream::setLocalAddr(const QHostAddress &addr, quint16 port)
302 d->haveLocalAddr = true;
303 d->localAddr = addr;
304 d->localPort = port;
307 int ClientStream::errorCondition() const
309 return d->errCond;
312 QString ClientStream::errorText() const
314 return d->errText;
317 // QDomElement ClientStream::errorAppSpec() const
318 // {
319 // return d->errAppSpec;cr_error
320 // }
322 // bool ClientStream::old() const
323 // {
324 // return d->client.old;
325 // }
327 void ClientStream::close()
329 if(d->state == Active) {
330 d->state = Closing;
331 // d->client.shutdown();
332 processNext();
334 else if(d->state != Idle && d->state != Closing) {
335 reset();
339 void ClientStream::setAllowPlain(bool b)
341 d->allowPlain = b;
344 void ClientStream::setRequireMutualAuth(bool b)
346 d->mutualAuth = b;
349 // void ClientStream::setSSFRange(int low, int high)
350 // {
351 // d->minimumSSF = low;
352 // d->maximumSSF = high;
353 // }
355 // void ClientStream::setOldOnly(bool b)
356 // {
357 // d->oldOnly = b;
358 // }
360 bool ClientStream::transfersAvailable() const
362 return ( !d->in.isEmpty() );
365 Transfer * ClientStream::read()
367 if(d->in.isEmpty())
368 return 0; //first from queue...
369 else
370 return d->in.dequeue();
373 void ClientStream::write( Request *request )
375 // pass to CoreProtocol for transformation into wire format
376 d->client.outgoingTransfer( request );
379 void cs_dump( const QByteArray &bytes )
381 //#define GW_CLIENTSTREAM_DEBUG 1
382 #ifdef GW_CLIENTSTREAM_DEBUG
383 CoreProtocol::debug( QString( "contains: %1 bytes " ).arg( bytes.count() ) );
384 uint count = 0;
385 while ( count < bytes.count() )
387 int dword = 0;
388 for ( int i = 0; i < 8; ++i )
390 if ( count + i < bytes.count() )
391 printf( "%02x ", bytes[ count + i ] );
392 else
393 printf( " " );
394 if ( i == 3 )
395 printf( " " );
397 printf(" | ");
398 dword = 0;
399 for ( int i = 0; i < 8; ++i )
401 if ( count + i < bytes.count() )
403 int j = bytes [ count + i ];
404 if ( j >= 0x20 && j <= 0x7e )
405 printf( "%2c ", j );
406 else
407 printf( "%2c ", '.' );
409 else
410 printf( " " );
411 if ( i == 3 )
412 printf( " " );
414 printf( "\n" );
415 count += 8;
417 printf( "\n" );
418 #else
419 Q_UNUSED( bytes );
420 #endif
423 void ClientStream::cp_outgoingData( const QByteArray& outgoingBytes )
425 // take formatted bytes from CoreProtocol and put them on the wire
426 #ifdef LIBGW_DEBUG
427 CoreProtocol::debug( "ClientStream::cp_outgoingData:" );
428 cs_dump( outgoingBytes );
429 #endif
430 d->ss->write( outgoingBytes );
433 void ClientStream::cp_incomingData()
435 CoreProtocol::debug( "ClientStream::cp_incomingData:" );
436 Transfer * incoming = d->client.incomingTransfer();
437 if ( incoming )
439 CoreProtocol::debug( " - got a new transfer" );
440 d->in.enqueue( incoming );
441 d->newTransfers = true;
442 emit doReadyRead();
444 else
445 CoreProtocol::debug( QString( " - client signalled incomingData but none was available, state is: %1" ).arg( d->client.state() ) );
448 void ClientStream::cr_connected()
450 d->bs = d->conn->stream();
451 connect(d->bs, SIGNAL(connectionClosed()), SLOT(bs_connectionClosed()));
452 connect(d->bs, SIGNAL(delayedCloseFinished()), SLOT(bs_delayedCloseFinished()));
454 QByteArray spare = d->bs->read();
456 d->ss = new SecureStream(d->bs);
457 connect(d->ss, SIGNAL(readyRead()), SLOT(ss_readyRead()));
458 connect(d->ss, SIGNAL(bytesWritten(int)), SLOT(ss_bytesWritten(int)));
459 connect(d->ss, SIGNAL(tlsHandshaken()), SLOT(ss_tlsHandshaken()));
460 connect(d->ss, SIGNAL(tlsClosed()), SLOT(ss_tlsClosed()));
461 connect(d->ss, SIGNAL(error(int)), SLOT(ss_error(int)));
463 //d->client.startDialbackOut("andbit.net", "im.pyxa.org");
464 //d->client.startServerOut(d->server);
466 // d->client.startClientOut(d->jid, d->oldOnly, d->conn->useSSL(), d->doAuth);
467 // d->client.setAllowTLS(d->tlsHandler ? true: false);
468 // d->client.setAllowBind(d->doBinding);
469 // d->client.setAllowPlain(d->allowPlain);
471 /*d->client.jid = d->jid;
472 d->client.server = d->server;
473 d->client.allowPlain = d->allowPlain;
474 d->client.oldOnly = d->oldOnly;
475 d->client.sasl_mech = d->sasl_mech;
476 d->client.doTLS = d->tlsHandler ? true: false;
477 d->client.doBinding = d->doBinding;*/
479 QPointer<QObject> self = this;
480 emit connected();
481 if(!self)
482 return;
484 // immediate SSL?
485 if(d->conn->useSSL()) {
486 CoreProtocol::debug( "CLIENTSTREAM: cr_connected(), starting TLS" );
487 d->using_tls = true;
488 d->ss->startTLSClient(d->tlsHandler, d->server, spare);
490 else {
491 /* d->client.addIncomingData(spare);
492 processNext();*/
496 void ClientStream::cr_error()
498 reset();
499 emit error(ErrConnection);
502 void ClientStream::bs_connectionClosed()
504 reset();
505 emit connectionClosed();
508 void ClientStream::bs_delayedCloseFinished()
510 // we don't care about this (we track all important data ourself)
513 void ClientStream::bs_error(int)
515 // TODO
518 void ClientStream::ss_readyRead()
520 QByteArray a;
521 a = d->ss->read();
523 #ifdef LIBGW_DEBUG
524 QByteArray cs(a.data(), a.size()+1);
525 CoreProtocol::debug( QString( "ClientStream: ss_readyRead() recv: %1 bytes" ).arg( a.size() ) );
526 cs_dump( a );
527 #endif
529 d->client.addIncomingData(a);
530 /* if(d->notify & CoreProtocol::NRecv) { */
531 //processNext();
534 void ClientStream::ss_bytesWritten(int bytes)
536 #ifdef LIBGW_DEBUG
537 CoreProtocol::debug( QString( "ClientStream::ss_bytesWritten: %1 bytes written" ).arg( bytes ) );
538 #else
539 Q_UNUSED( bytes );
540 #endif
543 void ClientStream::ss_tlsHandshaken()
545 QPointer<QObject> self = this;
546 emit securityLayerActivated(LayerTLS);
547 if(!self)
548 return;
549 processNext();
552 void ClientStream::ss_tlsClosed()
554 CoreProtocol::debug( "ClientStream::ss_tlsClosed()" );
555 reset();
556 emit connectionClosed();
559 void ClientStream::ss_error(int x)
561 CoreProtocol::debug( QString( "ClientStream::ss_error() x=%1 ").arg( x ) );
562 if(x == SecureStream::ErrTLS) {
563 reset();
564 d->errCond = TLSFail;
565 emit error(ErrTLS);
567 else {
568 reset();
569 emit error(ErrSecurityLayer);
573 void ClientStream::srvProcessNext()
577 void ClientStream::doReadyRead()
579 //QPointer<QObject> self = this;
580 emit readyRead();
581 //if(!self)
582 // return;
583 //d->in_rrsig = false;
586 void ClientStream::processNext()
588 if( !d->in.isEmpty() ) {
589 //d->in_rrsig = true;
590 QTimer::singleShot(0, this, SLOT(doReadyRead()));
594 bool ClientStream::handleNeed()
596 return false;
600 void ClientStream::doNoop()
604 void ClientStream::handleError()
608 #include "gwclientstream.moc"