1 /*
2 Kopete Oscar Protocol
3 connection.cpp - independent protocol encapsulation
4
5 Copyright (c) 2004-2005 by Matt Rogers <mattr@kde.org>
6
7 Based on code Copyright (c) 2004 SuSE Linux AG <http://www.suse.com>
8 Based on Iris, Copyright (C) 2003 Justin Karneges <justin@affinix.com>
9
10 Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
11
12 *************************************************************************
13 * *
14 * This library is free software; you can redistribute it and/or *
15 * modify it under the terms of the GNU Lesser General Public *
16 * License as published by the Free Software Foundation; either *
17 * version 2 of the License, or (at your option) any later version. *
18 * *
19 *************************************************************************
20 */
21
22 #include "connection.h"
23 #include "client.h"
24 #include "oscarclientstream.h"
25 #include "rateclassmanager.h"
26 #include "task.h"
27 #include "transfer.h"
28 #include <kdebug.h>
29
30 #include "oscartypeclasses.h"
31 #include <QList>
32 #include <krandom.h>
33
34 class ConnectionPrivate
35 {
36 public:
37 // The Oscar::WORD isn't typo see snacSequence function
38 Oscar::WORD snacSequence;
39 Oscar::WORD flapSequence;
40
41 QList<int> familyList;
42 RateClassManager* rateClassManager;
43
44 ClientStream* clientStream;
45 Client* client;
46
47 Task* root;
48 QHash<Oscar::DWORD, Oscar::MessageInfo> snacSequenceToMessageInfo;
49 };
50
51 QList<Oscar::WORD> Connection::m_startFlapSequenceList;
52
Connection(ClientStream * cs,const char * name)53 Connection::Connection( ClientStream* cs, const char* name )
54 : QObject( 0 )
55 {
56 setObjectName( QLatin1String(name) );
57 d = new ConnectionPrivate();
58 d->clientStream = cs;
59 d->client = 0;
60 d->rateClassManager = new RateClassManager( this );
61 d->root = new Task( this, true /* isRoot */ );
62 m_loggedIn = false;
63 initSequence();
64
65 }
66
~Connection()67 Connection::~Connection()
68 {
69 // During clientStream deletion it can emit connected signal so we disconnect signals.
70 disconnect( d->clientStream, 0, this, 0 );
71
72 delete d->rateClassManager;
73 delete d->clientStream;
74 delete d;
75 }
76
setStartFlapSequenceList(const QList<Oscar::WORD> & seqList)77 void Connection::setStartFlapSequenceList( const QList<Oscar::WORD>& seqList )
78 {
79 m_startFlapSequenceList = seqList;
80 }
81
setClient(Client * c)82 void Connection::setClient( Client* c )
83 {
84 d->client = c;
85 connect( c, SIGNAL(loggedIn()), this, SLOT(loggedIn()) );
86 }
87
connectToServer(const QString & host,quint16 port,bool encrypted,const QString & name)88 void Connection::connectToServer( const QString& host, quint16 port, bool encrypted, const QString &name )
89 {
90 connect( d->clientStream, SIGNAL(error(int)), this, SLOT(streamSocketError(int)) );
91 connect( d->clientStream, SIGNAL(readyRead()), this, SLOT(streamReadyRead()) );
92 connect( d->clientStream, SIGNAL(connected()), this, SIGNAL(connected()) );
93 d->clientStream->connectToServer( host, port, encrypted, name );
94 }
95
close()96 void Connection::close()
97 {
98 d->clientStream->close();
99 reset();
100 }
101
isSupported(int family) const102 bool Connection::isSupported( int family ) const
103 {
104 return ( d->familyList.indexOf( family ) != -1 );
105 }
106
supportedFamilies() const107 QList<int> Connection::supportedFamilies() const
108 {
109 return d->familyList;
110 }
111
addToSupportedFamilies(const QList<int> & familyList)112 void Connection::addToSupportedFamilies( const QList<int>& familyList )
113 {
114 d->familyList += familyList;
115 }
116
addToSupportedFamilies(int family)117 void Connection::addToSupportedFamilies( int family )
118 {
119 d->familyList.append( family );
120 }
121
taskError(const Oscar::SNAC & s,int errCode)122 void Connection::taskError( const Oscar::SNAC& s, int errCode )
123 {
124 d->client->notifyTaskError( s, errCode, false /*fatal*/ );
125 }
126
fatalTaskError(const Oscar::SNAC & s,int errCode)127 void Connection::fatalTaskError( const Oscar::SNAC& s, int errCode )
128 {
129 d->client->notifyTaskError( s, errCode, true /* fatal */ );
130 }
131
settings() const132 Oscar::Settings* Connection::settings() const
133 {
134 return d->client->clientSettings();
135 }
136
flapSequence()137 Oscar::WORD Connection::flapSequence()
138 {
139 d->flapSequence++;
140 if ( d->flapSequence >= 0x8000 ) //the max flap sequence is 0x8000 ( HEX )
141 d->flapSequence = 1;
142
143 return d->flapSequence;
144 }
145
snacSequence()146 Oscar::DWORD Connection::snacSequence()
147 {
148 d->snacSequence++;
149
150 if ( d->snacSequence == 0x0000 )
151 d->snacSequence++;
152
153 return d->snacSequence;
154 }
155
userId() const156 QString Connection::userId() const
157 {
158 return d->client->userId();
159 }
160
password() const161 QString Connection::password() const
162 {
163 return d->client->password();
164 }
165
isIcq() const166 bool Connection::isIcq() const
167 {
168 return d->client->isIcq();
169 }
170
rootTask() const171 Task* Connection::rootTask() const
172 {
173 return d->root;
174 }
175
ssiManager() const176 ContactManager* Connection::ssiManager() const
177 {
178 return d->client->ssiManager();
179 }
180
version() const181 const Oscar::ClientVersion* Connection::version() const
182 {
183 return d->client->version();
184 }
185
versionCap() const186 Oscar::Guid Connection::versionCap() const
187 {
188 return d->client->versionCap();
189 }
190
isLoggedIn() const191 bool Connection::isLoggedIn() const
192 {
193 return m_loggedIn;
194 }
195
localAddress() const196 QHostAddress Connection::localAddress() const
197 {
198 return d->clientStream->localAddress();
199 }
200
addMessageInfo(Oscar::DWORD snacSequence,const Oscar::MessageInfo & messageInfo)201 void Connection::addMessageInfo( Oscar::DWORD snacSequence, const Oscar::MessageInfo& messageInfo )
202 {
203 d->snacSequenceToMessageInfo.insert( snacSequence, messageInfo );
204 }
205
takeMessageInfo(Oscar::DWORD snacSequence)206 Oscar::MessageInfo Connection::takeMessageInfo( Oscar::DWORD snacSequence )
207 {
208 return d->snacSequenceToMessageInfo.take( snacSequence );
209 }
210
messageInfoList() const211 QList<Oscar::MessageInfo> Connection::messageInfoList() const
212 {
213 return d->snacSequenceToMessageInfo.values();
214 }
215
rateManager() const216 RateClassManager* Connection::rateManager() const
217 {
218 return d->rateClassManager;
219 }
220
send(Transfer * request) const221 void Connection::send( Transfer* request ) const
222 {
223 if( !d->clientStream )
224 {
225 kDebug(OSCAR_RAW_DEBUG) << "No stream to write on!";
226 return;
227 }
228 d->rateClassManager->queue( request );
229
230 }
231
forcedSend(Transfer * request) const232 void Connection::forcedSend( Transfer* request ) const
233 {
234 if ( !d->clientStream )
235 {
236 kDebug(OSCAR_RAW_DEBUG) << "No stream to write on";
237 return;
238 }
239 d->clientStream->write( request );
240 }
241
initSequence()242 void Connection::initSequence()
243 {
244 d->snacSequence = ( KRandom::random() & 0xFFFF );
245
246 if ( m_startFlapSequenceList.isEmpty() )
247 d->flapSequence = generateInitialFlapSequence();
248 else
249 d->flapSequence = m_startFlapSequenceList.value( qrand() % m_startFlapSequenceList.size() ) - 1;
250
251 kDebug(OSCAR_RAW_DEBUG) << "d->flapSequence:" << hex << d->flapSequence;
252 }
253
generateInitialFlapSequence() const254 Oscar::WORD Connection::generateInitialFlapSequence() const
255 {
256 // Taken from Miranda (icq_packet.cpp)
257 Oscar::DWORD n = qrand() % 0x8000;
258 Oscar::DWORD s = 0;
259
260 for ( Oscar::DWORD i = n; i >>= 3; s += i ) {}
261 return ((((0 - s) ^ (Oscar::BYTE)n) & 7) ^ n) + 2;
262 }
263
distribute(Transfer * transfer) const264 void Connection::distribute( Transfer * transfer ) const
265 {
266 //d->rateClassManager->recalcRateLevels();
267 if( !rootTask()->take( transfer ) )
268 kDebug(OSCAR_RAW_DEBUG) << "root task refused transfer";
269
270 delete transfer;
271 }
272
reset()273 void Connection::reset()
274 {
275 //clear the family list
276 d->familyList.clear();
277 d->rateClassManager->reset();
278 d->snacSequenceToMessageInfo.clear();
279 }
280
streamReadyRead()281 void Connection::streamReadyRead()
282 {
283 // take the incoming transfer and distribute it to the task tree
284 Transfer * transfer = d->clientStream->read();
285 distribute( transfer );
286 }
287
loggedIn()288 void Connection::loggedIn()
289 {
290 m_loggedIn = true;
291 }
292
streamSocketError(int code)293 void Connection::streamSocketError( int code )
294 {
295 emit socketError( code, d->clientStream->errorString() );
296 }
297
298