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