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/oscar/aim/aimaccount.cpp

924 lines
32 KiB

/*
aimaccount.cpp - Oscar Protocol Plugin, AIM part
Kopete (c) 2002-2003 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 <tqdom.h>
#include <tqfile.h>
#include <kdebug.h>
#include <tdeconfig.h>
#include <kdialogbase.h>
#include <tdelocale.h>
#include <tdepopupmenu.h>
#include <tdemessagebox.h>
#include <kmdcodec.h>
#include "kopeteawayaction.h"
#include "kopetepassword.h"
#include "kopetestdaction.h"
#include "kopeteuiglobal.h"
#include "kopetecontactlist.h"
#include "kopetemetacontact.h"
#include "kopeteprotocol.h"
#include "kopetechatsessionmanager.h"
#include "kopeteview.h"
#include <kopeteuiglobal.h>
#include "aimprotocol.h"
#include "aimaccount.h"
#include "aimchatsession.h"
#include "aimcontact.h"
#include "aimuserinfo.h"
#include "aimjoinchat.h"
#include "oscarmyselfcontact.h"
#include "oscarvisibilitydialog.h"
#include "oscarutils.h"
#include "client.h"
#include "ssimanager.h"
const DWORD AIM_ONLINE = 0x0;
const DWORD AIM_AWAY = 0x1;
namespace Kopete { class MetaContact; }
AIMMyselfContact::AIMMyselfContact( AIMAccount *acct )
: OscarMyselfContact( acct )
{
m_acct = acct;
}
void AIMMyselfContact::userInfoUpdated()
{
if ( ( details().userClass() & 32 ) == 0 )
setOnlineStatus( static_cast<AIMProtocol*>( protocol() )->statusOnline ); //we're online
else
setOnlineStatus( static_cast<AIMProtocol*>( protocol() )->statusAway ); //we're away
}
void AIMMyselfContact::setOwnProfile( const TQString& newProfile )
{
m_profileString = newProfile;
if ( m_acct->isConnected() )
m_acct->engine()->updateProfile( newProfile );
}
TQString AIMMyselfContact::userProfile()
{
return m_profileString;
}
Kopete::ChatSession* AIMMyselfContact::manager( Kopete::Contact::CanCreateFlags canCreate,
Oscar::WORD exchange, const TQString& room )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << endl;
Kopete::ContactPtrList chatMembers;
chatMembers.append( this );
Kopete::ChatSession* genericManager = 0L;
genericManager = Kopete::ChatSessionManager::self()->findChatSession( account()->myself(), chatMembers, protocol() );
AIMChatSession* session = dynamic_cast<AIMChatSession*>( genericManager );
if ( !session && canCreate == Contact::CanCreate )
{
session = new AIMChatSession( this, chatMembers, account()->protocol(), exchange, room );
session->setEngine( m_acct->engine() );
connect( session, TQT_SIGNAL( messageSent( Kopete::Message&, Kopete::ChatSession* ) ),
this, TQT_SLOT( sendMessage( Kopete::Message&, Kopete::ChatSession* ) ) );
m_chatRoomSessions.append( session );
}
return session;
}
void AIMMyselfContact::chatSessionDestroyed( Kopete::ChatSession* session )
{
m_chatRoomSessions.remove( session );
}
void AIMMyselfContact::sendMessage( Kopete::Message& message, Kopete::ChatSession* session )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "sending a message" << endl;
//TODO: remove duplication - factor into a message utils class or something
Oscar::Message msg;
TQString s;
if (message.plainBody().isEmpty()) // no text, do nothing
return;
//okay, now we need to change the message.escapedBody from real HTML to aimhtml.
//looking right now for docs on that "format".
//looks like everything except for alignment codes comes in the format of spans
//font-style:italic -> <i>
//font-weight:600 -> <b> (anything > 400 should be <b>, 400 is not bold)
//text-decoration:underline -> <u>
//font-family: -> <font face="">
//font-size:xxpt -> <font ptsize=xx>
s=message.escapedBody();
s.replace ( TQRegExp( TQString::fromLatin1("<span style=\"([^\"]*)\">([^<]*)</span>")),
TQString::fromLatin1("<style>\\1;\"\\2</style>"));
s.replace ( TQRegExp( TQString::fromLatin1("<style>([^\"]*)font-style:italic;([^\"]*)\"([^<]*)</style>")),
TQString::fromLatin1("<i><style>\\1\\2\"\\3</style></i>"));
s.replace ( TQRegExp( TQString::fromLatin1("<style>([^\"]*)font-weight:600;([^\"]*)\"([^<]*)</style>")),
TQString::fromLatin1("<b><style>\\1\\2\"\\3</style></b>"));
s.replace ( TQRegExp( TQString::fromLatin1("<style>([^\"]*)text-decoration:underline;([^\"]*)\"([^<]*)</style>")),
TQString::fromLatin1("<u><style>\\1\\2\"\\3</style></u>"));
s.replace ( TQRegExp( TQString::fromLatin1("<style>([^\"]*)font-family:([^;]*);([^\"]*)\"([^<]*)</style>")),
TQString::fromLatin1("<font face=\"\\2\"><style>\\1\\3\"\\4</style></font>"));
s.replace ( TQRegExp( TQString::fromLatin1("<style>([^\"]*)font-size:([^p]*)pt;([^\"]*)\"([^<]*)</style>")),
TQString::fromLatin1("<font ptsize=\"\\2\"><style>\\1\\3\"\\4</style></font>"));
s.replace ( TQRegExp( TQString::fromLatin1("<style>([^\"]*)color:([^;]*);([^\"]*)\"([^<]*)</style>")),
TQString::fromLatin1("<font color=\"\\2\"><style>\\1\\3\"\\4</style></font>"));
s.replace ( TQRegExp( TQString::fromLatin1("<style>([^\"]*)\"([^<]*)</style>")),
TQString::fromLatin1("\\2"));
//okay now change the <font ptsize="xx"> to <font size="xx">
//0-9 are size 1
s.replace ( TQRegExp ( TQString::fromLatin1("<font ptsize=\"\\d\">")),
TQString::fromLatin1("<font size=\"1\">"));
//10-11 are size 2
s.replace ( TQRegExp ( TQString::fromLatin1("<font ptsize=\"1[01]\">")),
TQString::fromLatin1("<font size=\"2\">"));
//12-13 are size 3
s.replace ( TQRegExp ( TQString::fromLatin1("<font ptsize=\"1[23]\">")),
TQString::fromLatin1("<font size=\"3\">"));
//14-16 are size 4
s.replace ( TQRegExp ( TQString::fromLatin1("<font ptsize=\"1[456]\">")),
TQString::fromLatin1("<font size=\"4\">"));
//17-22 are size 5
s.replace ( TQRegExp ( TQString::fromLatin1("<font ptsize=\"(?:1[789]|2[012])\">")),
TQString::fromLatin1("<font size=\"5\">"));
//23-29 are size 6
s.replace ( TQRegExp ( TQString::fromLatin1("<font ptsize=\"2[3456789]\">")),TQString::fromLatin1("<font size=\"6\">"));
//30- (and any I missed) are size 7
s.replace ( TQRegExp ( TQString::fromLatin1("<font ptsize=\"[^\"]*\">")),TQString::fromLatin1("<font size=\"7\">"));
s.replace ( TQRegExp ( TQString::fromLatin1("<br[ /]*>")), TQString::fromLatin1("<br>") );
kdDebug(14190) << k_funcinfo << "sending "
<< s << endl;
msg.setSender( contactId() );
msg.setText( Oscar::Message::UserDefined, s, m_acct->defaultCodec() );
msg.setTimestamp(message.timestamp());
msg.setType(0x03);
msg.addProperty( Oscar::Message::ChatRoom );
AIMChatSession* aimSession = dynamic_cast<AIMChatSession*>( session );
if ( !aimSession )
{
kdWarning(OSCAR_AIM_DEBUG) << "couldn't convert to AIM chat room session!" << endl;
session->messageSucceeded();
return;
}
msg.setExchange( aimSession->exchange() );
msg.setChatRoom( aimSession->roomName() );
m_acct->engine()->sendMessage( msg );
//session->appendMessage( message );
session->messageSucceeded();
}
AIMAccount::AIMAccount(Kopete::Protocol *parent, TQString accountID, const char *name)
: OscarAccount(parent, accountID, name, false)
{
kdDebug(14152) << k_funcinfo << accountID << ": Called."<< endl;
AIMMyselfContact* mc = new AIMMyselfContact( this );
setMyself( mc );
myself()->setOnlineStatus( static_cast<AIMProtocol*>( parent )->statusOffline );
TQString profile = configGroup()->readEntry( "Profile",
i18n( "Visit the Kopete website at <a href=\"http://trinitydesktop.org\">http://trinitydesktop.org</a>") );
mc->setOwnProfile( profile );
m_joinChatDialog = 0;
m_visibilityDialog = 0;
TQObject::connect( Kopete::ContactList::self(),
TQT_SIGNAL( globalIdentityChanged( const TQString&, const TQVariant& ) ),
this,
TQT_SLOT( slotGlobalIdentityChanged( const TQString&, const TQVariant& ) ) );
TQObject::connect( engine(), TQT_SIGNAL( chatRoomConnected( WORD, const TQString& ) ),
this, TQT_SLOT( connectedToChatRoom( WORD, const TQString& ) ) );
TQObject::connect( engine(), TQT_SIGNAL( userJoinedChat( Oscar::WORD, const TQString&, const TQString& ) ),
this, TQT_SLOT( userJoinedChat( Oscar::WORD, const TQString&, const TQString& ) ) );
TQObject::connect( engine(), TQT_SIGNAL( userLeftChat( Oscar::WORD, const TQString&, const TQString& ) ),
this, TQT_SLOT( userLeftChat( Oscar::WORD, const TQString&, const TQString& ) ) );
TQObject::connect( this, TQT_SIGNAL( buddyIconChanged() ), this, TQT_SLOT( slotBuddyIconChanged() ) );
}
AIMAccount::~AIMAccount()
{
}
OscarContact *AIMAccount::createNewContact( const TQString &contactId, Kopete::MetaContact *parentContact, const SSI& ssiItem )
{
AIMContact* contact = new AIMContact( this, contactId, parentContact, TQString(), ssiItem );
if ( !ssiItem.alias().isEmpty() )
contact->setProperty( Kopete::Global::Properties::self()->nickName(), ssiItem.alias() );
return contact;
}
TQString AIMAccount::sanitizedMessage( const TQString& message )
{
TQDomDocument doc;
TQString domError;
int errLine = 0, errCol = 0;
doc.setContent( message, false, &domError, &errLine, &errCol );
if ( !domError.isEmpty() ) //error parsing, do nothing
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "error from dom document conversion: "
<< domError << endl;
return message;
}
else
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "conversion to dom document successful."
<< "looking for font tags" << endl;
TQDomNodeList fontTagList = doc.elementsByTagName( "font" );
if ( fontTagList.count() == 0 )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "No font tags found. Returning normal message" << endl;
return message;
}
else
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Found font tags. Attempting replacement" << endl;
uint numFontTags = fontTagList.count();
for ( uint i = 0; i < numFontTags; i++ )
{
TQDomNode fontNode = fontTagList.item(i);
TQDomElement fontEl;
if ( !fontNode.isNull() && fontNode.isElement() )
fontEl = fontTagList.item(i).toElement();
else
continue;
if ( fontEl.hasAttribute( "back" ) )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Found attribute to replace. Doing replacement" << endl;
TQString backgroundColor = fontEl.attribute( "back" );
backgroundColor.insert( 0, "background-color: " );
backgroundColor.append( ';' );
fontEl.setAttribute( "style", backgroundColor );
fontEl.removeAttribute( "back" );
}
}
}
}
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "sanitized message is " << doc.toString();
return doc.toString();
}
TDEActionMenu* AIMAccount::actionMenu()
{
// kdDebug(14152) << k_funcinfo << accountId() << ": Called." << endl;
// mActionMenu is managed by Kopete::Account. It is deleted when
// it is no longer shown, so we can (safely) just make a new one here.
TDEActionMenu *mActionMenu = new TDEActionMenu(accountId(),
myself()->onlineStatus().iconFor( this ), this, "AIMAccount::mActionMenu");
AIMProtocol *p = AIMProtocol::protocol();
TQString accountNick = myself()->property( Kopete::Global::Properties::self()->nickName() ).value().toString();
mActionMenu->popupMenu()->insertTitle( myself()->onlineStatus().iconFor( myself() ),
i18n( "%2 <%1>" ).arg( accountId(), accountNick ));
mActionMenu->insert( new TDEAction( i18n("Online"), p->statusOnline.iconFor( this ), 0, this,
TQT_SLOT( slotGoOnline() ), mActionMenu, "AIMAccount::mActionOnline") );
TDEAction* mActionAway = new Kopete::AwayAction(i18n("Away"), p->statusAway.iconFor( this ), 0, this,
TQT_SLOT(slotGoAway( const TQString & )), this, "AIMAccount::mActionNA" );
mActionAway->setEnabled( isConnected() );
mActionMenu->insert( mActionAway );
TDEAction* mActionOffline = new TDEAction( i18n("Offline"), p->statusOffline.iconFor(this), 0, this,
TQT_SLOT( slotGoOffline() ), mActionMenu, "AIMAccount::mActionOffline");
mActionMenu->insert( mActionOffline );
mActionMenu->popupMenu()->insertSeparator();
TDEAction* m_joinChatAction = new TDEAction( i18n( "Join Chat..." ), TQString(), 0, this,
TQT_SLOT( slotJoinChat() ), mActionMenu, "join_a_chat" );
mActionMenu->insert( new TDEToggleAction( i18n( "Set Visibility..." ), 0, 0,
this, TQT_SLOT( slotSetVisiblility() ), this,
"AIMAccount::mActionSetVisibility") );
mActionMenu->insert( m_joinChatAction );
TDEAction* m_editInfoAction = new TDEAction( i18n( "Edit User Info..." ), "identity", 0,
this, TQT_SLOT( slotEditInfo() ), mActionMenu, "actionEditInfo");
mActionMenu->insert( m_editInfoAction );
return mActionMenu;
}
void AIMAccount::setAway(bool away, const TQString &awayReason)
{
// kdDebug(14152) << k_funcinfo << accountId() << "reason is " << awayReason << endl;
if ( away )
{
engine()->setStatus( Client::Away, awayReason );
AIMMyselfContact* me = static_cast<AIMMyselfContact *> ( myself() );
me->setLastAwayMessage(awayReason);
me->setProperty( Kopete::Global::Properties::self()->awayMessage(), awayReason );
}
else
{
engine()->setStatus( Client::Online );
AIMMyselfContact* me = static_cast<AIMMyselfContact *> ( myself() );
me->setLastAwayMessage(TQString());
me->removeProperty( Kopete::Global::Properties::self()->awayMessage() );
}
}
void AIMAccount::setOnlineStatus( const Kopete::OnlineStatus& status, const TQString& reason )
{
kdDebug(14152) << k_funcinfo << "called with reason = " << reason <<" status = "<< status.status() << endl;;
if ( status.status() == Kopete::OnlineStatus::Online )
setAway( false );
if ( status.status() == Kopete::OnlineStatus::Away )
setAway( true, reason );
}
void AIMAccount::setUserProfile(const TQString &profile)
{
kdDebug(14152) << k_funcinfo << "called." << endl;
AIMMyselfContact* aimmc = dynamic_cast<AIMMyselfContact*>( myself() );
if ( aimmc )
aimmc->setOwnProfile( profile );
configGroup()->writeEntry( TQString::fromLatin1( "Profile" ), profile );
}
void AIMAccount::slotEditInfo()
{
if ( !isConnected() )
{
KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
i18n( "Editing your user info is not possible because "
"you are not connected." ),
i18n( "Unable to edit user info" ) );
return;
}
AIMUserInfoDialog *myInfo = new AIMUserInfoDialog(static_cast<AIMContact *>( myself() ), this, true, 0L, "myInfo");
myInfo->exec(); // This is a modal dialog
}
void AIMAccount::slotGlobalIdentityChanged( const TQString& key, const TQVariant& value )
{
//do something with the photo
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Global identity changed" << endl;
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "key: " << key << endl;
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "value: " << value << endl;
if( !configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) )
{
if ( key == Kopete::Global::Properties::self()->nickName().key() )
{
//edit ssi item to change alias (if possible)
}
if ( key == Kopete::Global::Properties::self()->photo().key() )
{
setBuddyIcon( value.toString() );
}
}
}
void AIMAccount::slotBuddyIconChanged()
{
// need to disconnect because we could end up with many connections
TQObject::disconnect( engine(), TQT_SIGNAL( iconServerConnected() ), this, TQT_SLOT( slotBuddyIconChanged() ) );
if ( !engine()->isActive() )
{
TQObject::connect( engine(), TQT_SIGNAL( iconServerConnected() ), this, TQT_SLOT( slotBuddyIconChanged() ) );
return;
}
TQString photoPath = myself()->property( Kopete::Global::Properties::self()->photo() ).value().toString();
SSIManager* ssi = engine()->ssiManager();
Oscar::SSI item = ssi->findItemForIconByRef( 1 );
if ( photoPath.isEmpty() )
{
if ( item )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Removing icon hash item from ssi" << endl;
Oscar::SSI s(item);
//remove hash and alias
TQValueList<TLV> tList( item.tlvList() );
TLV t = Oscar::findTLV( tList, 0x00D5 );
if ( t )
tList.remove( t );
item.setTLVList( tList );
//s is old, item is new. modification will occur
engine()->modifySSIItem( s, item );
}
}
else
{
TQFile iconFile( photoPath );
iconFile.open( IO_ReadOnly );
KMD5 iconHash;
iconHash.update( *TQT_TQIODEVICE(&iconFile) );
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "hash is :" << iconHash.hexDigest() << endl;
//find old item, create updated item
if ( !item )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "no existing icon hash item in ssi. creating new" << endl;
TLV t;
t.type = 0x00D5;
t.data.resize( 18 );
t.data[0] = 0x00;
t.data[1] = 0x10;
memcpy(t.data.data() + 2, iconHash.rawDigest(), 16);
t.length = t.data.size();
TQValueList<Oscar::TLV> list;
list.append( t );
Oscar::SSI s( "1", 0, ssi->nextContactId(), ROSTER_BUDDYICONS, list );
//item is a non-valid ssi item, so the function will add an item
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "setting new icon item" << endl;
engine()->modifySSIItem( item, s );
}
else
{ //found an item
Oscar::SSI s(item);
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "modifying old item in ssi." << endl;
TQValueList<TLV> tList( item.tlvList() );
TLV t = Oscar::findTLV( tList, 0x00D5 );
if ( t )
tList.remove( t );
else
t.type = 0x00D5;
t.data.resize( 18 );
t.data[0] = 0x00;
t.data[1] = 0x10;
memcpy(t.data.data() + 2, iconHash.rawDigest(), 16);
t.length = t.data.size();
tList.append( t );
item.setTLVList( tList );
//s is old, item is new. modification will occur
engine()->modifySSIItem( s, item );
}
iconFile.close();
}
}
void AIMAccount::slotJoinChat()
{
if ( !isConnected() )
{
KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
i18n( "Joining an AIM chat room is not possible because "
"you are not connected." ),
i18n( "Unable to Join AIM Chat Room" ) );
return;
}
//get the exchange info
//create the dialog
//join the chat room
if ( !m_joinChatDialog )
{
m_joinChatDialog = new AIMJoinChatUI( this, false, Kopete::UI::Global::mainWidget() );
TQObject::connect( m_joinChatDialog, TQT_SIGNAL( closing( int ) ),
this, TQT_SLOT( joinChatDialogClosed( int ) ) );
TQValueList<int> list = engine()->chatExchangeList();
m_joinChatDialog->setExchangeList( list );
m_joinChatDialog->show();
}
else
m_joinChatDialog->raise();
}
void AIMAccount::slotGoOnline()
{
if ( myself()->onlineStatus().status() == Kopete::OnlineStatus::Away )
{
kdDebug(14152) << k_funcinfo << accountId() << " was away. welcome back." << endl;
engine()->setStatus( Client::Online );
myself()->removeProperty( Kopete::Global::Properties::self()->awayMessage() );
}
else if ( myself()->onlineStatus().status() == Kopete::OnlineStatus::Offline )
{
kdDebug(14152) << k_funcinfo << accountId() << " was offline. time to connect" << endl;
OscarAccount::connect();
}
else
{
kdDebug(14152) << k_funcinfo << accountId() << " is already online, doing nothing" << endl;
}
}
void AIMAccount::slotGoAway(const TQString &message)
{
kdDebug(14152) << k_funcinfo << message << endl;
setAway(true, message);
}
void AIMAccount::joinChatDialogClosed( int code )
{
if ( code == TQDialog::Accepted )
{
//join the chat
kdDebug(14152) << k_funcinfo << "chat accepted." << endl;
engine()->joinChatRoom( m_joinChatDialog->roomName(),
m_joinChatDialog->exchange().toInt() );
}
m_joinChatDialog->delayedDestruct();
m_joinChatDialog = 0L;
}
void AIMAccount::loginActions()
{
OscarAccount::loginActions();
using namespace AIM::PrivacySettings;
int privacySetting = this->configGroup()->readNumEntry( "PrivacySetting", AllowAll );
this->setPrivacySettings( privacySetting );
}
void AIMAccount::disconnected( DisconnectReason reason )
{
kdDebug( OSCAR_AIM_DEBUG ) << k_funcinfo << "Attempting to set status offline" << endl;
myself()->setOnlineStatus( static_cast<AIMProtocol*>( protocol() )->statusOffline );
TQDictIterator<Kopete::Contact> it( contacts() );
for( ; it.current(); ++it )
{
OscarContact* oc = dynamic_cast<OscarContact*>( it.current() );
if ( oc )
oc->setOnlineStatus( static_cast<AIMProtocol*>( protocol() )->statusOffline );
}
OscarAccount::disconnected( reason );
}
void AIMAccount::messageReceived( const Oscar::Message& message )
{
kdDebug(14152) << k_funcinfo << " Got a message, calling OscarAccount::messageReceived" << endl;
// Want to call the parent to do everything else
if ( message.type() != 0x0003 )
{
OscarAccount::messageReceived(message);
// Check to see if our status is away, and send an away message
// Might be duplicate code from the parent class to get some needed information
// Perhaps a refactoring is needed.
kdDebug(14152) << k_funcinfo << "Checking to see if I'm online.." << endl;
if( myself()->onlineStatus().status() == Kopete::OnlineStatus::Away )
{
TQString sender = Oscar::normalize( message.sender() );
AIMContact* aimSender = static_cast<AIMContact *> ( contacts()[sender] ); //should exist now
if ( !aimSender )
{
kdWarning(OSCAR_RAW_DEBUG) << "For some reason, could not get the contact "
<< "That this message is from: " << message.sender() << ", Discarding message" << endl;
return;
}
// Create, or get, a chat session with the contact
Kopete::ChatSession* chatSession = aimSender->manager( Kopete::Contact::CanCreate );
// get the away message we have set
AIMMyselfContact* myContact = static_cast<AIMMyselfContact *> ( myself() );
TQString msg = myContact->lastAwayMessage();
kdDebug(14152) << k_funcinfo << "Got away message: " << msg << endl;
// Create the message
Kopete::Message chatMessage( myself(), aimSender, msg, Kopete::Message::Outbound,
Kopete::Message::RichText );
kdDebug(14152) << k_funcinfo << "Sending autoresponse" << endl;
// Send the message
aimSender->sendAutoResponse( chatMessage );
}
}
if ( message.type() == 0x0003 )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "have chat message" << endl;
//handle chat room messages seperately
TQValueList<Kopete::ChatSession*> chats = Kopete::ChatSessionManager::self()->sessions();
TQValueList<Kopete::ChatSession*>::iterator it, itEnd = chats.end();
for ( it = chats.begin(); it != itEnd; ++it )
{
Kopete::ChatSession* kcs = ( *it );
AIMChatSession* session = dynamic_cast<AIMChatSession*>( kcs );
if ( !session )
continue;
if ( session->exchange() == message.exchange() &&
Oscar::normalize( session->roomName() ) ==
Oscar::normalize( message.chatRoom() ) )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "found chat session for chat room" << endl;
Kopete::Contact* ocSender = contacts()[Oscar::normalize( message.sender() )];
//sanitize;
TQString sanitizedMsg = sanitizedMessage( message.text( defaultCodec() ) );
Kopete::ContactPtrList me;
me.append( myself() );
Kopete::Message chatMessage( message.timestamp(), ocSender, me, sanitizedMsg,
Kopete::Message::Inbound, Kopete::Message::RichText );
session->appendMessage( chatMessage );
}
}
}
}
void AIMAccount::connectedToChatRoom( WORD exchange, const TQString& room )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Creating chat room session" << endl;
Kopete::ContactPtrList emptyList;
AIMMyselfContact* me = static_cast<AIMMyselfContact*>( myself() );
AIMChatSession* session = dynamic_cast<AIMChatSession*>( me->manager( Kopete::Contact::CanCreate,
exchange, room ) );
session->setDisplayName( room );
if ( session->view( true ) )
session->raiseView();
}
void AIMAccount::userJoinedChat( WORD exchange, const TQString& room, const TQString& contact )
{
if ( Oscar::normalize( contact ) == Oscar::normalize( myself()->contactId() ) )
return;
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "user " << contact << " has joined the chat" << endl;
TQValueList<Kopete::ChatSession*> chats = Kopete::ChatSessionManager::self()->sessions();
TQValueList<Kopete::ChatSession*>::iterator it, itEnd = chats.end();
for ( it = chats.begin(); it != itEnd; ++it )
{
Kopete::ChatSession* kcs = ( *it );
AIMChatSession* session = dynamic_cast<AIMChatSession*>( kcs );
if ( !session )
continue;
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << session->exchange() << " " << exchange << endl;
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << session->roomName() << " " << room << endl;
if ( session->exchange() == exchange && session->roomName() == room )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "found correct chat session" << endl;
Kopete::Contact* c;
if ( contacts()[Oscar::normalize( contact )] )
c = contacts()[Oscar::normalize( contact )];
else
{
Kopete::MetaContact* mc = addContact( Oscar::normalize( contact ),
contact, 0, Kopete::Account::Temporary );
if ( !mc )
kdWarning(OSCAR_AIM_DEBUG) << "Unable to add contact for chat room" << endl;
c = mc->contacts().first();
c->setNickName( contact );
}
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "adding contact" << endl;
session->addContact( c, static_cast<AIMProtocol*>( protocol() )->statusOnline, true /* suppress */ );
}
}
}
void AIMAccount::userLeftChat( WORD exchange, const TQString& room, const TQString& contact )
{
if ( Oscar::normalize( contact ) == Oscar::normalize( myself()->contactId() ) )
return;
TQValueList<Kopete::ChatSession*> chats = Kopete::ChatSessionManager::self()->sessions();
TQValueList<Kopete::ChatSession*>::iterator it, itEnd = chats.end();
for ( it = chats.begin(); it != itEnd; ++it )
{
Kopete::ChatSession* kcs = ( *it );
AIMChatSession* session = dynamic_cast<AIMChatSession*>( kcs );
if ( !session )
continue;
if ( session->exchange() == exchange && session->roomName() == room )
{
//delete temp contact
Kopete::Contact* c = contacts()[Oscar::normalize( contact )];
if ( !c )
{
kdWarning(OSCAR_AIM_DEBUG) << k_funcinfo << "couldn't find the contact that's left the chat!" << endl;
continue;
}
session->removeContact( c );
Kopete::MetaContact* mc = c->metaContact();
if ( mc->isTemporary() )
{
mc->removeContact( c );
delete c;
delete mc;
}
}
}
}
void AIMAccount::connectWithPassword( const TQString & )
{
kdDebug(14152) << k_funcinfo << "accountId='" << accountId() << "'" << endl;
// Get the screen name for this account
TQString screenName = accountId();
TQString server = configGroup()->readEntry( "Server", TQString::fromLatin1( "iwarg.ddns.net" ) );
uint port = configGroup()->readNumEntry( "Port", 5190 );
Connection* c = setupConnection( server, port );
TQString _password = password().cachedValue();
if ( _password.isEmpty() )
{
kdDebug(14150) << "Kopete is unable to attempt to sign-on to the "
<< "AIM network because no password was specified in the "
<< "preferences." << endl;
}
else if ( myself()->onlineStatus() == static_cast<AIMProtocol*>( protocol() )->statusOffline )
{
kdDebug(14152) << k_funcinfo << "Logging in as " << accountId() << endl ;
updateVersionUpdaterStamp();
engine()->start( server, port, accountId(), _password );
engine()->connectToServer( c, server, true /* doAuth */ );
myself()->setOnlineStatus( static_cast<AIMProtocol*>( protocol() )->statusConnecting );
}
}
void AIMAccount::slotSetVisiblility()
{
if( !isConnected() )
{
KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
i18n("You must be online to set users visibility."),
i18n("ICQ Plugin") );
return;
}
if ( !m_visibilityDialog )
{
m_visibilityDialog = new OscarVisibilityDialog( engine(), Kopete::UI::Global::mainWidget() );
TQObject::connect( m_visibilityDialog, TQT_SIGNAL( closing() ),
this, TQT_SLOT( slotVisibilityDialogClosed() ) );
//add all contacts;
OscarVisibilityDialog::ContactMap contactMap;
TQMap<TQString, TQString> revContactMap;
TQValueList<Oscar::SSI> contactList = engine()->ssiManager()->contactList();
TQValueList<Oscar::SSI>::const_iterator it, cEnd = contactList.constEnd();
for ( it = contactList.constBegin(); it != cEnd; ++it )
{
TQString contactId = ( *it ).name();
OscarContact* oc = dynamic_cast<OscarContact*>( contacts()[( *it ).name()] );
if ( oc )
{
contactMap.insert( oc->nickName(), contactId );
revContactMap.insert( contactId, oc->nickName() );
}
else
{
contactMap.insert( contactId, contactId );
revContactMap.insert( contactId, contactId );
}
}
m_visibilityDialog->addContacts( contactMap );
//add contacts from visible list
TQStringList tmpList;
contactList = engine()->ssiManager()->visibleList();
cEnd = contactList.constEnd();
for ( it = contactList.constBegin(); it != cEnd; ++it )
tmpList.append( revContactMap[( *it ).name()] );
m_visibilityDialog->addVisibleContacts( tmpList );
//add contacts from invisible list
tmpList.clear();
contactList = engine()->ssiManager()->invisibleList();
cEnd = contactList.constEnd();
for ( it = contactList.constBegin(); it != cEnd; ++it )
tmpList.append( revContactMap[( *it ).name()] );
m_visibilityDialog->addInvisibleContacts( tmpList );
m_visibilityDialog->resize( 550, 350 );
m_visibilityDialog->show();
}
else
{
m_visibilityDialog->raise();
}
}
void AIMAccount::slotVisibilityDialogClosed()
{
m_visibilityDialog->delayedDestruct();
m_visibilityDialog = 0L;
}
void AIMAccount::setPrivacySettings( int privacy )
{
using namespace AIM::PrivacySettings;
BYTE privacyByte = 0x01;
DWORD userClasses = 0xFFFFFFFF;
switch ( privacy )
{
case AllowAll:
privacyByte = 0x01;
break;
case BlockAll:
privacyByte = 0x02;
break;
case AllowPremitList:
privacyByte = 0x03;
break;
case BlockDenyList:
privacyByte = 0x04;
break;
case AllowMyContacts:
privacyByte = 0x05;
break;
case BlockAIM:
privacyByte = 0x01;
userClasses = 0x00000004;
break;
}
this->setPrivacyTLVs( privacyByte, userClasses );
}
void AIMAccount::setPrivacyTLVs( BYTE privacy, DWORD userClasses )
{
SSIManager* ssi = engine()->ssiManager();
Oscar::SSI item = ssi->findItem( TQString(), ROSTER_VISIBILITY );
TQValueList<Oscar::TLV> tList;
tList.append( TLV( 0x00CA, 1, (char *)&privacy ) );
tList.append( TLV( 0x00CB, sizeof(userClasses), (char *)&userClasses ) );
if ( !item )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Adding new privacy TLV item" << endl;
Oscar::SSI s( TQString(), 0, ssi->nextContactId(), ROSTER_VISIBILITY, tList );
engine()->modifySSIItem( item, s );
}
else
{ //found an item
Oscar::SSI s(item);
if ( Oscar::uptateTLVs( s, tList ) == true )
{
kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Updating privacy TLV item" << endl;
engine()->modifySSIItem( item, s );
}
}
}
#include "aimaccount.moc"