From a7ac6a0ac712892652da6dd8696b94d4c6d3ea84 Mon Sep 17 00:00:00 2001 From: Adam- Date: Sun, 13 Dec 2009 19:32:19 +0000 Subject: Added in a modestacker and rewrote almost all of the remaining old mode code git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2696 5417fbe8-f217-4b02-8779-1006273d7864 --- include/extern.h | 8 +- include/modes.h | 508 +++++++++++++++++++++++++ include/services.h | 442 ++++------------------ include/users.h | 72 ++-- src/actions.c | 61 +-- src/botserv.c | 99 +---- src/channels.c | 882 +++++++++++++++++++++++--------------------- src/chanserv.c | 240 ++++-------- src/core/cs_ban.c | 6 +- src/core/cs_clear.c | 151 ++------ src/core/cs_drop.c | 3 +- src/core/cs_modes.c | 14 +- src/core/cs_register.c | 6 +- src/core/cs_set.c | 6 +- src/core/ns_logout.c | 4 +- src/core/os_clearmodes.c | 100 +++-- src/core/os_defcon.c | 30 +- src/core/os_mode.c | 8 +- src/core/os_oline.c | 2 +- src/core/os_umode.c | 4 +- src/main.c | 3 + src/modes.cpp | 610 ++++++++++++++++++++++++------ src/modules/cs_enforce.c | 10 +- src/modules/cs_tban.c | 19 +- src/nickalias.cpp | 6 +- src/nickcore.cpp | 1 + src/protocol.cpp | 10 + src/protocol/bahamut.c | 66 +--- src/protocol/inspircd11.c | 74 +--- src/protocol/inspircd12.cpp | 85 +---- src/protocol/ratbox.c | 46 +-- src/protocol/unreal32.c | 118 ++---- src/regchannel.cpp | 2 +- src/users.c | 217 ++++++++++- 34 files changed, 2081 insertions(+), 1832 deletions(-) create mode 100644 include/modes.h diff --git a/include/extern.h b/include/extern.h index c02ef22e2..7cc3f3050 100644 --- a/include/extern.h +++ b/include/extern.h @@ -39,7 +39,6 @@ E void kill_user(const char *source, const char *user, const char *reason); E void bad_password(User * u); E void sqline(char *mask, char *reason); E void common_unban(ChannelInfo * ci, char *nick); -E void common_svsmode(User * u, const char *modes, const char *arg); /**** botserv.c ****/ @@ -79,14 +78,14 @@ E Channel *findchan(const char *chan); E Channel *firstchan(); E Channel *nextchan(); +E void ChanSetInternalModes(Channel *c, int ac, const char **av); + E void chan_deluser(User * user, Channel * c); E int is_on_chan(Channel * c, User * u); E User *nc_on_chan(Channel * c, NickCore * nc); E char *chan_get_modes(Channel * chan, int complete, int plus); -E void chan_set_modes(const char *source, Channel * chan, int ac, - const char **av, int check); E int chan_get_user_status(Channel * chan, User * user); E int chan_has_user_status(Channel * chan, User * user, int16 status); @@ -102,7 +101,7 @@ E void do_kick(const char *source, int ac, const char **av); E void do_part(const char *source, int ac, const char **av); E void do_sjoin(const char *source, int ac, const char **av); E void do_topic(const char *source, int ac, const char **av); -E void do_mass_mode(char *modes); +E void MassChannelModes(BotInfo *bi, const std::string &modes); E void chan_set_correct_modes(User * user, Channel * c, int give_modes); E void restore_unsynced_topics(); @@ -640,6 +639,7 @@ E int is_excepted_mask(ChannelInfo * ci, const char *mask); E int match_usermask(const char *mask, User * user); E char *create_mask(User * u); +E void UserSetInternalModes(User *user, int ac, const char **av); /******************************************************************************/ diff --git a/include/modes.h b/include/modes.h new file mode 100644 index 000000000..34e3ce463 --- /dev/null +++ b/include/modes.h @@ -0,0 +1,508 @@ +/* Mode support + * + * Copyright (C) 2008-2009 Adam + * Copyright (C) 2008-2009 Anope Team + * + * Please read COPYING and README for further details. + * + * + * $Id$ + * + */ + +/** All of the valid user mode names + */ +enum UserModeName +{ + UMODE_BEGIN, + + UMODE_SERV_ADMIN, UMODE_BOT, UMODE_CO_ADMIN, UMODE_FILTER, UMODE_HIDEOPER, UMODE_NETADMIN, + UMODE_REGPRIV, UMODE_PROTECTED, UMODE_NO_CTCP, UMODE_WEBTV, UMODE_WHOIS, UMODE_ADMIN, UMODE_DEAF, + UMODE_GLOBOPS, UMODE_HELPOP, UMODE_INVIS, UMODE_OPER, UMODE_PRIV, UMODE_GOD, UMODE_REGISTERED, + UMODE_SNOMASK, UMODE_VHOST, UMODE_WALLOPS, UMODE_CLOAK, UMODE_SSL, UMODE_CALLERID, UMODE_COMMONCHANS, + UMODE_HIDDEN, UMODE_STRIPCOLOR, + + UMODE_END +}; + +/** All of the valid channel mode names + */ +enum ChannelModeName +{ + CMODE_BEGIN, + + /* Channel modes */ + CMODE_BLOCKCOLOR, CMODE_FLOOD, CMODE_INVITE, CMODE_KEY, CMODE_LIMIT, CMODE_MODERATED, CMODE_NOEXTERNAL, + CMODE_PRIVATE, CMODE_REGISTERED, CMODE_SECRET, CMODE_TOPIC, CMODE_AUDITORIUM, CMODE_SSL, CMODE_ADMINONLY, + CMODE_NOCTCP, CMODE_FILTER, CMODE_NOKNOCK, CMODE_REDIRECT, CMODE_REGMODERATED, CMODE_NONICK, CMODE_OPERONLY, + CMODE_NOKICK, CMODE_REGISTEREDONLY, CMODE_STRIPCOLOR, CMODE_NONOTICE, CMODE_NOINVITE, CMODE_ALLINVITE, + CMODE_BLOCKCAPS, CMODE_PERM, CMODE_NICKFLOOD, CMODE_JOINFLOOD, + + /* b/e/I */ + CMODE_BAN, CMODE_EXCEPT, + CMODE_INVITEOVERRIDE, + + /* v/h/o/a/q */ + CMODE_VOICE, CMODE_HALFOP, CMODE_OP, + CMODE_PROTECT, CMODE_OWNER, + + CMODE_END +}; + +/** The different types of modes +*/ +enum ModeType +{ + /* Regular mode */ + MODE_REGULAR, + /* b/e/I */ + MODE_LIST, + /* k/l etc */ + MODE_PARAM, + /* v/h/o/a/q */ + MODE_STATUS +}; + + +/** This class is a user mode, all user modes use this/inherit from this + */ +class UserMode +{ + public: + + /* Mode name */ + UserModeName Name; + /* The mode char */ + char ModeChar; + /* Mode type, regular or param */ + ModeType Type; + + /** Default constructor + * @param nName The mode name + */ + UserMode(UserModeName mName); + + /** Default destructor + */ + virtual ~UserMode(); +}; + +class UserModeParam : public UserMode +{ + public: + /** Default constructor + * @param mName The mode name + */ + UserModeParam(UserModeName mName); + + /** Check if the param is valid + * @param value The param + * @return true or false + */ + virtual bool IsValid(const char *value) { return true; } +}; + +/** This class is a channel mode, all channel modes use this/inherit from this + */ +class CoreExport ChannelMode +{ + public: + + /* Mode name */ + ChannelModeName Name; + /* Type of mode this is */ + ModeType Type; + /* The mode char */ + char ModeChar; + + /** Default constructor + * @param mName The mode name + */ + ChannelMode(ChannelModeName mName); + + /** Default destructor + */ + virtual ~ChannelMode(); + + /** Can a user set this mode, used for mlock + * NOTE: User CAN be NULL, this is for checking if it can be locked with defcon + * @param u The user, or NULL + */ + virtual bool CanSet(User *u) { return true; } +}; + + +/** This is a mode for lists, eg b/e/I. These modes should inherit from this + */ +class CoreExport ChannelModeList : public ChannelMode +{ + public: + + /** Default constructor + * @param mName The mode name + */ + ChannelModeList(ChannelModeName mName); + + /** Default destructor + */ + virtual ~ChannelModeList(); + + /** Is the mask valid + * @param mask The mask + * @return true for yes, false for no + */ + virtual bool IsValid(const char *mask) { return true; } + + /** Add the mask to the channel, this should be overridden + * @param chan The channel + * @param mask The mask + */ + virtual void AddMask(Channel *chan, const char *mask) { } + + /** Delete the mask from the channel, this should be overridden + * @param chan The channel + * @param mask The mask + */ + virtual void DelMask(Channel *chan, const char *mask) { } + +}; + +/** This is a mode with a paramater, eg +k/l. These modes should use/inherit from this +*/ +class CoreExport ChannelModeParam : public ChannelMode +{ + public: + + /** Default constructor + * @param mName The mode name + * @param MinusArg true if this mode sends no arg when unsetting + */ + ChannelModeParam(ChannelModeName mName, bool MinusArg = false); + + /** Default destructor + */ + virtual ~ChannelModeParam(); + + /* Should we send an arg when unsetting this mode? */ + bool MinusNoArg; + + /** Is the param valid + * @param value The param + * @return true for yes, false for no + */ + virtual bool IsValid(const char *value) { return true; } +}; + +/** This is a mode that is a channel status, eg +v/h/o/a/q. +*/ +class CoreExport ChannelModeStatus : public ChannelMode +{ + public: + /** CUS_ values, see below + */ + int16 Status; + /* The symbol, eg @ % + */ + char Symbol; + + /** Default constructor + * @param mName The mode name + * @param mStatus A CUS_ value + * @param mSymbol The symbol for the mode, eg @ % + + * @param mProtectBotServ Should botserv clients reset this on themself if it gets unset? + */ + ChannelModeStatus(ChannelModeName mName, int16 mStatus, char mSymbol, bool mProtectBotServ = false); + + /** Default destructor + */ + virtual ~ChannelModeStatus(); + + /* Should botserv protect itself with this mode? eg if someone -o's botserv it will +o */ + bool ProtectBotServ; +}; + +/** Channel mode +b + */ +class CoreExport ChannelModeBan : public ChannelModeList +{ + public: + ChannelModeBan() : ChannelModeList(CMODE_BAN) { } + + void AddMask(Channel *chan, const char *mask); + + void DelMask(Channel *chan, const char *mask); +}; + +/** Channel mode +e + */ +class CoreExport ChannelModeExcept : public ChannelModeList +{ + public: + ChannelModeExcept() : ChannelModeList(CMODE_EXCEPT) { } + + void AddMask(Channel *chan, const char *mask); + + void DelMask(Channel *chan, const char *mask); +}; + +/** Channel mode +I + */ +class CoreExport ChannelModeInvite : public ChannelModeList +{ + public: + ChannelModeInvite() : ChannelModeList(CMODE_INVITEOVERRIDE) { } + + void AddMask(Channel *chan, const char *mask); + + void DelMask(Channel *chan, const char *mask); +}; + + +/** Channel mode +k (key) + */ +class CoreExport ChannelModeKey : public ChannelModeParam +{ + public: + ChannelModeKey() : ChannelModeParam(CMODE_KEY) { } + + bool IsValid(const char *value); +}; + +/** Channel mode +f (flood) + */ +class ChannelModeFlood : public ChannelModeParam +{ + public: + ChannelModeFlood() : ChannelModeParam(CMODE_FLOOD) { } + + bool IsValid(const char *value); +}; + +/** This class is used for channel mode +A (Admin only) + * Only opers can mlock it + */ +class CoreExport ChannelModeAdmin : public ChannelMode +{ + public: + ChannelModeAdmin() : ChannelMode(CMODE_ADMINONLY) { } + + /* Opers only */ + bool CanSet(User *u); +}; + +/** This class is used for channel mode +O (Opers only) + * Only opers can mlock it + */ +class CoreExport ChannelModeOper : public ChannelMode +{ + public: + ChannelModeOper() : ChannelMode(CMODE_OPERONLY) { } + + /* Opers only */ + bool CanSet(User *u); +}; + +/** This class is used for channel mode +r (registered channel) + * No one may mlock r + */ +class CoreExport ChannelModeRegistered : public ChannelMode +{ + public: + ChannelModeRegistered() : ChannelMode(CMODE_REGISTERED) { } + + /* No one mlocks +r */ + bool CanSet(User *u); +}; + +enum StackerType +{ + ST_CHANNEL, + ST_USER +}; + +class StackerInfo +{ + public: + /* Modes to be added */ + std::list > AddModes; + /* Modes to be deleted */ + std::list > DelModes; + /* The type of object this stacker info is for */ + StackerType Type; + /* Bot this is sent from */ + BotInfo *bi; + + /** Add a mode to this object + * @param Mode The mode + * @param Set true if setting, false if unsetting + * @param Param The param for the mode + */ + void AddMode(void *Mode, bool Set, const std::string &Param); +}; + +/** This is mode manager + * It contains functions for adding modes to Anope so Anope can track them + * and do things such as MLOCK. + * This also contains a mode stacker that will combine multiple modes and set + * them on a channel all at once + */ +class CoreExport ModeManager +{ + protected: + /* List of pairs of user/channels and their stacker info */ + static std::list > StackerObjects; + + /** Get the stacker info for an item, if one doesnt exist it is created + * @param Item The user/channel etc + * @return The stacker info + */ + static StackerInfo *GetInfo(void *Item); + + /** Build a list of mode strings to send to the IRCd from the mode stacker + * @param info The stacker info for a channel or user + * @return a list of strings + */ + static std::list BuildModeStrings(StackerInfo *info); + + /** Add a mode to the stacker, internal use only + * @param bi The client to set the modes from + * @param u The user + * @param um The user mode + * @param Set Adding or removing? + * @param Param A param, if there is one + */ + static void StackerAddInternal(BotInfo *bi, User *u, UserMode *um, bool Set, const std::string &Param); + + /** Add a mode to the stacker, internal use only + * @param bi The client to set the modes from + * @param c The channel + * @param cm The channel mode + * @param Set Adding or removing? + * @param Param A param, if there is one + */ + static void StackerAddInternal(BotInfo *bi, Channel *c, ChannelMode *cm, bool Set, const std::string &Param); + + /** Really add a mode to the stacker, internal use only + * @param bi The client to set the modes from + * @param Object The object, user/channel + * @param Mode The mode + * @param Set Adding or removing? + * @param Param A param, if there is one + * @param Type The type this is, user or channel + */ + static void StackerAddInternal(BotInfo *bi, void *Object, void *Mode, bool Set, const std::string &Param, StackerType Type); + + public: + /* User modes */ + static std::map UserModesByChar; + static std::map UserModesByName; + /* Channel modes */ + static std::map ChannelModesByChar; + static std::map ChannelModesByName; + /* Although there are two different maps for UserModes and ChannelModes + * the pointers in each are the same. This is used to increase + * efficiency. + */ + + /** Add a user mode to Anope + * @param Mode The mode + * @param um A UserMode or UserMode derived class + * @return true on success, false on error + */ + static bool AddUserMode(char Mode, UserMode *um); + + /** Add a channel mode to Anope + * @param Mode The mode + * @param cm A ChannelMode or ChannelMode derived class + * @return true on success, false on error + */ + static bool AddChannelMode(char Mode, ChannelMode *cm); + + /** Find a channel mode + * @param Mode The mode + * @return The mode class + */ + static ChannelMode *FindChannelModeByChar(char Mode); + + /** Find a user mode + * @param Mode The mode + * @return The mode class + */ + static UserMode *FindUserModeByChar(char Mode); + + /** Find a channel mode + * @param Mode The modename + * @return The mode class + */ + static ChannelMode *FindChannelModeByName(ChannelModeName Name); + + /** Find a user mode + * @param Mode The modename + * @return The mode class + */ + static UserMode *FindUserModeByName(UserModeName Name); + + /** Gets the channel mode char for a symbol (eg + returns v) + * @param Value The symbol + * @return The char + */ + static char GetStatusChar(char Value); + + /** Add a mode to the stacker to be set on a channel + * @param bi The client to set the modes from + * @param c The channel + * @param cm The channel mode + * @param Set true for setting, false for removing + * @param Param The param, if there is one + */ + static void StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool Set, const std::string &Param = ""); + + /** Add a mode to the stacker to be set on a channel + * @param bi The client to set the modes from + * @param c The channel + * @param Name The channel mode name + * @param Set true for setting, false for removing + * @param Param The param, if there is one + */ + static void StackerAdd(BotInfo *bi, Channel *c, ChannelModeName Name, bool Set, const std::string &Param = ""); + + /** Add a mode to the stacker to be set on a channel + * @param bi The client to set the modes from + * @param c The channel + * @param Mode The mode char + * @param Set true for setting, false for removing + * @param Param The param, if there is one + */ + static void StackerAdd(BotInfo *bi, Channel *c, const char Mode, bool Set, const std::string &Param = ""); + + /** Add a mode to the stacker to be set on a user + * @param bi The client to set the modes from + * @param u The user + * @param um The user mode + * @param Set true for setting, false for removing + * @param param The param, if there is one + */ + static void StackerAdd(BotInfo *bi, User *u, UserMode *um, bool Set, const std::string &Param = ""); + + /** Add a mode to the stacker to be set on a user + * @param bi The client to set the modes from + * @param u The user + * @param Name The user mode name + * @param Set true for setting, false for removing + * @param Param The param, if there is one + */ + static void StackerAdd(BotInfo *bi, User *u, UserModeName Name, bool Set, const std::string &Param = ""); + + /** Add a mode to the stacker to be set on a user + * @param bi The client to set the modes from + * @param u The user + * @param Mode The mode to be set + * @param Set true for setting, false for removing + * @param Param The param, if there is one + */ + static void StackerAdd(BotInfo *bi, User *u, const char Mode, bool Set, const std::string &Param = ""); + + /** Process all of the modes in the stacker and send them to the IRCd to be set on channels/users + */ + static void ProcessModes(); +}; + diff --git a/include/services.h b/include/services.h index 30bd0e34b..190529987 100644 --- a/include/services.h +++ b/include/services.h @@ -485,44 +485,9 @@ typedef struct hostcore_ HostCore; typedef struct exception_ Exception; typedef struct session_ Session; -enum UserModeName -{ - UMODE_BEGIN, - - /* Usermodes */ - UMODE_SERV_ADMIN, UMODE_BOT, UMODE_CO_ADMIN, UMODE_FILTER, UMODE_HIDEOPER, UMODE_NETADMIN, - UMODE_REGPRIV, UMODE_PROTECTED, UMODE_NO_CTCP, UMODE_WEBTV, UMODE_WHOIS, UMODE_ADMIN, UMODE_DEAF, - UMODE_GLOBOPS, UMODE_HELPOP, UMODE_INVIS, UMODE_OPER, UMODE_PRIV, UMODE_GOD, UMODE_REGISTERED, - UMODE_SNOMASK, UMODE_VHOST, UMODE_WALLOPS, UMODE_CLOAK, UMODE_SSL, UMODE_CALLERID, UMODE_COMMONCHANS, - UMODE_HIDDEN, UMODE_STRIPCOLOR, - - UMODE_END -}; - -enum ChannelModeName -{ - CMODE_BEGIN, - - /* Channel modes */ - CMODE_BLOCKCOLOR, CMODE_FLOOD, CMODE_INVITE, CMODE_KEY, CMODE_LIMIT, CMODE_MODERATED, CMODE_NOEXTERNAL, - CMODE_PRIVATE, CMODE_REGISTERED, CMODE_SECRET, CMODE_TOPIC, CMODE_AUDITORIUM, CMODE_SSL, CMODE_ADMINONLY, - CMODE_NOCTCP, CMODE_FILTER, CMODE_NOKNOCK, CMODE_REDIRECT, CMODE_REGMODERATED, CMODE_NONICK, CMODE_OPERONLY, - CMODE_NOKICK, CMODE_REGISTEREDONLY, CMODE_STRIPCOLOR, CMODE_NONOTICE, CMODE_NOINVITE, CMODE_ALLINVITE, - CMODE_BLOCKCAPS, CMODE_PERM, CMODE_NICKFLOOD, CMODE_JOINFLOOD, - - /* b/e/I */ - CMODE_BAN, CMODE_EXCEPT, - CMODE_INVITEOVERRIDE, - - /* v/h/o/a/q */ - CMODE_VOICE, CMODE_HALFOP, CMODE_OP, - CMODE_PROTECT, CMODE_OWNER, - - CMODE_END -}; - #include "bots.h" #include "opertype.h" +#include "modes.h" /*************************************************************************/ @@ -538,7 +503,6 @@ struct ircdvars_ { const char *botchanumode; /* Modes set when botserv joins a channel */ int svsnick; /* Supports SVSNICK */ int vhost; /* Supports vhost */ - const char *modeonunreg; /* Mode on Unregister */ int sgline; /* Supports SGline */ int sqline; /* Supports SQline */ int szline; /* Supports SZline */ @@ -985,51 +949,91 @@ class CoreExport Channel : public Extensible */ bool HasMode(ChannelModeName Name); + /** Set a mode internally on a channel, this is not sent out to the IRCd + * @param cm The mode + * @param param The param + * @param EnforceMLock true if mlocks should be enforced, false to override mlock + */ + void SetModeInternal(ChannelMode *cm, const std::string ¶m = "", bool EnforceMLock = true); + + /** Remove a mode internally on a channel, this is not sent out to the IRCd + * @param cm The mode + * @param param The param + * @param EnforceMLock true if mlocks should be enforced, false to override mlock + */ + void RemoveModeInternal(ChannelMode *cm, const std::string ¶m = "", bool EnforceMLock = true); + + /** Set a mode on a channel + * @param bi The client setting the modes + * @param cm The mode + * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock + */ + void SetMode(BotInfo *bi, ChannelMode *cm, const std::string ¶m = "", bool EnforceMLock = true); + /** * Set a mode on a channel + * @param bi The client setting the modes * @param Name The mode name * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock */ - void SetMode(ChannelModeName Name, const std::string param = ""); + void SetMode(BotInfo *bi, ChannelModeName Name, const std::string ¶m = "", bool EnforceMLock = true); /** * Set a mode on a channel + * @param bi The client setting the modes * @param Mode The mode * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock + */ + void SetMode(BotInfo *bi, char Mode, const std::string ¶m = "", bool EnforceMLock = true); + + /** Remove a mode from a channel + * @param bi The client setting the modes + * @param cm The mode + * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock */ - void SetMode(char Mode, const std::string param = ""); + void RemoveMode(BotInfo *bi, ChannelMode *cm, const std::string ¶m = "", bool EnforceMLock = true); /** * Remove a mode from a channel + * @param bi The client setting the modes * @param Name The mode name + * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock */ - void RemoveMode(ChannelModeName Name); + void RemoveMode(BotInfo *bi, ChannelModeName Name, const std::string ¶m = "", bool EnforceMLock = true); /** * Remove a mode from a channel + * @param bi The client setting the modes * @param Mode The mode + * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock */ - void RemoveMode(char Mode); + void RemoveMode(BotInfo *bi, char Mode, const std::string ¶m = "", bool EnforceMLock = true); /** Clear all the modes from the channel - * @param client The client unsetting the modes + * @param bi The client unsetting the modes */ - void ClearModes(char *client = NULL); + void ClearModes(BotInfo *bi = NULL); /** Clear all the bans from the channel - * @param client The client unsetting the modes + * @param bi The client unsetting the modes */ - void ClearBans(char *client = NULL); + void ClearBans(BotInfo *bi = NULL); /** Clear all the excepts from the channel - * @param client The client unsetting the modes + * @param bi The client unsetting the modes */ - void ClearExcepts(char *client = NULL); + void ClearExcepts(BotInfo *bi = NULL); /** Clear all the invites from the channel - * @param client The client unsetting the modes + * @param bi The client unsetting the modes */ - void ClearInvites(char *client = NULL); + void ClearInvites(BotInfo *bi = NULL); /** Get a param from the channel * @param Name The mode @@ -1042,6 +1046,13 @@ class CoreExport Channel : public Extensible * @param Name The mode */ const bool HasParam(ChannelModeName Name); + + /** Set a string of modes on the channel + * @param bi The client setting the modes + * @param EnforceMLock Should mlock be enforced on this mode change + * @param cmodes The modes to set + */ + void SetModes(BotInfo *bi, bool EnforceMLock, const std::string &cmodes, ...); }; /** Channelban type flags @@ -1178,335 +1189,6 @@ struct exception_ { * calculated at load time and never saved. */ }; -/*************************************************************************/ - -/** The different types of modes -*/ -enum ModeType -{ - /* Regular mode */ - MODE_REGULAR, - /* b/e/I */ - MODE_LIST, - /* k/l etc */ - MODE_PARAM, - /* v/h/o/a/q */ - MODE_STATUS -}; - -/** This class is a user mode, all user modes use this/inherit from this - */ -class UserMode -{ - public: - - /* Mode name */ - UserModeName Name; - /* The mode char */ - char ModeChar; - - /** Default constructor - * @param nName The mode name - */ - UserMode(UserModeName mName) - { - this->Name = mName; - } - - /** Default destructor - */ - virtual ~UserMode() { } -}; - -/** This class is a channel mode, all channel modes use this/inherit from this - */ -class CoreExport ChannelMode -{ - public: - - /* Mode name */ - ChannelModeName Name; - /* Type of mode this is */ - ModeType Type; - /* The mode char */ - char ModeChar; - - /** Default constructor - * @param mName The mode name - */ - ChannelMode(ChannelModeName mName) - { - this->Name = mName; - this->Type = MODE_REGULAR; - } - - /** Default destructor - */ - virtual ~ChannelMode() { } - - /** Can a user set this mode, used for mlock - * NOTE: User CAN be NULL, this is for checking if it can be locked with defcon - * @param u The user, or NULL - */ - virtual bool CanSet(User *u) { return true; } -}; - -/** This is a mode for lists, eg b/e/I. These modes should inherit from this - */ -class CoreExport ChannelModeList : public ChannelMode -{ - public: - - /** Default constructor - * @param mName The mode name - */ - ChannelModeList(ChannelModeName mName) : ChannelMode(mName) - { - this->Type = MODE_LIST; - } - - /** Default destructor - */ - virtual ~ChannelModeList() { } - - /** Is the mask valid - * @param mask The mask - * @return true for yes, false for no - */ - virtual bool IsValid(const char *mask) { return true; } - - /** Add the mask to the channel, this should be overridden - * @param chan The channel - * @param mask The mask - */ - virtual void AddMask(Channel *chan, const char *mask) { } - - /** Delete the mask from the channel, this should be overridden - * @param chan The channel - * @param mask The mask - */ - virtual void DelMask(Channel *chan, const char *mask) { } - -}; - -/** This is a mode with a paramater, eg +k/l. These modes should use/inherit from this -*/ -class CoreExport ChannelModeParam : public ChannelMode -{ - public: - - /** Default constructor - * @param mName The mode name - * @param MinusArg true if this mode sends no arg when unsetting - */ - ChannelModeParam(ChannelModeName mName, bool MinusArg = false) : ChannelMode(mName) - { - this->Type = MODE_PARAM; - MinusNoArg = MinusArg; - } - - /** Default destructor - */ - virtual ~ChannelModeParam() { } - - /* Should we send an arg when unsetting this mode? */ - bool MinusNoArg; - - /** Is the param valid - * @param value The param - * @return true for yes, false for no - */ - virtual bool IsValid(const char *value) { return true; } -}; - -/** This is a mode that is a channel status, eg +v/h/o/a/q. -*/ -class CoreExport ChannelModeStatus : public ChannelMode -{ - public: - /** CUS_ values, see below - */ - int16 Status; - /* The symbol, eg @ % + */ - char Symbol; - - /** Default constructor - * @param mName The mode name - * @param mStatus A CUS_ value - * @param mSymbol The symbol for the mode, eg @ % + - * @param mProtectBotServ Should botserv clients reset this on themself if it gets unset> - */ - ChannelModeStatus(ChannelModeName mName, int16 mStatus, char mSymbol, bool mProtectBotServ = false) : ChannelMode(mName) - { - this->Type = MODE_STATUS; - this->Status = mStatus; - this->Symbol = mSymbol; - this->ProtectBotServ = mProtectBotServ; - } - - /** Default destructor - */ - virtual ~ChannelModeStatus() { } - - /* Should botserv protect itself with this mode? eg if someone -o's botserv it will +o */ - bool ProtectBotServ; -}; - -/** This class manages modes, and has the ability to add channel and - * user modes to Anope to track internally - */ -class CoreExport ModeManager -{ - public: - /* User modes */ - static std::map UserModesByChar; - static std::map UserModesByName; - /* Channel modes */ - static std::map ChannelModesByChar; - static std::map ChannelModesByName; - /* Although there are two different maps for UserModes and ChannelModes - * the pointers in each are the same. This is used to increase - * efficiency. - */ - - /** Add a user mode to Anope - * @param Mode The mode - * @param um A UserMode or UserMode derived class - * @return true on success, false on error - */ - static bool AddUserMode(char Mode, UserMode *um); - - /** Add a channel mode to Anope - * @param Mode The mode - * @param cm A ChannelMode or ChannelMode derived class - * @return true on success, false on error - */ - static bool AddChannelMode(char Mode, ChannelMode *cm); - - /** Find a channel mode - * @param Mode The mode - * @return The mode class - */ - static ChannelMode *FindChannelModeByChar(char Mode); - - /** Find a user mode - * @param Mode The mode - * @return The mode class - */ - static UserMode *FindUserModeByChar(char Mode); - - /** Find a channel mode - * @param Mode The modename - * @return The mode class - */ - static ChannelMode *FindChannelModeByName(ChannelModeName Name); - - /** Find a user mode - * @param Mode The modename - * @return The mode class - */ - static UserMode *FindUserModeByName(UserModeName Name); - - /** Gets the channel mode char for a symbol (eg + returns v) - * @param Value The symbol - * @return The char - */ - static char GetStatusChar(char Value); -}; - -/** Channel mode +b - */ -class CoreExport ChannelModeBan : public ChannelModeList -{ - public: - ChannelModeBan() : ChannelModeList(CMODE_BAN) { } - - void AddMask(Channel *chan, const char *mask); - - void DelMask(Channel *chan, const char *mask); -}; - -/** Channel mode +e - */ -class CoreExport ChannelModeExcept : public ChannelModeList -{ - public: - ChannelModeExcept() : ChannelModeList(CMODE_EXCEPT) { } - - void AddMask(Channel *chan, const char *mask); - - void DelMask(Channel *chan, const char *mask); -}; - -/** Channel mode +I - */ -class CoreExport ChannelModeInvite : public ChannelModeList -{ - public: - ChannelModeInvite() : ChannelModeList(CMODE_INVITEOVERRIDE) { } - - void AddMask(Channel *chan, const char *mask); - - void DelMask(Channel *chan, const char *mask); -}; - -/** Channel mode +k (key) - */ -class CoreExport ChannelModeKey : public ChannelModeParam -{ - public: - ChannelModeKey() : ChannelModeParam(CMODE_KEY) { } - - bool IsValid(const char *value); -}; - -/** Channel mode +f (flood) - */ -class ChannelModeFlood : public ChannelModeParam -{ - public: - ChannelModeFlood() : ChannelModeParam(CMODE_FLOOD) { } - - bool IsValid(const char *value); -}; - -/** This class is used for channel mode +A (Admin only) - * Only opers can mlock it - */ -class CoreExport ChannelModeAdmin : public ChannelMode -{ - public: - ChannelModeAdmin() : ChannelMode(CMODE_ADMINONLY) { } - - /* Opers only */ - bool CanSet(User *u); -}; - -/** This class is used for channel mode +O (Opers only) - * Only opers can mlock it - */ -class CoreExport ChannelModeOper : public ChannelMode -{ - public: - ChannelModeOper() : ChannelMode(CMODE_OPERONLY) { } - - /* Opers only */ - bool CanSet(User *u); -}; - -/** This class is used for channel mode +r (registered channel) - * No one may mlock r - */ -class CoreExport ChannelModeRegistered : public ChannelMode -{ - public: - ChannelModeRegistered() : ChannelMode(CMODE_REGISTERED) { } - - /* No one mlocks +r */ - bool CanSet(User *u); -}; - - /*************************************************************************/ struct session_ { @@ -1639,6 +1321,7 @@ class CoreExport IRCDProto private: virtual void SendSVSKillInternal(const char *, const char *, const char *) = 0; virtual void SendModeInternal(BotInfo *, const char *, const char *) = 0; + virtual void SendModeInternal(User *, const char *) = 0; virtual void SendKickInternal(BotInfo *bi, const char *, const char *, const char *) = 0; virtual void SendNoticeChanopsInternal(BotInfo *bi, const char *, const char *) = 0; virtual void SendMessageInternal(BotInfo *bi, const char *dest, const char *buf); @@ -1661,6 +1344,7 @@ class CoreExport IRCDProto virtual void SendSVSKill(const char *source, const char *user, const char *fmt, ...); virtual void SendSVSMode(User *, int, const char **) = 0; virtual void SendMode(BotInfo *bi, const char *dest, const char *fmt, ...); + virtual void SendMode(User *u, const char *fmt, ...); virtual void SendClientIntroduction(const char *, const char *, const char *, const char *, const char *, const char *uid) = 0; virtual void SendKick(BotInfo *bi, const char *chan, const char *user, const char *fmt, ...); virtual void SendNoticeChanops(BotInfo *bi, const char *dest, const char *fmt, ...); @@ -1670,7 +1354,6 @@ class CoreExport IRCDProto virtual void SendPrivmsg(BotInfo *bi, const char *dest, const char *fmt, ...); virtual void SendGlobalNotice(BotInfo *bi, const char *dest, const char *msg); virtual void SendGlobalPrivmsg(BotInfo *bi, const char *dest, const char *msg); - virtual void SendBotOp(const char *, const char *) = 0; /** XXX: This is a hack for NickServ enforcers. It is deprecated. * If I catch any developer using this in new code, I will RIP YOUR BALLS OFF. @@ -1707,7 +1390,6 @@ class CoreExport IRCDProto virtual void SendSWhois(const char *, const char *, const char *) { } virtual void SendEOB() { } virtual void SendServer(Server *) = 0; - virtual void ProcessUsermodes(User *, int, const char **) = 0; virtual int IsNickValid(const char *) { return 1; } virtual int IsChannelValid(const char *); virtual void SendNumeric(const char *source, int numeric, const char *dest, const char *fmt, ...); diff --git a/include/users.h b/include/users.h index aced32c20..d277704ad 100644 --- a/include/users.h +++ b/include/users.h @@ -23,6 +23,8 @@ class CoreExport User : public Extensible std::string ident; std::string uid; bool OnAccess; /* If the user is on the access list of the nick theyre on */ + std::bitset<128> modes; /* Bitset of mode names the user has set on them */ + std::map Params; /* Map of user modes and the params this user has */ public: // XXX: exposing a tiny bit too much User *next, *prev; @@ -37,7 +39,6 @@ class CoreExport User : public Extensible Server *server; /* Server user is connected to */ time_t timestamp; /* Timestamp of the nick */ time_t my_signon; /* When did _we_ see the user? */ - std::bitset<128> modes; NickCore *nc; @@ -66,7 +67,6 @@ class CoreExport User : public Extensible /** Destroy a user. */ ~User(); - /** Update the nickname of a user record accordingly, should be * called from ircd protocol. @@ -100,7 +100,6 @@ class CoreExport User : public Extensible */ const std::string &GetUID() const; - /** Update the displayed ident (username) of a user record. * @param ident The new ident to give this user. */ @@ -161,26 +160,55 @@ class CoreExport User : public Extensible * @param Name Mode name * @return true or false */ - const bool HasMode(UserModeName Name) const; - - /** Set a mode on the user - * @param Name The mode name - */ - void SetMode(UserModeName Name); - - /* Set a mode on the user - * @param ModeChar The mode char - */ - void SetMode(char ModeChar); - - /** Remove a mode from the user - * @param Name The mode name - */ - void RemoveMode(UserModeName Name); + const bool HasMode(UserModeName Name) const; + + /** Set a mode internally on the user, the IRCd is not informed + * @param um The user mode + * @param Param The param, if there is one + */ + void SetModeInternal(UserMode *um, const std::string &Param = ""); + + /** Remove a mode internally on the user, the IRCd is not informed + * @param um The user mode + */ + void RemoveModeInternal(UserMode *um); + + /** Set a mode on the user + * @param um The user mode + * @param Param Optional param for the mode + */ + void SetMode(UserMode *um, const std::string &Param = ""); + + /** Set a mode on the user + * @param Name The mode name + * @param Param Optional param for the mode + */ + void SetMode(UserModeName Name, const std::string &Param = ""); + + /* Set a mode on the user + * @param ModeChar The mode char + * @param param Optional param for the mode + */ + void SetMode(char ModeChar, const std::string &Param = ""); + + /** Remove a mode on the user + * @param um The user mode + */ + void RemoveMode(UserMode *um); /** Remove a mode from the user - * @param ModeChar The mode char - */ - void RemoveMode(char ModeChar); + * @param Name The mode name + */ + void RemoveMode(UserModeName Name); + + /** Remove a mode from the user + * @param ModeChar The mode char + */ + void RemoveMode(char ModeChar); + + /** Set a string of modes on a user + * @param modes The modes + */ + void SetModes(const std::string &modes, ...); }; diff --git a/src/actions.c b/src/actions.c index 9ed6b3b72..37bf95798 100644 --- a/src/actions.c +++ b/src/actions.c @@ -130,10 +130,7 @@ void sqline(char *mask, char *reason) */ void common_unban(ChannelInfo * ci, char *nick) { - const char *av[4]; char *host = NULL; - char buf[BUFSIZE]; - int ac; uint32 ip = 0; User *u; Entry *ban, *next; @@ -163,63 +160,21 @@ void common_unban(ChannelInfo * ci, char *nick) if (host) ip = str_is_ip(host); - if (ircd->svsmode_unban) { + if (ircd->svsmode_unban) ircdproto->SendBanDel(ci->name, nick); - } else { - if (ircdcap->tsmode) { - snprintf(buf, BUFSIZE - 1, "%ld", static_cast(time(NULL))); - av[0] = ci->name; - av[1] = buf; - av[2] = "-b"; - ac = 4; - } else { - av[0] = ci->name; - av[1] = "-b"; - ac = 3; - } - - for (ban = ci->c->bans->entries; ban; ban = next) { + else + { + for (ban = ci->c->bans->entries; ban; ban = next) + { next = ban->next; if (entry_match(ban, u->nick, u->GetIdent().c_str(), u->host, ip) || - entry_match(ban, u->nick, u->GetIdent().c_str(), u->GetDisplayedHost().c_str(), ip)) { - ircdproto->SendMode(whosends(ci), ci->name, "-b %s", ban->mask); - if (ircdcap->tsmode) - av[3] = ban->mask; - else - av[2] = ban->mask; - - do_cmode(whosends(ci)->nick, ac, av); - } + entry_match(ban, u->nick, u->GetIdent().c_str(), u->GetDisplayedHost().c_str(), ip)) + ci->c->RemoveMode(NULL, CMODE_BAN, ban->mask); } } /* host_resolve() sstrdup us this info so we gotta free it */ - if (host) { + if (host) delete [] host; - } -} - -/*************************************************************************/ - -/** - * Prepare to set SVSMODE and update internal user modes - * @param u user to apply modes to - * @param modes the modes to set on the user - * @param arg the arguments for the user modes - * @return void - */ -void common_svsmode(User * u, const char *modes, const char *arg) -{ - int ac = 1; - const char *av[2]; - - av[0] = modes; - if (arg) { - av[1] = arg; - ac++; - } - - ircdproto->SendSVSMode(u, ac, av); - ircdproto->ProcessUsermodes(u, ac, av); } /*************************************************************************/ diff --git a/src/botserv.c b/src/botserv.c index cbd3ccfc2..ab20b0852 100644 --- a/src/botserv.c +++ b/src/botserv.c @@ -736,38 +736,20 @@ void bot_join(ChannelInfo * ci) if (!ci || !ci->c || !ci->bi) return; - if (Config.BSSmartJoin) { + if (Config.BSSmartJoin) + { /* We check for bans */ - if (ci->c->bans && ci->c->bans->count) { - char buf[BUFSIZE]; - const char *av[4]; + if (ci->c->bans && ci->c->bans->count) + { Entry *ban, *next; - int ac; - - if (ircdcap->tsmode) { - snprintf(buf, BUFSIZE - 1, "%ld", static_cast(time(NULL))); - av[0] = ci->c->name; - av[1] = buf; - av[2] = "-b"; - ac = 4; - } else { - av[0] = ci->c->name; - av[1] = "-b"; - ac = 3; - } - for (ban = ci->c->bans->entries; ban; ban = next) { + for (ban = ci->c->bans->entries; ban; ban = next) + { next = ban->next; - if (entry_match - (ban, ci->bi->nick, ci->bi->user, ci->bi->host, 0)) { - ircdproto->SendMode(whosends(ci), ci->name, "-b %s", - ban->mask); - if (ircdcap->tsmode) - av[3] = ban->mask; - else - av[2] = ban->mask; - do_cmode(whosends(ci)->nick, ac, av); + if (entry_match(ban, ci->bi->nick, ci->bi->user, ci->bi->host, 0)) + { + ci->c->RemoveMode(NULL, CMODE_BAN, ban->mask); } } } @@ -787,7 +769,8 @@ void bot_join(ChannelInfo * ci) ci->bi->nick, ci->bi->nick); } ircdproto->SendJoin(ci->bi, ci->c->name, ci->c->creation_time); - ircdproto->SendBotOp(ci->bi->nick, ci->c->name); + ci->c->SetMode(NULL, CMODE_PROTECT, ci->bi->nick); + ci->c->SetMode(NULL, CMODE_OP, ci->bi->nick); FOREACH_MOD(I_OnBotJoin, OnBotJoin(ci, ci->bi)); } @@ -809,31 +792,14 @@ static void check_ban(ChannelInfo * ci, User * u, int ttbtype) /* Should not use == here because bd->ttb[ttbtype] could possibly be > ci->ttb[ttbtype] * if the TTB was changed after it was not set (0) before and the user had already been * kicked a few times. Bug #1056 - Adam */ - const char *av[4]; - int ac; char mask[BUFSIZE]; - char buf[BUFSIZE]; bd->ttb[ttbtype] = 0; get_idealban(ci, u, mask, sizeof(mask)); - if (ircdcap->tsmode) { - snprintf(buf, BUFSIZE - 1, "%ld", static_cast(time(NULL))); - av[0] = ci->name; - av[1] = buf; - av[2] = "+b"; - av[3] = mask; - ac = 4; - } else { - av[0] = ci->name; - av[1] = "+b"; - av[2] = mask; - ac = 3; - } - - ircdproto->SendMode(ci->bi, ci->name, "+b %s", mask); - do_cmode(ci->bi->nick, ac, av); + if (ci->c) + ci->c->SetMode(NULL, CMODE_BAN, mask); FOREACH_MOD(I_OnBotBan, OnBotBan(u, ci, mask)); } } @@ -874,11 +840,8 @@ static void bot_kick(ChannelInfo * ci, User * u, int message, ...) void bot_raw_ban(User * requester, ChannelInfo * ci, char *nick, const char *reason) { - int ac; - const char *av[4]; const char *kav[4]; // seperate as not everything is constified XXX -- w00t char mask[BUFSIZE]; - char buf[BUFSIZE]; User *u = finduser(nick); if (!u) @@ -907,22 +870,7 @@ void bot_raw_ban(User * requester, ChannelInfo * ci, char *nick, get_idealban(ci, u, mask, sizeof(mask)); - if (ircdcap->tsmode) { - snprintf(buf, BUFSIZE - 1, "%ld", static_cast(time(NULL))); - av[0] = ci->name; - av[1] = buf; - av[2] = "+b"; - av[3] = mask; - ac = 4; - } else { - av[0] = ci->name; - av[1] = "+b"; - av[2] = mask; - ac = 3; - } - - ircdproto->SendMode(ci->bi, ci->name, "+b %s", mask); - do_cmode(ci->bi->nick, ac, av); + ci->c->SetMode(NULL, CMODE_BAN, mask); kav[0] = ci->name; kav[1] = nick; @@ -998,8 +946,6 @@ void bot_raw_kick(User * requester, ChannelInfo * ci, char *nick, void bot_raw_mode(User * requester, ChannelInfo * ci, const char *mode, char *nick) { - const char *av[4]; - int ac; char buf[BUFSIZE]; User *u; @@ -1024,22 +970,7 @@ void bot_raw_mode(User * requester, ChannelInfo * ci, const char *mode, && (get_access(u, ci) >= get_access(requester, ci))) return; - if (ircdcap->tsmode) { - av[0] = ci->name; - av[1] = buf; - av[2] = mode; - av[3] = nick; - ac = 4; - ircdproto->SendMode(ci->bi, av[0], "%s %s", av[2], av[3]); - } else { - av[0] = ci->name; - av[1] = mode; - av[2] = nick; - ac = 3; - ircdproto->SendMode(ci->bi, av[0], "%s %s", av[1], av[2]); - } - - do_cmode(ci->bi->nick, ac, av); + ci->c->SetModes(NULL, "%s %s", mode, nick); } /*************************************************************************/ diff --git a/src/channels.c b/src/channels.c index b9d276a49..2115d2658 100644 --- a/src/channels.c +++ b/src/channels.c @@ -133,58 +133,189 @@ bool Channel::HasMode(ChannelModeName Name) return modes[Name]; } -/** - * Set a mode on a channel - * @param Name The mode name +/** Set a mode internally on a channel, this is not sent out to the IRCd + * @param cm The mode + * @param param The param + * @param EnforeMLock true if mlocks should be enforced, false to override mlock */ -void Channel::SetMode(ChannelModeName Name, const std::string param) +void Channel::SetModeInternal(ChannelMode *cm, const std::string ¶m, bool EnforceMLock) { - modes[Name] = true; + if (!cm) + return; + + /* Setting v/h/o/a/q etc */ + if (cm->Type == MODE_STATUS) + { + if (param.empty()) + { + alog("Channel::SetModeInternal() mode %c with no parameter for channel %s", cm->ModeChar, this->name); + return; + } + + /* We don't track bots */ + if (findbot(param.c_str())) + return; + + User *u = finduser(param.c_str()); + if (!u) + { + if (debug) + alog("debug: MODE %s +%c for nonexistant user %s", this->name, cm->ModeChar, param.c_str()); + return; + } + + if (debug) + alog("debug: Setting +%c on %s for %s", cm->ModeChar, this->name, u->nick); + + ChannelModeStatus *cms = static_cast(cm); + /* Set the new status on the user */ + chan_set_user_status(this, u, cms->Status); + /* Enforce secureops, etc */ + chan_set_correct_modes(u, this, 0); + return; + } + /* Setting b/e/I etc */ + else if (cm->Type == MODE_LIST) + { + if (param.empty()) + { + alog("Channel::SetModeInternal() mode %c with no parameter for channel %s", cm->ModeChar, this->name); + return; + } + + ChannelModeList *cml = static_cast(cm); + cml->AddMask(this, param.c_str()); + return; + } + + modes[cm->Name] = true; /* Channel mode +P or so was set, mark this channel as persistant */ - if (Name == CMODE_PERM && ci) + if (cm->Name == CMODE_PERM && ci) { ci->SetFlag(CI_PERSIST); } if (!param.empty()) { + if (cm->Type != MODE_PARAM) + { + alog("Channel::SetModeInternal() mode %c for %s with a paramater, but its not a param mode", cm->ModeChar, this->name); + return; + } + /* They could be resetting the mode to change its params */ - std::map::iterator it = Params.find(Name); + std::map::iterator it = Params.find(cm->Name); if (it != Params.end()) { Params.erase(it); } - Params.insert(std::make_pair(Name, param)); + Params.insert(std::make_pair(cm->Name, param)); } - FOREACH_MOD(I_OnChannelModeSet, OnChannelModeSet(this, Name)); -} + FOREACH_MOD(I_OnChannelModeSet, OnChannelModeSet(this, cm->Name)); -/** - * Set a mode on a channel - * @param Mode The mode - */ -void Channel::SetMode(char Mode, const std::string param) -{ - ChannelMode *cm; + /* Check for mlock */ + + /* Non registered channel, no mlock */ + if (!ci || !EnforceMLock) + return; - if ((cm = ModeManager::FindChannelModeByChar(Mode))) + /* If this channel has this mode locked negative */ + if (ci->HasMLock(cm->Name, false)) { - SetMode(cm->Name, param); + /* Remove the mode */ + if (cm->Type == MODE_PARAM) + { + ChannelModeParam *cmp = static_cast(cmp); + + if (!cmp->MinusNoArg) + { + /* Get the current param set on the channel and send it with the mode */ + std::string cparam; + if (GetParam(cmp->Name, &cparam)) + RemoveMode(NULL, cm, cparam); + } + else + RemoveMode(NULL, cm); + } + else if (cm->Type == MODE_REGULAR) + RemoveMode(NULL, cm); + } + /* If this is a param mode and its mlocked +, check to ensure someone didn't reset it with the wrong param */ + else if (cm->Type == MODE_PARAM && ci->HasMLock(cm->Name, true)) + { + ChannelModeParam *cmp = static_cast(cm); + std::string cparam, ciparam; + /* Get the param currently set on this channel */ + GetParam(cmp->Name, &cparam); + /* Get the param set in mlock */ + ci->GetParam(cmp->Name, &ciparam); + + /* We have the wrong param set */ + if (cparam.empty() || ciparam.empty() || cparam != ciparam) + { + /* Reset the mode with the correct param */ + SetMode(NULL, cm, ciparam); + } } } -/** - * Remove a mode from a channel - * @param Name The mode name +/** Remove a mode internally on a channel, this is not sent out to the IRCd + * @param cm The mode + * @param param The param + * @param EnforceMLock true if mlocks should be enforced, false to override mlock */ -void Channel::RemoveMode(ChannelModeName Name) +void Channel::RemoveModeInternal(ChannelMode *cm, const std::string ¶m, bool EnforceMLock) { - modes[Name] = false; + if (!cm) + return; - if (Name == CMODE_PERM && ci) + /* Setting v/h/o/a/q etc */ + if (cm->Type == MODE_STATUS) + { + if (param.empty()) + { + alog("Channel::RemoveModeInternal() mode %c with no parameter for channel %s", cm->ModeChar, this->name); + return; + } + + /* We don't track bots */ + if (findbot(param.c_str())) + return; + + User *u = finduser(param.c_str()); + if (!u) + { + alog("Channel::RemoveModeInternal() MODE %s +%c for nonexistant user %s", this->name, cm->ModeChar, param.c_str()); + return; + } + + if (debug) + alog("debug: Setting +%c on %s for %s", cm->ModeChar, this->name, u->nick); + + ChannelModeStatus *cms = static_cast(cm); + chan_remove_user_status(this, u, cms->Status); + return; + } + /* Setting b/e/I etc */ + else if (cm->Type == MODE_LIST) + { + if (param.empty()) + { + alog("Channel::SetModeInternal() mode %c with no parameter for channel %s", cm->ModeChar, this->name); + return; + } + + ChannelModeList *cml = static_cast(cm); + cml->DelMask(this, param.c_str()); + return; + } + + modes[cm->Name] = false; + + if (cm->Name == CMODE_PERM && ci) { ci->UnsetFlag(CI_PERSIST); if (Config.s_BotServ && ci->bi && usercount == Config.BSMinUsers - 1) @@ -193,27 +324,118 @@ void Channel::RemoveMode(ChannelModeName Name) delete this; } - std::map::iterator it = Params.find(Name); - if (it != Params.end()) + if (cm->Type == MODE_PARAM) { - Params.erase(it); + std::map::iterator it = Params.find(cm->Name); + if (it != Params.end()) + { + Params.erase(it); + } } - FOREACH_MOD(I_OnChannelModeUnset, OnChannelModeUnset(this, Name)); + FOREACH_MOD(I_OnChannelModeUnset, OnChannelModeUnset(this, cm->Name)); + + /* Check for mlock */ + + /* Non registered channel, no mlock */ + if (!ci || !EnforceMLock) + return; + + /* This channel has this the mode locked on */ + if (ci->HasMLock(cm->Name, true)) + { + if (cm->Type == MODE_REGULAR) + { + /* Set the mode */ + SetMode(NULL, cm); + } + /* This is a param mode */ + else if (cm->Type == MODE_PARAM) + { + std::string cparam; + /* Get the param stored in mlock for this mode */ + if (ci->GetParam(cm->Name, &cparam)) + SetMode(NULL, cm, cparam); + } + } +} + +/** Set a mode on a channel + * @param bi The client setting the modes + * @param cm The mode + * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock + */ +void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const std::string ¶m, bool EnforceMLock) +{ + if (!cm) + return; + + ModeManager::StackerAdd(bi, this, cm, true, param); + SetModeInternal(cm, param, EnforceMLock); } /** - * Remove a mode from a channel + * Set a mode on a channel + * @param bi The client setting the modes + * @param Name The mode name + * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock + */ +void Channel::SetMode(BotInfo *bi, ChannelModeName Name, const std::string ¶m, bool EnforceMLock) +{ + SetMode(bi, ModeManager::FindChannelModeByName(Name), param, EnforceMLock); +} + +/** + * Set a mode on a channel + * @param bi The client setting the modes * @param Mode The mode + * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock */ -void Channel::RemoveMode(char Mode) +void Channel::SetMode(BotInfo *bi, char Mode, const std::string ¶m, bool EnforceMLock) { - ChannelMode *cm; + SetMode(bi, ModeManager::FindChannelModeByChar(Mode), param, EnforceMLock); +} - if ((cm = ModeManager::FindChannelModeByChar(Mode))) - { - RemoveMode(cm->Name); - } +/** Remove a mode from a channel + * @param bi The client setting the modes + * @param cm The mode + * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock + */ +void Channel::RemoveMode(BotInfo *bi, ChannelMode *cm, const std::string ¶m, bool EnforceMLock) +{ + if (!cm) + return; + + ModeManager::StackerAdd(bi, this, cm, false, param); + RemoveModeInternal(cm, param, EnforceMLock); +} + +/** + * Remove a mode from a channel + * @param bi The client setting the modes + * @param Name The mode name + * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock + */ +void Channel::RemoveMode(BotInfo *bi, ChannelModeName Name, const std::string ¶m, bool EnforceMLock) +{ + RemoveMode(bi, ModeManager::FindChannelModeByName(Name), param, EnforceMLock); +} + +/** + * Remove a mode from a channel + * @param bi The client setting the modes + * @param Mode The mode + * @param param Optional param arg for the mode + * @param EnforceMLock true if mlocks should be enforced, false to override mlock + */ +void Channel::RemoveMode(BotInfo *bi, char Mode, const std::string ¶m, bool EnforceMLock) +{ + RemoveMode(bi, ModeManager::FindChannelModeByChar(Mode), param, EnforceMLock); } /** Get a param from the channel @@ -254,15 +476,12 @@ const bool Channel::HasParam(ChannelModeName Name) /*************************************************************************/ /** Clear all the modes from the channel - * @param client The client unsetting the modes + * @param bi The client setting the modes */ -void Channel::ClearModes(char *client) +void Channel::ClearModes(BotInfo *bi) { ChannelMode *cm; ChannelModeParam *cmp; - std::string buf, buf2; - const char *argv[2]; - BotInfo *sender = (client ? findbot(client) : whosends(ci)); for (size_t n = CMODE_BEGIN + 1; n != CMODE_END; ++n) { @@ -272,41 +491,21 @@ void Channel::ClearModes(char *client) { if (cm->Type == MODE_REGULAR) { - buf = '-'; - buf += cm->ModeChar; - - argv[0] = buf.c_str(); - - ircdproto->SendMode(sender, this->name, "-%c", cm->ModeChar); - chan_set_modes(sender->nick, this, 1, argv, 0); + this->RemoveMode(NULL, cm); } else if (cm->Type == MODE_PARAM) { cmp = static_cast(cm); - buf = '-'; - buf += cmp->ModeChar; - buf2.clear(); - if (!cmp->MinusNoArg) { - buf2 = this->GetParam(cmp->Name, &buf2); - } - - argv[0] = buf.c_str(); - if (!buf2.empty()) - { - argv[1] = buf2.c_str(); - - ircdproto->SendMode(sender, this->name, "-%c %s", cm->ModeChar, buf2.c_str()); - chan_set_modes(sender->nick, this, 2, argv, 0); + std::string buf; + if (this->GetParam(cmp->Name, &buf)) + this->RemoveMode(NULL, cm, buf); } else { - argv[1] = NULL; - - ircdproto->SendMode(sender, this->name, "-%c", cm->ModeChar); - chan_set_modes(sender->nick, this, 1, argv, 0); + this->RemoveMode(NULL, cm); } } } @@ -316,100 +515,195 @@ void Channel::ClearModes(char *client) } /** Clear all the bans from the channel - * @param client The client unsetting the modes + * @param bi The client setting the modes */ -void Channel::ClearBans(char *client) +void Channel::ClearBans(BotInfo *bi) { Entry *entry, *nexte; - BotInfo *sender = (client ? findbot(client) : whosends(ci)); ChannelModeList *cml; - std::string buf; - const char *argv[2]; cml = static_cast(ModeManager::FindChannelModeByName(CMODE_BAN)); if (cml && this->bans && this->bans->count) { - buf = '-'; - buf += cml->ModeChar; - for (entry = this->bans->entries; entry; entry = nexte) { nexte = entry->next; - argv[0] = buf.c_str(); - argv[1] = sstrdup(entry->mask); - ircdproto->SendMode(sender, this->name, "%s %s", buf.c_str(), entry->mask); - chan_set_modes(sender->nick, this, 2, argv, 0); - delete [] argv[1]; + this->RemoveMode(bi, CMODE_BAN, entry->mask); } } } /** Clear all the excepts from the channel - * @param client The client unsetting the modes + * @param bi The client setting the modes */ -void Channel::ClearExcepts(char *client) +void Channel::ClearExcepts(BotInfo *bi) { Entry *entry, *nexte; - BotInfo *sender = (client ? findbot(client) : whosends(ci)); ChannelModeList *cml; - std::string buf; - const char *argv[2]; cml = static_cast(ModeManager::FindChannelModeByName(CMODE_EXCEPT)); if (cml && this->excepts && this->excepts->count) { - buf = '+'; - buf += cml->ModeChar; - for (entry = this->excepts->entries; entry; entry = nexte) { nexte = entry->next; - argv[0] = buf.c_str(); - argv[1] = sstrdup(entry->mask); - ircdproto->SendMode(sender, this->name, "%s %s", buf.c_str(), entry->mask); - chan_set_modes(sender->nick, this, 2, argv, 0); - delete [] argv[1]; + this->RemoveMode(bi, CMODE_EXCEPT, entry->mask); } } } /** Clear all the invites from the channel - * @param client The client unsetting the modes + * @param bi The client setting the modes */ -void Channel::ClearInvites(char *client) +void Channel::ClearInvites(BotInfo *bi) { Entry *entry, *nexte; - BotInfo *sender = (client ? findbot(client) : whosends(ci)); ChannelModeList *cml; - std::string buf; - const char *argv[2]; cml = static_cast(ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE)); if (cml && this->invites && this->invites->count) { - buf = '-'; - buf += cml->ModeChar; - for (entry = this->invites->entries; entry; entry = nexte) { nexte = entry->next; - argv[0] = buf.c_str(); - argv[1] = sstrdup(entry->mask); - ircdproto->SendMode(sender, this->name, "%s %s", buf.c_str(), entry->mask); - chan_set_modes(sender->nick, this, 2, argv, 0); - delete [] argv[1]; + this->RemoveMode(bi, CMODE_INVITEOVERRIDE, entry->mask); + } + } +} + +/** Set a string of modes on the channel + * @param bi The client setting the modes + * @param EnforceMLock Should mlock be enforced on this mode change + * @param cmodes The modes to set + */ +void Channel::SetModes(BotInfo *bi, bool EnforceMLock, const std::string &cmodes, ...) +{ + char buf[BUFSIZE] = ""; + va_list args; + std::string modebuf, sbuf; + int add = -1; + va_start(args, cmodes.c_str()); + vsnprintf(buf, BUFSIZE - 1, cmodes.c_str(), args); + va_end(args); + + spacesepstream sep(buf); + sep.GetToken(modebuf); + for (unsigned i = 0; i < modebuf.size(); ++i) + { + ChannelMode *cm; + + switch (modebuf[i]) + { + case '+': + add = 1; + continue; + case '-': + add = 0; + continue; + default: + if (add == -1) + continue; + cm = ModeManager::FindChannelModeByChar(modebuf[i]); + if (!cm) + continue; + } + + if (add) + { + if (cm->Type == MODE_PARAM && sep.GetToken(sbuf)) + this->SetMode(bi, cm, sbuf, EnforceMLock); + else + this->SetMode(bi, cm, "", EnforceMLock); + } + else if (add == 0) + { + if (cm->Type == MODE_PARAM && sep.GetToken(sbuf)) + this->RemoveMode(bi, cm, sbuf, EnforceMLock); + else + this->RemoveMode(bi, cm, "", EnforceMLock); } } } /*************************************************************************/ +/** Set modes internally on the channel + * @param c The channel + * @param ac Number of args + * @param av args + */ +void ChanSetInternalModes(Channel *c, int ac, const char **av) +{ + if (!ac) + return; + + int k = 0, j = 0, add = -1; + for (unsigned int i = 0; i < strlen(av[0]); ++i) + { + ChannelMode *cm; + + switch (av[0][i]) + { + case '+': + add = 1; + continue; + case '-': + add = 0; + continue; + default: + if (add == -1) + continue; + cm = ModeManager::FindChannelModeByChar(av[0][i]); + if (!cm) + continue; + } + + if (cm->Type == MODE_REGULAR) + { + if (add) + c->SetModeInternal(cm); + else + c->RemoveModeInternal(cm); + continue; + } + else if (cm->Type == MODE_PARAM) + { + ChannelModeParam *cmp = static_cast(cm); + + if (!add && cmp->MinusNoArg) + { + c->RemoveModeInternal(cm); + ++k; + continue; + } + } + if (++j < ac) + { + if (add) + c->SetModeInternal(cm, av[j]); + else + c->RemoveModeInternal(cm, av[j]); + } + else + { + alog("warning: ChanSetInternalModes() recieved more modes requiring params than params, modes: %s, ac: %d, j: %d", merge_args(ac, av), ac, j); + } + } + + if (j + k + 1 < ac) + { + alog("warning: ChanSetInternalModes() recieved more params than modes requiring them, modes: %s, ac: %d, j: %d k: %d", merge_args(ac, av), ac, j, k); + } +} + +/*************************************************************************/ + void chan_deluser(User * user, Channel * c) { struct c_userlist *u; @@ -563,204 +857,12 @@ void chan_remove_user_status(Channel * chan, User * user, int16 status) /*************************************************************************/ -void chan_set_modes(const char *source, Channel *chan, int ac, const char **av, int check) -{ - int add = 1, i, real_ac = ac; - ChannelMode *cm; - ChannelModeStatus *cms; - ChannelModeList *cml; - ChannelModeParam *cmp; - const char *modes, **real_av = av; - char mode; - BotInfo *bi; - unsigned char botmode = 0; - User *user; - - modes = av[0]; - - if (debug) - alog("debug: Changing modes for %s to %s", chan->name, merge_args(ac, av)); - - ac--; - - while ((mode = *modes++)) - { - switch (mode) - { - case '+': - add = 1; - continue; - case '-': - add = 0; - continue; - } - - if ((cm = ModeManager::FindChannelModeByChar(mode))) - { - /* v/h/o/a/q etc */ - if (cm->Type == MODE_STATUS) - { - cms = static_cast(cm); - - if (ac == 0) - { - alog("channel: mode %c%c with no parameter (?) for channel %s", add ? '+' : '-', mode, chan->name); - continue; - } - - ac--; - av++; - - if (cms->ProtectBotServ && !add) - { - if ((bi = findbot(*av))) - { - if (!botmode || botmode != mode) - { - ircdproto->SendMode(bi, chan->name, "+%c %s", mode, bi->nick); - botmode = mode; - continue; - } - else - { - botmode = mode; - continue; - } - } - } - else if ((bi = findbot(*av))) - continue; - - if (!(user = finduser(*av)) && !(ircd->ts6 && (user = find_byuid(*av)))) - { - if (debug) - { - alog("debug: MODE %s %c%c for nonexistent user %s", - chan->name, (add ? '+' : '-'), mode, *av); - } - continue; - } - - if (debug) - alog("debug: Setting %c%c on %s for %s", (add ? '+' : '-'), - mode, chan->name, user->nick); - - if (add) - chan_set_user_status(chan, user, cms->Status); - /* If this does +o, remove any DEOPPED flag */ - else - chan_remove_user_status(chan, user, cms->Status); - } - /* b/e/I etc */ - else if (cm->Type == MODE_LIST) - { - cml = static_cast(cm); - - if (ac == 0) - { - alog("channel: mode %c%c with no parameter (?) for channel %s", add ? '+' : '-', mode, chan->name); - continue; - } - - ac--; - av++; - - if (add) - cml->AddMask(chan, *av); - else - cml->DelMask(chan, *av); - } - else - { - if (cm->Type == MODE_PARAM) - { - cmp = static_cast(cm); - - if (add || !cmp->MinusNoArg) - { - if (ac == 0) - { - alog("channel: mode %c%c with no parameter (?) for channel %s", add ? '+' : '-', mode, chan->name