QXmpp  Version: 1.10.4
QXmppOutgoingClient_p.h
1 // SPDX-FileCopyrightText: 2024 Linus Jahn <lnj@kaidan.im>
2 //
3 // SPDX-License-Identifier: LGPL-2.1-or-later
4 
5 #ifndef QXMPPOUTGOINGCLIENT_P_H
6 #define QXMPPOUTGOINGCLIENT_P_H
7 
8 #include "QXmppOutgoingClient.h"
9 #include "QXmppPromise.h"
10 #include "QXmppSaslManager_p.h"
11 #include "QXmppSasl_p.h"
12 #include "QXmppStreamError_p.h"
13 #include "QXmppStreamManagement_p.h"
14 
15 #include "XmppSocket.h"
16 
17 #include <QDnsLookup>
18 #include <QDomElement>
19 
20 class QTimer;
21 class QXmppPacket;
22 
23 // this leaks into other files, maybe better put QXmppOutgoingClientPrivate into QXmpp::Private
24 using namespace QXmpp::Private;
25 
26 namespace QXmpp::Private {
27 
28 using LegacyError = std::variant<QAbstractSocket::SocketError, QXmpp::TimeoutError, QXmppStanza::Error::Condition>;
29 
30 // STARTTLS
31 class StarttlsManager
32 {
33 public:
34  static constexpr QStringView TaskName = u"STARTTLS";
35  QXmppTask<void> task() { return m_promise.task(); }
36  HandleElementResult handleElement(const QDomElement &el);
37 
38 private:
39  QXmppPromise<void> m_promise;
40 };
41 
42 struct ProtocolError {
43  QString text;
44 };
45 
46 struct BoundAddress {
47  QString user;
48  QString domain;
49  QString resource;
50 };
51 
52 // Resource Binding
53 class BindManager
54 {
55 public:
56  using Result = std::variant<BoundAddress, QXmppStanza::Error, ProtocolError>;
57  static constexpr QStringView TaskName = u"resource binding";
58 
59  explicit BindManager(SendDataInterface *socket) : m_socket(socket) { }
60 
61  QXmppTask<Result> bindAddress(const QString &resource);
62  HandleElementResult handleElement(const QDomElement &el);
63 
64 private:
65  SendDataInterface *m_socket;
66  QString m_iqId;
67  std::optional<QXmppPromise<Result>> m_promise;
68 };
69 
70 struct NonSaslAuthOptions {
71  bool plain;
72  bool digest;
73 };
74 
75 // Authentication using Non-SASL auth
76 class NonSaslAuthManager
77 {
78 public:
79  using OptionsResult = std::variant<NonSaslAuthOptions, QXmppError>;
80  using AuthResult = std::variant<Success, QXmppError>;
81  static constexpr QStringView TaskName = u"Non-SASL authentication";
82 
83  explicit NonSaslAuthManager(SendDataInterface *socket) : m_socket(socket) { }
84 
85  QXmppTask<OptionsResult> queryOptions(const QString &streamFrom, const QString &username);
86  QXmppTask<AuthResult> authenticate(bool plainText, const QString &username, const QString &password, const QString &resource, const QString &streamId);
87  HandleElementResult handleElement(const QDomElement &el);
88 
89 private:
90  struct NoQuery {
91  };
92  struct OptionsQuery {
94  };
95  struct AuthQuery {
97  QString id;
98  };
99 
100  SendDataInterface *m_socket;
101  std::variant<NoQuery, OptionsQuery, AuthQuery> m_query;
102 };
103 
104 // XEP-0199: XMPP Ping
105 class PingManager
106 {
107 public:
108  explicit PingManager(QXmppOutgoingClient *q);
109 
110  void onDataReceived();
111 
112 private:
113  void sendPing();
114 
115  QXmppOutgoingClient *q;
116  QTimer *pingTimer;
117  QTimer *timeoutTimer;
118 };
119 
120 using IqResult = QXmppOutgoingClient::IqResult;
121 
122 struct IqState {
123  QXmppPromise<IqResult> interface;
124  QString jid;
125 };
126 
127 // Manager for creating tasks for outgoing IQ requests
128 class OutgoingIqManager
129 {
130 public:
131  OutgoingIqManager(QXmppLoggable *l, StreamAckManager &streamAckMananger);
132  ~OutgoingIqManager();
133 
134  QXmppTask<IqResult> sendIq(QXmppIq &&, const QString &to);
135  QXmppTask<IqResult> sendIq(QXmppPacket &&, const QString &id, const QString &to);
136 
137  bool hasId(const QString &id) const;
138  bool isIdValid(const QString &id) const;
139 
140  QXmppTask<IqResult> start(const QString &id, const QString &to);
141  void finish(const QString &id, IqResult &&result);
142  void cancelAll();
143 
144  void onSessionOpened(const SessionBegin &);
145  void onSessionClosed(const SessionEnd &);
146  bool handleStanza(const QDomElement &stanza);
147 
148 private:
149  void warning(const QString &message);
150 
151  QXmppLoggable *l;
152  StreamAckManager &m_streamAckManager;
153  std::unordered_map<QString, IqState> m_requests;
154 };
155 
156 } // namespace QXmpp::Private
157 
158 class QXmppOutgoingClientPrivate
159 {
160 public:
161  struct Error {
162  QString text;
163  QXmppOutgoingClient::ConnectionError details;
164  LegacyError legacyError;
165  };
166 
167  explicit QXmppOutgoingClientPrivate(QXmppOutgoingClient *q);
168  void connectToHost(const ServerAddress &);
169  void connectToAddressList(std::vector<ServerAddress> &&);
170  void connectToNextAddress();
171 
172  // This object provides the configuration
173  // required for connecting to the XMPP server.
174  QXmppConfiguration config;
175  std::optional<Error> error;
176 
177  // Core stream
178  XmppSocket socket;
179  StreamAckManager streamAckManager;
180  OutgoingIqManager iqManager;
181 
182  // DNS
183  std::vector<ServerAddress> serverAddresses;
184  std::size_t nextServerAddressIndex = 0;
185  enum {
186  Current,
187  TryNext,
188  } nextAddressState = Current;
189 
190  // Stream
191  QString streamId;
192  QString streamFrom;
193  QString streamVersion;
194 
195  // Redirection
196  std::optional<StreamErrorElement::SeeOtherHost> redirect;
197 
198  // Authentication & Session
199  bool isAuthenticated = false;
200  bool bindModeAvailable = false;
201  bool sessionStarted = false;
202  AuthenticationMethod authenticationMethod = AuthenticationMethod::Sasl;
203  std::optional<Bind2Bound> bind2Bound;
204 
205  std::variant<QXmppOutgoingClient *, StarttlsManager, NonSaslAuthManager, SaslManager, Sasl2Manager, C2sStreamManager *, BindManager> listener;
206  FastTokenManager fastTokenManager;
207  C2sStreamManager c2sStreamManager;
208  CarbonManager carbonManager;
209  CsiManager csiManager;
210  PingManager pingManager;
211 
212  template<typename T, typename... Args>
213  T &setListener(Args... args)
214  {
215  listener = T { args... };
216  return std::get<T>(listener);
217  }
218 
219 private:
220  QXmppOutgoingClient *q;
221 };
222 
223 #endif // QXMPPOUTGOINGCLIENT_P_H
The QXmppConfiguration class holds configuration options.
Definition: QXmppConfiguration.h:36
The QXmppLoggable class represents a source of logging messages.
Definition: QXmppLogger.h:109
Definition: QXmppTask.h:61
The QXmppIq class is the base class for all IQs.
Definition: QXmppIq.h:22
Definition: Algorithms.h:12