|
|
|
/*
|
|
|
|
* jabbercontact.cpp - Regular Kopete Jabber protocol contact
|
|
|
|
*
|
|
|
|
* Copyright (c) 2002-2004 by Till Gerken <till@tantalo.net>
|
|
|
|
* Copyright (c) 2006 by Olivier Goffart <ogoffart @ 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 "jabbergroupcontact.h"
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kfiledialog.h>
|
|
|
|
#include <kinputdialog.h>
|
|
|
|
#include "jabberprotocol.h"
|
|
|
|
#include "jabberaccount.h"
|
|
|
|
#include "jabberclient.h"
|
|
|
|
#include "jabberfiletransfer.h"
|
|
|
|
#include "jabbergroupchatmanager.h"
|
|
|
|
#include "jabbergroupmembercontact.h"
|
|
|
|
#include "jabbercontactpool.h"
|
|
|
|
#include "kopetemetacontact.h"
|
|
|
|
#include "xmpp_tasks.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* JabberGroupContact constructor
|
|
|
|
*/
|
|
|
|
JabberGroupContact::JabberGroupContact (const XMPP::RosterItem &rosterItem, JabberAccount *account, Kopete::MetaContact * mc)
|
|
|
|
: JabberBaseContact ( XMPP::RosterItem ( rosterItem.jid().userHost () ), account, mc) , mNick( rosterItem.jid().resource() )
|
|
|
|
{
|
|
|
|
setIcon( "jabber_group" );
|
|
|
|
|
|
|
|
// initialize here, we need it set before we instantiate the manager below
|
|
|
|
mManager = 0;
|
|
|
|
|
|
|
|
setFileCapable ( false );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add our own nick as first subcontact (we need to do that here
|
|
|
|
* because we need to set this contact as myself() of the message
|
|
|
|
* manager).
|
|
|
|
*/
|
|
|
|
mSelfContact = addSubContact ( rosterItem );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Instantiate a new message manager without members.
|
|
|
|
*/
|
|
|
|
mManager = new JabberGroupChatManager ( protocol (), mSelfContact,
|
|
|
|
Kopete::ContactPtrList (), XMPP::Jid ( rosterItem.jid().userHost () ) );
|
|
|
|
|
|
|
|
connect ( mManager, TQT_SIGNAL ( closing ( Kopete::ChatSession* ) ), this, TQT_SLOT ( slotChatSessionDeleted () ) );
|
|
|
|
|
|
|
|
connect ( account->myself() , TQT_SIGNAL(onlineStatusChanged( Kopete::Contact*, const Kopete::OnlineStatus&, const Kopete::OnlineStatus& ) ) ,
|
|
|
|
this , TQT_SLOT(slotStatusChanged() ) ) ;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* FIXME: The first contact in the list of the message manager
|
|
|
|
* needs to be our own contact. This is a flaw in the Kopete
|
|
|
|
* API because it can't deal with group chat properly.
|
|
|
|
* If we are alone in a room, we are myself() already and members()
|
|
|
|
* is empty. This makes at least the history plugin crash.
|
|
|
|
*/
|
|
|
|
mManager->addContact ( this );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Let's construct the window:
|
|
|
|
* otherwise, the ref count of maznager is equal to zero.
|
|
|
|
* and if we receive a message before the window is shown,
|
|
|
|
* it will be deleted and we will be out of the channel
|
|
|
|
* In all case, there are no reason to don't show it.
|
|
|
|
*/
|
|
|
|
mManager->view( true , "kopete_chatwindow" );
|
|
|
|
}
|
|
|
|
|
|
|
|
JabberGroupContact::~JabberGroupContact ()
|
|
|
|
{
|
|
|
|
|
|
|
|
kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << endl;
|
|
|
|
|
|
|
|
if(mManager)
|
|
|
|
{
|
|
|
|
mManager->deleteLater();
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( Kopete::Contact *contact = mContactList.first (); contact; contact = mContactList.next () )
|
|
|
|
{
|
|
|
|
/*if(mManager)
|
|
|
|
mManager->removeContact( contact );*/
|
|
|
|
kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Deleting KC " << contact->contactId () << endl;
|
|
|
|
contact->deleteLater();
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( Kopete::MetaContact *metaContact = mMetaContactList.first (); metaContact; metaContact = mMetaContactList.next () )
|
|
|
|
{
|
|
|
|
kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Deleting KMC " << metaContact->metaContactId () << endl;
|
|
|
|
metaContact->deleteLater();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPtrList<KAction> *JabberGroupContact::customContextMenuActions ()
|
|
|
|
{
|
|
|
|
TQPtrList<KAction> *actionCollection = new TQPtrList<KAction>();
|
|
|
|
|
|
|
|
KAction *actionSetNick = new KAction (i18n ("Change nick name"), 0, 0, this, TQT_SLOT (slotChangeNick()), this, "jabber_changenick");
|
|
|
|
actionCollection->append( actionSetNick );
|
|
|
|
|
|
|
|
return actionCollection;
|
|
|
|
}
|
|
|
|
|
|
|
|
Kopete::ChatSession *JabberGroupContact::manager ( Kopete::Contact::CanCreateFlags canCreate )
|
|
|
|
{
|
|
|
|
if(!mManager && canCreate == Kopete::Contact::CanCreate)
|
|
|
|
{
|
|
|
|
kdWarning (JABBER_DEBUG_GLOBAL) << k_funcinfo << "somehow, the chat manager was removed, and the contact is still there" << endl;
|
|
|
|
mManager = new JabberGroupChatManager ( protocol (), mSelfContact,
|
|
|
|
Kopete::ContactPtrList (), XMPP::Jid ( rosterItem().jid().userHost() ) );
|
|
|
|
|
|
|
|
mManager->addContact ( this );
|
|
|
|
|
|
|
|
connect ( mManager, TQT_SIGNAL ( closing ( Kopete::ChatSession* ) ), this, TQT_SLOT ( slotChatSessionDeleted () ) );
|
|
|
|
|
|
|
|
//if we have to recreate the manager, we probably have to connect again to the chat.
|
|
|
|
slotStatusChanged();
|
|
|
|
}
|
|
|
|
return mManager;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void JabberGroupContact::handleIncomingMessage (const XMPP::Message & message)
|
|
|
|
{
|
|
|
|
// message type is always chat in a groupchat
|
|
|
|
TQString viewType = "kopete_chatwindow";
|
|
|
|
Kopete::Message *newMessage = 0L;
|
|
|
|
|
|
|
|
kdDebug (JABBER_DEBUG_GLOBAL) << k_funcinfo << "Received a message" << endl;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Don't display empty messages, these were most likely just carrying
|
|
|
|
* event notifications or other payload.
|
|
|
|
*/
|
|
|
|
if ( message.body().isEmpty () )
|
|
|
|
return;
|
|
|
|
|
|
|
|
manager(CanCreate); //force to create mManager
|
|
|
|
|
|
|
|
Kopete::ContactPtrList contactList = manager()->members();
|
|
|
|
|
|
|
|
// check for errors
|
|
|
|
if ( message.type () == "error" )
|
|
|
|
{
|
|
|
|
newMessage = new Kopete::Message( message.timeStamp (), this, contactList,
|
|
|
|
i18n("Your message could not be delivered: \"%1\", Reason: \"%2\"").
|
|
|
|
arg ( message.body () ).arg ( message.error().text ),
|
|
|
|
message.subject(), Kopete::Message::Inbound, Kopete::Message::PlainText, viewType );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// retrieve and reformat body
|
|
|
|
TQString body = message.body ();
|
|
|
|
|
|
|
|
if( !message.xencrypted().isEmpty () )
|
|
|
|
{
|
|
|
|
body = TQString ("-----BEGIN PGP MESSAGE-----\n\n") + message.xencrypted () + TQString ("\n-----END PGP MESSAGE-----\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// locate the originating contact
|
|
|
|
JabberBaseContact *subContact = account()->contactPool()->findExactMatch ( message.from () );
|
|
|
|
|
|
|
|
if ( !subContact )
|
|
|
|
{
|
|
|
|
kdWarning (JABBER_DEBUG_GLOBAL) << k_funcinfo << "the contact is not in the list : " << message.from().full()<< endl;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We couldn't find the contact for this message. That most likely means
|
|
|
|
* that it originated from a history backlog or something similar and
|
|
|
|
* the sending person is not in the channel anymore. We need to create
|
|
|
|
* a new contact for this which does not show up in the manager.
|
|
|
|
*/
|
|
|
|
subContact = addSubContact ( XMPP::RosterItem ( message.from () ), false );
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert XMPP::Message into Kopete::Message
|
|
|
|
newMessage = new Kopete::Message ( message.timeStamp (), subContact, contactList, body,
|
|
|
|
message.subject (),
|
|
|
|
subContact != mManager->myself() ? Kopete::Message::Inbound : Kopete::Message::Outbound,
|
|
|
|
Kopete::Message::PlainText, viewType );
|
|
|
|
}
|
|
|
|
|
|
|
|
// append message to manager
|
|
|
|
mManager->appendMessage ( *newMessage );
|
|
|
|
|
|
|
|
delete newMessage;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
JabberBaseContact *JabberGroupContact::addSubContact ( const XMPP::RosterItem &rosterItem, bool addToManager )
|
|
|
|
{
|
|
|
|
kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Adding new subcontact " << rosterItem.jid().full () << " to room " << mRosterItem.jid().full () << endl;
|
|
|
|
|
|
|
|
// see if this contact already exists, skip creation otherwise
|
|
|
|
JabberBaseContact *subContact = dynamic_cast<JabberGroupMemberContact *>( account()->contactPool()->findExactMatch ( rosterItem.jid () ) );
|
|
|
|
|
|
|
|
if ( subContact )
|
|
|
|
{
|
|
|
|
kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Contact already exists, not adding again." << endl;
|
|
|
|
return subContact;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create new meta contact that holds the group chat contact.
|
|
|
|
Kopete::MetaContact *metaContact = new Kopete::MetaContact ();
|
|
|
|
metaContact->setTemporary ( true );
|
|
|
|
mMetaContactList.append ( metaContact );
|
|
|
|
|
|
|
|
// now add contact to the pool, no dirty flag
|
|
|
|
subContact = account()->contactPool()->addGroupContact ( rosterItem, false, metaContact, false );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add the contact to our message manager first. We need
|
|
|
|
* to check the pointer for validity, because this method
|
|
|
|
* gets called from the constructor, where the manager
|
|
|
|
* does not exist yet.
|
|
|
|
*/
|
|
|
|
if ( mManager && addToManager )
|
|
|
|
mManager->addContact ( subContact );
|
|
|
|
|
|
|
|
// now, add the contact also to our own list
|
|
|
|
mContactList.append ( subContact );
|
|
|
|
|
|
|
|
connect(subContact , TQT_SIGNAL(contactDestroyed(Kopete::Contact*)) , this , TQT_SLOT(slotSubContactDestroyed(Kopete::Contact*)));
|
|
|
|
|
|
|
|
return subContact;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void JabberGroupContact::removeSubContact ( const XMPP::RosterItem &rosterItem )
|
|
|
|
{
|
|
|
|
kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Removing subcontact " << rosterItem.jid().full () << " from room " << mRosterItem.jid().full () << endl;
|
|
|
|
|
|
|
|
// make sure that subcontacts are only removed from the room contact, which has no resource
|
|
|
|
if ( !mRosterItem.jid().resource().isEmpty () )
|
|
|
|
{
|
|
|
|
kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "WARNING: Trying to remove subcontact from subcontact!" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find contact in the pool
|
|
|
|
JabberGroupMemberContact *subContact = dynamic_cast<JabberGroupMemberContact *>( account()->contactPool()->findExactMatch ( rosterItem.jid () ) );
|
|
|
|
|
|
|
|
if ( !subContact )
|
|
|
|
{
|
|
|
|
kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "WARNING: Subcontact couldn't be located!" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mManager && subContact->contactId() == mManager->myself()->contactId() )
|
|
|
|
{
|
|
|
|
//HACK WORKAROUND FIXME KDE4
|
|
|
|
//impossible to remove myself, or we will die
|
|
|
|
//subContact->setNickName( mNick ); //this is even worse than nothing
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove the contact from the message manager first
|
|
|
|
if(mManager)
|
|
|
|
mManager->removeContact ( subContact );
|
|
|
|
|
|
|
|
// remove the contact's meta contact from our internal list
|
|
|
|
mMetaContactList.remove ( subContact->metaContact () );
|
|
|
|
|
|
|
|
// remove the contact from our internal list
|
|
|
|
mContactList.remove ( subContact );
|
|
|
|
|
|
|
|
// delete the meta contact first
|
|
|
|
delete subContact->metaContact ();
|
|
|
|
|
|
|
|
// finally, delete the contact itself from the pool
|
|
|
|
account()->contactPool()->removeContact ( rosterItem.jid () );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void JabberGroupContact::sendFile ( const KURL &sourceURL, const TQString &/*fileName*/, uint /*fileSize*/ )
|
|
|
|
{
|
|
|
|
TQString filePath;
|
|
|
|
|
|
|
|
// if the file location is null, then get it from a file open dialog
|
|
|
|
if ( !sourceURL.isValid () )
|
|
|
|
filePath = KFileDialog::getOpenFileName( TQString() , "*", 0L, i18n ( "Kopete File Transfer" ) );
|
|
|
|
else
|
|
|
|
filePath = sourceURL.path(-1);
|
|
|
|
|
|
|
|
TQFile file ( filePath );
|
|
|
|
|
|
|
|
if ( file.exists () )
|
|
|
|
{
|
|
|
|
// send the file
|
|
|
|
new JabberFileTransfer ( account (), this, filePath );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void JabberGroupContact::slotChatSessionDeleted ()
|
|
|
|
{
|
|
|
|
|
|
|
|
mManager = 0;
|
|
|
|
|
|
|
|
if ( account()->isConnected () )
|
|
|
|
{
|
|
|
|
account()->client()->leaveGroupChat ( mRosterItem.jid().host (), mRosterItem.jid().user () );
|
|
|
|
}
|
|
|
|
|
|
|
|
//deleteLater(); //we will be deleted later when the the account will know we have left
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void JabberGroupContact::slotStatusChanged( )
|
|
|
|
{
|
|
|
|
if( !account()->isConnected() )
|
|
|
|
{
|
|
|
|
//we need to remove all contact, because when we connect again, we will not receive the notificaion they are gone.
|
|
|
|
TQPtrList<Kopete::Contact> copy_contactlist=mContactList;
|
|
|
|
for ( Kopete::Contact *contact = copy_contactlist.first (); contact; contact = copy_contactlist.next () )
|
|
|
|
{
|
|
|
|
removeSubContact( XMPP::Jid(contact->contactId()) );
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if( !isOnline() )
|
|
|
|
{
|
|
|
|
//HACK WORKAROUND XMPP::client->d->groupChatList must contains us.
|
|
|
|
account()->client()->joinGroupChat( rosterItem().jid().host() , rosterItem().jid().user() , mNick );
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO: away message
|
|
|
|
XMPP::Status newStatus = account()->protocol()->kosToStatus( account()->myself()->onlineStatus() );
|
|
|
|
account()->client()->setGroupChatStatus( rosterItem().jid().host() , rosterItem().jid().user() , newStatus );
|
|
|
|
}
|
|
|
|
|
|
|
|
void JabberGroupContact::slotChangeNick( )
|
|
|
|
{
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
TQString futureNewNickName = KInputDialog::getText( i18n( "Change nickanme - Jabber Plugin" ),
|
|
|
|
i18n( "Please enter the new nick name you want to have on the room <i>%1</i>" ).arg(rosterItem().jid().userHost()),
|
|
|
|
mNick, &ok );
|
|
|
|
if ( !ok || !account()->isConnected())
|
|
|
|
return;
|
|
|
|
|
|
|
|
mNick=futureNewNickName;
|
|
|
|
|
|
|
|
XMPP::Status status = account()->protocol()->kosToStatus( account()->myself()->onlineStatus() );
|
|
|
|
account()->client()->changeGroupChatNick( rosterItem().jid().host() , rosterItem().jid().user() , mNick , status);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void JabberGroupContact::slotSubContactDestroyed( Kopete::Contact * deadContact )
|
|
|
|
{
|
|
|
|
kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "cleaning dead subcontact " << deadContact->contactId() << " from room " << mRosterItem.jid().full () << endl;
|
|
|
|
|
|
|
|
mMetaContactList.remove ( deadContact->metaContact () );
|
|
|
|
mContactList.remove ( deadContact );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "jabbergroupcontact.moc"
|