/**
* This file is part of TelepathyQt
*
* @copyright Copyright (C) 2008-2010 Collabora Ltd.
* @copyright Copyright (C) 2008-2010 Nokia Corporation
* @license LGPL 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include
#include "TelepathyQt/_gen/contact.moc.hpp"
#include "TelepathyQt/debug-internal.h"
#include "TelepathyQt/future-internal.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace Tp
{
struct TP_QT_NO_EXPORT Contact::Private
{
Private(Contact *parent, ContactManager *manager,
const ReferencedHandles &handle)
: parent(parent),
manager(ContactManagerPtr(manager)),
handle(handle),
caps(manager->supportedFeatures().contains(Contact::FeatureCapabilities) ?
ContactCapabilities(true) : ContactCapabilities(
manager->connection()->capabilities().allClassSpecs(), false)),
isContactInfoKnown(false), isAvatarTokenKnown(false),
subscriptionState(SubscriptionStateUnknown),
publishState(SubscriptionStateUnknown),
blocked(false)
{
}
void updateAvatarData();
Contact *parent;
WeakPtr manager;
ReferencedHandles handle;
QString id;
Features requestedFeatures;
Features actualFeatures;
QString alias;
QMap vcardAddresses;
QStringList uris;
Presence presence;
ContactCapabilities caps;
LocationInfo location;
bool isContactInfoKnown;
InfoFields info;
bool isAvatarTokenKnown;
QString avatarToken;
AvatarData avatarData;
SubscriptionState subscriptionState;
SubscriptionState publishState;
QString publishStateMessage;
bool blocked;
QSet groups;
};
void Contact::Private::updateAvatarData()
{
/* If token is NULL, it means that CM doesn't know the token. In that case we
* have to request the avatar data to get the token. This happens with XMPP
* for offline contacts. We don't want to bypass the avatar cache, so we won't
* update avatar. */
if (avatarToken.isNull()) {
return;
}
/* If token is empty (""), it means the contact has no avatar. */
if (avatarToken.isEmpty()) {
debug() << "Contact" << parent->id() << "has no avatar";
avatarData = AvatarData();
emit parent->avatarDataChanged(avatarData);
return;
}
parent->manager()->requestContactAvatars(QList() << ContactPtr(parent));
}
struct TP_QT_NO_EXPORT Contact::InfoFields::Private : public QSharedData
{
Private(const ContactInfoFieldList &allFields)
: allFields(allFields) {}
ContactInfoFieldList allFields;
};
/**
* \class Contact::InfoFields
* \ingroup clientconn
* \headerfile TelepathyQt/contact.h
*
* \brief The Contact::InfoFields class represents the information of a
* Telepathy contact.
*/
/**
* Construct a info fields instance with the given fields. The instance will indicate that
* it is valid.
*/
Contact::InfoFields::InfoFields(const ContactInfoFieldList &allFields)
: mPriv(new Private(allFields))
{
}
/**
* Constructs a new invalid InfoFields instance.
*/
Contact::InfoFields::InfoFields()
{
}
/**
* Copy constructor.
*/
Contact::InfoFields::InfoFields(const Contact::InfoFields &other)
: mPriv(other.mPriv)
{
}
/**
* Class destructor.
*/
Contact::InfoFields::~InfoFields()
{
}
/**
* Assignment operator.
*/
Contact::InfoFields &Contact::InfoFields::operator=(const Contact::InfoFields &other)
{
this->mPriv = other.mPriv;
return *this;
}
/**
* Return a list containing all fields whose name are \a name.
*
* \param name The name used to match the fields.
* \return A list of ContactInfoField objects.
*/
ContactInfoFieldList Contact::InfoFields::fields(const QString &name) const
{
if (!isValid()) {
return ContactInfoFieldList();
}
ContactInfoFieldList ret;
foreach (const ContactInfoField &field, mPriv->allFields) {
if (field.fieldName == name) {
ret.append(field);
}
}
return ret;
}
/**
* Return a list containing all fields describing the contact information.
*
* \return The contact information as a list of ContactInfoField objects.
*/
ContactInfoFieldList Contact::InfoFields::allFields() const
{
return isValid() ? mPriv->allFields : ContactInfoFieldList();
}
/**
* \class Contact
* \ingroup clientconn
* \headerfile TelepathyQt/contact.h
*
* \brief The Contact class represents a Telepathy contact.
*
* The accessor functions on this object (id(), alias(), and so on) don't make any D-Bus calls;
* instead, they return/use values cached from a previous introspection run.
* The introspection process populates their values in the most efficient way possible based on what
* the service implements.
*
* To avoid unnecessary D-Bus traffic, some accessors only return valid
* information after specific features have been enabled.
* For instance, to retrieve the contact avatar token, it is necessary to
* enable the feature Contact::FeatureAvatarToken.
* See the individual methods descriptions for more details.
*
* Contact features can be enabled by constructing a ContactFactory and enabling
* the desired features, and passing it to AccountManager, Account or ClientRegistrar
* when creating them as appropriate. However, if a particular
* feature is only ever used in a specific circumstance, such as an user opening
* some settings dialog separate from the general view of the application,
* features can be later enabled as needed by calling ContactManager::upgradeContacts() with the
* additional features, and waiting for the resulting PendingOperation to finish.
*
* As an addition to accessors, signals are emitted to indicate that properties have
* changed, for example aliasChanged(), avatarTokenChanged(), etc.
*
* See \ref async_model, \ref shared_ptr
*/
/**
* Feature used in order to access contact alias info.
*
* \sa alias(), aliasChanged()
*/
const Feature Contact::FeatureAlias = Feature(QLatin1String(Contact::staticMetaObject.className()), 0, false);
/**
* Feature used in order to access contact avatar data info.
*
* Enabling this feature will also enable FeatureAvatarToken.
*
* \sa avatarData(), avatarDataChanged()
*/
const Feature Contact::FeatureAvatarData = Feature(QLatin1String(Contact::staticMetaObject.className()), 1, false);
/**
* Feature used in order to access contact avatar token info.
*
* \sa isAvatarTokenKnown(), avatarToken(), avatarTokenChanged()
*/
const Feature Contact::FeatureAvatarToken = Feature(QLatin1String(Contact::staticMetaObject.className()), 2, false);
/**
* Feature used in order to access contact capabilities info.
*
* \sa capabilities(), capabilitiesChanged()
*/
const Feature Contact::FeatureCapabilities = Feature(QLatin1String(Contact::staticMetaObject.className()), 3, false);
/**
* Feature used in order to access contact info fields.
*
* \sa infoFields(), infoFieldsChanged()
*/
const Feature Contact::FeatureInfo = Feature(QLatin1String(Contact::staticMetaObject.className()), 4, false);
/**
* Feature used in order to access contact location info.
*
* \sa location(), locationUpdated()
*/
const Feature Contact::FeatureLocation = Feature(QLatin1String(Contact::staticMetaObject.className()), 5, false);
/**
* Feature used in order to access contact presence info.
*
* \sa presence(), presenceChanged()
*/
const Feature Contact::FeatureSimplePresence = Feature(QLatin1String(Contact::staticMetaObject.className()), 6, false);
/**
* Feature used in order to access contact roster groups.
*
* \sa groups(), addedToGroup(), removedFromGroup()
*/
const Feature Contact::FeatureRosterGroups = Feature(QLatin1String(Contact::staticMetaObject.className()), 7, false);
/**
* Feature used in order to access contact addressable addresses info.
*
* \sa vcardAddresses(), uris()
*/
const Feature Contact::FeatureAddresses = Feature(QLatin1String(Contact::staticMetaObject.className()), 8, false);
/**
* Construct a new Contact object.
*
* \param manager ContactManager owning this contact.
* \param handle The contact handle.
* \param requestedFeatures The contact requested features.
* \param attributes The contact attributes.
*/
Contact::Contact(ContactManager *manager, const ReferencedHandles &handle,
const Features &requestedFeatures, const QVariantMap &attributes)
: Object(),
mPriv(new Private(this, manager, handle))
{
mPriv->requestedFeatures.unite(requestedFeatures);
mPriv->id = qdbus_cast(attributes[
TP_QT_IFACE_CONNECTION + QLatin1String("/contact-id")]);
}
/**
* Class destructor.
*/
Contact::~Contact()
{
debug() << "Contact" << id() << "destroyed";
delete mPriv;
}
/**
* Return the contact nanager owning this contact.
*
* \return A pointer to the ContactManager object.
*/
ContactManagerPtr Contact::manager() const
{
return ContactManagerPtr(mPriv->manager);
}
/**
* Return the handle of this contact.
*
* \return The handle as a ReferencedHandles object.
*/
ReferencedHandles Contact::handle() const
{
return mPriv->handle;
}
/**
* Return the identifier of this contact.
*
* \return The identifier.
*/
QString Contact::id() const
{
return mPriv->id;
}
/**
* Return the features requested on this contact.
*
* \return The requested features as a set of Feature objects.
*/
Features Contact::requestedFeatures() const
{
return mPriv->requestedFeatures;
}
/**
* Return the features that are actually enabled on this contact.
*
* \return The actual features as a set of Feature objects.
*/
Features Contact::actualFeatures() const
{
return mPriv->actualFeatures;
}
/**
* Return the alias of this contact.
*
* Change notification is via the aliasChanged() signal.
*
* This method requires Contact::FeatureAlias to be ready.
*
* \return The alias.
*/
QString Contact::alias() const
{
if (!mPriv->requestedFeatures.contains(FeatureAlias)) {
warning() << "Contact::alias() used on" << this
<< "for which FeatureAlias hasn't been requested - returning id";
return id();
}
return mPriv->alias;
}
/**
* Return the various vcard addresses that identify this contact.
*
* This method requires Contact::FeatureAddresses to be ready.
*
* \return The vcard addresses identifying this contact.
* \sa ContactManager::contactsForVCardAddresses(), uris()
*/
QMap Contact::vcardAddresses() const
{
return mPriv->vcardAddresses;
}
/**
* Return the various URI addresses that identify this contact.
*
* This method requires Contact::FeatureAddresses to be ready.
*
* \return The URI addresses identifying this contact.
* \sa ContactManager::contactsForUris(), vcardAddresses()
*/
QStringList Contact::uris() const
{
return mPriv->uris;
}
/**
* Return whether the avatar token of this contact is known.
*
* This method requires Contact::FeatureAvatarToken to be ready.
*
* \return \c true if the avatar token is known, \c false otherwise.
* \sa avatarToken()
*/
bool Contact::isAvatarTokenKnown() const
{
if (!mPriv->requestedFeatures.contains(FeatureAvatarToken)) {
warning() << "Contact::isAvatarTokenKnown() used on" << this
<< "for which FeatureAvatarToken hasn't been requested - returning false";
return false;
}
return mPriv->isAvatarTokenKnown;
}
/**
* Return the avatar token for this contact.
*
* Change notification is via the avatarTokenChanged() signal.
*
* This method requires Contact::FeatureAvatarToken to be ready.
*
* \return The avatar token.
* \sa isAvatarTokenKnown(), avatarTokenChanged(), avatarData()
*/
QString Contact::avatarToken() const
{
if (!mPriv->requestedFeatures.contains(FeatureAvatarToken)) {
warning() << "Contact::avatarToken() used on" << this
<< "for which FeatureAvatarToken hasn't been requested - returning \"\"";
return QString();
} else if (!isAvatarTokenKnown()) {
warning() << "Contact::avatarToken() used on" << this
<< "for which the avatar token is not (yet) known - returning \"\"";
return QString();
}
return mPriv->avatarToken;
}
/**
* Return the actual avatar for this contact.
*
* Change notification is via the avatarDataChanged() signal.
*
* This method requires Contact::FeatureAvatarData to be ready.
*
* \return The avatar as an AvatarData object.
* \sa avatarDataChanged(), avatarToken()
*/
AvatarData Contact::avatarData() const
{
if (!mPriv->requestedFeatures.contains(FeatureAvatarData)) {
warning() << "Contact::avatarData() used on" << this
<< "for which FeatureAvatarData hasn't been requested - returning \"\"";
return AvatarData();
}
return mPriv->avatarData;
}
/**
* Start a request to retrieve the avatar for this contact.
*
* Force the request of the avatar data. This method returns directly, emitting
* avatarTokenChanged() and avatarDataChanged() signals once the token and data are
* fetched from the server.
*
* This is only useful if the avatar token is unknown; see isAvatarTokenKnown().
* It happens in the case of offline XMPP contacts, because the server does not
* send the token for them and an explicit request of the avatar data is needed.
*
* This method requires Contact::FeatureAvatarData to be ready.
*
* \sa avatarData(), avatarDataChanged(), avatarToken(), avatarTokenChanged()
*/
void Contact::requestAvatarData()
{
if (!mPriv->requestedFeatures.contains(FeatureAvatarData)) {
warning() << "Contact::requestAvatarData() used on" << this
<< "for which FeatureAvatarData hasn't been requested - returning \"\"";
return;
}
return manager()->requestContactAvatars(QList() << ContactPtr(this));
}
/**
* Return the actual presence of this contact.
*
* Change notification is via the presenceChanged() signal.
*
* This method requires Contact::FeatureSimplePresence to be ready.
*
* \return The presence as a Presence object.
*/
Presence Contact::presence() const
{
if (!mPriv->requestedFeatures.contains(FeatureSimplePresence)) {
warning() << "Contact::presence() used on" << this
<< "for which FeatureSimplePresence hasn't been requested - returning Unknown";
return Presence();
}
return mPriv->presence;
}
/**
* Return the capabilities for this contact.
*
* User interfaces can use this information to show or hide UI components.
*
* If ContactManager::supportedFeatures() contains Contact::FeatureCapabilities,
* the returned object will be a ContactCapabilities object, where
* CapabilitiesBase::isSpecificToContact() will be \c true; if that feature
* isn't present, this returned object is the subset of
* Contact::manager()::connection()::capabilities()
* and CapabilitiesBase::isSpecificToContact() will be \c false.
*
* Change notification is via the capabilitiesChanged() signal.
*
* This method requires Contact::FeatureCapabilities to be ready.
*
* @return An object representing the contact capabilities.
*/
ContactCapabilities Contact::capabilities() const
{
if (!mPriv->requestedFeatures.contains(FeatureCapabilities)) {
warning() << "Contact::capabilities() used on" << this
<< "for which FeatureCapabilities hasn't been requested - returning 0";
return ContactCapabilities(false);
}
return mPriv->caps;
}
/**
* Return the location for this contact.
*
* Change notification is via the locationUpdated() signal.
*
* This method requires Contact::FeatureLocation to be ready.
*
* \return The contact location as a LocationInfo object.
*/
LocationInfo Contact::location() const
{
if (!mPriv->requestedFeatures.contains(FeatureLocation)) {
warning() << "Contact::location() used on" << this
<< "for which FeatureLocation hasn't been requested - returning 0";
return LocationInfo();
}
return mPriv->location;
}
/**
* Return whether the info card for this contact has been received.
*
* With some protocols (notably XMPP) information is not pushed from the server
* and must be requested explicitely using refreshInfo() or requestInfo(). This
* method can be used to know if the information is received from the server
* or if an explicit request is needed.
*
* This method requires Contacat::FeatureInfo to be ready.
*
* \return \c true if the information is known; \c false otherwise.
*/
bool Contact::isContactInfoKnown() const
{
if (!mPriv->requestedFeatures.contains(FeatureInfo)) {
warning() << "Contact::isContactInfoKnown() used on" << this
<< "for which FeatureInfo hasn't been requested - returning false";
return false;
}
return mPriv->isContactInfoKnown;
}
/**
* Return the information for this contact.
*
* Note that this method only return cached information. In order to refresh the
* information use refreshInfo().
*
* Change notification is via the infoFieldsChanged() signal.
*
* This method requires Contact::FeatureInfo to be ready.
*
* \return The contact info as a Contact::InfoFields object.
*/
Contact::InfoFields Contact::infoFields() const
{
if (!mPriv->requestedFeatures.contains(FeatureInfo)) {
warning() << "Contact::infoFields() used on" << this
<< "for which FeatureInfo hasn't been requested - returning empty "
"InfoFields";
return InfoFields();
}
return mPriv->info;
}
/**
* Refresh information for the given contact.
*
* Once the information is retrieved infoFieldsChanged() will be emitted.
*
* This method requires Contact::FeatureInfo to be ready.
*
* \return A PendingOperation, which will emit PendingOperation::finished
* when the call has finished.
* \sa infoFieldsChanged()
*/
PendingOperation *Contact::refreshInfo()
{
ConnectionPtr conn = manager()->connection();
if (!mPriv->requestedFeatures.contains(FeatureInfo)) {
warning() << "Contact::refreshInfo() used on" << this
<< "for which FeatureInfo hasn't been requested - failing";
return new PendingFailure(TP_QT_ERROR_NOT_AVAILABLE,
QLatin1String("FeatureInfo needs to be ready in order to "
"use this method"),
ContactPtr(this));
}
return manager()->refreshContactInfo(QList() << ContactPtr(this));
}
/**
* Start a request to retrieve the information for this contact.
*
* This method is useful for UIs that don't care about notification of changes
* in the contact information but want to show the contact information
* (e.g. right-click on a contact and show the contact info).
*
* \return A PendingContactInfo, which will emit PendingContactInfo::finished
* when the information has been retrieved or an error occurred.
*/
PendingContactInfo *Contact::requestInfo()
{
return new PendingContactInfo(ContactPtr(this));
}
/**
* Return whether the presence subscription state of this contact is known.
*
* \return \c true if the presence subscription state is known, \c false otherwise.
* \sa subscriptionState(), isSubscriptionRejected()
*/
bool Contact::isSubscriptionStateKnown() const
{
return mPriv->subscriptionState != SubscriptionStateUnknown;
}
/**
* Return whether a request to see this contact's presence was denied.
*
* \return \c if the a request to see the presence subscription was denied, \c false otherwise.
* \sa isSubscriptionStateKnown(), subscriptionState()
*/
bool Contact::isSubscriptionRejected() const
{
return mPriv->subscriptionState == SubscriptionStateRemovedRemotely;
}
/**
* Return the presence subscription state of this contact (i.e. whether the local user can retrieve
* information about this contact's presence).
*
* \return The presence subscription state as Contact::PresenceState.
* \sa isSubscriptionStateKnown(), isSubscriptionRejected()
*/
Contact::PresenceState Contact::subscriptionState() const
{
return subscriptionStateToPresenceState(mPriv->subscriptionState);
}
/**
* Return whether the presence publish state of this contact is known.
*
* \return \c true if the presence publish state is known, \c false otherwise.
* \sa publishState(), isPublishCancelled()
*/
bool Contact::isPublishStateKnown() const
{
return mPriv->publishState != SubscriptionStateUnknown;
}
/**
* Return whether a request to publish presence information to this contact was cancelled.
*
* \return \c true if a request to publish presence information was cancelled,
* \c false otherwise.
* \sa isPublishStateKnown(), publishState()
*/
bool Contact::isPublishCancelled() const
{
return mPriv->publishState == SubscriptionStateRemovedRemotely;
}
/**
* Return the presence publish state of this contact (i.e. whether this contact can retrieve
* information about the local user's presence).
*
* \return The presence publish state as Contact::PresenceState.
* \sa isSubscriptionStateKnown(), isSubscriptionRejected()
*/
Contact::PresenceState Contact::publishState() const
{
return subscriptionStateToPresenceState(mPriv->publishState);
}
/**
* If the publishState() is Contact::PresenceStateAsk, return an optional message that was sent
* by the contact asking to receive the local user's presence; omitted if none was given.
*
* \return The message that was sent by the contact asking to receive the local user's presence.
* \sa publishState()
*/
QString Contact::publishStateMessage() const
{
return mPriv->publishStateMessage;
}
/**
* Start a request that this contact allow the local user to subscribe to their presence (i.e. that
* this contact's subscribe attribute becomes Contact::PresenceStateYes)
*
* This method requires Connection::FeatureRoster to be ready.
*
* \return A PendingOperation which will emit PendingOperation::finished
* when the request has been made.
* \sa subscriptionState(), removePresenceSubscription()
*/
PendingOperation *Contact::requestPresenceSubscription(const QString &message)
{
return manager()->requestPresenceSubscription(QList() << ContactPtr(this), message);
}
/**
* Start a request for the local user to stop receiving presence from this contact.
*
* This method requires Connection::FeatureRoster to be ready.
*
* \return A PendingOperation which will emit PendingOperation::finished
* when the request has been made.
* \sa subscriptionState(), requestPresenceSubscription()
*/
PendingOperation *Contact::removePresenceSubscription(const QString &message)
{
return manager()->removePresenceSubscription(QList() << ContactPtr(this), message);
}
/**
* Start a request to authorize this contact's request to see the local user presence
* (i.e. that this contact publish attribute becomes Contact::PresenceStateYes).
*
* This method requires Connection::FeatureRoster to be ready.
*
* \return A PendingOperation which will emit PendingOperation::finished
* when the request has been made.
* \sa publishState(), removePresencePublication()
*/
PendingOperation *Contact::authorizePresencePublication(const QString &message)
{
return manager()->authorizePresencePublication(QList() << ContactPtr(this), message);
}
/**
* Start a request for the local user to stop sending presence to this contact.
*
* This method requires Connection::FeatureRoster to be ready.
*
* \return A PendingOperation which will emit PendingOperation::finished
* when the request has been made.
* \sa publishState(), authorizePresencePublication()
*/
PendingOperation *Contact::removePresencePublication(const QString &message)
{
return manager()->removePresencePublication(QList() << ContactPtr(this), message);
}
/**
* Return whether this contact is blocked.
*
* Change notification is via the blockStatusChanged() signal.
*
* \return \c true if blocked, \c false otherwise.
* \sa block()
*/
bool Contact::isBlocked() const
{
return mPriv->blocked;
}
/**
* Block this contact. Blocked contacts cannot send messages to the user;
* depending on the protocol, blocking a contact may have other effects.
*
* This method requires Connection::FeatureRoster to be ready.
*
* \return A PendingOperation which will emit PendingOperation::finished
* when an attempt has been made to take the requested action.
* \sa blockAndReportAbuse(), unblock()
*/
PendingOperation *Contact::block()
{
return manager()->blockContacts(QList() << ContactPtr(this));
}
/**
* Block this contact and additionally report abusive behaviour
* to the server.
*
* If reporting abusive behaviour is not supported by the protocol,
* this method has the same effect as block().
*
* This method requires Connection::FeatureRoster to be ready.
*
* \return A PendingOperation which will emit PendingOperation::finished
* when an attempt has been made to take the requested action.
* \sa ContactManager::canReportAbuse(), block(), unblock()
*/
PendingOperation *Contact::blockAndReportAbuse()
{
return manager()->blockContactsAndReportAbuse(QList() << ContactPtr(this));
}
/**
* Unblock this contact.
*
* This method requires Connection::FeatureRoster to be ready.
*
* \return A PendingOperation which will emit PendingOperation::finished
* when an attempt has been made to take the requested action.
* \sa block(), blockAndReportAbuse()
*/
PendingOperation *Contact::unblock()
{
return manager()->unblockContacts(QList() << ContactPtr(this));
}
/**
* Return the names of the user-defined roster groups to which the contact
* belongs.
*
* Change notification is via the addedToGroup() and removedFromGroup() signals.
*
* This method requires Connection::FeatureRosterGroups to be ready.
*
* \return A list of user-defined contact list groups names.
* \sa addToGroup(), removedFromGroup()
*/
QStringList Contact::groups() const
{
return mPriv->groups.toList();
}
/**
* Attempt to add the contact to the user-defined contact list
* group named \a group.
*
* This method requires Connection::FeatureRosterGroups to be ready.
*
* \param group The group name.
* \return A PendingOperation which will emit PendingOperation::finished
* when an attempt has been made to to add the contact to the user-defined contact
* list group.
* \sa groups(), removeFromGroup()
*/
PendingOperation *Contact::addToGroup(const QString &group)
{
return manager()->addContactsToGroup(group, QList() << ContactPtr(this));
}
/**
* Attempt to remove the contact from the user-defined contact list
* group named \a group.
*
* This method requires Connection::FeatureRosterGroups to be ready.
*
* \param group The group name.
* \return A PendingOperation which will emit PendingOperation::finished
* when an attempt has been made to to remote the contact to the user-defined contact
* list group.
* \sa groups(), addToGroup()
*/
PendingOperation *Contact::removeFromGroup(const QString &group)
{
return manager()->removeContactsFromGroup(group, QList() << ContactPtr(this));
}
void Contact::augment(const Features &requestedFeatures, const QVariantMap &attributes)
{
mPriv->requestedFeatures.unite(requestedFeatures);
mPriv->id = qdbus_cast(attributes[
TP_QT_IFACE_CONNECTION + QLatin1String("/contact-id")]);
if (attributes.contains(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST +
QLatin1String("/subscribe"))) {
uint subscriptionState = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/subscribe")));
setSubscriptionState((SubscriptionState) subscriptionState);
}
if (attributes.contains(TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST +
QLatin1String("/publish"))) {
uint publishState = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/publish")));
QString publishRequest = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_LIST + QLatin1String("/publish-request")));
setPublishState((SubscriptionState) publishState, publishRequest);
}
foreach (const Feature &feature, requestedFeatures) {
QString maybeAlias;
SimplePresence maybePresence;
RequestableChannelClassList maybeCaps;
QVariantMap maybeLocation;
ContactInfoFieldList maybeInfo;
if (feature == FeatureAlias) {
maybeAlias = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_ALIASING + QLatin1String("/alias")));
if (!maybeAlias.isEmpty()) {
receiveAlias(maybeAlias);
} else if (mPriv->alias.isEmpty()) {
mPriv->alias = mPriv->id;
}
} else if (feature == FeatureAvatarData) {
if (manager()->supportedFeatures().contains(FeatureAvatarData)) {
mPriv->actualFeatures.insert(FeatureAvatarData);
mPriv->updateAvatarData();
}
} else if (feature == FeatureAvatarToken) {
if (attributes.contains(
TP_QT_IFACE_CONNECTION_INTERFACE_AVATARS + QLatin1String("/token"))) {
receiveAvatarToken(qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_AVATARS + QLatin1String("/token"))));
} else {
if (manager()->supportedFeatures().contains(FeatureAvatarToken)) {
// AvatarToken being supported but not included in the mapping indicates
// that the avatar token is not known - however, the feature is working fine
mPriv->actualFeatures.insert(FeatureAvatarToken);
}
// In either case, the avatar token can't be known
mPriv->isAvatarTokenKnown = false;
mPriv->avatarToken = QLatin1String("");
}
} else if (feature == FeatureCapabilities) {
maybeCaps = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES + QLatin1String("/capabilities")));
if (!maybeCaps.isEmpty()) {
receiveCapabilities(maybeCaps);
} else {
if (manager()->supportedFeatures().contains(FeatureCapabilities) &&
mPriv->requestedFeatures.contains(FeatureCapabilities)) {
// Capabilities being supported but not updated in the
// mapping indicates that the capabilities is not known -
// however, the feature is working fine.
mPriv->actualFeatures.insert(FeatureCapabilities);
}
}
} else if (feature == FeatureInfo) {
maybeInfo = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_INFO + QLatin1String("/info")));
if (!maybeInfo.isEmpty()) {
receiveInfo(maybeInfo);
} else {
if (manager()->supportedFeatures().contains(FeatureInfo) &&
mPriv->requestedFeatures.contains(FeatureInfo)) {
// Info being supported but not updated in the
// mapping indicates that the info is not known -
// however, the feature is working fine
mPriv->actualFeatures.insert(FeatureInfo);
}
}
} else if (feature == FeatureLocation) {
maybeLocation = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_LOCATION + QLatin1String("/location")));
if (!maybeLocation.isEmpty()) {
receiveLocation(maybeLocation);
} else {
if (manager()->supportedFeatures().contains(FeatureLocation) &&
mPriv->requestedFeatures.contains(FeatureLocation)) {
// Location being supported but not updated in the
// mapping indicates that the location is not known -
// however, the feature is working fine
mPriv->actualFeatures.insert(FeatureLocation);
}
}
} else if (feature == FeatureSimplePresence) {
maybePresence = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE + QLatin1String("/presence")));
if (!maybePresence.status.isEmpty()) {
receiveSimplePresence(maybePresence);
} else {
mPriv->presence.setStatus(ConnectionPresenceTypeUnknown,
QLatin1String("unknown"), QLatin1String(""));
}
} else if (feature == FeatureRosterGroups) {
QStringList groups = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS + QLatin1String("/groups")));
mPriv->groups = groups.toSet();
} else if (feature == FeatureAddresses) {
VCardFieldAddressMap addresses = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_ADDRESSING + QLatin1String("/addresses")));
QStringList uris = qdbus_cast(attributes.value(
TP_QT_IFACE_CONNECTION_INTERFACE_ADDRESSING + QLatin1String("/uris")));
receiveAddresses(addresses, uris);
} else {
warning() << "Unknown feature" << feature << "encountered when augmenting Contact";
}
}
}
void Contact::receiveAlias(const QString &alias)
{
if (!mPriv->requestedFeatures.contains(FeatureAlias)) {
return;
}
mPriv->actualFeatures.insert(FeatureAlias);
if (mPriv->alias != alias) {
mPriv->alias = alias;
emit aliasChanged(alias);
}
}
void Contact::receiveAvatarToken(const QString &token)
{
setAvatarToken(token);
if (mPriv->actualFeatures.contains(FeatureAvatarData)) {
mPriv->updateAvatarData();
}
}
void Contact::setAvatarToken(const QString &token)
{
if (!mPriv->requestedFeatures.contains(FeatureAvatarToken)) {
return;
}
mPriv->actualFeatures.insert(FeatureAvatarToken);
if (!mPriv->isAvatarTokenKnown || mPriv->avatarToken != token) {
mPriv->isAvatarTokenKnown = true;
mPriv->avatarToken = token;
emit avatarTokenChanged(mPriv->avatarToken);
}
}
void Contact::receiveAvatarData(const AvatarData &avatar)
{
if (mPriv->avatarData.fileName != avatar.fileName) {
mPriv->avatarData = avatar;
emit avatarDataChanged(mPriv->avatarData);
}
}
void Contact::receiveSimplePresence(const SimplePresence &presence)
{
if (!mPriv->requestedFeatures.contains(FeatureSimplePresence)) {
return;
}
mPriv->actualFeatures.insert(FeatureSimplePresence);
if (mPriv->presence.status() != presence.status ||
mPriv->presence.statusMessage() != presence.statusMessage) {
mPriv->presence.setStatus(presence);
emit presenceChanged(mPriv->presence);
}
}
void Contact::receiveCapabilities(const RequestableChannelClassList &caps)
{
if (!mPriv->requestedFeatures.contains(FeatureCapabilities)) {
return;
}
mPriv->actualFeatures.insert(FeatureCapabilities);
if (mPriv->caps.allClassSpecs().bareClasses() != caps) {
mPriv->caps.updateRequestableChannelClasses(caps);
emit capabilitiesChanged(mPriv->caps);
}
}
void Contact::receiveLocation(const QVariantMap &location)
{
if (!mPriv->requestedFeatures.contains(FeatureLocation)) {
return;
}
mPriv->actualFeatures.insert(FeatureLocation);
if (mPriv->location.allDetails() != location) {
mPriv->location.updateData(location);
emit locationUpdated(mPriv->location);
}
}
void Contact::receiveInfo(const ContactInfoFieldList &info)
{
if (!mPriv->requestedFeatures.contains(FeatureInfo)) {
return;
}
mPriv->actualFeatures.insert(FeatureInfo);
mPriv->isContactInfoKnown = true;
if (mPriv->info.allFields() != info) {
mPriv->info = InfoFields(info);
emit infoFieldsChanged(mPriv->info);
}
}
void Contact::receiveAddresses(const QMap &addresses,
const QStringList &uris)
{
if (!mPriv->requestedFeatures.contains(FeatureAddresses)) {
return;
}
mPriv->actualFeatures.insert(FeatureAddresses);
mPriv->vcardAddresses = addresses;
mPriv->uris = uris;
}
Contact::PresenceState Contact::subscriptionStateToPresenceState(uint subscriptionState)
{
switch (subscriptionState) {
case SubscriptionStateAsk:
return PresenceStateAsk;
case SubscriptionStateYes:
return PresenceStateYes;
default:
return PresenceStateNo;
}
}
void Contact::setSubscriptionState(SubscriptionState state)
{
if (mPriv->subscriptionState == state) {
return;
}
mPriv->subscriptionState = state;
emit subscriptionStateChanged(subscriptionStateToPresenceState(state));
}
void Contact::setPublishState(SubscriptionState state, const QString &message)
{
if (mPriv->publishState == state && mPriv->publishStateMessage == message) {
return;
}
mPriv->publishState = state;
mPriv->publishStateMessage = message;
emit publishStateChanged(subscriptionStateToPresenceState(state), message);
}
void Contact::setBlocked(bool value)
{
if (mPriv->blocked == value) {
return;
}
mPriv->blocked = value;
emit blockStatusChanged(value);
}
void Contact::setAddedToGroup(const QString &group)
{
if (!mPriv->groups.contains(group)) {
mPriv->groups.insert(group);
emit addedToGroup(group);
}
}
void Contact::setRemovedFromGroup(const QString &group)
{
if (mPriv->groups.remove(group)) {
emit removedFromGroup(group);
}
}
/**
* \fn void Contact::aliasChanged(const QString &alias)
*
* Emitted when the value of alias() changes.
*
* \param alias The new alias of this contact.
* \sa alias()
*/
/**
* \fn void Contact::avatarTokenChanged(const QString &avatarToken)
*
* Emitted when the value of avatarToken() changes.
*
* \param avatarToken The new avatar token of this contact.
* \sa avatarToken()
*/
/**
* \fn void Contact::avatarDataChanged(const QString &avatarToken)
*
* Emitted when the value of avatarData() changes.
*
* \param avatarData The new avatar of this contact.
* \sa avatarData()
*/
/**
* \fn void Contact::presenceChanged(const Tp::Presence &presence)
*
* Emitted when the value of presence() changes.
*
* \param presence The new presence of this contact.
* \sa presence()
*/
/**
* \fn void Contact::capabilitiesChanged(const Tp::ContactCapabilities &caps)
*
* Emitted when the value of capabilities() changes.
*
* \param caps The new capabilities of this contact.
* \sa capabilities()
*/
/**
* \fn void Contact::locationUpdated(const Tp::LocationInfo &location)
*
* Emitted when the value of location() changes.
*
* \param caps The new location of this contact.
* \sa location()
*/
/**
* \fn void Contact::infoFieldsChanged(const Tp::Contact::InfoFields &infoFields)
*
* Emitted when the value of infoFields() changes.
*
* \param InfoFields The new info of this contact.
* \sa infoFields()
*/
/**
* \fn void Contact::subscriptionStateChanged(Tp::Contact::PresenceState state)
*
* Emitted when the value of subscriptionState() changes.
*
* \param state The new subscription state of this contact.
* \sa subscriptionState()
*/
/**
* \fn void Contact::publishStateChanged(Tp::Contact::PresenceState state, const QString &message)
*
* Emitted when the value of publishState() changes.
*
* \param state The new publish state of this contact.
* \sa publishState()
*/
/**
* \fn void Contact::blockStatusChanged(bool blocked)
*
* Emitted when the value of isBlocked() changes.
*
* \param status The new block status of this contact.
* \sa isBlocked()
*/
/**
* \fn void Contact::addedToGroup(const QString &group)
*
* Emitted when this contact is added to \a group of the contact list.
*
* \param group The group name.
* \sa groups(), removedFromGroup()
*/
/**
* \fn void Contact::removedFromGroup(const QString &group)
*
* Emitted when this contact is removed from \a group of the contact list.
*
* \param group The group name.
* \sa groups(), addedToGroup()
*/
} // Tp