From f2aadfefa283aafc88131c643b97acd28989ac20 Mon Sep 17 00:00:00 2001 From: Cochise César Date: Mon, 10 Jan 2022 01:27:06 -0300 Subject: Implement XEP-0080: User Location --- src/base/QXmppConstants.cpp | 3 + src/base/QXmppConstants_p.h | 3 + src/base/QXmppGeolocItem.cpp | 202 +++++++++++++++++++++++++++++++++++++++++++ src/base/QXmppGeolocItem.h | 54 ++++++++++++ 4 files changed, 262 insertions(+) create mode 100644 src/base/QXmppGeolocItem.cpp create mode 100644 src/base/QXmppGeolocItem.h (limited to 'src/base') diff --git a/src/base/QXmppConstants.cpp b/src/base/QXmppConstants.cpp index d6e46ae6..b738341b 100644 --- a/src/base/QXmppConstants.cpp +++ b/src/base/QXmppConstants.cpp @@ -58,6 +58,9 @@ const char *ns_register_feature = "http://jabber.org/features/iq-register"; // XEP-0078: Non-SASL Authentication const char *ns_auth = "jabber:iq:auth"; const char *ns_authFeature = "http://jabber.org/features/iq-auth"; +// XEP-0080: User Location +const char *ns_geoloc = "http://jabber.org/protocol/geoloc"; +const char *ns_geoloc_notify = "http://jabber.org/protocol/geoloc+notify"; // XEP-0085: Chat State Notifications const char *ns_chat_states = "http://jabber.org/protocol/chatstates"; // XEP-0091: Legacy Delayed Delivery diff --git a/src/base/QXmppConstants_p.h b/src/base/QXmppConstants_p.h index 7fa7afd5..346c60f5 100644 --- a/src/base/QXmppConstants_p.h +++ b/src/base/QXmppConstants_p.h @@ -70,6 +70,9 @@ extern const char *ns_register_feature; // XEP-0078: Non-SASL Authentication extern const char *ns_auth; extern const char *ns_authFeature; +// XEP-0080: User Location +extern const char *ns_geoloc; +extern const char *ns_geoloc_notify; // XEP-0085: Chat State Notifications extern const char *ns_chat_states; // XEP-0091: Legacy Delayed Delivery diff --git a/src/base/QXmppGeolocItem.cpp b/src/base/QXmppGeolocItem.cpp new file mode 100644 index 00000000..bef54b69 --- /dev/null +++ b/src/base/QXmppGeolocItem.cpp @@ -0,0 +1,202 @@ +// SPDX-FileCopyrightText: 2022 Cochise César +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "QXmppGeolocItem.h" + +#include "QXmppConstants_p.h" +#include "QXmppUtils.h" + +#include +#include + +/// \cond +class QXmppGeolocItemPrivate : public QSharedData +{ +public: + std::optional accuracy; + QString country; + QString locality; + std::optional latitude; + std::optional longitude; +}; +/// \endcond + +/// +/// \class QXmppGeolocItem +/// +/// This class represents a PubSub item for \xep{0080, User Location}. +/// +/// \since QXmpp 1.5 +/// + +/// +/// Default constructor +/// +QXmppGeolocItem::QXmppGeolocItem() + : d(new QXmppGeolocItemPrivate) +{ +} + +/// Copy-constructor. +QXmppGeolocItem::QXmppGeolocItem(const QXmppGeolocItem &other) = default; + +QXmppGeolocItem::~QXmppGeolocItem() = default; + +/// Assignment operator. +QXmppGeolocItem &QXmppGeolocItem::operator=(const QXmppGeolocItem &other) = default; + +/// +/// Returns the horizontal GPS error in meters. +/// +std::optional QXmppGeolocItem::accuracy() const +{ + return d->accuracy; +} + +/// +/// Sets the horizontal GPS error. +/// +void QXmppGeolocItem::setAccuracy(std::optional accuracy) +{ + d->accuracy = std::move(accuracy); +} + +/// +/// Returns the country. +/// +QString QXmppGeolocItem::country() const +{ + return d->country; +} + +/// +/// Sets the country. +/// +void QXmppGeolocItem::setCountry(QString country) +{ + d->country = std::move(country); +} + +/// +/// Returns the latitude in decimal degrees. +/// +std::optional QXmppGeolocItem::latitude() const +{ + return d->latitude; +} + +/// +/// Sets the latitude. +/// +void QXmppGeolocItem::setLatitude(std::optional lat) +{ + if (lat && (*lat > 90 || *lat < -90)) { + d->latitude.reset(); + return; + } + d->latitude = std::move(lat); +} + +/// +/// Returns the locality such as a town or a city. +/// +QString QXmppGeolocItem::locality() const +{ + return d->locality; +} + +/// +/// Sets the locality. +/// +void QXmppGeolocItem::setLocality(QString locality) +{ + d->locality = std::move(locality); +} + +/// +/// Returns the longitude in decimal degrees. +/// +std::optional QXmppGeolocItem::longitude() const +{ + return d->longitude; +} + +/// +/// Sets the longitude. +/// +void QXmppGeolocItem::setLongitude(std::optional lon) +{ + if (lon && (*lon > 180 || *lon < -180)) { + d->longitude.reset(); + return; + } + d->longitude = std::move(lon); +} + +/// +/// Returns true, if the element is a valid \xep{0080}: User Location PubSub item. +/// +bool QXmppGeolocItem::isItem(const QDomElement &itemElement) +{ + auto isPayloadValid = [](const QDomElement &payload) -> bool { + return payload.tagName() == QStringLiteral("geoloc") && + payload.namespaceURI() == ns_geoloc; + }; + + return QXmppPubSubItem::isItem(itemElement, isPayloadValid); +} + +/// \cond +std::optional parseOptDouble(const QDomElement &element) +{ + bool ok = false; + if (auto val = element.text().toDouble(&ok); ok) { + return val; + } + return {}; +} + +void QXmppGeolocItem::parsePayload(const QDomElement &tune) +{ + for (auto child = tune.firstChildElement(); !child.isNull(); child = child.nextSiblingElement()) { + const auto tagName = child.tagName(); + if (tagName == QStringLiteral("accuracy")) { + d->accuracy = parseOptDouble(child); + } else if (tagName == QStringLiteral("country")) { + d->country = child.text(); + } else if (tagName == QStringLiteral("lat")) { + setLatitude(parseOptDouble(child)); + } else if (tagName == QStringLiteral("locality")) { + d->locality = child.text(); + } else if (tagName == QStringLiteral("lon")) { + setLongitude(parseOptDouble(child)); + } + } +} + +auto writeTextEl(QXmlStreamWriter *writer, const QString &name, const std::optional &val) +{ + if (val.has_value()) { + writer->writeTextElement(name, QString::number(*val)); + } +} +auto writeTextEl(QXmlStreamWriter *writer, const QString &name, const QString &val) +{ + helperToXmlAddTextElement(writer, name, val); +} + +void QXmppGeolocItem::serializePayload(QXmlStreamWriter *writer) const +{ + writer->writeStartElement(QStringLiteral("geoloc")); + writer->writeDefaultNamespace(ns_geoloc); + + writeTextEl(writer, QStringLiteral("accuracy"), d->accuracy); + writeTextEl(writer, QStringLiteral("country"), d->country); + writeTextEl(writer, QStringLiteral("lat"), d->latitude); + writeTextEl(writer, QStringLiteral("locality"), d->locality); + writeTextEl(writer, QStringLiteral("lon"), d->longitude); + + writer->writeEndElement(); +} +/// \endcond diff --git a/src/base/QXmppGeolocItem.h b/src/base/QXmppGeolocItem.h new file mode 100644 index 00000000..5b1148f2 --- /dev/null +++ b/src/base/QXmppGeolocItem.h @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2022 Cochise César +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#ifndef QXMPPGEOLOCITEM_H +#define QXMPPGEOLOCITEM_H + +#include "QXmppPubSubItem.h" + +#include + +#include + +class QXmppGeolocItemPrivate; + +class QXMPP_EXPORT QXmppGeolocItem : public QXmppPubSubItem +{ +public: + QXmppGeolocItem(); + QXmppGeolocItem(const QXmppGeolocItem &other); + ~QXmppGeolocItem(); + + QXmppGeolocItem &operator=(const QXmppGeolocItem &other); + + std::optional accuracy() const; + void setAccuracy(std::optional accuracy); + + QString country() const; + void setCountry(QString country); + + std::optional latitude() const; + void setLatitude(std::optional lat); + + QString locality() const; + void setLocality(QString locality); + + std::optional longitude() const; + void setLongitude(std::optional lon); + + static bool isItem(const QDomElement &itemElement); + +protected: + /// \cond + void parsePayload(const QDomElement &payloadElement) override; + void serializePayload(QXmlStreamWriter *writer) const override; + /// \endcond + +private: + QSharedDataPointer d; +}; + +Q_DECLARE_METATYPE(QXmppGeolocItem) + +#endif // QXMPPGEOLOCITEM_H -- cgit v1.2.3