File indexing completed on 2024-04-21 04:04:42

0001  /*
0002   * jabbercontactpool.cpp
0003   *
0004   * Copyright (c) 2004 by Till Gerken <till@tantalo.net>
0005   * Copyright (c) 2006      by Olivier Goffart  <ogoffart at kde.org>
0006   *
0007   * Kopete    (c) by the Kopete developers  <kopete-devel@kde.org>
0008   *
0009   * *************************************************************************
0010   * *                                                                       *
0011   * * This program is free software; you can redistribute it and/or modify  *
0012   * * it under the terms of the GNU General Public License as published by  *
0013   * * the Free Software Foundation; either either version 2
0014    of the License, or (at your option) any later version.of the License, or     *
0015   * * (at your option) any later version.                                   *
0016   * *                                                                       *
0017   * *************************************************************************
0018   */
0019 
0020 #include "jabbercontactpool.h"
0021 #include "jabber_protocol_debug.h"
0022 
0023 #include <KMessageBox>
0024 #include <kopeteaccountmanager.h>
0025 #include <kopetecontactlist.h>
0026 #include "kopeteuiglobal.h"
0027 #include "kopetemetacontact.h"
0028 
0029 #include "jabberprotocol.h"
0030 #include "jabberbasecontact.h"
0031 #include "jabbercontact.h"
0032 #include "jabbergroupcontact.h"
0033 #include "jabbergroupmembercontact.h"
0034 #include "jabberresourcepool.h"
0035 #include "jabberaccount.h"
0036 #include "jabbertransport.h"
0037 
0038 JabberContactPool::JabberContactPool ( JabberAccount *account )
0039 {
0040 
0041     mAccount = account;
0042 
0043 }
0044 
0045 JabberContactPool::~JabberContactPool ()
0046 {
0047     qDeleteAll(mPool);
0048 }
0049 
0050 JabberContactPoolItem *JabberContactPool::findPoolItem ( const XMPP::RosterItem &contact )
0051 {
0052 
0053     // see if the contact already exists
0054     foreach(JabberContactPoolItem *mContactItem, mPool)
0055     {
0056         if ( mContactItem->contact()->rosterItem().jid().full().toLower() == contact.jid().full().toLower() )
0057         {
0058             return mContactItem;
0059         }
0060     }
0061 
0062     return 0;
0063 
0064 }
0065 
0066 JabberContact *JabberContactPool::addContact ( const XMPP::RosterItem &contact, Kopete::MetaContact *metaContact, bool dirty )
0067 {
0068     // see if the contact already exists
0069     JabberContactPoolItem *mContactItem = findPoolItem ( contact );
0070     if ( mContactItem)
0071     {
0072         qCDebug(JABBER_PROTOCOL_LOG) << "Updating existing contact " << contact.jid().full() << "   -  " <<   mContactItem->contact();
0073 
0074         // It exists, update it.
0075         mContactItem->contact()->updateContact ( contact );
0076         mContactItem->setDirty ( dirty );
0077 
0078         JabberContact *retval = dynamic_cast<JabberContact *>(mContactItem->contact ());
0079 
0080         if ( !retval )
0081         {
0082             KMessageBox::error ( Kopete::UI::Global::mainWidget (),
0083                                  "Fatal error in the Jabber contact pool. Please restart Kopete and submit a debug log "
0084                                  "of your session to http://bugs.kde.org.",
0085                                  "Fatal Jabber Error" );
0086         }
0087 
0088         return retval;
0089     }
0090 
0091     qCDebug(JABBER_PROTOCOL_LOG) << "Adding new contact " << contact.jid().full();
0092     
0093     JabberTransport *transport=0l;
0094     QString legacyId;
0095     //find if the contact should be added to a transport.
0096     if(mAccount->transports().contains(contact.jid().domain()))
0097     {
0098         transport=mAccount->transports()[contact.jid().domain()];
0099         legacyId=transport->legacyId( contact.jid() );
0100     }
0101         
0102     // create new contact instance and add it to the dictionary
0103     JabberContact *newContact = new JabberContact ( contact, transport ? (Kopete::Account*)transport : (Kopete::Account*)mAccount, metaContact , legacyId );
0104     JabberContactPoolItem *newContactItem = new JabberContactPoolItem ( newContact );
0105     connect ( newContact, SIGNAL (contactDestroyed(Kopete::Contact*)), this, SLOT (slotContactDestroyed(Kopete::Contact*)) );
0106     newContactItem->setDirty ( dirty );
0107     mPool.append ( newContactItem );
0108 
0109     return newContact;
0110 
0111 }
0112 
0113 JabberBaseContact *JabberContactPool::addGroupContact ( const XMPP::RosterItem &contact, bool roomContact, Kopete::MetaContact *metaContact, bool dirty )
0114 {
0115 
0116     XMPP::RosterItem mContact ( roomContact ? contact.jid().userHost () : contact.jid().full() );
0117 
0118     // see if the contact already exists
0119     JabberContactPoolItem *mContactItem = findPoolItem ( mContact );
0120     if ( mContactItem)
0121     {
0122         if(mContactItem->contact()->inherits(roomContact ?
0123                  (const char*)("JabberGroupContact") : (const char*)("JabberGroupMemberContact") ) )
0124         {
0125             
0126             qCDebug(JABBER_PROTOCOL_LOG) << "Updating existing contact " << mContact.jid().full();
0127             
0128             // It exists, update it.
0129             mContactItem->contact()->updateContact ( mContact );
0130             mContactItem->setDirty ( dirty );
0131     
0132             //we must tell to the originating function that no new contact has been added
0133             return 0L;//mContactItem->contact ();
0134         }
0135         else
0136         {
0137             //this happen if we receive a MUC invitaiton:  when the invitaiton is received, it's from the muc itself
0138             //and then kopete will create a temporary contact for it. but it will not be a good contact.
0139             qCDebug(JABBER_PROTOCOL_LOG) << "Bad contact will be removed and re-added " << mContact.jid().full();
0140             Kopete::MetaContact *old_mc=mContactItem->contact()->metaContact();
0141             delete mContactItem->contact();
0142             mContactItem = 0L;
0143             if(old_mc->contacts().isEmpty() && old_mc!=metaContact)
0144             {
0145                 Kopete::ContactList::self()->removeMetaContact( old_mc );
0146             }
0147             
0148         }
0149 
0150     }
0151 
0152     qCDebug(JABBER_PROTOCOL_LOG) << "Adding new contact " << mContact.jid().full();
0153 
0154     // create new contact instance and add it to the dictionary
0155     JabberBaseContact *newContact;
0156 
0157     if ( roomContact )
0158         newContact = new JabberGroupContact ( contact, mAccount, metaContact );
0159     else
0160         newContact = new JabberGroupMemberContact ( contact, mAccount, metaContact );
0161 
0162     JabberContactPoolItem *newContactItem = new JabberContactPoolItem ( newContact );
0163 
0164     connect ( newContact, SIGNAL (contactDestroyed(Kopete::Contact*)), this, SLOT (slotContactDestroyed(Kopete::Contact*)) );
0165 
0166     newContactItem->setDirty ( dirty );
0167     mPool.append ( newContactItem );
0168 
0169     return newContact;
0170 
0171 }
0172 
0173 void JabberContactPool::removeContact ( const XMPP::Jid &jid )
0174 {
0175     qCDebug(JABBER_PROTOCOL_LOG) << "Removing contact " << jid.full();
0176 
0177     foreach(JabberContactPoolItem *mContactItem, mPool)
0178     {
0179         if ( mContactItem->contact()->rosterItem().jid().full().toLower() == jid.full().toLower() )
0180         {
0181             /*
0182              * The following deletion will cause slotContactDestroyed()
0183              * to be called, which will clean the up the list.
0184              */
0185             if(mContactItem->contact())
0186             {
0187                 Kopete::MetaContact *mc=mContactItem->contact()->metaContact();
0188                 delete mContactItem->contact ();
0189                 if(mc && mc->contacts().isEmpty())
0190                 {
0191                     Kopete::ContactList::self()->removeMetaContact(mc) ;
0192                 }
0193             }
0194             return;
0195         }
0196     }
0197 
0198     qCDebug(JABBER_PROTOCOL_LOG) << "WARNING: No match found!";
0199 
0200 }
0201 
0202 void JabberContactPool::slotContactDestroyed ( Kopete::Contact *contact )
0203 {
0204     qCDebug(JABBER_PROTOCOL_LOG) << "Contact deleted, collecting the pieces...";
0205 
0206     JabberBaseContact *jabberContact = static_cast<JabberBaseContact *>( contact ); 
0207     //WARNING  this ptr is not usable, we are in the Kopete::Contact destructor
0208 
0209     // remove contact from the pool
0210     foreach(JabberContactPoolItem *mContactItem, mPool)
0211     {
0212         if ( mContactItem->contact() == jabberContact )
0213         {
0214             JabberContactPoolItem *deletedItem = mPool.takeAt( mPool.indexOf(mContactItem) );
0215             delete deletedItem;
0216 
0217             break;
0218         }
0219     }
0220 
0221     // delete all resources for it
0222     if(contact->account()==(Kopete::Account*)(mAccount))
0223         mAccount->resourcePool()->removeAllResources ( XMPP::Jid ( contact->contactId() ) );
0224     else
0225     {
0226         //this is a legacy contact. we have no way to get the real Jid at this point, we can only guess it.
0227         QString contactId= contact->contactId().replace('@','%') + '@' + contact->account()->myself()->contactId();
0228         mAccount->resourcePool()->removeAllResources ( XMPP::Jid ( contactId ) ) ;
0229     }
0230 
0231 }
0232 
0233 void JabberContactPool::clear ()
0234 {
0235     qCDebug(JABBER_PROTOCOL_LOG) << "Clearing the contact pool.";
0236 
0237     foreach(JabberContactPoolItem *mContactItem, mPool)
0238     {
0239         /*
0240          * The following deletion will cause slotContactDestroyed()
0241          * to be called, which will clean the up the list.
0242          * NOTE: this is a very inefficient way to clear the list
0243          */
0244         delete mContactItem->contact ();
0245     }
0246 
0247 }
0248 
0249 void JabberContactPool::setDirty ( const XMPP::Jid &jid, bool dirty )
0250 {
0251     qCDebug(JABBER_PROTOCOL_LOG) << "Setting flag for " << jid.full() << " to " << dirty;
0252 
0253     foreach(JabberContactPoolItem *mContactItem, mPool)
0254     {
0255         if ( mContactItem->contact()->rosterItem().jid().full().toLower() == jid.full().toLower() )
0256         {
0257             mContactItem->setDirty ( dirty );
0258             return;
0259         }
0260     }
0261 
0262     qCDebug(JABBER_PROTOCOL_LOG) << "WARNING: No match found!";
0263 
0264 }
0265 
0266 void JabberContactPool::cleanUp ()
0267 {
0268     qCDebug(JABBER_PROTOCOL_LOG) << "Cleaning dirty items from contact pool.";
0269 
0270     foreach(JabberContactPoolItem *mContactItem, mPool)
0271     {
0272         if ( mContactItem->dirty () )
0273         {
0274             qCDebug(JABBER_PROTOCOL_LOG) << "Removing dirty contact " << mContactItem->contact()->contactId ();
0275 
0276             /*
0277              * The following deletion will cause slotContactDestroyed()
0278              * to be called, which will clean the up the list.
0279              */
0280             delete mContactItem->contact ();
0281         }
0282     }
0283 
0284 }
0285 
0286 JabberBaseContact *JabberContactPool::findExactMatch ( const XMPP::Jid &jid )
0287 {
0288 
0289     foreach(JabberContactPoolItem *mContactItem, mPool)
0290     {
0291         if ( mContactItem->contact()->rosterItem().jid().full().toLower () == jid.full().toLower () )
0292         {
0293             return mContactItem->contact ();
0294         }
0295     }
0296 
0297     return 0L;
0298 
0299 }
0300 
0301 JabberBaseContact *JabberContactPool::findRelevantRecipient ( const XMPP::Jid &jid )
0302 {
0303 
0304     foreach(JabberContactPoolItem *mContactItem, mPool)
0305     {
0306         if ( mContactItem->contact()->rosterItem().jid().full().toLower () == jid.userHost().toLower () )
0307         {
0308             return mContactItem->contact ();
0309         }
0310     }
0311 
0312     return 0L;
0313 
0314 }
0315 
0316 QList<JabberBaseContact*> JabberContactPool::findRelevantSources ( const XMPP::Jid &jid )
0317 {
0318     QList<JabberBaseContact*> list;
0319 
0320     foreach(JabberContactPoolItem *mContactItem, mPool)
0321     {
0322         if ( mContactItem->contact()->rosterItem().jid().userHost().toLower () == jid.userHost().toLower () )
0323         {
0324             list.append ( mContactItem->contact () );
0325         }
0326     }
0327 
0328     return list;
0329 
0330 }
0331 
0332 JabberContactPoolItem::JabberContactPoolItem ( JabberBaseContact *contact )
0333 {
0334     mDirty = true;
0335     mContact = contact;
0336 }
0337 
0338 JabberContactPoolItem::~JabberContactPoolItem ()
0339 {
0340 }
0341 
0342 void JabberContactPoolItem::setDirty ( bool dirty )
0343 {
0344     mDirty = dirty;
0345 }
0346 
0347 bool JabberContactPoolItem::dirty ()
0348 {
0349     return mDirty;
0350 }
0351 
0352 JabberBaseContact *JabberContactPoolItem::contact ()
0353 {
0354     return mContact;
0355 }
0356 
0357 #include "moc_jabbercontactpool.cpp"