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 *************************************************************************
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. *
15 *************************************************************************
23 #include <kstaticdeleter.h>
25 #include <kopeteonlinestatus.h>
26 #include <kopeteonlinestatusmanager.h>
28 #include "icqprotocol.h"
30 #include "icqpresence.h"
35 //BEGIN class PresenceOverlay
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
);
53 Presence::Flags mFlags
;
58 PresenceOverlay
PresenceOverlay::createForFlags( Presence::Flags flags
)
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
)
80 else if ( data
[n
].overlayFlag() & flags
)
87 PresenceOverlay
&PresenceOverlay::operator+=( const PresenceOverlay
&other
)
89 mFlags
|= other
.mFlags
;
90 if ( mName
.isEmpty() )
92 else if ( !other
.mName
.isEmpty() )
93 mName
+= QString( ", " ) + other
.mName
;
95 mIcons
<< other
.mIcons
;
99 //END class PresenceOverlay
102 //BEGIN struct PresenceTypeData
104 typedef QList
<Presence::Flags
> FlagsList
;
105 struct PresenceTypeData
108 Kopete::OnlineStatus::StatusType onlineStatusType
;
109 unsigned long setFlag
;
110 unsigned long getFlag
;
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
) }
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
)
165 kWarning(14153) << k_funcinfo
<< "type " << (int)type
<< " not found! Returning Offline" << endl
;
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
)
177 kWarning(14153) << k_funcinfo
<< "status " << (int)status
<< " not found! Returning Offline. This should not happen." << endl
;
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
)
189 kWarning(14153) << k_funcinfo
<< "online status " << (int)statusType
<< " not found! Returning Offline. This should not happen." << endl
;
193 //END struct PresenceTypeData
195 //BEGIN class OnlineStatusManager
197 class OnlineStatusManager::Private
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
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() ) );
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()
261 OnlineStatusManager::~OnlineStatusManager()
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() );
280 kWarning() << k_funcinfo
<< "Kopete::OnlineStatus doesn't exists for internal status" << presence
.internalStatus() << endl
;
285 Kopete::OnlineStatus
OnlineStatusManager::connectingStatus()
287 return d
->connecting
;
290 Kopete::OnlineStatus
OnlineStatusManager::unknownStatus()
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() );
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
,
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
;
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
)
353 if ( (oClass
& ClassCode::ICQ
) == ClassCode::ICQ
)
358 if ( (oClass
& ClassCode::WIRELESS
) == ClassCode::WIRELESS
)
361 if ( (oStatus
& StatusCode::INVISIBLE
) == StatusCode::INVISIBLE
)
364 return Presence( type
, flags
);
367 unsigned long Presence::basicOscarStatus() const
369 const PresenceTypeData
&data
= PresenceTypeData::forType( type() );
373 Presence::Type
Presence::typeFromOscarStatus( unsigned long status
)
375 const PresenceTypeData
&data
= PresenceTypeData::forStatus( status
& 0xff );
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;