QXmpp Version: 1.10.0
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 QXmppTask<void> task() { return m_promise.task(); }
35 HandleElementResult handleElement(const QDomElement &el);
36
37private:
38 QXmppPromise<void> m_promise;
39};
40
41struct ProtocolError {
42 QString text;
43};
44
45struct BoundAddress {
46 QString user;
47 QString domain;
48 QString resource;
49};
50
51// Resource Binding
52class BindManager
53{
54public:
55 using Result = std::variant<BoundAddress, QXmppStanza::Error, ProtocolError>;
56
57 explicit BindManager(SendDataInterface *socket) : m_socket(socket) { }
58
59 QXmppTask<Result> bindAddress(const QString &resource);
60 HandleElementResult handleElement(const QDomElement &el);
61
62private:
63 SendDataInterface *m_socket;
64 QString m_iqId;
65 std::optional<QXmppPromise<Result>> m_promise;
66};
67
68struct NonSaslAuthOptions {
69 bool plain;
70 bool digest;
71};
72
73// Authentication using Non-SASL auth
74class NonSaslAuthManager
75{
76public:
77 using OptionsResult = std::variant<NonSaslAuthOptions, QXmppError>;
78 using AuthResult = std::variant<Success, QXmppError>;
79
80 explicit NonSaslAuthManager(SendDataInterface *socket) : m_socket(socket) { }
81
82 QXmppTask<OptionsResult> queryOptions(const QString &streamFrom, const QString &username);
83 QXmppTask<AuthResult> authenticate(bool plainText, const QString &username, const QString &password, const QString &resource, const QString &streamId);
84 HandleElementResult handleElement(const QDomElement &el);
85
86private:
87 struct NoQuery {
88 };
89 struct OptionsQuery {
91 };
92 struct AuthQuery {
94 QString id;
95 };
96
97 SendDataInterface *m_socket;
98 std::variant<NoQuery, OptionsQuery, AuthQuery> m_query;
99};
100
101// XEP-0199: XMPP Ping
102class PingManager
103{
104public:
105 explicit PingManager(QXmppOutgoingClient *q);
106
107 void onDataReceived();
108
109private:
110 void sendPing();
111
112 QXmppOutgoingClient *q;
113 QTimer *pingTimer;
114 QTimer *timeoutTimer;
115};
116
117using IqResult = QXmppOutgoingClient::IqResult;
118
119struct IqState {
120 QXmppPromise<IqResult> interface;
121 QString jid;
122};
123
124// Manager for creating tasks for outgoing IQ requests
125class OutgoingIqManager
126{
127public:
128 OutgoingIqManager(QXmppLoggable *l, StreamAckManager &streamAckMananger);
129 ~OutgoingIqManager();
130
131 QXmppTask<IqResult> sendIq(QXmppIq &&, const QString &to);
132 QXmppTask<IqResult> sendIq(QXmppPacket &&, const QString &id, const QString &to);
133
134 bool hasId(const QString &id) const;
135 bool isIdValid(const QString &id) const;
136
137 QXmppTask<IqResult> start(const QString &id, const QString &to);
138 void finish(const QString &id, IqResult &&result);
139 void cancelAll();
140
141 void onSessionOpened(const SessionBegin &);
142 void onSessionClosed(const SessionEnd &);
143 bool handleStanza(const QDomElement &stanza);
144
145private:
146 void warning(const QString &message);
147
148 QXmppLoggable *l;
149 StreamAckManager &m_streamAckManager;
150 std::unordered_map<QString, IqState> m_requests;
151};
152
153} // namespace QXmpp::Private
154
155class QXmppOutgoingClientPrivate
156{
157public:
158 struct Error {
159 QString text;
160 QXmppOutgoingClient::ConnectionError details;
161 LegacyError legacyError;
162 };
163
164 explicit QXmppOutgoingClientPrivate(QXmppOutgoingClient *q);
165 void connectToHost(const ServerAddress &);
166 void connectToAddressList(std::vector<ServerAddress> &&);
167 void connectToNextAddress();
168
169 // This object provides the configuration
170 // required for connecting to the XMPP server.
171 QXmppConfiguration config;
172 std::optional<Error> error;
173
174 // Core stream
175 XmppSocket socket;
176 StreamAckManager streamAckManager;
177 OutgoingIqManager iqManager;
178
179 // DNS
180 std::vector<ServerAddress> serverAddresses;
181 std::size_t nextServerAddressIndex = 0;
182 enum {
183 Current,
184 TryNext,
185 } nextAddressState = Current;
186
187 // Stream
188 QString streamId;
189 QString streamFrom;
190 QString streamVersion;
191
192 // Redirection
193 std::optional<StreamErrorElement::SeeOtherHost> redirect;
194
195 // Authentication & Session
196 bool isAuthenticated = false;
197 bool bindModeAvailable = false;
198 bool sessionStarted = false;
199 AuthenticationMethod authenticationMethod = AuthenticationMethod::Sasl;
200 std::optional<Bind2Bound> bind2Bound;
201
202 std::variant<QXmppOutgoingClient *, StarttlsManager, NonSaslAuthManager, SaslManager, Sasl2Manager, C2sStreamManager *, BindManager> listener;
203 FastTokenManager fastTokenManager;
204 C2sStreamManager c2sStreamManager;
205 CarbonManager carbonManager;
206 CsiManager csiManager;
207 PingManager pingManager;
208
209 template<typename T, typename... Args>
210 T &setListener(Args... args)
211 {
212 listener = T { args... };
213 return std::get<T>(listener);
214 }
215
216private:
217 QXmppOutgoingClient *q;
218};
219
220#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:110
Definition: QXmppTask.h:62