QXmpp  Version: 1.15.1
QXmppIqHandling.h
1 // SPDX-FileCopyrightText: 2022 Linus Jahn <lnj@kaidan.im>
2 //
3 // SPDX-License-Identifier: LGPL-2.1-or-later
4 
5 #ifndef QXMPPIQHANDLING_H
6 #define QXMPPIQHANDLING_H
7 
8 #include "QXmppAsync_p.h"
9 #include "QXmppClient.h"
10 #include "QXmppE2eeMetadata.h"
11 #include "QXmppIq.h"
12 #include "QXmppUtils_p.h"
13 #include "QXmppXmlTags_p.h"
14 
15 #include "StringLiterals.h"
16 
17 #include <QDomElement>
18 
19 namespace QXmpp {
20 
21 namespace Private {
22 
23 QXMPP_EXPORT void sendIqReply(QXmppClient *client,
24  const QString &requestId,
25  const QString &requestFrom,
26  const std::optional<QXmppE2eeMetadata> &e2eeMetadata,
27  QXmppIq &&iq);
28 
29 QXMPP_EXPORT std::tuple<bool, QString, QString> checkIsIqRequest(const QDomElement &el);
30 
31 template<typename... VariantTypes>
32 void processHandleIqResult(QXmppClient *client,
33  const QString &requestId,
34  const QString &requestFrom,
35  const std::optional<QXmppE2eeMetadata> &e2eeMetadata,
36  std::variant<VariantTypes...> &&result)
37 {
38  std::visit(
39  [&]<typename T>(T &&value) {
40  static_assert(
41  std::is_base_of_v<QXmppIq, T> || std::is_same_v<QXmppStanza::Error, T> || IsTask<T>,
42  "QXmppIq based type, QXmppStanza::Error or QXmppTask required");
43 
44  if constexpr (std::is_base_of_v<QXmppIq, T>) {
45  sendIqReply(client, requestId, requestFrom, e2eeMetadata, std::move(value));
46  } else if constexpr (std::is_same_v<QXmppStanza::Error, T>) {
47  QXmppIq iq;
49  iq.setError(value);
50  sendIqReply(client, requestId, requestFrom, e2eeMetadata, std::move(iq));
51  } else if constexpr (IsTask<T>) {
52  value.then(client, [=](TaskValueType<T> &&v) {
53  processHandleIqResult(client, requestId, requestFrom, e2eeMetadata, std::move(v));
54  });
55  }
56  },
57  std::move(result));
58 }
59 
60 template<typename T>
61 void processHandleIqResult(QXmppClient *client,
62  const QString &requestId,
63  const QString &requestFrom,
64  const std::optional<QXmppE2eeMetadata> &e2eeMetadata,
65  QXmppTask<T> task)
66 {
67  task.then(client, [client, requestId, requestFrom, e2eeMetadata](T result) {
68  processHandleIqResult(client, requestId, requestFrom, e2eeMetadata, result);
69  });
70 }
71 
72 template<typename T, typename = std::enable_if_t<std::is_base_of_v<QXmppIq, T>, void>>
73 void processHandleIqResult(QXmppClient *client,
74  const QString &requestId,
75  const QString &requestFrom,
76  const std::optional<QXmppE2eeMetadata> &e2eeMetadata,
77  T &&result)
78 {
79  sendIqReply(client, requestId, requestFrom, e2eeMetadata, std::move(result));
80 }
81 
82 template<typename Handler, typename IqType>
83 auto invokeIqHandler(Handler handler, IqType &&iq)
84 {
85  if constexpr (std::is_invocable<Handler, IqType &&>()) {
86  return handler(std::move(iq));
87  } else {
88  return handler->handleIq(std::move(iq));
89  }
90 }
91 
92 template<typename IqType, typename Handler>
93 bool handleIqType(Handler handler,
94  QXmppClient *client,
95  const QDomElement &element,
96  const std::optional<QXmppE2eeMetadata> &e2eeMetadata,
97  const QString &tagName,
98  const QString &xmlNamespace)
99 {
100  if (isPayloadType<IqType>(std::tuple { tagName, xmlNamespace })) {
101  if (auto iq = parseElement<IqType>(element)) {
102  if constexpr (std::is_base_of_v<QXmppIq, IqType>) {
103  iq->setE2eeMetadata(e2eeMetadata);
104  }
105 
106  processHandleIqResult(client, element.attribute(u"id"_s), element.attribute(u"from"_s), e2eeMetadata,
107  invokeIqHandler(std::forward<Handler>(handler), std::move(*iq)));
108  return true;
109  }
110  }
111  return false;
112 }
113 
114 } // namespace Private
115 
192 template<typename... IqTypes, typename Handler>
193 bool handleIqRequests(const QDomElement &element,
194  const std::optional<QXmppE2eeMetadata> &e2eeMetadata,
195  QXmppClient *client,
196  Handler handler)
197 {
198  if (auto [isRequest, tagName, xmlns] = Private::checkIsIqRequest(element); isRequest) {
199  return (Private::handleIqType<IqTypes>(handler, client, element, e2eeMetadata, tagName, xmlns) || ...);
200  }
201  return false;
202 }
203 
275 template<typename... IqTypes, typename Handler>
276 bool handleIqRequests(const QDomElement &element, QXmppClient *client, Handler handler)
277 {
278  return handleIqRequests<IqTypes...>(element, std::nullopt, client, std::forward<Handler>(handler));
279 }
280 
281 } // namespace QXmpp
282 
283 #endif // QXMPPIQHANDLING_H
Definition: QXmppTask.h:67
void setError(const QXmppStanza::Error &error)
Definition: QXmppStanza.cpp:811
The QXmppIq class is the base class for all IQs.
Definition: QXmppIq.h:22
void setType(QXmppIq::Type)
Definition: QXmppIq.cpp:70
bool handleIqRequests(const QDomElement &element, const std::optional< QXmppE2eeMetadata > &e2eeMetadata, QXmppClient *client, Handler handler)
Definition: QXmppIqHandling.h:193
auto then(const QObject *context, Continuation continuation) -> QXmppTask< QXmpp::Private::InvokeContinuationResult< Continuation, T >>
Definition: QXmppTask.h:453
void setE2eeMetadata(const std::optional< QXmppE2eeMetadata > &e2eeMetadata)
Definition: QXmppStanza.cpp:888
The Error class represents a stanza error.
Definition: QXmppStanza.h:111
Main class for starting and managing connections to XMPP servers.
Definition: QXmppClient.h:61