File indexing completed on 2024-04-14 04:01:43
0001 0002 /*************************************************************************** 0003 jabberaccount.cpp - core Jabber account class 0004 ------------------- 0005 begin : Sat M??? 8 2003 0006 copyright : (C) 2003 by Till Gerken <till@tantalo.net> 0007 Based on JabberProtocol by Daniel Stone <dstone@kde.org> 0008 and Till Gerken <till@tantalo.net>. 0009 copyright : (C) 2006 by Olivier Goffart <ogoffart at kde.org> 0010 Copyright 2006 by Tommi Rantala <tommi.rantala@cs.helsinki.fi> 0011 0012 Kopete (C) 2001-2006 Kopete developers 0013 <kopete-devel@kde.org>. 0014 ***************************************************************************/ 0015 0016 /*************************************************************************** 0017 * * 0018 * This program is free software; you can redistribute it and/or modify * 0019 * it under the terms of the GNU General Public License as published by * 0020 * the Free Software Foundation; either either version 2 0021 of the License, or (at your option) any later version.of the License, or * 0022 * (at your option) any later version. * 0023 * * 0024 ***************************************************************************/ 0025 0026 #include "im.h" 0027 #include "filetransfer.h" 0028 #include "xmpp.h" 0029 #include "xmpp_tasks.h" 0030 #include "qca.h" 0031 #include "bsocket.h" 0032 0033 #include "jabberaccount.h" 0034 #include "jabberbookmarks.h" 0035 0036 #include <time.h> 0037 0038 #include <QString> 0039 #include <QRegExp> 0040 #include <QTimer> 0041 0042 #include <KComponentData> 0043 #include <KConfig> 0044 #include <KMessageBox> 0045 #include <KLocalizedString> 0046 #include <KAboutData> 0047 #include <k3socketbase.h> 0048 #include <KPasswordDialog> 0049 #include <KInputDialog> 0050 #include <KActionMenu> 0051 #include <KComponentData> 0052 0053 #include "jabberconnector.h" 0054 #include "jabberresourcepool.h" 0055 #include "jabbercontactpool.h" 0056 // #include "jabberfiletransfer.h" 0057 #include "jabbercontact.h" 0058 #include "jabbergroupcontact.h" 0059 #include "jabbercapabilitiesmanager.h" 0060 // #include "jabbertransport.h" 0061 /*#include "dlgxmppconsole.h" 0062 #include "dlgjabberservices.h" 0063 #include "dlgjabberchatjoin.h"*/ 0064 #include "jt_pubsub.h" 0065 0066 #include <sys/utsname.h> 0067 0068 #ifdef SUPPORT_JINGLE 0069 #include "voicecaller.h" 0070 #include "jinglevoicecaller.h" 0071 0072 // NOTE: Disabled for 0.12, will develop them futher in KDE4 0073 // #include "jinglesessionmanager.h" 0074 // #include "jinglesession.h" 0075 // #include "jinglevoicesession.h" 0076 #include "jinglevoicesessiondialog.h" 0077 #endif 0078 0079 #define KOPETE_CAPS_NODE "http://kopete.kde.org/jabber/caps" 0080 0081 0082 0083 JabberAccount::JabberAccount (JabberProtocol * parent, const QString & accountId) 0084 :JabberProtocol( parent/*, accountId, false */) 0085 { 0086 qCDebug(JABBER_PROTOCOL_LOG) << "Instantiating new account " << accountId; 0087 0088 m_protocol = parent; 0089 0090 m_jabberClient = 0L; 0091 0092 m_resourcePool = 0L; 0093 m_contactPool = 0L; 0094 #ifdef SUPPORT_JINGLE 0095 m_voiceCaller = 0L; 0096 //m_jingleSessionManager = 0L; // NOTE: Disabled for 0.12 0097 #endif 0098 // m_bookmarks = new JabberBookmarks(this); 0099 m_removing=false; 0100 m_notifiedUserCannotBindTransferPort = false; 0101 // add our own contact to the pool 0102 // JabberContact *myContact = contactPool()->addContact ( XMPP::RosterItem ( accountId ), Kopete::ContactList::self()->myself(), false ); 0103 // setMyself( myContact ); 0104 0105 m_initialPresence = XMPP::Status ( "", "", 5, true ); 0106 0107 } 0108 0109 JabberAccount::~JabberAccount () 0110 { 0111 disconnect ( 0/*Kopete::Account::Manual*/ ); 0112 0113 // Remove this account from Capabilities manager. 0114 protocol()->capabilitiesManager()->removeAccount( this ); 0115 0116 cleanup (); 0117 0118 // QMap<QString,JabberTransport*> tranposrts_copy=m_transports; 0119 // QMap<QString,JabberTransport*>::Iterator it; 0120 // for ( it = tranposrts_copy.begin(); it != tranposrts_copy.end(); ++it ) 0121 // delete it.value(); 0122 } 0123 0124 void JabberAccount::cleanup () 0125 { 0126 0127 delete m_jabberClient; 0128 0129 m_jabberClient = 0L; 0130 0131 delete m_resourcePool; 0132 m_resourcePool = 0L; 0133 0134 delete m_contactPool; 0135 m_contactPool = 0L; 0136 0137 #ifdef SUPPORT_JINGLE 0138 delete m_voiceCaller; 0139 m_voiceCaller = 0L; 0140 0141 // delete m_jingleSessionManager; 0142 // m_jingleSessionManager = 0L; 0143 #endif 0144 } 0145 0146 // void JabberAccount::setS5BServerPort ( int port ) 0147 // { 0148 // 0149 // if ( !m_jabberClient ) 0150 // { 0151 // return; 0152 // } 0153 // 0154 // if ( !m_jabberClient->setS5BServerPort ( port ) && !m_notifiedUserCannotBindTransferPort) 0155 // { 0156 // KMessageBox::queuedMessageBox ( 0, KMessageBox::Sorry, 0157 // 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." ), 0158 // i18n ( "Failed to start Jabber File Transfer Manager" ) ); 0159 // m_notifiedUserCannotBindTransferPort = true; 0160 // } 0161 // 0162 // } 0163 0164 JabberResourcePool *JabberAccount::resourcePool () 0165 { 0166 0167 if ( !m_resourcePool ) 0168 m_resourcePool = new JabberResourcePool ( this ); 0169 0170 return m_resourcePool; 0171 0172 } 0173 0174 JabberContactPool *JabberAccount::contactPool () 0175 { 0176 0177 if ( !m_contactPool ) 0178 m_contactPool = new JabberContactPool ( this ); 0179 0180 return m_contactPool; 0181 0182 } 0183 0184 // bool JabberAccount::createContact (const QString & contactId, Kopete::MetaContact * metaContact) 0185 // { 0186 // 0187 // // collect all group names 0188 // QStringList groupNames; 0189 // Kopete::GroupList groupList = metaContact->groups(); 0190 // foreach( Kopete::Group *group, groupList ) 0191 // groupNames += group->displayName(); 0192 // 0193 // XMPP::Jid jid ( contactId ); 0194 // XMPP::RosterItem item ( jid ); 0195 // item.setName ( metaContact->displayName () ); 0196 // item.setGroups ( groupNames ); 0197 // 0198 // // this contact will be created with the "dirty" flag set 0199 // // (it will get reset if the contact appears in the roster during connect) 0200 // JabberContact *contact = contactPool()->addContact ( item, metaContact, true ); 0201 // 0202 // return ( contact != 0 ); 0203 // 0204 // } 0205 0206 void JabberAccount::errorConnectFirst () 0207 { 0208 0209 KMessageBox::queuedMessageBox ( 0, 0210 KMessageBox::Error, 0211 i18n ("Please connect first."), i18n ("Jabber Error") ); 0212 0213 } 0214 0215 void JabberAccount::errorConnectionLost () 0216 { 0217 // disconnected(0 /*Kopete::Account::ConnectionReset */); 0218 } 0219 0220 bool JabberAccount::isConnecting () 0221 { 0222 return false; 0223 // XMPP::Jid jid ( contactId () ); 0224 // 0225 // // see if we are currently trying to connect 0226 // return resourcePool()->bestResource ( jid ).status().show () == QString("connecting"); 0227 0228 } 0229 0230 void JabberAccount::connectWithPassword ( const QString &password ) 0231 { 0232 qCDebug(JABBER_PROTOCOL_LOG) << "called"; 0233 0234 /* Cancel connection process if no password has been supplied. */ 0235 if ( password.isEmpty () ) 0236 { 0237 disconnect ( 0/*Kopete::Account::Manual*/ ); 0238 return; 0239 } 0240 0241 /* Don't do anything if we are already connected. */ 0242 if ( isConnected () ) 0243 return; 0244 0245 // instantiate new client backend or clean up old one 0246 if ( !m_jabberClient ) 0247 { 0248 m_jabberClient = new JabberClient; 0249 0250 QObject::connect ( m_jabberClient, SIGNAL (csDisconnected()), this, SLOT (slotCSDisconnected()) ); 0251 QObject::connect ( m_jabberClient, SIGNAL (csError(int)), this, SLOT (slotCSError(int)) ); 0252 QObject::connect ( m_jabberClient, SIGNAL (tlsWarning(QCA::TLS::IdentityResult,QCA::Validity)), this, SLOT (slotHandleTLSWarning(QCA::TLS::IdentityResult,QCA::Validity)) ); 0253 QObject::connect ( m_jabberClient, SIGNAL (connected()), this, SLOT (slotConnected()) ); 0254 QObject::connect ( m_jabberClient, SIGNAL (error(JabberClient::ErrorCode)), this, SLOT (slotClientError(JabberClient::ErrorCode)) ); 0255 0256 QObject::connect ( m_jabberClient, SIGNAL (subscription(XMPP::Jid,QString)), 0257 this, SLOT (slotSubscription(XMPP::Jid,QString)) ); 0258 QObject::connect ( m_jabberClient, SIGNAL (rosterRequestFinished(bool)), 0259 this, SLOT (slotRosterRequestFinished(bool)) ); 0260 QObject::connect ( m_jabberClient, SIGNAL (newContact(XMPP::RosterItem)), 0261 this, SLOT (slotContactUpdated(XMPP::RosterItem)) ); 0262 QObject::connect ( m_jabberClient, SIGNAL (contactUpdated(XMPP::RosterItem)), 0263 this, SLOT (slotContactUpdated(XMPP::RosterItem)) ); 0264 QObject::connect ( m_jabberClient, SIGNAL (contactDeleted(XMPP::RosterItem)), 0265 this, SLOT (slotContactDeleted(XMPP::RosterItem)) ); 0266 QObject::connect ( m_jabberClient, SIGNAL (resourceAvailable(XMPP::Jid,XMPP::Resource)), 0267 this, SLOT (slotResourceAvailable(XMPP::Jid,XMPP::Resource)) ); 0268 QObject::connect ( m_jabberClient, SIGNAL (resourceUnavailable(XMPP::Jid,XMPP::Resource)), 0269 this, SLOT (slotResourceUnavailable(XMPP::Jid,XMPP::Resource)) ); 0270 QObject::connect ( m_jabberClient, SIGNAL (messageReceived(XMPP::Message)), 0271 this, SLOT (slotReceivedMessage(XMPP::Message)) ); 0272 QObject::connect ( m_jabberClient, SIGNAL (incomingFileTransfer()), 0273 this, SLOT (slotIncomingFileTransfer()) ); 0274 QObject::connect ( m_jabberClient, SIGNAL (groupChatJoined(XMPP::Jid)), 0275 this, SLOT (slotGroupChatJoined(XMPP::Jid)) ); 0276 QObject::connect ( m_jabberClient, SIGNAL (groupChatLeft(XMPP::Jid)), 0277 this, SLOT (slotGroupChatLeft(XMPP::Jid)) ); 0278 QObject::connect ( m_jabberClient, SIGNAL (groupChatPresence(XMPP::Jid,XMPP::Status)), 0279 this, SLOT (slotGroupChatPresence(XMPP::Jid,XMPP::Status)) ); 0280 QObject::connect ( m_jabberClient, SIGNAL (groupChatError(XMPP::Jid,int,QString)), 0281 this, SLOT (slotGroupChatError(XMPP::Jid,int,QString)) ); 0282 QObject::connect ( m_jabberClient, SIGNAL (debugMessage(QString)), 0283 this, SLOT (slotClientDebugMessage(QString)) ); 0284 } 0285 else 0286 { 0287 m_jabberClient->disconnect (); 0288 } 0289 0290 // we need to use the old protocol for now 0291 m_jabberClient->setUseXMPP09 ( true ); 0292 0293 // set SSL flag (this should be converted to forceTLS when using the new protocol) 0294 m_jabberClient->setUseSSL ( false ); 0295 0296 // override server and port (this should be dropped when using the new protocol and no direct SSL) 0297 m_jabberClient->setOverrideHost ( true, server (), port () ); 0298 0299 // allow plaintext password authentication or not? 0300 m_jabberClient->setAllowPlainTextPassword ( false ); 0301 0302 // enable file transfer (if empty, IP will be set after connection has been established) 0303 // KConfigGroup config = KSharedConfig::openConfig()->group ( "Jabber" ); 0304 // m_jabberClient->setFileTransfersEnabled ( true, config.readEntry ( "LocalIP" ) ); 0305 // setS5BServerPort ( config.readEntry ( "LocalPort", 8010 ) ); 0306 0307 // 0308 // Determine system name 0309 // 0310 struct utsname utsBuf; 0311 0312 uname (&utsBuf); 0313 0314 m_jabberClient->setClientName ("Kopete"); 0315 m_jabberClient->setClientVersion (KGlobal::mainComponent().aboutData()->version ()); 0316 m_jabberClient->setOSName (QString ("%1 %2").arg (utsBuf.sysname, 1).arg (utsBuf.release, 2)); 0317 0318 0319 // Set caps node information 0320 m_jabberClient->setCapsNode(KOPETE_CAPS_NODE); 0321 m_jabberClient->setCapsVersion(KGlobal::mainComponent().aboutData()->version()); 0322 0323 // Set Disco Identity information 0324 DiscoItem::Identity identity; 0325 identity.category = "client"; 0326 identity.type = "pc"; 0327 identity.name = "Kopete"; 0328 m_jabberClient->setDiscoIdentity(identity); 0329 0330 //BEGIN TIMEZONE INFORMATION 0331 // 0332 // Set timezone information (code from Psi) 0333 // Copyright (C) 2001-2003 Justin Karneges 0334 // 0335 time_t x; 0336 time(&x); 0337 char str[256]; 0338 char fmt[32]; 0339 int timezoneOffset(0); 0340 QString timezoneString; 0341 0342 strcpy ( fmt, "%z" ); 0343 strftime ( str, 256, fmt, localtime ( &x ) ); 0344 0345 if ( strcmp ( fmt, str ) ) 0346 { 0347 QString s = str; 0348 if ( s.at ( 0 ) == '+' ) 0349 s.remove ( 0, 1 ); 0350 s.truncate ( s.length () - 2 ); 0351 timezoneOffset = s.toInt(); 0352 } 0353 0354 strcpy ( fmt, "%Z" ); 0355 strftime ( str, 256, fmt, localtime ( &x ) ); 0356 0357 if ( strcmp ( fmt, str ) ) 0358 timezoneString = str; 0359 //END of timezone code 0360 0361 qCDebug(JABBER_PROTOCOL_LOG) << "Determined timezone " << timezoneString << " with UTC offset " << timezoneOffset << " hours."; 0362 0363 m_jabberClient->setTimeZone ( timezoneString, timezoneOffset ); 0364 0365 qCDebug(JABBER_PROTOCOL_LOG) << "Connecting to Jabber server " << server() << ":" << port(); 0366 0367 setPresence( XMPP::Status ("connecting", "", 0, true) ); 0368 0369 switch ( m_jabberClient->connect ( XMPP::Jid ( accountId () + QString("/") + resource () ), password ) ) 0370 { 0371 case JabberClient::NoTLS: 0372 // no SSL support, at the connecting stage this means the problem is client-side 0373 KMessageBox::queuedMessageBox(0, KMessageBox::Error, 0374 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.", 0375 accountId()), 0376 i18n ("Jabber SSL Error")); 0377 break; 0378 0379 case JabberClient::Ok: 0380 default: 0381 // everything alright! 0382 0383 break; 0384 } 0385 } 0386 0387 void JabberAccount::slotClientDebugMessage ( const QString &msg ) 0388 { 0389 0390 qCDebug(JABBER_PROTOCOL_LOG) << msg; 0391 0392 } 0393 0394 bool JabberAccount::handleTLSWarning ( 0395 JabberClient *jabberClient, 0396 QCA::TLS::IdentityResult identityResult, 0397 QCA::Validity validityResult ) 0398 { 0399 QString validityString, code, idString, idCode; 0400 0401 QString server = jabberClient->jid().domain (); 0402 QString accountId = jabberClient->jid().bare (); 0403 0404 switch ( identityResult ) 0405 { 0406 case QCA::TLS::Valid: 0407 break; 0408 case QCA::TLS::HostMismatch: 0409 idString = i18n("The host name does not match the one in the certificate."); 0410 idCode = "HostMismatch"; 0411 break; 0412 case QCA::TLS::InvalidCertificate: 0413 idString = i18n("The certificate is invalid."); 0414 idCode = "InvalidCert"; 0415 break; 0416 case QCA::TLS::NoCertificate: 0417 idString = i18n("No certificate was presented."); 0418 idCode = "NoCert"; 0419 break; 0420 } 0421 0422 switch ( validityResult ) 0423 { 0424 case QCA::ValidityGood: 0425 break; 0426 case QCA::ErrorRejected: 0427 validityString = i18n("The Certificate Authority rejected the certificate."); 0428 code = "Rejected"; 0429 break; 0430 case QCA::ErrorUntrusted: 0431 validityString = i18n("The certificate is not trusted."); 0432 code = "Untrusted"; 0433 break; 0434 case QCA::ErrorSignatureFailed: 0435 validityString = i18n("The signature is invalid."); 0436 code = "SignatureFailed"; 0437 break; 0438 case QCA::ErrorInvalidCA: 0439 validityString = i18n("The Certificate Authority is invalid."); 0440 code = "InvalidCA"; 0441 break; 0442 case QCA::ErrorInvalidPurpose: 0443 validityString = i18n("Invalid certificate purpose."); 0444 code = "InvalidPurpose"; 0445 break; 0446 case QCA::ErrorSelfSigned: 0447 validityString = i18n("The certificate is self-signed."); 0448 code = "SelfSigned"; 0449 break; 0450 case QCA::ErrorRevoked: 0451 validityString = i18n("The certificate has been revoked."); 0452 code = "Revoked"; 0453 break; 0454 case QCA::ErrorPathLengthExceeded: 0455 validityString = i18n("Maximum certificate chain length was exceeded."); 0456 code = "PathLengthExceeded"; 0457 break; 0458 case QCA::ErrorExpired: 0459 validityString = i18n("The certificate has expired."); 0460 code = "Expired"; 0461 break; 0462 case QCA::ErrorExpiredCA: 0463 validityString = i18n("The Certificate Authority has expired."); 0464 code = "ExpiredCA"; 0465 break; 0466 case QCA::ErrorValidityUnknown: 0467 validityString = i18n("Validity is unknown."); 0468 code = "ValidityUnknown"; 0469 break; 0470 } 0471 0472 QString message; 0473 0474 if (!idString.isEmpty()) 0475 { 0476 if (!validityString.isEmpty()) 0477 { 0478 message = i18n("<qt><p>The identity and the certificate of server %1 could not be " 0479 "validated for account %2:</p><p>%3</p><p>%4</p><p>Do you want to continue?</p></qt>", 0480 server, accountId, idString, validityString); 0481 } 0482 else 0483 { 0484 message = i18n("<qt><p>The certificate of server %1 could not be validated for " 0485 "account %2: %3</p><p>Do you want to continue?</p></qt>", 0486 server, accountId, idString); 0487 } 0488 } else { 0489 message = i18n("<qt><p>The certificate of server %1 could not be validated for " 0490 "account %2: %3</p><p>Do you want to continue?</p></qt>", 0491 server, accountId, validityString); 0492 } 0493 0494 return ( KMessageBox::warningContinueCancel ( 0, 0495 message, 0496 i18n("Jabber Connection Certificate Problem"), 0497 KStandardGuiItem::cont(),KStandardGuiItem::cancel(), 0498 QString("KopeteTLSWarning") + server + idCode + code) == KMessageBox::Continue ); 0499 0500 } 0501 0502 void JabberAccount::slotHandleTLSWarning ( 0503 QCA::TLS::IdentityResult identityResult, 0504 QCA::Validity validityResult ) 0505 { 0506 qCDebug(JABBER_PROTOCOL_LOG) << "Handling TLS warning..."; 0507 0508 if ( handleTLSWarning ( m_jabberClient, identityResult, validityResult ) ) 0509 { 0510 // resume stream 0511 m_jabberClient->continueAfterTLSWarning (); 0512 } 0513 else 0514 { 0515 // disconnect stream 0516 disconnect ( 0/*Kopete::Account::Manual*/ ); 0517 } 0518 0519 } 0520 0521 void JabberAccount::slotClientError ( JabberClient::ErrorCode errorCode ) 0522 { 0523 qCDebug(JABBER_PROTOCOL_LOG) << "Handling client error..."; 0524 0525 switch ( errorCode ) 0526 { 0527 case JabberClient::NoTLS: 0528 default: 0529 KMessageBox::queuedMessageBox ( 0, KMessageBox::Error, 0530 i18n ("An encrypted connection with the Jabber server could not be established."), 0531 i18n ("Jabber Connection Error")); 0532 disconnect ( 0/*Kopete::Account::Manual*/ ); 0533 break; 0534 } 0535 0536 } 0537 0538 void JabberAccount::slotConnected () 0539 { 0540 qCDebug(JABBER_PROTOCOL_LOG) << "Connected to Jabber server."; 0541 0542 #ifdef SUPPORT_JINGLE 0543 if(!m_voiceCaller) 0544 { 0545 qCDebug(JABBER_PROTOCOL_LOG) << "Creating Jingle Voice caller..."; 0546 m_voiceCaller = new JingleVoiceCaller( this ); 0547 QObject::connect(m_voiceCaller,SIGNAL(incoming(Jid)),this,SLOT(slotIncomingVoiceCall(Jid))); 0548 m_voiceCaller->initialize(); 0549 } 0550 0551 #if 0 0552 if(!m_jingleSessionManager) 0553 { 0554 qCDebug(JABBER_PROTOCOL_LOG) << "Creating Jingle Session Manager..."; 0555 m_jingleSessionManager = new JingleSessionManager( this ); 0556 QObject::connect(m_jingleSessionManager, SIGNAL(incomingSession(QString,JingleSession*)), this, SLOT(slotIncomingJingleSession(QString,JingleSession*))); 0557 } 0558 #endif 0559 0560 // Set caps extensions 0561 m_jabberClient->client()->addExtension("voice-v1", Features(QString("http://www.google.com/xmpp/protocol/voice/v1"))); 0562 #endif 0563 0564 qCDebug(JABBER_PROTOCOL_LOG) << "Requesting roster..."; 0565 m_jabberClient->requestRoster (); 0566 } 0567 0568 void JabberAccount::slotRosterRequestFinished ( bool success ) 0569 { 0570 0571 if ( success ) 0572 { 0573 // the roster was imported successfully, clear 0574 // all "dirty" items from the contact list 0575 contactPool()->cleanUp (); 0576 } 0577 0578 /* Since we are online now, set initial presence. Don't do this 0579 * before the roster request or we will receive presence 0580 * information before we have updated our roster with actual 0581 * contacts from the server! (Iris won't forward presence 0582 * information in that case either). */ 0583 qCDebug(JABBER_PROTOCOL_LOG) << "Setting initial presence..."; 0584 setPresence ( m_initialPresence ); 0585 0586 } 0587 0588 void JabberAccount::slotIncomingFileTransfer () 0589 { 0590 0591 // delegate the work to a file transfer object 0592 // new JabberFileTransfer ( this, client()->fileTransferManager()->takeIncoming () ); 0593 0594 } 0595 0596 void JabberAccount::setOnlineStatus( const JabberProtocol::OnlineStatus& status, const QString& reason ) 0597 { 0598 XMPP::Status xmppStatus = m_protocol->osToStatus( status, reason ); 0599 0600 if( status == JabberProtocol::JabberOffline ) 0601 { 0602 xmppStatus.setIsAvailable( false ); 0603 qCDebug(JABBER_PROTOCOL_LOG) << "CROSS YOUR FINGERS! THIS IS GONNA BE WILD"; 0604 disconnect (0/*Manual*/, xmppStatus); 0605 return; 0606 } 0607 0608 if( isConnecting () ) 0609 { 0610 return; 0611 } 0612 0613 0614 if ( !isConnected () ) 0615 { 0616 // we are not connected yet, so connect now 0617 m_initialPresence = xmppStatus; 0618 // connect ( status ); 0619 } 0620 else 0621 { 0622 setPresence ( xmppStatus ); 0623 } 0624 } 0625 0626 void JabberAccount::setStatusMessage( const QString& statusMessage ) 0627 { 0628 Q_UNUSED(statusMessage); 0629 } 0630 0631 void JabberAccount::disconnect ( int reason ) 0632 { 0633 qCDebug(JABBER_PROTOCOL_LOG) << "disconnect() called"; 0634 0635 if (isConnected ()) 0636 { 0637 qCDebug(JABBER_PROTOCOL_LOG) << "Still connected, closing connection..."; 0638 /* Tell backend class to disconnect. */ 0639 m_jabberClient->disconnect (); 0640 } 0641 0642 // make sure that the connection animation gets stopped if we're still 0643 // in the process of connecting 0644 setPresence ( XMPP::Status ("", "", 0, false) ); 0645 m_initialPresence = XMPP::Status ("", "", 5, true); 0646 0647 /* FIXME: 0648 * We should delete the JabberClient instance here, 0649 * but active timers in Iris prevent us from doing so. 0650 * (in a failed connection attempt, these timers will 0651 * try to access an already deleted object). 0652 * Instead, the instance will lurk until the next 0653 * connection attempt. 0654 */ 0655 qCDebug(JABBER_PROTOCOL_LOG) << "Disconnected."; 0656 0657 // disconnected ( reason ); 0658 } 0659 0660 void JabberAccount::disconnect( int reason, XMPP::Status &status ) 0661 { 0662 qCDebug(JABBER_PROTOCOL_LOG) << "disconnect( reason, status ) called"; 0663 0664 if (isConnected ()) 0665 { 0666 qCDebug(JABBER_PROTOCOL_LOG) << "Still connected, closing connection..."; 0667 /* Tell backend class to disconnect. */ 0668 m_jabberClient->disconnect (status); 0669 } 0670 0671 // make sure that the connection animation gets stopped if we're still 0672 // in the process of connecting 0673 setPresence ( status ); 0674 0675 /* FIXME: 0676 * We should delete the JabberClient instance here, 0677 * but active timers in Iris prevent us from doing so. 0678 * (in a failed connection attempt, these timers will 0679 * try to access an already deleted object). 0680 * Instead, the instance will lurk until the next 0681 * connection attempt. 0682 */ 0683 qCDebug(JABBER_PROTOCOL_LOG) << "Disconnected."; 0684 0685 // Kopete::Account::disconnected ( reason ); 0686 } 0687 0688 void JabberAccount::disconnect () 0689 { 0690 disconnect ( /*Manual*/0 ); 0691 } 0692 0693 void JabberAccount::slotConnect () 0694 { 0695 // connect (); 0696 } 0697 0698 void JabberAccount::slotDisconnect () 0699 { 0700 disconnect ( /*Kopete::Account::Manual*/ 0); 0701 } 0702 0703 void JabberAccount::slotCSDisconnected () 0704 { 0705 qCDebug(JABBER_PROTOCOL_LOG) << "Disconnected from Jabber server."; 0706 0707 /* 0708 * We should delete the JabberClient instance here, 0709 * but timers etc prevent us from doing so. Iris does 0710 * not like to be deleted from a slot. 0711 */ 0712 0713 /* It seems that we don't get offline notifications when going offline 0714 * with the protocol, so clear all resources manually. */ 0715 resourcePool()->clear(); 0716 0717 } 0718 0719 void JabberAccount::handleStreamError (int streamError, int streamCondition, int connectorCode, const QString &server, int &errorClass, QString additionalErrMsg) 0720 { 0721 QString errorText; 0722 QString errorCondition; 0723 0724 errorClass = 0/*Kopete::Account::InvalidHost*/; 0725 0726 /* 0727 * Display error to user. 0728 * FIXME: for unknown errors, maybe add error codes? 0729 */ 0730 switch(streamError) 0731 { 0732 case XMPP::Stream::ErrParse: 0733 errorClass = /*Kopete::Account::Unknown*/0; 0734 errorText = i18n("Malformed packet received."); 0735 break; 0736 0737 case XMPP::Stream::ErrProtocol: 0738 errorClass = /*Kopete::Account::Unknown*/0; 0739 errorText = i18n("There was an unrecoverable error in the protocol."); 0740 break; 0741 0742 case XMPP::Stream::ErrStream: 0743 switch(streamCondition) 0744 { 0745 case XMPP::Stream::GenericStreamError: 0746 errorCondition = i18n("Generic stream error."); 0747 break; 0748 case XMPP::Stream::Conflict: 0749 // FIXME: need a better error message here 0750 errorCondition = i18n("There was a conflict in the information received."); 0751 break; 0752 case XMPP::Stream::ConnectionTimeout: 0753 errorCondition = i18n("The stream timed out."); 0754 break; 0755 case XMPP::Stream::InternalServerError: 0756 errorCondition = i18n("Internal server error."); 0757 break; 0758 case XMPP::Stream::InvalidFrom: 0759 errorCondition = i18n("Stream packet received from an invalid address."); 0760 break; 0761 case XMPP::Stream::InvalidXml: 0762 errorCondition = i18n("Malformed stream packet received."); 0763 break; 0764 case XMPP::Stream::PolicyViolation: 0765 // FIXME: need a better error message here 0766 errorCondition = i18n("Policy violation in the protocol stream."); 0767 break; 0768 case XMPP::Stream::ResourceConstraint: 0769 // FIXME: need a better error message here 0770 errorCondition = i18n("Resource constraint."); 0771 break; 0772 case XMPP::Stream::SystemShutdown: 0773 // FIXME: need a better error message here 0774 errorCondition = i18n("System shutdown."); 0775 break; 0776 default: 0777 errorCondition = i18n("Unknown reason."); 0778 break; 0779 } 0780 0781 errorText = i18n("There was an error in the protocol stream: %1", errorCondition); 0782 break; 0783 0784 case XMPP::ClientStream::ErrConnection: 0785 switch(connectorCode) 0786 { 0787 case KNetwork::KSocketBase::LookupFailure: 0788 errorClass = /*Kopete::Account::InvalidHost*/0; 0789 errorCondition = i18n("Host not found."); 0790 break; 0791 case KNetwork::KSocketBase::AddressInUse: 0792 errorCondition = i18n("Address is already in use."); 0793 break; 0794 case KNetwork::KSocketBase::AlreadyCreated: 0795 errorCondition = i18n("Cannot recreate the socket."); 0796 break; 0797 case KNetwork::KSocketBase::AlreadyBound: 0798 errorCondition = i18n("Cannot bind the socket again."); 0799 break; 0800 case KNetwork::KSocketBase::AlreadyConnected: 0801 errorCondition = i18n("Socket is already connected."); 0802 break; 0803 case KNetwork::KSocketBase::NotConnected: 0804 errorCondition = i18n("Socket is not connected."); 0805 break; 0806 case KNetwork::KSocketBase::NotBound: 0807 errorCondition = i18n("Socket is not bound."); 0808 break; 0809 case KNetwork::KSocketBase::NotCreated: 0810 errorCondition = i18n("Socket has not been created."); 0811 break; 0812 case KNetwork::KSocketBase::WouldBlock: 0813 errorCondition = i18n("The socket operation would block. You should not see this error: please use \"Report Bug\" from the Help menu."); 0814 break; 0815 case KNetwork::KSocketBase::ConnectionRefused: 0816 errorCondition = i18n("Connection refused."); 0817 break; 0818 case KNetwork::KSocketBase::ConnectionTimedOut: 0819 errorCondition = i18n("Connection timed out."); 0820 break; 0821 case KNetwork::KSocketBase::InProgress: 0822 errorCondition = i18n("Connection attempt already in progress."); 0823 break; 0824 case KNetwork::KSocketBase::NetFailure: 0825 errorCondition = i18n("Network failure."); 0826 break; 0827 case KNetwork::KSocketBase::NotSupported: 0828 errorCondition = i18n("Operation is not supported."); 0829 break; 0830 case KNetwork::KSocketBase::Timeout: 0831 errorCondition = i18n("Socket timed out."); 0832 break; 0833 default: 0834 errorClass = /*Kopete::Account::ConnectionReset*/0; 0835 //errorCondition = i18n("Sorry, something unexpected happened that I do not know more about."); 0836 break; 0837 } 0838 if(!errorCondition.isEmpty()) 0839 errorText = i18n("There was a connection error: %1", errorCondition); 0840 break; 0841 0842 case XMPP::ClientStream::ErrNeg: 0843 switch(streamCondition) 0844 { 0845 case XMPP::ClientStream::HostUnknown: 0846 // FIXME: need a better error message here 0847 errorCondition = i18n("Unknown host."); 0848 break; 0849 case XMPP::ClientStream::RemoteConnectionFailed: 0850 // FIXME: need a better error message here 0851 errorCondition = i18n("Could not connect to a required remote resource."); 0852 break; 0853 case XMPP::ClientStream::SeeOtherHost: 0854 errorCondition = i18n("It appears we have been redirected to another server; I do not know how to handle this."); 0855 break; 0856 case XMPP::ClientStream::UnsupportedVersion: 0857 errorCondition = i18n("Unsupported protocol version."); 0858 break; 0859 default: 0860 errorCondition = i18n("Unknown error."); 0861 break; 0862 } 0863 0864 errorText = i18n("There was a negotiation error: %1", errorCondition); 0865 break; 0866 0867 case XMPP::ClientStream::ErrTLS: 0868 switch(streamCondition) 0869 { 0870 case XMPP::ClientStream::TLSStart: 0871 errorCondition = i18n("Server rejected our request to start the TLS handshake."); 0872 break; 0873 case XMPP::ClientStream::TLSFail: 0874 errorCondition = i18n("Failed to establish a secure connection."); 0875 break; 0876 default: 0877 errorCondition = i18n("Unknown error."); 0878 break; 0879 } 0880 0881 errorText = i18n("There was a Transport Layer Security (TLS) error: %1", errorCondition); 0882 break; 0883 0884 case XMPP::ClientStream::ErrAuth: 0885 switch(streamCondition) 0886 { 0887 case XMPP::ClientStream::GenericAuthError: 0888 errorCondition = i18n("Login failed with unknown reason."); 0889 break; 0890 case XMPP::ClientStream::NoMech: 0891 errorCondition = i18n("No appropriate authentication mechanism available."); 0892 break; 0893 case XMPP::ClientStream::BadProto: 0894 errorCondition = i18n("Bad SASL authentication protocol."); 0895 break; 0896 case XMPP::ClientStream::BadServ: 0897 errorCondition = i18n("Server failed mutual authentication."); 0898 break; 0899 case XMPP::ClientStream::EncryptionRequired: 0900 errorCondition = i18n("Encryption is required but not present."); 0901 break; 0902 case XMPP::ClientStream::InvalidAuthzid: 0903 errorCondition = i18n("Invalid user ID."); 0904 break; 0905 case XMPP::ClientStream::InvalidMech: 0906 errorCondition = i18n("Invalid mechanism."); 0907 break; 0908 case XMPP::ClientStream::InvalidRealm: 0909 errorCondition = i18n("Invalid realm."); 0910 break; 0911 case XMPP::ClientStream::MechTooWeak: 0912 errorCondition = i18n("Mechanism too weak."); 0913 break; 0914 case XMPP::ClientStream::NotAuthorized: 0915 errorCondition = i18n("Wrong credentials supplied. (check your user ID and password)"); 0916 break; 0917 case XMPP::ClientStream::TemporaryAuthFailure: 0918 errorCondition = i18n("Temporary failure, please try again later."); 0919 break; 0920 default: 0921 errorCondition = i18n("Unknown error."); 0922 break; 0923 } 0924 0925 errorText = i18n("There was an error authenticating with the server: %1", errorCondition); 0926 break; 0927 0928 case XMPP::ClientStream::ErrSecurityLayer: 0929 switch(streamCondition) 0930 { 0931 case XMPP::ClientStream::LayerTLS: 0932 errorCondition = i18n("Transport Layer Security (TLS) problem."); 0933 break; 0934 case XMPP::ClientStream::LayerSASL: 0935 errorCondition = i18n("Simple Authentication and Security Layer (SASL) problem."); 0936 break; 0937 default: 0938 errorCondition = i18n("Unknown error."); 0939 break; 0940 } 0941 0942 errorText = i18n("There was an error in the security layer: %1", errorCondition); 0943 break; 0944 0945 case XMPP::ClientStream::ErrBind: 0946 switch(streamCondition) 0947 { 0948 case XMPP::ClientStream::BindNotAllowed: 0949 errorCondition = i18n("No permission to bind the resource."); 0950 break; 0951 case XMPP::ClientStream::BindConflict: 0952 errorCondition = i18n("The resource is already in use."); 0953 break; 0954 default: 0955 errorCondition = i18n("Unknown error."); 0956 break; 0957 } 0958 0959 errorText = i18n("Could not bind a resource: %1", errorCondition); 0960 break; 0961 0962 default: 0963 errorText = i18n("Unknown error."); 0964 break; 0965 } 0966 0967 /* 0968 * This mustn't be queued as otherwise the reconnection 0969 * API will attempt to reconnect, queueing another 0970 * error until memory is exhausted. 0971 */ 0972 if(!errorText.isEmpty()) { 0973 if (!additionalErrMsg.isEmpty()) { 0974 KMessageBox::detailedError (0, 0975 errorText, 0976 additionalErrMsg, 0977 i18n("Connection problem with Jabber server %1", server)); 0978 } else { 0979 KMessageBox::error (0, 0980 errorText, 0981 i18n("Connection problem with Jabber server %1", server)); 0982 } 0983 } 0984 0985 } 0986 0987 void JabberAccount::slotCSError ( int error ) 0988 { 0989 qCDebug(JABBER_PROTOCOL_LOG) << "Error in stream signalled."; 0990 0991 if ( ( error == XMPP::ClientStream::ErrAuth ) 0992 && ( client()->clientStream()->errorCondition () == XMPP::ClientStream::NotAuthorized ) ) 0993 { 0994 qCDebug(JABBER_PROTOCOL_LOG) << "Incorrect password, retrying."; 0995 disconnect(/*Kopete::Account::BadPassword*/0); 0996 } 0997 else 0998 { 0999 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). */ 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 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 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::warningTwoActions (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::PrimaryAction: 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 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 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 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 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 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 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 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 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 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 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 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 1578 void JabberAccount::slotEditVCard () 1579 { 1580 // static_cast<JabberContact *>( myself() )->slotUserInfo (); 1581 } 1582 1583 const QString JabberAccount::resource () const 1584 { 1585 1586 return "KsirK"; 1587 1588 } 1589 1590 const QString JabberAccount::server () const 1591 { 1592 1593 return "localhost"; 1594 1595 } 1596 1597 const int JabberAccount::port () const 1598 { 1599 1600 return 5222; 1601 1602 } 1603 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 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 #include "moc_jabberaccount.cpp" 1718 1719 // vim: set noet ts=4 sts=4 sw=4: