You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kopete/protocols/jabber/jabbercontactpool.cpp

356 lines
11 KiB

/*
* jabbercontactpool.cpp
*
* Copyright (c) 2004 by Till Gerken <till@tantalo.net>
* Copyright (c) 2006 by Olivier Goffart <ogoffart at kde.org>
*
* Kopete (c) by the Kopete developers <kopete-devel@kde.org>
*
* *************************************************************************
* * *
* * This program is free software; you can redistribute it and/or modify *
* * it under the terms of the GNU General Public License as published by *
* * the Free Software Foundation; either version 2 of the License, or *
* * (at your option) any later version. *
* * *
* *************************************************************************
*/
#include "jabbercontactpool.h"
#include <tqptrlist.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <kopeteaccountmanager.h>
#include <kopetecontactlist.h>
#include "kopeteuiglobal.h"
#include "jabberprotocol.h"
#include "jabberbasecontact.h"
#include "jabbercontact.h"
#include "jabbergroupcontact.h"
#include "jabbergroupmembercontact.h"
#include "jabberresourcepool.h"
#include "jabberaccount.h"
#include "jabbertransport.h"
JabberContactPool::JabberContactPool ( JabberAccount *account )
{
// automatically delete all contacts in the pool upon removal
mPool.setAutoDelete (true);
mAccount = account;
}
JabberContactPool::~JabberContactPool ()
{
}
JabberContactPoolItem *JabberContactPool::findPoolItem ( const XMPP::RosterItem &contact )
{
// see if the contact already exists
for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
{
if ( mContactItem->contact()->rosterItem().jid().full().lower() == contact.jid().full().lower() )
{
return mContactItem;
}
}
return 0;
}
JabberContact *JabberContactPool::addContact ( const XMPP::RosterItem &contact, Kopete::MetaContact *metaContact, bool dirty )
{
// see if the contact already exists
JabberContactPoolItem *mContactItem = findPoolItem ( contact );
if ( mContactItem)
{
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Updating existing contact " << contact.jid().full() << " - " << mContactItem->contact() << endl;
// It exists, update it.
mContactItem->contact()->updateContact ( contact );
mContactItem->setDirty ( dirty );
JabberContact *retval = dynamic_cast<JabberContact *>(mContactItem->contact ());
if ( !retval )
{
KMessageBox::error ( Kopete::UI::Global::mainWidget (),
"Fatal error in the Jabber contact pool. Please restart Kopete and submit a debug log "
"of your session to http://bugs.kde.org.",
"Fatal Jabber Error" );
}
return retval;
}
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Adding new contact " << contact.jid().full() << endl;
JabberTransport *transport=0l;
TQString legacyId;
//find if the contact should be added to a transport.
if(mAccount->transports().contains(contact.jid().domain()))
{
transport=mAccount->transports()[contact.jid().domain()];
legacyId=transport->legacyId( contact.jid() );
}
// create new contact instance and add it to the dictionary
JabberContact *newContact = new JabberContact ( contact, transport ? (Kopete::Account*)transport : (Kopete::Account*)mAccount, metaContact , legacyId );
JabberContactPoolItem *newContactItem = new JabberContactPoolItem ( newContact );
connect ( newContact, TQT_SIGNAL ( contactDestroyed ( Kopete::Contact * ) ), this, TQT_SLOT ( slotContactDestroyed ( Kopete::Contact * ) ) );
newContactItem->setDirty ( dirty );
mPool.append ( newContactItem );
return newContact;
}
JabberBaseContact *JabberContactPool::addGroupContact ( const XMPP::RosterItem &contact, bool roomContact, Kopete::MetaContact *metaContact, bool dirty )
{
XMPP::RosterItem mContact ( roomContact ? contact.jid().userHost () : contact.jid().full() );
// see if the contact already exists
JabberContactPoolItem *mContactItem = findPoolItem ( mContact );
if ( mContactItem)
{
if(mContactItem->contact()->inherits(roomContact ?
(const char*)("JabberGroupContact") : (const char*)("JabberGroupMemberContact") ) )
{
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Updating existing contact " << mContact.jid().full() << endl;
// It exists, update it.
mContactItem->contact()->updateContact ( mContact );
mContactItem->setDirty ( dirty );
//we must tell to the originating function that no new contact has been added
return 0L;//mContactItem->contact ();
}
else
{
//this happen if we receive a MUC invitaiton: when the invitaiton is received, it's from the muc itself
//and then kopete will create a temporary contact for it. but it will not be a good contact.
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Bad contact will be removed and re-added " << mContact.jid().full() << endl;
Kopete::MetaContact *old_mc=mContactItem->contact()->metaContact();
delete mContactItem->contact();
mContactItem = 0L;
if(old_mc->contacts().isEmpty() && old_mc!=metaContact)
{
Kopete::ContactList::self()->removeMetaContact( old_mc );
}
}
}
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Adding new contact " << mContact.jid().full() << endl;
// create new contact instance and add it to the dictionary
JabberBaseContact *newContact;
if ( roomContact )
newContact = new JabberGroupContact ( contact, mAccount, metaContact );
else
newContact = new JabberGroupMemberContact ( contact, mAccount, metaContact );
JabberContactPoolItem *newContactItem = new JabberContactPoolItem ( newContact );
connect ( newContact, TQT_SIGNAL ( contactDestroyed ( Kopete::Contact * ) ), this, TQT_SLOT ( slotContactDestroyed ( Kopete::Contact * ) ) );
newContactItem->setDirty ( dirty );
mPool.append ( newContactItem );
return newContact;
}
void JabberContactPool::removeContact ( const XMPP::Jid &jid )
{
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Removing contact " << jid.full() << endl;
for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
{
if ( mContactItem->contact()->rosterItem().jid().full().lower() == jid.full().lower() )
{
/*
* The following deletion will cause slotContactDestroyed()
* to be called, which will clean the up the list.
*/
if(mContactItem->contact())
{
Kopete::MetaContact *mc=mContactItem->contact()->metaContact();
delete mContactItem->contact ();
if(mc && mc->contacts().isEmpty())
{
Kopete::ContactList::self()->removeMetaContact(mc) ;
}
}
return;
}
}
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "WARNING: No match found!" << endl;
}
void JabberContactPool::slotContactDestroyed ( Kopete::Contact *contact )
{
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Contact deleted, collecting the pieces..." << endl;
JabberBaseContact *jabberContact = static_cast<JabberBaseContact *>( contact );
//WARNING this ptr is not usable, we are in the Kopete::Contact destructor
// remove contact from the pool
for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
{
if ( mContactItem->contact() == jabberContact )
{
mPool.remove ();
break;
}
}
// delete all resources for it
if(contact->account()==(Kopete::Account*)(mAccount))
mAccount->resourcePool()->removeAllResources ( XMPP::Jid ( contact->contactId() ) );
else
{
//this is a legacy contact. we have no way to get the real Jid at this point, we can only guess it.
TQString contactId= contact->contactId().replace('@','%') + "@" + contact->account()->myself()->contactId();
mAccount->resourcePool()->removeAllResources ( XMPP::Jid ( contactId ) ) ;
}
}
void JabberContactPool::clear ()
{
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Clearing the contact pool." << endl;
for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
{
/*
* The following deletion will cause slotContactDestroyed()
* to be called, which will clean the up the list.
* NOTE: this is a very inefficient way to clear the list
*/
delete mContactItem->contact ();
}
}
void JabberContactPool::setDirty ( const XMPP::Jid &jid, bool dirty )
{
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Setting flag for " << jid.full() << " to " << dirty << endl;
for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
{
if ( mContactItem->contact()->rosterItem().jid().full().lower() == jid.full().lower() )
{
mContactItem->setDirty ( dirty );
return;
}
}
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "WARNING: No match found!" << endl;
}
void JabberContactPool::cleanUp ()
{
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Cleaning dirty items from contact pool." << endl;
for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
{
if ( mContactItem->dirty () )
{
kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Removing dirty contact " << mContactItem->contact()->contactId () << endl;
/*
* The following deletion will cause slotContactDestroyed()
* to be called, which will clean the up the list.
*/
delete mContactItem->contact ();
}
}
}
JabberBaseContact *JabberContactPool::findExactMatch ( const XMPP::Jid &jid )
{
for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
{
if ( mContactItem->contact()->rosterItem().jid().full().lower () == jid.full().lower () )
{
return mContactItem->contact ();
}
}
return 0L;
}
JabberBaseContact *JabberContactPool::findRelevantRecipient ( const XMPP::Jid &jid )
{
for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
{
if ( mContactItem->contact()->rosterItem().jid().full().lower () == jid.userHost().lower () )
{
return mContactItem->contact ();
}
}
return 0L;
}
TQPtrList<JabberBaseContact> JabberContactPool::findRelevantSources ( const XMPP::Jid &jid )
{
TQPtrList<JabberBaseContact> list;
for(JabberContactPoolItem *mContactItem = mPool.first (); mContactItem; mContactItem = mPool.next ())
{
if ( mContactItem->contact()->rosterItem().jid().userHost().lower () == jid.userHost().lower () )
{
list.append ( mContactItem->contact () );
}
}
return list;
}
JabberContactPoolItem::JabberContactPoolItem ( JabberBaseContact *contact )
{
mDirty = true;
mContact = contact;
}
JabberContactPoolItem::~JabberContactPoolItem ()
{
}
void JabberContactPoolItem::setDirty ( bool dirty )
{
mDirty = dirty;
}
bool JabberContactPoolItem::dirty ()
{
return mDirty;
}
JabberBaseContact *JabberContactPoolItem::contact ()
{
return mContact;
}
#include "jabbercontactpool.moc"