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: