QXmpp  Version: 1.8.1
QXmppOutgoingClient.h
1 // SPDX-FileCopyrightText: 2010 Manjeet Dahiya <manjeetdahiya@gmail.com>
2 // SPDX-FileCopyrightText: 2010 Jeremy LainĂ© <jeremy.laine@m4x.org>
3 // SPDX-FileCopyrightText: 2020 Linus Jahn <lnj@kaidan.im>
4 //
5 // SPDX-License-Identifier: LGPL-2.1-or-later
6 
7 #ifndef QXMPPOUTGOINGCLIENT_H
8 #define QXMPPOUTGOINGCLIENT_H
9 
10 #include "QXmppAuthenticationError.h"
11 #include "QXmppBindError.h"
12 #include "QXmppClient.h"
13 #include "QXmppPromise.h"
14 #include "QXmppStanza.h"
15 #include "QXmppStreamError.h"
16 
17 #include <QAbstractSocket>
18 
19 class QDomElement;
20 class QSslError;
21 class QSslSocket;
22 
23 class QXmppConfiguration;
24 class QXmppPresence;
25 class QXmppIq;
26 class QXmppMessage;
28 class QXmppOutgoingClientPrivate;
29 class TestClient;
30 
31 namespace QXmpp::Private {
32 class C2sStreamManager;
33 class CarbonManager;
34 class CsiManager;
35 class OutgoingIqManager;
36 class PingManager;
37 class SendDataInterface;
38 class StreamAckManager;
39 class XmppSocket;
40 struct Bind2Request;
41 struct Bind2Bound;
42 struct SmEnabled;
43 struct SmFailed;
44 struct SmResumed;
45 struct StreamErrorElement;
46 
47 enum HandleElementResult {
48  Accepted,
49  Rejected,
50  Finished,
51 };
52 
53 enum class AuthenticationMethod {
54  NonSasl,
55  Sasl,
56  Sasl2,
57 };
58 
59 struct SessionBegin {
60  bool smEnabled;
61  bool smResumed;
62  bool bind2Used;
63  bool fastTokenChanged;
64  AuthenticationMethod authenticationMethod;
65 };
66 
67 struct SessionEnd {
68  bool smCanResume;
69 };
70 } // namespace QXmpp::Private
71 
72 namespace QXmpp::Private::Sasl2 {
73 struct Authenticate;
74 struct StreamFeature;
75 struct Success;
76 } // namespace QXmpp::Private::Sasl2
77 
78 // The QXmppOutgoingClient class represents an outgoing XMPP stream to an XMPP server.
79 class QXMPP_EXPORT QXmppOutgoingClient : public QXmppLoggable
80 {
81  Q_OBJECT
82 
83 public:
84  using IqResult = std::variant<QDomElement, QXmppError>;
85  using ConnectionError = std::variant<QAbstractSocket::SocketError, QXmpp::TimeoutError, QXmpp::StreamError, QXmpp::AuthenticationError, QXmpp::BindError>;
86 
87  explicit QXmppOutgoingClient(QObject *parent);
88  ~QXmppOutgoingClient() override;
89 
90  void connectToHost();
91  void disconnectFromHost();
92  bool isAuthenticated() const;
93  bool isConnected() const;
94  QXmppTask<IqResult> sendIq(QXmppIq &&);
95 
97  QSslSocket *socket() const;
98  QXmppStanza::Error::Condition xmppStreamError();
99 
100  QXmppConfiguration &configuration();
101 
102  QXmpp::Private::XmppSocket &xmppSocket() const;
103  QXmpp::Private::StreamAckManager &streamAckManager() const;
104  QXmpp::Private::OutgoingIqManager &iqManager() const;
105  QXmpp::Private::C2sStreamManager &c2sStreamManager() const;
106  QXmpp::Private::CarbonManager &carbonManager() const;
107  QXmpp::Private::CsiManager &csiManager() const;
108 
110  Q_SIGNAL void connected(const QXmpp::Private::SessionBegin &);
111 
113  Q_SIGNAL void disconnected(const QXmpp::Private::SessionEnd &);
114 
116  Q_SIGNAL void errorOccurred(const QString &text, const QXmppOutgoingClient::ConnectionError &details, QXmppClient::Error oldError);
117 
119  Q_SIGNAL void elementReceived(const QDomElement &element, bool &handled);
120 
122  Q_SIGNAL void presenceReceived(const QXmppPresence &);
123 
125  Q_SIGNAL void messageReceived(const QXmppMessage &);
126 
129  Q_SIGNAL void iqReceived(const QXmppIq &);
130 
132  Q_SIGNAL void sslErrors(const QList<QSslError> &errors);
133 
134 private:
135  void handleStart();
136  void handleStream(const QDomElement &element);
137  void handlePacketReceived(const QDomElement &element);
138  QXmpp::Private::HandleElementResult handleElement(const QDomElement &nodeRecv);
139  void handleStreamFeatures(const QXmppStreamFeatures &features);
140  void handleStreamError(const QXmpp::Private::StreamErrorElement &streamError);
141  bool handleStanza(const QDomElement &);
142  bool handleStarttls(const QXmppStreamFeatures &features);
143 
144  void _q_socketDisconnected();
145  void socketError(QAbstractSocket::SocketError);
146  void socketSslErrors(const QList<QSslError> &);
147 
148  void startSasl2Auth(const QXmpp::Private::Sasl2::StreamFeature &sasl2Feature);
149  void startNonSaslAuth();
150  void startSmResume();
151  void startSmEnable();
152  void startResourceBinding();
153  void openSession();
154  void closeSession();
155  void setError(const QString &text, ConnectionError &&details);
156  void throwKeepAliveError();
157 
158  // for unit tests, see TestClient
159  void enableStreamManagement(bool resetSequenceNumber);
160  bool handleIqResponse(const QDomElement &);
161 
162  friend class QXmppOutgoingClientPrivate;
163  friend class QXmpp::Private::PingManager;
164  friend class QXmpp::Private::C2sStreamManager;
165  friend class QXmppRegistrationManager;
166  friend class TestClient;
167 
168  const std::unique_ptr<QXmppOutgoingClientPrivate> d;
169 };
170 
171 namespace QXmpp::Private {
172 
173 class C2sStreamManager
174 {
175 public:
176  using Result = std::variant<Success, QXmppError>;
177 
178  explicit C2sStreamManager(QXmppOutgoingClient *q);
179 
180  HandleElementResult handleElement(const QDomElement &);
181  bool hasResumeAddress() const { return m_canResume && !m_resumeHost.isEmpty() && m_resumePort; }
182  std::pair<QString, quint16> resumeAddress() const { return { m_resumeHost, m_resumePort }; }
183  void onStreamStart();
184  void onStreamFeatures(const QXmppStreamFeatures &);
185  void onStreamClosed();
186  void onSasl2Authenticate(Sasl2::Authenticate &auth, const Sasl2::StreamFeature &feature);
187  void onSasl2Success(const Sasl2::Success &success);
188  void onBind2Request(Bind2Request &request, const std::vector<QString> &bind2Features);
189  void onBind2Bound(const Bind2Bound &);
190  bool canResume() const { return m_canResume; }
191  bool enabled() const { return m_enabled; }
192  bool streamResumed() const { return m_streamResumed; }
193  bool canRequestResume() const { return m_smAvailable && !m_enabled && m_canResume; }
194  QXmppTask<void> requestResume();
195  bool canRequestEnable() const { return m_smAvailable && !m_enabled; }
196  QXmppTask<void> requestEnable();
197 
198 private:
199  friend class ::TestClient;
200 
201  void onEnabled(const SmEnabled &enabled);
202  void onEnableFailed(const SmFailed &failed);
203  void onResumed(const SmResumed &resumed);
204  void onResumeFailed(const SmFailed &failed);
205  bool setResumeAddress(const QString &address);
206  void setEnabled(bool enabled) { m_enabled = enabled; }
207  void setResumed(bool resumed) { m_streamResumed = resumed; }
208 
209  struct NoRequest { };
210  struct ResumeRequest {
212  };
213  struct EnableRequest {
215  };
216 
217  QXmppOutgoingClient *q;
218 
219  std::variant<NoRequest, ResumeRequest, EnableRequest> m_request;
220  bool m_smAvailable = false;
221  QString m_smId;
222  bool m_canResume = false;
223  QString m_resumeHost;
224  quint16 m_resumePort = 0;
225  bool m_enabled = false;
226  bool m_streamResumed = false;
227 };
228 
229 // XEP-0280: Message Carbons
230 class CarbonManager
231 {
232 public:
233  void setEnableViaBind2(bool enable) { m_enableViaBind2 = enable; }
234  bool enabled() const { return m_enabled; }
235  void onBind2Request(Bind2Request &request, const std::vector<QString> &bind2Features);
236  void onSessionOpened(const SessionBegin &session);
237 
238 private:
239  // whether to enable carbons via bind2 if available
240  bool m_enableViaBind2 = false;
241  // whether carbons have been enabled via bind2
242  bool m_enabled = false;
243  bool m_requested = false;
244 };
245 
246 // XEP-0352: Client State Indication
247 class CsiManager
248 {
249 public:
250  enum State {
251  Active,
252  Inactive,
253  };
254 
255  explicit CsiManager(QXmppOutgoingClient *client);
256 
257  State state() const { return m_state; }
258  void setState(State);
259  void onSessionOpened(const SessionBegin &);
260  void onStreamFeatures(const QXmppStreamFeatures &);
261  void onBind2Request(Bind2Request &request, const std::vector<QString> &bind2Features);
262 
263 private:
264  void sendState();
265 
266  QXmppOutgoingClient *m_client;
267  State m_state = Active;
268  bool m_synced = true;
269  bool m_featureAvailable = false;
270  bool m_bind2InactiveSet = false;
271 };
272 
273 } // namespace QXmpp::Private
274 
275 #endif // QXMPPOUTGOINGCLIENT_H
The QXmppConfiguration class holds configuration options.
Definition: QXmppConfiguration.h:36
The QXmppStreamFeatures class represents the features returned by an XMPP server or client...
Definition: QXmppStreamFeatures.h:22
The QXmppLoggable class represents a source of logging messages.
Definition: QXmppLogger.h:109
Definition: QXmppTask.h:61
Error
Definition: QXmppClient.h:74
Definition: QXmppSasl_p.h:160
The QXmppPresence class represents an XMPP presence stanza.
Definition: QXmppPresence.h:20
Condition
A detailed condition of the error.
Definition: QXmppStanza.h:110
The QXmppRegistrationManager class manages in-band registration and account management tasks like cha...
Definition: QXmppRegistrationManager.h:221
The QXmppIq class is the base class for all IQs.
Definition: QXmppIq.h:22
The QXmppMessage class represents an XMPP message.
Definition: QXmppMessage.h:45
Definition: Algorithms.h:12