mirror of https://notabug.org/acetone/ircabot.git
427 lines
22 KiB
C++
427 lines
22 KiB
C++
//This program 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 3 of the License, or
|
|
//(at your option) any later version.
|
|
|
|
//This program 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.
|
|
|
|
// Copyright (c) Petr Bena 2015 - 2019
|
|
|
|
#ifndef NETWORK_H
|
|
#define NETWORK_H
|
|
|
|
#include "../libirc/network_core.h"
|
|
#include "priority.h"
|
|
#include "user.h"
|
|
#include "mode.h"
|
|
#include <QList>
|
|
#include <QString>
|
|
#include <QDateTime>
|
|
#include <QSslSocket>
|
|
#include <QThread>
|
|
#include <QAbstractSocket>
|
|
#include <QTcpSocket>
|
|
#include <QTimer>
|
|
#include "../libirc/irc_standards.h"
|
|
|
|
class QTcpSocket;
|
|
|
|
#ifndef ETIMEDOUT
|
|
#define ETIMEDOUT 10
|
|
#endif
|
|
#define EHANDSHAKE 20
|
|
#define EDISCONNECTED 30
|
|
|
|
namespace libirc
|
|
{
|
|
class ServerAddress;
|
|
}
|
|
|
|
namespace libircclient
|
|
{
|
|
enum Encoding
|
|
{
|
|
// Default by Qt
|
|
EncodingDefault = 0,
|
|
EncodingASCII = 1,
|
|
EncodingUTF8 = 2,
|
|
EncodingUTF16 = 3,
|
|
//EncodingUTF32 = 4,
|
|
EncodingLatin = 5
|
|
};
|
|
|
|
class Server;
|
|
class Channel;
|
|
class Parser;
|
|
|
|
class Network : public libirc::Network
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
friend class Network_SenderThread;
|
|
|
|
Network(libirc::ServerAddress &server, const QString &name, const Encoding &enc = EncodingDefault);
|
|
Network(const QHash<QString, QVariant> &hash);
|
|
~Network() override;
|
|
virtual void Connect();
|
|
virtual void Reconnect();
|
|
virtual void Disconnect(QString reason = "");
|
|
bool IsAway() const;
|
|
virtual bool IsConnected();
|
|
virtual void SetAway(bool away, const QString &message = "");
|
|
//! This function can be used to change the default nickname that will be requested upon connection to server
|
|
//! subsequent calls of this function while on active IRC connection will be ignored.
|
|
virtual void SetDefaultNick(const QString &nick);
|
|
virtual void SetDefaultIdent(const QString &ident);
|
|
virtual void SetDefaultUsername(const QString &realname);
|
|
virtual bool IsSSL();
|
|
virtual QString GetNick();
|
|
virtual QString GetHost();
|
|
virtual QString GetServerVersion();
|
|
virtual int GetTimeout() const;
|
|
unsigned int GetPort();
|
|
virtual QString GetIdent();
|
|
virtual QString GetServerAddress();
|
|
virtual User *GetLocalUserInfo();
|
|
virtual void SetHelpForMode(char mode, const QString &message);
|
|
virtual QString GetHelpForMode(char mode, QString missing);
|
|
virtual Channel *GetChannel(QString channel_name);
|
|
virtual QList<Channel *> GetChannels();
|
|
virtual Encoding GetEncoding();
|
|
virtual void SetPassword(const QString &Password);
|
|
virtual void RequestJoin(const QString &name, Priority priority = Priority_Normal);
|
|
virtual void TransferRaw(QString raw, Priority priority = Priority_Normal);
|
|
virtual int SendMessage(const QString &text, Channel *channel, Priority priority = Priority_Normal);
|
|
virtual int SendMessage(const QString &text, User *user, Priority priority = Priority_Normal);
|
|
virtual int SendMessage(const QString &text, const QString &target, Priority priority = Priority_Normal);
|
|
virtual int SendAction(const QString &text, Channel *channel, Priority priority = Priority_Normal);
|
|
virtual int SendAction(const QString &text, const QString &target, Priority priority = Priority_Normal);
|
|
virtual int SendNotice(const QString &text, User *user, Priority priority = Priority_Normal);
|
|
virtual int SendNotice(const QString &text, Channel *channel, Priority priority = Priority_Normal);
|
|
virtual int SendNotice(const QString &text, const QString &target, Priority priority = Priority_Normal);
|
|
virtual int SendCtcp(const QString &name, const QString &text, const QString &target, Priority priority = Priority_Normal);
|
|
virtual void RequestPart(const QString &channel_name, Priority priority = Priority_Normal);
|
|
virtual void RequestPart(Channel *channel, Priority priority = Priority_Normal);
|
|
virtual void RequestNick(const QString &nick, Priority priority = Priority_Normal);
|
|
virtual void Identify(QString Nickname = "", QString Password = "", Priority priority = Priority_Normal);
|
|
// IRCv3
|
|
virtual bool SupportsIRCv3() const;
|
|
virtual void EnableIRCv3Support();
|
|
virtual void DisableIRCv3Support();
|
|
//! Requests IRCv3 capability, this needs to be called before connection is initiated
|
|
virtual void RequestCapability(const QString &capability);
|
|
//! Remove a capability from list of requested caps, meaning we will not ask for it after connecting to server
|
|
virtual void DisableCapability(const QString &capability);
|
|
//! Returns true in case this capability is on a list of caps we want to enabled after connection to network
|
|
virtual bool CapabilityRequested(const QString &capability);
|
|
virtual bool CapabilityEnabled(const QString &capability);
|
|
//! Works only after connection is established - will return true in case network supports this capability
|
|
virtual bool CapabilitySupported(const QString &capability);
|
|
virtual QList<QString> GetSupportedCaps();
|
|
virtual QList<QString> GetSubscribedCaps();
|
|
virtual bool ContainsChannel(const QString &channel_name);
|
|
//! Returns a network lag in MS, measured from last PONG response
|
|
virtual long long GetLag();
|
|
virtual long long GetBytesSent();
|
|
virtual long long GetBytesReceived();
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// Synchronization tools
|
|
//! This will update the nick in operating memory, it will not request it from server and may cause troubles
|
|
//! if not properly called. This is only used for resynchronization.
|
|
virtual void _st_SetNick(const QString &nick);
|
|
//! This will delete all internal memory structures related to channels this user is in.
|
|
//! Use only for synchronization purposes, while implementing something like grumpyd
|
|
//! calling this function on live IRC network connection will have unpredictable result
|
|
void _st_ClearChannels();
|
|
/*!
|
|
* \brief InsertChannel Inserts a deep copy of provided channel to local list of channels
|
|
* \param channel Source which is copied, can be safely deleted
|
|
* \return The copy of input object which was inserted to local vector of channels same as result of GetChannel
|
|
*/
|
|
Channel *_st_InsertChannel(libircclient::Channel *channel);
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
/*!
|
|
* \brief StartsWithCUPrefix checks the user name whether it starts with a CUMode prefix (such as @)
|
|
* \param user_name Name of user including the prefix (@channel_op)
|
|
* \return 0 in case there is no prefix, otherwise it returns the respective CUMode (o in case of @)
|
|
*/
|
|
virtual char StartsWithCUPrefix(QString user_name);
|
|
/*!
|
|
* \brief PositionOfChannelPrefix returns a position of UCP or negative number in case it's not in there
|
|
* \param prefix
|
|
* \return
|
|
*/
|
|
virtual int PositionOfUCPrefix(char prefix);
|
|
virtual void SetChannelUserPrefixes(const QList<char> &data);
|
|
virtual void SetCModes(const QList<char> &data);
|
|
virtual QList<char> GetChannelUserPrefixes();
|
|
virtual bool HasCap(const QString &cap);
|
|
virtual QList<char> GetCModes();
|
|
virtual QList<char> GetCPModes();
|
|
virtual void SetCPModes(const QList<char> &data);
|
|
virtual void SetCRModes(const QList<char> &data);
|
|
virtual QList<char> GetCCModes();
|
|
virtual QList<char> GetCRModes();
|
|
virtual QList<char> GetSTATUSMSGModes();
|
|
virtual void SetSTATUSMSGModes(const QList<char> &data);
|
|
virtual void SetCUModes(const QList<char> &data);
|
|
virtual QList<char> GetCUModes();
|
|
virtual void SetCCModes(const QList<char> &data);
|
|
virtual UMode GetLocalUserMode();
|
|
virtual QList<char> ModeHelper_GetSortedChannelPrefixes(const QList<char> &unsorted_list);
|
|
virtual QList<char> ModeHelper_GetSortedCUModes(const QList<char> &unsorted_list);
|
|
QList<char> ParameterModes();
|
|
void LoadHash(const QHash<QString, QVariant> &hash) override;
|
|
QHash<QString, QVariant> ToHash() override;
|
|
//! This will automatically fix your own identification data in case they change
|
|
//! For example if server changes your hostname (cloak) system will recognize
|
|
//! the change and update localUser accordingly.
|
|
//!
|
|
//! There is a small CPU penalty for this, so this feature can be turned off
|
|
//! in case that this information isn't important for you
|
|
bool ResolveOnSelfChanges;
|
|
bool ResolveOnNickConflicts;
|
|
QHash<char, QString> ChannelModeHelp;
|
|
QHash<char, QString> UserModeHelp;
|
|
|
|
signals:
|
|
// Primitives
|
|
void Event_RawOutgoing(QByteArray data);
|
|
void Event_RawIncoming(QByteArray data);
|
|
void Event_Invalid(QByteArray data);
|
|
void Event_ConnectionFailure(QAbstractSocket::SocketError reason);
|
|
void Event_ConnectionError(QString error, int code);
|
|
void Event_Parse(libircclient::Parser *parser);
|
|
void Event_SSLFailure(QList<QSslError> error_l, bool *fail);
|
|
//! Server gave us some unknown command
|
|
void Event_Unknown(libircclient::Parser *parser);
|
|
void Event_Timeout();
|
|
void Event_Connected();
|
|
void Event_Disconnected();
|
|
void Event_Broken(libircclient::Parser *parser, QString reason);
|
|
void Event_NetworkFailure(QString reason, int failure);
|
|
//! Emitted when server sent us IRC_NUMERIC_UNKNOWN
|
|
void Event_NUMERIC_UNKNOWN(libircclient::Parser *parser);
|
|
|
|
// Channel related
|
|
void Event_SelfJoin(libircclient::Channel *chan);
|
|
void Event_Join(libircclient::Parser *parser, libircclient::User *user, libircclient::Channel *chan);
|
|
/*!
|
|
* \brief Event_PerChannelQuit Emitted when a user quit the network for every single channel this user was in
|
|
* so that it's extremely simple to render the information in related scrollbacks
|
|
* \param parser Pointer to parser of IRC raw message
|
|
* \param chan Pointer to channel this user just left
|
|
*/
|
|
void Event_PerChannelQuit(libircclient::Parser *parser, libircclient::Channel *chan);
|
|
void Event_Quit(libircclient::Parser *parser);
|
|
//! Emitted before the channel is removed from memory on part of a channel you were in
|
|
void Event_SelfPart(libircclient::Parser *parser, libircclient::Channel *chan);
|
|
void Event_Part(libircclient::Parser *parser, libircclient::Channel *chan);
|
|
void Event_SelfKick(libircclient::Parser *parser, libircclient::Channel *chan);
|
|
void Event_Kick(libircclient::Parser *parser, libircclient::Channel *chan);
|
|
//! Emitted when someone changes the topic
|
|
void Event_TOPIC(libircclient::Parser *parser, libircclient::Channel * chan, QString old_topic);
|
|
//! Retrieved after channel is joined as part of info
|
|
void Event_TOPICInfo(libircclient::Parser *parser, libircclient::Channel *chan);
|
|
void Event_TOPICWhoTime(libircclient::Parser *parser, libircclient::Channel *chan);
|
|
void Event_ModeInfo(libircclient::Parser *parser, libircclient::Channel *channel);
|
|
//! When user's channel mode was changed, but the changed mode was lower priority than the one which
|
|
//! user already possesed.
|
|
//! This change is very minor and probably doesn't reflect any real change
|
|
|
|
//! Exampe: user who had owner ~ and halfop % (effectively being ~%) had halfop removed
|
|
void Event_ChannelUserSubmodeChanged(libircclient::Parser *parser, libircclient::Channel *channel, libircclient::User *user);
|
|
void Event_ChannelModeChanged(libircclient::Parser *parser, libircclient::Channel *channel);
|
|
void Event_ChannelUserModeChanged(libircclient::Parser *parser, libircclient::Channel *channel, libircclient::User *user);
|
|
void Event_CreationTime(libircclient::Parser *parser);
|
|
void Event_EndOfBans(libircclient::Parser *parser);
|
|
void Event_EndOfExcepts(libircclient::Parser *parser);
|
|
void Event_EndOfInvites(libircclient::Parser *parser);
|
|
void Event_CPMInserted(libircclient::Parser *parser, libircclient::ChannelPMode mode, libircclient::Channel *channel);
|
|
void Event_CPMRemoved(libircclient::Parser *parser, libircclient::ChannelPMode mode, libircclient::Channel *channel);
|
|
void Event_INVITE(libircclient::Parser *parser);
|
|
|
|
// Server related
|
|
void Event_PONG(libircclient::Parser *parser);
|
|
void Event_EndOfNames(libircclient::Parser *parser);
|
|
void Event_ServerMode(libircclient::Parser *parser);
|
|
void Event_MOTDEnd(libircclient::Parser *parser);
|
|
void Event_MOTDBegin(libircclient::Parser *parser);
|
|
void Event_MOTD(libircclient::Parser *parser);
|
|
void Event_Mode(libircclient::Parser *parser);
|
|
void Event_NickCollision(libircclient::Parser *parser);
|
|
void Event_INFO(libircclient::Parser *parser);
|
|
//! IRC_NUMERIC_MYINFO
|
|
void Event_MyInfo(libircclient::Parser *parser);
|
|
void Event_Welcome(libircclient::Parser *parser);
|
|
void Event_ISUPPORT(libircclient::Parser *parser);
|
|
|
|
// Whois
|
|
//! Emitted for all WHOIS events, in case you don't want to attach to individual replies
|
|
void Event_WhoisGeneric(libircclient::Parser *parser);
|
|
void Event_WhoisUser(libircclient::Parser *parser, libircclient::User *user);
|
|
void Event_WhoisOperator(libircclient::Parser *parser);
|
|
void Event_WhoisIdle(libircclient::Parser *parser, unsigned int seconds_idle, QDateTime signon_time);
|
|
void Event_WhoisRegNick(libircclient::Parser *parser);
|
|
void Event_WhoisChannels(libircclient::Parser *parser);
|
|
void Event_WhoisServer(libircclient::Parser *parser);
|
|
void Event_WhoisEnd(libircclient::Parser *parser);
|
|
void Event_WhoisSpecial(libircclient::Parser *parser);
|
|
void Event_WhoisAccount(libircclient::Parser *parser);
|
|
void Event_WhoisSecure(libircclient::Parser *parser);
|
|
void Event_WhoisHost(libircclient::Parser *parser);
|
|
void Event_WhoisModes(libircclient::Parser *parser);
|
|
|
|
// Messaging
|
|
void Event_PRIVMSG(libircclient::Parser *parser);
|
|
void Event_CTCP(libircclient::Parser *parser, QString ctcp, QString parameters);
|
|
void Event_NOTICE(libircclient::Parser *parser);
|
|
|
|
// Users
|
|
void Event_UserAwayStatusChange(libircclient::Parser *parser, libircclient::Channel *channel, libircclient::User *user);
|
|
void Event_NICK(libircclient::Parser *parser, QString old_nick, QString new_nick);
|
|
void Event_SelfNICK(libircclient::Parser *parser, QString old_nick, QString new_nick);
|
|
void Event_WHO(libircclient::Parser *parser, libircclient::Channel *channel, libircclient::User *user);
|
|
void Event_EndOfWHO(libircclient::Parser *parser);
|
|
void Event_PMode(libircclient::Parser *parser, char mode);
|
|
void Event_UnAway(libircclient::Parser *parser);
|
|
void Event_NowAway(libircclient::Parser *parser);
|
|
void Event_AWAY(libircclient::Parser *parser);
|
|
void Event_RplAway(libircclient::Parser *parser);
|
|
void Event_SelfCHGHOST(libircclient::Parser *parser, QString old_host, QString old_ident, QString new_host, QString new_ident);
|
|
void Event_CHGHOST(libircclient::Parser *parser, QString old_host, QString old_ident, QString new_host, QString new_ident);
|
|
|
|
// IRCv3
|
|
void Event_CAP(libircclient::Parser *parser);
|
|
void Event_CAP_ACK(libircclient::Parser *parser);
|
|
void Event_CAP_NAK(libircclient::Parser *parser);
|
|
void Event_CAP_Timeout();
|
|
void Event_CAP_RequestedCapNotSupported(QString name);
|
|
|
|
protected slots:
|
|
virtual void OnSslHandshakeFailure(QList<QSslError> errors);
|
|
virtual void OnError(QAbstractSocket::SocketError er);
|
|
virtual void OnReceive();
|
|
virtual void OnDisconnect();
|
|
virtual void OnConnected();
|
|
virtual void OnSend();
|
|
virtual void OnPing();
|
|
virtual void OnPingSend();
|
|
virtual void OnCapSupportTimeout();
|
|
|
|
protected:
|
|
virtual void OnReceive(const QByteArray &data);
|
|
virtual void closeError(const QString &error, int code);
|
|
bool usingSSL;
|
|
QTcpSocket *socket;
|
|
//! These capabilities will be automatically requested from a server if it supports them
|
|
QList<QString> _capabilitiesRequested;
|
|
QList<QString> _capabilitiesSupported;
|
|
QList<QString> _capabilitiesSubscribed;
|
|
bool _loggedIn;
|
|
int _capGraceTime;
|
|
bool _enableCap;
|
|
QString hostname;
|
|
unsigned int port;
|
|
int pingTimeout;
|
|
int pingRate;
|
|
QString defaultQuit;
|
|
bool autoRejoin;
|
|
bool autoIdentify;
|
|
QString identifyString;
|
|
QString password;
|
|
|
|
private:
|
|
void updateSelfAway(Parser *parser, bool status, const QString &text);
|
|
void processIncomingRawData(QByteArray data);
|
|
void processNamrpl(Parser *parser);
|
|
void process433(Parser *parser);
|
|
void processInfo(Parser *parser);
|
|
void processWho(Parser *parser);
|
|
void processPrivMsg(Parser *parser);
|
|
void processMode(Parser *parser);
|
|
void processMdIn(Parser *parser);
|
|
void processTopic(Parser *parser);
|
|
void processKick(Parser *parser);
|
|
void processTopicWhoTime(Parser *parser);
|
|
void processPMode(Parser *parser, char mode);
|
|
void processMTime(Parser *parser);
|
|
void processJoin(Parser *parser, bool self_command);
|
|
void processNick(Parser *parser, bool self_command);
|
|
void processAway(Parser *parser, bool self_command);
|
|
void processCap(Parser *parser);
|
|
void processWhoisUser(Parser &parser);
|
|
void processWhoisIdle(Parser &parser);
|
|
void processChangeHost(Parser &parser);
|
|
void standardLogin();
|
|
void deleteTimers();
|
|
void initialize();
|
|
void freemm();
|
|
void resetCap();
|
|
void processAutoCap();
|
|
void pseudoSleep(unsigned int msec);
|
|
QByteArray getDataToSend();
|
|
void scheduleDelivery(const QByteArray &data, libircclient::Priority priority);
|
|
void autoJoin();
|
|
|
|
/////////////////////////////////////
|
|
// This probably doesn't need syncing
|
|
unsigned int MSDelayOnEmpty;
|
|
unsigned int MSDelayOnOpen;
|
|
unsigned int MSWait;
|
|
QTimer capTimeout;
|
|
bool capProcessingMultilineLS;
|
|
bool capProcessingChangeRequest;
|
|
bool capAutoRequestFinished;
|
|
bool loggedIn;
|
|
bool scheduling;
|
|
QDateTime senderTime;
|
|
QTimer senderTimer;
|
|
QMutex mutex;
|
|
unsigned long long bytesSent;
|
|
unsigned long long bytesRcvd;
|
|
QList<QByteArray> hprFIFO;
|
|
QList<QByteArray> mprFIFO;
|
|
QList<QByteArray> lprFIFO;
|
|
/////////////////////////////////////
|
|
|
|
//! List of symbols that are used to prefix users
|
|
QList<char> channelUserPrefixes;
|
|
//! Channel modes with no parameters
|
|
QList<char> CModes;
|
|
//! Channel parameter modes (+b, +I)
|
|
QList<char> CPModes;
|
|
//! Channel secret modes (+k)
|
|
QList<char> CRModes;
|
|
//! Channel user modes (+o, +v)
|
|
QList<char> CUModes;
|
|
//! Channel numeric modes (+l)
|
|
QList<char> CCModes;
|
|
//! https://tools.ietf.org/html/draft-hardy-irc-isupport-00#section-4.18
|
|
QList<char> STATUSMSG_Modes;
|
|
QString originalNick;
|
|
UMode localUserMode;
|
|
QString alternateNick;
|
|
int alternateNickNumber;
|
|
QString awayMessage;
|
|
char channelPrefix;
|
|
Server *server;
|
|
QList<User*> users;
|
|
Encoding encoding = EncodingDefault;
|
|
QList<Channel*> channels;
|
|
User localUser;
|
|
QDateTime lastPing;
|
|
QTimer *timerPingTimeout;
|
|
QTimer *timerPingSend;
|
|
//! List of channels to join after connection to network
|
|
QList<QString> channelsToJoin;
|
|
long long lastPingResponseTimeInMs = 0;
|
|
};
|
|
}
|
|
|
|
#endif // NETWORK_H
|