Loading...
Searching...
No Matches
QXmppOutgoingClient_p.h
// SPDX-FileCopyrightText: 2024 Linus Jahn <lnj@kaidan.im>
//
// SPDX-License-Identifier: LGPL-2.1-or-later
#ifndef QXMPPOUTGOINGCLIENT_P_H
#define QXMPPOUTGOINGCLIENT_P_H
#include "QXmppOutgoingClient.h"
#include "QXmppPromise.h"
#include "QXmppSaslManager_p.h"
#include "QXmppSasl_p.h"
#include "QXmppStreamManagement_p.h"
#include "StreamError.h"
#include "XmppSocket.h"
#include <QDnsLookup>
#include <QDomElement>
class QTimer;
class QXmppPacket;
// this leaks into other files, maybe better put QXmppOutgoingClientPrivate into QXmpp::Private
using namespace QXmpp::Private;
namespace QXmpp::Private {
using LegacyError = std::variant<QAbstractSocket::SocketError, QXmpp::TimeoutError, QXmppStanza::Error::Condition>;
// STARTTLS
class StarttlsManager
{
public:
static constexpr QStringView TaskName = u"STARTTLS";
QXmppTask<void> task() { return m_promise.task(); }
HandleElementResult handleElement(const QDomElement &el);
private:
QXmppPromise<void> m_promise;
};
struct ProtocolError {
QString text;
};
struct BoundAddress {
QString user;
QString domain;
QString resource;
};
// Resource Binding
class BindManager
{
public:
using Result = std::variant<BoundAddress, QXmppStanza::Error, ProtocolError>;
static constexpr QStringView TaskName = u"resource binding";
explicit BindManager(SendDataInterface *socket) : m_socket(socket) { }
QXmppTask<Result> bindAddress(const QString &resource);
HandleElementResult handleElement(const QDomElement &el);
private:
SendDataInterface *m_socket;
QString m_iqId;
std::optional<QXmppPromise<Result>> m_promise;
};
struct NonSaslAuthOptions {
bool plain;
bool digest;
};
// Authentication using Non-SASL auth
class NonSaslAuthManager
{
public:
using OptionsResult = std::variant<NonSaslAuthOptions, QXmppError>;
using AuthResult = std::variant<Success, QXmppError>;
static constexpr QStringView TaskName = u"Non-SASL authentication";
explicit NonSaslAuthManager(SendDataInterface *socket) : m_socket(socket) { }
QXmppTask<OptionsResult> queryOptions(const QString &streamFrom, const QString &username);
QXmppTask<AuthResult> authenticate(bool plainText, const QString &username, const QString &password, const QString &resource, const QString &streamId);
HandleElementResult handleElement(const QDomElement &el);
private:
struct NoQuery {
};
struct OptionsQuery {
QXmppPromise<OptionsResult> p;
};
struct AuthQuery {
QXmppPromise<AuthResult> p;
QString id;
};
SendDataInterface *m_socket;
std::variant<NoQuery, OptionsQuery, AuthQuery> m_query;
};
// XEP-0199: XMPP Ping
class PingManager
{
public:
explicit PingManager(QXmppOutgoingClient *q);
void onDataReceived();
private:
void sendPing();
QXmppOutgoingClient *q;
QTimer *pingTimer;
QTimer *timeoutTimer;
};
using IqResult = QXmppOutgoingClient::IqResult;
struct IqState {
QXmppPromise<IqResult> interface;
QString jid;
};
// Manager for creating tasks for outgoing IQ requests
class OutgoingIqManager
{
public:
OutgoingIqManager(QXmppLoggable *l, StreamAckManager &streamAckMananger);
~OutgoingIqManager();
QXmppTask<IqResult> sendIq(QXmppIq &&, const QString &to);
QXmppTask<IqResult> sendIq(QXmppPacket &&, const QString &id, const QString &to);
bool hasId(const QString &id) const;
bool isIdValid(const QString &id) const;
QXmppTask<IqResult> start(const QString &id, const QString &to);
void finish(const QString &id, IqResult &&result);
void cancelAll();
void onSessionOpened(const SessionBegin &);
void onSessionClosed(const SessionEnd &);
bool handleStanza(const QDomElement &stanza);
private:
void warning(const QString &message);
QXmppLoggable *l;
StreamAckManager &m_streamAckManager;
std::unordered_map<QString, IqState> m_requests;
};
} // namespace QXmpp::Private
class QXmppOutgoingClientPrivate
{
public:
struct Error {
QString text;
QXmppOutgoingClient::ConnectionError details;
LegacyError legacyError;
};
explicit QXmppOutgoingClientPrivate(QXmppOutgoingClient *q);
void connectToHost(const ServerAddress &);
void connectToAddressList(std::vector<ServerAddress> &&);
void connectToNextAddress();
// This object provides the configuration
// required for connecting to the XMPP server.
QXmppConfiguration config;
std::optional<Error> error;
// Core stream
XmppSocket socket;
StreamAckManager streamAckManager;
OutgoingIqManager iqManager;
// DNS
std::vector<ServerAddress> serverAddresses;
std::size_t nextServerAddressIndex = 0;
enum {
Current,
TryNext,
} nextAddressState = Current;
QString streamId;
// Redirection
std::optional<StreamErrorElement::SeeOtherHost> redirect;
// Authentication & Session
bool isAuthenticated = false;
bool bindModeAvailable = false;
bool sessionStarted = false;
AuthenticationMethod authenticationMethod = AuthenticationMethod::Sasl;
std::optional<Bind2Bound> bind2Bound;
std::variant<QXmppOutgoingClient *, StarttlsManager, NonSaslAuthManager, SaslManager, Sasl2Manager, C2sStreamManager *, BindManager> listener;
FastTokenManager fastTokenManager;
C2sStreamManager c2sStreamManager;
CarbonManager carbonManager;
CsiManager csiManager;
PingManager pingManager;
template<typename T, typename... Args>
T &setListener(Args... args)
{
listener = T { args... };
return std::get<T>(listener);
}
private:
QXmppOutgoingClient *q;
};
#endif // QXMPPOUTGOINGCLIENT_P_H