/* icqpresence.cpp - ICQ online status and presence management Copyright (c) 2004 by Richard Smith Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * 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 #include #include #include #include #include #include #include "icqprotocol.h" #include "icqpresence.h" namespace ICQ { //BEGIN struct PresenceTypeData struct PresenceTypeData { Presence::Type type; Kopete::OnlineStatus::StatusType onlineStatusType; unsigned long setFlag; unsigned long getFlag; TQString caption; TQString visibleName; TQString invisibleName; const char *visibleIcon; const char *invisibleIcon; unsigned int categories; unsigned int options; static const PresenceTypeData *all(); static const PresenceTypeData &forType( Presence::Type type ); static const PresenceTypeData &fortqStatus( unsigned long status ); static const PresenceTypeData &forOnlineStatusType( const Kopete::OnlineStatus::StatusType statusType ); }; const PresenceTypeData *PresenceTypeData::all() { using namespace Kopete; using namespace ICQ::StatusCode; /** * The order here is important - this is the order the IS_XXX flags will be checked for in. * That, in particular, means that NA, Occupied and DND must appear before Away, and that * DND must appear before Occupied. Offline (testing all bits) must go first, and Online * (testing no bits - will always match a status) must go last. * * Free For Chat is currently listed after Away, since if someone is Away + Free For Chat we * want to show them as Away more than we want to show them FFC. */ static const PresenceTypeData data[] = { { Presence::Offline, OnlineStatus::Offline, OFFLINE, OFFLINE, i18n( "O&ffline" ), i18n("Offline"), i18n("Offline"), 0, "contact_invisible_overlay", Kopete::OnlineStatusManager::Offline, 0 }, { Presence::DoNotDisturb, OnlineStatus::Away, SET_DND, IS_DND, i18n( "&Do Not Disturb" ), i18n("Do Not Disturb"), i18n("Do Not Disturb (Invisible)"), "contact_busy_overlay", "contact_invisible_overlay", Kopete::OnlineStatusManager::Busy, Kopete::OnlineStatusManager::HasAwayMessage }, { Presence::Occupied, OnlineStatus::Away, SET_OCC, IS_OCC, i18n( "O&ccupied" ), i18n("Occupied"), i18n("Occupied (Invisible)"), "contact_busy_overlay", "contact_invisible_overlay", 0, Kopete::OnlineStatusManager::HasAwayMessage }, { Presence::NotAvailable, OnlineStatus::Away, SET_NA, IS_NA, i18n( "Not A&vailable" ), i18n("Not Available"), i18n("Not Available (Invisible)"), "contact_xa_overlay", "contact_invisible_overlay", Kopete::OnlineStatusManager::ExtendedAway, Kopete::OnlineStatusManager::HasAwayMessage }, { Presence::Away, OnlineStatus::Away, SET_AWAY, IS_AWAY, i18n( "&Away" ), i18n("Away"), i18n("Away (Invisible)"), "contact_away_overlay", "contact_invisible_overlay", Kopete::OnlineStatusManager::Away, Kopete::OnlineStatusManager::HasAwayMessage }, { Presence::FreeForChat, OnlineStatus::Online, SET_FFC, IS_FFC, i18n( "&Free for Chat" ), i18n("Free For Chat"), i18n("Free For Chat (Invisible)"), "icq_ffc", "contact_invisible_overlay", Kopete::OnlineStatusManager::FreeForChat, 0 }, { Presence::Online, OnlineStatus::Online, ONLINE, ONLINE, i18n( "O&nline" ), i18n("Online"), i18n("Online (Invisible)"), 0, "contact_invisible_overlay", Kopete::OnlineStatusManager::Online, 0 } }; return data; } const PresenceTypeData &PresenceTypeData::forType( Presence::Type type ) { const PresenceTypeData *array = all(); for ( uint n = 0; n < Presence::TypeCount; ++n ) if ( array[n].type == type ) return array[n]; kdWarning(14153) << k_funcinfo << "type " << (int)type << " not found! Returning Offline" << endl; return array[0]; } const PresenceTypeData &PresenceTypeData::fortqStatus( unsigned long status ) { const PresenceTypeData *array = all(); for ( uint n = 0; n < Presence::TypeCount; ++n ) { //kdDebug(14153) << k_funcinfo << "array[n].getFlag is " << array[n].getFlag << ", status is " << status << ", & is " << (array[n].getFlag & status) << endl; if ( (array[n].getFlag & status) == array[n].getFlag ) return array[n]; } kdWarning(14153) << k_funcinfo << "status " << (int)status << " not found! Returning Offline. This should not happen." << endl; return array[0]; } const PresenceTypeData &PresenceTypeData::forOnlineStatusType( const Kopete::OnlineStatus::StatusType statusType ) { const PresenceTypeData *array = all(); for ( int n = Presence::TypeCount - 1; n >= 0; --n ) { if ( array[n].onlineStatusType == statusType ) return array[n]; } kdWarning(14153) << k_funcinfo << "online status " << (int)statusType << " not found! Returning Offline. This should not happen." << endl; return array[0]; } //END struct PresenceTypeData //BEGIN class OnlineStatusManager class OnlineStatusManager::Private { public: typedef std::vector StatusList; // connecting and unknown should have the same internal status as offline, so converting to a Presence gives an Offline one Private() : connecting( Kopete::OnlineStatus::Connecting, 99, ICQProtocol::protocol(), 99, "icq_connecting", i18n("Connecting...") ) , unknown( Kopete::OnlineStatus::Unknown, 0, ICQProtocol::protocol(), Presence::Offline, "status_unknown", i18n("Unknown") ) , waitingForAuth( Kopete::OnlineStatus::Unknown, 1, ICQProtocol::protocol(), Presence::Offline, "button_cancel", i18n("Waiting for Authorization") ) , invisible( Kopete::OnlineStatus::Invisible, 2, ICQProtocol::protocol(), Presence::Offline, TQString(), TQString(), TQString(), Kopete::OnlineStatusManager::Invisible, Kopete::OnlineStatusManager::HideFromMenu ) { createStatusList( false, 0, visibleStatusList ); createStatusList( true, Presence::TypeCount, invisibleStatusList ); } void createStatusList( bool invisible, const uint invisibleOffset, StatusList &statusList ) { //weight 0, 1 and 2 are used by KOS unknown, waitingForAuth and invisible const uint firstUsableWeight = 3; statusList.reserve( Presence::TypeCount ); for ( uint n = 0; n < Presence::TypeCount; ++n ) { const PresenceTypeData &data = PresenceTypeData::forType( static_cast(n) ); const uint weight = n + firstUsableWeight; const uint internalStatus = n + invisibleOffset; TQStringList overlayIcons( data.visibleIcon ); TQString description( data.visibleName ); Kopete::OnlineStatus status; if ( invisible ) { overlayIcons << data.invisibleIcon; description = data.invisibleName; //don't add invisible KOS to account's context menu status = Kopete::OnlineStatus( data.onlineStatusType, weight, ICQProtocol::protocol(), internalStatus, overlayIcons, description ); } else { //add visible KOS status = Kopete::OnlineStatus( data.onlineStatusType, weight, ICQProtocol::protocol(), internalStatus, overlayIcons, description, data.caption, data.categories, data.options ); } statusList.push_back( status ); } } StatusList visibleStatusList, invisibleStatusList; Kopete::OnlineStatus connecting; Kopete::OnlineStatus unknown; Kopete::OnlineStatus waitingForAuth; Kopete::OnlineStatus invisible; }; OnlineStatusManager::OnlineStatusManager() : d( new Private ) { } OnlineStatusManager::~OnlineStatusManager() { delete d; } Presence OnlineStatusManager::presenceOf( uint internalStatus ) { if ( internalStatus < Presence::TypeCount ) { return Presence( static_cast( internalStatus ), Presence::Visible ); } else if ( internalStatus < 2 * Presence::TypeCount ) { return Presence( static_cast( internalStatus - Presence::TypeCount ), Presence::Invisible ); } else { kdWarning(14153) << k_funcinfo << "No presence exists for internal status " << internalStatus << "! Returning Offline" << endl; return Presence( Presence::Offline, Presence::Visible ); } } Kopete::OnlineStatus OnlineStatusManager::onlineStatusOf( const Presence &presence ) { if ( presence.visibility() == Presence::Visible ) return d->visibleStatusList[ presence.type() ]; else return d->invisibleStatusList[ presence.type() ]; } Kopete::OnlineStatus OnlineStatusManager::connectingtqStatus() { return d->connecting; } Kopete::OnlineStatus OnlineStatusManager::unknowntqStatus() { return d->unknown; } Kopete::OnlineStatus OnlineStatusManager::waitingForAuth() { return d->waitingForAuth; } //END class OnlineStatusManager //BEGIN class Presence Presence Presence::fromOnlineStatus( const Kopete::OnlineStatus &status ) { if ( status.protocol() == ICQProtocol::protocol() ) { OnlineStatusManager *store = ICQProtocol::protocol()->statusManager(); return store->presenceOf( status.internalStatus() ); } else { //status is a libkopete builtin status object //don't even think about converting it to ICQ::Presence using presenceOf! return Presence( PresenceTypeData::forOnlineStatusType( status.status() ).type, Presence::Visible ); } } Kopete::OnlineStatus Presence::toOnlineStatus() const { OnlineStatusManager *store = ICQProtocol::protocol()->statusManager(); return store->onlineStatusOf( *this ); } unsigned long Presence::toOscartqStatus() const { unsigned long basictqStatus = basicOscartqStatus(); if ( _visibility == Invisible ) basictqStatus |= StatusCode::INVISIBLE; return basictqStatus; } Presence Presence::fromOscartqStatus( unsigned long code ) { Type type = typeFromOscartqStatus( code & ~StatusCode::INVISIBLE ); bool invisible = (code & StatusCode::INVISIBLE) == StatusCode::INVISIBLE; return Presence( type, invisible ? Invisible : Visible ); } unsigned long Presence::basicOscartqStatus() const { const PresenceTypeData &data = PresenceTypeData::forType( _type ); return data.setFlag; } Presence::Type Presence::typeFromOscartqStatus( unsigned long status ) { const PresenceTypeData &data = PresenceTypeData::fortqStatus( status ); return data.type; } //END class Presence } // end namespace ICQ // vim: set noet ts=4 sts=4 sw=4: // kate: indent-mode: csands; space-indent off; tab-width 4;