%PDF- %PDF-
| Direktori : /data/old/usr/local/include/znc/ |
| Current File : //data/old/usr/local/include/znc/Client.h |
/*
* Copyright (C) 2004-2018 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ZNC_CLIENT_H
#define ZNC_CLIENT_H
#include <znc/zncconfig.h>
#include <znc/Socket.h>
#include <znc/Utils.h>
#include <znc/Message.h>
#include <znc/main.h>
#include <memory>
#include <functional>
// Forward Declarations
class CZNC;
class CUser;
class CIRCNetwork;
class CIRCSock;
class CClient;
class CMessage;
class CChan;
// !Forward Declarations
class CAuthBase : private CCoreTranslationMixin {
public:
CAuthBase(const CString& sUsername, const CString& sPassword,
CZNCSock* pSock)
: m_sUsername(sUsername), m_sPassword(sPassword), m_pSock(pSock) {}
virtual ~CAuthBase() {}
CAuthBase(const CAuthBase&) = delete;
CAuthBase& operator=(const CAuthBase&) = delete;
virtual void SetLoginInfo(const CString& sUsername,
const CString& sPassword, CZNCSock* pSock) {
m_sUsername = sUsername;
m_sPassword = sPassword;
m_pSock = pSock;
}
void AcceptLogin(CUser& User);
void RefuseLogin(const CString& sReason);
const CString& GetUsername() const { return m_sUsername; }
const CString& GetPassword() const { return m_sPassword; }
Csock* GetSocket() const { return m_pSock; }
CString GetRemoteIP() const;
// Invalidate this CAuthBase instance which means it will no longer use
// m_pSock and AcceptLogin() or RefusedLogin() will have no effect.
virtual void Invalidate();
protected:
virtual void AcceptedLogin(CUser& User) = 0;
virtual void RefusedLogin(const CString& sReason) = 0;
private:
CString m_sUsername;
CString m_sPassword;
CZNCSock* m_pSock;
};
class CClientAuth : public CAuthBase {
public:
CClientAuth(CClient* pClient, const CString& sUsername,
const CString& sPassword);
virtual ~CClientAuth() {}
CClientAuth(const CClientAuth&) = delete;
CClientAuth& operator=(const CClientAuth&) = delete;
void Invalidate() override {
m_pClient = nullptr;
CAuthBase::Invalidate();
}
void AcceptedLogin(CUser& User) override;
void RefusedLogin(const CString& sReason) override;
private:
protected:
CClient* m_pClient;
};
class CClient : public CIRCSocket {
public:
CClient()
: CIRCSocket(),
m_bGotPass(false),
m_bGotNick(false),
m_bGotUser(false),
m_bInCap(false),
m_bCapNotify(false),
m_bAwayNotify(false),
m_bAccountNotify(false),
m_bExtendedJoin(false),
m_bNamesx(false),
m_bUHNames(false),
m_bAway(false),
m_bServerTime(false),
m_bBatch(false),
m_bEchoMessage(false),
m_bSelfMessage(false),
m_bPlaybackActive(false),
m_pUser(nullptr),
m_pNetwork(nullptr),
m_sNick("unknown-nick"),
m_sPass(""),
m_sUser(""),
m_sNetwork(""),
m_sIdentifier(""),
m_spAuth(),
m_ssAcceptedCaps(),
m_ssSupportedTags(),
m_mCoreCaps({
{"multi-prefix",
{false, [this](bool bVal) { m_bNamesx = bVal; }}},
{"userhost-in-names",
{false, [this](bool bVal) { m_bUHNames = bVal; }}},
{"echo-message",
{false, [this](bool bVal) { m_bEchoMessage = bVal; }}},
{"server-time",
{false, [this](bool bVal) {
m_bServerTime = bVal;
SetTagSupport("time", bVal);
}}},
{"batch", {false, [this](bool bVal) {
m_bBatch = bVal;
SetTagSupport("batch", bVal);
}}},
{"cap-notify",
{false, [this](bool bVal) { m_bCapNotify = bVal; }}},
{"away-notify",
{true, [this](bool bVal) { m_bAwayNotify = bVal; }}},
{"account-notify",
{true, [this](bool bVal) { m_bAccountNotify = bVal; }}},
{"extended-join",
{true, [this](bool bVal) { m_bExtendedJoin = bVal; }}},
}) {
EnableReadLine();
// RFC says a line can have 512 chars max, but we are
// a little more gentle ;)
SetMaxBufferThreshold(1024);
// For compatibility with older clients
m_mCoreCaps["znc.in/server-time-iso"] = m_mCoreCaps["server-time"];
m_mCoreCaps["znc.in/batch"] = m_mCoreCaps["batch"];
m_mCoreCaps["znc.in/self-message"] = {
false, [this](bool bVal) { m_bSelfMessage = bVal; }};
}
virtual ~CClient();
CClient(const CClient&) = delete;
CClient& operator=(const CClient&) = delete;
void SendRequiredPasswordNotice();
void AcceptLogin(CUser& User);
void RefuseLogin(const CString& sReason);
CString GetNick(bool bAllowIRCNick = true) const;
CString GetNickMask() const;
CString GetIdentifier() const { return m_sIdentifier; }
bool HasCapNotify() const { return m_bCapNotify; }
bool HasAwayNotify() const { return m_bAwayNotify; }
bool HasAccountNotify() const { return m_bAccountNotify; }
bool HasExtendedJoin() const { return m_bExtendedJoin; }
bool HasNamesx() const { return m_bNamesx; }
bool HasUHNames() const { return m_bUHNames; }
bool IsAway() const { return m_bAway; }
bool HasServerTime() const { return m_bServerTime; }
bool HasBatch() const { return m_bBatch; }
bool HasEchoMessage() const { return m_bEchoMessage; }
bool HasSelfMessage() const { return m_bSelfMessage; }
static bool IsValidIdentifier(const CString& sIdentifier);
void UserCommand(CString& sLine);
void UserPortCommand(CString& sLine);
void StatusCTCP(const CString& sCommand);
void BouncedOff();
bool IsAttached() const { return m_pUser != nullptr; }
bool IsPlaybackActive() const { return m_bPlaybackActive; }
void SetPlaybackActive(bool bActive) { m_bPlaybackActive = bActive; }
void PutIRC(const CString& sLine);
/** Sends a raw data line to the client.
* @param sLine The line to be sent.
*
* The line is first passed \e unmodified to the \ref
* CModule::OnSendToClient() module hook. If no module halts the process,
* the line is then sent to the client.
*
* These lines appear in the debug output in the following syntax:
* \code [time] (user/network) ZNC -> CLI [line] \endcode
*
* Prefer \l PutClient() instead.
*/
bool PutClientRaw(const CString& sLine);
/** Sends a message to the client.
* See \l PutClient(const CMessage&) for details.
*/
void PutClient(const CString& sLine);
/** Sends a message to the client.
* @param Message The message to be sent.
* @note Only known and compatible messages and tags are sent.
* @return \c true if the message was sent, or \c false if it was ignored.
*
* This method ensures that only messages and tags, that the client has
* explicitly requested, are sent. Not all IRC clients are capable of
* handling all messages and tags. For example, some older versions of
* popular clients were prepared to parse just one interesting tag,
* \c time, and would break if multiple tags were included. Furthermore,
* messages that are specific to a certain capability, should not be sent
* to a client that has not requested the respective capability. Thus, in
* order to stay compatible with a variety of IRC clients, ZNC has to
* filter out messages and tags that the client has not explicitly
* requested.
*
* ### Message types
*
* The following table documents which capabilities the client is required
* to have requested in order to receive certain types of messages.
*
* Message type | Capability
* ------------ | ----------
* \c ACCOUNT | \l CClient::HasAccountNotify() (<a href="http://ircv3.net/specs/extensions/account-notify-3.1.html">account-notify</a>)
* \c AWAY | \l CClient::HasAwayNotify() (<a href="http://ircv3.net/specs/extensions/away-notify-3.1.html">away-notify</a>)
*
* ### Message tags
*
* The following table documents currently supported message tags, and
* which capabilities the client is required to have requested to receive
* the respective message tags.
*
* Message tag | Capability
* ----------- | ----------
* \c time | \l CClient::HasServerTime() (<a href="http://ircv3.net/specs/extensions/server-time-3.2.html">server-time</a>)
* \c batch | \l CClient::HasBatch() (<a href="http://ircv3.net/specs/extensions/batch-3.2.html">batch</a>)
*
* Additional tags can be added via \l CClient::SetTagSupport().
*
* @warning Bypassing the filter may cause troubles to some older IRC
* clients.
*
* It is possible to bypass the filter by converting a message to a string
* using \l CMessage::ToString(), and passing the resulting raw line to the
* \l CClient::PutClientRaw(const CString& sLine):
* \code
* pClient->PutClientRaw(Message.ToString());
* \endcode
*/
bool PutClient(const CMessage& Message);
unsigned int PutStatus(const CTable& table);
void PutStatus(const CString& sLine);
void PutStatusNotice(const CString& sLine);
void PutModule(const CString& sModule, const CString& sLine);
void PutModNotice(const CString& sModule, const CString& sLine);
bool IsCapEnabled(const CString& sCap) const {
return 1 == m_ssAcceptedCaps.count(sCap);
}
bool IsTagEnabled(const CString& sTag) const {
return 1 == m_ssSupportedTags.count(sTag);
}
/** Registers a tag as being supported or unsupported by the client.
* This doesn't affect tags which the client sends.
* @param sTag The tag to register.
* @param bState Whether the client supports the tag.
*/
void SetTagSupport(const CString& sTag, bool bState);
void NotifyServerDependentCaps(const SCString& ssCaps);
void ClearServerDependentCaps();
void ReadLine(const CString& sData) override;
bool SendMotd();
void HelpUser(const CString& sFilter = "");
void AuthUser();
void Connected() override;
void Timeout() override;
void Disconnected() override;
void ConnectionRefused() override;
void ReachedMaxBuffer() override;
void SetNick(const CString& s);
void SetAway(bool bAway) { m_bAway = bAway; }
CUser* GetUser() const { return m_pUser; }
void SetNetwork(CIRCNetwork* pNetwork, bool bDisconnect = true,
bool bReconnect = true);
CIRCNetwork* GetNetwork() const { return m_pNetwork; }
const std::vector<CClient*>& GetClients() const;
const CIRCSock* GetIRCSock() const;
CIRCSock* GetIRCSock();
CString GetFullName() const;
private:
void HandleCap(const CMessage& Message);
void RespondCap(const CString& sResponse);
void ParsePass(const CString& sAuthLine);
void ParseUser(const CString& sAuthLine);
void ParseIdentifier(const CString& sAuthLine);
template <typename T>
void AddBuffer(const T& Message);
void EchoMessage(const CMessage& Message);
std::set<CChan*> MatchChans(const CString& sPatterns) const;
unsigned int AttachChans(const std::set<CChan*>& sChans);
unsigned int DetachChans(const std::set<CChan*>& sChans);
bool OnActionMessage(CActionMessage& Message);
bool OnCTCPMessage(CCTCPMessage& Message);
bool OnJoinMessage(CJoinMessage& Message);
bool OnModeMessage(CModeMessage& Message);
bool OnNoticeMessage(CNoticeMessage& Message);
bool OnPartMessage(CPartMessage& Message);
bool OnPingMessage(CMessage& Message);
bool OnPongMessage(CMessage& Message);
bool OnQuitMessage(CQuitMessage& Message);
bool OnTextMessage(CTextMessage& Message);
bool OnTopicMessage(CTopicMessage& Message);
bool OnOtherMessage(CMessage& Message);
protected:
bool m_bGotPass;
bool m_bGotNick;
bool m_bGotUser;
bool m_bInCap;
bool m_bCapNotify;
bool m_bAwayNotify;
bool m_bAccountNotify;
bool m_bExtendedJoin;
bool m_bNamesx;
bool m_bUHNames;
bool m_bAway;
bool m_bServerTime;
bool m_bBatch;
bool m_bEchoMessage;
bool m_bSelfMessage;
bool m_bPlaybackActive;
CUser* m_pUser;
CIRCNetwork* m_pNetwork;
CString m_sNick;
CString m_sPass;
CString m_sUser;
CString m_sNetwork;
CString m_sIdentifier;
std::shared_ptr<CAuthBase> m_spAuth;
SCString m_ssAcceptedCaps;
SCString m_ssSupportedTags;
// The capabilities supported by the ZNC core - capability names mapped
// to a pair which contains a bool describing whether the capability is
// server-dependent, and a capability value change handler.
std::map<CString, std::pair<bool, std::function<void(bool bVal)>>>
m_mCoreCaps;
// A subset of CIRCSock::GetAcceptedCaps(), the caps that can be listed
// in CAP LS and may be notified to the client with CAP NEW (cap-notify).
SCString m_ssServerDependentCaps;
friend class ClientTest;
};
#endif // !ZNC_CLIENT_H