1 
2 /***************************************************************************
3                    jabberaccount.cpp  -  core Jabber account class
4                              -------------------
5     begin                : Sat M??? 8 2003
6     copyright            : (C) 2003 by Till Gerken <till@tantalo.net>
7 							Based on JabberProtocol by Daniel Stone <dstone@kde.org>
8 							and Till Gerken <till@tantalo.net>.
9 	copyright            : (C) 2006 by Olivier Goffart <ogoffart at kde.org>
10 	Copyright 2006 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
11 
12 			   Kopete (C) 2001-2006 Kopete developers
13 			   <kopete-devel@kde.org>.
14  ***************************************************************************/
15 
16 /***************************************************************************
17  *                                                                         *
18  *   This program is free software; you can redistribute it and/or modify  *
19  *   it under the terms of the GNU General Public License as published by  *
20  *   the Free Software Foundation; either either version 2
21    of the License, or (at your option) any later version.of the License, or     *
22  *   (at your option) any later version.                                   *
23  *                                                                         *
24  ***************************************************************************/
25 
26 #include "im.h"
27 #include "filetransfer.h"
28 #include "xmpp.h"
29 #include "xmpp_tasks.h"
30 #include "qca.h"
31 #include "bsocket.h"
32 
33 #include "jabberaccount.h"
34 #include "jabberbookmarks.h"
35 
36 #include <time.h>
37 
38 #include <QString>
39 #include <QRegExp>
40 #include <QTimer>
41 
42 #include <KComponentData>
43 #include <KConfig>
44 #include <KMessageBox>
45 #include <KLocalizedString>
46 #include <KAboutData>
47 #include <k3socketbase.h>
48 #include <KPasswordDialog>
49 #include <KInputDialog>
50 #include <KActionMenu>
51 #include <KComponentData>
52 
53 #include "jabberconnector.h"
54 #include "jabberresourcepool.h"
55 #include "jabbercontactpool.h"
56 // #include "jabberfiletransfer.h"
57 #include "jabbercontact.h"
58 #include "jabbergroupcontact.h"
59 #include "jabbercapabilitiesmanager.h"
60 // #include "jabbertransport.h"
61 /*#include "dlgxmppconsole.h"
62 #include "dlgjabberservices.h"
63 #include "dlgjabberchatjoin.h"*/
64 #include "jt_pubsub.h"
65 
66 #include <sys/utsname.h>
67 
68 #ifdef SUPPORT_JINGLE
69 #include "voicecaller.h"
70 #include "jinglevoicecaller.h"
71 
72 // NOTE: Disabled for 0.12, will develop them futher in KDE4
73 // #include "jinglesessionmanager.h"
74 // #include "jinglesession.h"
75 // #include "jinglevoicesession.h"
76 #include "jinglevoicesessiondialog.h"
77 #endif
78 
79 #define KOPETE_CAPS_NODE "http://kopete.kde.org/jabber/caps"
80 
81 
82 
JabberAccount(JabberProtocol * parent,const QString & accountId)83 JabberAccount::JabberAccount (JabberProtocol * parent, const QString & accountId)
84 			  :JabberProtocol( parent/*, accountId, false */)
85 {
86 	qCDebug(JABBER_PROTOCOL_LOG) << "Instantiating new account " << accountId;
87 
88 	m_protocol = parent;
89 
90 	m_jabberClient = 0L;
91 
92 	m_resourcePool = 0L;
93 	m_contactPool = 0L;
94 #ifdef SUPPORT_JINGLE
95 	m_voiceCaller = 0L;
96 	//m_jingleSessionManager = 0L; // NOTE: Disabled for 0.12
97 #endif
98 // 	m_bookmarks = new JabberBookmarks(this);
99 	m_removing=false;
100 	m_notifiedUserCannotBindTransferPort = false;
101 	// add our own contact to the pool
102 // 	JabberContact *myContact = contactPool()->addContact ( XMPP::RosterItem ( accountId ), Kopete::ContactList::self()->myself(), false );
103 // 	setMyself( myContact );
104 
105 	m_initialPresence = XMPP::Status ( "", "", 5, true );
106 
107 }
108 
~JabberAccount()109 JabberAccount::~JabberAccount ()
110 {
111 	disconnect ( 0/*Kopete::Account::Manual*/ );
112 
113 	// Remove this account from Capabilities manager.
114 	protocol()->capabilitiesManager()->removeAccount( this );
115 
116 	cleanup ();
117 
118 // 	QMap<QString,JabberTransport*> tranposrts_copy=m_transports;
119 // 	QMap<QString,JabberTransport*>::Iterator it;
120 // 	for ( it = tranposrts_copy.begin(); it != tranposrts_copy.end(); ++it )
121 // 		delete it.value();
122 }
123 
cleanup()124 void JabberAccount::cleanup ()
125 {
126 
127 	delete m_jabberClient;
128 
129 	m_jabberClient = 0L;
130 
131 	delete m_resourcePool;
132 	m_resourcePool = 0L;
133 
134 	delete m_contactPool;
135 	m_contactPool = 0L;
136 
137 #ifdef SUPPORT_JINGLE
138 	delete m_voiceCaller;
139 	m_voiceCaller = 0L;
140 
141 // 	delete m_jingleSessionManager;
142 // 	m_jingleSessionManager = 0L;
143 #endif
144 }
145 
146 // void JabberAccount::setS5BServerPort ( int port )
147 // {
148 //
149 // 	if ( !m_jabberClient )
150 // 	{
151 // 		return;
152 // 	}
153 //
154 // 	if ( !m_jabberClient->setS5BServerPort ( port ) && !m_notifiedUserCannotBindTransferPort)
155 // 	{
156 // 		KMessageBox::queuedMessageBox ( 0, KMessageBox::Sorry,
157 // 							 i18n ( "Could not bind the Jabber file transfer manager to a local port. Please check if the file transfer port is already in use, or choose another port in the account settings." ),
158 // 							 i18n ( "Failed to start Jabber File Transfer Manager" ) );
159 // 		m_notifiedUserCannotBindTransferPort = true;
160 // 	}
161 //
162 // }
163 
resourcePool()164 JabberResourcePool *JabberAccount::resourcePool ()
165 {
166 
167 	if ( !m_resourcePool )
168 		m_resourcePool = new JabberResourcePool ( this );
169 
170 	return m_resourcePool;
171 
172 }
173 
contactPool()174 JabberContactPool *JabberAccount::contactPool ()
175 {
176 
177 	if ( !m_contactPool )
178 		m_contactPool = new JabberContactPool ( this );
179 
180 	return m_contactPool;
181 
182 }
183 
184 // bool JabberAccount::createContact (const QString & contactId,  Kopete::MetaContact * metaContact)
185 // {
186 //
187 // 	// collect all group names
188 // 	QStringList groupNames;
189 // 	Kopete::GroupList groupList = metaContact->groups();
190 // 	foreach( Kopete::Group *group, groupList )
191 // 		groupNames += group->displayName();
192 //
193 // 	XMPP::Jid jid ( contactId );
194 // 	XMPP::RosterItem item ( jid );
195 // 	item.setName ( metaContact->displayName () );
196 // 	item.setGroups ( groupNames );
197 //
198 // 	// this contact will be created with the "dirty" flag set
199 // 	// (it will get reset if the contact appears in the roster during connect)
200 // 	JabberContact *contact = contactPool()->addContact ( item, metaContact, true );
201 //
202 // 	return ( contact != 0 );
203 //
204 // }
205 
errorConnectFirst()206 void JabberAccount::errorConnectFirst ()
207 {
208 
209 	KMessageBox::queuedMessageBox ( 0,
210 									KMessageBox::Error,
211 									i18n ("Please connect first."), i18n ("Jabber Error") );
212 
213 }
214 
errorConnectionLost()215 void JabberAccount::errorConnectionLost ()
216 {
217 // 	disconnected(0 /*Kopete::Account::ConnectionReset */);
218 }
219 
isConnecting()220 bool JabberAccount::isConnecting ()
221 {
222 return false;
223 // 	XMPP::Jid jid ( contactId () );
224 //
225 // 	// see if we are currently trying to connect
226 // 	return resourcePool()->bestResource ( jid ).status().show () == QString("connecting");
227 
228 }
229 
connectWithPassword(const QString & password)230 void JabberAccount::connectWithPassword ( const QString &password )
231 {
232 	qCDebug(JABBER_PROTOCOL_LOG) << "called";
233 
234 	/* Cancel connection process if no password has been supplied. */
235 	if ( password.isEmpty () )
236 	{
237 		disconnect ( 0/*Kopete::Account::Manual*/ );
238 		return;
239 	}
240 
241 	/* Don't do anything if we are already connected. */
242 	if ( isConnected () )
243 		return;
244 
245 	// instantiate new client backend or clean up old one
246 	if ( !m_jabberClient )
247 	{
248 		m_jabberClient = new JabberClient;
249 
250 		QObject::connect ( m_jabberClient, SIGNAL (csDisconnected()), this, SLOT (slotCSDisconnected()) );
251 		QObject::connect ( m_jabberClient, SIGNAL (csError(int)), this, SLOT (slotCSError(int)) );
252 		QObject::connect ( m_jabberClient, SIGNAL (tlsWarning(QCA::TLS::IdentityResult,QCA::Validity)), this, SLOT (slotHandleTLSWarning(QCA::TLS::IdentityResult,QCA::Validity)) );
253 		QObject::connect ( m_jabberClient, SIGNAL (connected()), this, SLOT (slotConnected()) );
254 		QObject::connect ( m_jabberClient, SIGNAL (error(JabberClient::ErrorCode)), this, SLOT (slotClientError(JabberClient::ErrorCode)) );
255 
256 		QObject::connect ( m_jabberClient, SIGNAL (subscription(XMPP::Jid,QString)),
257 				   this, SLOT (slotSubscription(XMPP::Jid,QString)) );
258 		QObject::connect ( m_jabberClient, SIGNAL (rosterRequestFinished(bool)),
259 				   this, SLOT (slotRosterRequestFinished(bool)) );
260 		QObject::connect ( m_jabberClient, SIGNAL (newContact(XMPP::RosterItem)),
261 				   this, SLOT (slotContactUpdated(XMPP::RosterItem)) );
262 		QObject::connect ( m_jabberClient, SIGNAL (contactUpdated(XMPP::RosterItem)),
263 				   this, SLOT (slotContactUpdated(XMPP::RosterItem)) );
264 		QObject::connect ( m_jabberClient, SIGNAL (contactDeleted(XMPP::RosterItem)),
265 				   this, SLOT (slotContactDeleted(XMPP::RosterItem)) );
266 		QObject::connect ( m_jabberClient, SIGNAL (resourceAvailable(XMPP::Jid,XMPP::Resource)),
267 				   this, SLOT (slotResourceAvailable(XMPP::Jid,XMPP::Resource)) );
268 		QObject::connect ( m_jabberClient, SIGNAL (resourceUnavailable(XMPP::Jid,XMPP::Resource)),
269 				   this, SLOT (slotResourceUnavailable(XMPP::Jid,XMPP::Resource)) );
270 		QObject::connect ( m_jabberClient, SIGNAL (messageReceived(XMPP::Message)),
271 				   this, SLOT (slotReceivedMessage(XMPP::Message)) );
272 		QObject::connect ( m_jabberClient, SIGNAL (incomingFileTransfer()),
273 				   this, SLOT (slotIncomingFileTransfer()) );
274 		QObject::connect ( m_jabberClient, SIGNAL (groupChatJoined(XMPP::Jid)),
275 				   this, SLOT (slotGroupChatJoined(XMPP::Jid)) );
276 		QObject::connect ( m_jabberClient, SIGNAL (groupChatLeft(XMPP::Jid)),
277 				   this, SLOT (slotGroupChatLeft(XMPP::Jid)) );
278 		QObject::connect ( m_jabberClient, SIGNAL (groupChatPresence(XMPP::Jid,XMPP::Status)),
279 				   this, SLOT (slotGroupChatPresence(XMPP::Jid,XMPP::Status)) );
280 		QObject::connect ( m_jabberClient, SIGNAL (groupChatError(XMPP::Jid,int,QString)),
281 				   this, SLOT (slotGroupChatError(XMPP::Jid,int,QString)) );
282 		QObject::connect ( m_jabberClient, SIGNAL (debugMessage(QString)),
283 				   this, SLOT (slotClientDebugMessage(QString)) );
284 	}
285 	else
286 	{
287 		m_jabberClient->disconnect ();
288 	}
289 
290 	// we need to use the old protocol for now
291 	m_jabberClient->setUseXMPP09 ( true );
292 
293 	// set SSL flag (this should be converted to forceTLS when using the new protocol)
294 	m_jabberClient->setUseSSL ( false );
295 
296 	// override server and port (this should be dropped when using the new protocol and no direct SSL)
297 	m_jabberClient->setOverrideHost ( true, server (), port () );
298 
299 	// allow plaintext password authentication or not?
300 	m_jabberClient->setAllowPlainTextPassword ( false );
301 
302 	// enable file transfer (if empty, IP will be set after connection has been established)
303 // 	KConfigGroup config = KSharedConfig::openConfig()->group ( "Jabber" );
304 // 	m_jabberClient->setFileTransfersEnabled ( true, config.readEntry ( "LocalIP" ) );
305 // 	setS5BServerPort ( config.readEntry ( "LocalPort", 8010 ) );
306 
307 	//
308 	// Determine system name
309 	//
310 		struct utsname utsBuf;
311 
312 		uname (&utsBuf);
313 
314 		m_jabberClient->setClientName ("Kopete");
315 		m_jabberClient->setClientVersion (KGlobal::mainComponent().aboutData()->version ());
316 		m_jabberClient->setOSName (QString ("%1 %2").arg (utsBuf.sysname, 1).arg (utsBuf.release, 2));
317 
318 
319 	// Set caps node information
320 	m_jabberClient->setCapsNode(KOPETE_CAPS_NODE);
321 	m_jabberClient->setCapsVersion(KGlobal::mainComponent().aboutData()->version());
322 
323 	// Set Disco Identity information
324 	DiscoItem::Identity identity;
325 	identity.category = "client";
326 	identity.type = "pc";
327 	identity.name = "Kopete";
328 	m_jabberClient->setDiscoIdentity(identity);
329 
330 	//BEGIN TIMEZONE INFORMATION
331 	//
332 	// Set timezone information (code from Psi)
333 	// Copyright (C) 2001-2003  Justin Karneges
334 	//
335 	time_t x;
336 	time(&x);
337 	char str[256];
338 	char fmt[32];
339 	int timezoneOffset(0);
340 	QString timezoneString;
341 
342 	strcpy ( fmt, "%z" );
343 	strftime ( str, 256, fmt, localtime ( &x ) );
344 
345 	if ( strcmp ( fmt, str ) )
346 	{
347 		QString s = str;
348 		if ( s.at ( 0 ) == '+' )
349 			s.remove ( 0, 1 );
350 		s.truncate ( s.length () - 2 );
351 		timezoneOffset = s.toInt();
352 	}
353 
354 	strcpy ( fmt, "%Z" );
355 	strftime ( str, 256, fmt, localtime ( &x ) );
356 
357 	if ( strcmp ( fmt, str ) )
358 		timezoneString = str;
359 	//END of timezone code
360 
361 	qCDebug(JABBER_PROTOCOL_LOG) << "Determined timezone " << timezoneString << " with UTC offset " << timezoneOffset << " hours.";
362 
363 	m_jabberClient->setTimeZone ( timezoneString, timezoneOffset );
364 
365 	qCDebug(JABBER_PROTOCOL_LOG) << "Connecting to Jabber server " << server() << ":" << port();
366 
367 	setPresence( XMPP::Status ("connecting", "", 0, true) );
368 
369 	switch ( m_jabberClient->connect ( XMPP::Jid ( accountId () + QString("/") + resource () ), password ) )
370 	{
371 		case JabberClient::NoTLS:
372 			// no SSL support, at the connecting stage this means the problem is client-side
373 			KMessageBox::queuedMessageBox(0, KMessageBox::Error,
374 								i18n ("SSL support could not be initialized for account %1. This is most likely because the QCA TLS plugin is not installed on your system.",
375 								accountId()),
376 								i18n ("Jabber SSL Error"));
377 			break;
378 
379 		case JabberClient::Ok:
380 		default:
381 			// everything alright!
382 
383 			break;
384 	}
385 }
386 
slotClientDebugMessage(const QString & msg)387 void JabberAccount::slotClientDebugMessage ( const QString &msg )
388 {
389 
390 	qCDebug(JABBER_PROTOCOL_LOG) << msg;
391 
392 }
393 
handleTLSWarning(JabberClient * jabberClient,QCA::TLS::IdentityResult identityResult,QCA::Validity validityResult)394 bool JabberAccount::handleTLSWarning (
395 		JabberClient *jabberClient,
396 		QCA::TLS::IdentityResult identityResult,
397 		QCA::Validity validityResult )
398 {
399 	QString validityString, code, idString, idCode;
400 
401 	QString server    = jabberClient->jid().domain ();
402 	QString accountId = jabberClient->jid().bare ();
403 
404 	switch ( identityResult )
405 	{
406 		case QCA::TLS::Valid:
407 			break;
408 		case QCA::TLS::HostMismatch:
409 			idString = i18n("The host name does not match the one in the certificate.");
410 			idCode   = "HostMismatch";
411 			break;
412 		case QCA::TLS::InvalidCertificate:
413 			idString = i18n("The certificate is invalid.");
414 			idCode   = "InvalidCert";
415 			break;
416 		case QCA::TLS::NoCertificate:
417 			idString = i18n("No certificate was presented.");
418 			idCode   = "NoCert";
419 			break;
420 	}
421 
422 	switch ( validityResult )
423 	{
424 		case QCA::ValidityGood:
425 			break;
426 		case QCA::ErrorRejected:
427 			validityString = i18n("The Certificate Authority rejected the certificate.");
428 			code = "Rejected";
429 			break;
430 		case QCA::ErrorUntrusted:
431 			validityString = i18n("The certificate is not trusted.");
432 			code = "Untrusted";
433 			break;
434 		case QCA::ErrorSignatureFailed:
435 			validityString = i18n("The signature is invalid.");
436 			code = "SignatureFailed";
437 			break;
438 		case QCA::ErrorInvalidCA:
439 			validityString = i18n("The Certificate Authority is invalid.");
440 			code = "InvalidCA";
441 			break;
442 		case QCA::ErrorInvalidPurpose:
443 			validityString = i18n("Invalid certificate purpose.");
444 			code = "InvalidPurpose";
445 			break;
446 		case QCA::ErrorSelfSigned:
447 			validityString = i18n("The certificate is self-signed.");
448 			code = "SelfSigned";
449 			break;
450 		case QCA::ErrorRevoked:
451 			validityString = i18n("The certificate has been revoked.");
452 			code = "Revoked";
453 			break;
454 		case QCA::ErrorPathLengthExceeded:
455 			validityString = i18n("Maximum certificate chain length was exceeded.");
456 			code = "PathLengthExceeded";
457 			break;
458 		case QCA::ErrorExpired:
459 			validityString = i18n("The certificate has expired.");
460 			code = "Expired";
461 			break;
462 		case QCA::ErrorExpiredCA:
463 			validityString = i18n("The Certificate Authority has expired.");
464 			code = "ExpiredCA";
465 			break;
466 		case QCA::ErrorValidityUnknown:
467 			validityString = i18n("Validity is unknown.");
468 			code = "ValidityUnknown";
469 			break;
470 	}
471 
472 	QString message;
473 
474 	if (!idString.isEmpty())
475 	{
476 		if (!validityString.isEmpty())
477 		{
478 			message = i18n("<qt><p>The identity and the certificate of server %1 could not be "
479 					"validated for account %2:</p><p>%3</p><p>%4</p><p>Do you want to continue?</p></qt>",
480 					server, accountId, idString, validityString);
481 		}
482 		else
483 		{
484 			message = i18n("<qt><p>The certificate of server %1 could not be validated for "
485 					"account %2: %3</p><p>Do you want to continue?</p></qt>",
486 					server, accountId, idString);
487 		}
488 	} else {
489 		message = i18n("<qt><p>The certificate of server %1 could not be validated for "
490 			"account %2: %3</p><p>Do you want to continue?</p></qt>",
491 			server, accountId, validityString);
492 	}
493 
494 	return ( KMessageBox::warningContinueCancel ( 0,
495 					  message,
496 					  i18n("Jabber Connection Certificate Problem"),
497 					  KStandardGuiItem::cont(),KStandardGuiItem::cancel(),
498 					  QString("KopeteTLSWarning") + server + idCode + code) == KMessageBox::Continue );
499 
500 }
501 
slotHandleTLSWarning(QCA::TLS::IdentityResult identityResult,QCA::Validity validityResult)502 void JabberAccount::slotHandleTLSWarning (
503 		QCA::TLS::IdentityResult identityResult,
504 		QCA::Validity validityResult )
505 {
506 	qCDebug(JABBER_PROTOCOL_LOG) << "Handling TLS warning...";
507 
508 	if ( handleTLSWarning ( m_jabberClient, identityResult, validityResult ) )
509 	{
510 		// resume stream
511 		m_jabberClient->continueAfterTLSWarning ();
512 	}
513 	else
514 	{
515 		// disconnect stream
516 		disconnect ( 0/*Kopete::Account::Manual*/ );
517 	}
518 
519 }
520 
slotClientError(JabberClient::ErrorCode errorCode)521 void JabberAccount::slotClientError ( JabberClient::ErrorCode errorCode )
522 {
523 	qCDebug(JABBER_PROTOCOL_LOG) << "Handling client error...";
524 
525 	switch ( errorCode )
526 	{
527 		case JabberClient::NoTLS:
528 		default:
529 			KMessageBox::queuedMessageBox ( 0, KMessageBox::Error,
530 					     i18n ("An encrypted connection with the Jabber server could not be established."),
531 					     i18n ("Jabber Connection Error"));
532 			disconnect ( 0/*Kopete::Account::Manual*/ );
533 			break;
534 	}
535 
536 }
537 
slotConnected()538 void JabberAccount::slotConnected ()
539 {
540 	qCDebug(JABBER_PROTOCOL_LOG) << "Connected to Jabber server.";
541 
542 #ifdef SUPPORT_JINGLE
543 	if(!m_voiceCaller)
544 	{
545 		qCDebug(JABBER_PROTOCOL_LOG) << "Creating Jingle Voice caller...";
546 		m_voiceCaller = new JingleVoiceCaller( this );
547 		QObject::connect(m_voiceCaller,SIGNAL(incoming(Jid)),this,SLOT(slotIncomingVoiceCall(Jid)));
548 		m_voiceCaller->initialize();
549 	}
550 
551 #if 0
552 	if(!m_jingleSessionManager)
553 	{
554 		qCDebug(JABBER_PROTOCOL_LOG) << "Creating Jingle Session Manager...";
555 		m_jingleSessionManager = new JingleSessionManager( this );
556 		QObject::connect(m_jingleSessionManager, SIGNAL(incomingSession(QString,JingleSession*)), this, SLOT(slotIncomingJingleSession(QString,JingleSession*)));
557 	}
558 #endif
559 
560 	// Set caps extensions
561 	m_jabberClient->client()->addExtension("voice-v1", Features(QString("http://www.google.com/xmpp/protocol/voice/v1")));
562 #endif
563 
564 	qCDebug(JABBER_PROTOCOL_LOG) << "Requesting roster...";
565 	m_jabberClient->requestRoster ();
566 }
567 
slotRosterRequestFinished(bool success)568 void JabberAccount::slotRosterRequestFinished ( bool success )
569 {
570 
571 	if ( success )
572 	{
573 		// the roster was imported successfully, clear
574 		// all "dirty" items from the contact list
575 		contactPool()->cleanUp ();
576 	}
577 
578 	/* Since we are online now, set initial presence. Don't do this
579 	* before the roster request or we will receive presence
580 	* information before we have updated our roster with actual
581 	* contacts from the server! (Iris won't forward presence
582 	* information in that case either). */
583 	qCDebug(JABBER_PROTOCOL_LOG) << "Setting initial presence...";
584 	setPresence ( m_initialPresence );
585 
586 }
587 
slotIncomingFileTransfer()588 void JabberAccount::slotIncomingFileTransfer ()
589 {
590 
591 	// delegate the work to a file transfer object
592 // 	new JabberFileTransfer ( this, client()->fileTransferManager()->takeIncoming () );
593 
594 }
595 
setOnlineStatus(const JabberProtocol::OnlineStatus & status,const QString & reason)596 void JabberAccount::setOnlineStatus( const JabberProtocol::OnlineStatus& status, const QString& reason )
597 {
598 	XMPP::Status xmppStatus = m_protocol->osToStatus( status, reason );
599 
600   if( status == JabberProtocol::JabberOffline )
601 	{
602 			xmppStatus.setIsAvailable( false );
603 			qCDebug(JABBER_PROTOCOL_LOG) << "CROSS YOUR FINGERS! THIS IS GONNA BE WILD";
604             disconnect (0/*Manual*/, xmppStatus);
605             return;
606     }
607 
608 	if( isConnecting () )
609 	{
610 		return;
611 	}
612 
613 
614 	if ( !isConnected () )
615 	{
616 		// we are not connected yet, so connect now
617 		m_initialPresence = xmppStatus;
618 // 		connect ( status );
619 	}
620 	else
621 	{
622 		setPresence ( xmppStatus );
623 	}
624 }
625 
setStatusMessage(const QString & statusMessage)626 void JabberAccount::setStatusMessage( const QString& statusMessage )
627 {
628 	Q_UNUSED(statusMessage);
629 }
630 
disconnect(int reason)631 void JabberAccount::disconnect ( int reason )
632 {
633 	qCDebug(JABBER_PROTOCOL_LOG) << "disconnect() called";
634 
635 	if (isConnected ())
636 	{
637 		qCDebug(JABBER_PROTOCOL_LOG) << "Still connected, closing connection...";
638 		/* Tell backend class to disconnect. */
639 		m_jabberClient->disconnect ();
640 	}
641 
642 	// make sure that the connection animation gets stopped if we're still
643 	// in the process of connecting
644 	setPresence ( XMPP::Status ("", "", 0, false) );
645 	m_initialPresence = XMPP::Status ("", "", 5, true);
646 
647 	/* FIXME:
648 	 * We should delete the JabberClient instance here,
649 	 * but active timers in Iris prevent us from doing so.
650 	 * (in a failed connection attempt, these timers will
651 	 * try to access an already deleted object).
652 	 * Instead, the instance will lurk until the next
653 	 * connection attempt.
654 	 */
655 	qCDebug(JABBER_PROTOCOL_LOG) << "Disconnected.";
656 
657 // 	disconnected ( reason );
658 }
659 
disconnect(int reason,XMPP::Status & status)660 void JabberAccount::disconnect( int reason, XMPP::Status &status )
661 {
662     qCDebug(JABBER_PROTOCOL_LOG) << "disconnect( reason, status ) called";
663 
664 	if (isConnected ())
665 	{
666 		qCDebug(JABBER_PROTOCOL_LOG) << "Still connected, closing connection...";
667 		/* Tell backend class to disconnect. */
668 		m_jabberClient->disconnect (status);
669 	}
670 
671 	// make sure that the connection animation gets stopped if we're still
672 	// in the process of connecting
673 	setPresence ( status );
674 
675 	/* FIXME:
676 	 * We should delete the JabberClient instance here,
677 	 * but active timers in Iris prevent us from doing so.
678 	 * (in a failed connection attempt, these timers will
679 	 * try to access an already deleted object).
680 	 * Instead, the instance will lurk until the next
681 	 * connection attempt.
682 	 */
683 	qCDebug(JABBER_PROTOCOL_LOG) << "Disconnected.";
684 
685 // 	Kopete::Account::disconnected ( reason );
686 }
687 
disconnect()688 void JabberAccount::disconnect ()
689 {
690 	disconnect ( /*Manual*/0 );
691 }
692 
slotConnect()693 void JabberAccount::slotConnect ()
694 {
695 // 	connect ();
696 }
697 
slotDisconnect()698 void JabberAccount::slotDisconnect ()
699 {
700 	disconnect ( /*Kopete::Account::Manual*/ 0);
701 }
702 
slotCSDisconnected()703 void JabberAccount::slotCSDisconnected ()
704 {
705 	qCDebug(JABBER_PROTOCOL_LOG) << "Disconnected from Jabber server.";
706 
707 	/*
708 	 * We should delete the JabberClient instance here,
709 	 * but timers etc prevent us from doing so. Iris does
710 	 * not like to be deleted from a slot.
711 	 */
712 
713 	/* It seems that we don't get offline notifications when going offline
714 	 * with the protocol, so clear all resources manually. */
715 	resourcePool()->clear();
716 
717 }
718 
handleStreamError(int streamError,int streamCondition,int connectorCode,const QString & server,int & errorClass,QString additionalErrMsg)719 void JabberAccount::handleStreamError (int streamError, int streamCondition, int connectorCode, const QString &server, int &errorClass, QString additionalErrMsg)
720 {
721 	QString errorText;
722 	QString errorCondition;
723 
724 	errorClass = 0/*Kopete::Account::InvalidHost*/;
725 
726 	/*
727 	 * Display error to user.
728 	 * FIXME: for unknown errors, maybe add error codes?
729 	 */
730 	switch(streamError)
731 	{
732 		case XMPP::Stream::ErrParse:
733 			errorClass = /*Kopete::Account::Unknown*/0;
734 			errorText = i18n("Malformed packet received.");
735 			break;
736 
737 		case XMPP::Stream::ErrProtocol:
738 			errorClass = /*Kopete::Account::Unknown*/0;
739 			errorText = i18n("There was an unrecoverable error in the protocol.");
740 			break;
741 
742 		case XMPP::Stream::ErrStream:
743 			switch(streamCondition)
744 			{
745 				case XMPP::Stream::GenericStreamError:
746 					errorCondition = i18n("Generic stream error.");
747 					break;
748 				case XMPP::Stream::Conflict:
749 					// FIXME: need a better error message here
750 					errorCondition = i18n("There was a conflict in the information received.");
751 					break;
752 				case XMPP::Stream::ConnectionTimeout:
753 					errorCondition = i18n("The stream timed out.");
754 					break;
755 				case XMPP::Stream::InternalServerError:
756 					errorCondition = i18n("Internal server error.");
757 					break;
758 				case XMPP::Stream::InvalidFrom:
759 					errorCondition = i18n("Stream packet received from an invalid address.");
760 					break;
761 				case XMPP::Stream::InvalidXml:
762 					errorCondition = i18n("Malformed stream packet received.");
763 					break;
764 				case XMPP::Stream::PolicyViolation:
765 					// FIXME: need a better error message here
766 					errorCondition = i18n("Policy violation in the protocol stream.");
767 					break;
768 				case XMPP::Stream::ResourceConstraint:
769 					// FIXME: need a better error message here
770 					errorCondition = i18n("Resource constraint.");
771 					break;
772 				case XMPP::Stream::SystemShutdown:
773 					// FIXME: need a better error message here
774 					errorCondition = i18n("System shutdown.");
775 					break;
776 				default:
777 					errorCondition = i18n("Unknown reason.");
778 					break;
779 			}
780 
781 			errorText = i18n("There was an error in the protocol stream: %1", errorCondition);
782 			break;
783 
784 		case XMPP::ClientStream::ErrConnection:
785 			switch(connectorCode)
786 			{
787  				case KNetwork::KSocketBase::LookupFailure:
788 					errorClass = /*Kopete::Account::InvalidHost*/0;
789 					errorCondition = i18n("Host not found.");
790 					break;
791 				case KNetwork::KSocketBase::AddressInUse:
792 					errorCondition = i18n("Address is already in use.");
793 					break;
794 				case KNetwork::KSocketBase::AlreadyCreated:
795 					errorCondition = i18n("Cannot recreate the socket.");
796 					break;
797 				case KNetwork::KSocketBase::AlreadyBound:
798 					errorCondition = i18n("Cannot bind the socket again.");
799 					break;
800 				case KNetwork::KSocketBase::AlreadyConnected:
801 					errorCondition = i18n("Socket is already connected.");
802 					break;
803 				case KNetwork::KSocketBase::NotConnected:
804 					errorCondition = i18n("Socket is not connected.");
805 					break;
806 				case KNetwork::KSocketBase::NotBound:
807 					errorCondition = i18n("Socket is not bound.");
808 					break;
809 				case KNetwork::KSocketBase::NotCreated:
810 					errorCondition = i18n("Socket has not been created.");
811 					break;
812 				case KNetwork::KSocketBase::WouldBlock:
813 					errorCondition = i18n("The socket operation would block. You should not see this error: please use \"Report Bug\" from the Help menu.");
814 					break;
815 				case KNetwork::KSocketBase::ConnectionRefused:
816 					errorCondition = i18n("Connection refused.");
817 					break;
818 				case KNetwork::KSocketBase::ConnectionTimedOut:
819 					errorCondition = i18n("Connection timed out.");
820 					break;
821 				case KNetwork::KSocketBase::InProgress:
822 					errorCondition = i18n("Connection attempt already in progress.");
823 					break;
824 				case KNetwork::KSocketBase::NetFailure:
825 					errorCondition = i18n("Network failure.");
826 					break;
827 				case KNetwork::KSocketBase::NotSupported:
828 					errorCondition = i18n("Operation is not supported.");
829 					break;
830 				case KNetwork::KSocketBase::Timeout:
831 					errorCondition = i18n("Socket timed out.");
832 					break;
833 				default:
834 					errorClass = /*Kopete::Account::ConnectionReset*/0;
835 					//errorCondition = i18n("Sorry, something unexpected happened that I do not know more about.");
836 					break;
837 			}
838 			if(!errorCondition.isEmpty())
839 				errorText = i18n("There was a connection error: %1", errorCondition);
840 			break;
841 
842 		case XMPP::ClientStream::ErrNeg:
843 			switch(streamCondition)
844 			{
845 				case XMPP::ClientStream::HostUnknown:
846 					// FIXME: need a better error message here
847 					errorCondition = i18n("Unknown host.");
848 					break;
849 				case XMPP::ClientStream::RemoteConnectionFailed:
850 					// FIXME: need a better error message here
851 					errorCondition = i18n("Could not connect to a required remote resource.");
852 					break;
853 				case XMPP::ClientStream::SeeOtherHost:
854 					errorCondition = i18n("It appears we have been redirected to another server; I do not know how to handle this.");
855 					break;
856 				case XMPP::ClientStream::UnsupportedVersion:
857 					errorCondition = i18n("Unsupported protocol version.");
858 					break;
859 				default:
860 					errorCondition = i18n("Unknown error.");
861 					break;
862 			}
863 
864 			errorText = i18n("There was a negotiation error: %1", errorCondition);
865 			break;
866 
867 		case XMPP::ClientStream::ErrTLS:
868 			switch(streamCondition)
869 			{
870 				case XMPP::ClientStream::TLSStart:
871 					errorCondition = i18n("Server rejected our request to start the TLS handshake.");
872 					break;
873 				case XMPP::ClientStream::TLSFail:
874 					errorCondition = i18n("Failed to establish a secure connection.");
875 					break;
876 				default:
877 					errorCondition = i18n("Unknown error.");
878 					break;
879 			}
880 
881 			errorText = i18n("There was a Transport Layer Security (TLS) error: %1", errorCondition);
882 			break;
883 
884 		case XMPP::ClientStream::ErrAuth:
885 			switch(streamCondition)
886 			{
887 				case XMPP::ClientStream::GenericAuthError:
888 					errorCondition = i18n("Login failed with unknown reason.");
889 					break;
890 				case XMPP::ClientStream::NoMech:
891 					errorCondition = i18n("No appropriate authentication mechanism available.");
892 					break;
893 				case XMPP::ClientStream::BadProto:
894 					errorCondition = i18n("Bad SASL authentication protocol.");
895 					break;
896 				case XMPP::ClientStream::BadServ:
897 					errorCondition = i18n("Server failed mutual authentication.");
898 					break;
899 				case XMPP::ClientStream::EncryptionRequired:
900 					errorCondition = i18n("Encryption is required but not present.");
901 					break;
902 				case XMPP::ClientStream::InvalidAuthzid:
903 					errorCondition = i18n("Invalid user ID.");
904 					break;
905 				case XMPP::ClientStream::InvalidMech:
906 					errorCondition = i18n("Invalid mechanism.");
907 					break;
908 				case XMPP::ClientStream::InvalidRealm:
909 					errorCondition = i18n("Invalid realm.");
910 					break;
911 				case XMPP::ClientStream::MechTooWeak:
912 					errorCondition = i18n("Mechanism too weak.");
913 					break;
914 				case XMPP::ClientStream::NotAuthorized:
915 					errorCondition = i18n("Wrong credentials supplied. (check your user ID and password)");
916 					break;
917 				case XMPP::ClientStream::TemporaryAuthFailure:
918 					errorCondition = i18n("Temporary failure, please try again later.");
919 					break;
920 				default:
921 					errorCondition = i18n("Unknown error.");
922 					break;
923 			}
924 
925 			errorText = i18n("There was an error authenticating with the server: %1", errorCondition);
926 			break;
927 
928 		case XMPP::ClientStream::ErrSecurityLayer:
929 			switch(streamCondition)
930 			{
931 				case XMPP::ClientStream::LayerTLS:
932 					errorCondition = i18n("Transport Layer Security (TLS) problem.");
933 					break;
934 				case XMPP::ClientStream::LayerSASL:
935 					errorCondition = i18n("Simple Authentication and Security Layer (SASL) problem.");
936 					break;
937 				default:
938 					errorCondition = i18n("Unknown error.");
939 					break;
940 			}
941 
942 			errorText = i18n("There was an error in the security layer: %1", errorCondition);
943 			break;
944 
945 		case XMPP::ClientStream::ErrBind:
946 			switch(streamCondition)
947 			{
948 				case XMPP::ClientStream::BindNotAllowed:
949 					errorCondition = i18n("No permission to bind the resource.");
950 					break;
951 				case XMPP::ClientStream::BindConflict:
952 					errorCondition = i18n("The resource is already in use.");
953 					break;
954 				default:
955 					errorCondition = i18n("Unknown error.");
956 					break;
957 			}
958 
959 			errorText = i18n("Could not bind a resource: %1", errorCondition);
960 			break;
961 
962 		default:
963 			errorText = i18n("Unknown error.");
964 			break;
965 	}
966 
967 	/*
968 	 * This mustn't be queued as otherwise the reconnection
969 	 * API will attempt to reconnect, queueing another
970 	 * error until memory is exhausted.
971 	 */
972 	if(!errorText.isEmpty()) {
973 		if (!additionalErrMsg.isEmpty()) {
974 			KMessageBox::detailedError (0,
975 					errorText,
976 					additionalErrMsg,
977 					i18n("Connection problem with Jabber server %1", server));
978 		} else {
979 			KMessageBox::error (0,
980 					errorText,
981 					i18n("Connection problem with Jabber server %1", server));
982 		}
983 	}
984 
985 }
986 
slotCSError(int error)987 void JabberAccount::slotCSError ( int error )
988 {
989 	qCDebug(JABBER_PROTOCOL_LOG) << "Error in stream signalled.";
990 
991 	if ( ( error == XMPP::ClientStream::ErrAuth )
992 		&& ( client()->clientStream()->errorCondition () == XMPP::ClientStream::NotAuthorized ) )
993 	{
994 		qCDebug(JABBER_PROTOCOL_LOG) << "Incorrect password, retrying.";
995 		disconnect(/*Kopete::Account::BadPassword*/0);
996 	}
997 	else
998 	{
999 		int errorClass =  0;
1000 
1001 		qCDebug(JABBER_PROTOCOL_LOG) << "Disconnecting.";
1002 
1003 		// display message to user
1004 		if(!m_removing) //when removing the account, connection errors are normal.
1005 			handleStreamError (error, client()->clientStream()->errorCondition (), client()->clientConnector()->errorCode (), server (), errorClass, client()->clientStream()->errorText());
1006 
1007 		disconnect ( errorClass );
1008 
1009 		/*	slotCSDisconnected  will not be called*/
1010 		resourcePool()->clear();
1011 	}
1012 
1013 }
1014 
1015 /* Set presence (usually called by dialog widget). */
setPresence(const XMPP::Status & status)1016 void JabberAccount::setPresence ( const XMPP::Status &status )
1017 {
1018 	qCDebug(JABBER_PROTOCOL_LOG) << "Status: " << status.show () << ", Reason: " << status.status ();
1019 
1020 	// fetch input status
1021 	XMPP::Status newStatus = status;
1022 
1023 	// TODO: Check if Caps is enabled
1024 	// Send entity capabilities
1025 	if( client() )
1026 	{
1027 		newStatus.setCapsNode( client()->capsNode() );
1028 		newStatus.setCapsVersion( client()->capsVersion() );
1029 		newStatus.setCapsExt( client()->capsExt() );
1030 	}
1031 
1032 	// make sure the status gets the correct priority
1033 	newStatus.setPriority ( 5 );
1034 
1035 	XMPP::Jid jid ( this->contactId() );
1036 	XMPP::Resource newResource ( resource (), newStatus );
1037 
1038 	// update our resource in the resource pool
1039 	resourcePool()->addResource ( jid, newResource );
1040 
1041 	// make sure that we only consider our own resource locally
1042 	resourcePool()->lockToResource ( jid, newResource );
1043 
1044 	/*
1045 	 * Unless we are in the connecting status, send a presence packet to the server
1046 	 */
1047 	if(status.show () != QString("connecting") )
1048 	{
1049 		/*
1050 		 * Make sure we are actually connected before sending out a packet.
1051 		 */
1052 		if (isConnected())
1053 		{
1054 			qCDebug(JABBER_PROTOCOL_LOG) << "Sending new presence to the server.";
1055 
1056 			XMPP::JT_Presence * task = new XMPP::JT_Presence ( client()->rootTask ());
1057 
1058 			task->pres ( newStatus );
1059 			task->go ( true );
1060 		}
1061 		else
1062 		{
1063 			qCDebug(JABBER_PROTOCOL_LOG) << "We were not connected, presence update aborted.";
1064 		}
1065 	}
1066 
1067 }
1068 
slotXMPPConsole()1069 void JabberAccount::slotXMPPConsole ()
1070 {
1071 	/* Check if we're connected. */
1072 	if ( !isConnected () )
1073 	{
1074 		errorConnectFirst ();
1075 		return;
1076 	}
1077 
1078 /*	dlgXMPPConsole *w = new dlgXMPPConsole( client (), 0);
1079 	QObject::connect( m_jabberClient, SIGNAL (incomingXML(QString)),
1080 				   w, SLOT (slotIncomingXML(QString)) );
1081 	QObject::connect( m_jabberClient, SIGNAL (outgoingXML(QString)),
1082 				   w, SLOT (slotOutgoingXML(QString)) );
1083 	w->show();*/
1084 }
1085 
slotSubscription(const XMPP::Jid & jid,const QString & type)1086 void JabberAccount::slotSubscription (const XMPP::Jid & jid, const QString & type)
1087 {
1088 	qCDebug(JABBER_PROTOCOL_LOG) << jid.full () << ", " << type;
1089 
1090 	if (type == "subscribe")
1091 	{
1092 		/*
1093 		 * A user wants to subscribe to our presence.
1094 		 */
1095 		qCDebug(JABBER_PROTOCOL_LOG) << jid.full () << " is asking for authorization to subscribe.";
1096 
1097 		// Is the user already in our contact list?
1098 // 		JabberBaseContact *contact = contactPool()->findExactMatch( jid );
1099 // 		Kopete::MetaContact *metaContact=0L;
1100 // 		if(contact)
1101 // 			metaContact=contact->metaContact();
1102 
1103 // 		Kopete::AddedInfoEvent::ShowActionOptions actions = Kopete::AddedInfoEvent::AuthorizeAction;
1104 // 		actions |= Kopete::AddedInfoEvent::BlockAction;
1105 //
1106 // 		if( !metaContact || metaContact->isTemporary() )
1107 // 			actions |= Kopete::AddedInfoEvent::AddAction;
1108 
1109 /*		Kopete::AddedInfoEvent* event = new Kopete::AddedInfoEvent( jid.full(), this );
1110 		QObject::connect( event, SIGNAL(actionActivated(uint)),
1111 		                  this, SLOT(slotAddedInfoEventActionActivated(uint)) );
1112 
1113 		event->showActions( actions );
1114 		event->sendEvent();*/
1115 	}
1116 	else if (type == "unsubscribed")
1117 	{
1118 		/*
1119 		 * Someone else removed our authorization to see them.
1120 		 */
1121 		qCDebug(JABBER_PROTOCOL_LOG) << jid.full() << " revoked our presence authorization";
1122 
1123 		XMPP::JT_Roster *task;
1124 
1125 		switch (KMessageBox::warningYesNo (0,
1126 								  i18n
1127 								  ("The Jabber user %1 removed %2's subscription to him/her. "
1128 								   "This account will no longer be able to view his/her online/offline status. "
1129 								   "Do you want to delete the contact?",
1130 								    jid.full(), accountId()), i18n ("Notification"), KStandardGuiItem::del(), KGuiItem( i18n("Keep") )))
1131 		{
1132 
1133 			case KMessageBox::Yes:
1134 				/*
1135 				 * Delete this contact from our roster.
1136 				 */
1137 				task = new XMPP::JT_Roster ( client()->rootTask ());
1138 
1139 				task->remove (jid);
1140 				task->go (true);
1141 
1142 				break;
1143 
1144 			default:
1145 				/*
1146 				 * We want to leave the contact in our contact list.
1147 				 * In this case, we need to delete all the resources
1148 				 * we have for it, as the Jabber server won't signal us
1149 				 * that the contact is offline now.
1150 				 */
1151 				resourcePool()->removeAllResources ( jid );
1152 				break;
1153 
1154 		}
1155 	}
1156 }
1157 
slotAddedInfoEventActionActivated(uint actionId)1158 void JabberAccount::slotAddedInfoEventActionActivated ( uint actionId )
1159 {
1160 /*	const Kopete::AddedInfoEvent *event =
1161 		dynamic_cast<const Kopete::AddedInfoEvent *>(sender());
1162 
1163 	if ( !event || !isConnected() )
1164 		return;
1165 
1166 	XMPP::Jid jid(event->contactId());
1167 	if ( actionId == Kopete::AddedInfoEvent::AuthorizeAction )
1168 	{*/
1169 		/*
1170 		* Authorize user.
1171 		*/
1172 /*		XMPP::JT_Presence *task = new XMPP::JT_Presence ( client()->rootTask () );
1173 		task->sub ( jid, "subscribed" );
1174 		task->go ( true );
1175 	}
1176 	else if ( actionId == Kopete::AddedInfoEvent::BlockAction )
1177 	{*/
1178 		/*
1179 		* Reject subscription.
1180 		*/
1181 /*		XMPP::JT_Presence *task = new XMPP::JT_Presence ( client()->rootTask () );
1182 		task->sub ( jid, "unsubscribed" );
1183 		task->go ( true );
1184 	}
1185 	else if( actionId == Kopete::AddedInfoEvent::AddContactAction )
1186 	{
1187 		Kopete::MetaContact *parentContact=event->addContact();
1188 		if(parentContact)
1189 		{
1190 			QStringList groupNames;
1191 			Kopete::GroupList groupList = parentContact->groups();
1192 			foreach(Kopete::Group *group,groupList)
1193 				groupNames += group->displayName();
1194 
1195 			XMPP::RosterItem item;
1196 
1197 			item.setJid ( jid );
1198 			item.setName ( parentContact->displayName() );
1199 			item.setGroups ( groupNames );
1200 
1201 			// add the new contact to our roster.
1202 			XMPP::JT_Roster * rosterTask = new XMPP::JT_Roster ( client()->rootTask () );
1203 
1204 			rosterTask->set ( item.jid(), item.name(), item.groups() );
1205 			rosterTask->go ( true );
1206 
1207 			// send a subscription request.
1208 			XMPP::JT_Presence *presenceTask = new XMPP::JT_Presence ( client()->rootTask () );
1209 
1210 			presenceTask->sub ( jid, "subscribe" );
1211 			presenceTask->go ( true );
1212 		}
1213 	}*/
1214 }
1215 
1216 
1217 
slotContactUpdated(const XMPP::RosterItem & item)1218 void JabberAccount::slotContactUpdated (const XMPP::RosterItem & item)
1219 {
1220 
1221 	/**
1222 	 * Subscription types are: Both, From, To, Remove, None.
1223 	 * Both:   Both sides have authed each other, each side
1224 	 *         can see each other's presence
1225 	 * From:   The other side can see us.
1226 	 * To:     We can see the other side. (implies we are
1227 	 *         authed)
1228 	 * Remove: Other side revoked our subscription request.
1229 	 *         Not to be handled here.
1230 	 * None:   No subscription.
1231 	 *
1232 	 * Regardless of the subscription type, we have to add
1233 	 * a roster item here.
1234 	 */
1235 
1236 	qCDebug(JABBER_PROTOCOL_LOG) << "New roster item " << item.jid().full () << " (Subscription: " << item.subscription().toString () << ")";
1237 
1238 	/*
1239 	 * See if the contact need to be added, according to the criterias of
1240 	 *  JEP-0162: Best Practices for Roster and Subscription Management
1241 	 * http://www.jabber.org/jeps/jep-0162.html#contacts
1242 	 */
1243 	bool need_to_add=false;
1244 	if(item.subscription().type() == XMPP::Subscription::Both || item.subscription().type() == XMPP::Subscription::To)
1245 		need_to_add = true;
1246 	else if( !item.ask().isEmpty() )
1247 		need_to_add = true;
1248 	else if( !item.name().isEmpty() || !item.groups().isEmpty() )
1249 		need_to_add = true;
1250 
1251 	/*
1252 	 * See if the contact is already on our contact list
1253 	 */
1254 	JabberBaseContact *c= contactPool()->findExactMatch( item.jid() );
1255 
1256 // 	if( c && c == c->Kopete::Contact::account()->myself() )  //don't use JabberBaseContact::account() which return alwaus the JabberAccount, and not the transport
1257 // 	{
1258 // 		// don't let remove the gateway contact, eh!
1259 // 		need_to_add = true;
1260 // 	}
1261 
1262 /*	if(need_to_add)
1263 	{
1264 		Kopete::MetaContact *metaContact=0L;
1265 		if (!c)
1266 		{*/
1267 			/*
1268 			* No metacontact has been found which contains a contact with this ID,
1269 			* so add a new metacontact to the list.
1270 			*/
1271 // 			metaContact = new Kopete::MetaContact ();
1272 // 			QStringList groups = item.groups ();
1273 //
1274 // 			// add this metacontact to all groups the contact is a member of
1275 // 			for (QStringList::Iterator it = groups.begin (); it != groups.end (); ++it)
1276 // 				metaContact->addToGroup (Kopete::ContactList::self ()->findGroup (*it));
1277 //
1278 // 			// put it onto contact list
1279 // 			Kopete::ContactList::self ()->addMetaContact ( metaContact );
1280 // 		}
1281 // 		else
1282 // 		{
1283 // 			metaContact=c->metaContact();
1284 // 			//TODO: synchronize groups
1285 // 		}
1286 
1287 		/*
1288 		* Add / update the contact in our pool. In case the contact is already there,
1289 		* it will be updated. In case the contact is not in the meta contact yet, it
1290 		* will be added to it.
1291 		* The "dirty" flag is false here, because we just received the contact from
1292 		* the server's roster. As such, it is now a synchronized entry.
1293 		*/
1294 		JabberBaseContact *contact = contactPool()->addContact ( item, false );
1295 
1296 		/*
1297 		* Set authorization property
1298 		*/
1299 		if ( !item.ask().isEmpty () )
1300 		{
1301 // 			contact->setProperty ( protocol()->propAuthorizationStatus, i18n ( "Waiting for authorization" ) );
1302 		}
1303 		else
1304 		{
1305 // 			contact->removeProperty ( protocol()->propAuthorizationStatus );
1306 		}
1307 // 	}
1308 	/*else*/ if(c)  //we don't need to add it, and it is in the contact list
1309 	{
1310 /*		Kopete::MetaContact *metaContact=c->metaContact();
1311 		if(metaContact->isTemporary())
1312 			return;
1313 		qCDebug(JABBER_PROTOCOL_LOG) << c->contactId() <<
1314 				" is on the contact list while it shouldn't.  we are removing it.  - " << c ;
1315 		delete c;
1316 		if(metaContact->contacts().isEmpty())
1317 			Kopete::ContactList::self()->removeMetaContact( metaContact );*/
1318 	}
1319 
1320 }
1321 
slotContactDeleted(const XMPP::RosterItem & item)1322 void JabberAccount::slotContactDeleted (const XMPP::RosterItem & item)
1323 {
1324 	qCDebug(JABBER_PROTOCOL_LOG) << "Deleting contact " << item.jid().full ();
1325 
1326 	// since the contact instance will get deleted here, the GUI should be updated
1327 	contactPool()->removeContact ( item.jid () );
1328 
1329 }
1330 
slotReceivedMessage(const XMPP::Message & message)1331 void JabberAccount::slotReceivedMessage (const XMPP::Message & message)
1332 {
1333 	qCDebug(JABBER_PROTOCOL_LOG) << "New message from " << message.from().full ();
1334 
1335 	JabberBaseContact *contactFrom;
1336 
1337 	if ( message.type() == "groupchat" )
1338 	{
1339 		// this is a groupchat message, forward it to the group contact
1340 		// (the one without resource name)
1341 		XMPP::Jid jid ( message.from().userHost () );
1342 
1343 		// try to locate an exact match in our pool first
1344 		contactFrom = contactPool()->findExactMatch ( jid );
1345 
1346 		/**
1347 		 * If there was no exact match, something is really messed up.
1348 		 * We can't receive groupchat messages from rooms that we are
1349 		 * not a member of and if the room contact vanished somehow,
1350 		 * we're in deep trouble.
1351 		 */
1352 		if ( !contactFrom )
1353 		{
1354 			qCDebug(JABBER_PROTOCOL_LOG) << "WARNING: Received a groupchat message but couldn't find room contact. Ignoring message.";
1355 			return;
1356 		}
1357 	}
1358 	else
1359 	{
1360 		// try to locate an exact match in our pool first
1361 		contactFrom = contactPool()->findExactMatch ( message.from () );
1362 
1363 		if ( !contactFrom )
1364 		{
1365 			// we have no exact match, try a broader search
1366 			contactFrom = contactPool()->findRelevantRecipient ( message.from () );
1367 		}
1368 
1369 		// see if we found the contact in our pool
1370 		if ( !contactFrom )
1371 		{
1372 			// eliminate the resource from this contact,
1373 			// otherwise we will add the contact with the
1374 			// resource to our list
1375 			// NOTE: This is a stupid way to do it, but
1376 			// message.from().setResource("") had no
1377 			// effect. Iris bug?
1378 			XMPP::Jid jid ( message.from().userHost () );
1379 
1380 			// the contact is not in our pool, add it as a temporary contact
1381 			qCDebug(JABBER_PROTOCOL_LOG) << jid.full () << " is unknown to us, creating temporary contact.";
1382 
1383 // 			Kopete::MetaContact *metaContact = new Kopete::MetaContact ();
1384 //
1385 // 			metaContact->setTemporary (true);
1386 
1387 			contactFrom = contactPool()->addContact ( XMPP::RosterItem ( jid ), false );
1388 
1389 // 			Kopete::ContactList::self ()->addMetaContact (metaContact);
1390 		}
1391 	}
1392 
1393 	// pass the message on to the contact
1394 	contactFrom->handleIncomingMessage (message);
1395 
1396 }
1397 
slotJoinNewChat()1398 void JabberAccount::slotJoinNewChat ()
1399 {
1400 
1401 	if (!isConnected ())
1402 	{
1403 		errorConnectFirst ();
1404 		return;
1405 	}
1406 
1407 // 	dlgJabberChatJoin *joinDialog = new dlgJabberChatJoin ( this, 0 );
1408 // 	joinDialog->show ();
1409 
1410 }
1411 
slotGroupChatJoined(const XMPP::Jid & jid)1412 void JabberAccount::slotGroupChatJoined (const XMPP::Jid & jid)
1413 {
1414 	qCDebug(JABBER_PROTOCOL_LOG) << "Joined groupchat " << jid.full ();
1415 
1416 	// Create new meta contact that holds the groupchat contact.
1417 // 	Kopete::MetaContact *metaContact = new Kopete::MetaContact ();
1418 
1419 // 	metaContact->setTemporary ( true );
1420 
1421 	// Create a groupchat contact for this room
1422 	JabberGroupContact *groupContact = dynamic_cast<JabberGroupContact *>( contactPool()->addGroupContact ( XMPP::RosterItem ( jid ), true, false ) );
1423 
1424 	if(groupContact)
1425 	{
1426 		// Add the groupchat contact to the meta contact.
1427 		//metaContact->addContact ( groupContact );
1428 
1429 // 		Kopete::ContactList::self ()->addMetaContact ( metaContact );
1430 	}
1431 // 	else
1432 // 		delete metaContact;
1433 
1434 	/**
1435 	 * Add an initial resource for this contact to the pool. We need
1436 	 * to do this to be able to lock the group status to our own presence.
1437 	 * Our own presence will be updated right after this method returned
1438 	 * by slotGroupChatPresence(), since the server will signal our own
1439 	 * presence back to us.
1440 	 */
1441 	resourcePool()->addResource ( XMPP::Jid ( jid.userHost () ), XMPP::Resource ( jid.resource () ) );
1442 
1443 	// lock the room to our own status
1444 	resourcePool()->lockToResource ( XMPP::Jid ( jid.userHost () ), jid.resource () );
1445 
1446 // 	m_bookmarks->insertGroupChat(jid);
1447 }
1448 
slotGroupChatLeft(const XMPP::Jid & jid)1449 void JabberAccount::slotGroupChatLeft (const XMPP::Jid & jid)
1450 {
1451 	qCDebug(JABBER_PROTOCOL_LOG) << "Left groupchat " << jid.full ();
1452 
1453 	// remove group contact from list
1454 // 	Kopete::Contact *contact =
1455 // 			Kopete::ContactList::self()->findContact( protocol()->pluginId() , accountId() , jid.userHost() );
1456 //
1457 // 	if ( contact )
1458 // 	{
1459 // 		Kopete::MetaContact *metaContact= contact->metaContact();
1460 // 		if( metaContact && metaContact->isTemporary() )
1461 // 			Kopete::ContactList::self()->removeMetaContact ( metaContact );
1462 // 		else
1463 // 			contact->deleteLater();
1464 // 	}
1465 
1466 	// now remove it from our pool, which should clean up all subcontacts as well
1467 	contactPool()->removeContact ( XMPP::Jid ( jid.userHost () ) );
1468 
1469 }
1470 
slotGroupChatPresence(const XMPP::Jid & jid,const XMPP::Status & status)1471 void JabberAccount::slotGroupChatPresence (const XMPP::Jid & jid, const XMPP::Status & status)
1472 {
1473 	qCDebug(JABBER_PROTOCOL_LOG) << "Received groupchat presence for room " << jid.full ();
1474 
1475 	// fetch room contact (the one without resource)
1476 	JabberGroupContact *groupContact = dynamic_cast<JabberGroupContact *>( contactPool()->findExactMatch ( XMPP::Jid ( jid.userHost () ) ) );
1477 
1478 	if ( !groupContact )
1479 	{
1480 		qCDebug(JABBER_PROTOCOL_LOG) << "WARNING: Groupchat presence signalled, but we don't have a room contact?";
1481 		return;
1482 	}
1483 
1484 	if ( !status.isAvailable () )
1485 	{
1486 		qCDebug(JABBER_PROTOCOL_LOG) << jid.full () << " has become unavailable, removing from room";
1487 
1488 		// remove the resource from the pool
1489 		resourcePool()->removeResource ( jid, XMPP::Resource ( jid.resource (), status ) );
1490 
1491 		// the person has become unavailable, remove it
1492 		groupContact->removeSubContact ( XMPP::RosterItem ( jid ) );
1493 	}
1494 	else
1495 	{
1496 		// add a resource for this contact to the pool (existing resources will be updated)
1497 		resourcePool()->addResource ( jid, XMPP::Resource ( jid.resource (), status ) );
1498 
1499 		// make sure the contact exists in the room (if it exists already, it won't be added twice)
1500 		groupContact->addSubContact ( XMPP::RosterItem ( jid ) );
1501 	}
1502 
1503 }
1504 
slotGroupChatError(const XMPP::Jid & jid,int error,const QString & reason)1505 void JabberAccount::slotGroupChatError (const XMPP::Jid &jid, int error, const QString &reason)
1506 {
1507 	qCDebug(JABBER_PROTOCOL_LOG) << "Group chat error - room " << jid.full () << " had error " << error << " (" << reason << ")";
1508 
1509 	switch (error)
1510 	{
1511 	case JabberClient::InvalidPasswordForMUC:
1512 		{
1513 			KPasswordDialog dlg(0);
1514             dlg.setPrompt(i18n("A password is required to join the room %1.", jid.node()));
1515 			if (dlg.exec() == KPasswordDialog::Accepted)
1516 				m_jabberClient->joinGroupChat(jid.domain(), jid.node(), jid.resource(), dlg.password());
1517 		}
1518 		break;
1519 
1520 	case JabberClient::NicknameConflict:
1521 		{
1522 			bool ok;
1523 			QString nickname = KInputDialog::getText(i18n("Error trying to join %1: nickname %2 is already in use", jid.node(), jid.resource()),
1524 									i18n("Provide your nickname"),
1525 									QString(),
1526 									&ok);
1527 			if (ok)
1528 			{
1529 				m_jabberClient->joinGroupChat(jid.domain(), jid.node(), nickname);
1530 			}
1531 		}
1532 		break;
1533 
1534 	case JabberClient::BannedFromThisMUC:
1535 		KMessageBox::queuedMessageBox ( 0,
1536 									KMessageBox::Error,
1537 									i18n ("You cannot join the room %1 because you have been banned", jid.node()),
1538 									i18n ("Jabber Group Chat") );
1539 		break;
1540 
1541 	case JabberClient::MaxUsersReachedForThisMuc:
1542 		KMessageBox::queuedMessageBox ( 0,
1543 									KMessageBox::Error,
1544 									i18n ("You cannot join the room %1 because the maximum number of users has been reached", jid.node()),
1545 									i18n ("Jabber Group Chat") );
1546 		break;
1547 
1548 	default:
1549 		{
1550 		QString detailedReason = reason.isEmpty () ? i18n ( "No reason given by the server" ) : reason;
1551 
1552 		KMessageBox::queuedMessageBox ( 0,
1553 									KMessageBox::Error,
1554 									i18n ("There was an error processing your request for groupchat %1. (Reason: %2, Code %3)", jid.full (), detailedReason, error ),
1555 									i18n ("Jabber Group Chat") );
1556 		}
1557 	}
1558 }
1559 
slotResourceAvailable(const XMPP::Jid & jid,const XMPP::Resource & resource)1560 void JabberAccount::slotResourceAvailable (const XMPP::Jid & jid, const XMPP::Resource & resource)
1561 {
1562 
1563 	qCDebug(JABBER_PROTOCOL_LOG) << "New resource available for " << jid.full();
1564 
1565 	resourcePool()->addResource ( jid, resource );
1566 
1567 }
1568 
slotResourceUnavailable(const XMPP::Jid & jid,const XMPP::Resource & resource)1569 void JabberAccount::slotResourceUnavailable (const XMPP::Jid & jid, const XMPP::Resource & resource)
1570 {
1571 
1572 	qCDebug(JABBER_PROTOCOL_LOG) << "Resource now unavailable for " << jid.full ();
1573 
1574 	resourcePool()->removeResource ( jid, resource );
1575 
1576 }
1577 
slotEditVCard()1578 void JabberAccount::slotEditVCard ()
1579 {
1580 // 	static_cast<JabberContact *>( myself() )->slotUserInfo ();
1581 }
1582 
resource() const1583 const QString JabberAccount::resource () const
1584 {
1585 
1586 	return "KsirK";
1587 
1588 }
1589 
server() const1590 const QString JabberAccount::server () const
1591 {
1592 
1593 	return "localhost";
1594 
1595 }
1596 
port() const1597 const int JabberAccount::port () const
1598 {
1599 
1600 	return 5222;
1601 
1602 }
1603 
slotGetServices()1604 void JabberAccount::slotGetServices ()
1605 {
1606 /*	dlgJabberServices *dialog = new dlgJabberServices (this);
1607 
1608 	dialog->show ();
1609 	dialog->raise ();*/
1610 }
1611 
1612 // void JabberAccount::slotIncomingVoiceCall( const Jid &jid )
1613 // {
1614 // 	qCDebug(JABBER_PROTOCOL_LOG) ;
1615 // #ifdef SUPPORT_JINGLE
1616 // 	if(voiceCaller())
1617 // 	{
1618 // 		qCDebug(JABBER_PROTOCOL_LOG) << "Showing voice dialog.";
1619 // 		JingleVoiceSessionDialog *voiceDialog = new JingleVoiceSessionDialog( jid, voiceCaller() );
1620 // 		voiceDialog->show();
1621 // 	}
1622 // #else
1623 // 	Q_UNUSED(jid);
1624 // #endif
1625 // }
1626 
1627 // void JabberAccount::slotIncomingJingleSession( const QString &sessionType, JingleSession *session )
1628 // {
1629 // #ifdef SUPPORT_JINGLE
1630 // 	if(sessionType == "http://www.google.com/session/phone")
1631 // 	{
1632 // 		QString from = ((XMPP::Jid)session->peers().first()).full();
1633 // 		//KMessageBox::queuedMessageBox( 0, KMessageBox::Information, QString("Received a voice session invitation from %1.").arg(from) );
1634 // 		JingleVoiceSessionDialog *voiceDialog = new JingleVoiceSessionDialog( static_cast<JingleVoiceSession*>(session) );
1635 // 		voiceDialog->show();
1636 // 	}
1637 // #else
1638 // 	Q_UNUSED( sessionType );
1639 // 	Q_UNUSED( session );
1640 // #endif
1641 // }
1642 
1643 
1644 // void JabberAccount::addTransport( JabberTransport * tr, const QString &jid )
1645 // {
1646 // 	m_transports.insert(jid,tr);
1647 // }
1648 //
1649 // void JabberAccount::removeTransport( const QString &jid )
1650 // {
1651 // 	m_transports.remove(jid);
1652 // }
1653 
1654 // bool JabberAccount::removeAccount( )
1655 // {
1656 // 	if(!m_removing)
1657 // 	{
1658 // 		int result=KMessageBox::warningYesNoCancel( 0 ,
1659 // 				   i18n( "Do you want to also unregister \"%1\" from the Jabber server ?\n"
1660 // 				   			    "If you unregister, your whole contact list may be removed from the server,"
1661 // 							    " and you will never be able to connect to this account with any client", accountLabel() ),
1662 // 					i18n("Unregister"),
1663 // 					KGuiItem(i18n( "Remove and Unregister" ), "edit-delete"),
1664 // 					KGuiItem(i18n( "Remove only from Kopete"), "user-trash"),KStandardGuiItem::cancel(),
1665 // 					QString(), KMessageBox::Notify | KMessageBox::Dangerous );
1666 // 		if(result == KMessageBox::Cancel)
1667 // 		{
1668 // 			return false;
1669 // 		}
1670 // 		else if(result == KMessageBox::Yes)
1671 // 		{
1672 // 			if (!isConnected())
1673 // 			{
1674 // 				errorConnectFirst ();
1675 // 				return false;
1676 // 			}
1677 //
1678 // 			XMPP::JT_Register *task = new XMPP::JT_Register ( client()->rootTask () );
1679 // 			QObject::connect ( task, SIGNAL (finished()), this, SLOT (slotUnregisterFinished) );
1680 // 			task->unreg ();
1681 // 			task->go ( true );
1682 // 			m_removing=true;
1683 // 			// from my experiment, not all server reply us with a response.   it simply dosconnect
1684 // 			// so after one seconde, we will force to remove the account
1685 // 			QTimer::singleShot(1111, this, SLOT(slotUnregisterFinished()));
1686 //
1687 // 			return false; //the account will be removed when the task will be finished
1688 // 		}
1689 // 	}
1690 //
1691 // 	//remove transports from config file.
1692 // /*	QMap<QString,JabberTransport*> tranposrts_copy=m_transports;
1693 // 	QMap<QString,JabberTransport*>::Iterator it;
1694 // 	for ( it = tranposrts_copy.begin(); it != tranposrts_copy.end(); ++it )
1695 // 	{
1696 // 		(*it)->jabberAccountRemoved();
1697 // 	}*/
1698 // 	return true;
1699 // }
1700 
slotUnregisterFinished()1701 void JabberAccount::slotUnregisterFinished( )
1702 {
1703 	const XMPP::JT_Register * task = dynamic_cast<const XMPP::JT_Register *>(sender ());
1704 
1705 	if ( task && ! task->success ())
1706 	{
1707 		KMessageBox::queuedMessageBox ( 0L, KMessageBox::Error,
1708 			i18n ("An error occurred while trying to remove the account:\n%1", task->statusString()),
1709 			i18n ("Jabber Account Unregistration"));
1710 		m_removing=false;
1711 		return;
1712 	}
1713 // 	if(m_removing)  //it may be because this is now the timer.
1714 // 		Kopete::AccountManager::self()->removeAccount( this ); //this will delete this
1715 }
1716 
1717 
1718 
1719 // vim: set noet ts=4 sts=4 sw=4:
1720