Update ICQ presence stuff. Now it's like AIM presence.
[kdenetwork.git] / kopete / protocols / oscar / icq / icqpresence.cpp
blob6cc8e79ef14ff0c610354bc8f96e6f6da8bf8990
1 /*
2 icqpresence.cpp - ICQ online status and presence management
4 Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
5 Copyright (c) 2007 by Roman Jarosz <kedgedev@centrum.cz>
6 Kopete (c) 2002-2007 by the Kopete developers <kopete-devel@kde.org>
8 *************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 *************************************************************************
18 #include <QHash>
19 #include <QFlags>
21 #include <kdebug.h>
22 #include <klocale.h>
23 #include <kstaticdeleter.h>
25 #include <kopeteonlinestatus.h>
26 #include <kopeteonlinestatusmanager.h>
28 #include "icqprotocol.h"
30 #include "icqpresence.h"
32 namespace ICQ
35 //BEGIN class PresenceOverlay
37 class PresenceOverlay
39 public:
40 PresenceOverlay() : mFlags( Presence::None ) {}
41 PresenceOverlay( Presence::Flags flags, QString name, QStringList icons )
42 : mFlags(flags), mName(name), mIcons(icons) {}
44 static PresenceOverlay createForFlags( Presence::Flags flags );
46 Presence::Flags overlayFlag() const { return mFlags; }
47 QString overlayName() const { return mName; }
48 QStringList overlayIcons() const { return mIcons; }
50 PresenceOverlay &operator+= ( const PresenceOverlay &other );
52 private:
53 Presence::Flags mFlags;
54 QString mName;
55 QStringList mIcons;
58 PresenceOverlay PresenceOverlay::createForFlags( Presence::Flags flags )
60 /**
61 * Here are defined all available overlays. We can define overlay for one Presence::Flags
62 * or for combination of Presence::Flags. If a flags argument in this function is combination
63 * of flags than a PresenceOverlay object is created from combination of defined overlays or
64 * if the combination is defined separately than we return that PresenceOverlay object.
67 const int dataSize = 3;
68 static const PresenceOverlay data[dataSize] =
70 PresenceOverlay( Presence::Invisible, i18n("Invisible"), QStringList(QString("contact_invisible_overlay")) ),
71 PresenceOverlay( Presence::Wireless, i18n("Mobile"), QStringList(QString("contact_phone_overlay")) ),
72 PresenceOverlay( Presence::AIM, i18n("AIM"), QStringList(QString("aim_overlay")) )
75 PresenceOverlay overlay;
76 for ( int n = 0; n < dataSize; ++n )
78 if ( data[n].overlayFlag() == flags )
79 return data[n];
80 else if ( data[n].overlayFlag() & flags )
81 overlay += data[n];
84 return overlay;
87 PresenceOverlay &PresenceOverlay::operator+=( const PresenceOverlay &other )
89 mFlags |= other.mFlags;
90 if ( mName.isEmpty() )
91 mName = other.mName;
92 else if ( !other.mName.isEmpty() )
93 mName += QString( ", " ) + other.mName;
95 mIcons << other.mIcons;
96 return *this;
99 //END class PresenceOverlay
102 //BEGIN struct PresenceTypeData
104 typedef QList<Presence::Flags> FlagsList;
105 struct PresenceTypeData
107 Presence::Type type;
108 Kopete::OnlineStatus::StatusType onlineStatusType;
109 unsigned long setFlag;
110 unsigned long getFlag;
111 QString caption;
112 QString name;
113 QStringList overlayIcons;
114 Kopete::OnlineStatusManager::Categories categories;
115 Kopete::OnlineStatusManager::Options options;
116 FlagsList overlayFlagsList;
118 static const PresenceTypeData *all();
119 static const PresenceTypeData &forType( Presence::Type type );
120 static const PresenceTypeData &forStatus( unsigned long status );
121 static const PresenceTypeData &forOnlineStatusType( const Kopete::OnlineStatus::StatusType statusType );
124 const PresenceTypeData *PresenceTypeData::all()
126 using namespace Kopete;
127 using namespace ICQ::StatusCode;
129 * The order here is important - this is the order the IS_XXX flags will be checked for in.
130 * That, in particular, means that NA, Occupied and DND must appear before Away, and that
131 * DND must appear before Occupied. Offline (testing all bits) must go first, and Online
132 * (testing no bits - will always match a status) must go last.
134 * Free For Chat is currently listed after Away, since if someone is Away + Free For Chat we
135 * want to show them as Away more than we want to show them FFC.
137 * OverlayFlagsList should contain all possible flags combinations that can occur in ICQ protocol.
138 * If overlayFlagsList contains flag None than this KOS will be in account's context menu.
140 static const PresenceTypeData data[] =
142 { Presence::Offline, OnlineStatus::Offline, OFFLINE, OFFLINE, i18n( "O&ffline" ), i18n("Offline"), QStringList(), Kopete::OnlineStatusManager::Offline, 0, FlagsList() << Presence::None << Presence::AIM << Presence::Invisible },
144 { Presence::DoNotDisturb, OnlineStatus::Away, SET_DND, IS_DND, i18n( "&Do Not Disturb" ), i18n("Do Not Disturb"), QStringList(QString("contact_busy_overlay")), Kopete::OnlineStatusManager::Busy, Kopete::OnlineStatusManager::HasStatusMessage, FlagsList() << Presence::None << Presence::Invisible << Presence::Wireless << (Presence::Wireless | Presence::Invisible) },
146 { Presence::Occupied, OnlineStatus::Away, SET_OCC, IS_OCC, i18n( "O&ccupied" ), i18n("Occupied"), QStringList(QString("contact_busy_overlay")), 0, Kopete::OnlineStatusManager::HasStatusMessage, FlagsList() << Presence::None << Presence::Invisible },
148 { Presence::NotAvailable, OnlineStatus::Away, SET_NA, IS_NA, i18n( "Not A&vailable" ), i18n("Not Available"), QStringList(QString("contact_xa_overlay")), Kopete::OnlineStatusManager::ExtendedAway, Kopete::OnlineStatusManager::HasStatusMessage, FlagsList() << Presence::None << Presence::Invisible },
150 { Presence::Away, OnlineStatus::Away, SET_AWAY, IS_AWAY, i18n( "&Away" ), i18n("Away"), QStringList(QString("contact_away_overlay")), Kopete::OnlineStatusManager::Away, Kopete::OnlineStatusManager::HasStatusMessage, FlagsList() << Presence::None << Presence::Invisible << Presence::AIM << (Presence::AIM | Presence::Invisible) << Presence::Wireless << (Presence::Wireless | Presence::Invisible) },
152 { Presence::FreeForChat, OnlineStatus::Online, SET_FFC, IS_FFC, i18n( "&Free for Chat" ), i18n("Free For Chat"), QStringList(QString("icq_ffc")), Kopete::OnlineStatusManager::FreeForChat, 0, FlagsList() << Presence::None << (Presence::None | Presence::Invisible) },
154 { Presence::Online, OnlineStatus::Online, ONLINE, ONLINE, i18n( "O&nline" ), i18n("Online"), QStringList(), Kopete::OnlineStatusManager::Online, 0, FlagsList() << Presence::None << Presence::Invisible << Presence::AIM << (Presence::AIM | Presence::Invisible) << Presence::Wireless << (Presence::Wireless | Presence::Invisible) }
156 return data;
159 const PresenceTypeData &PresenceTypeData::forType( Presence::Type type )
161 const PresenceTypeData *array = all();
162 for ( uint n = 0; n < Presence::TypeCount; ++n )
163 if ( array[n].type == type )
164 return array[n];
165 kWarning(14153) << k_funcinfo << "type " << (int)type << " not found! Returning Offline" << endl;
166 return array[0];
169 const PresenceTypeData &PresenceTypeData::forStatus( unsigned long status )
171 const PresenceTypeData *array = all();
172 for ( uint n = 0; n < Presence::TypeCount; ++n )
174 if ( (array[n].getFlag & status) == array[n].getFlag )
175 return array[n];
177 kWarning(14153) << k_funcinfo << "status " << (int)status << " not found! Returning Offline. This should not happen." << endl;
178 return array[0];
181 const PresenceTypeData &PresenceTypeData::forOnlineStatusType( const Kopete::OnlineStatus::StatusType statusType )
183 const PresenceTypeData *array = all();
184 for ( int n = Presence::TypeCount - 1; n >= 0; --n )
186 if ( array[n].onlineStatusType == statusType )
187 return array[n];
189 kWarning(14153) << k_funcinfo << "online status " << (int)statusType << " not found! Returning Offline. This should not happen." << endl;
190 return array[0];
193 //END struct PresenceTypeData
195 //BEGIN class OnlineStatusManager
197 class OnlineStatusManager::Private
199 public:
200 typedef QHash<int, Kopete::OnlineStatus> StatusHash;
202 // connecting and unknown should have the same internal status as offline, so converting to a Presence gives an Offline one
203 Private()
204 : connecting( Kopete::OnlineStatus::Connecting, 99, ICQProtocol::protocol(),
205 99, QStringList(QString("icq_connecting")), i18n("Connecting...") )
206 , unknown( Kopete::OnlineStatus::Unknown, 0, ICQProtocol::protocol(),
207 Presence::Offline, QStringList(QString("status_unknown")), i18n("Unknown") )
208 , waitingForAuth( Kopete::OnlineStatus::Unknown, 1, ICQProtocol::protocol(),
209 Presence::Offline, QStringList(QString("button_cancel")), i18n("Waiting for Authorization") )
210 , invisible( Kopete::OnlineStatus::Invisible, 2, ICQProtocol::protocol(),
211 Presence::Offline, QStringList(), QString(),
212 QString(), Kopete::OnlineStatusManager::Invisible,
213 Kopete::OnlineStatusManager::HideFromMenu )
216 //weight 0, 1 and 2 are used by KOS unknown, waitingForAuth and invisible
217 const uint firstUsableWeight = 3;
218 for ( uint i = 0; i < Presence::TypeCount; ++i )
220 const PresenceTypeData &data = PresenceTypeData::forType( static_cast<Presence::Type>(i) );
221 const uint weight = i + firstUsableWeight;
222 for ( int j = 0; j < data.overlayFlagsList.count(); ++j )
224 const uint internalStatus = data.overlayFlagsList.at(j) | data.type;
226 Kopete::OnlineStatus status;
227 if ( data.overlayFlagsList.at(j) != Presence::None )
229 PresenceOverlay overlay = PresenceOverlay::createForFlags( data.overlayFlagsList.at(j) );
230 //don't add KOS to account's context menu
231 status = Kopete::OnlineStatus( data.onlineStatusType, weight,
232 ICQProtocol::protocol(), internalStatus,
233 data.overlayIcons + overlay.overlayIcons(),
234 data.name + QString(" (%1)").arg( overlay.overlayName() ) );
236 else
238 //add KOS
239 status = Kopete::OnlineStatus( data.onlineStatusType, weight,
240 ICQProtocol::protocol(), internalStatus,
241 data.overlayIcons, data.name,
242 data.caption, data.categories, data.options );
244 statusHash[internalStatus] = status;
249 StatusHash statusHash;
250 Kopete::OnlineStatus connecting;
251 Kopete::OnlineStatus unknown;
252 Kopete::OnlineStatus waitingForAuth;
253 Kopete::OnlineStatus invisible;
256 OnlineStatusManager::OnlineStatusManager()
257 : d( new Private )
261 OnlineStatusManager::~OnlineStatusManager()
263 delete d;
266 Kopete::OnlineStatus OnlineStatusManager::onlineStatusOf( const Presence &presence )
268 if ( d->statusHash.contains( presence.internalStatus() ) )
270 return d->statusHash.value( presence.internalStatus() );
272 else if ( d->statusHash.contains( presence.type() ) )
274 kWarning() << k_funcinfo << "Kopete::OnlineStatus doesn't exists for internal status" << presence.internalStatus()
275 << "Using basic status for type" << presence.type() << endl;
276 return d->statusHash.value( presence.type() );
278 else
280 kWarning() << k_funcinfo << "Kopete::OnlineStatus doesn't exists for internal status" << presence.internalStatus() << endl;
281 return d->unknown;
285 Kopete::OnlineStatus OnlineStatusManager::connectingStatus()
287 return d->connecting;
290 Kopete::OnlineStatus OnlineStatusManager::unknownStatus()
292 return d->unknown;
295 Kopete::OnlineStatus OnlineStatusManager::waitingForAuth()
297 return d->waitingForAuth;
300 //END class OnlineStatusManager
302 //BEGIN class Presence
304 Presence::Presence( Type type, Flags flags )
306 _internalStatus = type | flags;
309 Presence::Presence( uint internalStatus )
311 _internalStatus = internalStatus;
314 Presence Presence::fromOnlineStatus( const Kopete::OnlineStatus &status )
316 if ( status.protocol() == ICQProtocol::protocol() )
318 return Presence( status.internalStatus() );
320 else
322 //status is a libkopete builtin status object
323 //don't even think about converting it to ICQ::Presence using presenceOf!
324 return Presence( PresenceTypeData::forOnlineStatusType( status.status() ).type,
325 Presence::None );
329 Kopete::OnlineStatus Presence::toOnlineStatus() const
331 OnlineStatusManager *store = ICQProtocol::protocol()->statusManager();
332 return store->onlineStatusOf( *this );
336 unsigned long Presence::toOscarStatus() const
338 unsigned long basicStatus = basicOscarStatus();
339 if ( (_internalStatus & Invisible) == Invisible )
340 basicStatus |= StatusCode::INVISIBLE;
341 return basicStatus;
344 Presence Presence::fromOscarStatus( unsigned long oStatus, int oClass )
346 Type type = typeFromOscarStatus( oStatus );
348 //Hack for aim away contacts
349 if ( type == Online && (oClass & ClassCode::AWAY) == ClassCode::AWAY )
350 type = Away;
352 Flags flags = None;
353 if ( (oClass & ClassCode::ICQ) == ClassCode::ICQ )
354 flags |= None;
355 else
356 flags |= AIM;
358 if ( (oClass & ClassCode::WIRELESS) == ClassCode::WIRELESS )
359 flags |= Wireless;
361 if ( (oStatus & StatusCode::INVISIBLE) == StatusCode::INVISIBLE )
362 flags |= Invisible;
364 return Presence( type, flags );
367 unsigned long Presence::basicOscarStatus() const
369 const PresenceTypeData &data = PresenceTypeData::forType( type() );
370 return data.setFlag;
373 Presence::Type Presence::typeFromOscarStatus( unsigned long status )
375 const PresenceTypeData &data = PresenceTypeData::forStatus( status & 0xff );
376 return data.type;
379 //END class Presence
381 } // end namespace ICQ
383 // vim: set noet ts=4 sts=4 sw=4:
384 // kate: indent-mode: csands; space-indent off; tab-width 4;