1/*
2 kopeteaccount.h - Kopete Account
3
4 Copyright (c) 2007 by Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
5 Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@kde.org>
6 Copyright (c) 2003-2004 by Martijn Klingens <klingens@kde.org>
7 Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
8
9 Kopete (c) 2002-2007 by the Kopete developers <kopete-devel@kde.org>
10
11 *************************************************************************
12 * *
13 * This library is free software; you can redistribute it and/or *
14 * modify it under the terms of the GNU Lesser General Public *
15 * License as published by the Free Software Foundation; either *
16 * version 2 of the License, or (at your option) any later version. *
17 * *
18 *************************************************************************
19*/
20
21#ifndef KOPETEACCOUNT_H
22#define KOPETEACCOUNT_H
23
24#include "kopeteonlinestatus.h"
25#include "kopetestatusmessage.h"
26#include "kopete_export.h"
27
28#include <QtCore/QObject>
29#include <QtGui/QPixmap>
30#include <QtCore/QHash>
31
32#include <kconfiggroup.h>
33#include <kiconloader.h>
34#include <solid/networking.h>
35
36class KActionMenu;
37class KConfigGroup;
38
39namespace Kopete
40{
41class Contact;
42class Protocol;
43class MetaContact;
44class Group;
45class OnlineStatus;
46class BlackLister;
47class StatusMessage;
48class Identity;
49class PropertyContainer;
50
51/**
52 * The Kopete::Account class handles one account.
53 * Each protocol implementation should subclass this class in its own custom account class.
54 * There are a few pure virtual methods that must be implemented. Examples are:
55 * \li \ref connect()
56 * \li \ref disconnect()
57 * \li \ref createContact()
58 *
59 * The accountId is an @em constant unique id, which represents the login.
60 * The @ref myself() contact is one of the most important contacts, which represents
61 * the user tied to this account. You must create this contact in the contructor of your
62 * account and pass it to @ref setMyself().
63 *
64 * All account data is saved to @ref KConfig. This includes the accountId, the autoconnect flag and
65 * the color. You can save more data using @ref configGroup()
66 *
67 * When you create a new account, you have to register it with the account manager by calling
68 * @ref AccountManager::registerAccount.
69 *
70 * @author Olivier Goffart <ogoffart\@kde.org>
71 */
72class KOPETE_EXPORT Account : public QObject
73{
74 Q_OBJECT
75
76 Q_ENUMS( AddMode )
77 Q_PROPERTY( QString accountId READ accountId )
78 Q_PROPERTY( bool excludeConnect READ excludeConnect WRITE setExcludeConnect )
79 Q_PROPERTY( QColor color READ color WRITE setColor )
80 Q_PROPERTY( QPixmap accountIcon READ accountIcon )
81 Q_PROPERTY( bool isConnected READ isConnected )
82 Q_PROPERTY( bool isAway READ isAway )
83 Q_PROPERTY( bool suppressStatusNotification READ suppressStatusNotification )
84 Q_PROPERTY( uint priority READ priority WRITE setPriority )
85
86public:
87 /**
88 * \brief Describes how the account was disconnected
89 *
90 * Manual means that the disconnection was done by the user and no reconnection
91 * will take place. Any other value will reconnect the account on disconnection.
92 * The case where the password is wrong will be handled differently.
93 * @see @ref disconnected
94 */
95 enum DisconnectReason {
96 OtherClient = -4, ///< connection went down because another client connected the same account
97 BadPassword = -3, ///< connection failed because password was incorrect
98 BadUserName = -2, ///< connection failed because user name was invalid / unknown
99 InvalidHost = -1, ///< connection failed because host is unreachable
100 Manual = 0, ///< the user disconnected normally
101 ConnectionReset = 1, ///< the connection was lost
102 Unknown = 99 ///< the reason for disconnection is unknown
103 };
104
105 /**
106 * \brief Describes what should be done when the contact is added to a metacontact
107 * @sa @ref addContact()
108 */
109 enum AddMode {
110 ChangeKABC = 0, ///< The KDE Address book may be updated
111 DontChangeKABC = 1, ///< The KDE Address book will not be changed
112 Temporary = 2 ///< The contact will not be added on the contact list
113 };
114
115 /**
116 * \brief Describes what should be done when we set new OnlineStatus
117 * @sa @ref setOnlineStatus()
118 */
119 enum OnlineStatusOption {
120 None = 0x00, ///< Use the online status
121 KeepSpecialFlags = 0x01 ///< Use the online status but keep special flags, e.g. Invisible
122 };
123 Q_DECLARE_FLAGS(OnlineStatusOptions, OnlineStatusOption)
124
125 /**
126 * Constructor for the Account object.
127 *
128 * @param parent the protocol for this account. The account is a child object of the
129 * protocol, so it will be automatically deleted when the protocol is.
130 * @param accountID the unique ID of this account.
131 * @param name the name of this QObject.
132 */
133 Account(Protocol *parent, const QString &accountID);
134
135 /**
136 * Destroy the Account object.
137 */
138 ~Account();
139
140 /**
141 * \return the Protocol for this account
142 */
143 Protocol *protocol() const ;
144
145 /**
146 * \return the unique ID of this account used as the login
147 */
148 QString accountId() const;
149
150 /**
151 * The label for this account.
152 *
153 * This is used in the GUI.
154 * \return The label of this account
155 */
156 QString accountLabel() const;
157
158 /**
159 * \brief Get the priority of this account.
160 *
161 * Used for sorting and determining the preferred account to message a contact.
162 */
163 uint priority() const;
164
165 /**
166 * \brief Set the priority of this account.
167 *
168 * @note This method is called by the UI, and should not be called elsewhere.
169 */
170 void setPriority( uint priority );
171
172 /**
173 * \brief Set if the account should not log in automatically.
174 *
175 * This function can be used by the EditAccountPage. Kopete handles connection automatically.
176 * @sa @ref excludeConnect
177 */
178 void setExcludeConnect(bool);
179
180 /**
181 * \brief Get if the account should not log in.
182 *
183 * @return @c true if the account should not be connected when connectAll at startup, @c false otherwise.
184 */
185 bool excludeConnect() const;
186
187 /**
188 * \brief Get the color for this account.
189 *
190 * The color will be used to visually differentiate this account from other accounts on the
191 * same protocol.
192 *
193 * \return the user color for this account
194 */
195 const QColor color() const;
196
197 /**
198 * \brief Set the color for this account.
199 *
200 * This is called by Kopete's account config page; you don't have to set the color yourself.
201 *
202 * @sa @ref color()
203 */
204 void setColor( const QColor &color);
205
206 /**
207 * \brief Get the icon for this account.
208 *
209 * Generates an image of size @p size representing this account. The result is not cached.
210 *
211 * @param size the size of the icon. If the size is 0, the default size is used.
212 * @return the icon for this account, colored if needed
213 */
214 QPixmap accountIcon( const int size = 0 ) const;
215
216 /*
217 * \brief Get the icon path for this account.
218 *
219 * This is the account icon path.
220 *
221 * @return the icon path for this account.
222 */
223 QString accountIconPath(const KIconLoader::Group size) const;
224
225 /**
226 * \brief change the account icon.
227 * by default the icon of an account is the protocol one, but it may be overide it.
228 * Set QString() to go back to the default (the protocol icon)
229 *
230 * this call will emit colorChanged()
231 */
232 void setCustomIcon( const QString& );
233
234 /**
235 * \brief return the icon base
236 * This is the custom account icon set with setIcon. if this icon is null, then the protocol icon is used
237 * don't use this function to get the icon that need to be displayed, use accountIcon
238 */
239 QString customIcon() const;
240
241 /**
242 * \brief Retrieve the identity this account belongs to
243 *
244 * \return a pointer to the Identity object this account belongs to.
245 *
246 * \see setIdentity().
247 */
248 Identity * identity() const;
249
250 /**
251 * \brief Sets the identity this account belongs to
252 *
253 * Setting the account to a new identity implies it to be removed from the
254 * identity it was previously associated.
255 *
256 * @param ident The identity this account should be associated to
257 * \return @c true if the identity was changed, @c false otherwise
258 *
259 * @note You should call the default implementation from your reimplementation
260 */
261 virtual bool setIdentity( Kopete::Identity *ident );
262
263 /**
264 * \brief Retrieve the 'myself' contact.
265 *
266 * \return a pointer to the Contact object for this account
267 *
268 * \see setMyself().
269 */
270 Contact * myself() const;
271
272 /**
273 * @brief Fill the menu with actions for this account
274 *
275 * You have to reimplement this method to add custom actions to the @p actionMenu which will
276 * be shown in the statusbar. It is the caller's responsibility to ensure the menu is deleted.
277 *
278 * The default implementation provides a generic menu, with actions generated from the protocol's
279 * registered statuses, and an action to show the account's settings dialog.
280 *
281 * You should call the default implementation from your reimplementation, and add more actions
282 * you require to the resulting action menu.
283 *
284 * @see OnlineStatusManager::registerOnlineStatus
285 */
286 virtual void fillActionMenu( KActionMenu *actionMenu );
287
288 /**
289 * @brief Return true if account has custom status menu.
290 *
291 * You have to reimplement this method and return true if you don't want to have status menu in menu
292 * which will be shown in the statusbar
293 *
294 * The default implementation returns false.
295 */
296 virtual bool hasCustomStatusMenu() const;
297
298 /**
299 * @brief Retrieve the list of contacts for this account (except myself contact)
300 *
301 * The list is guaranteed to contain only contacts for this account,
302 * so you can safely use static_cast to your own derived contact class
303 * if needed.
304 */
305 const QHash<QString,Contact*>& contacts();
306
307 /**
308 * Indicates whether or not we should suppress status notifications
309 * for contacts belonging to this account.
310 *
311 * This is used when we just connected or disconnected, and every contact has their initial
312 * status set.
313 *
314 * @return @c true if notifications should not be used, @c false otherwise
315 */
316 bool suppressStatusNotification() const;
317
318 /**
319 * \brief Create a contact (creating a new metacontact if necessary)
320 *
321 * If a contact for this account with ID @p contactId is not already on the contact list,
322 * a new contact with that ID is created, and added to a new metacontact.
323 *
324 * If @p mode is @c ChangeKABC, MetaContact::updateKABC will be called on the resulting metacontact.
325 * If @p mode is @c Temporary, MetaContact::setTemporary will be called on the resulting metacontact,
326 * and the metacontact will not be added to @p group.
327 * If @p mode is @c DontChangeKABC, no additional action is carried out.
328 *
329 * @param contactId the @ref Contact::contactId of the contact to create
330 * @param displayName the displayname (alias) of the new metacontact. Leave as QString() if
331 * no alias is known, then by default, the nick will be taken as alias and tracked if changed.
332 * @param group the group to add the created metacontact to, or 0 for the top-level group.
333 * @param mode the mode used to add the contact. Use DontChangeKABC when deserializing.
334 * @return the new created metacontact or 0L if the operation failed
335 */
336 MetaContact* addContact( const QString &contactId, const QString &displayName = QString(), Group *group = 0, AddMode mode = DontChangeKABC );
337
338 /**
339 * @brief Create a new contact, adding it to an existing metacontact
340 *
341 * If a contact for this account with ID @p contactId is not already on the contact list,
342 * a new contact with that ID is created, and added to the metacontact @p parent.
343 *
344 * @param contactId the @ref Contact::contactId of the contact to create
345 * @param parent the parent metacontact (must not be 0)
346 * @param mode the mode used to add the contact. See addContact(const QString&,const QString&,Group*,AddMode) for details.
347 *
348 * @return @c true if creation of the contact succeeded or the contact was already in the list,
349 * @c false otherwise.
350 */
351 bool addContact( const QString &contactId, MetaContact *parent, AddMode mode = DontChangeKABC );
352
353 /**
354 * @brief Indicate whether the account is connected at all.
355 *
356 * This is a convenience method that calls @ref Contact::isOnline() on @ref myself().
357 * This function is safe to call if @ref setMyself() has not been called yet.
358 *
359 * @see @ref isConnectedChanged()
360 */
361 bool isConnected() const;
362
363 /**
364 * @brief Indicate whether the account is away.
365 *
366 * This is a convenience method that queries @ref Contact::onlineStatus() on @ref myself().
367 * This function is safe to call if @ref setMyself() has not been called yet.
368 *
369 * @see @ref isBusy()
370 */
371 bool isAway() const;
372
373 /**
374 * @brief Indicate whether the account is busy.
375 *
376 * In busy mode all visible and sound events should be disabled.
377 *
378 * This is a convenience method that queries @ref Contact::onlineStatus() on @ref myself().
379 * This function is safe to call if @ref setMyself() has not been called yet.
380 *
381 * @see @ref isAway()
382 */
383 bool isBusy() const;
384
385 /**
386 * Return the @ref KConfigGroup used to write and read special properties
387 *
388 * "Protocol", "AccountId" , "Color", "AutoConnect", "Priority", "Enabled" , "Icon" are reserved keyword
389 * already in use in that group.
390 *
391 * for compatibility, try to not use key that start with a uppercase
392 */
393 KConfigGroup *configGroup() const;
394
395 /**
396 * @brief Remove the account from the server.
397 *
398 * Reimplement this if your protocol supports removing the accounts from the server.
399 * This function is called by @ref AccountManager::removeAccount typically when you remove the
400 * account on the account config page.
401 *
402 * You should add a confirmation message box before removing the account. The default
403 * implementation does nothing.
404 *
405 * @return @c false only if the user requested for the account to be deleted, and deleting the
406 * account failed. Returns @c true in all other cases.
407 */
408 virtual bool removeAccount();
409
410 /**
411 * \return a pointer to the blacklist of the account
412 * @todo remove or implement correctly (BlackLister)
413 */
414 BlackLister* blackLister();
415
416 /**
417 * \return @c true if the contact with ID @p contactId is in the blacklist, @c false otherwise.
418 * @todo remove or implement correctly (BlackLister)
419 */
420 virtual bool isBlocked( const QString &contactId );
421
422protected:
423 /**
424 * \brief Set the 'myself' contact.
425 *
426 * This contact must be defined for every account, because it holds the online status
427 * of the account. You must call this function in the constructor of your account.
428 *
429 * The myself contact can't be deleted as long as the account still exists. The myself
430 * contact is used as a member of every ChatSession involving this account. myself's
431 * contactId should be the accountID. The online status of the myself contact represents
432 * the account's status.
433 *
434 * The myself should have the @ref ContactList::myself() as parent metacontact
435 *
436 */
437 void setMyself( Contact *myself );
438
439 /**
440 * \brief Create a new contact in the specified metacontact
441 *
442 * You shouldn't ever call this method yourself. To add contacts, use @ref addContact().
443 *
444 * This method is called by @ref addContact(). In this method, you should create the
445 * new custom @ref Contact, using @p parentContact as the parent.
446 *
447 * If the metacontact is not temporary and the protocol supports it, you can add the
448 * contact to the server.
449 *
450 * @param contactId the ID of the contact to create
451 * @param parentContact the metacontact to add this contact to
452 * @return @c true if creating the contact succeeded, @c false on failure.
453 */
454 virtual bool createContact( const QString &contactId, MetaContact *parentContact ) =0;
455
456
457 /**
458 * \brief Sets the account label
459 *
460 * @param label The label to set
461 */
462 void setAccountLabel( const QString &label );
463
464protected slots:
465 /**
466 * \brief The service has been disconnected
467 *
468 * You have to call this method when you are disconnected. Depending on the value of
469 * @p reason, this function may attempt to reconnect to the server.
470 *
471 * - BadPassword will ask again for the password
472 * - OtherClient will show a message box
473 *
474 * @param reason the reason for the disconnection.
475 */
476 virtual void disconnected( Kopete::Account::DisconnectReason reason );
477
478 /**
479 * @brief Sets the online status of all contacts in this account to the same value
480 *
481 * Some protocols do not provide status-changed events for all contacts when an account
482 * becomes connected or disconnected. For such protocols, this function may be useful
483 * to set all contacts offline.
484 *
485 * Calls @ref Kopete::Contact::setOnlineStatus on all contacts of this account (except the
486 * @ref myself() contact), passing @p status as the status.
487 *
488 * @param status the status to set all contacts of this account except @ref myself() to.
489 */
490 void setAllContactsStatus( const Kopete::OnlineStatus &status );
491
492 /**
493 * @brief React to network status changes
494 *
495 * @param status the new network status.
496 */
497 void networkingStatusChanged( const Solid::Networking::Status status );
498
499signals:
500 /**
501 * The color of the account has been changed
502 *
503 * also emitted when the icon change
504 * @todo probably rename to accountIconChanged
505 */
506 void colorChanged( const QColor & );
507
508 /**
509 * Emitted when the account is deleted.
510 * @warning emitted in the Account destructor. It is not safe to call any functions on @p account.
511 */
512 void accountDestroyed( const Kopete::Account *account );
513
514 /**
515 * Emitted whenever @ref isConnected() changes.
516 */
517 void isConnectedChanged();
518
519private:
520 /**
521 * @internal
522 * Reads the configuration information of the account from KConfig.
523 */
524 void readConfig();
525
526public:
527 /**
528 * @internal
529 * Register a new Contact with the account. This should be called @em only from the
530 * @ref Contact constructor, not from anywhere else (not even a derived class).
531 */
532 bool registerContact( Contact *c );
533
534public slots:
535 /**
536 * @brief Go online for this service.
537 *
538 * @param initialStatus is the status to connect with. If it is an invalid status for this
539 * account, the default online for the account should be used.
540 * @todo probably deprecate in favor of setOnlineStatus
541 */
542 virtual void connect( const Kopete::OnlineStatus& initialStatus = OnlineStatus() ) = 0;
543
544 /**
545 * @brief Go offline for this service.
546 *
547 * If the service is connecting, you should abort the connection.
548 *
549 * You should call the @ref disconnected function from this function.
550 * @todo probably deprecate in favor of setOnlineStatus
551 */
552 virtual void disconnect( ) = 0 ;
553
554public slots:
555 /**
556 * Reimplement this function to set the online status
557 * @param status is the new status
558 * @param reason is the status message to set.
559 * @param options specify how the status should be set
560 * @note If needed, you need to connect. if the offline status is given, you should disconnect
561 */
562 virtual void setOnlineStatus( const Kopete::OnlineStatus& status,
563 const Kopete::StatusMessage &reason = Kopete::StatusMessage(),
564 const OnlineStatusOptions& options = None ) = 0;
565 /**
566 * Reimplement this function to set the status message(with metadata).
567 * You should use this method to set the status message instead of using setOnlineStatus.
568 * @param statusMessage is the status message to set. (Use Kopete::StatusMessage).
569 */
570 virtual void setStatusMessage( const Kopete::StatusMessage &statusMessage ) = 0;
571
572 /**
573 * Disconnects account, required before resume()
574 * Returns false if account is already suspended.
575 */
576 bool suspend( const Kopete::StatusMessage &reason = Kopete::StatusMessage() );
577
578 /**
579 * Sets account to the online status that was active when suspend() was called.
580 * Returns false if account has not been suspended or status has changed to something other than Offline in the meantime.
581 */
582 bool resume();
583
584 /**
585 * Display the edit account widget for the account
586 */
587 void editAccount( QWidget* parent = 0L );
588
589 /**
590 * Add a user to the blacklist. The default implementation calls
591 * blackList()->addContact( contactId )
592 *
593 * @param contactId the contact to be added to the blacklist
594 * @todo remove or implement correctly (BlackLister)
595 */
596 virtual void block( const QString &contactId );
597
598 /**
599 * Remove a user from the blacklist. The default implementation calls
600 * blackList()->removeContact( contactId )
601 *
602 * @param contactId the contact to be removed from the blacklist
603 * @todo remove or implement correctly (BlackLister)
604 */
605 virtual void unblock( const QString &contactId );
606
607private slots:
608 /**
609 * Restore online status and status message on reconnect.
610 */
611 void reconnect();
612
613 /**
614 * Track the deletion of a Contact and clean up
615 */
616 void contactDestroyed( Kopete::Contact * );
617
618 /**
619 * The @ref myself() contact's online status changed.
620 */
621 void slotOnlineStatusChanged( Kopete::Contact *contact, const Kopete::OnlineStatus &newStatus, const Kopete::OnlineStatus &oldStatus );
622
623 /**
624 * The @ref myself() contact's property changed.
625 */
626 void slotContactPropertyChanged( Kopete::PropertyContainer *, const QString &, const QVariant &, const QVariant & );
627
628 /**
629 * Stop the suppression of status notification (connected to a timer)
630 */
631 void slotStopSuppression();
632
633private:
634 class Private;
635 Private * const d;
636};
637Q_DECLARE_OPERATORS_FOR_FLAGS(Account::OnlineStatusOptions)
638
639} //END namespace Kopete
640
641#endif
642
643