This repository has been archived on 2025-12-24. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
yachat/iris-legacy/iris/xmpp-core/protocol.h

362 lines
9.8 KiB
C
Raw Permalink Normal View History

2025-12-25 01:37:49 +05:00
/*
* protocol.h - XMPP-Core protocol state machine
* Copyright (C) 2004 Justin Karneges
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef PROTOCOL_H
#define PROTOCOL_H
#include <qpair.h>
//Added by qt3to4:
#include <QList>
#include "xmlprotocol.h"
#include "xmpp.h"
#define NS_ETHERX "http://etherx.jabber.org/streams"
#define NS_CLIENT "jabber:client"
#define NS_SERVER "jabber:server"
#define NS_DIALBACK "jabber:server:dialback"
#define NS_STREAMS "urn:ietf:params:xml:ns:xmpp-streams"
#define NS_TLS "urn:ietf:params:xml:ns:xmpp-tls"
#define NS_SASL "urn:ietf:params:xml:ns:xmpp-sasl"
#define NS_SESSION "urn:ietf:params:xml:ns:xmpp-session"
#define NS_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas"
#define NS_BIND "urn:ietf:params:xml:ns:xmpp-bind"
#define NS_COMPRESS_FEATURE "http://jabber.org/features/compress"
#define NS_COMPRESS_PROTOCOL "http://jabber.org/protocol/compress"
namespace XMPP
{
class Version
{
public:
Version(int maj=0, int min=0);
int major, minor;
};
class StreamFeatures
{
public:
StreamFeatures();
bool tls_supported, sasl_supported, bind_supported, compress_supported;
bool tls_required;
QStringList sasl_mechs;
QStringList compression_mechs;
};
class BasicProtocol : public XmlProtocol
{
public:
// xmpp 1.0 error conditions
enum SASLCond {
Aborted,
IncorrectEncoding,
InvalidAuthzid,
InvalidMech,
MechTooWeak,
NotAuthorized,
TemporaryAuthFailure
};
enum StreamCond {
BadFormat,
BadNamespacePrefix,
Conflict,
ConnectionTimeout,
HostGone,
HostUnknown,
ImproperAddressing,
InternalServerError,
InvalidFrom,
InvalidId,
InvalidNamespace,
InvalidXml,
StreamNotAuthorized,
PolicyViolation,
RemoteConnectionFailed,
ResourceConstraint,
RestrictedXml,
SeeOtherHost,
SystemShutdown,
UndefinedCondition,
UnsupportedEncoding,
UnsupportedStanzaType,
UnsupportedVersion,
XmlNotWellFormed
};
enum BindCond {
BindBadRequest,
BindNotAllowed,
BindConflict
};
// extend the XmlProtocol enums
enum Need {
NSASLMechs = XmlProtocol::NCustom, // need SASL mechlist
NStartTLS, // need to switch on TLS layer
NCompress, // need to switch on compression layer
NSASLFirst, // need SASL first step
NSASLNext, // need SASL next step
NSASLLayer, // need to switch on SASL layer
NCustom = XmlProtocol::NCustom+10
};
enum Event {
EFeatures = XmlProtocol::ECustom, // breakpoint after features packet is received
ESASLSuccess, // breakpoint after successful sasl auth
EStanzaReady, // a stanza was received
EStanzaSent, // a stanza was sent
EReady, // stream is ready for stanza use
ECustom = XmlProtocol::ECustom+10
};
enum Error {
ErrProtocol = XmlProtocol::ErrCustom, // there was an error in the xmpp-core protocol exchange
ErrStream, // <stream:error>, see errCond, errText, and errAppSpec for details
ErrStartTLS, // server refused starttls
ErrCompress, // server refused compression
ErrAuth, // authorization error. errCond holds sasl condition (or numeric code for old-protocol)
ErrBind, // server refused resource bind
ErrCustom = XmlProtocol::ErrCustom+10
};
BasicProtocol();
~BasicProtocol();
void reset();
// for outgoing xml
QDomDocument doc;
// sasl-related
QString saslMech() const;
QByteArray saslStep() const;
void setSASLMechList(const QStringList &list);
void setSASLFirst(const QString &mech, const QByteArray &step);
void setSASLNext(const QByteArray &step);
void setSASLAuthed();
// send / recv
void sendStanza(const QDomElement &e);
void sendDirect(const QString &s);
void sendWhitespace();
QDomElement recvStanza();
// shutdown
void shutdown();
void shutdownWithError(int cond, const QString &otherHost="");
// <stream> information
QString to, from, id, lang;
Version version;
// error output
int errCond;
QString errText;
QDomElement errAppSpec;
QString otherHost;
QByteArray spare; // filled with unprocessed data on NStartTLS and NSASLLayer
bool isReady() const;
enum { TypeElement, TypeStanza, TypeDirect, TypePing };
protected:
static int stringToSASLCond(const QString &s);
static int stringToStreamCond(const QString &s);
static QString saslCondToString(int);
static QString streamCondToString(int);
void send(const QDomElement &e, bool clip=false);
void sendStreamError(int cond, const QString &text="", const QDomElement &appSpec=QDomElement());
void sendStreamError(const QString &text); // old-style
bool errorAndClose(int cond, const QString &text="", const QDomElement &appSpec=QDomElement());
bool error(int code);
void delayErrorAndClose(int cond, const QString &text="", const QDomElement &appSpec=QDomElement());
void delayError(int code);
// reimplemented
QDomElement docElement();
void handleDocOpen(const Parser::Event &pe);
bool handleError();
bool handleCloseFinished();
bool doStep(const QDomElement &e);
void itemWritten(int id, int size);
virtual QString defaultNamespace();
virtual QStringList extraNamespaces(); // stringlist: prefix,uri,prefix,uri, [...]
virtual void handleStreamOpen(const Parser::Event &pe);
virtual bool doStep2(const QDomElement &e)=0;
void setReady(bool b);
QString sasl_mech;
QStringList sasl_mechlist;
QByteArray sasl_step;
bool sasl_authed;
QDomElement stanzaToRecv;
private:
struct SASLCondEntry
{
const char *str;
int cond;
};
static SASLCondEntry saslCondTable[];
struct StreamCondEntry
{
const char *str;
int cond;
};
static StreamCondEntry streamCondTable[];
struct SendItem
{
QDomElement stanzaToSend;
QString stringToSend;
bool doWhitespace;
};
QList<SendItem> sendList;
bool doShutdown, delayedError, closeError, ready;
int stanzasPending, stanzasWritten;
void init();
void extractStreamError(const QDomElement &e);
};
class CoreProtocol : public BasicProtocol
{
public:
enum {
NPassword = NCustom, // need password for old-mode
EDBVerify = ECustom, // breakpoint after db:verify request
ErrPlain = ErrCustom // server only supports plain, but allowPlain is false locally
};
CoreProtocol();
~CoreProtocol();
void reset();
void startClientOut(const Jid &jid, bool oldOnly, bool tlsActive, bool doAuth, bool doCompression);
void startServerOut(const QString &to);
void startDialbackOut(const QString &to, const QString &from);
void startDialbackVerifyOut(const QString &to, const QString &from, const QString &id, const QString &key);
void startClientIn(const QString &id);
void startServerIn(const QString &id);
void setLang(const QString &s);
void setAllowTLS(bool b);
void setAllowBind(bool b);
void setAllowPlain(bool b); // old-mode
const Jid& jid() const;
void setPassword(const QString &s);
void setFrom(const QString &s);
void setDialbackKey(const QString &s);
// input
QString user, host;
// status
bool old;
StreamFeatures features;
//static QString xmlToString(const QDomElement &e, bool clip=false);
class DBItem
{
public:
enum { ResultRequest, ResultGrant, VerifyRequest, VerifyGrant, Validated };
int type;
Jid to, from;
QString key, id;
bool ok;
};
private:
enum Step {
Start,
Done,
SendFeatures,
GetRequest,
HandleTLS,
GetSASLResponse,
IncHandleSASLSuccess,
GetFeatures, // read features packet
HandleFeatures, // act on features, by initiating tls, sasl, or bind
GetTLSProceed, // read <proceed/> tls response
GetCompressProceed, // read <compressed/> compression response
GetSASLFirst, // perform sasl first step using provided data
GetSASLChallenge, // read server sasl challenge
GetSASLNext, // perform sasl next step using provided data
HandleSASLSuccess, // handle what must be done after reporting sasl success
GetBindResponse, // read bind response
HandleAuthGet, // send old-protocol auth-get
GetAuthGetResponse, // read auth-get response
HandleAuthSet, // send old-protocol auth-set
GetAuthSetResponse // read auth-set response
};
QList<DBItem> dbrequests, dbpending, dbvalidated;
bool server, dialback, dialback_verify;
int step;
bool digest;
bool tls_started, sasl_started, compress_started;
Jid jid_;
bool oldOnly;
bool allowPlain;
bool doTLS, doAuth, doBinding, doCompress;
QString password;
QString dialback_id, dialback_key;
QString self_from;
void init();
static int getOldErrorCode(const QDomElement &e);
bool loginComplete();
bool isValidStanza(const QDomElement &e) const;
bool grabPendingItem(const Jid &to, const Jid &from, int type, DBItem *item);
bool normalStep(const QDomElement &e);
bool dialbackStep(const QDomElement &e);
// reimplemented
bool stepAdvancesParser() const;
bool stepRequiresElement() const;
void stringSend(const QString &s);
void stringRecv(const QString &s);
QString defaultNamespace();
QStringList extraNamespaces();
void handleStreamOpen(const Parser::Event &pe);
bool doStep2(const QDomElement &e);
void elementSend(const QDomElement &e);
void elementRecv(const QDomElement &e);
};
}
#endif