QXmpp Version: 1.10.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 "QXmppStreamError_p.h"
13#include "QXmppStreamManagement_p.h"
14
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 {
93 QXmppPromise<OptionsResult> p;
94 };
95 struct AuthQuery {
96 QXmppPromise<AuthResult> p;
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
127// Manager for creating tasks for outgoing IQ requests
128class OutgoingIqManager
129{
130public:
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
148private:
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
158class QXmppOutgoingClientPrivate
159{
160public:
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
219private:
220 QXmppOutgoingClient *q;
221};
222
223#endif // QXMPPOUTGOINGCLIENT_P_H