1 /**
2 * This file is part of TelepathyQt
3 *
4 * @copyright Copyright (C) 2008-2010 Collabora Ltd. <http://www.collabora.co.uk/>
5 * @copyright Copyright (C) 2008-2010 Nokia Corporation
6 * @license LGPL 2.1
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <TelepathyQt/Contact>
24
25 #include "TelepathyQt/_gen/contact.moc.hpp"
26
27 #include "TelepathyQt/debug-internal.h"
28 #include "TelepathyQt/future-internal.h"
29
30 #include <TelepathyQt/AvatarData>
31 #include <TelepathyQt/Connection>
32 #include <TelepathyQt/ConnectionCapabilities>
33 #include <TelepathyQt/Constants>
34 #include <TelepathyQt/ContactCapabilities>
35 #include <TelepathyQt/ContactManager>
36 #include <TelepathyQt/LocationInfo>
37 #include <TelepathyQt/PendingContactInfo>
38 #include <TelepathyQt/PendingStringList>
39 #include <TelepathyQt/PendingVoid>
40 #include <TelepathyQt/Presence>
41 #include <TelepathyQt/ReferencedHandles>
42
43 namespace Tp
44 {
45
46 struct TP_QT_NO_EXPORT Contact::Private
47 {
PrivateTp::Contact::Private48 Private(Contact *parent, ContactManager *manager,
49 const ReferencedHandles &handle)
50 : parent(parent),
51 manager(ContactManagerPtr(manager)),
52 handle(handle),
53 caps(manager->supportedFeatures().contains(Contact::FeatureCapabilities) ?
54 ContactCapabilities(true) : ContactCapabilities(
55 manager->connection()->capabilities().allClassSpecs(), false)),
56 isContactInfoKnown(false), isAvatarTokenKnown(false),
57 subscriptionState(SubscriptionStateUnknown),
58 publishState(SubscriptionStateUnknown),
59 blocked(false)
60 {
61 }
62
63 void updateAvatarData();
64
65 Contact *parent;
66
67 WeakPtr<ContactManager> manager;
68 ReferencedHandles handle;
69 QString id;
70
71 Features requestedFeatures;
72 Features actualFeatures;
73
74 QString alias;
75 QMap<QString, QString> vcardAddresses;
76 QStringList uris;
77 Presence presence;
78 ContactCapabilities caps;
79 LocationInfo location;
80
81 bool isContactInfoKnown;
82 InfoFields info;
83
84 bool isAvatarTokenKnown;
85 QString avatarToken;
86 AvatarData avatarData;
87
88 SubscriptionState subscriptionState;
89 SubscriptionState publishState;
90 QString publishStateMessage;
91 bool blocked;
92
93 QSet<QString> groups;
94
95 QStringList clientTypes;
96 };
97
updateAvatarData()98 void Contact::Private::updateAvatarData()
99 {
100 /* If token is NULL, it means that CM doesn't know the token. In that case we
101 * have to request the avatar data to get the token. This happens with XMPP
102 * for offline contacts. We don't want to bypass the avatar cache, so we won't
103 * update avatar. */
104 if (avatarToken.isNull()) {
105 return;
106 }
107
108 /* If token is empty (""), it means the contact has no avatar. */
109 if (avatarToken.isEmpty()) {
110 debug() << "Contact" << parent->id() << "has no avatar";
111 avatarData = AvatarData();
112 emit parent->avatarDataChanged(avatarData);
113 return;
114 }
115
116 parent->manager()->requestContactAvatars(QList<ContactPtr>() << ContactPtr(parent));
117 }
118
119 struct TP_QT_NO_EXPORT Contact::InfoFields::Private : public QSharedData
120 {
PrivateTp::Contact::InfoFields::Private121 Private(const ContactInfoFieldList &allFields)
122 : allFields(allFields) {}
123
124 ContactInfoFieldList allFields;
125 };
126
127 /**
128 * \class Contact::InfoFields
129 * \ingroup clientconn
130 * \headerfile TelepathyQt/contact.h <TelepathyQt/Contact>
131 *
132 * \brief The Contact::InfoFields class represents the information of a
133 * Telepathy contact.
134 */
135
136 /**
137 * Construct a info fields instance with the given fields. The instance will indicate that
138 * it is valid.
139 */
InfoFields(const ContactInfoFieldList & allFields)140 Contact::InfoFields::InfoFields(const ContactInfoFieldList &allFields)
141 : mPriv(new Private(allFields))
142 {
143 }
144
145 /**
146 * Constructs a new invalid InfoFields instance.
147 */
InfoFields()148 Contact::InfoFields::InfoFields()
149 {
150 }
151
152 /**
153 * Copy constructor.
154 */
InfoFields(const Contact::InfoFields & other)155 Contact::InfoFields::InfoFields(const Contact::InfoFields &other)
156 : mPriv(other.mPriv)
157 {
158 }
159
160 /**
161 * Class destructor.
162 */
~InfoFields()163 Contact::InfoFields::~InfoFields()
164 {
165 }
166
167 /**
168 * Assignment operator.
169 */
operator =(const Contact::InfoFields & other)170 Contact::InfoFields &Contact::InfoFields::operator=(const Contact::InfoFields &other)
171 {
172 this->mPriv = other.mPriv;
173 return *this;
174 }
175
176 /**
177 * Return a list containing all fields whose name are \a name.
178 *
179 * \param name The name used to match the fields.
180 * \return A list of ContactInfoField objects.
181 */
fields(const QString & name) const182 ContactInfoFieldList Contact::InfoFields::fields(const QString &name) const
183 {
184 if (!isValid()) {
185 return ContactInfoFieldList();
186 }
187
188 ContactInfoFieldList ret;
189 foreach (const ContactInfoField &field, mPriv->allFields) {
190 if (field.fieldName == name) {
191 ret.append(field);
192 }
193 }
194 return ret;
195 }
196
197 /**
198 * Return a list containing all fields describing the contact information.
199 *
200 * \return The contact information as a list of ContactInfoField objects.
201 */
allFields() const202 ContactInfoFieldList Contact::InfoFields::allFields() const
203 {
204 return isValid() ? mPriv->allFields : ContactInfoFieldList();
205 }
206
207 /**
208 * \class Contact
209 * \ingroup clientconn
210 * \headerfile TelepathyQt/contact.h <TelepathyQt/Contact>
211 *
212 * \brief The Contact class represents a Telepathy contact.
213 *
214 * The accessor functions on this object (id(), alias(), and so on) don't make any D-Bus calls;
215 * instead, they return/use values cached from a previous introspection run.
216 * The introspection process populates their values in the most efficient way possible based on what
217 * the service implements.
218 *
219 * To avoid unnecessary D-Bus traffic, some accessors only return valid
220 * information after specific features have been enabled.
221 * For instance, to retrieve the contact avatar token, it is necessary to
222 * enable the feature Contact::FeatureAvatarToken.
223 * See the individual methods descriptions for more details.
224 *
225 * Contact features can be enabled by constructing a ContactFactory and enabling
226 * the desired features, and passing it to AccountManager, Account or ClientRegistrar
227 * when creating them as appropriate. However, if a particular
228 * feature is only ever used in a specific circumstance, such as an user opening
229 * some settings dialog separate from the general view of the application,
230 * features can be later enabled as needed by calling ContactManager::upgradeContacts() with the
231 * additional features, and waiting for the resulting PendingOperation to finish.
232 *
233 * As an addition to accessors, signals are emitted to indicate that properties have
234 * changed, for example aliasChanged(), avatarTokenChanged(), etc.
235 *
236 * See \ref async_model, \ref shared_ptr
237 */
238
239 /**
240 * Feature used in order to access contact alias info.
241 *
242 * \sa alias(), aliasChanged()
243 */
244 const Feature Contact::FeatureAlias = Feature(QLatin1String(Contact::staticMetaObject.className()), 0, false);
245
246 /**
247 * Feature used in order to access contact avatar data info.
248 *
249 * Enabling this feature will also enable FeatureAvatarToken.
250 *
251 * \sa avatarData(), avatarDataChanged()
252 */
253 const Feature Contact::FeatureAvatarData = Feature(QLatin1String(Contact::staticMetaObject.className()), 1, false);
254
255 /**
256 * Feature used in order to access contact avatar token info.
257 *
258 * \sa isAvatarTokenKnown(), avatarToken(), avatarTokenChanged()
259 */
260 const Feature Contact::FeatureAvatarToken = Feature(QLatin1String(Contact::staticMetaObject.className()), 2, false);
261
262 /**
263 * Feature used in order to access contact capabilities info.
264 *
265 * \sa capabilities(), capabilitiesChanged()
266 */
267 const Feature Contact::FeatureCapabilities = Feature(QLatin1String(Contact::staticMetaObject.className()), 3, false);
268
269 /**
270 * Feature used in order to access contact info fields.
271 *
272 * \sa infoFields(), infoFieldsChanged()
273 */
274 const Feature Contact::FeatureInfo = Feature(QLatin1String(Contact::staticMetaObject.className()), 4, false);
275
276 /**
277 * Feature used in order to access contact location info.
278 *
279 * \sa location(), locationUpdated()
280 */
281 const Feature Contact::FeatureLocation = Feature(QLatin1String(Contact::staticMetaObject.className()), 5, false);
282
283 /**
284 * Feature used in order to access contact presence info.
285 *
286 * \sa presence(), presenceChanged()
287 */
288 const Feature Contact::FeatureSimplePresence = Feature(QLatin1String(Contact::staticMetaObject.className()), 6, false);
289
290 /**
291 * Feature used in order to access contact roster groups.
292 *
293 * \sa groups(), addedToGroup(), removedFromGroup()
294 */
295 const Feature Contact::FeatureRosterGroups = Feature(QLatin1String(Contact::staticMetaObject.className()), 7, false);
296
297 /**
298 * Feature used in order to access contact addressable addresses info.
299 *
300 * \sa vcardAddresses(), uris()
301 */
302 const Feature Contact::FeatureAddresses = Feature(QLatin1String(Contact::staticMetaObject.className()), 8, false);
303
304 /**
305 * Feature used in order to access contact client types info.
306 *
307 * \sa clientTypes(), requestClientTypes(), clientTypesChanged()
308 */
309 const Feature Contact::FeatureClientTypes = Feature(QLatin1String(Contact::staticMetaObject.className()), 9, false);
310
311 /**
312 * Construct a new Contact object.
313 *
314 * \param manager ContactManager owning this contact.
315 * \param handle The contact handle.
316 * \param requestedFeatures The contact requested features.
317 * \param attributes The contact attributes.
318 */
Contact(ContactManager * manager,const ReferencedHandles & handle,const Features & requestedFeatures,const QVariantMap & attributes)319 Contact::Contact(ContactManager *manager, const ReferencedHandles &handle,
320 const Features &requestedFeatures, const QVariantMap &attributes)
321 : Object(),
322 mPriv(new Private(this, manager, handle))
323 {
324 mPriv->requestedFeatures.unite(requestedFeatures);
325 mPriv->id = qdbus_cast<QString>(attributes[
326 TP_QT_IFACE_CONNECTION + QLatin1String("/contact-id")]);
327 }
328
329 /**
330 * Class destructor.
331 */
~Contact()332 Contact::~Contact()
333 {
334 debug() << "Contact" << id() << "destroyed";
335 delete mPriv;
336 }
337
338 /**
339 * Return the contact nanager owning this contact.
340 *
341 * \return A pointer to the ContactManager object.
342 */
manager() const343 ContactManagerPtr Contact::manager() const
344 {
345 return ContactManagerPtr(mPriv->manager);
346 }
347
348 /**
349 * Return the handle of this contact.
350 *
351 * \return The handle as a ReferencedHandles object.
352 */
handle() const353 ReferencedHandles Contact::handle() const
354 {
355 return mPriv->handle;
356 }
357
358 /**
359 * Return the identifier of this contact.
360 *
361 * \return The identifier.
362 */
id() const363 QString Contact::id() const
364 {
365 return mPriv->id;
366 }
367
368 /**
369 * Return the features requested on this contact.
370 *
371 * \return The requested features as a set of Feature objects.
372 */
requestedFeatures() const373 Features Contact::requestedFeatures() const
374 {
375 return mPriv->requestedFeatures;
376 }
377
378 /**
379 * Return the features that are actually enabled on this contact.
380 *
381 * \return The actual features as a set of Feature objects.
382 */
actualFeatures() const383 Features Contact::actualFeatures() const
384 {
385 return mPriv->actualFeatures;
386 }
387
388 /**
389 * Return the alias of this contact.
390 *
391 * Change notification is via the aliasChanged() signal.
392 *
393 * This method requires Contact::FeatureAlias to be ready.
394 *
395 * \return The alias.
396 */
alias() const397 QString Contact::alias() const
398 {
399 if (!mPriv->requestedFeatures.contains(FeatureAlias)) {
400 warning() << "Contact::alias() used on" << this
401 << "for which FeatureAlias hasn't been requested - returning id";
402 return id();
403 }
404
405 return mPriv->alias;
406 }
407
408 /**
409 * Return the various vcard addresses that identify this contact.
410 *
411 * This method requires Contact::FeatureAddresses to be ready.
412 *
413 * \return The vcard addresses identifying this contact.
414 * \sa ContactManager::contactsForVCardAddresses(), uris()
415 */
vcardAddresses() const416 QMap<QString, QString> Contact::vcardAddresses() const
417 {
418 return mPriv->vcardAddresses;
419 }
420
421 /**
422 * Return the various URI addresses that identify this contact.
423 *
424 * This method requires Contact::FeatureAddresses to be ready.
425 *
426 * \return The URI addresses identifying this contact.
427 * \sa ContactManager::contactsForUris(), vcardAddresses()
428 */
uris() const429 QStringList Contact::uris() const
430 {
431 return mPriv->uris;
432 }
433
434 /**
435 * Return whether the avatar token of this contact is known.
436 *
437 * This method requires Contact::FeatureAvatarToken to be ready.
438 *
439 * \return \c true if the avatar token is known, \c false otherwise.
440 * \sa avatarToken()
441 */
isAvatarTokenKnown() const442 bool Contact::isAvatarTokenKnown() const
443 {
444 if (!mPriv->requestedFeatures.contains(FeatureAvatarToken)) {
445 warning() << "Contact::isAvatarTokenKnown() used on" << this
446 << "for which FeatureAvatarToken hasn't been requested - returning false";
447 return false;
448 }
449
450 return mPriv->isAvatarTokenKnown;
451 }
452
453 /**
454 * Return the avatar token for this contact.
455 *
456 * Change notification is via the avatarTokenChanged() signal.
457 *
458 * This method requires Contact::FeatureAvatarToken to be ready.
459 *
460 * \return The avatar token.
461 * \sa isAvatarTokenKnown(), avatarTokenChanged(), avatarData()
462 */
avatarToken() const463 QString Contact::avatarToken() const
464 {
465 if (!mPriv->requestedFeatures.contains(FeatureAvatarToken)) {
466 warning() << "Contact::avatarToken() used on" << this
467 << "for which FeatureAvatarToken hasn't been requested - returning \"\"";
468 return QString();
469 } else if (!isAvatarTokenKnown()) {
470 warning() << "Contact::avatarToken() used on" << this
471 << "for which the avatar token is not (yet) known - returning \"\"";
472 return QString();
473 }
474
475 return mPriv->avatarToken;
476 }
477
478 /**
479 * Return the actual avatar for this contact.
480 *
481 * Change notification is via the avatarDataChanged() signal.
482 *
483 * This method requires Contact::FeatureAvatarData to be ready.
484 *
485 * \return The avatar as an AvatarData object.
486 * \sa avatarDataChanged(), avatarToken()
487 */
avatarData() const488 AvatarData Contact::avatarData() const
489 {
490 if (!mPriv->requestedFeatures.contains(FeatureAvatarData)) {
491 warning() << "Contact::avatarData() used on" << this
492 << "for which FeatureAvatarData hasn't been requested - returning \"\"";
493 return AvatarData();
494 }
495
496 return mPriv->avatarData;
497 }
498
499 /**
500 * Start a request to retrieve the avatar for this contact.
501 *
502 * Force the request of the avatar data. This method returns directly, emitting
503 * avatarTokenChanged() and avatarDataChanged() signals once the token and data are
504 * fetched from the server.
505 *
506 * This is only useful if the avatar token is unknown; see isAvatarTokenKnown().
507 * It happens in the case of offline XMPP contacts, because the server does not
508 * send the token for them and an explicit request of the avatar data is needed.
509 *
510 * This method requires Contact::FeatureAvatarData to be ready.
511 *
512 * \sa avatarData(), avatarDataChanged(), avatarToken(), avatarTokenChanged()
513 */
requestAvatarData()514 void Contact::requestAvatarData()
515 {
516 if (!mPriv->requestedFeatures.contains(FeatureAvatarData)) {
517 warning() << "Contact::requestAvatarData() used on" << this
518 << "for which FeatureAvatarData hasn't been requested - returning \"\"";
519 return;
520 }
521
522 return manager()->requestContactAvatars(QList<ContactPtr>() << ContactPtr(this));
523 }
524
525 /**
526 * Return the actual presence of this contact.
527 *
528 * Change notification is via the presenceChanged() signal.
529 *
530 * This method requires Contact::FeatureSimplePresence to be ready.
531 *
532 * \return The presence as a Presence object.
533 */
presence() const534 Presence Contact::presence() const
535 {
536 if (!mPriv->requestedFeatures.contains(FeatureSimplePresence)) {
537 warning() << "Contact::presence() used on" << this
538 << "for which FeatureSimplePresence hasn't been requested - returning Unknown";
539 return Presence();
540 }
541
542 return mPriv->presence;
543 }
544
545 /**
546 * Return the capabilities for this contact.
547 *
548 * User interfaces can use this information to show or hide UI components.
549 *
550 * If ContactManager::supportedFeatures() contains Contact::FeatureCapabilities,
551 * the returned object will be a ContactCapabilities object, where
552 * CapabilitiesBase::isSpecificToContact() will be \c true; if that feature
553 * isn't present, this returned object is the subset of
554 * Contact::manager()::connection()::capabilities()
555 * and CapabilitiesBase::isSpecificToContact() will be \c false.
556 *
557 * Change notification is via the capabilitiesChanged() signal.
558 *
559 * This method requires Contact::FeatureCapabilities to be ready.
560 *
561 * @return An object representing the contact capabilities.
562 */
capabilities() const563 ContactCapabilities Contact::capabilities() const
564 {
565 if (!mPriv->requestedFeatures.contains(FeatureCapabilities)) {
566 warning() << "Contact::capabilities() used on" << this
567 << "for which FeatureCapabilities hasn't been requested - returning 0";
568 return ContactCapabilities(false);
569 }
570
571 return mPriv->caps;
572 }
573
574 /**
575 * Return the location for this contact.
576 *
577 * Change notification is via the locationUpdated() signal.
578 *
579 * This method requires Contact::FeatureLocation to be ready.
580 *
581 * \return The contact location as a LocationInfo object.
582 */
location() const583 LocationInfo Contact::location() const
584 {
585 if (!mPriv->requestedFeatures.contains(FeatureLocation)) {
586 warning() << "Contact::location() used on" << this
587 << "for which FeatureLocation hasn't been requested - returning 0";
588 return LocationInfo();
589 }
590
591 return mPriv->location;
592 }
593
594 /**
595 * Return whether the info card for this contact has been received.
596 *
597 * With some protocols (notably XMPP) information is not pushed from the server
598 * and must be requested explicitely using refreshInfo() or requestInfo(). This
599 * method can be used to know if the information is received from the server
600 * or if an explicit request is needed.
601 *
602 * This method requires Contacat::FeatureInfo to be ready.
603 *
604 * \return \c true if the information is known; \c false otherwise.
605 */
isContactInfoKnown() const606 bool Contact::isContactInfoKnown() const
607 {
608 if (!mPriv->requestedFeatures.contains(FeatureInfo)) {
609 warning() << "Contact::isContactInfoKnown() used on" << this
610 << "for which FeatureInfo hasn't been requested - returning false";
611 return false;
612 }
613
614 return mPriv->isContactInfoKnown;
615 }
616
617 /**
618 * Return the information for this contact.
619 *
620 * Note that this method only return cached information. In order to refresh the
621 * information use refreshInfo().
622 *
623 * Change notification is via the infoFieldsChanged() signal.
624 *
625 * This method requires Contact::FeatureInfo to be ready.
626 *
627 * \return The contact info as a Contact::InfoFields object.
628 */
infoFields() const629 Contact::InfoFields Contact::infoFields() const
630 {
631 if (!mPriv->requestedFeatures.contains(FeatureInfo)) {
632 warning() << "Contact::infoFields() used on" << this
633 << "for which FeatureInfo hasn't been requested - returning empty "
634 "InfoFields";
635 return InfoFields();
636 }
637
638 return mPriv->info;
639 }
640
641 /**
642 * Refresh information for the given contact.
643 *
644 * Once the information is retrieved infoFieldsChanged() will be emitted.
645 *
646 * This method requires Contact::FeatureInfo to be ready.
647 *
648 * \return A PendingOperation, which will emit PendingOperation::finished
649 * when the call has finished.
650 * \sa infoFieldsChanged()
651 */
refreshInfo()652 PendingOperation *Contact::refreshInfo()
653 {
654 ConnectionPtr conn = manager()->connection();
655 if (!mPriv->requestedFeatures.contains(FeatureInfo)) {
656 warning() << "Contact::refreshInfo() used on" << this
657 << "for which FeatureInfo hasn't been requested - failing";
658 return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE,
659 QLatin1String("FeatureInfo needs to be ready in order to "
660 "use this method"),
661 ContactPtr(this));
662 }
663
664 return manager()->refreshContactInfo(QList<ContactPtr>() << ContactPtr(this));
665 }
666
667 /**
668 * Start a request to retrieve the information for this contact.
669 *
670 * This method is useful for UIs that don't care about notification of changes
671 * in the contact information but want to show the contact information
672 * (e.g. right-click on a contact and show the contact info).
673 *
674 * \return A PendingContactInfo, which will emit PendingContactInfo::finished
675 * when the information has been retrieved or an error occurred.
676 */
requestInfo()677 PendingContactInfo *Contact::requestInfo()
678 {
679 return new PendingContactInfo(ContactPtr(this));
680 }
681
682 /**
683 * Return whether the presence subscription state of this contact is known.
684 *
685 * \return \c true if the presence subscription state is known, \c false otherwise.
686 * \sa subscriptionState(), isSubscriptionRejected()
687 */
isSubscriptionStateKnown() const688 bool Contact::isSubscriptionStateKnown() const
689 {
690 return mPriv->subscriptionState != SubscriptionStateUnknown;
691 }
692
693 /**
694 * Return whether a request to see this contact's presence was denied.
695 *
696 * \return \c if the a request to see the presence subscription was denied, \c false otherwise.
697 * \sa isSubscriptionStateKnown(), subscriptionState()
698 */
isSubscriptionRejected() const699 bool Contact::isSubscriptionRejected() const
700 {
701 return mPriv->subscriptionState == SubscriptionStateRemovedRemotely;
702 }
703
704 /**
705 * Return the presence subscription state of this contact (i.e. whether the local user can retrieve
706 * information about this contact's presence).
707 *
708 * \return The presence subscription state as Contact::PresenceState.
709 * \sa isSubscriptionStateKnown(), isSubscriptionRejected()
710 */
subscriptionState() const711 Contact::PresenceState Contact::subscriptionState() const
712 {
713 return subscriptionStateToPresenceState(mPriv->subscriptionState);
714 }
715
716 /**
717 * Return whether the presence publish state of this contact is known.
718 *
719 * \return \c true if the presence publish state is known, \c false otherwise.
720 * \sa publishState(), isPublishCancelled()
721 */
isPublishStateKnown() const722 bool Contact::isPublishStateKnown() const
723 {
724 return mPriv->publishState != SubscriptionStateUnknown;
725 }
726
727 /**
728 * Return whether a request to publish presence information to this contact was cancelled.
729 *
730 * \return \c true if a request to publish presence information was cancelled,
731 * \c false otherwise.
732 * \sa isPublishStateKnown(), publishState()
733 */
isPublishCancelled() const734 bool Contact::isPublishCancelled() const
735 {
736 return mPriv->publishState == SubscriptionStateRemovedRemotely;
737 }
738
739 /**
740 * Return the presence publish state of this contact (i.e. whether this contact can retrieve
741 * information about the local user's presence).
742 *
743 * \return The presence publish state as Contact::PresenceState.
744 * \sa isSubscriptionStateKnown(), isSubscriptionRejected()
745 */
publishState() const746 Contact::PresenceState Contact::publishState() const
747 {
748 return subscriptionStateToPresenceState(mPriv->publishState);
749 }
750
751 /**
752 * If the publishState() is Contact::PresenceStateAsk, return an optional message that was sent
753 * by the contact asking to receive the local user's presence; omitted if none was given.
754 *
755 * \return The message that was sent by the contact asking to receive the local user's presence.
756 * \sa publishState()
757 */
publishStateMessage() const758 QString Contact::publishStateMessage() const
759 {
760 return mPriv->publishStateMessage;
761 }
762
763 /**
764 * Start a request that this contact allow the local user to subscribe to their presence (i.e. that
765 * this contact's subscribe attribute becomes Contact::PresenceStateYes)
766 *
767 * This method requires Connection::FeatureRoster to be ready.
768 *
769 * \return A PendingOperation which will emit PendingOperation::finished
770 * when the request has been made.
771 * \sa subscriptionState(), removePresenceSubscription()
772 */
requestPresenceSubscription(const QString & message)773 PendingOperation *Contact::requestPresenceSubscription(const QString &message)
774 {
775 return manager()->requestPresenceSubscription(QList<ContactPtr>() << ContactPtr(this), message);
776 }
777
778 /**
779 * Start a request for the local user to stop receiving presence from this contact.
780 *
781 * This method requires Connection::FeatureRoster to be ready.
782 *
783 * \return A PendingOperation which will emit PendingOperation::finished
784 * when the request has been made.
785 * \sa subscriptionState(), requestPresenceSubscription()
786 */
removePresenceSubscription(const QString & message)787 PendingOperation *Contact::removePresenceSubscription(const QString &message)
788 {
789 return manager()->removePresenceSubscription(QList<ContactPtr>() << ContactPtr(this), message);
790 }
791
792 /**
793 * Start a request to authorize this contact's request to see the local user presence
794 * (i.e. that this contact publish attribute becomes Contact::PresenceStateYes).
795 *
796 * This method requires Connection::FeatureRoster to be ready.
797 *
798 * \return A PendingOperation which will emit PendingOperation::finished
799 * when the request has been made.
800 * \sa publishState(), removePresencePublication()
801 */
authorizePresencePublication(const QString & message)802 PendingOperation *Contact::authorizePresencePublication(const QString &message)
803 {
804 return manager()->authorizePresencePublication(QList<ContactPtr>() << ContactPtr(this), message);
805 }
806
807 /**
808 * Start a request for the local user to stop sending presence to this contact.
809 *
810 * This method requires Connection::FeatureRoster to be ready.
811 *
812 * \return A PendingOperation which will emit PendingOperation::finished
813 * when the request has been made.
814 * \sa publishState(), authorizePresencePublication()
815 */
removePresencePublication(const QString & message)816 PendingOperation *Contact::removePresencePublication(const QString &message)
817 {
818 return manager()->removePresencePublication(QList<ContactPtr>() << ContactPtr(this), message);
819 }
820
821 /**
822 * Return whether this contact is blocked.
823 *
824 * Change notification is via the blockStatusChanged() signal.
825 *
826 * \return \c true if blocked, \c false otherwise.
827 * \sa block()
828 */
isBlocked() const829 bool Contact::isBlocked() const
830 {
831 return mPriv->blocked;
832 }
833
834 /**
835 * Block this contact. Blocked contacts cannot send messages to the user;
836 * depending on the protocol, blocking a contact may have other effects.
837 *
838 * This method requires Connection::FeatureRoster to be ready.
839 *
840 * \return A PendingOperation which will emit PendingOperation::finished
841 * when an attempt has been made to take the requested action.
842 * \sa blockAndReportAbuse(), unblock()
843 */
block()844 PendingOperation *Contact::block()
845 {
846 return manager()->blockContacts(QList<ContactPtr>() << ContactPtr(this));
847 }
848
849 /**
850 * Block this contact and additionally report abusive behaviour
851 * to the server.
852 *
853 * If reporting abusive behaviour is not supported by the protocol,
854 * this method has the same effect as block().
855 *
856 * This method requires Connection::FeatureRoster to be ready.
857 *
858 * \return A PendingOperation which will emit PendingOperation::finished
859 * when an attempt has been made to take the requested action.
860 * \sa ContactManager::canReportAbuse(), block(), unblock()
861 */
blockAndReportAbuse()862 PendingOperation *Contact::blockAndReportAbuse()
863 {
864 return manager()->blockContactsAndReportAbuse(QList<ContactPtr>() << ContactPtr(this));
865 }
866
867 /**
868 * Unblock this contact.
869 *
870 * This method requires Connection::FeatureRoster to be ready.
871 *
872 * \return A PendingOperation which will emit PendingOperation::finished
873 * when an attempt has been made to take the requested action.
874 * \sa block(), blockAndReportAbuse()
875 */
unblock()876 PendingOperation *Contact::unblock()
877 {
878 return manager()->unblockContacts(QList<ContactPtr>() << ContactPtr(this));
879 }
880
881 /**
882 * Return the names of the user-defined roster groups to which the contact
883 * belongs.
884 *
885 * Change notification is via the addedToGroup() and removedFromGroup() signals.
886 *
887 * This method requires Connection::FeatureRosterGroups to be ready.
888 *
889 * \return A list of user-defined contact list groups names.
890 * \sa addToGroup(), removedFromGroup()
891 */
groups() const892 QStringList Contact::groups() const
893 {
894 return mPriv->groups.toList();
895 }
896
897 /**
898 * Attempt to add the contact to the user-defined contact list
899 * group named \a group.
900 *
901 * This method requires Connection::FeatureRosterGroups to be ready.
902 *
903 * \param group The group name.
904 * \return A PendingOperation which will emit PendingOperation::finished
905 * when an attempt has been made to to add the contact to the user-defined contact
906 * list group.
907 * \sa groups(), removeFromGroup()
908 */
addToGroup(const QString & group)909 PendingOperation *Contact::addToGroup(const QString &group)
910 {
911 return manager()->addContactsToGroup(group, QList<ContactPtr>() << ContactPtr(this));
912 }
913
914 /**
915 * Attempt to remove the contact from the user-defined contact list
916 * group named \a group.
917 *
918 * This method requires Connection::FeatureRosterGroups to be ready.
919 *
920 * \param group The group name.
921 * \return A PendingOperation which will emit PendingOperation::finished
922 * when an attempt has been made to to remote the contact to the user-defined contact
923 * list group.
924 * \sa groups(), addToGroup()
925 */
removeFromGroup(const QString & group)926 PendingOperation *Contact::removeFromGroup(const QString &group)
927 {
928 return manager()->removeContactsFromGroup(group, QList<ContactPtr>() << ContactPtr(this));
929 }
930
931 /**
932 * Return the client types of this contact, if known.
933 *
934 * Client types are represented using the values documented by the XMPP registrar,
935 * with some additional types. A contact can set one or more client types, or can simply
936 * advertise itself as unknown - in this case, an empty list is returned.
937 *
938 * This method returns cached information and is more appropriate for "lazy"
939 * client type finding, for instance displaying the client types (if available)
940 * of everyone in your contact list. For getting latest up-to-date information from
941 * the server you should use requestClientTypes() instead.
942 *
943 * This method requires FeatureClientTypes to be ready.
944 *
945 * \return A list of the client types advertised by this contact.
946 * \sa requestClientTypes(), clientTypesChanged()
947 */
clientTypes() const948 QStringList Contact::clientTypes() const
949 {
950 if (!mPriv->requestedFeatures.contains(FeatureClientTypes)) {
951 warning() << "Contact::clientTypes() used on" << this
952 << "for which FeatureClientTypes hasn't been requested - returning an empty list";
953 return QStringList();
954 }
955
956 return mPriv->clientTypes;
957 }
958
959 /**
960 * Return the current client types of the given contact.
961 *
962 * If necessary, this method will make a request to the server for up-to-date
963 * information and wait for a reply. Therefore, this method is more appropriate
964 * for use in a "Contact Information..." dialog; it can be used to show progress
965 * information (while waiting for the method to return), and can distinguish
966 * between various error conditions.
967 *
968 * This method requires FeatureClientTypes to be ready.
969 *
970 * \return A list of the client types advertised by this contact.
971 * \sa clientTypes(), clientTypesChanged()
972 */
requestClientTypes()973 PendingStringList *Contact::requestClientTypes()
974 {
975 if (!mPriv->requestedFeatures.contains(FeatureClientTypes)) {
976 warning() << "Contact::requestClientTypes() used on" << this
977 << "for which FeatureClientTypes hasn't been requested - the operation will fail";
978 }
979
980 Client::ConnectionInterfaceClientTypesInterface *clientTypesInterface =
981 manager()->connection()->interface<Client::ConnectionInterfaceClientTypesInterface>();
982
983 return new PendingStringList(
984 clientTypesInterface->RequestClientTypes(mPriv->handle.at(0)),
985 ContactPtr(this));
986 }
987
augment(const Features & requestedFeatures,const QVariantMap & attributes)988 void Contact::augment(const Features &requestedFeatures, const QVariantMap &attributes)
989 {
990 mPriv->requestedFeatures.unite(requestedFeatures);
991
992 mPriv->id = qdbus_cast<QString>(attributes[
993 TP_QT_IFACE_CONNECTION + QLatin1String("/contact-id")]);
994
995 if (attributes.contains(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST +
996 QLatin1String("/subscribe"))) {
997 uint subscriptionState = qdbus_cast<uint>(attributes.value(
998 TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/subscribe")));
999 setSubscriptionState((SubscriptionState) subscriptionState);
1000 }
1001
1002 if (attributes.contains(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST +
1003 QLatin1String("/publish"))) {
1004 uint publishState = qdbus_cast<uint>(attributes.value(
1005 TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/publish")));
1006 QString publishRequest = qdbus_cast<QString>(attributes.value(
1007 TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/publish-request")));
1008 setPublishState((SubscriptionState) publishState, publishRequest);
1009 }
1010
1011 foreach (const Feature &feature, requestedFeatures) {
1012 QString maybeAlias;
1013 SimplePresence maybePresence;
1014 RequestableChannelClassList maybeCaps;
1015 QVariantMap maybeLocation;
1016 ContactInfoFieldList maybeInfo;
1017
1018 if (feature == FeatureAlias) {
1019 maybeAlias = qdbus_cast<QString>(attributes.value(
1020 TP_QT_IFACE_CONNECTION_INTERFACE_ALIASING + QLatin1String("/alias")));
1021
1022 if (!maybeAlias.isEmpty()) {
1023 receiveAlias(maybeAlias);
1024 } else if (mPriv->alias.isEmpty()) {
1025 mPriv->alias = mPriv->id;
1026 }
1027 } else if (feature == FeatureAvatarData) {
1028 if (manager()->supportedFeatures().contains(FeatureAvatarData)) {
1029 mPriv->actualFeatures.insert(FeatureAvatarData);
1030 mPriv->updateAvatarData();
1031 }
1032 } else if (feature == FeatureAvatarToken) {
1033 if (attributes.contains(
1034 TP_QT_IFACE_CONNECTION_INTERFACE_AVATARS + QLatin1String("/token"))) {
1035 receiveAvatarToken(qdbus_cast<QString>(attributes.value(
1036 TP_QT_IFACE_CONNECTION_INTERFACE_AVATARS + QLatin1String("/token"))));
1037 } else {
1038 if (manager()->supportedFeatures().contains(FeatureAvatarToken)) {
1039 // AvatarToken being supported but not included in the mapping indicates
1040 // that the avatar token is not known - however, the feature is working fine
1041 mPriv->actualFeatures.insert(FeatureAvatarToken);
1042 }
1043 // In either case, the avatar token can't be known
1044 mPriv->isAvatarTokenKnown = false;
1045 mPriv->avatarToken = QLatin1String("");
1046 }
1047 } else if (feature == FeatureCapabilities) {
1048 maybeCaps = qdbus_cast<RequestableChannelClassList>(attributes.value(
1049 TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES + QLatin1String("/capabilities")));
1050
1051 if (!maybeCaps.isEmpty()) {
1052 receiveCapabilities(maybeCaps);
1053 } else {
1054 if (manager()->supportedFeatures().contains(FeatureCapabilities) &&
1055 mPriv->requestedFeatures.contains(FeatureCapabilities)) {
1056 // Capabilities being supported but not updated in the
1057 // mapping indicates that the capabilities is not known -
1058 // however, the feature is working fine.
1059 mPriv->actualFeatures.insert(FeatureCapabilities);
1060 }
1061 }
1062 } else if (feature == FeatureInfo) {
1063 maybeInfo = qdbus_cast<ContactInfoFieldList>(attributes.value(
1064 TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_INFO + QLatin1String("/info")));
1065
1066 if (!maybeInfo.isEmpty()) {
1067 receiveInfo(maybeInfo);
1068 } else {
1069 if (manager()->supportedFeatures().contains(FeatureInfo) &&
1070 mPriv->requestedFeatures.contains(FeatureInfo)) {
1071 // Info being supported but not updated in the
1072 // mapping indicates that the info is not known -
1073 // however, the feature is working fine
1074 mPriv->actualFeatures.insert(FeatureInfo);
1075 }
1076 }
1077 } else if (feature == FeatureLocation) {
1078 maybeLocation = qdbus_cast<QVariantMap>(attributes.value(
1079 TP_QT_IFACE_CONNECTION_INTERFACE_LOCATION + QLatin1String("/location")));
1080
1081 if (!maybeLocation.isEmpty()) {
1082 receiveLocation(maybeLocation);
1083 } else {
1084 if (manager()->supportedFeatures().contains(FeatureLocation) &&
1085 mPriv->requestedFeatures.contains(FeatureLocation)) {
1086 // Location being supported but not updated in the
1087 // mapping indicates that the location is not known -
1088 // however, the feature is working fine
1089 mPriv->actualFeatures.insert(FeatureLocation);
1090 }
1091 }
1092 } else if (feature == FeatureSimplePresence) {
1093 maybePresence = qdbus_cast<SimplePresence>(attributes.value(
1094 TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE + QLatin1String("/presence")));
1095
1096 if (!maybePresence.status.isEmpty()) {
1097 receiveSimplePresence(maybePresence);
1098 } else {
1099 mPriv->presence.setStatus(ConnectionPresenceTypeUnknown,
1100 QLatin1String("unknown"), QLatin1String(""));
1101 }
1102 } else if (feature == FeatureRosterGroups) {
1103 QStringList groups = qdbus_cast<QStringList>(attributes.value(
1104 TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS + QLatin1String("/groups")));
1105 mPriv->groups = groups.toSet();
1106 } else if (feature == FeatureAddresses) {
1107 VCardFieldAddressMap addresses = qdbus_cast<VCardFieldAddressMap>(attributes.value(
1108 TP_QT_IFACE_CONNECTION_INTERFACE_ADDRESSING + QLatin1String("/addresses")));
1109 QStringList uris = qdbus_cast<QStringList>(attributes.value(
1110 TP_QT_IFACE_CONNECTION_INTERFACE_ADDRESSING + QLatin1String("/uris")));
1111 receiveAddresses(addresses, uris);
1112 } else if (feature == FeatureClientTypes) {
1113 QStringList maybeClientTypes = qdbus_cast<QStringList>(attributes.value(
1114 TP_QT_IFACE_CONNECTION_INTERFACE_CLIENT_TYPES + QLatin1String("/client-types")));
1115
1116 if (!maybeClientTypes.isEmpty()) {
1117 receiveClientTypes(maybeClientTypes);
1118 } else {
1119 if (manager()->supportedFeatures().contains(FeatureClientTypes) &&
1120 mPriv->requestedFeatures.contains(FeatureClientTypes)) {
1121 // ClientTypes being supported but not updated in the
1122 // mapping indicates that the info is not known -
1123 // however, the feature is working fine
1124 mPriv->actualFeatures.insert(FeatureClientTypes);
1125 }
1126 }
1127 } else {
1128 warning() << "Unknown feature" << feature << "encountered when augmenting Contact";
1129 }
1130 }
1131 }
1132
receiveAlias(const QString & alias)1133 void Contact::receiveAlias(const QString &alias)
1134 {
1135 if (!mPriv->requestedFeatures.contains(FeatureAlias)) {
1136 return;
1137 }
1138
1139 mPriv->actualFeatures.insert(FeatureAlias);
1140
1141 if (mPriv->alias != alias) {
1142 mPriv->alias = alias;
1143 emit aliasChanged(alias);
1144 }
1145 }
1146
receiveAvatarToken(const QString & token)1147 void Contact::receiveAvatarToken(const QString &token)
1148 {
1149 setAvatarToken(token);
1150
1151 if (mPriv->actualFeatures.contains(FeatureAvatarData)) {
1152 mPriv->updateAvatarData();
1153 }
1154 }
1155
setAvatarToken(const QString & token)1156 void Contact::setAvatarToken(const QString &token)
1157 {
1158 if (!mPriv->requestedFeatures.contains(FeatureAvatarToken)) {
1159 return;
1160 }
1161
1162 mPriv->actualFeatures.insert(FeatureAvatarToken);
1163
1164 if (!mPriv->isAvatarTokenKnown || mPriv->avatarToken != token) {
1165 mPriv->isAvatarTokenKnown = true;
1166 mPriv->avatarToken = token;
1167 emit avatarTokenChanged(mPriv->avatarToken);
1168 }
1169 }
1170
receiveAvatarData(const AvatarData & avatar)1171 void Contact::receiveAvatarData(const AvatarData &avatar)
1172 {
1173 if (mPriv->avatarData.fileName != avatar.fileName) {
1174 mPriv->avatarData = avatar;
1175 emit avatarDataChanged(mPriv->avatarData);
1176 }
1177 }
1178
receiveSimplePresence(const SimplePresence & presence)1179 void Contact::receiveSimplePresence(const SimplePresence &presence)
1180 {
1181 if (!mPriv->requestedFeatures.contains(FeatureSimplePresence)) {
1182 return;
1183 }
1184
1185 mPriv->actualFeatures.insert(FeatureSimplePresence);
1186
1187 if (mPriv->presence.status() != presence.status ||
1188 mPriv->presence.statusMessage() != presence.statusMessage) {
1189 mPriv->presence.setStatus(presence);
1190 emit presenceChanged(mPriv->presence);
1191 }
1192 }
1193
receiveCapabilities(const RequestableChannelClassList & caps)1194 void Contact::receiveCapabilities(const RequestableChannelClassList &caps)
1195 {
1196 if (!mPriv->requestedFeatures.contains(FeatureCapabilities)) {
1197 return;
1198 }
1199
1200 mPriv->actualFeatures.insert(FeatureCapabilities);
1201
1202 if (mPriv->caps.allClassSpecs().bareClasses() != caps) {
1203 mPriv->caps.updateRequestableChannelClasses(caps);
1204 emit capabilitiesChanged(mPriv->caps);
1205 }
1206 }
1207
receiveLocation(const QVariantMap & location)1208 void Contact::receiveLocation(const QVariantMap &location)
1209 {
1210 if (!mPriv->requestedFeatures.contains(FeatureLocation)) {
1211 return;
1212 }
1213
1214 mPriv->actualFeatures.insert(FeatureLocation);
1215
1216 if (mPriv->location.allDetails() != location) {
1217 mPriv->location.updateData(location);
1218 emit locationUpdated(mPriv->location);
1219 }
1220 }
1221
receiveInfo(const ContactInfoFieldList & info)1222 void Contact::receiveInfo(const ContactInfoFieldList &info)
1223 {
1224 if (!mPriv->requestedFeatures.contains(FeatureInfo)) {
1225 return;
1226 }
1227
1228 mPriv->actualFeatures.insert(FeatureInfo);
1229 mPriv->isContactInfoKnown = true;
1230
1231 if (mPriv->info.allFields() != info) {
1232 mPriv->info = InfoFields(info);
1233 emit infoFieldsChanged(mPriv->info);
1234 }
1235 }
1236
receiveAddresses(const QMap<QString,QString> & addresses,const QStringList & uris)1237 void Contact::receiveAddresses(const QMap<QString, QString> &addresses,
1238 const QStringList &uris)
1239 {
1240 if (!mPriv->requestedFeatures.contains(FeatureAddresses)) {
1241 return;
1242 }
1243
1244 mPriv->actualFeatures.insert(FeatureAddresses);
1245 mPriv->vcardAddresses = addresses;
1246 mPriv->uris = uris;
1247 }
1248
receiveClientTypes(const QStringList & clientTypes)1249 void Contact::receiveClientTypes(const QStringList &clientTypes)
1250 {
1251 if (!mPriv->requestedFeatures.contains(FeatureClientTypes)) {
1252 return;
1253 }
1254
1255 mPriv->actualFeatures.insert(FeatureClientTypes);
1256
1257 if (mPriv->clientTypes != clientTypes) {
1258 mPriv->clientTypes = clientTypes;
1259 emit clientTypesChanged(mPriv->clientTypes);
1260 }
1261 }
1262
subscriptionStateToPresenceState(uint subscriptionState)1263 Contact::PresenceState Contact::subscriptionStateToPresenceState(uint subscriptionState)
1264 {
1265 switch (subscriptionState) {
1266 case SubscriptionStateAsk:
1267 return PresenceStateAsk;
1268 case SubscriptionStateYes:
1269 return PresenceStateYes;
1270 default:
1271 return PresenceStateNo;
1272 }
1273 }
1274
setSubscriptionState(SubscriptionState state)1275 void Contact::setSubscriptionState(SubscriptionState state)
1276 {
1277 if (mPriv->subscriptionState == state) {
1278 return;
1279 }
1280
1281 mPriv->subscriptionState = state;
1282
1283 emit subscriptionStateChanged(subscriptionStateToPresenceState(state));
1284 }
1285
setPublishState(SubscriptionState state,const QString & message)1286 void Contact::setPublishState(SubscriptionState state, const QString &message)
1287 {
1288 if (mPriv->publishState == state && mPriv->publishStateMessage == message) {
1289 return;
1290 }
1291
1292 mPriv->publishState = state;
1293 mPriv->publishStateMessage = message;
1294
1295 emit publishStateChanged(subscriptionStateToPresenceState(state), message);
1296 }
1297
setBlocked(bool value)1298 void Contact::setBlocked(bool value)
1299 {
1300 if (mPriv->blocked == value) {
1301 return;
1302 }
1303
1304 mPriv->blocked = value;
1305
1306 emit blockStatusChanged(value);
1307 }
1308
setAddedToGroup(const QString & group)1309 void Contact::setAddedToGroup(const QString &group)
1310 {
1311 if (!mPriv->groups.contains(group)) {
1312 mPriv->groups.insert(group);
1313 emit addedToGroup(group);
1314 }
1315 }
1316
setRemovedFromGroup(const QString & group)1317 void Contact::setRemovedFromGroup(const QString &group)
1318 {
1319 if (mPriv->groups.remove(group)) {
1320 emit removedFromGroup(group);
1321 }
1322 }
1323
1324 /**
1325 * \fn void Contact::aliasChanged(const QString &alias)
1326 *
1327 * Emitted when the value of alias() changes.
1328 *
1329 * \param alias The new alias of this contact.
1330 * \sa alias()
1331 */
1332
1333 /**
1334 * \fn void Contact::avatarTokenChanged(const QString &avatarToken)
1335 *
1336 * Emitted when the value of avatarToken() changes.
1337 *
1338 * \param avatarToken The new avatar token of this contact.
1339 * \sa avatarToken()
1340 */
1341
1342 /**
1343 * \fn void Contact::avatarDataChanged(const QString &avatarToken)
1344 *
1345 * Emitted when the value of avatarData() changes.
1346 *
1347 * \param avatarData The new avatar of this contact.
1348 * \sa avatarData()
1349 */
1350
1351 /**
1352 * \fn void Contact::presenceChanged(const Tp::Presence &presence)
1353 *
1354 * Emitted when the value of presence() changes.
1355 *
1356 * \param presence The new presence of this contact.
1357 * \sa presence()
1358 */
1359
1360 /**
1361 * \fn void Contact::capabilitiesChanged(const Tp::ContactCapabilities &caps)
1362 *
1363 * Emitted when the value of capabilities() changes.
1364 *
1365 * \param caps The new capabilities of this contact.
1366 * \sa capabilities()
1367 */
1368
1369 /**
1370 * \fn void Contact::locationUpdated(const Tp::LocationInfo &location)
1371 *
1372 * Emitted when the value of location() changes.
1373 *
1374 * \param location The new location of this contact.
1375 * \sa location()
1376 */
1377
1378 /**
1379 * \fn void Contact::infoFieldsChanged(const Tp::Contact::InfoFields &infoFields)
1380 *
1381 * Emitted when the value of infoFields() changes.
1382 *
1383 * \param infoFields The new info of this contact.
1384 * \sa infoFields()
1385 */
1386
1387 /**
1388 * \fn void Contact::subscriptionStateChanged(Tp::Contact::PresenceState state)
1389 *
1390 * Emitted when the value of subscriptionState() changes.
1391 *
1392 * \param state The new subscription state of this contact.
1393 * \sa subscriptionState()
1394 */
1395
1396 /**
1397 * \fn void Contact::publishStateChanged(Tp::Contact::PresenceState state, const QString &message)
1398 *
1399 * Emitted when the value of publishState() changes.
1400 *
1401 * \param state The new publish state of this contact.
1402 * \param message The new user-defined status message of this contact.
1403 * \sa publishState()
1404 */
1405
1406 /**
1407 * \fn void Contact::blockStatusChanged(bool blocked)
1408 *
1409 * Emitted when the value of isBlocked() changes.
1410 *
1411 * \param blocked The new block status of this contact.
1412 * \sa isBlocked()
1413 */
1414
1415 /**
1416 * \fn void Contact::addedToGroup(const QString &group)
1417 *
1418 * Emitted when this contact is added to \a group of the contact list.
1419 *
1420 * \param group The group name.
1421 * \sa groups(), removedFromGroup()
1422 */
1423
1424 /**
1425 * \fn void Contact::removedFromGroup(const QString &group)
1426 *
1427 * Emitted when this contact is removed from \a group of the contact list.
1428 *
1429 * \param group The group name.
1430 * \sa groups(), addedToGroup()
1431 */
1432
1433 /**
1434 * \fn void Contact::clientTypesChanged(const QStringList &clientTypes)
1435 *
1436 * Emitted when the client types of this contact change or become known.
1437 *
1438 * \param clientTypes The contact's client types
1439 * \sa clientTypes(), requestClientTypes()
1440 */
1441
1442 } // Tp
1443