QXmpp Version: 1.14.4
Loading...
Searching...
No Matches
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 "QXmppStreamManagement_p.h"
13
14#include "StreamError.h"
15#include "XmppSocket.h"
16
17#include <QDnsLookup>
18#include <QDomElement>
19
20class QTimer;
21class QXmppPacket;
22
23// this leaks into other files, maybe better put QXmppOutgoingClientPrivate into QXmpp::Private
24using namespace QXmpp::Private;
25
26namespace QXmpp::Private {
27
28using LegacyError = std::variant<QAbstractSocket::SocketError, QXmpp::TimeoutError, QXmppStanza::Error::Condition>;
29
30// STARTTLS
31class StarttlsManager
32{
33public:
34 static constexpr QStringView TaskName = u"STARTTLS";
35 QXmppTask<void> task() { return m_promise.task(); }
36 HandleElementResult handleElement(const QDomElement &el);
37
38private:
39 QXmppPromise<void> m_promise;
40};
41
42struct ProtocolError {
43 QString text;
44};
45
46struct BoundAddress {
47 QString user;
48 QString domain;
49 QString resource;
50};
51
52// Resource Binding
53class BindManager
54{
55public:
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
64private:
65 SendDataInterface *m_socket;
66 QString m_iqId;
67 std::optional<QXmppPromise<Result>> m_promise;
68};
69
70struct NonSaslAuthOptions {
71 bool plain;
72 bool digest;
73};
74
75// Authentication using Non-SASL auth
76class NonSaslAuthManager
77{
78public:
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
89private:
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
105class PingManager
106{
107public:
108 explicit PingManager(QXmppOutgoingClient *q);
109
110 void onDataReceived();
111
112private:
113 void sendPing();
114
115 QXmppOutgoingClient *q;
116 QTimer *pingTimer;
117 QTimer *timeoutTimer;
118};
119
120using IqResult = QXmppOutgoingClient::IqResult;
121
122struct IqState {
123 QXmppPromise<IqResult> interface;
124 QString jid;
125
126 explicit IqState(QString jid) : jid(std::move(jid)) { }
127 IqState(IqState &&) = default;
128 IqState &operator=(IqState &&) = default;
129 IqState(const IqState &) = delete;
130 IqState &operator=(const IqState &) = delete;
131};
132
133// Manager for creating tasks for outgoing IQ requests
134class OutgoingIqManager
135{
136public:
137 OutgoingIqManager(QXmppLoggable *l, StreamAckManager &streamAckMananger);
138 ~OutgoingIqManager();
139
140 QXmppTask<IqResult> sendIq(QXmppIq &&, const QString &to);
141 QXmppTask<IqResult> sendIq(QXmppPacket &&, const QString &id, const QString &to);
142
143 bool hasId(const QString &id) const;
144 bool isIdValid(const QString &id) const;
145
146 QXmppTask<IqResult> start(const QString &id, const QString &to);
147 void finish(const QString &id, IqResult &&result);
148 void cancelAll();
149
150 void onSessionOpened(const SessionBegin &);
151 void onSessionClosed(const SessionEnd &);
152 bool handleStanza(const QDomElement &stanza);
153
154private:
155 void warning(const QString &message);
156
157 QXmppLoggable *l;
158 StreamAckManager &m_streamAckManager;
159 std::unordered_map<QString, IqState> m_requests;
160};
161
162} // namespace QXmpp::Private
163
164class QXmppOutgoingClientPrivate
165{
166public:
167 struct Error {
168 QString text;
169 QXmppOutgoingClient::ConnectionError details;
170 LegacyError legacyError;
171 };
172
173 explicit QXmppOutgoingClientPrivate(QXmppOutgoingClient *q);
174 void connectToHost(const ServerAddress &);
175 void connectToAddressList(std::vector<ServerAddress> &&);
176 void connectToNextAddress();
177
178 // This object provides the configuration
179 // required for connecting to the XMPP server.
180 QXmppConfiguration config;
181 std::optional<Error> error;
182
183 // Core stream
184 XmppSocket socket;
185 StreamAckManager streamAckManager;
186 OutgoingIqManager iqManager;
187
188 // DNS
189 std::vector<ServerAddress> serverAddresses;
190 std::size_t nextServerAddressIndex = 0;
191 enum {
192 Current,
193 TryNext,
194 } nextAddressState = Current;
195
196 QString streamId;
197
198 // Redirection
199 std::optional<StreamErrorElement::SeeOtherHost> redirect;
200
201 // Authentication & Session
202 bool isAuthenticated = false;
203 bool bindModeAvailable = false;
204 bool sessionStarted = false;
205 AuthenticationMethod authenticationMethod = AuthenticationMethod::Sasl;
206 std::optional<Bind2Bound> bind2Bound;
207
208 std::variant<QXmppOutgoingClient *, StarttlsManager, NonSaslAuthManager, SaslManager, Sasl2Manager, C2sStreamManager *, BindManager> listener;
209 FastTokenManager fastTokenManager;
210 C2sStreamManager c2sStreamManager;
211 CarbonManager carbonManager;
212 CsiManager csiManager;
213 PingManager pingManager;
214
215 template<typename T, typename... Args>
216 T &setListener(Args... args)
217 {
218 listener = T { args... };
219 return std::get<T>(listener);
220 }
221
222private:
223 QXmppOutgoingClient *q;
224};
225
226#endif // QXMPPOUTGOINGCLIENT_P_H
The QXmppConfiguration class holds configuration options.
Definition QXmppConfiguration.h:37
The QXmppIq class is the base class for all IQs.
Definition QXmppIq.h:23
The QXmppLoggable class represents a source of logging messages.
Definition QXmppLogger.h:109
Create and update QXmppTask objects to communicate results of asynchronous operations.
Definition QXmppTask.h:81
Definition QXmppTask.h:330
std::variant< T, QXmppError > Result
Definition QXmppGlobal.h:209