diff options
Diffstat (limited to 'kopete/protocols/oscar')
71 files changed, 4944 insertions, 66 deletions
diff --git a/kopete/protocols/oscar/CMakeLists.txt b/kopete/protocols/oscar/CMakeLists.txt index 9491dadf..bbffa100 100644 --- a/kopete/protocols/oscar/CMakeLists.txt +++ b/kopete/protocols/oscar/CMakeLists.txt @@ -10,6 +10,7 @@ ################################################# add_subdirectory( liboscar ) +add_subdirectory( aim ) add_subdirectory( icq ) add_subdirectory( icons ) diff --git a/kopete/protocols/oscar/Makefile.am b/kopete/protocols/oscar/Makefile.am index 3fce9e09..93f1f859 100644 --- a/kopete/protocols/oscar/Makefile.am +++ b/kopete/protocols/oscar/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = liboscar . icq icons +SUBDIRS = liboscar . aim icq icons METASOURCES = AUTO AM_CPPFLAGS = -I./ui -I$(srcdir)/ui \ -I./liboscar -I$(srcdir)/liboscar \ diff --git a/kopete/protocols/oscar/TODO b/kopete/protocols/oscar/TODO index 3e20780e..25c82ee8 100644 --- a/kopete/protocols/oscar/TODO +++ b/kopete/protocols/oscar/TODO @@ -2,6 +2,7 @@ This is the TODO file for the OSCAR plugin. ====== Possible refactorings ===== +- Unify status handling for ICQ and AIM? I like the ICQ::Presence thing, that's cool - Do delayed contact creation like on MSN so that when we actually get a good status code back from the SSI manipulation, we create the contact then rather than hoping it all works out. @@ -46,6 +47,7 @@ that was done in oscarsocket, that will need redoing in liboscar for the same account, one at home and one at work). - make renaming serverside contacts possible (function is there but fails due to massive contactlist bugs caused by above mentioned classes) +- support logging in with something different than "online" status for AIM - finish icq userinfo dialog and sending your own icq userinfo to the server, it's easy to do but because of the mass of items takes lots of time and is extremely boring. (requires snac 0x15, * parsing) diff --git a/kopete/protocols/oscar/aim/CMakeLists.txt b/kopete/protocols/oscar/aim/CMakeLists.txt new file mode 100644 index 00000000..75230df3 --- /dev/null +++ b/kopete/protocols/oscar/aim/CMakeLists.txt @@ -0,0 +1,47 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +add_subdirectory( ui ) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/ui + ${CMAKE_CURRENT_SOURCE_DIR}/ui + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/../liboscar + ${CMAKE_SOURCE_DIR}/kopete/libkopete + ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### other data ################################ + +install( FILES + kopete_aim.desktop aim.protocol + DESTINATION ${SERVICES_INSTALL_DIR} ) + + +##### kopete_aim (module) ####################### + +tde_add_kpart( kopete_aim AUTOMOC + SOURCES + aimprotocol.cpp aimaccount.cpp aimcontact.cpp aimuserinfo.cpp + aimjoinchat.cpp aimchatsession.cpp + LINK + kopeteaimui-static kopete_oscar-shared + DESTINATION ${PLUGIN_INSTALL_DIR} +) diff --git a/kopete/protocols/oscar/aim/Makefile.am b/kopete/protocols/oscar/aim/Makefile.am new file mode 100644 index 00000000..5d1cc8b6 --- /dev/null +++ b/kopete/protocols/oscar/aim/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = ui +METASOURCES = AUTO +AM_CPPFLAGS = -I$(srcdir)/../ \ + -I$(srcdir)/ui/ \ + -I$(top_builddir)/kopete/protocols/oscar/aim/ui \ + -I$(srcdir)/../liboscar \ + $(KOPETE_INCLUDES) $(all_includes) + +kde_module_LTLIBRARIES = kopete_aim.la + +kopete_aim_la_SOURCES = aimprotocol.cpp aimaccount.cpp aimcontact.cpp aimuserinfo.cpp aimjoinchat.cpp aimchatsession.cpp + +kopete_aim_la_LDFLAGS = -no-undefined -module $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor +kopete_aim_la_LIBADD = ../libkopete_oscar.la ui/libkopeteaimui.la \ + $(top_builddir)/kopete/libkopete/libkopete.la + +service_DATA = kopete_aim.desktop aim.protocol +servicedir = $(kde_servicesdir) diff --git a/kopete/protocols/oscar/aim/aim.protocol b/kopete/protocols/oscar/aim/aim.protocol new file mode 100644 index 00000000..0af5be59 --- /dev/null +++ b/kopete/protocols/oscar/aim/aim.protocol @@ -0,0 +1,13 @@ +[Protocol] +exec=kopete "%u" +protocol=aim +input=none +output=none +helper=true +listing=false +reading=false +writing=false +makedir=false +deleting=false +URIMode=rawuri +Icon=aim_protocol diff --git a/kopete/protocols/oscar/aim/aimaccount.cpp b/kopete/protocols/oscar/aim/aimaccount.cpp new file mode 100644 index 00000000..f6be26b7 --- /dev/null +++ b/kopete/protocols/oscar/aim/aimaccount.cpp @@ -0,0 +1,924 @@ +/* + 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://kopete.kde.org\">http://kopete.kde.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( "login.oscar.aol.com" ) ); + 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" +//kate: tab-width 4; indent-mode csands; diff --git a/kopete/protocols/oscar/aim/aimaccount.h b/kopete/protocols/oscar/aim/aimaccount.h new file mode 100644 index 00000000..63adeac7 --- /dev/null +++ b/kopete/protocols/oscar/aim/aimaccount.h @@ -0,0 +1,148 @@ +/* + AIMAccount - Oscar Protocol Account + + Copyright (c) 2002 by Chris TenHarmsel <tenharmsel@staticmethod.net> + + Kopete (c) 2002 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. * + * * + ************************************************************************* + +*/ + +#ifndef AIMACCOUNT_H +#define AIMACCOUNT_H + +#include <tqdict.h> +#include <tqstring.h> +#include <tqwidget.h> +#include "oscartypeclasses.h" + +#include "oscaraccount.h" +#include "oscarmyselfcontact.h" + +namespace AIM +{ + namespace PrivacySettings + { + enum { AllowAll = 0, AllowMyContacts, AllowPremitList, BlockAll, BlockAIM, BlockDenyList }; + } +} + +namespace Kopete +{ +class Contact; +class Group; +class ChatSession; +} + +class TDEAction; +class OscarContact; +class AIMContact; +class AIMAccount; +class AIMJoinChatUI; +class AIMChatSession; +class OscarVisibilityDialog; + +class AIMMyselfContact : public OscarMyselfContact +{ +Q_OBJECT + +public: + AIMMyselfContact( AIMAccount *acct ); + void userInfoUpdated(); + void setOwnProfile( const TQString& newProfile ); + TQString userProfile(); + void setLastAwayMessage( const TQString& msg) {m_lastAwayMessage = msg;} + TQString lastAwayMessage() { return m_lastAwayMessage; }; + + virtual Kopete::ChatSession* manager( Kopete::Contact::CanCreateFlags = Kopete::Contact::CannotCreate, + WORD exchange = 0, const TQString& room = TQString()); + +public slots: + void sendMessage( Kopete::Message&, Kopete::ChatSession* session ); + void chatSessionDestroyed( Kopete::ChatSession* ); + +private: + TQString m_profileString; + AIMAccount* m_acct; + /** + * There has GOT to be a better way to get this away message + */ + TQString m_lastAwayMessage; + TQValueList<Kopete::ChatSession*> m_chatRoomSessions; + + +}; + +class AIMAccount : public OscarAccount +{ +Q_OBJECT + + +public: + AIMAccount(Kopete::Protocol *parent, TQString accountID, const char *name=0L); + virtual ~AIMAccount(); + + // Accessor method for the action menu + virtual TDEActionMenu* actionMenu(); + + void setAway(bool away, const TQString &awayReason = TQString() ); + + virtual void connectWithPassword( const TQString &password ); + + void setUserProfile(const TQString &profile); + + void setPrivacySettings( int privacy ); + +public slots: + /** Reimplementation from Kopete::Account */ + void setOnlineStatus( const Kopete::OnlineStatus& status, const TQString& reason = TQString() ); + void slotEditInfo(); + void slotGoOnline(); + + void slotGlobalIdentityChanged( const TQString&, const TQVariant& ); + void slotBuddyIconChanged(); + + void slotJoinChat(); + +protected slots: + void slotGoAway(const TQString&); + void joinChatDialogClosed( int ); + + virtual void loginActions(); + virtual void disconnected( Kopete::Account::DisconnectReason reason ); + virtual void messageReceived( const Oscar::Message& message ); + + void connectedToChatRoom( WORD exchange, const TQString& roomName ); + void userJoinedChat( Oscar::WORD exchange, const TQString& room, const TQString& contact ); + void userLeftChat( Oscar::WORD exchange, const TQString& room, const TQString& contact ); + + void slotSetVisiblility(); + void slotVisibilityDialogClosed(); + +protected: + + /** + * Implement virtual method from OscarAccount + * This allows OscarAccount to take care of adding new contacts + */ + OscarContact *createNewContact( const TQString &contactId, Kopete::MetaContact *parentContact, const SSI& ssiItem ); + + TQString sanitizedMessage( const TQString& message ); + +private: + // Set privacy tlv item + void setPrivacyTLVs( BYTE privacy, DWORD userClasses ); + + AIMJoinChatUI* m_joinChatDialog; + OscarVisibilityDialog* m_visibilityDialog; +}; +#endif +//kate: tab-width 4; indent-mode csands; diff --git a/kopete/protocols/oscar/aim/aimchatsession.cpp b/kopete/protocols/oscar/aim/aimchatsession.cpp new file mode 100644 index 00000000..10938a6a --- /dev/null +++ b/kopete/protocols/oscar/aim/aimchatsession.cpp @@ -0,0 +1,73 @@ +// aimchatsession.cpp + +// Copyright (C) 2005 Matt Rogers <mattr@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. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +// 02110-1301, USA. + + +#include "aimchatsession.h" +#include "kopetecontact.h" +#include "kopetechatsessionmanager.h" +#include "kopeteprotocol.h" +#include "client.h" + +AIMChatSession::AIMChatSession( const Kopete::Contact* user, Kopete::ContactPtrList others, + Kopete::Protocol* protocol, Oscar::WORD exchange, + const TQString& room ) + + : Kopete::ChatSession( user, others, protocol, "AIMChatSession" ) +{ + Kopete::ChatSessionManager::self()->registerChatSession( this ); + setInstance( protocol->instance() ); + setMayInvite( false ); + m_exchange = exchange; + m_roomName = room; + m_engine = 0; +} + +AIMChatSession::~AIMChatSession() +{ + m_engine->disconnectChatRoom( m_exchange, m_roomName ); +} + +void AIMChatSession::setEngine( Client* engine ) +{ + m_engine = engine; +} + +TQString AIMChatSession::roomName() const +{ + + return m_roomName; +} + +void AIMChatSession::setRoomName( const TQString& room ) +{ + m_roomName = room; +} + +Oscar::WORD AIMChatSession::exchange() const +{ + return m_exchange; +} + +void AIMChatSession::setExchange( Oscar::WORD exchange ) +{ + m_exchange = exchange; +} + + +#include "aimchatsession.moc" diff --git a/kopete/protocols/oscar/aim/aimchatsession.h b/kopete/protocols/oscar/aim/aimchatsession.h new file mode 100644 index 00000000..b4e78e3d --- /dev/null +++ b/kopete/protocols/oscar/aim/aimchatsession.h @@ -0,0 +1,78 @@ +// aimchatsession.h +// Copyright (C) 2005 Matt Rogers <mattr@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. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA +// 02110-1301, USA. + +#ifndef AIMCHATSESSION_H +#define AIMCHATSESSION_H + +#include "kopetechatsession.h" +#include "oscartypes.h" + +class Client; + +class AIMChatSession : public Kopete::ChatSession +{ +Q_OBJECT + +public: + AIMChatSession( const Kopete::Contact* contact, Kopete::ContactPtrList others, + Kopete::Protocol* protocol, Oscar::WORD exchange = 0, + const TQString& room = TQString() ); + virtual ~AIMChatSession(); + + /** + * Set the engine to use so that we can disconnect from the chat service + * properly + */ + void setEngine( Client* engine ); + + /** + * Get the name of the AIM chat room represented by + * this ChatSession object + * @return the name of the chat room + */ + TQString roomName() const; + + /** + * Set the name of the AIM chat room represented by + * this ChatSession object + * @param room the name of the AIM chat room + */ + void setRoomName( const TQString& room ); + + /** + * Get the exchange of the AIM chat room represented by + * this ChatSession object + * @return the exchange of the chat room + */ + Oscar::WORD exchange() const; + + /** + * Set the exchange of the AIM chat room represented by + * this ChatSession object + * @param exchange the exchange of the AIM chat room + */ + void setExchange( Oscar::WORD exchange ); + +private: + TQString m_roomName; + Oscar::WORD m_exchange; + Client* m_engine; +}; + + +#endif diff --git a/kopete/protocols/oscar/aim/aimcontact.cpp b/kopete/protocols/oscar/aim/aimcontact.cpp new file mode 100644 index 00000000..2fa79bf1 --- /dev/null +++ b/kopete/protocols/oscar/aim/aimcontact.cpp @@ -0,0 +1,520 @@ +/* + aimcontact.cpp - Oscar Protocol Plugin + + Copyright (c) 2003 by Will Stephenson + Kopete (c) 2002-2004 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 <time.h> + +#include <tqimage.h> +#include <tqregexp.h> +#include <tqtimer.h> +#include <tqtextcodec.h> + +#include <tdeapplication.h> +#include <tdeactionclasses.h> +#include <tdelocale.h> +#include <kdebug.h> +#include <tdemessagebox.h> + +#include "kopeteaway.h" +#include "kopetechatsession.h" +#include "kopeteuiglobal.h" +#include "kopetemetacontact.h" + +//liboscar +#include "client.h" +#include "oscartypes.h" +#include "oscarutils.h" +#include "ssimanager.h" + +#include "aimprotocol.h" +#include "aimuserinfo.h" +#include "aimcontact.h" +#include "aimaccount.h" + +AIMContact::AIMContact( Kopete::Account* account, const TQString& name, Kopete::MetaContact* parent, + const TQString& icon, const Oscar::SSI& ssiItem ) +: OscarContact(account, name, parent, icon, ssiItem ) +{ + mProtocol=static_cast<AIMProtocol *>(protocol()); + setOnlineStatus( mProtocol->statusOffline ); + + m_infoDialog = 0L; + m_warnUserAction = 0L; + mUserProfile=""; + m_haveAwayMessage = false; + m_mobile = false; + // Set the last autoresponse time to the current time yesterday + m_lastAutoresponseTime = TQDateTime::currentDateTime().addDays(-1); + + TQObject::connect( mAccount->engine(), TQT_SIGNAL( receivedUserInfo( const TQString&, const UserDetails& ) ), + this, TQT_SLOT( userInfoUpdated( const TQString&, const UserDetails& ) ) ); + TQObject::connect( mAccount->engine(), TQT_SIGNAL( userIsOffline( const TQString& ) ), + this, TQT_SLOT( userOffline( const TQString& ) ) ); + TQObject::connect( mAccount->engine(), TQT_SIGNAL( receivedAwayMessage( const TQString&, const TQString& ) ), + this, TQT_SLOT( updateAwayMessage( const TQString&, const TQString& ) ) ); + TQObject::connect( mAccount->engine(), TQT_SIGNAL( receivedProfile( const TQString&, const TQString& ) ), + this, TQT_SLOT( updateProfile( const TQString&, const TQString& ) ) ); + TQObject::connect( mAccount->engine(), TQT_SIGNAL( userWarned( const TQString&, TQ_UINT16, TQ_UINT16 ) ), + this, TQT_SLOT( gotWarning( const TQString&, TQ_UINT16, TQ_UINT16 ) ) ); + TQObject::connect( mAccount->engine(), TQT_SIGNAL( haveIconForContact( const TQString&, TQByteArray ) ), + this, TQT_SLOT( haveIcon( const TQString&, TQByteArray ) ) ); + TQObject::connect( mAccount->engine(), TQT_SIGNAL( iconServerConnected() ), + this, TQT_SLOT( requestBuddyIcon() ) ); + TQObject::connect( this, TQT_SIGNAL( featuresUpdated() ), this, TQT_SLOT( updateFeatures() ) ); +} + +AIMContact::~AIMContact() +{ +} + +bool AIMContact::isReachable() +{ + return true; +} + +TQPtrList<TDEAction> *AIMContact::customContextMenuActions() +{ + + TQPtrList<TDEAction> *actionCollection = new TQPtrList<TDEAction>(); + if ( !m_warnUserAction ) + { + m_warnUserAction = new TDEAction( i18n( "&Warn User" ), 0, this, TQT_SLOT( warnUser() ), this, "warnAction" ); + } + m_actionVisibleTo = new TDEToggleAction(i18n("Always &Visible To"), "", 0, + this, TQT_SLOT(slotVisibleTo()), this, "actionVisibleTo"); + m_actionInvisibleTo = new TDEToggleAction(i18n("Always &Invisible To"), "", 0, + this, TQT_SLOT(slotInvisibleTo()), this, "actionInvisibleTo"); + + bool on = account()->isConnected(); + + m_warnUserAction->setEnabled( on ); + + m_actionVisibleTo->setEnabled(on); + m_actionInvisibleTo->setEnabled(on); + + SSIManager* ssi = account()->engine()->ssiManager(); + m_actionVisibleTo->setChecked( ssi->findItem( m_ssiItem.name(), ROSTER_VISIBLE )); + m_actionInvisibleTo->setChecked( ssi->findItem( m_ssiItem.name(), ROSTER_INVISIBLE )); + + actionCollection->append( m_warnUserAction ); + + actionCollection->append(m_actionVisibleTo); + actionCollection->append(m_actionInvisibleTo); + + + return actionCollection; +} + +const TQString AIMContact::awayMessage() +{ + return property(mProtocol->awayMessage).value().toString(); +} + +void AIMContact::setAwayMessage(const TQString &message) +{ + kdDebug(14152) << k_funcinfo << + "Called for '" << contactId() << "', away msg='" << message << "'" << endl; + TQString filteredMessage = message; + filteredMessage.replace( + TQRegExp(TQString::fromLatin1("<[hH][tT][mM][lL].*>(.*)</[hH][tT][mM][lL]>")), + TQString::fromLatin1("\\1")); + filteredMessage.replace( + TQRegExp(TQString::fromLatin1("<[bB][oO][dD][yY].*>(.*)</[bB][oO][dD][yY]>")), + TQString::fromLatin1("\\1") ); + TQRegExp fontRemover( TQString::fromLatin1("<[fF][oO][nN][tT].*>(.*)</[fF][oO][nN][tT]>") ); + fontRemover.setMinimal(true); + while ( filteredMessage.find( fontRemover ) != -1 ) + filteredMessage.replace( fontRemover, TQString::fromLatin1("\\1") ); + setProperty(mProtocol->awayMessage, filteredMessage); +} + +int AIMContact::warningLevel() const +{ + return m_warningLevel; +} + +void AIMContact::updateSSIItem() +{ + if ( m_ssiItem.type() != 0xFFFF && m_ssiItem.waitingAuth() == false && + onlineStatus() == Kopete::OnlineStatus::Unknown ) + { + //make sure they're offline + setOnlineStatus( static_cast<AIMProtocol*>( protocol() )->statusOffline ); + } +} + +void AIMContact::slotUserInfo() +{ + if ( !m_infoDialog) + { + m_infoDialog = new AIMUserInfoDialog( this, static_cast<AIMAccount*>( account() ), false, Kopete::UI::Global::mainWidget(), 0 ); + if( !m_infoDialog ) + return; + connect( m_infoDialog, TQT_SIGNAL( finished() ), this, TQT_SLOT( closeUserInfoDialog() ) ); + m_infoDialog->show(); + if ( mAccount->isConnected() ) + { + mAccount->engine()->requestAIMProfile( contactId() ); + mAccount->engine()->requestAIMAwayMessage( contactId() ); + } + } + else + m_infoDialog->raise(); +} + +void AIMContact::userInfoUpdated( const TQString& contact, const UserDetails& details ) +{ + if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) ) + return; + + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << contact << endl; + + //if they don't have an SSI alias, make sure we use the capitalization from the + //server so their contact id looks all pretty. + TQString nickname = property( Kopete::Global::Properties::self()->nickName() ).value().toString(); + if ( nickname.isEmpty() || Oscar::normalize( nickname ) == Oscar::normalize( contact ) ) + setNickName( contact ); + + ( details.userClass() & CLASS_WIRELESS ) ? m_mobile = true : m_mobile = false; + + if ( ( details.userClass() & CLASS_AWAY ) == STATUS_ONLINE ) + { + if ( m_mobile ) + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Contact: " << contact << " is mobile-online." << endl; + setOnlineStatus( mProtocol->statusWirelessOnline ); + } + else + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Contact: " << contact << " is online." << endl; + setOnlineStatus( mProtocol->statusOnline ); //we're online + } + removeProperty( mProtocol->awayMessage ); + m_haveAwayMessage = false; + } + else if ( ( details.userClass() & CLASS_AWAY ) ) // STATUS_AWAY + { + if ( m_mobile ) + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Contact: " << contact << " is mobile-away." << endl; + setOnlineStatus( mProtocol->statusWirelessOnline ); + } + else + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Contact: " << contact << " is away." << endl; + setOnlineStatus( mProtocol->statusAway ); //we're away + } + if ( !m_haveAwayMessage ) //prevent cyclic away message requests + { + mAccount->engine()->requestAIMAwayMessage( contactId() ); + m_haveAwayMessage = true; + } + } + else + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Contact: " << contact << " class " << details.userClass() << " is unhandled... defaulting to away." << endl; + setOnlineStatus( mProtocol->statusAway ); //we're away + if ( !m_haveAwayMessage ) //prevent cyclic away message requests + { + mAccount->engine()->requestAIMAwayMessage( contactId() ); + m_haveAwayMessage = true; + } + } + + if ( details.buddyIconHash().size() > 0 && details.buddyIconHash() != m_details.buddyIconHash() ) + { + if ( !mAccount->engine()->hasIconConnection() ) + mAccount->engine()->requestServerRedirect( 0x0010 ); + + int time = ( TDEApplication::random() % 10 ) * 1000; + kdDebug(OSCAR_ICQ_DEBUG) << k_funcinfo << "updating buddy icon in " << time/1000 << " seconds" << endl; + TQTimer::singleShot( time, this, TQT_SLOT( requestBuddyIcon() ) ); + } + + OscarContact::userInfoUpdated( contact, details ); +} + +void AIMContact::userOnline( const TQString& userId ) +{ + if ( Oscar::normalize( userId ) == Oscar::normalize( contactId() ) ) + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Getting more contact info" << endl; + setOnlineStatus( mProtocol->statusOnline ); + } +} + +void AIMContact::userOffline( const TQString& userId ) +{ + if ( Oscar::normalize( userId ) == Oscar::normalize( contactId() ) ) + { + setOnlineStatus( mProtocol->statusOffline ); + removeProperty( mProtocol->awayMessage ); + } +} + +void AIMContact::updateAwayMessage( const TQString& contact, const TQString& message ) +{ + if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) ) + return; + else + { + if ( message.isEmpty() ) + { + removeProperty( mProtocol->awayMessage ); + if ( !m_mobile ) + setOnlineStatus( mProtocol->statusOnline ); + else + setOnlineStatus( mProtocol->statusWirelessOnline ); + m_haveAwayMessage = false; + } + else + { + m_haveAwayMessage = true; + setAwayMessage( message ); + if ( !m_mobile ) + setOnlineStatus( mProtocol->statusAway ); + else + setOnlineStatus( mProtocol->statusWirelessAway ); + } + } + + emit updatedProfile(); +} + +void AIMContact::updateProfile( const TQString& contact, const TQString& profile ) +{ + if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) ) + return; + + setProperty( mProtocol->clientProfile, profile ); + emit updatedProfile(); +} + +void AIMContact::gotWarning( const TQString& contact, TQ_UINT16 increase, TQ_UINT16 newLevel ) +{ + //somebody just got bitchslapped! :O + Q_UNUSED( increase ); + if ( Oscar::normalize( contact ) == Oscar::normalize( contactId() ) ) + m_warningLevel = newLevel; + + //TODO add a KNotify event after merge to HEAD +} + +void AIMContact::requestBuddyIcon() +{ + kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Updating buddy icon for " << contactId() << endl; + if ( m_details.buddyIconHash().size() > 0 ) + { + account()->engine()->requestBuddyIcon( contactId(), m_details.buddyIconHash(), + m_details.iconCheckSumType() ); + } +} + +void AIMContact::haveIcon( const TQString& user, TQByteArray icon ) +{ + if ( Oscar::normalize( user ) != Oscar::normalize( contactId() ) ) + return; + + kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Updating icon for " << contactId() << endl; + TQImage buddyIcon( icon ); + if ( buddyIcon.isNull() ) + { + kdWarning(OSCAR_AIM_DEBUG) << k_funcinfo << "Failed to convert buddy icon to TQImage" << endl; + return; + } + + setProperty( Kopete::Global::Properties::self()->photo(), buddyIcon ); +} + +void AIMContact::closeUserInfoDialog() +{ + m_infoDialog->delayedDestruct(); + m_infoDialog = 0L; +} + +void AIMContact::warnUser() +{ + TQString nick = property( Kopete::Global::Properties::self()->nickName() ).value().toString(); + TQString message = i18n( "<qt>Would you like to warn %1 anonymously or with your name?<br>" \ + "(Warning a user on AIM will result in a \"Warning Level\"" \ + " increasing for the user you warn. Once this level has reached a" \ + " certain point, they will not be able to sign on. Please do not abuse" \ + " this function, it is meant for legitimate practices.)</qt>" ).arg( nick ); + + + int result = KMessageBox::questionYesNoCancel( Kopete::UI::Global::mainWidget(), message, + i18n( "Warn User %1?" ).arg( nick ), + i18n( "Warn Anonymously" ), i18n( "Warn" ) ); + + if ( result == KMessageBox::Yes ) + mAccount->engine()->sendWarning( contactId(), true); + else if ( result == KMessageBox::No ) + mAccount->engine()->sendWarning( contactId(), false); +} + +void AIMContact::slotVisibleTo() +{ + account()->engine()->setVisibleTo( contactId(), m_actionVisibleTo->isChecked() ); +} + +void AIMContact::slotInvisibleTo() +{ + account()->engine()->setInvisibleTo( contactId(), m_actionInvisibleTo->isChecked() ); +} + +void AIMContact::slotSendMsg(Kopete::Message& message, Kopete::ChatSession *) +{ + 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\">")); + + // strip left over line break + s.remove(TQRegExp(TQString::fromLatin1("<br\b[^>]*>$"))); + + s.replace ( TQRegExp ( TQString::fromLatin1("<br[ /]*>")), TQString::fromLatin1("<br>") ); + + // strip left over line break + s.remove( TQRegExp( TQString::fromLatin1( "<br>$" ) ) ); + + kdDebug(14190) << k_funcinfo << "sending " + << s << endl; + + // XXX Need to check for message size? + + if ( m_details.hasCap( CAP_UTF8 ) ) + msg.setText( Oscar::Message::UCS2, s ); + else + msg.setText( Oscar::Message::UserDefined, s, contactCodec() ); + + msg.setReceiver(mName); + msg.setTimestamp(message.timestamp()); + msg.setType(0x01); + + mAccount->engine()->sendMessage(msg); + + // Show the message we just sent in the chat window + manager(Kopete::Contact::CanCreate)->appendMessage(message); + manager(Kopete::Contact::CanCreate)->messageSucceeded(); +} + +void AIMContact::updateFeatures() +{ + setProperty( static_cast<AIMProtocol*>(protocol())->clientFeatures, m_clientFeatures ); +} + +void AIMContact::sendAutoResponse(Kopete::Message& msg) +{ + // The target time is 2 minutes later than the last message + int delta = m_lastAutoresponseTime.secsTo( TQDateTime::currentDateTime() ); + kdDebug(14152) << k_funcinfo << "Last autoresponse time: " << m_lastAutoresponseTime << endl; + kdDebug(14152) << k_funcinfo << "Current time: " << TQDateTime::currentDateTime() << endl; + kdDebug(14152) << k_funcinfo << "Difference: " << delta << endl; + // Check to see if we're past that time + if(delta > 120) + { + kdDebug(14152) << k_funcinfo << "Sending auto response" << endl; + + // This code was yoinked straight from OscarContact::slotSendMsg() + // If only that slot wasn't private, but I'm not gonna change it right now. + Oscar::Message message; + + if ( m_details.hasCap( CAP_UTF8 ) ) + { + message.setText( Oscar::Message::UCS2, msg.plainBody() ); + } + else + { + TQTextCodec* codec = contactCodec(); + message.setText( Oscar::Message::UserDefined, msg.plainBody(), codec ); + } + + message.setTimestamp( msg.timestamp() ); + message.setSender( mAccount->accountId() ); + message.setReceiver( mName ); + message.setType( 0x01 ); + + // isAuto defaults to false + mAccount->engine()->sendMessage( message, true); + kdDebug(14152) << k_funcinfo << "Sent auto response" << endl; + manager(Kopete::Contact::CanCreate)->appendMessage(msg); + manager(Kopete::Contact::CanCreate)->messageSucceeded(); + // Update the last autoresponse time + m_lastAutoresponseTime = TQDateTime::currentDateTime(); + } + else + { + kdDebug(14152) << k_funcinfo << "Not enough time since last autoresponse, NOT sending" << endl; + } +} +#include "aimcontact.moc" +//kate: tab-width 4; indent-mode csands; diff --git a/kopete/protocols/oscar/aim/aimcontact.h b/kopete/protocols/oscar/aim/aimcontact.h new file mode 100644 index 00000000..eea346ac --- /dev/null +++ b/kopete/protocols/oscar/aim/aimcontact.h @@ -0,0 +1,103 @@ +/* + aimcontact.h - Oscar Protocol Plugin + + Copyright (c) 2003 by Will Stephenson + Copyright (c) 2004 by Matt Rogers <mattr@kde.org> + Kopete (c) 2002-2004 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. * + * * + ************************************************************************* +*/ + +#ifndef AIMCONTACT_H +#define AIMCONTACT_H + +#include <tqdatetime.h> + +#include "oscarcontact.h" + + +namespace Kopete +{ +class ChatSession; +} + +class AIMAccount; +class AIMProtocol; +class AIMUserInfoDialog; + +class AIMContact : public OscarContact +{ +Q_OBJECT + + +public: + AIMContact( Kopete::Account*, const TQString&, Kopete::MetaContact*, + const TQString& icon = TQString(), const Oscar::SSI& ssiItem = Oscar::SSI() ); + virtual ~AIMContact(); + + bool isReachable(); + TQPtrList<TDEAction> *customContextMenuActions(); + + const TQString &userProfile() { return mUserProfile; } + + virtual const TQString awayMessage(); + virtual void setAwayMessage( const TQString &message ); + + int warningLevel() const; + + /** + * Gets the last time an autoresponse was sent to this contact + * @returns TQDateTime Object that represents the date/time + */ + TQDateTime lastAutoResponseTime() {return m_lastAutoresponseTime;} + + /** Sends an auto response to this contact */ + virtual void sendAutoResponse(Kopete::Message& msg); + +public slots: + void updateSSIItem(); + void slotUserInfo(); + void userInfoUpdated( const TQString& contact, const UserDetails& details ); + void userOnline( const TQString& userId ); + void userOffline( const TQString& userId ); + void updateAwayMessage( const TQString& userId, const TQString& message ); + void updateProfile( const TQString& contact, const TQString& profile ); + void gotWarning( const TQString& contact, TQ_UINT16, TQ_UINT16 ); + +signals: + void updatedProfile(); + +protected slots: + virtual void slotSendMsg(Kopete::Message& message, Kopete::ChatSession *); + virtual void updateFeatures(); + +private slots: + void requestBuddyIcon(); + void haveIcon( const TQString&, TQByteArray ); + void closeUserInfoDialog(); + void warnUser(); + + void slotVisibleTo(); + void slotInvisibleTo(); + +private: + AIMProtocol* mProtocol; + AIMUserInfoDialog* m_infoDialog; + TQString mUserProfile; + bool m_haveAwayMessage; + bool m_mobile; // Is this user mobile (i.e. do they have message forwarding on, or mobile AIM) + TQDateTime m_lastAutoresponseTime; + + TDEAction* m_warnUserAction; + TDEToggleAction *m_actionVisibleTo; + TDEToggleAction *m_actionInvisibleTo; +}; +#endif +//kate: tab-width 4; indent-mode csands; diff --git a/kopete/protocols/oscar/aim/aimjoinchat.cpp b/kopete/protocols/oscar/aim/aimjoinchat.cpp new file mode 100644 index 00000000..bc4a3edf --- /dev/null +++ b/kopete/protocols/oscar/aim/aimjoinchat.cpp @@ -0,0 +1,94 @@ +// aimjoinchat.cpp + +// Copyright (C) 2005 Matt Rogers <mattr@kde.org> + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include "aimjoinchat.h" + +#include <tqlineedit.h> +#include <tqcombobox.h> +#include <tdelocale.h> + +#include "aimjoinchatbase.h" +#include "aimaccount.h" + +AIMJoinChatUI::AIMJoinChatUI( AIMAccount* account, bool modal, + TQWidget* parent, const char* name ) + : KDialogBase( parent, name, modal, i18n( "Join AIM Chat Room" ), + Cancel | User1, User1, true, i18n( "Join" ) ) +{ + + kdDebug(OSCAR_AIM_DEBUG) << k_funcinfo << "Account " << account->accountId() + << " joining a chat room" << endl; + + m_account = account; + + m_joinUI = new AIMJoinChatBase( this, "aimjoinchatbase" ); + + setMainWidget( m_joinUI ); + + TQObject::connect( this, TQT_SIGNAL( user1Clicked() ), this, TQT_SLOT( joinChat() ) ); + TQObject::connect( this, TQT_SIGNAL( cancelClicked() ), this, TQT_SLOT( closeClicked() ) ); +} + +AIMJoinChatUI::~AIMJoinChatUI() +{ + m_exchanges.clear(); +} + +void AIMJoinChatUI::setExchangeList( const TQValueList<int>& list ) +{ + m_exchanges = list; + TQStringList exchangeList; + TQValueList<int>::const_iterator it = list.begin(); + while ( it != list.end() ) + { + exchangeList.append( TQString::number( ( *it ) ) ); + ++it; + } + + + m_joinUI->exchange->insertStringList( exchangeList ); +} + +void AIMJoinChatUI::joinChat() +{ + m_roomName = m_joinUI->roomName->text(); + int item = m_joinUI->exchange->currentItem(); + m_exchange = m_joinUI->exchange->text( item ); + + emit closing( TQDialog::Accepted ); +} + +void AIMJoinChatUI::closeClicked() +{ + //hmm, do nothing? + emit closing( TQDialog::Rejected ); +} + +TQString AIMJoinChatUI::roomName() const +{ + return m_roomName; +} + +TQString AIMJoinChatUI::exchange() const +{ + return m_exchange; +} + +#include "aimjoinchat.moc" +//kate: space-indent on; indent-width 4; diff --git a/kopete/protocols/oscar/aim/aimjoinchat.h b/kopete/protocols/oscar/aim/aimjoinchat.h new file mode 100644 index 00000000..828aab35 --- /dev/null +++ b/kopete/protocols/oscar/aim/aimjoinchat.h @@ -0,0 +1,63 @@ +// aimjoinchat.h + +// Copyright (C) 2005 Matt Rogers <mattr@kde.org> + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#ifndef AIMJOINCHAT_H +#define AIMJOINCHAT_H + +#include <kdialogbase.h> + +#include "oscartypes.h" + +class AIMAccount; +class AIMJoinChatBase; + +class AIMJoinChatUI : public KDialogBase +{ +Q_OBJECT + +public: + AIMJoinChatUI( AIMAccount*, bool modal, TQWidget* parent = 0, + const char* name = 0 ); + ~AIMJoinChatUI(); + + void setExchangeList( const TQValueList<int>& ); + TQValueList<int> exchangeList() const; + + TQString roomName() const; + TQString exchange() const; + + +protected slots: + void joinChat(); + void closeClicked(); + +signals: + void closing( int ); + +private: + AIMJoinChatBase* m_joinUI; + AIMAccount* m_account; + TQValueList<int> m_exchanges; + TQString m_roomName; + TQString m_exchange; + +}; + +#endif +//kate: space-indent on; indent-width 4; diff --git a/kopete/protocols/oscar/aim/aimprotocol.cpp b/kopete/protocols/oscar/aim/aimprotocol.cpp new file mode 100644 index 00000000..f71e1848 --- /dev/null +++ b/kopete/protocols/oscar/aim/aimprotocol.cpp @@ -0,0 +1,320 @@ +/* + oscarprotocol.cpp - Oscar Protocol Plugin + + Copyright (c) 2002 by Tom Linsky <twl6@po.cwru.edu> + + 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 <tqstringlist.h> +#include <kgenericfactory.h> +#include <tdemessagebox.h> +#include <kdebug.h> + +#include "aimprotocol.h" +#include "aimaccount.h" +#include "aimcontact.h" +#include "aimaddcontactpage.h" +#include "aimeditaccountwidget.h" + +#include "accountselector.h" +#include "kopeteaccountmanager.h" +#include "kopeteonlinestatusmanager.h" +#include "kopeteglobal.h" +#include "kopeteuiglobal.h" +#include "kopetemetacontact.h" + +#include <kdialogbase.h> +#include <tdemessagebox.h> +#include <kimageio.h> + +typedef KGenericFactory<AIMProtocol> AIMProtocolFactory; + +K_EXPORT_COMPONENT_FACTORY( kopete_aim, AIMProtocolFactory( "kopete_aim" ) ) + +AIMProtocol* AIMProtocol::protocolStatic_ = 0L; + + +AIMProtocolHandler::AIMProtocolHandler() : Kopete::MimeTypeHandler(false) +{ + registerAsProtocolHandler(TQString::fromLatin1("aim")); +} + +void AIMProtocolHandler::handleURL(const KURL &url) const +{ +/** + * Send a Message ================================================= + * aim:goim + * aim:goim?screenname=screen+name + * aim:goim?screenname=screen+name&message=message + * Add Buddy ====================================================== + * aim:addbuddy + * aim:addbuddy?screenname=screen+name + * Buddy Icon ===================================================== + * aim:buddyicon + * aim:buddyicon?src=image_source + * aim:buddyicon?screename=screen+name + * aim:buddyicon?src=image_source&screename=screen+name + * Get and Send Files ============================================= + * aim:getfile?screename=(sn) + * aim:sendfile?screenname=(sn) + * Register User ================================================== + * aim:RegisterUser?ScreenName=sn&Password=pw&SignonNow=False + * Away Message =================================================== + * aim:goaway?message=brb+or+something + * Chat Rooms ===================================================== + * aim:GoChat?RoomName=room+name&Exchange=number + **/ + + AIMProtocol *proto = AIMProtocol::protocol(); + kdDebug(14152) << k_funcinfo << "URL url : '" << url.url() << "'" << endl; + kdDebug(14152) << k_funcinfo << "URL path : '" << url.path() << "'" << endl; + TQString command = url.path(); + TQString realCommand, firstParam, secondParam; + bool needContactAddition = false; + if ( command.find( "goim", 0, false ) != -1 ) + { + realCommand = "goim"; + kdDebug(14152) << k_funcinfo << "Handling send IM request" << endl; + command.remove(0,4); + if ( command.find( "?screenname=", 0, false ) == -1 ) + { + kdWarning(14152) << k_funcinfo << "Unhandled AIM URI:" << url.url() << endl; + return; + } + command.remove( 0, 12 ); + int andSign = command.find( "&" ); + if ( andSign > 0 ) + command = command.left( andSign ); + + firstParam = command; + firstParam.replace( "+", " " ); + needContactAddition = true; + } + else + if ( command.find( "addbuddy", 0, false ) != -1 ) + { + realCommand = "addbuddy"; + kdDebug(14152) << k_funcinfo << "Handling AIM add buddy request" << endl; + command.remove( 0, 8 ); + if ( command.find( "?screenname=", 0, false ) == -1 ) + { + kdWarning(14152) << k_funcinfo << "Unhandled AIM URI:" << url.url() << endl; + return; + } + + command.remove(0, 12); + int andSign = command.find("&"); + if ( andSign > 0 ) + command = command.left(andSign); + command.replace("+", " "); + + firstParam = command; + needContactAddition = true; + } + else + if ( command.find( "gochat", 0, false ) != -1 ) + { + realCommand = "gochat"; + kdDebug(14152) << k_funcinfo << "Handling AIM chat room request" << endl; + command.remove( 0, 6 ); + + if ( command.find( "?RoomName=", 0, false ) == -1 ) + { + kdWarning(14152) << "Unhandled AIM URI: " << url.url() << endl; + return; + } + + command.remove( 0, 10 ); + + int andSign = command.find("&"); + if (andSign > 0) // strip off anything else for now + { + firstParam = command.left(andSign); + } + command.remove( 0, andSign ); + kdDebug(14152) << "command is now: " << command << endl; + command.remove( 0, 10 ); //remove "&Exchange=" + secondParam = command; + kdDebug(14152) << k_funcinfo << firstParam << " " << secondParam << endl; + firstParam.replace("+", " "); + } + + Kopete::Account *account = 0; + TQDict<Kopete::Account> accounts = Kopete::AccountManager::self()->accounts(proto); + + if (accounts.count() == 1) + { + TQDictIterator<Kopete::Account> it(accounts); + account = it.current(); + + } + else + { + KDialogBase *chooser = new KDialogBase(0, "chooser", true, + i18n("Choose Account"), KDialogBase::Ok|KDialogBase::Cancel, + KDialogBase::Ok, false); + AccountSelector *accSelector = new AccountSelector(proto, chooser, "accSelector"); + chooser->setMainWidget(accSelector); + + int ret = chooser->exec(); + account = accSelector->selectedItem(); + + delete chooser; + if (ret == TQDialog::Rejected || account == 0) + { + kdDebug(14152) << k_funcinfo << "Cancelled" << endl; + return; + } + } + + Kopete::MetaContact* mc = 0; + if ( needContactAddition || realCommand == "addbuddy" ) + { + if ( !account->isConnected() ) + { + kdDebug(14152) << k_funcinfo << "Can't add contact, we are offline!" << endl; + KMessageBox::sorry( Kopete::UI::Global::mainWidget(), i18n("You need to be connected to be able to add contacts."), + i18n("AIM") ); + return; + } + + if (KMessageBox::questionYesNo(Kopete::UI::Global::mainWidget(), + i18n("Do you want to add '%1' to your contact list?").arg(command), + TQString(), i18n("Add"), i18n("Do Not Add")) + != KMessageBox::Yes) + { + kdDebug(14152) << k_funcinfo << "Cancelled" << endl; + return; + } + + kdDebug(14152) << k_funcinfo << + "Adding Contact; screenname = " << firstParam << endl; + mc = account->addContact(firstParam, command, 0L, Kopete::Account::Temporary); + } + + if ( realCommand == "gochat" ) + { + AIMAccount* aimAccount = dynamic_cast<AIMAccount*>( account ); + if ( aimAccount && aimAccount->isConnected() ) + { + aimAccount->engine()->joinChatRoom( firstParam, secondParam.toInt() ); + } + else + KMessageBox::sorry( Kopete::UI::Global::mainWidget(), + i18n( "Unable to connect to the chat room %1 because the account" + " for %2 is not connected." ).arg( firstParam ).arg( aimAccount->accountId() ), + TQString() ); + + } + + if ( mc && realCommand == "goim" ) + { + mc->execute(); + } + +} + + + + +AIMProtocol::AIMProtocol(TQObject *parent, const char *name, const TQStringList &) + : Kopete::Protocol( AIMProtocolFactory::instance(), parent, name ), + statusOnline( Kopete::OnlineStatus::Online, 2, this, 0, TQString(), i18n("Online"), i18n("Online"), Kopete::OnlineStatusManager::Online ), + statusOffline( Kopete::OnlineStatus::Offline, 2, this, 10, TQString(), i18n("Offline"), i18n("Offline"), Kopete::OnlineStatusManager::Offline ), + statusAway( Kopete::OnlineStatus::Away, 2, this, 20, "contact_away_overlay", i18n("Away"), i18n("Away"), Kopete::OnlineStatusManager::Away, + Kopete::OnlineStatusManager::HasAwayMessage ), + statusWirelessOnline( Kopete::OnlineStatus::Online, 1, this, 30, "contact_phone_overlay", i18n("Mobile"), i18n("Mobile"), + Kopete::OnlineStatusManager::Online, Kopete::OnlineStatusManager::HideFromMenu ), + statusWirelessAway( Kopete::OnlineStatus::Away, 1, this, 31, TQStringList::split( " ", "contact_phone_overlay contact_away_overlay"), + i18n("Mobile Away"), i18n("Mobile Away"), Kopete::OnlineStatusManager::Away, Kopete::OnlineStatusManager::HideFromMenu ), + statusConnecting(Kopete::OnlineStatus::Connecting, 99, this, 99, "aim_connecting", i18n("Connecting...")), + awayMessage(Kopete::Global::Properties::self()->awayMessage()), + clientFeatures("clientFeatures", i18n("Client Features"), 0, false), + clientProfile( "clientProfile", i18n( "User Profile"), 0, false, true), + iconHash("iconHash", i18n("Buddy Icon MD5 Hash"), TQString(), true, false, true) +{ + if (protocolStatic_) + kdDebug(14152) << k_funcinfo << "AIM plugin already initialized" << endl; + else + protocolStatic_ = this; + + setCapabilities(0x1FFF); // setting capabilities - FIXME to use proper enum + kdDebug(14152) << k_funcinfo << "capabilities set to 0x1FFF" << endl; + addAddressBookField("messaging/aim", Kopete::Plugin::MakeIndexField); + KImageIO::registerFormats(); +} + +AIMProtocol::~AIMProtocol() +{ + protocolStatic_ =0L; +} + +AIMProtocol *AIMProtocol::protocol(void) +{ + return protocolStatic_; +} + +Kopete::Contact *AIMProtocol::deserializeContact(Kopete::MetaContact *metaContact, + const TQMap<TQString, TQString> &serializedData, + const TQMap<TQString, TQString> &/*addressBookData*/) +{ + + TQString contactId = serializedData["contactId"]; + TQString accountId = serializedData["accountId"]; + TQString displayName = serializedData["displayName"]; + + // Get the account it belongs to + TQDict<Kopete::Account> accounts = Kopete::AccountManager::self()->accounts( this ); + Kopete::Account *account = accounts[accountId]; + + if ( !account ) //no account + return 0; + + uint ssiGid = 0, ssiBid = 0, ssiType = 0xFFFF; + TQString ssiName; + bool ssiWaitingAuth = false; + if ( serializedData.contains( "ssi_type" ) ) + { + ssiName = serializedData["ssi_name"]; + TQString authStatus = serializedData["ssi_waitingAuth"]; + if ( authStatus == "true" ) + ssiWaitingAuth = true; + ssiGid = serializedData["ssi_gid"].toUInt(); + ssiBid = serializedData["ssi_bid"].toUInt(); + ssiType = serializedData["ssi_type"].toUInt(); + } + + Oscar::SSI item( ssiName, ssiGid, ssiBid, ssiType, TQValueList<TLV>(), 0 ); + item.setWaitingAuth( ssiWaitingAuth ); + + AIMContact *c = new AIMContact( account, contactId, metaContact, TQString(), item ); + return c; +} + +AddContactPage *AIMProtocol::createAddContactWidget(TQWidget *parent, Kopete::Account *account) +{ + return ( new AIMAddContactPage( account->isConnected(), parent ) ); +} + +KopeteEditAccountWidget *AIMProtocol::createEditAccountWidget(Kopete::Account *account, TQWidget *parent) +{ + return ( new AIMEditAccountWidget( this, account, parent ) ); +} + +Kopete::Account *AIMProtocol::createNewAccount(const TQString &accountId) +{ + return ( new AIMAccount( this, accountId ) ); +} + +#include "aimprotocol.moc" +// vim: set noet ts=4 sts=4 sw=4: diff --git a/kopete/protocols/oscar/aim/aimprotocol.h b/kopete/protocols/oscar/aim/aimprotocol.h new file mode 100644 index 00000000..26d092b6 --- /dev/null +++ b/kopete/protocols/oscar/aim/aimprotocol.h @@ -0,0 +1,86 @@ +/* + oscarprotocol.h - Oscar Protocol Plugin + + Copyright (c) 2002 by Tom Linsky <twl6@po.cwru.edu> + Copyright (c) 2005 by Matt Rogers <mattr@kde.org> + Kopete (c) 2002 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. * + * * + ************************************************************************* + */ + +#ifndef AIMPROTOCOL_H +#define AIMPROTOCOL_H + +#include "kopeteprotocol.h" +#include "kopetecontactproperty.h" +#include "kopetemimetypehandler.h" +#include "kopeteonlinestatus.h" + +#include <tqmap.h> + +namespace Kopete +{ +class OnlineStatus; +} + +class AIMProtocolHandler : public Kopete::MimeTypeHandler +{ +public: + AIMProtocolHandler(); + void handleURL( const KURL & url ) const; +}; + +class AIMProtocol : public Kopete::Protocol +{ + Q_OBJECT + + +public: + AIMProtocol( TQObject *parent, const char *name, const TQStringList &args ); + virtual ~AIMProtocol(); + /** + * Return the active instance of the protocol + * because it's a singleton, can only be used inside AIM classes, not in oscar lib + */ + static AIMProtocol *protocol(); + + bool canSendOffline() const { return false; } + + virtual Kopete::Contact *deserializeContact( Kopete::MetaContact *metaContact, + const TQMap<TQString, TQString> &serializedData, + const TQMap<TQString, TQString> &addressBookData ); + + AddContactPage*createAddContactWidget( TQWidget *parent, Kopete::Account *account ); + KopeteEditAccountWidget* createEditAccountWidget( Kopete::Account *account, TQWidget *parent ); + Kopete::Account* createNewAccount( const TQString &accountId ); + + /** + * The set of online statuses that AIM contacts can have + */ + const Kopete::OnlineStatus statusOnline; + const Kopete::OnlineStatus statusOffline; + const Kopete::OnlineStatus statusAway; + const Kopete::OnlineStatus statusWirelessOnline; + const Kopete::OnlineStatus statusWirelessAway; + const Kopete::OnlineStatus statusConnecting; + + const Kopete::ContactPropertyTmpl awayMessage; + const Kopete::ContactPropertyTmpl clientFeatures; + const Kopete::ContactPropertyTmpl clientProfile; + const Kopete::ContactPropertyTmpl iconHash; + +private: + /** The active instance of oscarprotocol */ + static AIMProtocol *protocolStatic_; + AIMProtocolHandler protohandler; +}; + +#endif +//kate: tab-width 4; indent-mode csands; diff --git a/kopete/protocols/oscar/aim/aimuserinfo.cpp b/kopete/protocols/oscar/aim/aimuserinfo.cpp new file mode 100644 index 00000000..0cce3a5c --- /dev/null +++ b/kopete/protocols/oscar/aim/aimuserinfo.cpp @@ -0,0 +1,224 @@ +/* + oscaruserinfo.cpp - Oscar Protocol Plugin + + Copyright (c) 2002 by Tom Linsky <twl6@po.cwru.edu> + + Kopete (c) 2002 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 "aimuserinfo.h" + +#include "aimaccount.h" +#include "aimcontact.h" +#include "aimprotocol.h" + +#include <tqlineedit.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqtimer.h> + +#include <tdelocale.h> +#include <kstandarddirs.h> +#include <ktextbrowser.h> +#include <kdebug.h> +#include <tdeapplication.h> + +#include <ktextedit.h> +#include <krun.h> + +AIMUserInfoDialog::AIMUserInfoDialog( Kopete::Contact *c, AIMAccount *acc, bool modal, + TQWidget *parent, const char* name ) + : KDialogBase( parent, name, modal, i18n( "User Information on %1" ) + .arg( c->property( Kopete::Global::Properties::self()->nickName() ).value().toString() ), + Cancel | Ok , Ok, true ) +{ + kdDebug(14200) << k_funcinfo << "for contact '" << c->contactId() << "'" << endl; + + m_contact = c; + mAccount = acc; + + mMainWidget = new AIMUserInfoWidget(this, "aimuserinfowidget"); + setMainWidget(mMainWidget); + + TQObject::connect(this, TQT_SIGNAL(okClicked()), this, TQT_SLOT(slotSaveClicked())); + TQObject::connect(this, TQT_SIGNAL(user1Clicked()), this, TQT_SLOT(slotUpdateClicked())); + TQObject::connect(this, TQT_SIGNAL(cancelClicked()), this, TQT_SLOT(slotCloseClicked())); + TQObject::connect(c, TQT_SIGNAL(updatedProfile()), this, TQT_SLOT(slotUpdateProfile())); + + mMainWidget->txtScreenName->setText( c->contactId() ); + + TQString nickName = c->property( Kopete::Global::Properties::self()->nickName() ).value().toString(); + if( nickName.isEmpty() ) + mMainWidget->txtNickName->setText( c->contactId() ); + else + mMainWidget->txtNickName->setText( nickName ); + + if(m_contact == mAccount->myself()) // edit own account profile + { + mMainWidget->lblWarnLevel->hide(); + mMainWidget->txtWarnLevel->hide(); + mMainWidget->lblIdleTime->hide(); + mMainWidget->txtIdleTime->hide(); + mMainWidget->lblOnlineSince->hide(); + mMainWidget->txtOnlineSince->hide(); + mMainWidget->txtAwayMessage->hide(); + mMainWidget->lblAwayMessage->hide(); + + userInfoView=0L; + mMainWidget->userInfoFrame->setFrameStyle(TQFrame::NoFrame | TQFrame::Plain); + TQVBoxLayout *l = new TQVBoxLayout(mMainWidget->userInfoFrame); + userInfoEdit = new KTextEdit(TQString(), TQString(), + mMainWidget->userInfoFrame, "userInfoEdit"); + userInfoEdit->setTextFormat(PlainText); + + AIMMyselfContact* aimmc = dynamic_cast<AIMMyselfContact*>( c ); + if ( aimmc ) + userInfoEdit->setText( aimmc->userProfile() ); + else + userInfoEdit->setText( TQString() ); + + setButtonText(Ok, i18n("&Save Profile")); + showButton(User1, false); + l->addWidget(userInfoEdit); + } + else + { + userInfoEdit=0L; + mMainWidget->userInfoFrame->setFrameStyle(TQFrame::NoFrame | TQFrame::Plain); + TQVBoxLayout *l = new TQVBoxLayout(mMainWidget->userInfoFrame); + userInfoView = new KTextBrowser(mMainWidget->userInfoFrame, "userInfoView"); + userInfoView->setTextFormat(AutoText); + userInfoView->setNotifyClick(true); + TQObject::connect( + userInfoView, TQT_SIGNAL(urlClick(const TQString&)), + this, TQT_SLOT(slotUrlClicked(const TQString&))); + TQObject::connect( + userInfoView, TQT_SIGNAL(mailClick(const TQString&, const TQString&)), + this, TQT_SLOT(slotMailClicked(const TQString&, const TQString&))); + showButton(Cancel, false); + setButtonText(Ok, i18n("&Close")); + setEscapeButton(Ok); + l->addWidget(userInfoView); + + if(m_contact->isOnline()) + { + // Update the user view to indicate that we're requesting the user's profile + userInfoView->setText(i18n("Requesting User Profile, please wait...")); + } + TQTimer::singleShot(0, this, TQT_SLOT(slotUpdateProfile())); + } +} + +AIMUserInfoDialog::~AIMUserInfoDialog() +{ + kdDebug(14200) << k_funcinfo << "Called." << endl; +} + +void AIMUserInfoDialog::slotUpdateClicked() +{ + kdDebug(14200) << k_funcinfo << "Called." << endl; + TQString newNick = mMainWidget->txtNickName->text(); + TQString currentNick = m_contact->property( Kopete::Global::Properties::self()->nickName() ).value().toString(); + if ( !newNick.isEmpty() && ( newNick != currentNick ) ) + { + //m_contact->rename(newNick); + //emit updateNickname(newNick); + setCaption(i18n("User Information on %1").arg(newNick)); + } + +} + +void AIMUserInfoDialog::slotSaveClicked() +{ + kdDebug(14200) << k_funcinfo << "Called." << endl; + + if (userInfoEdit) + { // editable mode, set profile + TQString newNick = mMainWidget->txtNickName->text(); + TQString currentNick = m_contact->property( Kopete::Global::Properties::self()->nickName() ).value().toString(); + if(!newNick.isEmpty() && ( newNick != currentNick ) ) + { + //m_contact->rename(newNick); + //emit updateNickname(newNick); + setCaption(i18n("User Information on %1").arg(newNick)); + } + + mAccount->setUserProfile(userInfoEdit->text()); + } + + emit closing(); +} + +void AIMUserInfoDialog::slotCloseClicked() +{ + kdDebug(14200) << k_funcinfo << "Called." << endl; + emit closing(); +} + +void AIMUserInfoDialog::slotUpdateProfile() +{ + kdDebug(14152) << k_funcinfo << "Got User Profile." << endl; + AIMProtocol* p = static_cast<AIMProtocol*>( mAccount->protocol() ); + TQString awayMessage = m_contact->property( p->awayMessage ).value().toString(); + mMainWidget->txtAwayMessage->setText( awayMessage ); + + if ( awayMessage.isNull() ) + { + mMainWidget->txtAwayMessage->hide(); + mMainWidget->lblAwayMessage->hide(); + } + else + { + mMainWidget->txtAwayMessage->show(); + mMainWidget->lblAwayMessage->show(); + } + + TQString onlineSince = m_contact->property("onlineSince").value().toString(); + //TQString onlineSince = m_details.onlineSinceTime().toString(); + mMainWidget->txtOnlineSince->setText( onlineSince ); + + AIMContact* c = static_cast<AIMContact*>( m_contact ); + mMainWidget->txtIdleTime->setText(c->formattedIdleTime()); + mMainWidget->txtWarnLevel->setText(TQString::number(c->warningLevel())); + + TQString contactProfile = m_contact->property( p->clientProfile ).value().toString(); + if ( contactProfile.isNull() ) + { + contactProfile = + i18n("<html><body><I>No user information provided</I></body></html>"); + } + + if(userInfoEdit) + { + userInfoEdit->setText(contactProfile); + } + else if(userInfoView) + { + userInfoView->setText(contactProfile); + } + +} + +void AIMUserInfoDialog::slotUrlClicked(const TQString &url) +{ + new KRun(KURL(url)); +} + +void AIMUserInfoDialog::slotMailClicked(const TQString&, const TQString &address) +{ + new KRun(KURL(address)); +} + +#include "aimuserinfo.moc" + +//kate: indent-mode csands; tab-width 4; space-indent off; replace-tabs off; diff --git a/kopete/protocols/oscar/aim/aimuserinfo.h b/kopete/protocols/oscar/aim/aimuserinfo.h new file mode 100644 index 00000000..d9e77fc5 --- /dev/null +++ b/kopete/protocols/oscar/aim/aimuserinfo.h @@ -0,0 +1,60 @@ +/* + oscaruserinfo.h - Oscar Protocol Plugin + + Copyright (c) 2002 by Tom Linsky <twl6@po.cwru.edu> + + Kopete (c) 2002 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. * + * * + ************************************************************************* +*/ + +#ifndef AIMUSERINFO_H +#define AIMUSERINFO_H + +#include <kdialogbase.h> +#include "aiminfobase.h" + +namespace Kopete { class Contact; } +class KTextEdit; +class OscarAccount; +class AIMMyselfContact; +class AIMAccount; + +class AIMUserInfoDialog : public KDialogBase +{ + Q_OBJECT + + public: + AIMUserInfoDialog(Kopete::Contact *c, AIMAccount *acc, bool modal, + TQWidget *parent, const char* name); + ~AIMUserInfoDialog(); + + private: + AIMAccount *mAccount; + Kopete::Contact* m_contact; + AIMUserInfoWidget *mMainWidget; + KTextBrowser *userInfoView; + KTextEdit *userInfoEdit; + + private slots: + void slotSaveClicked(); + void slotCloseClicked(); + void slotUpdateClicked(); + void slotUpdateProfile(); + void slotUrlClicked(const TQString&); + void slotMailClicked(const TQString&, const TQString&); + + signals: +// void updateNickname(const TQString &); + void closing(); +}; + +#endif + diff --git a/kopete/protocols/oscar/aim/kopete_aim.desktop b/kopete/protocols/oscar/aim/kopete_aim.desktop new file mode 100644 index 00000000..cf590551 --- /dev/null +++ b/kopete/protocols/oscar/aim/kopete_aim.desktop @@ -0,0 +1,77 @@ +[Desktop Entry] +Type=Service +X-Kopete-Version=1000900 +Icon=aim_protocol +X-TDE-ServiceTypes=Kopete/Protocol +X-TDE-Library=kopete_aim +X-Kopete-Messaging-Protocol=messaging/aim +X-TDE-PluginInfo-Author=Kopete Developers +X-TDE-PluginInfo-Email=kopete-devel@kde.org +X-TDE-PluginInfo-Name=kopete_aim +X-TDE-PluginInfo-Version=0.10.0 +X-TDE-PluginInfo-Website=http://kopete.kde.org +X-TDE-PluginInfo-Category=Protocols +X-TDE-PluginInfo-Depends= +X-TDE-PluginInfo-License=GPL +X-TDE-PluginInfo-EnabledByDefault=false +Name=AIM +Name[bn]=এ-আই-এম +Name[hi]=एआरईएम +Name[ne]=एआईएम +Comment=Protocol to connect to AIM +Comment[ar]=البرتوكول سيتصل بـ AIM +Comment[be]=Пратакол AIM +Comment[bg]=Протокол за връзка с AIM +Comment[bn]=এ-আই-এমতে সংযোগ করতে প্রোটোকল +Comment[br]=Komenad kevreañ ouzh AIM +Comment[bs]=AIM protokol +Comment[ca]=Protocol per a connectar-se a AIM +Comment[cs]=Protokol k připojení k AIM +Comment[cy]=Protocol i gysylltu ag AIM +Comment[da]=Protokol til at forbinde til AIM +Comment[de]=Protokoll zur Verbindung mit dem AIM +Comment[el]=Πρωτόκολλο για σύνδεση στο AIM +Comment[es]=Protocolo para conectar a AIM +Comment[et]=Protokoll ühendumiseks AIM-iga +Comment[eu]=AIM-era konektatzeko protokoloa +Comment[fa]=قرارداد برای اتصال به AIM +Comment[fi]=Yhteyskäytäntö AIM-verkkoon kytkeytymiseen +Comment[fr]=Protocole pour se connecter sur AIM +Comment[ga]=Prótacal chun ceangal le AIM +Comment[gl]=Protocolo para se conectar ó AIM +Comment[he]=פרוטוקול התחברות ל- AIM +Comment[hi]=से जुड़ने का प्रोटोकॉल +Comment[hr]=Protokol za povezivanje na AIM +Comment[hu]=Protokoll az AIM használatához +Comment[is]=Samskiptamáti til að tengjast AIM +Comment[it]=Protocollo per connessione a AIM +Comment[ja]=AIM に接続するプロトコル +Comment[ka]=AIM დაკავშირების ოქმი +Comment[kk]=AIM-ге қосылу протоколы +Comment[km]=ពិធីការភ្ជាប់ទៅ AIM +Comment[lt]=Protokolas prisijungimui prie AIM +Comment[mk]=Протокол за поврзување на AIM +Comment[nb]=Protokoll for å koble til AIM +Comment[nds]=Protokoll för't Tokoppeln na AIM +Comment[ne]=एआईएम मा जडान गर्नुपर्ने प्रोटोकल +Comment[nl]=Protocol voor AOL Instant Messenger +Comment[nn]=Protokoll for å kopla til AIM +Comment[pl]=Protokół połączenia z serwerem AIM +Comment[pt]=Um protocolo para se ligar ao AIM +Comment[pt_BR]=Protocolo de conexão ao AIM +Comment[ro]=Protocol de conectare la AIM +Comment[ru]=Протокол для подключения к AIM +Comment[sk]=Protokol pre pripojenie k AIM +Comment[sl]=Protokol za povezavo na AIM +Comment[sr]=Протокол за повезивање на AIM +Comment[sr@Latn]=Protokol za povezivanje na AIM +Comment[sv]=Protokoll för att ansluta till AIM +Comment[ta]=IRC உடன் இணைக்க விதிமுறை +Comment[tg]=Қарордоди пайвастшавӣ ба AIM +Comment[tr]=AIM'e bağlantı iletişim kuralı +Comment[uk]=Протокол для з'єднання з AIM +Comment[uz]=AIM bilan aloqa oʻrnatish uchun protokol +Comment[uz@cyrillic]=AIM билан алоқа ўрнатиш учун протокол +Comment[zh_CN]=连接到 AIM 协议 +Comment[zh_HK]=用來連接至 AIM 的通訊協定 +Comment[zh_TW]=連線到 AIM 的協定 diff --git a/kopete/protocols/oscar/aim/ui/CMakeLists.txt b/kopete/protocols/oscar/aim/ui/CMakeLists.txt new file mode 100644 index 00000000..8f5ff329 --- /dev/null +++ b/kopete/protocols/oscar/aim/ui/CMakeLists.txt @@ -0,0 +1,31 @@ +################################################# +# +# (C) 2010-2011 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/../.. + ${CMAKE_CURRENT_SOURCE_DIR}/../../liboscar + ${CMAKE_BINARY_DIR}/kopete/libkopete/ui + ${CMAKE_SOURCE_DIR}/kopete/libkopete + ${CMAKE_SOURCE_DIR}/kopete/libkopete/ui + ${TDE_INCLUDE_DIR} + ${TQT_INCLUDE_DIRS} +) + + +##### kopeteaimui (static) ###################### + +tde_add_library( kopeteaimui STATIC_PIC AUTOMOC + SOURCES + aimaddcontactui.ui aimeditaccountui.ui aiminfobase.ui + aimjoinchatbase.ui aimaddcontactpage.cpp aimeditaccountwidget.cpp +) diff --git a/kopete/protocols/oscar/aim/ui/Makefile.am b/kopete/protocols/oscar/aim/ui/Makefile.am new file mode 100644 index 00000000..aa690449 --- /dev/null +++ b/kopete/protocols/oscar/aim/ui/Makefile.am @@ -0,0 +1,15 @@ +METASOURCES = AUTO +AM_CPPFLAGS = $(KOPETE_INCLUDES) \ + -I$(srcdir)/.. \ + -I$(srcdir)/../.. \ + -I$(srcdir)/../../liboscar \ + $(all_includes) + +noinst_LTLIBRARIES = libkopeteaimui.la + +libkopeteaimui_la_SOURCES = aimaddcontactui.ui aimeditaccountui.ui \ + aiminfobase.ui aimjoinchatbase.ui aimaddcontactpage.cpp aimeditaccountwidget.cpp + +libkopeteaimui_la_LIBADD = $(top_builddir)/kopete/libkopete/libkopete.la + + diff --git a/kopete/protocols/oscar/aim/ui/aimaddcontactpage.cpp b/kopete/protocols/oscar/aim/ui/aimaddcontactpage.cpp new file mode 100644 index 00000000..c6612027 --- /dev/null +++ b/kopete/protocols/oscar/aim/ui/aimaddcontactpage.cpp @@ -0,0 +1,83 @@ +/*************************************************************************** + description + ------------------- + begin : + copyright : (C) 2002 by nbetcher + email : nbetcher@usinternet.com + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "aimaddcontactui.h" +#include "aimaddcontactpage.h" + +#include "kopeteaccount.h" + +#include <tqlayout.h> +#include <tqlineedit.h> +#include <tdelocale.h> +#include <tdemessagebox.h> + +AIMAddContactPage::AIMAddContactPage(bool connected, TQWidget *parent, + const char *name ) + : AddContactPage(parent,name) +{ + m_gui = 0; + (new TQVBoxLayout(this))->setAutoAdd(true); + + if(connected) + { + m_gui = new aimAddContactUI(this); + canadd = true; + } + else + { + noaddMsg1 = new TQLabel(i18n("You need to be connected to be able to add contacts."), this); + noaddMsg2 = new TQLabel(i18n("Connect to the AIM network and try again."), this); + canadd = false; + } +} + + +AIMAddContactPage::~AIMAddContactPage() +{ +} + +bool AIMAddContactPage::validateData() +{ + if ( !canadd ) + return false; + + if ( !m_gui ) + return false; + + TQString sn = m_gui->addSN->text(); + if ( sn.isEmpty() ) + { + KMessageBox::sorry ( this, + i18n("<qt>You must enter a valid screen name.</qt>"), + i18n("No Screen Name") ); + return false; + } + return true; +} + +bool AIMAddContactPage::apply(Kopete::Account *account, + Kopete::MetaContact *metaContact) +{ + if(validateData()) + { // If everything is ok + return account->addContact( m_gui->addSN->text(), metaContact, Kopete::Account::ChangeKABC ); + } + return false; +} +//kate: tab-width 4; indent-mode csands; + +#include "aimaddcontactpage.moc" diff --git a/kopete/protocols/oscar/aim/ui/aimaddcontactpage.h b/kopete/protocols/oscar/aim/ui/aimaddcontactpage.h new file mode 100644 index 00000000..c3bcaa36 --- /dev/null +++ b/kopete/protocols/oscar/aim/ui/aimaddcontactpage.h @@ -0,0 +1,42 @@ + +#ifndef AIMADDCONTACTPAGE_H +#define AIMADDCONTACTPAGE_H + +#include <tqwidget.h> +#include <tqlabel.h> +#include "addcontactpage.h" + +class aimAddContactUI; +class AIMAccount; +namespace Kopete +{ +class Account; +class MetaContact; +} + +class AIMAddContactPage : public AddContactPage +{ +Q_OBJECT + + +public: + AIMAddContactPage(bool connected, TQWidget *parent=0, + const char *name=0); + ~AIMAddContactPage(); + + /** Validates the data entered */ + virtual bool validateData(); + /** Applies the addition to the account */ + virtual bool apply( Kopete::Account *account, Kopete::MetaContact *); + +protected: + /** The actual GUI */ + aimAddContactUI *m_gui; + TQLabel *noaddMsg1; + TQLabel *noaddMsg2; + bool canadd; +}; +#endif + +//kate: tab-width 4; indent-mode csands; + diff --git a/kopete/protocols/oscar/aim/ui/aimaddcontactui.ui b/kopete/protocols/oscar/aim/ui/aimaddcontactui.ui new file mode 100644 index 00000000..663d2fc5 --- /dev/null +++ b/kopete/protocols/oscar/aim/ui/aimaddcontactui.ui @@ -0,0 +1,64 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>aimAddContactUI</class> +<widget class="TQWidget"> + <property name="name"> + <cstring>aimAddContactUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>455</width> + <height>131</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="TQGroupBox"> + <property name="name"> + <cstring>GroupBox1</cstring> + </property> + <property name="title"> + <string>Contact Information</string> + </property> + <property name="layoutMargin" stdset="0"> + </property> + <property name="layoutSpacing" stdset="0"> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="TQLineEdit" row="0" column="1"> + <property name="name"> + <cstring>addSN</cstring> + </property> + </widget> + <widget class="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>AIM screen name:</string> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>addSN</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kopete/protocols/oscar/aim/ui/aimeditaccountui.ui b/kopete/protocols/oscar/aim/ui/aimeditaccountui.ui new file mode 100644 index 00000000..c2ec9844 --- /dev/null +++ b/kopete/protocols/oscar/aim/ui/aimeditaccountui.ui @@ -0,0 +1,540 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>aimEditAccountUI</class> +<widget class="TQWidget"> + <property name="name"> + <cstring>aimEditAccountUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>560</width> + <height>583</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="caption"> + <string>Account Preferences - AIM</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>labelStatusMessage</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="TQTabWidget" row="0" column="0"> + <property name="name"> + <cstring>tabWidget6</cstring> + </property> + <widget class="TQWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>&Basic Setup</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQGroupBox"> + <property name="name"> + <cstring>groupBox72</cstring> + </property> + <property name="title"> + <string>Account Information</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>lblAccountId</cstring> + </property> + <property name="text"> + <string>AIM &screen name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>edtAccountId</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>The screen name of your AIM account.</string> + </property> + <property name="whatsThis" stdset="0"> + <string>The screen name of your AIM account. This should be in the form of an alphanumeric string (spaces allowed, not case sensitive).</string> + </property> + </widget> + <widget class="TQLineEdit"> + <property name="name"> + <cstring>edtAccountId</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>The screen name of your AIM account.</string> + </property> + <property name="whatsThis" stdset="0"> + <string>The screen name of your AIM account. This should be in the form of an alphanumeric string (spaces allowed, not case sensitive).</string> + </property> + </widget> + </hbox> + </widget> + <widget class="Kopete::UI::PasswordWidget" row="1" column="0"> + <property name="name"> + <cstring>mPasswordWidget</cstring> + </property> + </widget> + <widget class="TQCheckBox" row="3" column="0"> + <property name="name"> + <cstring>mGlobalIdentity</cstring> + </property> + <property name="text"> + <string>Exclu&de from Global Identity</string> + </property> + </widget> + <widget class="TQCheckBox" row="2" column="0"> + <property name="name"> + <cstring>mAutoLogon</cstring> + </property> + <property name="text"> + <string>E&xclude from connect all</string> + </property> + <property name="whatsThis" stdset="0"> + <string>If you check that case, the account will not be connected when you press the "Connect All" button, or at startup even if you selected to automatically connect at startup</string> + </property> + </widget> + </grid> + </widget> + <widget class="TQGroupBox"> + <property name="name"> + <cstring>groupBox5</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Registration</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel6</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>To connect to the AOL Instant Messaging network, you will need to use a screen name from AIM, AOL, or .Mac.<br><br>If you do not currently have an AIM screen name, please click the button to create one.</string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + <widget class="TQPushButton"> + <property name="name"> + <cstring>buttonRegister</cstring> + </property> + <property name="text"> + <string>Re&gister New Account</string> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>90</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="TQWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Accou&nt Preferences</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQGroupBox" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>groupBox73</cstring> + </property> + <property name="title"> + <string>Connection Preferences</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQCheckBox"> + <property name="name"> + <cstring>optionOverrideServer</cstring> + </property> + <property name="text"> + <string>&Override default server information</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>layout58</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>lblServer</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Ser&ver:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>edtServerAddress</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>The IP address or hostmask of the AIM server you wish to connect to.</string> + </property> + <property name="whatsThis" stdset="0"> + <string>The IP address or hostmask of the AIM server you wish to connect to. Normally you will want the default (login.oscar.aol.com).</string> + </property> + </widget> + <widget class="TQLineEdit"> + <property name="name"> + <cstring>edtServerAddress</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>login.oscar.aol.com</string> + </property> + <property name="toolTip" stdset="0"> + <string>The IP address or hostmask of the AIM server you wish to connect to.</string> + </property> + <property name="whatsThis" stdset="0"> + <string>The IP address or hostmask of the AIM server you wish to connect to. Normally you will want the default (login.oscar.aol.com).</string> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>lblPort</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Po&rt:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>sbxServerPort</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>The port on the AIM server that you would like to connect to.</string> + </property> + <property name="whatsThis" stdset="0"> + <string>The port on the AIM server that you would like to connect to. Normally this is 5190.</string> + </property> + </widget> + <widget class="TQSpinBox"> + <property name="name"> + <cstring>sbxServerPort</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="maxValue"> + <number>65534</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="value"> + <number>5190</number> + </property> + <property name="toolTip" stdset="0"> + <string>The port on the AIM server that you would like to connect to.</string> + </property> + <property name="whatsThis" stdset="0"> + <string>The port on the AIM server that you would like to connect to. Normally this is 5190.</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer21</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>200</height> + </size> + </property> + </spacer> + <widget class="TQComboBox" row="1" column="1"> + <property name="name"> + <cstring>encodingCombo</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Default to the following &encoding for messages:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>encodingCombo</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="TQWidget"> + <property name="name"> + <cstring>tab</cstring> + </property> + <attribute name="title"> + <string>Pri&vacy</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQButtonGroup" row="0" column="0"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="title"> + <string>Visibility settings</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQRadioButton" row="2" column="0"> + <property name="name"> + <cstring>rbAllowPerimtList</cstring> + </property> + <property name="text"> + <string>Allow only from visible list</string> + </property> + </widget> + <widget class="TQRadioButton" row="0" column="1"> + <property name="name"> + <cstring>rbBlockAll</cstring> + </property> + <property name="text"> + <string>Block all users</string> + </property> + </widget> + <widget class="TQRadioButton" row="1" column="1"> + <property name="name"> + <cstring>rbBlockAIM</cstring> + </property> + <property name="text"> + <string>Block AIM users</string> + </property> + </widget> + <widget class="TQRadioButton" row="2" column="1"> + <property name="name"> + <cstring>rbBlockDenyList</cstring> + </property> + <property name="text"> + <string>Block only from invisible list</string> + </property> + </widget> + <widget class="TQRadioButton" row="0" column="0"> + <property name="name"> + <cstring>rbAllowAll</cstring> + </property> + <property name="text"> + <string>Allow all users</string> + </property> + </widget> + <widget class="TQRadioButton" row="1" column="0"> + <property name="name"> + <cstring>rbAllowMyContacts</cstring> + </property> + <property name="text"> + <string>Allow only contact list's users</string> + </property> + </widget> + </grid> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>31</width> + <height>225</height> + </size> + </property> + </spacer> + </grid> + </widget> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>Kopete::UI::PasswordWidget</class> + <header location="local">kopetepasswordwidget.h</header> + <sizehint> + <width>50</width> + <height>50</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>1</hordata> + <verdata>0</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + <signal>changed()</signal> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="1002">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082</data> + </image> +</images> +<connections> + <connection> + <sender>optionOverrideServer</sender> + <signal>toggled(bool)</signal> + <receiver>lblServer</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>optionOverrideServer</sender> + <signal>toggled(bool)</signal> + <receiver>lblPort</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>optionOverrideServer</sender> + <signal>toggled(bool)</signal> + <receiver>edtServerAddress</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>optionOverrideServer</sender> + <signal>toggled(bool)</signal> + <receiver>sbxServerPort</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>tabWidget6</tabstop> + <tabstop>edtAccountId</tabstop> + <tabstop>mAutoLogon</tabstop> + <tabstop>buttonRegister</tabstop> + <tabstop>optionOverrideServer</tabstop> + <tabstop>edtServerAddress</tabstop> + <tabstop>sbxServerPort</tabstop> + <tabstop>encodingCombo</tabstop> + <tabstop>rbAllowAll</tabstop> + <tabstop>rbAllowMyContacts</tabstop> + <tabstop>rbAllowPerimtList</tabstop> + <tabstop>rbBlockAll</tabstop> + <tabstop>rbBlockAIM</tabstop> + <tabstop>rbBlockDenyList</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kopetepasswordwidget.h</includehint> +</includehints> +</UI> diff --git a/kopete/protocols/oscar/aim/ui/aimeditaccountwidget.cpp b/kopete/protocols/oscar/aim/ui/aimeditaccountwidget.cpp new file mode 100644 index 00000000..e3c1f62b --- /dev/null +++ b/kopete/protocols/oscar/aim/ui/aimeditaccountwidget.cpp @@ -0,0 +1,172 @@ +#include "aimeditaccountwidget.h" +#include "aimeditaccountui.h" + +#include <tqlayout.h> +#include <tqcheckbox.h> +#include <tqpushbutton.h> +#include <tqradiobutton.h> +#include <tqlineedit.h> +#include <tqspinbox.h> + +#include <kdebug.h> +#include <krun.h> +#include <kpassdlg.h> +#include <tdeconfig.h> + +#include "kopetepassword.h" +#include "kopetepasswordwidget.h" + +#include "aimprotocol.h" +#include "aimaccount.h" + +AIMEditAccountWidget::AIMEditAccountWidget( AIMProtocol *protocol, + Kopete::Account *account, TQWidget *parent, const char *name ) + : TQWidget( parent, name ), KopeteEditAccountWidget( account ) +{ + //kdDebug(14152) << k_funcinfo << "Called." << endl; + + mAccount = dynamic_cast<AIMAccount*>( account ); + mProtocol = protocol; + + // create the gui (generated from a .ui file) + ( new TQVBoxLayout( this ) )->setAutoAdd( true ); + mGui = new aimEditAccountUI( this, "AIMEditAccountWidget::mGui" ); + + // Read in the settings from the account if it exists + if ( mAccount ) + { + mGui->mPasswordWidget->load( &mAccount->password() ); + mGui->edtAccountId->setText( account->accountId() ); + //Remove me after we can change Account IDs (Matt) + mGui->edtAccountId->setDisabled( true ); + mGui->mAutoLogon->setChecked( account->excludeConnect() ); + TQString serverEntry = account->configGroup()->readEntry( "Server", "login.oscar.aol.com" ); + int portEntry = account->configGroup()->readNumEntry( "Port", 5190 ); + if ( serverEntry != "login.oscar.aol.com" || portEntry != 5190 ) + mGui->optionOverrideServer->setChecked( true ); + else + mGui->optionOverrideServer->setChecked( false ); + + mGui->edtServerAddress->setText( serverEntry ); + mGui->sbxServerPort->setValue( portEntry ); + + using namespace AIM::PrivacySettings; + + int privacySetting = mAccount->configGroup()->readNumEntry( "PrivacySetting", AllowAll ); + switch( privacySetting ) + { + case AllowAll: + mGui->rbAllowAll->setChecked( true ); + break; + case AllowMyContacts: + mGui->rbAllowMyContacts->setChecked( true ); + break; + case AllowPremitList: + mGui->rbAllowPerimtList->setChecked( true ); + break; + case BlockAll: + mGui->rbBlockAll->setChecked( true ); + break; + case BlockAIM: + mGui->rbBlockAIM->setChecked( true ); + break; + case BlockDenyList: + mGui->rbBlockDenyList->setChecked( true ); + break; + default: + mGui->rbAllowAll->setChecked( true ); + } + + // Global Identity + mGui->mGlobalIdentity->setChecked( account->configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) ); + } + TQObject::connect( mGui->buttonRegister, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotOpenRegister() ) ); + + /* Set tab order to password custom widget correctly */ + TQWidget::setTabOrder( mGui->edtAccountId, mGui->mPasswordWidget->mRemembered ); + TQWidget::setTabOrder( mGui->mPasswordWidget->mRemembered, mGui->mPasswordWidget->mPassword ); + TQWidget::setTabOrder( mGui->mPasswordWidget->mPassword, mGui->mAutoLogon ); +} + +AIMEditAccountWidget::~AIMEditAccountWidget() +{} + +Kopete::Account *AIMEditAccountWidget::apply() +{ + kdDebug( 14152 ) << k_funcinfo << "Called." << endl; + + // If this is a new account, create it + if ( !mAccount ) + { + kdDebug( 14152 ) << k_funcinfo << "creating a new account" << endl; + TQString newId = mGui->edtAccountId->text(); + mAccount = new AIMAccount( mProtocol, newId ); + } + + mGui->mPasswordWidget->save( &mAccount->password() ); + + mAccount->setExcludeConnect( mGui->mAutoLogon->isChecked() ); // save the autologon choice + if ( mGui->optionOverrideServer->isChecked() ) + { + static_cast<OscarAccount *>( mAccount )->setServerAddress( mGui->edtServerAddress->text() ); + static_cast<OscarAccount *>( mAccount )->setServerPort( mGui->sbxServerPort->value() ); + } + else + { + static_cast<OscarAccount *>( mAccount )->setServerAddress( "login.oscar.aol.com" ); + static_cast<OscarAccount *>( mAccount )->setServerPort( 5190 ); + } + + using namespace AIM::PrivacySettings; + int privacySetting = AllowAll; + + if ( mGui->rbAllowAll->isChecked() ) + privacySetting = AllowAll; + else if ( mGui->rbAllowMyContacts->isChecked() ) + privacySetting = AllowMyContacts; + else if ( mGui->rbAllowPerimtList->isChecked() ) + privacySetting = AllowPremitList; + else if ( mGui->rbBlockAll->isChecked() ) + privacySetting = BlockAll; + else if ( mGui->rbBlockAIM->isChecked() ) + privacySetting = BlockAIM; + else if ( mGui->rbBlockDenyList->isChecked() ) + privacySetting = BlockDenyList; + + mAccount->configGroup()->writeEntry( "PrivacySetting", privacySetting ); + mAccount->setPrivacySettings( privacySetting ); + + // Global Identity + mAccount->configGroup()->writeEntry( "ExcludeGlobalIdentity", mGui->mGlobalIdentity->isChecked() ); + return mAccount; +} + +bool AIMEditAccountWidget::validateData() +{ + //kdDebug(14152) << k_funcinfo << "Called." << endl; + + TQString userName = mGui->edtAccountId->text(); + TQString server = mGui->edtServerAddress->text(); + int port = mGui->sbxServerPort->value(); + + if ( userName.length() < 1 ) + return false; + + if ( port < 1 ) + return false; + + if ( server.length() < 1 ) + return false; + + // Seems good to me + //kdDebug(14152) << k_funcinfo << "Account data validated successfully." << endl; + return true; +} + +void AIMEditAccountWidget::slotOpenRegister() +{ + KRun::runURL( "http://my.screenname.aol.com/_cqr/login/login.psp?siteId=snshomepage&mcState=initialized&createSn=1", "text/html" ); +} + +#include "aimeditaccountwidget.moc" +// vim: set noet ts=4 sts=4 sw=4: diff --git a/kopete/protocols/oscar/aim/ui/aimeditaccountwidget.h b/kopete/protocols/oscar/aim/ui/aimeditaccountwidget.h new file mode 100644 index 00000000..6ccaceb5 --- /dev/null +++ b/kopete/protocols/oscar/aim/ui/aimeditaccountwidget.h @@ -0,0 +1,59 @@ +/* + AIMeditaccountwidget.h - AIM Account Widget + + Copyright (c) 2003 by Chris TenHarmsel <tenharmsel@staticmethod.net> + + Kopete (c) 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. * + * * + ************************************************************************* +*/ + + +#ifndef AIMEDITACCOUNTWIDGET_H +#define AIMEDITACCOUNTWIDGET_H + +#include <tqwidget.h> +#include "editaccountwidget.h" +/** + * @author Chris TenHarmsel <tenharmsel@staticmethod.net> + */ + +namespace Kopete +{ +class Account; +} + +class AIMAccount; +class AIMProtocol; +class aimEditAccountUI; + +class AIMEditAccountWidget : public TQWidget, public KopeteEditAccountWidget +{ +Q_OBJECT + + +public: + AIMEditAccountWidget(AIMProtocol *protocol, Kopete::Account *account, + TQWidget *parent=0, const char *name=0); + virtual ~AIMEditAccountWidget(); + + virtual bool validateData(); + virtual Kopete::Account *apply(); + +private slots: + void slotOpenRegister(); + +protected: + AIMAccount *mAccount; + AIMProtocol *mProtocol; + aimEditAccountUI *mGui; +}; +#endif +//kate: tab-width 4; indent-mode csands; diff --git a/kopete/protocols/oscar/aim/ui/aiminfobase.ui b/kopete/protocols/oscar/aim/ui/aiminfobase.ui new file mode 100644 index 00000000..188e4aad --- /dev/null +++ b/kopete/protocols/oscar/aim/ui/aiminfobase.ui @@ -0,0 +1,246 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>AIMUserInfoWidget</class> +<widget class="TQWidget"> + <property name="name"> + <cstring>AIMUserInfoWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>360</width> + <height>408</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>360</width> + <height>400</height> + </size> + </property> + <property name="layoutMargin" stdset="0"> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>lblNickName</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Nickname:</string> + </property> + </widget> + <widget class="TQLineEdit"> + <property name="name"> + <cstring>txtNickName</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>lblScreenName</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Screen name:</string> + </property> + </widget> + <widget class="TQLineEdit"> + <property name="name"> + <cstring>txtScreenName</cstring> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>layout10</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>lblWarnLevel</cstring> + </property> + <property name="text"> + <string>Warning level:</string> + </property> + </widget> + <widget class="TQLineEdit"> + <property name="name"> + <cstring>txtWarnLevel</cstring> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>lblIdleTime</cstring> + </property> + <property name="text"> + <string>Idle minutes:</string> + </property> + </widget> + <widget class="TQLineEdit"> + <property name="name"> + <cstring>txtIdleTime</cstring> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + <widget class="TQLayoutWidget"> + <property name="name"> + <cstring>layout11</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel"> + <property name="name"> + <cstring>lblOnlineSince</cstring> + </property> + <property name="text"> + <string>Online since:</string> + </property> + </widget> + <widget class="TQLineEdit"> + <property name="name"> + <cstring>txtOnlineSince</cstring> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>lblAwayMessage</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Away message:</string> + </property> + <property name="alignment"> + <set>AlignTop</set> + </property> + </widget> + <widget class="KTextBrowser"> + <property name="name"> + <cstring>txtAwayMessage</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="textFormat"> + <enum>AutoText</enum> + </property> + </widget> + <widget class="TQLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Profile:</string> + </property> + </widget> + <widget class="TQFrame"> + <property name="name"> + <cstring>userInfoFrame</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>64</width> + <height>16</height> + </size> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>txtNickName</tabstop> + <tabstop>txtScreenName</tabstop> + <tabstop>txtWarnLevel</tabstop> + <tabstop>txtIdleTime</tabstop> + <tabstop>txtOnlineSince</tabstop> + <tabstop>txtAwayMessage</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>ktextbrowser.h</includehint> +</includehints> +</UI> diff --git a/kopete/protocols/oscar/aim/ui/aimjoinchatbase.ui b/kopete/protocols/oscar/aim/ui/aimjoinchatbase.ui new file mode 100644 index 00000000..5b2d084b --- /dev/null +++ b/kopete/protocols/oscar/aim/ui/aimjoinchatbase.ui @@ -0,0 +1,124 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>AIMJoinChatBase</class> +<widget class="TQWidget"> + <property name="name"> + <cstring>AIMJoinChatBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>343</width> + <height>99</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="TQLabel" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Please enter the name of the chat room you wish to join.</string> + </property> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Maximum</enum> + </property> + <property name="sizeHint"> + <size> + <width>60</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="TQLabel" row="2" column="1"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Room &name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>roomName</cstring> + </property> + </widget> + <widget class="TQLabel" row="3" column="1"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>E&xchange:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>exchange</cstring> + </property> + </widget> + <widget class="TQLineEdit" row="2" column="2"> + <property name="name"> + <cstring>roomName</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="TQComboBox" row="3" column="2"> + <property name="name"> + <cstring>exchange</cstring> + </property> + </widget> + <spacer row="4" column="2"> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kopete/protocols/oscar/icons/cr128-app-aim_protocol.png b/kopete/protocols/oscar/icons/cr128-app-aim_protocol.png Binary files differnew file mode 100644 index 00000000..cb718f02 --- /dev/null +++ b/kopete/protocols/oscar/icons/cr128-app-aim_protocol.png diff --git a/kopete/protocols/oscar/icons/cr16-action-aim_away.png b/kopete/protocols/oscar/icons/cr16-action-aim_away.png Binary files differnew file mode 100644 index 00000000..c71e92a6 --- /dev/null +++ b/kopete/protocols/oscar/icons/cr16-action-aim_away.png diff --git a/kopete/protocols/oscar/icons/cr16-action-aim_connecting.mng b/kopete/protocols/oscar/icons/cr16-action-aim_connecting.mng Binary files differnew file mode 100644 index 00000000..90417a14 --- /dev/null +++ b/kopete/protocols/oscar/icons/cr16-action-aim_connecting.mng diff --git a/kopete/protocols/oscar/icons/cr16-action-aim_offline.png b/kopete/protocols/oscar/icons/cr16-action-aim_offline.png Binary files differnew file mode 100644 index 00000000..3ba42b20 --- /dev/null +++ b/kopete/protocols/oscar/icons/cr16-action-aim_offline.png diff --git a/kopete/protocols/oscar/icons/cr16-action-aim_online.png b/kopete/protocols/oscar/icons/cr16-action-aim_online.png Binary files differnew file mode 100644 index 00000000..2261523f --- /dev/null +++ b/kopete/protocols/oscar/icons/cr16-action-aim_online.png diff --git a/kopete/protocols/oscar/icons/cr16-app-aim_protocol.png b/kopete/protocols/oscar/icons/cr16-app-aim_protocol.png Binary files differnew file mode 100644 index 00000000..9e5a3331 --- /dev/null +++ b/kopete/protocols/oscar/icons/cr16-app-aim_protocol.png diff --git a/kopete/protocols/oscar/icons/cr32-app-aim_protocol.png b/kopete/protocols/oscar/icons/cr32-app-aim_protocol.png Binary files differnew file mode 100644 index 00000000..01d92d38 --- /dev/null +++ b/kopete/protocols/oscar/icons/cr32-app-aim_protocol.png diff --git a/kopete/protocols/oscar/icons/cr48-app-aim_protocol.png b/kopete/protocols/oscar/icons/cr48-app-aim_protocol.png Binary files differnew file mode 100644 index 00000000..493f3b6c --- /dev/null +++ b/kopete/protocols/oscar/icons/cr48-app-aim_protocol.png diff --git a/kopete/protocols/oscar/icons/cr64-app-aim_protocol.png b/kopete/protocols/oscar/icons/cr64-app-aim_protocol.png Binary files differnew file mode 100644 index 00000000..04ed6dc8 --- /dev/null +++ b/kopete/protocols/oscar/icons/cr64-app-aim_protocol.png diff --git a/kopete/protocols/oscar/icons/hi16-action-aim_away.png b/kopete/protocols/oscar/icons/hi16-action-aim_away.png Binary files differnew file mode 100644 index 00000000..d1b45d8c --- /dev/null +++ b/kopete/protocols/oscar/icons/hi16-action-aim_away.png diff --git a/kopete/protocols/oscar/icons/hi16-action-aim_connecting.mng b/kopete/protocols/oscar/icons/hi16-action-aim_connecting.mng Binary files differnew file mode 100644 index 00000000..19767318 --- /dev/null +++ b/kopete/protocols/oscar/icons/hi16-action-aim_connecting.mng diff --git a/kopete/protocols/oscar/icons/hi16-action-aim_offline.png b/kopete/protocols/oscar/icons/hi16-action-aim_offline.png Binary files differnew file mode 100644 index 00000000..6c64cae1 --- /dev/null +++ b/kopete/protocols/oscar/icons/hi16-action-aim_offline.png diff --git a/kopete/protocols/oscar/icons/hi16-action-aim_online.png b/kopete/protocols/oscar/icons/hi16-action-aim_online.png Binary files differnew file mode 100644 index 00000000..9d9bfdee --- /dev/null +++ b/kopete/protocols/oscar/icons/hi16-action-aim_online.png diff --git a/kopete/protocols/oscar/icons/hi16-app-aim_protocol.png b/kopete/protocols/oscar/icons/hi16-app-aim_protocol.png Binary files differnew file mode 100644 index 00000000..9d9bfdee --- /dev/null +++ b/kopete/protocols/oscar/icons/hi16-app-aim_protocol.png diff --git a/kopete/protocols/oscar/icons/hi32-app-aim_protocol.png b/kopete/protocols/oscar/icons/hi32-app-aim_protocol.png Binary files differnew file mode 100644 index 00000000..596785ec --- /dev/null +++ b/kopete/protocols/oscar/icons/hi32-app-aim_protocol.png diff --git a/kopete/protocols/oscar/liboscar/CMakeLists.txt b/kopete/protocols/oscar/liboscar/CMakeLists.txt index 102ac0ff..6053541f 100644 --- a/kopete/protocols/oscar/liboscar/CMakeLists.txt +++ b/kopete/protocols/oscar/liboscar/CMakeLists.txt @@ -27,7 +27,7 @@ tde_add_library( oscar STATIC_PIC AUTOMOC inputprotocolbase.cpp coreprotocol.cpp flapprotocol.cpp snacprotocol.cpp transfer.cpp rtf.cc bytestream.cpp oscarclientstream.cpp safedelete.cpp stream.cpp oscarconnector.cpp - oscarbytestream.cpp buffer.cpp md5.c logintask.cpp + oscarbytestream.cpp buffer.cpp md5.c logintask.cpp aimlogintask.cpp icqlogintask.cpp closeconnectiontask.cpp rateclassmanager.cpp serverversionstask.cpp rateinfotask.cpp errortask.cpp locationrightstask.cpp profiletask.cpp blmlimitstask.cpp diff --git a/kopete/protocols/oscar/liboscar/Makefile.am b/kopete/protocols/oscar/liboscar/Makefile.am index 2a235e83..ab0def67 100644 --- a/kopete/protocols/oscar/liboscar/Makefile.am +++ b/kopete/protocols/oscar/liboscar/Makefile.am @@ -8,7 +8,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/kopete/libkopete $(all_includes) liboscar_la_SOURCES = oscarutils.cpp client.cpp task.cpp connector.cpp \ inputprotocolbase.cpp coreprotocol.cpp flapprotocol.cpp snacprotocol.cpp transfer.cpp rtf.cc \ bytestream.cpp oscarclientstream.cpp safedelete.cpp stream.cpp oscarconnector.cpp \ - oscarbytestream.cpp buffer.cpp md5.c logintask.cpp icqlogintask.cpp \ + oscarbytestream.cpp buffer.cpp md5.c logintask.cpp aimlogintask.cpp icqlogintask.cpp \ closeconnectiontask.cpp rateclassmanager.cpp serverversionstask.cpp rateinfotask.cpp \ errortask.cpp locationrightstask.cpp profiletask.cpp blmlimitstask.cpp \ servicesetuptask.cpp icbmparamstask.cpp ssimanager.cpp rateclass.cpp rateclass.h \ diff --git a/kopete/protocols/oscar/liboscar/aimlogintask.cpp b/kopete/protocols/oscar/liboscar/aimlogintask.cpp new file mode 100644 index 00000000..a371b0df --- /dev/null +++ b/kopete/protocols/oscar/liboscar/aimlogintask.cpp @@ -0,0 +1,254 @@ +/* + Kopete Oscar Protocol + aimlogintask.h - Handles logging into to the AIM service + + Copyright (c) 2004 Matt Rogers <mattr@kde.org> + + Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ +#include "aimlogintask.h" + +#include <stdlib.h> +#include <kdebug.h> +#include <tdelocale.h> +#include "connection.h" +#include "oscartypes.h" +#include "oscarutils.h" +#include "transfer.h" + +#include "md5.h" + +using namespace Oscar; + +AimLoginTask::AimLoginTask( Task* parent ) + : Task ( parent ) +{ +} + +AimLoginTask::~AimLoginTask() +{ +} + +void AimLoginTask::onGo() +{ + //send Snac 17,06 + sendAuthStringRequest(); + //when we have the authKey, login + connect( this, TQT_SIGNAL( haveAuthKey() ), this, TQT_SLOT( sendLoginRequest() ) ); +} + +bool AimLoginTask::forMe( Transfer* transfer ) const +{ + SnacTransfer* st = dynamic_cast<SnacTransfer*>( transfer ); + + if (!st) + return false; + + if ( st && st->snacService() == 0x17 ) + { + WORD subtype = st->snacSubtype(); + switch ( subtype ) + { + case 0x0002: + case 0x0003: + case 0x0006: + case 0x0007: + return true; + break; + default: + return false; + break; + } + } + return false; +} + +const TQByteArray& AimLoginTask::cookie() const +{ + return m_cookie; +} + +const TQString& AimLoginTask::bosHost() const +{ + return m_bosHost; +} + +const TQString& AimLoginTask::bosPort() const +{ + return m_bosPort; +} + +bool AimLoginTask::take( Transfer* transfer ) +{ + if ( forMe( transfer ) ) + { + SnacTransfer* st = dynamic_cast<SnacTransfer*>( transfer ); + if (!st) + return false; + + WORD subtype = st->snacSubtype(); + switch ( subtype ) + { + case 0x0003: + setTransfer( transfer ); + handleLoginResponse(); + setTransfer( 0 ); + return true; + break; + case 0x0007: + setTransfer( transfer ); + processAuthStringReply(); + setTransfer( 0 ); + return true; + break; + default: + return false; + break; + } + + return false; + } + return false; +} + +void AimLoginTask::sendAuthStringRequest() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo + << "SEND CLI_AUTH_REQUEST, sending login request" << endl; + + FLAP f = { 0x02, 0, 0 }; + SNAC s = { 0x0017, 0x0006, 0x0000, client()->snacSequence() }; + + Buffer* outbuf = new Buffer; + outbuf->addTLV(0x0001, client()->userId().length(), client()->userId().latin1() ); + outbuf->addDWord(0x004B0000); // empty TLV 0x004B + outbuf->addDWord(0x005A0000); // empty TLV 0x005A + + Transfer* st = createTransfer( f, s, outbuf ); + send( st ); +} + +void AimLoginTask::processAuthStringReply() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Got the authorization key" << endl; + Buffer *inbuf = transfer()->buffer(); + WORD keylen = inbuf->getWord(); + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Key length is " << keylen << endl; + m_authKey.duplicate( inbuf->getBlock(keylen) ); + emit haveAuthKey(); +} + +void AimLoginTask::sendLoginRequest() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "SEND (CLI_MD5_LOGIN) sending AIM login" << endl; + + FLAP f = { 0x02, 0, 0 }; + SNAC s = { 0x0017, 0x0002, 0x0000, client()->snacSequence() }; + Buffer *outbuf = new Buffer; + const Oscar::ClientVersion* version = client()->version(); + + outbuf->addTLV(0x0001, client()->userId().length(), client()->userId().latin1()); + + TQByteArray digest( 17 ); //apparently MD5 digests are 16 bytes long + encodePassword( digest ); + digest[16] = '\0'; //do this so that addTLV sees a NULL-terminator + + outbuf->addTLV(0x0025, 16, digest); + outbuf->addTLV(0x0003, version->clientString.length(), version->clientString.latin1() ); + outbuf->addTLV16(0x0016, version->clientId ); + outbuf->addTLV16(0x0017, version->major ); + outbuf->addTLV16(0x0018, version->minor ); + outbuf->addTLV16(0x0019, version->point ); + outbuf->addTLV16(0x001a, version->build ); + outbuf->addDWord(0x00140004); //TLV type 0x0014, length 0x0004 + outbuf->addDWord( version->other ); //TLV data for type 0x0014 + outbuf->addTLV(0x000f, version->lang.length(), version->lang.latin1() ); + outbuf->addTLV(0x000e, version->country.length(), version->country.latin1() ); + + //if set, old-style buddy lists will not work... you will need to use SSI + outbuf->addTLV8(0x004a,0x01); + + Transfer *st = createTransfer( f, s, outbuf ); + send( st ); +} + +void AimLoginTask::handleLoginResponse() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "RECV SNAC 0x17, 0x07 - AIM Login Response" << endl; + + SnacTransfer* st = dynamic_cast<SnacTransfer*> ( transfer() ); + + if ( !st ) + { + setError( -1 , TQString() ); + return; + } + + TQValueList<TLV> tlvList = st->buffer()->getTLVList(); + + TLV uin = findTLV( tlvList, 0x0001 ); + if ( uin ) + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "found TLV(1) [SN], SN=" << TQString( uin.data ) << endl; + } + + TLV err = findTLV( tlvList, 0x0008 ); + + if ( err ) + { + WORD errorNum = ( ( err.data[0] << 8 ) | err.data[1] ); + + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << k_funcinfo << "found TLV(8) [ERROR] error= " << + errorNum << endl; + Oscar::SNAC s = { 0, 0, 0, 0 }; + client()->fatalTaskError( s, errorNum ); + setError( errorNum, TQString() ); + return; //if there's an error, we'll need to disconnect anyways + } + + TLV server = findTLV( tlvList, 0x0005 ); + if ( server ) + { + TQString ip = TQString( server.data ); + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "found TLV(5) [SERVER] " << ip << endl; + int index = ip.find( ':' ); + m_bosHost = ip.left( index ); + ip.remove( 0 , index+1 ); //get rid of the colon and everything before it + m_bosPort = ip.left(4); //we only need 4 bytes + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "We should reconnect to server '" << m_bosHost << + "' on port " << m_bosPort << endl; + } + + TLV cookie = findTLV( tlvList, 0x0006 ); + if ( cookie ) + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "found TLV(6) [COOKIE]" << endl; + m_cookie.duplicate( cookie.data ); + setSuccess( 0, TQString() ); + } + tlvList.clear(); +} + +void AimLoginTask::encodePassword( TQByteArray& digest ) const +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << endl; + md5_state_t state; + md5_init( &state ); + md5_append( &state, ( const md5_byte_t* ) m_authKey.data(), m_authKey.size() ); + md5_append( &state, ( const md5_byte_t* ) client()->password().latin1(), client()->password().length() ); + md5_append( &state, ( const md5_byte_t* ) AIM_MD5_STRING, strlen( AIM_MD5_STRING ) ); + md5_finish( &state, ( md5_byte_t* ) digest.data() ); +} + +//kate: indent-mode csands; tab-width 4; + +#include "aimlogintask.moc" diff --git a/kopete/protocols/oscar/liboscar/aimlogintask.h b/kopete/protocols/oscar/liboscar/aimlogintask.h new file mode 100644 index 00000000..82850a47 --- /dev/null +++ b/kopete/protocols/oscar/liboscar/aimlogintask.h @@ -0,0 +1,83 @@ +/* + Kopete Oscar Protocol + aimlogintask.h - Handles logging into to the AIM service + + Copyright (c) 2004 Matt Rogers <mattr@kde.org> + + Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org> + + ************************************************************************* + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + ************************************************************************* +*/ + +#ifndef _OSCAR_AIMLOGINTASK_H_ +#define _OSCAR_AIMLOGINTASK_H_ + +#include "task.h" + +using namespace Oscar; + +class AimLoginTask : public Task +{ +Q_OBJECT + +public: + AimLoginTask( Task* parent ); + ~AimLoginTask(); + bool take( Transfer* transfer ); + virtual void onGo(); + + //Protocol specific stuff + const TQByteArray& cookie() const; + const TQString& bosHost() const; + const TQString& bosPort() const; + +protected: + bool forMe( Transfer* transfer ) const; + +signals: + void haveAuthKey(); + +private: + //! Encodes a password using MD5 + void encodePassword( TQByteArray& digest ) const; + + //! Send SNAC 0x17, 0x06 + void sendAuthStringRequest(); + + //! Handle SNAC 0x17, 0x07 + void processAuthStringReply(); + + //! Handle SNAC 0x17, 0x03 + void handleLoginResponse(); + + //! Parse the error codes to generate a reason why sign-on failed + //Massive code duplication with CloseConnectionTask + bool parseDisconnectCode( int error, TQString& reason ); + +private slots: + //! Send SNAC 0x17, 0x02 + void sendLoginRequest(); + +private: + //! The authorization key to use when encoding the password + TQByteArray m_authKey; + + //! The all important connection cookie + TQByteArray m_cookie; + + //! The new BOS Host + TQString m_bosHost; + + //! The new BOS Port + TQString m_bosPort; + +}; + +#endif diff --git a/kopete/protocols/oscar/liboscar/buddyicontask.cpp b/kopete/protocols/oscar/liboscar/buddyicontask.cpp index 43e3e792..c7661481 100644 --- a/kopete/protocols/oscar/liboscar/buddyicontask.cpp +++ b/kopete/protocols/oscar/liboscar/buddyicontask.cpp @@ -69,7 +69,10 @@ void BuddyIconTask::onGo() if ( m_action == Receive ) { - sendICQBuddyIconRequest(); + if ( client()->isIcq() ) + sendICQBuddyIconRequest(); + else + sendAIMBuddyIconRequest(); } else sendIcon(); @@ -117,6 +120,8 @@ bool BuddyIconTask::take( Transfer* transfer ) setTransfer( transfer ); if ( st->snacSubtype() == 0x0003 ) handleUploadResponse(); + else if ( st->snacSubtype() == 0x0005 ) + handleAIMBuddyIconResponse(); else handleICQBuddyIconResponse(); @@ -152,6 +157,41 @@ void BuddyIconTask::handleUploadResponse() } +void BuddyIconTask::sendAIMBuddyIconRequest() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "requesting buddy icon for " << m_user << endl; + FLAP f = { 0x02, 0, 0 }; + m_seq = client()->snacSequence(); + SNAC s = { 0x0010, 0x0004, 0x0000, m_seq }; + Buffer* b = new Buffer; + + b->addBUIN( m_user.latin1() ); //TODO: check encoding + b->addByte( 0x01 ); + b->addWord( 0x0001 ); + b->addByte( m_hashType ); + b->addByte( m_hash.size() ); //MD5 Hash Size + b->addString( m_hash, m_hash.size() ); //MD5 Hash + Transfer* t = createTransfer( f, s, b ); + send( t ); +} + +void BuddyIconTask::handleAIMBuddyIconResponse() +{ + Buffer* b = transfer()->buffer(); + TQString user = b->getBUIN(); + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Receiving buddy icon for " << user << endl; + b->skipBytes(2); //unknown field. not used + BYTE iconType = b->getByte(); + Q_UNUSED( iconType ); + BYTE hashSize = b->getByte(); + TQByteArray iconHash; + iconHash.duplicate( b->getBlock(hashSize) ); + WORD iconSize = b->getWord(); + TQByteArray icon; + icon.duplicate( b->getBlock(iconSize) ); + emit haveIcon( user, icon ); +} + void BuddyIconTask::sendICQBuddyIconRequest() { kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "requesting buddy icon for " << m_user << endl; diff --git a/kopete/protocols/oscar/liboscar/buddyicontask.h b/kopete/protocols/oscar/liboscar/buddyicontask.h index 1a18aa45..c3b7c4f9 100644 --- a/kopete/protocols/oscar/liboscar/buddyicontask.h +++ b/kopete/protocols/oscar/liboscar/buddyicontask.h @@ -50,6 +50,8 @@ signals: private: void sendIcon(); void handleUploadResponse(); + void sendAIMBuddyIconRequest(); + void handleAIMBuddyIconResponse(); void sendICQBuddyIconRequest(); void handleICQBuddyIconResponse(); diff --git a/kopete/protocols/oscar/liboscar/changevisibilitytask.h b/kopete/protocols/oscar/liboscar/changevisibilitytask.h index 554645f4..0ec5ab04 100644 --- a/kopete/protocols/oscar/liboscar/changevisibilitytask.h +++ b/kopete/protocols/oscar/liboscar/changevisibilitytask.h @@ -24,7 +24,7 @@ /** * This class provides a way to change how the account user * appears on everybody else's contact list. It is used to - * implement the invisible online status in ICQ + * implement the invisible online status in ICQ and AIM * @author Matt Rogers */ class ChangeVisibilityTask : public Task diff --git a/kopete/protocols/oscar/liboscar/client.cpp b/kopete/protocols/oscar/liboscar/client.cpp index 2bae2155..7ed6c0d6 100644 --- a/kopete/protocols/oscar/liboscar/client.cpp +++ b/kopete/protocols/oscar/liboscar/client.cpp @@ -93,6 +93,7 @@ public: int stage; //Protocol specific data + bool isIcq; bool redirectRequested; TQValueList<WORD> redirectionServices; WORD currentRedirect; @@ -145,6 +146,7 @@ Client::Client( TQObject* parent ) d = new ClientPrivate; d->tzoffset = 0; d->active = false; + d->isIcq = false; //default to AIM d->redirectRequested = false; d->currentRedirect = 0; d->connectAsStatus = 0x0; // default to online @@ -231,6 +233,30 @@ void Client::close() d->ssiManager->clear(); } +void Client::setStatus( AIMStatus status, const TQString &_message ) +{ + // AIM: you're away exactly when your away message isn't empty. + // can't use TQString() as a message either; ProfileTask + // interprets null as "don't change". + TQString message; + if ( status == Online ) + message = TQString::fromAscii(""); + else + { + if ( _message.isEmpty() ) + message = TQString::fromAscii(" "); + else + message = _message; + } + + Connection* c = d->connections.connectionForFamily( 0x0002 ); + if ( !c ) + return; + ProfileTask* pt = new ProfileTask( c->rootTask() ); + pt->setAwayMessage( message ); + pt->go( true ); +} + void Client::setStatus( DWORD status, const TQString &message ) { // remember the message to reply with, when requested @@ -372,20 +398,24 @@ void Client::serviceSetupFinished() { d->active = true; - setStatus( d->connectAsStatus, d->connectWithMessage ); + if ( isIcq() ) + setStatus( d->connectAsStatus, d->connectWithMessage ); d->ownStatusTask->go(); - //retrieve offline messages - Connection* c = d->connections.connectionForFamily( 0x0015 ); - if ( !c ) { - return; - } + if ( isIcq() ) + { + //retrieve offline messages + Connection* c = d->connections.connectionForFamily( 0x0015 ); + if ( !c ) { + return; + } - OfflineMessagesTask *offlineMsgTask = new OfflineMessagesTask( c->rootTask() ); - connect( offlineMsgTask, TQT_SIGNAL( receivedOfflineMessage(const Oscar::Message& ) ), - this, TQT_SIGNAL( messageReceived(const Oscar::Message& ) ) ); - offlineMsgTask->go( true ); + OfflineMessagesTask *offlineMsgTask = new OfflineMessagesTask( c->rootTask() ); + connect( offlineMsgTask, TQT_SIGNAL( receivedOfflineMessage(const Oscar::Message& ) ), + this, TQT_SIGNAL( messageReceived(const Oscar::Message& ) ) ); + offlineMsgTask->go( true ); + } emit haveSSIList(); emit loggedIn(); @@ -566,6 +596,16 @@ bool Client::isActive() const return d->active; } +bool Client::isIcq() const +{ + return d->isIcq; +} + +void Client::setIsIcq( bool isIcq ) +{ + d->isIcq = isIcq; +} + void Client::debug( const TQString& str ) { Q_UNUSED(str); @@ -813,6 +853,16 @@ void Client::setChatExchangeList( const TQValueList<int>& exchanges ) d->exchanges = exchanges; } +void Client::requestAIMProfile( const TQString& contact ) +{ + d->userInfoTask->requestInfoFor( contact, UserInfoTask::Profile ); +} + +void Client::requestAIMAwayMessage( const TQString& contact ) +{ + d->userInfoTask->requestInfoFor( contact, UserInfoTask::AwayMessage ); +} + void Client::requestICQAwayMessage( const TQString& contact, ICQStatus contactStatus ) { kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "requesting away message for " << contact << endl; @@ -944,6 +994,17 @@ void Client::uinSearch( const TQString& uin ) ust->searchUserByUIN( uin ); } +void Client::updateProfile( const TQString& profile ) +{ + Connection* c = d->connections.connectionForFamily( 0x0002 ); + if ( !c ) { + return; + } + ProfileTask* pt = new ProfileTask( c->rootTask() ); + pt->setProfileText( profile ); + pt->go(true); +} + void Client::sendTyping( const TQString & contact, bool typing ) { Connection* c = d->connections.connectionForFamily( 0x0004 ); diff --git a/kopete/protocols/oscar/liboscar/client.h b/kopete/protocols/oscar/liboscar/client.h index f71a8333..71cf668a 100644 --- a/kopete/protocols/oscar/liboscar/client.h +++ b/kopete/protocols/oscar/liboscar/client.h @@ -68,6 +68,7 @@ public: FatalProtocolError = 3 }; + enum AIMStatus { Online = 0, Away }; enum ICQStatus { ICQOnline = 0, ICQAway, ICQNotAvailable, ICQOccupied, ICQDoNotDisturb, ICQFreeForChat }; /************* @@ -101,6 +102,8 @@ public: /** Logout and disconnect */ void close(); + /** Set our status for AIM */ + void setStatus( AIMStatus status, const TQString &message = TQString() ); /** Set our status for ICQ */ void setStatus( DWORD status, const TQString &message = TQString() ); @@ -238,6 +241,18 @@ public: TQValueList<int> chatExchangeList() const; /** + * Request the aim profile + * \param contact the contact to get info for + */ + void requestAIMProfile( const TQString& contact ); + + /** + * Request the aim away message + * \param contact the contact to get info for + */ + void requestAIMAwayMessage( const TQString& contact ); + + /** * Add the icq away message request to queue * \param contact the contact to get info for */ @@ -258,6 +273,9 @@ public: //! Run a UIN search void uinSearch( const TQString& uin ); + //! Update the user's AIM profile + void updateProfile( const TQString& profile ); + //! Get buddy icon information for a person void requestBuddyIcon( const TQString& user, const TQByteArray& hash, BYTE hashType ); @@ -326,6 +344,10 @@ public: /** Change the current status message w/o changing status */ void setStatusMessage( const TQString &message ); + /** ICQ Settings */ + bool isIcq() const; + void setIsIcq( bool isIcq ); + /** Host's IP address */ TQCString ipAddress() const; diff --git a/kopete/protocols/oscar/liboscar/clientreadytask.cpp b/kopete/protocols/oscar/liboscar/clientreadytask.cpp index 6d1b07a7..3025a0d8 100644 --- a/kopete/protocols/oscar/liboscar/clientreadytask.cpp +++ b/kopete/protocols/oscar/liboscar/clientreadytask.cpp @@ -64,21 +64,38 @@ void ClientReadyTask::onGo() buffer->addWord( 0x0003 ); break; case 0x0013: - buffer->addWord( 0x0002 ); + buffer->addWord( client()->isIcq() ? 0x0002 : 0x0003 ); break; default: buffer->addWord( 0x0001 ); }; - - if ( i == 0x0002 ) { - buffer->addWord( 0x0101 ); + + if ( client()->isIcq() ) + { + if ( i == 0x0002 ) + buffer->addWord( 0x0101 ); + else + buffer->addWord( 0x0110 ); + + //always add 0x047B + buffer->addWord( 0x047B ); } - else { - buffer->addWord( 0x0110 ); + else //we're AIM so AOL has us do something completely different! *sigh* + { + switch( i ) + { + case 0x0008: + case 0x000B: + case 0x000C: + buffer->addWord( 0x0104 ); + buffer->addWord( 0x0001 ); + break; + default: + buffer->addWord( 0x0110 ); + buffer->addWord( 0x059B ); + break; + }; } - - //always add 0x047B - buffer->addWord( 0x047B ); } //send the damn thing so we can finally be finished diff --git a/kopete/protocols/oscar/liboscar/connection.cpp b/kopete/protocols/oscar/liboscar/connection.cpp index dc66aefa..16757785 100644 --- a/kopete/protocols/oscar/liboscar/connection.cpp +++ b/kopete/protocols/oscar/liboscar/connection.cpp @@ -154,6 +154,11 @@ TQString Connection::password() const return d->client->password(); } +bool Connection::isIcq() const +{ + return d->client->isIcq(); +} + Task* Connection::rootTask() const { return d->root; diff --git a/kopete/protocols/oscar/liboscar/connection.h b/kopete/protocols/oscar/liboscar/connection.h index 962c84c1..9a3cd861 100644 --- a/kopete/protocols/oscar/liboscar/connection.h +++ b/kopete/protocols/oscar/liboscar/connection.h @@ -143,6 +143,7 @@ public: TQString userId() const; TQString password() const; + bool isIcq() const; SSIManager* ssiManager() const; const Oscar::ClientVersion* version() const; RateClassManager* rateManager() const; diff --git a/kopete/protocols/oscar/liboscar/logintask.cpp b/kopete/protocols/oscar/liboscar/logintask.cpp index c3d568f9..73379e40 100644 --- a/kopete/protocols/oscar/liboscar/logintask.cpp +++ b/kopete/protocols/oscar/liboscar/logintask.cpp @@ -1,6 +1,6 @@ /* Kopete Oscar Protocol - logintask.cpp - Handles logging into to the ICQ service + logintask.cpp - Handles logging into to the AIM or ICQ service Copyright (c) 2004 Matt Rogers <mattr@kde.org> @@ -22,6 +22,7 @@ #include <kdebug.h> #include <tdelocale.h> +#include "aimlogintask.h" #include "connection.h" #include "closeconnectiontask.h" #include "icqlogintask.h" @@ -39,26 +40,49 @@ StageOneLoginTask::StageOneLoginTask( Task* parent ) : Task ( parent ) { + m_aimTask = 0L; m_icqTask = 0L; m_closeTask = 0L; } StageOneLoginTask::~StageOneLoginTask() { + delete m_aimTask; delete m_icqTask; delete m_closeTask; } bool StageOneLoginTask::take( Transfer* transfer ) { - if ( forMe( transfer ) ) { - kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Starting ICQ login" << endl; - m_icqTask = new IcqLoginTask( client()->rootTask() ); - m_closeTask = new CloseConnectionTask( client()->rootTask() ); - - //connect finished signal - connect( m_closeTask, TQT_SIGNAL( finished() ), this, TQT_SLOT( closeTaskFinished() ) ); - m_icqTask->go( true ); + if ( forMe( transfer ) ) + { + if ( client()->isIcq() ) + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Starting ICQ login" << endl; + m_icqTask = new IcqLoginTask( client()->rootTask() ); + m_closeTask = new CloseConnectionTask( client()->rootTask() ); + + //connect finished signal + connect( m_closeTask, TQT_SIGNAL( finished() ), this, TQT_SLOT( closeTaskFinished() ) ); + m_icqTask->go( true ); + } + else + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Starting AIM login" << endl; + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Sending the FLAP version back" << endl; + + //send the flap version response + FLAP f = { 0x01, 0 , 0 }; + Buffer *outbuf = new Buffer; + outbuf->addDWord(0x00000001); //flap version + f.length = outbuf->length(); + Transfer* ft = createTransfer( f, outbuf ); + send( ft ); + + m_aimTask = new AimLoginTask( client()->rootTask() ); + connect( m_aimTask, TQT_SIGNAL( finished() ), this, TQT_SLOT( aimTaskFinished() ) ); + m_aimTask->go( true ); + } return true; } return false; @@ -74,6 +98,16 @@ void StageOneLoginTask::closeTaskFinished() setSuccess( m_closeTask->statusCode(), m_closeTask->statusString() ); } +void StageOneLoginTask::aimTaskFinished() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << endl; + m_cookie = m_aimTask->cookie(); + m_bosPort = m_aimTask->bosPort(); + m_bosServer = m_aimTask->bosHost(); + + setSuccess( m_aimTask->statusCode(), m_aimTask->statusString() ); +} + bool StageOneLoginTask::forMe( Transfer* transfer ) const { FlapTransfer* ft = dynamic_cast<FlapTransfer*> ( transfer ); diff --git a/kopete/protocols/oscar/liboscar/logintask.h b/kopete/protocols/oscar/liboscar/logintask.h index 626de7bb..3e1a21c5 100644 --- a/kopete/protocols/oscar/liboscar/logintask.h +++ b/kopete/protocols/oscar/liboscar/logintask.h @@ -1,6 +1,6 @@ /* Kopete Oscar Protocol - logintask.h - Handles logging into to the ICQ service + logintask.h - Handles logging into to the AIM or ICQ service Copyright (c) 2004 Matt Rogers <mattr@kde.org> @@ -23,6 +23,7 @@ #include "oscartypes.h" #include "task.h" +#include "aimlogintask.h" #include "icqlogintask.h" #include "closeconnectiontask.h" @@ -69,6 +70,7 @@ public: public slots: void closeTaskFinished(); + void aimTaskFinished(); protected: bool forMe( Transfer* transfer ) const; @@ -76,6 +78,7 @@ protected: private: //Tasks we want to control + AimLoginTask* m_aimTask; IcqLoginTask* m_icqTask; CloseConnectionTask* m_closeTask; diff --git a/kopete/protocols/oscar/liboscar/oscartypes.h b/kopete/protocols/oscar/liboscar/oscartypes.h index ffe76c30..4e13a509 100644 --- a/kopete/protocols/oscar/liboscar/oscartypes.h +++ b/kopete/protocols/oscar/liboscar/oscartypes.h @@ -27,6 +27,7 @@ //! Debug Areas const int OSCAR_RAW_DEBUG = 14151; const int OSCAR_GEN_DEBUG = 14150; +const int OSCAR_AIM_DEBUG = 14152; const int OSCAR_ICQ_DEBUG = 14153; namespace Oscar @@ -247,6 +248,9 @@ struct ClientVersion /* ICQ Version Characteristics */ const unsigned char ICQ_TCP_VERSION = 0x0008; + /* AIM Version Characteristics */ + const char AIM_MD5_STRING[] = "AOL Instant Messenger (SM)"; + /* SSI types */ const WORD ROSTER_CONTACT = 0x0000; // a normal contact const WORD ROSTER_GROUP = 0x0001; // a group of contacts diff --git a/kopete/protocols/oscar/liboscar/profiletask.cpp b/kopete/protocols/oscar/liboscar/profiletask.cpp index 4b2122a0..bc516fff 100644 --- a/kopete/protocols/oscar/liboscar/profiletask.cpp +++ b/kopete/protocols/oscar/liboscar/profiletask.cpp @@ -74,13 +74,39 @@ void ProfileTask::sendProfileUpdate() Buffer *buffer = new Buffer(); Buffer capBuf; - capBuf.addString( oscar_caps[CAP_ICQSERVERRELAY], 16 ); // we support type-2 messages - capBuf.addString( oscar_caps[CAP_UTF8], 16 ); // we can send/receive UTF encoded messages - capBuf.addString( oscar_caps[CAP_ISICQ], 16 ); // I think this is an icq client, but maybe I'm wrong - capBuf.addString( oscar_caps[CAP_KOPETE], 16 ); // we are the borg, resistance is futile - //capBuf.addString( oscar_caps[CAP_RTFMSGS], 16 ); // we do incoming RTF messages - capBuf.addString( oscar_caps[CAP_TYPING], 16 ); // we know you're typing something to us! - capBuf.addString( oscar_caps[CAP_BUDDYICON], 16 ); //can you take my picture? + if ( !m_profileText.isNull() && !client()->isIcq() ) + { + static const TQString defencoding = "text/aolrtf; charset=\"us-ascii\""; + buffer->addTLV(0x0001, defencoding.length(), defencoding.latin1()); + buffer->addTLV(0x0002, m_profileText.length(), m_profileText.local8Bit()); + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "setting profile = " << m_profileText << endl; + } + + if ( !m_awayMessage.isNull() && !client()->isIcq() ) + { + static const TQString defencoding = "text/aolrtf; charset=\"us-ascii\""; + buffer->addTLV(0x0003, defencoding.length(), defencoding.latin1()); + buffer->addTLV(0x0004, m_awayMessage.length(), m_awayMessage.local8Bit()); + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "setting away message = " << m_awayMessage << endl; + } + + if ( client()->isIcq() ) + { + capBuf.addString( oscar_caps[CAP_ICQSERVERRELAY], 16 ); // we support type-2 messages + capBuf.addString( oscar_caps[CAP_UTF8], 16 ); // we can send/receive UTF encoded messages + capBuf.addString( oscar_caps[CAP_ISICQ], 16 ); // I think this is an icq client, but maybe I'm wrong + capBuf.addString( oscar_caps[CAP_KOPETE], 16 ); // we are the borg, resistance is futile + //capBuf.addString( oscar_caps[CAP_RTFMSGS], 16 ); // we do incoming RTF messages + capBuf.addString( oscar_caps[CAP_TYPING], 16 ); // we know you're typing something to us! + capBuf.addString( oscar_caps[CAP_BUDDYICON], 16 ); //can you take my picture? + } + else + { + capBuf.addString( oscar_caps[CAP_UTF8], 16 ); //we can send/receive UTF encoded messages + capBuf.addString( oscar_caps[CAP_KOPETE], 16 ); // we are the borg, resistance is futile + capBuf.addString( oscar_caps[CAP_TYPING], 16 ); // we know you're typing something to us! + capBuf.addString( oscar_caps[CAP_BUDDYICON], 16 ); //can you take my picture? + } //kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "adding capabilities, size=" << capBuf.length() << endl; buffer->addTLV(0x0005, capBuf.length(), capBuf.buffer()); diff --git a/kopete/protocols/oscar/liboscar/profiletask.h b/kopete/protocols/oscar/liboscar/profiletask.h index 69d1119e..a51075a5 100644 --- a/kopete/protocols/oscar/liboscar/profiletask.h +++ b/kopete/protocols/oscar/liboscar/profiletask.h @@ -21,7 +21,8 @@ #include "task.h" /** -Also takes care of updating the capabilities supported by the client (ICQ). +Task that sets the profile and away message on the server (AIM only). +Also takes care of updating the capabilities supported by the client (AIM and ICQ). The profile will be updated only if the profile text has been set non-null. The away message will be set only if the away message has been set non-null. diff --git a/kopete/protocols/oscar/liboscar/sendmessagetask.cpp b/kopete/protocols/oscar/liboscar/sendmessagetask.cpp index 0f9c8f5f..d95c17ed 100644 --- a/kopete/protocols/oscar/liboscar/sendmessagetask.cpp +++ b/kopete/protocols/oscar/liboscar/sendmessagetask.cpp @@ -98,9 +98,21 @@ void SendMessageTask::onGo() break; } - b->addDWord( 0x00030000 ); //empty TLV 3 to get an ack from the server + // Add the TLV to indicate if this is an autoresponse: 0x00040000 + // Right now, only supported for the AIM client, I'm not sure about ICQ + // For some reason you can't have both a 0x0004 and 0x0003 TLV in the same + // SNAC, if you do the AIM server complains + if ( !client()->isIcq() && (m_autoResponse == true) ) + { + TLV tlv4( 0x0004, 0, NULL); + b->addTLV( tlv4 ); + } + else + { + b->addDWord( 0x00030000 ); //empty TLV 3 to get an ack from the server + } - if ( m_message.type() != 2 && ! m_message.hasProperty( Oscar::Message::StatusMessageRequest ) ) { + if ( client()->isIcq() && m_message.type() != 2 && ! m_message.hasProperty( Oscar::Message::StatusMessageRequest ) ) { b->addDWord( 0x00060000 ); //empty TLV 6 to store message on the server if not online } } @@ -130,10 +142,18 @@ void SendMessageTask::addChannel1Data( Buffer* b ) { Buffer tlv2buffer; - //Send features TLV using data from pidgin. - tlv2buffer.addDWord( 0x05010002 ); //TLV 0x0501, length 2 - tlv2buffer.addWord( 0x0106 ); //TLV 0x0501 data - + //Send features TLV using data from pidgin. Features are different + //depending on whether we're ICQ or AIM + if ( client()->isIcq() ) + { + tlv2buffer.addDWord( 0x05010002 ); //TLV 0x0501, length 2 + tlv2buffer.addWord( 0x0106 ); //TLV 0x0501 data + } + else + { + tlv2buffer.addDWord( 0x05010004 ); //TLV 0x0501, length 4 + tlv2buffer.addDWord( 0x01010102 ); //TLV 0x0501 data. + } //we only send one message part. There's only one client that actually uses //them and it's quite old and infrequently used tlv2buffer.addWord( 0x0101 ); //add TLV(0x0101) also known as TLV(257) diff --git a/kopete/protocols/oscar/liboscar/serverversionstask.cpp b/kopete/protocols/oscar/liboscar/serverversionstask.cpp index 7d001ec3..336f3b02 100644 --- a/kopete/protocols/oscar/liboscar/serverversionstask.cpp +++ b/kopete/protocols/oscar/liboscar/serverversionstask.cpp @@ -115,6 +115,7 @@ void ServerVersionsTask::handleFamilies() void ServerVersionsTask::requestFamilyVersions() { + bool isIcq = client()->isIcq(); int listLength = m_familiesList.count(); FLAP f = { 0x02, 0, 0 }; @@ -124,18 +125,22 @@ void ServerVersionsTask::requestFamilyVersions() kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "SEND SNAC 0x01, 0x17 - Snac family versions we want" << endl; - for ( int i = 0; i < listLength; i++ ) { + for ( int i = 0; i < listLength; i++ ) + { outbuf->addWord( m_familiesList[i] ); - if ( m_familiesList[i] == 0x0001 ) { + if ( m_familiesList[i] == 0x0001 ) val = 0x0003; - } - else { - if ( m_familiesList[i] == 0x0013 ) { - val = 0x0004; // for ICQ2002 + else + { + if ( m_familiesList[i] == 0x0013 ) + { + if ( isIcq ) + val = 0x0004; // for ICQ2002 + else + val = 0x0003; } - else { + else val = 0x0001; - } } outbuf->addWord(val); diff --git a/kopete/protocols/oscar/liboscar/tests/logintest.cpp b/kopete/protocols/oscar/liboscar/tests/logintest.cpp index e344c3e1..d1025059 100644 --- a/kopete/protocols/oscar/liboscar/tests/logintest.cpp +++ b/kopete/protocols/oscar/liboscar/tests/logintest.cpp @@ -33,6 +33,7 @@ void LoginTest::slotDoTest() // connect to server tqDebug( "connecting to server "); + myClient->setIsIcq( true ); myClient->start( server, 5190, "userid", "password" ); myClient->connectToServer( myConnection, server, true ); connected = true; diff --git a/kopete/protocols/oscar/liboscar/tests/ssigrouptest.cpp b/kopete/protocols/oscar/liboscar/tests/ssigrouptest.cpp index 2f646ecf..410b6021 100644 --- a/kopete/protocols/oscar/liboscar/tests/ssigrouptest.cpp +++ b/kopete/protocols/oscar/liboscar/tests/ssigrouptest.cpp @@ -33,6 +33,7 @@ void LoginTest::slotDoTest() // connect to server tqDebug( "connecting to server "); + myClient->setIsIcq( true ); myClient->start( server, 5190, "userid", "password" ); myClient->connectToServer( myConnection, server, true ); TQTimer::singleShot( 10000, this, TQT_SLOT(runAddGroupTest() ) ); diff --git a/kopete/protocols/oscar/liboscar/tests/userinfotest.cpp b/kopete/protocols/oscar/liboscar/tests/userinfotest.cpp index d7ccac68..8d75b79d 100644 --- a/kopete/protocols/oscar/liboscar/tests/userinfotest.cpp +++ b/kopete/protocols/oscar/liboscar/tests/userinfotest.cpp @@ -33,6 +33,7 @@ void LoginTest::slotDoTest() // connect to server tqDebug( "connecting to server "); + myClient->setIsIcq( true ); myClient->start( server, 5190, "userid", "password" ); myClient->connectToServer( myConnection, server, true ); //TQObject::connect( myClient, TQT_SIGNAL( userIsOnline( const TQString& ) ), this, TQT_SLOT( runUserInfoTest())); diff --git a/kopete/protocols/oscar/oscaraccount.cpp b/kopete/protocols/oscar/oscaraccount.cpp index a28a8035..b74a12e7 100644 --- a/kopete/protocols/oscar/oscaraccount.cpp +++ b/kopete/protocols/oscar/oscaraccount.cpp @@ -95,17 +95,21 @@ public: }; OscarAccount::OscarAccount(Kopete::Protocol *parent, const TQString &accountID, const char *name, bool isICQ) -: Kopete::PasswordedAccount( parent, accountID, 8, name ) +: Kopete::PasswordedAccount( parent, accountID, isICQ ? 8 : 16, name ) { kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << " accountID='" << accountID << "', isICQ=" << isICQ << endl; d = new OscarAccountPrivate( *this ); d->engine = new Client( this ); - + d->engine->setIsIcq( isICQ ); + d->versionAlreadyUpdated = false; d->versionUpdaterStamp = OscarVersionUpdater::self()->stamp(); - d->engine->setVersion( OscarVersionUpdater::self()->getICQVersion() ); + if ( isICQ ) + d->engine->setVersion( OscarVersionUpdater::self()->getICQVersion() ); + else + d->engine->setVersion( OscarVersionUpdater::self()->getAIMVersion() ); d->engine->setCodecProvider( d ); d->olnscDialog = 0L; @@ -178,6 +182,13 @@ void OscarAccount::loginActions() kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "processing SSI list" << endl; processSSIList(); + //start a chat nav connection + if ( !engine()->isIcq() ) + { + kdDebug(OSCAR_GEN_DEBUG) << k_funcinfo << "sending request for chat nav service" << endl; + d->engine->requestServerRedirect( 0x000D ); + } + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "sending request for icon service" << endl; d->engine->requestServerRedirect( 0x0010 ); @@ -462,7 +473,7 @@ void OscarAccount::setBuddyIcon( KURL url ) if ( image.isNull() ) return; - const TQSize size = TQSize( 52, 64 ); + const TQSize size = ( d->engine->isIcq() ) ? TQSize( 52, 64 ) : TQSize( 48, 48 ); image = image.smoothScale( size, TQ_ScaleMax ); if( image.width() > size.width()) @@ -794,8 +805,9 @@ void OscarAccount::slotSendBuddyIcon() TQString OscarAccount::getFLAPErrorMessage( int code ) { - TQString acctType = i18n("ICQ"); - TQString acctDescription = i18n("ICQ user id", "UIN"); + bool isICQ = d->engine->isIcq(); + TQString acctType = isICQ ? i18n("ICQ") : i18n("AIM"); + TQString acctDescription = isICQ ? i18n("ICQ user id", "UIN") : i18n("AIM user id", "screen name"); TQString reason; //FLAP errors are always fatal //negative codes are things added by liboscar developers diff --git a/kopete/protocols/oscar/oscaraccount.h b/kopete/protocols/oscar/oscaraccount.h index d53208d2..2a657d06 100644 --- a/kopete/protocols/oscar/oscaraccount.h +++ b/kopete/protocols/oscar/oscaraccount.h @@ -45,7 +45,7 @@ class KDE_EXPORT OscarAccount : public Kopete::PasswordedAccount public: - OscarAccount(Kopete::Protocol *parent, const TQString &accountID, const char *name=0L, bool isICQ=true); + OscarAccount(Kopete::Protocol *parent, const TQString &accountID, const char *name=0L, bool isICQ=false); virtual ~OscarAccount(); /** Provide the derived accounts and contacts with access to the backend */ diff --git a/kopete/protocols/oscar/oscarcontact.cpp b/kopete/protocols/oscar/oscarcontact.cpp index 0ef5673a..4de182ad 100644 --- a/kopete/protocols/oscar/oscarcontact.cpp +++ b/kopete/protocols/oscar/oscarcontact.cpp @@ -170,9 +170,15 @@ void OscarContact::userInfoUpdated( const TQString& contact, const UserDetails& TQStringList capList; // Append client name and version in case we found one - if ( !m_details.clientName().isEmpty() ) { - capList << i18n( "Translators: client name and version", - "%1").arg( m_details.clientName() ); + if ( m_details.userClass() & 0x0080 /* WIRELESS */ ) + capList << i18n( "Mobile AIM Client" ); + else + { + if ( !m_details.clientName().isEmpty() ) + { + capList << i18n( "Translators: client name and version", + "%1").arg( m_details.clientName() ); + } } // and now for some general informative capabilities diff --git a/kopete/protocols/oscar/oscarversionupdater.cpp b/kopete/protocols/oscar/oscarversionupdater.cpp index 7d5806e3..16149c18 100644 --- a/kopete/protocols/oscar/oscarversionupdater.cpp +++ b/kopete/protocols/oscar/oscarversionupdater.cpp @@ -32,6 +32,7 @@ OscarVersionUpdater::OscarVersionUpdater() : mStamp( 1 ), mUpdating( false ) { initICQVersionInfo(); + initAIMVersionInfo(); } OscarVersionUpdater::~OscarVersionUpdater() @@ -99,8 +100,37 @@ void OscarVersionUpdater::initICQVersionInfo() mICQVersion.lang = config.readEntry( "Lang", "en" ); } +void OscarVersionUpdater::initAIMVersionInfo() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << endl; + + TDEConfigGroup config( TDEGlobal::config(), "AIMVersion" ); + + mAIMVersion.clientString = config.readEntry( "ClientString", "AOL Instant Messenger (SM), version 5.1.3036/WIN32" ); + mAIMVersion.clientId = config.readEntry( "ClientId", "0x0109" ).toUShort( 0, 0 ); + mAIMVersion.major = config.readEntry( "Major", "0x0005" ).toUShort( 0, 0 ); + mAIMVersion.minor = config.readEntry( "Minor", "0x0001" ).toUShort( 0, 0 ); + mAIMVersion.point = config.readEntry( "Point", "0x0000" ).toUShort( 0, 0 ); + mAIMVersion.build = config.readEntry( "Build", "0x0bdc" ).toUShort( 0, 0 ); + mAIMVersion.other = config.readEntry( "Other", "0x000000d2" ).toUInt( 0, 0 ); + mAIMVersion.country = config.readEntry( "Country", "us" ); + mAIMVersion.lang = config.readEntry( "Lang", "en" ); +} + void OscarVersionUpdater::printDebug() { + kdDebug(OSCAR_RAW_DEBUG) << "*************** AIM VERSION INFO ***************" << endl; + kdDebug(OSCAR_RAW_DEBUG) << "client string: " << mAIMVersion.clientString << endl; + kdDebug(OSCAR_RAW_DEBUG) << "client id: " << TQString::number( mAIMVersion.clientId, 16 ) << endl; + kdDebug(OSCAR_RAW_DEBUG) << "major: " << TQString::number( mAIMVersion.major, 16 ) << endl; + kdDebug(OSCAR_RAW_DEBUG) << "minor: " << TQString::number( mAIMVersion.minor, 16 ) << endl; + kdDebug(OSCAR_RAW_DEBUG) << "point: " << TQString::number( mAIMVersion.point, 16 ) << endl; + kdDebug(OSCAR_RAW_DEBUG) << "build: " << TQString::number( mAIMVersion.build, 16 ) << endl; + kdDebug(OSCAR_RAW_DEBUG) << "other: " << TQString::number( mAIMVersion.other, 16 ) << endl; + kdDebug(OSCAR_RAW_DEBUG) << "country: " << mAIMVersion.country << endl; + kdDebug(OSCAR_RAW_DEBUG) << "lang: " << mAIMVersion.lang << endl; + kdDebug(OSCAR_RAW_DEBUG) << "************************************************" << endl; + kdDebug(OSCAR_RAW_DEBUG) << "*************** ICQ VERSION INFO ***************" << endl; kdDebug(OSCAR_RAW_DEBUG) << "client string: " << mICQVersion.clientString << endl; kdDebug(OSCAR_RAW_DEBUG) << "client id: " << TQString::number( mICQVersion.clientId, 16 ) << endl; @@ -139,6 +169,7 @@ void OscarVersionUpdater::slotTransferResult ( TDEIO::Job *job ) if ( doc.setContent ( mVersionData ) ) { Oscar::ClientVersion tmpICQ = mICQVersion; + Oscar::ClientVersion tmpAIM = mAIMVersion; parseDocument( doc ); @@ -147,6 +178,12 @@ void OscarVersionUpdater::slotTransferResult ( TDEIO::Job *job ) storeVersionInfo( "ICQVersion", mICQVersion ); bUpdate = true; } + + if ( !equal( tmpAIM, mAIMVersion ) ) + { + storeVersionInfo( "AIMVersion", mAIMVersion ); + bUpdate = true; + } } } @@ -174,6 +211,9 @@ void OscarVersionUpdater::parseDocument( TQDomDocument& doc ) { if ( versionElement.tagName() == "icq" ) parseVersion( mICQVersion, versionElement ); + else if ( versionElement.tagName() == "aim" ) + parseVersion( mAIMVersion, versionElement ); + versionElement = versionElement.nextSibling().toElement(); } } diff --git a/kopete/protocols/oscar/oscarversionupdater.h b/kopete/protocols/oscar/oscarversionupdater.h index deec082d..5c39683f 100644 --- a/kopete/protocols/oscar/oscarversionupdater.h +++ b/kopete/protocols/oscar/oscarversionupdater.h @@ -64,11 +64,22 @@ public: const Oscar::ClientVersion* getICQVersion() const { return &mICQVersion; } /** + * Return structure with version info for AIM. + * @return Oscar::ClientVersion. + */ + const Oscar::ClientVersion* getAIMVersion() const { return &mAIMVersion; } + + /** * Set structure with ICQ version info to default. */ void initICQVersionInfo(); /** + * Set structure with AIM version info to default. + */ + void initAIMVersionInfo(); + + /** * Print debug info. */ void printDebug(); @@ -98,6 +109,7 @@ private: static OscarVersionUpdater *versionUpdaterStatic; Oscar::ClientVersion mICQVersion; + Oscar::ClientVersion mAIMVersion; TDEIO::TransferJob *mTransferJob; TQByteArray mVersionData; |