// SPDX-FileCopyrightText: 2020 Linus Jahn // // SPDX-License-Identifier: LGPL-2.1-or-later #include "QXmppPubSubNodeConfig.h" static const auto NODE_CONFIG_FORM_TYPE = QStringLiteral(u"http://jabber.org/protocol/pubsub#node_config"); static const auto PUBLISH_OPTIONS_FORM_TYPE = QStringLiteral("http://jabber.org/protocol/pubsub#publish-options"); static const auto ACCESS_MODEL = QStringLiteral("pubsub#access_model"); static const auto BODY_XSLT = QStringLiteral("pubsub#body_xslt"); static const auto CHILD_ASSOCIATION_POLICY = QStringLiteral("pubsub#children_association_policy"); static const auto CHILD_ASSOCIATION_ALLOWLIST = QStringLiteral("pubsub#children_association_whitelist"); static const auto CHILD_NODES = QStringLiteral("pubsub#children"); static const auto CHILD_NODES_MAX = QStringLiteral("pubsub#children_max"); static const auto COLLECTIONS = QStringLiteral("pubsub#collection"); static const auto CONTACT_JIDS = QStringLiteral("pubsub#contact"); static const auto DATA_FORM_XSLT = QStringLiteral("pubsub#dataform_xslt"); static const auto NOTIFICATIONS_ENABLED = QStringLiteral("pubsub#deliver_notifications"); static const auto INCLUDE_PAYLOADS = QStringLiteral("pubsub#deliver_payloads"); static const auto DESCRIPTION = QStringLiteral("pubsub#description"); static const auto ITEM_EXPIRY = QStringLiteral("pubsub#item_expire"); static const auto NOTIFICATION_ITEM_PUBLISHER = QStringLiteral("pubsub#itemreply"); static const auto LANGUAGE = QStringLiteral("pubsub#language"); static const auto MAX_ITEMS = QStringLiteral("pubsub#max_items"); static const auto MAX_PAYLOAD_SIZE = QStringLiteral("pubsub#max_payload_size"); static const auto NODE_TYPE = QStringLiteral("pubsub#node_type"); static const auto NOTIFICATION_TYPE = QStringLiteral("pubsub#notification_type"); static const auto CONFIG_NOTIFICATIONS_ENABLED = QStringLiteral("pubsub#notify_config"); static const auto NODE_DELETE_NOTIFICATIONS_ENABLED = QStringLiteral("pubsub#notify_delete"); static const auto RETRACT_NOTIFICATIONS_ENABLED = QStringLiteral("pubsub#notify_retract"); static const auto SUB_NOTIFICATIONS_ENABLED = QStringLiteral("pubsub#notify_sub"); static const auto PERSIST_ITEMS = QStringLiteral("pubsub#persist_items"); static const auto PRESENCE_BASED_NOTIFICATIONS = QStringLiteral("pubsub#presence_based_delivery"); static const auto PUBLISH_MODEL = QStringLiteral("pubsub#publish_model"); static const auto PURGE_WHEN_OFFLINE = QStringLiteral("pubsub#purge_offline"); static const auto ALLOWED_ROSTER_GROUPS = QStringLiteral("pubsub#roster_groups_allowed"); static const auto SEND_LAST_ITEM = QStringLiteral("pubsub#send_last_published_item"); static const auto TEMPORARY_SUBSCRIPTIONS = QStringLiteral("pubsub#tempsub"); static const auto ALLOW_SUBSCRIPTIONS = QStringLiteral("pubsub#subscribe"); static const auto TITLE = QStringLiteral("pubsub#title"); static const auto PAYLOAD_TYPE = QStringLiteral("pubsub#type"); // helper for std::visit template struct overloaded : Ts... { using Ts::operator()...; }; // explicit deduction guide (not needed as of C++20) template overloaded(Ts...) -> overloaded; class QXmppPubSubNodeConfigPrivate : public QSharedData { public: std::optional accessModel; QString bodyXslt; std::optional childAssociationPolicy; QStringList childAssociationAllowlist; QStringList childNodes; std::optional childNodesMax; QStringList collections; QStringList contactJids; QString dataFormXslt; std::optional notificationsEnabled; std::optional includePayloads; QString description; std::optional itemExpiry; std::optional notificationItemPublisher; QString language; QXmppPubSubNodeConfig::ItemLimit maxItems; std::optional maxPayloadSize; std::optional nodeType; std::optional notificationType; std::optional configNotificationsEnabled; std::optional deleteNotificationsEnabled; std::optional retractNotificationsEnabled; std::optional subNotificationsEnabled; std::optional persistItems; std::optional presenceBasedNotifications; std::optional publishModel; std::optional purgeWhenOffline; QStringList allowedRosterGroups; std::optional sendLastItem; std::optional temporarySubscriptions; std::optional allowSubscriptions; QString title; QString payloadType; }; std::optional QXmppPubSubNodeConfig::accessModelFromString(const QString &string) { if (string == QStringLiteral("open")) { return Open; } if (string == QStringLiteral("presence")) { return Presence; } if (string == QStringLiteral("roster")) { return Roster; } if (string == QStringLiteral("authorize")) { return Authorize; } if (string == QStringLiteral("whitelist")) { return Allowlist; } return std::nullopt; } QString QXmppPubSubNodeConfig::accessModelToString(AccessModel model) { switch (model) { case Open: return QStringLiteral("open"); case Presence: return QStringLiteral("presence"); case Roster: return QStringLiteral("roster"); case Authorize: return QStringLiteral("authorize"); case Allowlist: return QStringLiteral("whitelist"); } return {}; } std::optional QXmppPubSubNodeConfig::publishModelFromString(const QString &string) { if (string == QStringLiteral("publishers")) { return Publishers; } if (string == QStringLiteral("subscribers")) { return Subscribers; } if (string == QStringLiteral("open")) { return Anyone; } return std::nullopt; } QString QXmppPubSubNodeConfig::publishModelToString(QXmppPubSubNodeConfig::PublishModel model) { switch (model) { case Publishers: return QStringLiteral("publishers"); case Subscribers: return QStringLiteral("subscribers"); case Anyone: return QStringLiteral("open"); } return {}; } std::optional QXmppPubSubNodeConfig::childAssociatationPolicyFromString(const QString &string) { if (string == QStringLiteral("all")) { return ChildAssociationPolicy::All; } if (string == QStringLiteral("owners")) { return ChildAssociationPolicy::Owners; } if (string == QStringLiteral("whitelist")) { return ChildAssociationPolicy::Whitelist; } return std::nullopt; } QString QXmppPubSubNodeConfig::childAssociationPolicyToString(QXmppPubSubNodeConfig::ChildAssociationPolicy policy) { switch (policy) { case ChildAssociationPolicy::All: return QStringLiteral("all"); case ChildAssociationPolicy::Owners: return QStringLiteral("owners"); case ChildAssociationPolicy::Whitelist: return QStringLiteral("whitelist"); } return {}; } std::optional QXmppPubSubNodeConfig::itemPublisherFromString(const QString &string) { if (string == QStringLiteral("owner")) { return NodeOwner; } if (string == QStringLiteral("publisher")) { return Publisher; } return std::nullopt; } QString QXmppPubSubNodeConfig::itemPublisherToString(ItemPublisher publisher) { switch (publisher) { case NodeOwner: return QStringLiteral("owner"); case Publisher: return QStringLiteral("publisher"); } return {}; } std::optional QXmppPubSubNodeConfig::nodeTypeFromString(const QString &string) { if (string == QStringLiteral("leaf")) { return Leaf; } if (string == QStringLiteral("collection")) { return Collection; } return std::nullopt; } QString QXmppPubSubNodeConfig::nodeTypeToString(NodeType type) { switch (type) { case Leaf: return QStringLiteral("leaf"); case Collection: return QStringLiteral("collection"); } return {}; } std::optional QXmppPubSubNodeConfig::notificationTypeFromString(const QString &string) { if (string == QStringLiteral("normal")) { return Normal; } if (string == QStringLiteral("headline")) { return Headline; } return std::nullopt; } QString QXmppPubSubNodeConfig::notificationTypeToString(NotificationType type) { switch (type) { case Normal: return QStringLiteral("normal"); case Headline: return QStringLiteral("headline"); } return {}; } std::optional QXmppPubSubNodeConfig::sendLastItemTypeFromString(const QString &string) { if (string == QStringLiteral("never")) { return Never; } if (string == QStringLiteral("on_sub")) { return OnSubscription; } if (string == QStringLiteral("on_sub_and_presence")) { return OnSubscriptionAndPresence; } return std::nullopt; } QString QXmppPubSubNodeConfig::sendLastItemTypeToString(SendLastItemType type) { switch (type) { case Never: return QStringLiteral("never"); case OnSubscription: return QStringLiteral("on_sub"); case OnSubscriptionAndPresence: return QStringLiteral("on_sub_and_presence"); } return {}; } std::optional QXmppPubSubNodeConfig::fromDataForm(const QXmppDataForm &form) { if (form.formType() != NODE_CONFIG_FORM_TYPE) { return std::nullopt; } QXmppPubSubNodeConfig nodeConfig; if (QXmppDataFormBase::fromDataForm(form, nodeConfig)) { return nodeConfig; } return std::nullopt; } QXmppPubSubNodeConfig::QXmppPubSubNodeConfig() : d(new QXmppPubSubNodeConfigPrivate) { } QXmppPubSubNodeConfig::QXmppPubSubNodeConfig(const QXmppPubSubNodeConfig &) = default; QXmppPubSubNodeConfig::QXmppPubSubNodeConfig(QXmppPubSubNodeConfig &&) = default; QXmppPubSubNodeConfig::~QXmppPubSubNodeConfig() = default; QXmppPubSubNodeConfig &QXmppPubSubNodeConfig::operator=(const QXmppPubSubNodeConfig &) = default; QXmppPubSubNodeConfig &QXmppPubSubNodeConfig::operator=(QXmppPubSubNodeConfig &&) = default; std::optional QXmppPubSubNodeConfig::accessModel() const { return d->accessModel; } void QXmppPubSubNodeConfig::setAccessModel(std::optional accessModel) { d->accessModel = accessModel; } QString QXmppPubSubNodeConfig::bodyXslt() const { return d->bodyXslt; } void QXmppPubSubNodeConfig::setBodyXslt(const QString &bodyXslt) { d->bodyXslt = bodyXslt; } std::optional QXmppPubSubNodeConfig::childAssociationPolicy() const { return d->childAssociationPolicy; } void QXmppPubSubNodeConfig::setChildAssociationPolicy(std::optional childAssociationPolicy) { d->childAssociationPolicy = childAssociationPolicy; } QStringList QXmppPubSubNodeConfig::childAssociationAllowlist() const { return d->childAssociationAllowlist; } void QXmppPubSubNodeConfig::setChildAssociationAllowlist(const QStringList &childAssociationWhitelist) { d->childAssociationAllowlist = childAssociationWhitelist; } QStringList QXmppPubSubNodeConfig::childNodes() const { return d->childNodes; } void QXmppPubSubNodeConfig::setChildNodes(const QStringList &childNodes) { d->childNodes = childNodes; } std::optional QXmppPubSubNodeConfig::childNodesMax() const { return d->childNodesMax; } void QXmppPubSubNodeConfig::setChildNodesMax(std::optional childNodesMax) { d->childNodesMax = childNodesMax; } QStringList QXmppPubSubNodeConfig::collections() const { return d->collections; } void QXmppPubSubNodeConfig::setCollections(const QStringList &collections) { d->collections = collections; } QStringList QXmppPubSubNodeConfig::contactJids() const { return d->contactJids; } void QXmppPubSubNodeConfig::setContactJids(const QStringList &contactJids) { d->contactJids = contactJids; } QString QXmppPubSubNodeConfig::dataFormXslt() const { return d->dataFormXslt; } void QXmppPubSubNodeConfig::setDataFormXslt(const QString &dataFormXslt) { d->dataFormXslt = dataFormXslt; } std::optional QXmppPubSubNodeConfig::notificationsEnabled() const { return d->notificationsEnabled; } void QXmppPubSubNodeConfig::setNotificationsEnabled(std::optional notificationsEnabled) { d->notificationsEnabled = notificationsEnabled; } std::optional QXmppPubSubNodeConfig::includePayloads() const { return d->includePayloads; } void QXmppPubSubNodeConfig::setIncludePayloads(std::optional includePayloads) { d->includePayloads = includePayloads; } QString QXmppPubSubNodeConfig::description() const { return d->description; } void QXmppPubSubNodeConfig::setDescription(const QString &description) { d->description = description; } std::optional QXmppPubSubNodeConfig::itemExpiry() const { return d->itemExpiry; } void QXmppPubSubNodeConfig::setItemExpiry(std::optional itemExpiry) { d->itemExpiry = itemExpiry; } std::optional QXmppPubSubNodeConfig::notificationItemPublisher() const { return d->notificationItemPublisher; } void QXmppPubSubNodeConfig::setNotificationItemPublisher(std::optional notificationItemPublisher) { d->notificationItemPublisher = notificationItemPublisher; } QString QXmppPubSubNodeConfig::language() const { return d->language; } void QXmppPubSubNodeConfig::setLanguage(const QString &language) { d->language = language; } QXmppPubSubNodeConfig::ItemLimit QXmppPubSubNodeConfig::maxItems() const { return d->maxItems; } void QXmppPubSubNodeConfig::setMaxItems(ItemLimit maxItems) { d->maxItems = maxItems; } std::optional QXmppPubSubNodeConfig::maxPayloadSize() const { return d->maxPayloadSize; } void QXmppPubSubNodeConfig::setMaxPayloadSize(std::optional maxPayloadSize) { d->maxPayloadSize = maxPayloadSize; } std::optional QXmppPubSubNodeConfig::nodeType() const { return d->nodeType; } void QXmppPubSubNodeConfig::setNodeType(std::optional nodeType) { d->nodeType = nodeType; } std::optional QXmppPubSubNodeConfig::notificationType() const { return d->notificationType; } void QXmppPubSubNodeConfig::setNotificationType(std::optional notificationType) { d->notificationType = notificationType; } std::optional QXmppPubSubNodeConfig::configNotificationsEnabled() const { return d->configNotificationsEnabled; } void QXmppPubSubNodeConfig::setConfigNotificationsEnabled(std::optional configNotificationsEnabled) { d->configNotificationsEnabled = configNotificationsEnabled; } std::optional QXmppPubSubNodeConfig::deleteNotificationsEnabled() const { return d->deleteNotificationsEnabled; } void QXmppPubSubNodeConfig::setDeleteNotificationsEnabled(std::optional nodeDeleteNotificationsEnabled) { d->deleteNotificationsEnabled = nodeDeleteNotificationsEnabled; } std::optional QXmppPubSubNodeConfig::retractNotificationsEnabled() const { return d->retractNotificationsEnabled; } void QXmppPubSubNodeConfig::setRetractNotificationsEnabled(std::optional retractNotificationsEnabled) { d->retractNotificationsEnabled = retractNotificationsEnabled; } std::optional QXmppPubSubNodeConfig::subNotificationsEnabled() const { return d->subNotificationsEnabled; } void QXmppPubSubNodeConfig::setSubNotificationsEnabled(std::optional subNotificationsEnabled) { d->subNotificationsEnabled = subNotificationsEnabled; } std::optional QXmppPubSubNodeConfig::persistItems() const { return d->persistItems; } void QXmppPubSubNodeConfig::setPersistItems(std::optional persistItems) { d->persistItems = persistItems; } std::optional QXmppPubSubNodeConfig::presenceBasedNotifications() const { return d->presenceBasedNotifications; } void QXmppPubSubNodeConfig::setPresenceBasedNotifications(std::optional presenceBasedNotifications) { d->presenceBasedNotifications = presenceBasedNotifications; } std::optional QXmppPubSubNodeConfig::publishModel() const { return d->publishModel; } void QXmppPubSubNodeConfig::setPublishModel(std::optional publishModel) { d->publishModel = publishModel; } std::optional QXmppPubSubNodeConfig::purgeWhenOffline() const { return d->purgeWhenOffline; } void QXmppPubSubNodeConfig::setPurgeWhenOffline(std::optional purgeWhenOffline) { d->purgeWhenOffline = purgeWhenOffline; } QStringList QXmppPubSubNodeConfig::allowedRosterGroups() const { return d->allowedRosterGroups; } void QXmppPubSubNodeConfig::setAllowedRosterGroups(const QStringList &allowedRosterGroups) { d->allowedRosterGroups = allowedRosterGroups; } std::optional QXmppPubSubNodeConfig::sendLastItem() const { return d->sendLastItem; } void QXmppPubSubNodeConfig::setSendLastItem(std::optional sendLastItem) { d->sendLastItem = sendLastItem; } std::optional QXmppPubSubNodeConfig::temporarySubscriptions() const { return d->temporarySubscriptions; } void QXmppPubSubNodeConfig::setTemporarySubscriptions(std::optional temporarySubscriptions) { d->temporarySubscriptions = temporarySubscriptions; } std::optional QXmppPubSubNodeConfig::allowSubscriptions() const { return d->allowSubscriptions; } void QXmppPubSubNodeConfig::setAllowSubscriptions(std::optional allowSubscriptions) { d->allowSubscriptions = allowSubscriptions; } QString QXmppPubSubNodeConfig::title() const { return d->title; } void QXmppPubSubNodeConfig::setTitle(const QString &title) { d->title = title; } QString QXmppPubSubNodeConfig::payloadType() const { return d->payloadType; } void QXmppPubSubNodeConfig::setPayloadType(const QString &payloadType) { d->payloadType = payloadType; } QString QXmppPubSubNodeConfig::formType() const { return NODE_CONFIG_FORM_TYPE; } bool QXmppPubSubNodeConfig::parseField(const QXmppDataForm::Field &field) { // ignore hidden fields using Type = QXmppDataForm::Field::Type; if (field.type() == Type::HiddenField) { return false; } const auto key = field.key(); const auto value = field.value(); if (key == ACCESS_MODEL) { d->accessModel = accessModelFromString(field.value().toString()); } else if (key == BODY_XSLT) { d->bodyXslt = value.toString(); } else if (key == CHILD_ASSOCIATION_POLICY) { d->childAssociationPolicy = childAssociatationPolicyFromString(value.toString()); } else if (key == CHILD_ASSOCIATION_ALLOWLIST) { d->childAssociationAllowlist = value.toStringList(); } else if (key == CHILD_NODES) { d->childNodes = value.toStringList(); } else if (key == CHILD_NODES_MAX) { d->childNodesMax = parseUInt(value); } else if (key == COLLECTIONS) { d->collections = value.toStringList(); } else if (key == CONTACT_JIDS) { d->contactJids = value.toStringList(); } else if (key == DATA_FORM_XSLT) { d->dataFormXslt = value.toString(); } else if (key == NOTIFICATIONS_ENABLED) { d->notificationsEnabled = parseBool(value); } else if (key == INCLUDE_PAYLOADS) { d->includePayloads = parseBool(value); } else if (key == DESCRIPTION) { d->description = value.toString(); } else if (key == ITEM_EXPIRY) { d->itemExpiry = parseUInt(value); } else if (key == NOTIFICATION_ITEM_PUBLISHER) { d->notificationItemPublisher = itemPublisherFromString(value.toString()); } else if (key == LANGUAGE) { d->language = value.toString(); } else if (key == MAX_ITEMS) { bool ok = false; if (const auto maxItems = value.toULongLong(&ok); ok) { d->maxItems = maxItems; } else if (value.type() == QVariant::String && value.toString() == QStringLiteral("max")) { d->maxItems = Max(); } else { d->maxItems = Unset(); } } else if (key == MAX_PAYLOAD_SIZE) { d->maxPayloadSize = parseUInt(value); } else if (key == NODE_TYPE) { d->nodeType = nodeTypeFromString(value.toString()); } else if (key == NOTIFICATION_TYPE) { d->notificationType = notificationTypeFromString(value.toString()); } else if (key == CONFIG_NOTIFICATIONS_ENABLED) { d->configNotificationsEnabled = parseBool(value); } else if (key == NODE_DELETE_NOTIFICATIONS_ENABLED) { d->deleteNotificationsEnabled = parseBool(value); } else if (key == RETRACT_NOTIFICATIONS_ENABLED) { d->retractNotificationsEnabled = parseBool(value); } else if (key == SUB_NOTIFICATIONS_ENABLED) { d->subNotificationsEnabled = parseBool(value); } else if (key == PERSIST_ITEMS) { d->persistItems = parseBool(value); } else if (key == PRESENCE_BASED_NOTIFICATIONS) { d->presenceBasedNotifications = parseBool(value); } else if (key == PUBLISH_MODEL) { d->publishModel = publishModelFromString(value.toString()); } else if (key == PURGE_WHEN_OFFLINE) { d->purgeWhenOffline = parseBool(value); } else if (key == ALLOWED_ROSTER_GROUPS) { d->allowedRosterGroups = value.toStringList(); } else if (key == SEND_LAST_ITEM) { d->sendLastItem = sendLastItemTypeFromString(value.toString()); } else if (key == TEMPORARY_SUBSCRIPTIONS) { d->temporarySubscriptions = parseBool(value); } else if (key == ALLOW_SUBSCRIPTIONS) { d->allowSubscriptions = parseBool(value); } else if (key == TITLE) { d->title = value.toString(); } else if (key == PAYLOAD_TYPE) { d->payloadType = value.toString(); } else { return false; } return true; } void QXmppPubSubNodeConfig::serializeForm(QXmppDataForm &form) const { using Type = QXmppDataForm::Field::Type; serializeOptional(form, Type::ListSingleField, ACCESS_MODEL, d->accessModel, accessModelToString); serializeNullable(form, Type::TextSingleField, BODY_XSLT, d->bodyXslt); serializeOptional(form, Type::ListSingleField, CHILD_ASSOCIATION_POLICY, d->childAssociationPolicy, childAssociationPolicyToString); serializeEmptyable(form, Type::TextMultiField, CHILD_ASSOCIATION_ALLOWLIST, d->childAssociationAllowlist); serializeEmptyable(form, Type::TextMultiField, CHILD_NODES, d->childNodes); serializeOptionalNumber(form, Type::TextSingleField, CHILD_NODES_MAX, d->childNodesMax); serializeEmptyable(form, Type::TextMultiField, COLLECTIONS, d->collections); serializeEmptyable(form, Type::JidMultiField, CONTACT_JIDS, d->contactJids); serializeNullable(form, Type::TextSingleField, DATA_FORM_XSLT, d->dataFormXslt); serializeOptional(form, Type::BooleanField, NOTIFICATIONS_ENABLED, d->notificationsEnabled); serializeOptional(form, Type::BooleanField, INCLUDE_PAYLOADS, d->includePayloads); serializeNullable(form, Type::TextSingleField, DESCRIPTION, d->description); serializeOptionalNumber(form, Type::TextSingleField, ITEM_EXPIRY, d->itemExpiry); serializeOptional(form, Type::ListSingleField, NOTIFICATION_ITEM_PUBLISHER, d->notificationItemPublisher, itemPublisherToString); serializeNullable(form, Type::TextSingleField, LANGUAGE, d->language); std::visit(overloaded { [](Unset) {}, [&](uint64_t value) { serializeValue(form, Type::TextSingleField, MAX_ITEMS, QString::number(value)); }, [&](Max) { serializeValue(form, Type::TextSingleField, MAX_ITEMS, QStringLiteral("max")); } }, d->maxItems); serializeOptionalNumber(form, Type::TextSingleField, MAX_PAYLOAD_SIZE, d->maxPayloadSize); serializeOptional(form, Type::ListSingleField, NODE_TYPE, d->nodeType, nodeTypeToString); serializeOptional(form, Type::ListSingleField, NOTIFICATION_TYPE, d->notificationType, notificationTypeToString); serializeOptional(form, Type::BooleanField, CONFIG_NOTIFICATIONS_ENABLED, d->configNotificationsEnabled); serializeOptional(form, Type::BooleanField, NODE_DELETE_NOTIFICATIONS_ENABLED, d->deleteNotificationsEnabled); serializeOptional(form, Type::BooleanField, RETRACT_NOTIFICATIONS_ENABLED, d->retractNotificationsEnabled); serializeOptional(form, Type::BooleanField, SUB_NOTIFICATIONS_ENABLED, d->subNotificationsEnabled); serializeOptional(form, Type::BooleanField, PERSIST_ITEMS, d->persistItems); serializeOptional(form, Type::BooleanField, PRESENCE_BASED_NOTIFICATIONS, d->presenceBasedNotifications); serializeOptional(form, Type::ListSingleField, PUBLISH_MODEL, d->publishModel, publishModelToString); serializeOptional(form, Type::BooleanField, PURGE_WHEN_OFFLINE, d->purgeWhenOffline); serializeEmptyable(form, Type::ListMultiField, ALLOWED_ROSTER_GROUPS, d->allowedRosterGroups); serializeOptional(form, Type::ListSingleField, SEND_LAST_ITEM, d->sendLastItem, sendLastItemTypeToString); serializeOptional(form, Type::BooleanField, TEMPORARY_SUBSCRIPTIONS, d->temporarySubscriptions); serializeOptional(form, Type::BooleanField, ALLOW_SUBSCRIPTIONS, d->allowSubscriptions); serializeNullable(form, Type::TextSingleField, TITLE, d->title); serializeNullable(form, Type::TextSingleField, PAYLOAD_TYPE, d->payloadType); } QString QXmppPubSubPublishOptions::formType() const { return PUBLISH_OPTIONS_FORM_TYPE; }