diff options
42 files changed, 1226 insertions, 1266 deletions
diff --git a/data/example.conf b/data/example.conf index 1216e163b..777e28748 100644 --- a/data/example.conf +++ b/data/example.conf @@ -639,6 +639,7 @@ log * * chanserv/access/list chanserv/drop chanserv/forbid chanserv/getkey * chanserv/list chanserv/suspend chanserv/topic chanserv/status + * chanserv/mode * * chanserv/saset/bantype chanserv/saset/description chanserv/saset/email chanserv/saset/entrymsg * chanserv/saset/founder chanserv/saset/keeptopic chanserv/saset/opnotice @@ -1044,7 +1045,7 @@ chanserv * The core modules to load for ChanServ. This is a space separated list that corresponds * to the base names of the modules for ChanServ. This directive is optional, but highly recommended. */ - modules = "cs_help cs_register cs_set cs_saset cs_saset_noexpire cs_set_bantype cs_set_description cs_set_entrymsg cs_set_founder cs_set_keeptopic cs_set_opnotice cs_set_peace cs_set_persist cs_set_private cs_set_restricted cs_set_secure cs_set_securefounder cs_set_secureops cs_set_signkick cs_set_successor cs_set_topiclock cs_set_xop cs_xop cs_access cs_akick cs_drop cs_ban cs_clearusers cs_modes cs_getkey cs_invite cs_kick cs_list cs_topic cs_info cs_forbid cs_suspend cs_status cs_unban cs_clone" + modules = "cs_help cs_register cs_set cs_saset cs_saset_noexpire cs_set_bantype cs_set_description cs_set_entrymsg cs_set_founder cs_set_keeptopic cs_set_opnotice cs_set_peace cs_set_persist cs_set_private cs_set_restricted cs_set_secure cs_set_securefounder cs_set_secureops cs_set_signkick cs_set_successor cs_set_topiclock cs_set_xop cs_xop cs_access cs_akick cs_drop cs_ban cs_clearusers cs_modes cs_getkey cs_invite cs_kick cs_list cs_topic cs_info cs_forbid cs_suspend cs_status cs_unban cs_clone cs_mode" /* * The default options for newly registered channels. Note that changing these options diff --git a/data/mysql/tables.sql b/data/mysql/tables.sql index fb9b7335a..e165e94ad 100644 --- a/data/mysql/tables.sql +++ b/data/mysql/tables.sql @@ -111,6 +111,7 @@ CREATE TABLE IF NOT EXISTS `anope_cs_info` ( `mlock_on` text NOT NULL, `mlock_off` text NOT NULL, `mlock_params` text NOT NULL, + `mlock_params_off` text NOT NULL, `entry_message` text NOT NULL, `memomax` smallint(5) unsigned NOT NULL DEFAULT '0', `botnick` varchar(255) NOT NULL DEFAULT '', diff --git a/docs/Changes.conf b/docs/Changes.conf index 792477f12..def316054 100644 --- a/docs/Changes.conf +++ b/docs/Changes.conf @@ -1,7 +1,7 @@ Anope Version 1.9.4 ------------------- memoserv:modules added ms_ignore -chanserv:modules added cs_clone +chanserv:modules added cs_clone and cs_mode Anope Version 1.9.3 ------------------ @@ -106,18 +106,10 @@ How To Add IRCd Support 23) TS6: Does the IRCd support TS6? Use 1 for yes, 0 for no.
- 24) Channel CIDR: Set to 1 if channel bans, excepts and invites
- support CIDR masks. Expected syntax: *!*@ip/mask.
- When set to 1, anope will only parse strict CIDR masks.
- IRCd's that try to correct invalid CIDR's (like nefarious)
- will need a custom implementation in the core.
- Contact the anope Dev Team if this is the case.
- Set to 0 if CIDR's are not supported by your IRCd.
-
- 25) Global TLD Prefix: Prefix used to send global messages, should probably
+ 24) Global TLD Prefix: Prefix used to send global messages, should probably
be "$"
- 26) Max Modes: The max number of mode changes we can send in one line
+ 25) Max Modes: The max number of mode changes we can send in one line
3) Modes
diff --git a/include/channels.h b/include/channels.h index 54a85426b..cf4d97df3 100644 --- a/include/channels.h +++ b/include/channels.h @@ -64,13 +64,12 @@ enum ChannelFlags class CoreExport Channel : public Extensible, public Flags<ChannelFlags> { + public: + typedef std::multimap<ChannelModeName, Anope::string> ModeList; private: /** A map of channel modes with their parameters set on this channel */ - std::map<ChannelModeName, Anope::string> Params; - - /* Modes set on the channel */ - Flags<ChannelModeName, CMODE_END * 2> modes; + ModeList modes; public: /** Default constructor @@ -87,10 +86,6 @@ class CoreExport Channel : public Extensible, public Flags<ChannelFlags> ChannelInfo *ci; /* Corresponding ChannelInfo */ time_t creation_time; /* When channel was created */ - EList *bans; - EList *excepts; - EList *invites; - /* List of users in the channel */ CUserList users; @@ -146,16 +141,18 @@ class CoreExport Channel : public Extensible, public Flags<ChannelFlags> */ bool HasUserStatus(User *u, ChannelModeName Name) const; - /** See if the channel has any modes at all - * @return true or false - */ - inline bool HasModes() const { return modes.FlagCount(); } - /** See if a channel has a mode * @param Name The mode name - * @return true or false + * @return The number of modes set + * @param param The optional mode param */ - bool HasMode(ChannelModeName Name) const; + size_t HasMode(ChannelModeName Name, const Anope::string ¶m = ""); + + /** Get a list of modes on a channel + * @param Name A mode name to get the list of + * @return a pair of iterators for the beginning and end of the list + */ + std::pair<ModeList::iterator, ModeList::iterator> GetModeList(ChannelModeName Name); /** Set a mode internally on a channel, this is not sent out to the IRCd * @param cm The mode @@ -205,30 +202,6 @@ class CoreExport Channel : public Extensible, public Flags<ChannelFlags> */ void RemoveMode(BotInfo *bi, ChannelModeName Name, const Anope::string ¶m = "", bool EnforceMLock = true); - /** Clear all the modes from the channel - * @param bi The client unsetting the modes - * @param internal Only remove the modes internally - */ - void ClearModes(BotInfo *bi = NULL, bool internal = false); - - /** Clear all the bans from the channel - * @param bi The client unsetting the modes - * @param internal Only remove the modes internally - */ - void ClearBans(BotInfo *bi = NULL, bool internal = false); - - /** Clear all the excepts from the channel - * @param bi The client unsetting the modes - * @param internal Only remove the modes internally - */ - void ClearExcepts(BotInfo *bi = NULL, bool internal = false); - - /** Clear all the invites from the channel - * @param bi The client unsetting the modes - * @param internal Only remove the modes internally - */ - void ClearInvites(BotInfo *bi = NULL, bool internal = false); - /** Get a param from the channel * @param Name The mode * @param Target a string to put the param into @@ -236,11 +209,6 @@ class CoreExport Channel : public Extensible, public Flags<ChannelFlags> */ bool GetParam(ChannelModeName Name, Anope::string &Target) const; - /** Check if a mode is set and has a param - * @param Name The mode - */ - bool HasParam(ChannelModeName Name) const; - /** 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 diff --git a/include/extern.h b/include/extern.h index b8bcb5be3..bd951ee5e 100644 --- a/include/extern.h +++ b/include/extern.h @@ -75,18 +75,6 @@ E void MassChannelModes(BotInfo *bi, const Anope::string &modes); E void chan_set_correct_modes(User *user, Channel *c, int give_modes); -E Entry *entry_create(const Anope::string &mask); -E Entry *entry_add(EList *list, const Anope::string &mask); -E void entry_delete(EList *list, Entry *e); -E EList *list_create(); -E int entry_match(Entry *e, const Anope::string &nick, const Anope::string &user, const Anope::string &host, uint32 ip); -E int entry_match_mask(Entry *e, const Anope::string &mask, uint32 ip); -E Entry *elist_match(EList *list, const Anope::string &nick, const Anope::string &user, const Anope::string &host, uint32 ip); -E Entry *elist_match_mask(EList *list, const Anope::string &mask, uint32 ip); -E Entry *elist_match_user(EList *list, User *u); -E Entry *elist_find_mask(EList *list, const Anope::string &mask); -E long get_memuse(EList *list); - inline BotInfo *whosends(ChannelInfo *ci) { if (!ci || !ci->bi || !ci->c || !ci->botflags.HasFlag(BS_SYMBIOSIS) || !ci->c->FindUser(ci->bi)) @@ -272,9 +260,7 @@ E bool str_is_cidr(const Anope::string &str, uint32 &ip, uint32 &mask, Anope::st /**** modes.cpp ****/ /* Number of generic modes we support */ E unsigned GenericChannelModes, GenericUserModes; -E Flags<ChannelModeName, CMODE_END * 2> DefMLockOn; -E Flags<ChannelModeName, CMODE_END * 2> DefMLockOff; -E std::map<ChannelModeName, Anope::string> DefMLockParams; +E std::multimap<ChannelModeName, ModeLock> def_mode_locks; E void SetDefaultMLock(ServerConfig *config); /**** nickserv.c ****/ diff --git a/include/language.h b/include/language.h index 0b1c60f2c..634b840dd 100644 --- a/include/language.h +++ b/include/language.h @@ -274,7 +274,6 @@ enum LanguageString CHAN_LEVEL_INVITE, CHAN_LEVEL_AKICK, CHAN_LEVEL_SET, - CHAN_LEVEL_CLEAR, CHAN_LEVEL_UNBAN, CHAN_LEVEL_OPDEOP, CHAN_LEVEL_ACCESS_LIST, @@ -300,6 +299,7 @@ enum LanguageString CHAN_LEVEL_BANME, CHAN_LEVEL_BAN, CHAN_LEVEL_TOPIC, + CHAN_LEVEL_MODE, CHAN_LEVEL_INFO, CHAN_LEVEL_AUTOOWNER, CHAN_LEVEL_OWNER, @@ -555,13 +555,8 @@ enum LanguageString CHAN_UNBANNED, CHAN_UNBANNED_OTHER, CHAN_TOPIC_SYNTAX, - CHAN_CLEAR_SYNTAX, - CHAN_CLEARED_BANS, - CHAN_CLEARED_EXCEPTS, - CHAN_CLEARED_MODES, - CHAN_CLEARED_OPS, + CHAN_CLEARUSERS_SYNTAX, CHAN_CLEARED_USERS, - CHAN_CLEARED_INVITES, CHAN_CLONED, CHAN_CLONED_ACCESS, CHAN_CLONED_AKICK, @@ -597,6 +592,15 @@ enum LanguageString CHAN_DEOWNER_SYNTAX, CHAN_KICK_SYNTAX, CHAN_BAN_SYNTAX, + CHAN_MODE_SYNTAX, + CHAN_MODE_LOCK_UNKNOWN, + CHAN_MODE_LOCK_MISSING_PARAM, + CHAN_MODE_LOCK_NONE, + CHAN_MODE_LOCK_HEADER, + CHAN_MODE_LOCKED, + CHAN_MODE_NOT_LOCKED, + CHAN_MODE_UNLOCKED, + CHAN_MODE_LIST_FMT, MEMO_HAVE_NEW_MEMO, MEMO_HAVE_NEW_MEMOS, MEMO_TYPE_READ_LAST, @@ -931,9 +935,6 @@ enum LanguageString OPER_OLINE_SYNTAX, OPER_OLINE_SUCCESS, OPER_OLINE_IRCOP, - OPER_CLEARMODES_SYNTAX, - OPER_CLEARMODES_DONE, - OPER_CLEARMODES_ALL_DONE, OPER_KICK_SYNTAX, OPER_SVSNICK_SYNTAX, OPER_SVSNICK_NEWNICK, @@ -1266,7 +1267,7 @@ enum LanguageString CHAN_HELP_CMD_AKICK, CHAN_HELP_CMD_DROP, CHAN_HELP_CMD_BAN, - CHAN_HELP_CMD_CLEAR, + CHAN_HELP_CMD_CLEARUSERS, CHAN_HELP_CMD_DEVOICE, CHAN_HELP_CMD_GETKEY, CHAN_HELP_CMD_INFO, @@ -1287,6 +1288,7 @@ enum LanguageString CHAN_HELP_CMD_PROTECT, CHAN_HELP_CMD_DEOP, CHAN_HELP_CMD_CLONE, + CHAN_HELP_CMD_MODE, CHAN_HELP, CHAN_HELP_EXPIRES, CHAN_HELP_REGISTER, @@ -1358,9 +1360,10 @@ enum LanguageString CHAN_HELP_KICK, CHAN_HELP_BAN, CHAN_HELP_TOPIC, - CHAN_HELP_CLEAR, + CHAN_HELP_CLEARUSERS, CHAN_HELP_GETKEY, CHAN_HELP_CLONE, + CHAN_HELP_MODE, CHAN_SERVADMIN_HELP, CHAN_SERVADMIN_HELP_DROP, CHAN_SERVADMIN_HELP_SET_NOEXPIRE, @@ -1403,7 +1406,6 @@ enum LanguageString OPER_HELP_CMD_STAFF, OPER_HELP_CMD_MODE, OPER_HELP_CMD_KICK, - OPER_HELP_CMD_CLEARMODES, OPER_HELP_CMD_AKILL, OPER_HELP_CMD_SNLINE, OPER_HELP_CMD_SQLINE, @@ -1442,7 +1444,6 @@ enum LanguageString OPER_HELP_MODE, OPER_HELP_UMODE, OPER_HELP_OLINE, - OPER_HELP_CLEARMODES, OPER_HELP_KICK, OPER_HELP_SVSNICK, OPER_HELP_AKILL, diff --git a/include/modes.h b/include/modes.h index 299d1a2db..ce0281cd0 100644 --- a/include/modes.h +++ b/include/modes.h @@ -185,17 +185,17 @@ class CoreExport ChannelModeList : public ChannelMode */ virtual bool IsValid(const Anope::string &mask) const { return true; } - /** Add the mask to the channel, this should be overridden + /** Called when a mask is added to a channel * @param chan The channel * @param mask The mask */ - virtual void AddMask(Channel *chan, const Anope::string &mask) { } + virtual void OnAdd(Channel *chan, const Anope::string &mask) { } - /** Delete the mask from the channel, this should be overridden + /** Called when a mask is removed from a channel * @param chan The channel * @param mask The mask */ - virtual void DelMask(Channel *chan, const Anope::string &mask) { } + virtual void OnDel(Channel *chan, const Anope::string &mask) { } }; @@ -254,9 +254,9 @@ class CoreExport ChannelModeBan : public ChannelModeList public: ChannelModeBan(char modeChar) : ChannelModeList(CMODE_BAN, "CMODE_BAN", modeChar) { } - void AddMask(Channel *chan, const Anope::string &mask); + void OnAdd(Channel *chan, const Anope::string &mask); - void DelMask(Channel *chan, const Anope::string &mask); + void OnDel(Channel *chan, const Anope::string &mask); }; /** Channel mode +e @@ -266,9 +266,9 @@ class CoreExport ChannelModeExcept : public ChannelModeList public: ChannelModeExcept(char modeChar) : ChannelModeList(CMODE_EXCEPT, "CMODE_EXCEPT", modeChar) { } - void AddMask(Channel *chan, const Anope::string &mask); + void OnAdd(Channel *chan, const Anope::string &mask); - void DelMask(Channel *chan, const Anope::string &mask); + void OnDel(Channel *chan, const Anope::string &mask); }; /** Channel mode +I @@ -278,9 +278,9 @@ class CoreExport ChannelModeInvex : public ChannelModeList public: ChannelModeInvex(char modeChar) : ChannelModeList(CMODE_INVITEOVERRIDE, "CMODE_INVITEOVERRIDE", modeChar) { } - void AddMask(Channel *chan, const Anope::string &mask); + void OnAdd(Channel *chan, const Anope::string &mask); - void DelMask(Channel *chan, const Anope::string &mask); + void OnDel(Channel *chan, const Anope::string &mask); }; diff --git a/include/modules.h b/include/modules.h index 481b5180b..be5c14447 100644 --- a/include/modules.h +++ b/include/modules.h @@ -991,20 +991,18 @@ class CoreExport Module : public Extensible virtual void OnUserModeAdd(UserMode *um) { } /** Called when a mode is about to be mlocked - * @param ci The channel - * @param Name The mode being mlocked - * @param status true if its being mlocked +, false for - - * @param param The param, if there is one and if status is true + * @param ci The channel the mode is being locked on + * @param lock The mode lock * @return EVENT_CONTINUE to let other modules decide, EVENT_STOP to deny the mlock. */ - virtual EventReturn OnMLock(ChannelInfo *ci, ChannelModeName Name, bool status, const Anope::string ¶m) { return EVENT_CONTINUE; } + virtual EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) { return EVENT_CONTINUE; } /** Called when a mode is about to be unlocked - * @param ci The channel - * @param Name The mode being mlocked + * @param ci The channel the mode is being unlocked from + * @param mode The mode being unlocked * @return EVENT_CONTINUE to let other modules decide, EVENT_STOP to deny the mlock. */ - virtual EventReturn OnUnMLock(ChannelInfo *ci, ChannelModeName Name) { return EVENT_CONTINUE; } + virtual EventReturn OnUnMLock(ChannelInfo *ci, ChannelMode *mode, const Anope::string ¶m) { return EVENT_CONTINUE; } /** Called after a module is loaded * @param u The user loading the module, can be NULL diff --git a/include/regchannel.h b/include/regchannel.h index 1300b9cf4..dd47a88fc 100644 --- a/include/regchannel.h +++ b/include/regchannel.h @@ -62,15 +62,26 @@ enum ChannelInfoFlag CI_END }; +struct ModeLock +{ + bool set; + ChannelModeName name; + Anope::string param; + Anope::string setter; + time_t created; + + ModeLock(bool s, ChannelModeName n, const Anope::string &p, const Anope::string &se = "", time_t c = Anope::CurTime) : set(s), name(n), param(p), setter(se), created(c) { } +}; + class CoreExport ChannelInfo : public Extensible, public Flags<ChannelInfoFlag, CI_END> { private: - std::map<ChannelModeName, Anope::string> Params; /* Map of parameters by mode name for mlock */ + typedef std::multimap<ChannelModeName, ModeLock> ModeList; + private: std::vector<ChanAccess *> access; /* List of authorized users */ std::vector<AutoKick *> akick; /* List of users to kickban */ std::vector<BadWord *> badwords; /* List of badwords */ - Flags<ChannelModeName, CMODE_END * 2> mlock_on; /* Modes mlocked on */ - Flags<ChannelModeName, CMODE_END * 2> mlock_off; /* Modes mlocked off */ + ModeList mode_locks; public: /** Default constructor @@ -241,51 +252,51 @@ class CoreExport ChannelInfo : public Extensible, public Flags<ChannelInfoFlag, void LoadMLock(); /** Check if a mode is mlocked - * @param Name The mode + * @param mode The mode + * @param An optional param * @param status True to check mlock on, false for mlock off * @return true on success, false on fail */ - bool HasMLock(ChannelModeName Name, bool status) const; + bool HasMLock(ChannelMode *mode, const Anope::string ¶m, bool status) const; /** Set a mlock - * @param Name The mode + * @param mode The mode * @param status True for mlock on, false for mlock off * @param param An optional param arg for + mlocked modes + * @param setter Who is setting the mlock + * @param created When the mlock was created * @return true on success, false on failure (module blocking) */ - bool SetMLock(ChannelModeName Name, bool status, const Anope::string ¶m = ""); + bool SetMLock(ChannelMode *mode, bool status, const Anope::string ¶m = "", const Anope::string &setter = "", time_t created = Anope::CurTime); /** Remove a mlock - * @param Name The mode - * @return true on success, false on failure (module blcoking) + * @param mode The mode + * @param param The param of the mode, required if it is a list or status mode + * @return true on success, false on failure */ - bool RemoveMLock(ChannelModeName Name); + bool RemoveMLock(ChannelMode *mode, const Anope::string ¶m = ""); /** Clear all mlocks on the channel */ void ClearMLock(); - /** Get the number of mlocked modes for this channel - * @param status true for mlock on, false for mlock off - * @return The number of mlocked modes - */ - size_t GetMLockCount(bool status) const; - - /** Get a param from the channel - * @param Name The mode - * @param Target a string to put the param into - * @return true on success + /** Get all of the mlocks for this channel + * @return The mlocks */ - bool GetParam(ChannelModeName Name, Anope::string &Target) const; + const std::multimap<ChannelModeName, ModeLock> &GetMLock() const; - /** Check if a mode is set and has a param - * @param Name The mode + /** Get a list of modes on a channel + * @param Name The mode name to get a list of + * @return a pair of iterators for the beginning and end of the list */ - bool HasParam(ChannelModeName Name) const; + std::pair<ModeList::iterator, ModeList::iterator> GetModeList(ChannelModeName Name); - /** Clear all the params from the channel + /** Get details for a specific mlock + * @param name The mode name + * @param An optional param to match with + * @return The MLock, if any */ - void ClearParams(); + ModeLock *GetMLock(ChannelModeName name, const Anope::string ¶m = ""); /** Check whether a user is permitted to be on this channel * @param u The user diff --git a/include/services.h b/include/services.h index 38abf931f..4d2401883 100644 --- a/include/services.h +++ b/include/services.h @@ -453,9 +453,6 @@ struct IRCDVar int svsmode_ucmode; /* Can remove User Channel Modes with SVSMODE */ int sglineenforce; int ts6; /* ircd is TS6 */ - int cidrchanbei; /* channel bans/excepts/invites support CIDR (syntax: +b *!*@192.168.0.0/15) - * 0 for no support, 1 for strict cidr support, anything else - * for ircd specific support (nefarious only cares about first /mask) */ const char *globaltldprefix; /* TLD prefix used for Global */ unsigned maxmodes; /* Max modes to send per line */ }; @@ -636,7 +633,6 @@ enum ChannelAccess CA_AUTOVOICE, CA_OPDEOP, /* ChanServ commands OP and DEOP */ CA_ACCESS_LIST, - CA_CLEAR, CA_NOJOIN, /* Maximum */ CA_ACCESS_CHANGE, CA_MEMO, @@ -662,6 +658,7 @@ enum ChannelAccess CA_BANME, CA_BAN, CA_TOPIC, + CA_MODE, CA_INFO, CA_AUTOOWNER, CA_OWNER, @@ -756,7 +753,7 @@ struct LevelInfo enum EntryType { ENTRYTYPE_NONE, - ENTRYTYPE_CIDR4, + ENTRYTYPE_CIDR, ENTRYTYPE_NICK_WILD, ENTRYTYPE_NICK, ENTRYTYPE_USER_WILD, @@ -767,17 +764,27 @@ enum EntryType class Entry : public Flags<EntryType> { + Anope::string mask; + public: - Entry *next, *prev; - uint32 cidr_ip; /* IP mask for CIDR matching */ - uint32 cidr_mask; /* Netmask for CIDR matching */ - Anope::string nick, user, host, mask; -}; + unsigned char cidr_len; + Anope::string nick, user, host; -struct EList -{ - Entry *entries; - int32 count; + /** Constructor + * @param _host A full nick!ident@host/cidr mask + */ + Entry(const Anope::string &_host); + + /** Get the banned mask for this entry + * @return The mask + */ + const Anope::string GetMask(); + + /** Check if this entry matches a user + * @param u The user + * @return true on match + */ + bool Matches(User *u) const; }; /*************************************************************************/ diff --git a/include/sockets.h b/include/sockets.h index a24e346d7..c9e5bfed0 100644 --- a/include/sockets.h +++ b/include/sockets.h @@ -80,6 +80,18 @@ union CoreExport sockaddrs void ntop(int type, const void *src); }; +class CoreExport cidr +{ + sockaddrs addr; + Anope::string cidr_ip; + unsigned char cidr_len; + public: + cidr(const Anope::string &ip); + cidr(const Anope::string &ip, unsigned char len); + Anope::string mask() const; + bool match(sockaddrs &other); +}; + class SocketException : public CoreException { public: diff --git a/include/users.h b/include/users.h index 6aed13548..d9f47792f 100644 --- a/include/users.h +++ b/include/users.h @@ -139,6 +139,10 @@ class CoreExport User : public Extensible */ Anope::string GetMask() const; + /** Get the full display mask (nick!vident@vhost/chost) + */ + Anope::string GetDisplayedMask() const; + /** Updates the realname of the user record. */ void SetRealname(const Anope::string &realname); diff --git a/modules/core/cs_clearusers.cpp b/modules/core/cs_clearusers.cpp index 55c6f684e..028c7e5d6 100644 --- a/modules/core/cs_clearusers.cpp +++ b/modules/core/cs_clearusers.cpp @@ -28,15 +28,9 @@ class CommandCSClearUsers : public Command ChannelInfo *ci = c ? c->ci : NULL; Anope::string modebuf; - ChannelMode *owner = ModeManager::FindChannelModeByName(CMODE_OWNER); - ChannelMode *admin = ModeManager::FindChannelModeByName(CMODE_PROTECT); - ChannelMode *op = ModeManager::FindChannelModeByName(CMODE_OP); - ChannelMode *halfop = ModeManager::FindChannelModeByName(CMODE_HALFOP); - ChannelMode *voice = ModeManager::FindChannelModeByName(CMODE_VOICE); - if (!c) u->SendMessage(ChanServ, CHAN_X_NOT_IN_USE, chan.c_str()); - else if (!check_access(u, ci, CA_CLEAR)) + else if (!check_access(u, ci, CA_FOUNDER)) u->SendMessage(ChanServ, ACCESS_DENIED); Anope::string buf = "CLEAR USERS command from " + u->nick + " (" + u->Account()->display + ")"; @@ -55,18 +49,18 @@ class CommandCSClearUsers : public Command bool OnHelp(User *u, const Anope::string &subcommand) { - u->SendMessage(ChanServ, CHAN_HELP_CLEAR); + u->SendMessage(ChanServ, CHAN_HELP_CLEARUSERS); return true; } void OnSyntaxError(User *u, const Anope::string &subcommand) { - SyntaxError(ChanServ, u, "CLEAR", CHAN_CLEAR_SYNTAX); + SyntaxError(ChanServ, u, "CLEAR", CHAN_CLEARUSERS_SYNTAX); } void OnServHelp(User *u) { - u->SendMessage(ChanServ, CHAN_HELP_CMD_CLEAR); + u->SendMessage(ChanServ, CHAN_HELP_CMD_CLEARUSERS); } }; diff --git a/modules/core/cs_forbid.cpp b/modules/core/cs_forbid.cpp index ef55439b2..25fd90868 100644 --- a/modules/core/cs_forbid.cpp +++ b/modules/core/cs_forbid.cpp @@ -63,12 +63,16 @@ class CommandCSForbid : public Command ci->forbidby = u->nick; ci->forbidreason = reason; - if ((c = findchan(ci->name))) + if ((c = ci->c)) { /* Before banning everyone, it might be prudent to clear +e and +I lists.. * to prevent ppl from rejoining.. ~ Viper */ - c->ClearExcepts(); - c->ClearInvites(); + std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> modes = c->GetModeList(CMODE_EXCEPT); + for (; modes.first != modes.second; ++modes.first) + c->RemoveMode(NULL, CMODE_EXCEPT, modes.first->second); + modes = c->GetModeList(CMODE_INVITEOVERRIDE); + for (; modes.first != modes.second; ++modes.first) + c->RemoveMode(NULL, CMODE_INVITEOVERRIDE, modes.first->second); for (CUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end; ) { diff --git a/modules/core/cs_info.cpp b/modules/core/cs_info.cpp index d9c507505..0df02ff43 100644 --- a/modules/core/cs_info.cpp +++ b/modules/core/cs_info.cpp @@ -66,7 +66,8 @@ class CommandCSInfo : public Command u->SendMessage(ChanServ, CHAN_INFO_TIME_REGGED, do_strftime(ci->time_registered).c_str()); u->SendMessage(ChanServ, CHAN_INFO_LAST_USED, do_strftime(ci->last_used).c_str()); - if (!ci->last_topic.empty() && (show_all || (!ci->HasMLock(CMODE_SECRET, true) && (!ci->c || !ci->c->HasMode(CMODE_SECRET))))) + ModeLock *secret = ci->GetMLock(CMODE_SECRET); + if (!ci->last_topic.empty() && (show_all || ((!secret || secret->set == false) && (!ci->c || !ci->c->HasMode(CMODE_SECRET))))) { u->SendMessage(ChanServ, CHAN_INFO_LAST_TOPIC, ci->last_topic.c_str()); u->SendMessage(ChanServ, CHAN_INFO_TOPIC_SET_BY, ci->last_topic_setter.c_str()); diff --git a/modules/core/cs_mode.cpp b/modules/core/cs_mode.cpp new file mode 100644 index 000000000..e92a76988 --- /dev/null +++ b/modules/core/cs_mode.cpp @@ -0,0 +1,306 @@ +/* ChanServ core functions + * + * (C) 2003-2010 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + */ + +/*************************************************************************/ + +#include "module.h" + +class CommandCSMode : public Command +{ + void DoLock(User *u, ChannelInfo *ci, const std::vector<Anope::string> ¶ms) + { + const Anope::string &subcommand = params[2]; + const Anope::string ¶m = params.size() > 3 ? params[3] : ""; + + if (subcommand.equals_ci("ADD") && !param.empty()) + { + spacesepstream sep(param); + Anope::string modes; + + sep.GetToken(modes); + + int adding = -1; + for (size_t i = 0; i < modes.length(); ++i) + { + switch (modes[i]) + { + case '+': + adding = 1; + break; + case '-': + adding = 0; + break; + default: + if (adding == -1) + break; + ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]); + if (!cm || !cm->CanSet(u)) + { + u->SendMessage(ChanServ, CHAN_MODE_LOCK_UNKNOWN, modes[i]); + break; + } + Anope::string mode_param; + if (((cm->Type == MODE_STATUS || cm->Type == MODE_LIST) && !sep.GetToken(mode_param)) || (cm->Type == MODE_PARAM && adding && !sep.GetToken(mode_param))) + u->SendMessage(ChanServ, CHAN_MODE_LOCK_MISSING_PARAM, cm->ModeChar); + else + { + ci->SetMLock(cm, adding, mode_param, u->nick); + if (!mode_param.empty()) + mode_param = " " + mode_param; + u->SendMessage(ChanServ, CHAN_MODE_LOCKED, adding ? '+' : '-', cm->ModeChar, mode_param.c_str(), ci->name.c_str()); + } + } + } + + if (ci->c) + check_modes(ci->c); + } + else if (subcommand.equals_ci("DEL") && !param.empty()) + { + spacesepstream sep(param); + Anope::string modes; + + sep.GetToken(modes); + + int adding = -1; + for (size_t i = 0; i < modes.length(); ++i) + { + switch (modes[i]) + { + case '+': + adding = 1; + break; + case '-': + adding = 0; + break; + default: + if (adding == -1) + break; + ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]); + if (!cm || !cm->CanSet(u)) + { + u->SendMessage(ChanServ, CHAN_MODE_LOCK_UNKNOWN, modes[i]); + break; + } + Anope::string mode_param; + if (!cm->Type == MODE_REGULAR && !sep.GetToken(mode_param)) + u->SendMessage(ChanServ, CHAN_MODE_LOCK_MISSING_PARAM, cm->ModeChar); + else + { + if (ci->RemoveMLock(cm, mode_param)) + { + if (!mode_param.empty()) + mode_param = " " + mode_param; + u->SendMessage(ChanServ, CHAN_MODE_UNLOCKED, adding == 1 ? '+' : '-', cm->ModeChar, mode_param.c_str(), ci->name.c_str()); + } + else + u->SendMessage(ChanServ, CHAN_MODE_NOT_LOCKED, cm->ModeChar, ci->name.c_str()); + } + } + } + } + else if (subcommand.equals_ci("LIST")) + { + const std::multimap<ChannelModeName, ModeLock> &mlocks = ci->GetMLock(); + if (mlocks.empty()) + { + u->SendMessage(ChanServ, CHAN_MODE_LOCK_NONE, ci->name.c_str()); + } + else + { + u->SendMessage(ChanServ, CHAN_MODE_LOCK_HEADER, ci->name.c_str()); + for (std::multimap<ChannelModeName, ModeLock>::const_iterator it = mlocks.begin(), it_end = mlocks.end(); it != it_end; ++it) + { + const ModeLock &ml = it->second; + ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); + if (!cm) + continue; + + Anope::string modeparam = ml.param; + if (!modeparam.empty()) + modeparam = " " + modeparam; + Anope::string setter = ml.setter; + if (setter.empty()) + setter = ci->founder ? ci->founder->display : "Unknown"; + u->SendMessage(ChanServ, CHAN_MODE_LIST_FMT, ml.set ? '+' : '-', cm->ModeChar, modeparam.c_str(), setter.c_str(), do_strftime(ml.created).c_str()); + } + } + } + else + this->OnSyntaxError(u, subcommand); + } + + void DoSet(User *u, ChannelInfo *ci, const std::vector<Anope::string> ¶ms) + { + spacesepstream sep(params.size() > 3 ? params[3] : ""); + Anope::string modes = params[2], param; + + Log(LOG_COMMAND, u, this, ci) << "to set " << params[2]; + + int adding = -1; + for (size_t i = 0; i < modes.length(); ++i) + { + switch (modes[i]) + { + case '+': + adding = 1; + break; + case '-': + adding = 0; + break; + case '*': + if (adding == -1) + break; + for (std::map<Anope::string, Mode *>::const_iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) + { + Mode *m = it->second; + if (m->Class == MC_CHANNEL) + { + ChannelMode *cm = debug_cast<ChannelMode *>(m); + if (cm->Type == MODE_REGULAR || (!adding && cm->Type == MODE_PARAM)) + { + if (!cm->CanSet(u)) + continue; + if (adding) + ci->c->SetMode(NULL, cm); + else + ci->c->RemoveMode(NULL, cm); + } + } + } + break; + default: + if (adding == -1) + break; + ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]); + if (!cm || !cm->CanSet(u)) + continue; + switch (cm->Type) + { + case MODE_REGULAR: + if (adding) + ci->c->SetMode(NULL, cm); + else + ci->c->RemoveMode(NULL, cm); + break; + case MODE_PARAM: + if (adding && !sep.GetToken(param)) + break; + if (adding) + ci->c->SetMode(NULL, cm, param); + else + ci->c->RemoveMode(NULL, cm); + break; + case MODE_STATUS: + if (!sep.GetToken(param)) + break; + if (str_is_wildcard(param)) + { + for (CUserList::const_iterator it = ci->c->users.begin(), it_end = ci->c->users.end(); it != it_end; ++it) + { + UserContainer *uc = *it; + + if (Anope::Match(u->GetMask(), param)) + { + if (adding) + ci->c->SetMode(NULL, cm, uc->user->nick); + else + ci->c->RemoveMode(NULL, cm, uc->user->nick); + } + } + } + else + { + if (adding) + ci->c->SetMode(NULL, cm, param); + else + ci->c->RemoveMode(NULL, cm, param); + } + break; + case MODE_LIST: + if (!sep.GetToken(param)) + break; + if (adding) + ci->c->SetMode(NULL, cm, param); + else + { + std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> its = ci->c->GetModeList(cm->Name); + for (; its.first != its.second;) + { + const Anope::string &mask = its.first->second; + ++its.first; + + if (Anope::Match(mask, param)) + ci->c->RemoveMode(NULL, cm, mask); + } + } + } + } + } + } + + public: + CommandCSMode() : Command("MODE", 3, 4) + { + } + + CommandReturn Execute(User *u, const std::vector<Anope::string> ¶ms) + { + const Anope::string &subcommand = params[1]; + + ChannelInfo *ci = cs_findchan(params[0]); + + if (!ci || !ci->c) + u->SendMessage(ChanServ, CHAN_X_NOT_IN_USE, ci->name.c_str()); + else if (!check_access(u, ci, CA_MODE) && !u->Account()->HasCommand("chanserv/mode")) + u->SendMessage(ChanServ, ACCESS_DENIED); + else if (subcommand.equals_ci("LOCK")) + this->DoLock(u, ci, params); + else if (subcommand.equals_ci("SET")) + this->DoSet(u, ci, params); + else + this->OnSyntaxError(u, ""); + + return MOD_CONT; + } + + bool OnHelp(User *u, const Anope::string &subcommand) + { + u->SendMessage(ChanServ, CHAN_HELP_MODE); + return true; + } + + void OnSyntaxError(User *u, const Anope::string &subcommand) + { + SyntaxError(ChanServ, u, "MODE", CHAN_MODE_SYNTAX); + } + + void OnServHelp(User *u) + { + u->SendMessage(ChanServ, CHAN_HELP_CMD_MODE); + } +}; + +class CSMode : public Module +{ + CommandCSMode commandcsmode; + + public: + CSMode(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator) + { + this->SetAuthor("Anope"); + this->SetType(CORE); + + this->AddCommand(ChanServ, &commandcsmode); + } +}; + +MODULE_INIT(CSMode) diff --git a/modules/core/cs_set.cpp b/modules/core/cs_set.cpp index 04721cab8..e9774ba42 100644 --- a/modules/core/cs_set.cpp +++ b/modules/core/cs_set.cpp @@ -44,7 +44,7 @@ class CommandCSSet : public Command // XXX Remove after 1.9.4 release if (params[1].equals_ci("MLOCK")) { - u->SendMessage(ChanServ, CHAN_SET_MLOCK_DEPRECATED); + u->SendMessage(ChanServ, CHAN_SET_MLOCK_DEPRECATED, Config->s_ChanServ.c_str()); return MOD_CONT; } diff --git a/modules/core/cs_set_persist.cpp b/modules/core/cs_set_persist.cpp index bee71f95e..1a567ef83 100644 --- a/modules/core/cs_set_persist.cpp +++ b/modules/core/cs_set_persist.cpp @@ -61,7 +61,7 @@ class CommandCSSetPersist : public Command if (ci->c && !ci->c->HasMode(CMODE_PERM)) ci->c->SetMode(NULL, cm); /* Add it to the channels mlock */ - ci->SetMLock(CMODE_PERM, true); + ci->SetMLock(cm, true); } } @@ -81,7 +81,7 @@ class CommandCSSetPersist : public Command if (ci->c && ci->c->HasMode(CMODE_PERM)) ci->c->RemoveMode(NULL, cm); /* Remove from mlock */ - ci->RemoveMLock(CMODE_PERM); + ci->RemoveMLock(cm); } /* No channel mode, no BotServ, but using ChanServ as the botserv bot diff --git a/modules/core/db_plain.cpp b/modules/core/db_plain.cpp index d6f7963d5..5db485fc8 100644 --- a/modules/core/db_plain.cpp +++ b/modules/core/db_plain.cpp @@ -258,7 +258,6 @@ ChannelLevel ChannelLevels[] = { {"AUTOVOICE", CA_AUTOVOICE}, {"OPDEOP", CA_OPDEOP}, {"ACCESS_LIST", CA_ACCESS_LIST}, - {"CLEAR", CA_CLEAR}, {"NOJOIN", CA_NOJOIN}, {"ACCESS_CHANGE", CA_ACCESS_CHANGE}, {"MEMO", CA_MEMO}, @@ -749,6 +748,16 @@ class DBPlain : public Module /* For now store mlocked modes in extensible, Anope hasn't yet connected to the IRCd and doesn't know what modes exist */ ci->Extend("db_mlp", new ExtensibleItemRegular<std::vector<std::pair<Anope::string, Anope::string> > >(mlp)); } + else if (key.equals_ci("MLP_OFF")) + { + std::vector<std::pair<Anope::string, Anope::string> > mlp; + ci->GetExtRegular("db_mlp_off", mlp); + + mlp.push_back(std::make_pair(params[0], params[1])); + + /* For now store mlocked modes in extensible, Anope hasn't yet connected to the IRCd and doesn't know what modes exist */ + ci->Extend("db_mlp_off", new ExtensibleItemRegular<std::vector<std::pair<Anope::string, Anope::string> > >(mlp)); + } else if (key.equals_ci("MI")) { Memo *m = new Memo; @@ -972,30 +981,29 @@ class DBPlain : public Module db << ci->GetAkick(k)->reason; db << endl; } - if (ci->GetMLockCount(true)) + db << "MD MLOCK_ON"; { - db << "MD MLOCK_ON"; - Anope::string oldmodes; if ((!Me || !Me->IsSynced()) && ci->GetExtRegular("db_mlock_modes_on", oldmodes)) - { db << " " << oldmodes; - } else { - for (std::map<char, ChannelMode *>::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + for (std::map<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) { - ChannelMode *cm = it->second; - if (ci->HasMLock(cm->Name, true)) + const ModeLock &ml = it->second; + if (ml.set) + { + ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); + if (!cm || cm->Type != MODE_REGULAR) + continue; db << " " << cm->NameAsString; + } } } - db << endl; } - if (ci->GetMLockCount(false)) + db << endl; + db << "MD MLOCK_OFF"; { - db << "MD MLOCK_OFF"; - Anope::string oldmodes; if ((!Me || !Me->IsSynced()) && ci->GetExtRegular("db_mlock_modes_off", oldmodes)) { @@ -1003,32 +1011,41 @@ class DBPlain : public Module } else { - for (std::map<char, ChannelMode *>::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + for (std::map<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) { - ChannelMode *cm = it->second; - if (ci->HasMLock(cm->Name, false)) + const ModeLock &ml = it->second; + if (!ml.set) + { + ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); + if (!cm || cm->Type != MODE_REGULAR) + continue; db << " " << cm->NameAsString; + } } } - db << endl; } - std::vector<std::pair<Anope::string, Anope::string> > oldparams;; - if ((!Me || !Me->IsSynced()) && ci->GetExtRegular("db_mlp", oldparams)) + db << endl; { - for (std::vector<std::pair<Anope::string, Anope::string> >::iterator it = oldparams.begin(), it_end = oldparams.end(); it != it_end; ++it) + std::vector<std::pair<Anope::string, Anope::string> > oldparams;; + if ((!Me || !Me->IsSynced()) && ci->GetExtRegular("db_mlp", oldparams)) { - db << "MD MLP " << it->first << " " << it->second << endl; + for (std::vector<std::pair<Anope::string, Anope::string> >::iterator it = oldparams.begin(), it_end = oldparams.end(); it != it_end; ++it) + { + db << "MD MLP " << it->first << " " << it->second << endl; + } } - } - else - { - for (std::map<char, ChannelMode *>::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + else { - ChannelMode *cm = it->second; - Anope::string Param; + for (std::map<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) + { + const ModeLock &ml = it->second; + ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); + if (!cm) + continue; - if (ci->GetParam(cm->Name, Param)) - db << "MD MLP " << cm->NameAsString << " " << Param << endl; + if (!ml.param.empty()) + db << "MD MLP" << (ml.set ? " " : "_OFF ") << cm->NameAsString << " " << ml.param << endl; + } } } MemoInfo *memos = &ci->memos; diff --git a/modules/core/os_defcon.cpp b/modules/core/os_defcon.cpp index e17a6d33a..cfc8ebe62 100644 --- a/modules/core/os_defcon.cpp +++ b/modules/core/os_defcon.cpp @@ -207,7 +207,7 @@ class OSDefcon : public Module EventReturn OnPreCommandRun(User *u, BotInfo *bi, Anope::string &command, Anope::string &message, bool fantasy) { - if (!is_oper(u) && CheckDefCon(DEFCON_OPER_ONLY) || CheckDefCon(DEFCON_SILENT_OPER_ONLY)) + if (!is_oper(u) && (CheckDefCon(DEFCON_OPER_ONLY) || CheckDefCon(DEFCON_SILENT_OPER_ONLY))) { if (!CheckDefCon(DEFCON_SILENT_OPER_ONLY)) u->SendMessage(bi, OPER_DEFCON_DENIED); diff --git a/modules/extra/db_mysql.cpp b/modules/extra/db_mysql.cpp index 147a35229..e49676658 100644 --- a/modules/extra/db_mysql.cpp +++ b/modules/extra/db_mysql.cpp @@ -203,11 +203,16 @@ static Anope::string MakeMLock(ChannelInfo *ci, bool status) ; else { - for (std::map<char, ChannelMode *>::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + for (std::map<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) { - ChannelMode *cm = it->second; - if (ci->HasMLock(cm->Name, status)) + const ModeLock &ml = it->second; + if (ml.set == status) + { + ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); + if (!cm || cm->Type != MODE_REGULAR) + continue; ret += " " + cm->NameAsString; + } } if (!ret.empty()) @@ -227,12 +232,12 @@ static inline Anope::string GetMLockOff(ChannelInfo *ci) return MakeMLock(ci, false); } -static Anope::string GetMLockParams(ChannelInfo *ci) +static Anope::string GetMLockParams(ChannelInfo *ci, bool onoff) { Anope::string ret; std::vector<std::pair<Anope::string, Anope::string> > oldparams;; - if ((!Me || !Me->IsSynced()) && ci->GetExtRegular("db_mlp", oldparams)) + if ((!Me || !Me->IsSynced()) && ci->GetExtRegular(onoff ? "db_mlp" : "db_mlp_off", oldparams)) { for (std::vector<std::pair<Anope::string, Anope::string> >::iterator it = oldparams.begin(), it_end = oldparams.end(); it != it_end; ++it) { @@ -241,13 +246,16 @@ static Anope::string GetMLockParams(ChannelInfo *ci) } else { - for (std::map<char, ChannelMode *>::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + for (std::map<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) { - ChannelMode *cm = it->second; + const ModeLock &ml = it->second; - Anope::string param; - if (ci->GetParam(cm->Name, param)) - ret += " " + cm->NameAsString + " " + param; + if (!ml.param.empty() && ml.set == onoff) + { + ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); + if (cm) + ret += " " + cm->NameAsString + " " + ml.param; + } } } @@ -661,10 +669,21 @@ class DBMySQL : public Module spacesepstream sep(r.Get(i, "mlock_params")); Anope::string buf, buf2; while (sep.GetToken(buf) && sep.GetToken(buf2)) - mlp.push_back(std::make_pair(Anope::string(buf), Anope::string(buf2))); + mlp.push_back(std::make_pair(buf, buf2)); ci->Extend("db_mlp", new ExtensibleItemRegular<std::vector<std::pair<Anope::string, Anope::string> > >(mlp)); } + if (!r.Get(i, "mlock_params_off").empty()) + { + std::vector<std::pair<Anope::string, Anope::string> > mlp; + + spacesepstream sep(r.Get(i, "mlock_params_off")); + Anope::string buf, buf2; + while (sep.GetToken(buf) && sep.GetToken(buf2)) + mlp.push_back(std::make_pair(buf, buf2)); + + ci->Extend("db_mlp_off", new ExtensibleItemRegular<std::vector<std::pair<Anope::string, Anope::string> > >(mlp)); + } if (!r.Get(i, "flags").empty()) { @@ -1022,7 +1041,8 @@ class DBMySQL : public Module { this->RunQuery("UPDATE `anope_cs_info` SET `mlock_on` = '" + GetMLockOn(ci) + "' WHERE `name` = '" + this->Escape(ci->name) + "'"); this->RunQuery("UPDATE `anope_cs_info` SET `mlock_off` = '" + GetMLockOff(ci) + "' WHERE `name` = '" + this->Escape(ci->name) + "'"); - this->RunQuery("UPDATE `anope_cs_info` SET `mlock_params` = '" + GetMLockParams(ci) + "' WHERE `name` = '" + this->Escape(ci->name) + "'"); + this->RunQuery("UPDATE `anope_cs_info` SET `mlock_params` = '" + GetMLockParams(ci, true) + "' WHERE `name` = '" + this->Escape(ci->name) + "'"); + this->RunQuery("UPDATE `anope_cs_info` SET `mlock_params_off` = '" + GetMLockParams(ci, false) + "' WHERE `name` = '" + this->Escape(ci->name) + "'"); } else if (params[1].equals_ci("BANTYPE")) { @@ -1240,14 +1260,14 @@ class DBMySQL : public Module void OnChanRegistered(ChannelInfo *ci) { - Anope::string flags = BuildFlagsList(ci), mlockon = GetMLockOn(ci), mlockoff = GetMLockOff(ci), mlockparams = GetMLockParams(ci); - this->RunQuery("INSERT INTO `anope_cs_info` (name, founder, successor, descr, time_registered, last_used, last_topic, last_topic_setter, last_topic_time, flags, forbidby, forbidreason, bantype, mlock_on, mlock_off, mlock_params, entry_message, memomax, botnick, botflags, capsmin, capspercent, floodlines, floodsecs, repeattimes) VALUES('" + + Anope::string flags = BuildFlagsList(ci), mlockon = GetMLockOn(ci), mlockoff = GetMLockOff(ci), mlockparams = GetMLockParams(ci, true), mlockparams_off = GetMLockParams(ci, false); + this->RunQuery("INSERT INTO `anope_cs_info` (name, founder, successor, descr, time_registered, last_used, last_topic, last_topic_setter, last_topic_time, flags, forbidby, forbidreason, bantype, mlock_on, mlock_off, mlock_params, mlock_params_off, entry_message, memomax, botnick, botflags, capsmin, capspercent, floodlines, floodsecs, repeattimes) VALUES('" + this->Escape(ci->name) + "', '" + this->Escape(ci->founder ? ci->founder->display : "") + "', '" + this->Escape(ci->successor ? ci->successor->display : "") + "', '" + this->Escape(ci->desc) + "', " + stringify(ci->time_registered) + ", " + stringify(ci->last_used) + ", '" + this->Escape(ci->last_topic) + "', '" + this->Escape(ci->last_topic_setter) + "', " + stringify(ci->last_topic_time) + ", '" + flags + "', '" + this->Escape(ci->forbidby) + "', '" + this->Escape(ci->forbidreason) + "', " + stringify(ci->bantype) + ", '" + - mlockon + "', '" + mlockoff + "', '" + mlockparams + "', '" + this->Escape(ci->entry_message) + "', " + + mlockon + "', '" + mlockoff + "', '" + mlockparams + "', '" + mlockparams_off + "', '" + this->Escape(ci->entry_message) + "', " + stringify(ci->memos.memomax) + ", '" + this->Escape(ci->bi ? ci->bi->nick : "") + "', '" + GetBotFlags(ci->botflags) + "', " + stringify(ci->capsmin) + ", " + stringify(ci->capspercent) + ", " + stringify(ci->floodlines) + ", " + stringify(ci->floodsecs) + ", " + stringify(ci->repeattimes) + ") " + "ON DUPLICATE KEY UPDATE founder=VALUES(founder), successor=VALUES(successor), descr=VALUES(descr), time_registered=VALUES(time_registered), last_used=VALUES(last_used), last_topic=VALUES(last_topic), last_topic_setter=VALUES(last_topic_setter), last_topic_time=VALUES(last_topic_time), flags=VALUES(flags), forbidby=VALUES(forbidby), forbidreason=VALUES(forbidreason), bantype=VALUES(bantype), mlock_on=VALUES(mlock_on), mlock_off=VALUES(mlock_off), mlock_params=VALUES(mlock_params), entry_message=VALUES(entry_message), memomax=VALUES(memomax), botnick=VALUES(botnick), botflags=VALUES(botflags), capsmin=VALUES(capsmin), capspercent=VALUES(capspercent), floodlines=VALUES(floodlines), floodsecs=VALUES(floodsecs), repeattimes=VALUES(repeattimes)"); diff --git a/modules/extra/m_xmlrpc_main.cpp b/modules/extra/m_xmlrpc_main.cpp index 1053523b8..74b570ee2 100644 --- a/modules/extra/m_xmlrpc_main.cpp +++ b/modules/extra/m_xmlrpc_main.cpp @@ -174,27 +174,23 @@ class MyXMLRPCEvent : public XMLRPCEvent if (c) { - request->reply("bancount", stringify((c && c->bans ? c->bans->count : 0))); - if (c->bans && c->bans->count) - { - int i = 0; - for (Entry *entry = c->bans->entries; entry; entry = entry->next, ++i) - request->reply("ban" + stringify(i), iface->Sanitize(entry->mask)); - } - request->reply("exceptcount", stringify((c && c->excepts ? c->excepts->count : 0))); - if (c->excepts && c->excepts->count) - { - int i = 0; - for (Entry *entry = c->excepts->entries; entry; entry = entry->next, ++i) - request->reply("except" + stringify(i), iface->Sanitize(entry->mask)); - } - request->reply("invitecount", stringify((c && c->invites ? c->invites->count : 0))); - if (c->invites && c->invites->count) - { - int i = 0; - for (Entry *entry = c->invites->entries; entry; entry = entry->next, ++i) - request->reply("invite" + stringify(i), iface->Sanitize(entry->mask)); - } + request->reply("bancount", stringify(c->HasMode(CMODE_BAN))); + int count = 0; + std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> its = c->GetModeList(CMODE_BAN); + for (; its.first != its.second; ++its.first) + request->reply("ban" + stringify(++count), iface->Sanitize(its.first->second)); + + request->reply("exceptcount", stringify(c->HasMode(CMODE_EXCEPT))); + count = 0; + its = c->GetModeList(CMODE_EXCEPT); + for (; its.first != its.second; ++its.first) + request->reply("except" + stringify(++count), iface->Sanitize(its.first->second)); + + request->reply("invitecount", stringify(c->HasMode(CMODE_INVITEOVERRIDE))); + count = 0; + its = c->GetModeList(CMODE_INVITEOVERRIDE); + for (; its.first != its.second; ++its.first) + request->reply("invite" + stringify(++count), iface->Sanitize(its.first->second)); Anope::string users; for (CUserList::const_iterator it = c->users.begin(); it != c->users.end(); ++it) diff --git a/modules/protocol/bahamut.cpp b/modules/protocol/bahamut.cpp index 70dffb8ce..e2a5b2af7 100644 --- a/modules/protocol/bahamut.cpp +++ b/modules/protocol/bahamut.cpp @@ -37,7 +37,6 @@ IRCDVar myIrcd[] = { 0, /* Can remove User Channel Modes with SVSMODE */ 0, /* Sglines are not enforced until user reconnects */ 0, /* ts6 */ - 0, /* CIDR channelbans */ "$", /* TLD Prefix for Global */ 6, /* Max number of modes we can send per line */ } diff --git a/modules/protocol/inspircd11.cpp b/modules/protocol/inspircd11.cpp index 7d1d456ac..f7a13ad7a 100644 --- a/modules/protocol/inspircd11.cpp +++ b/modules/protocol/inspircd11.cpp @@ -38,7 +38,6 @@ IRCDVar myIrcd[] = { 0, /* Can remove User Channel Modes with SVSMODE */ 0, /* Sglines are not enforced until user reconnects */ 0, /* ts6 */ - 1, /* CIDR channelbans */ "$", /* TLD Prefix for Global */ 20, /* Max number of modes we can send per line */ } diff --git a/modules/protocol/inspircd12.cpp b/modules/protocol/inspircd12.cpp index c4c5fa558..196c748cf 100644 --- a/modules/protocol/inspircd12.cpp +++ b/modules/protocol/inspircd12.cpp @@ -38,7 +38,6 @@ IRCDVar myIrcd[] = { 0, /* Can remove User Channel Modes with SVSMODE */ 0, /* Sglines are not enforced until user reconnects */ 1, /* ts6 */ - 1, /* CIDR channelbans */ "$", /* TLD Prefix for Global */ 20, /* Max number of modes we can send per line */ } diff --git a/modules/protocol/inspircd20.cpp b/modules/protocol/inspircd20.cpp index ea696c15a..848590b2d 100644 --- a/modules/protocol/inspircd20.cpp +++ b/modules/protocol/inspircd20.cpp @@ -38,7 +38,6 @@ IRCDVar myIrcd[] = { 0, /* Can remove User Channel Modes with SVSMODE */ 0, /* Sglines are not enforced until user reconnects */ 1, /* ts6 */ - 1, /* CIDR channelbans */ "$", /* TLD Prefix for Global */ 20, /* Max number of modes we can send per line */ } diff --git a/modules/protocol/ratbox.cpp b/modules/protocol/ratbox.cpp index 9b5f02e46..0e034aa00 100644 --- a/modules/protocol/ratbox.cpp +++ b/modules/protocol/ratbox.cpp @@ -37,7 +37,6 @@ IRCDVar myIrcd[] = { 0, /* Can remove User Channel Modes with SVSMODE */ 0, /* Sglines are not enforced until user reconnects */ 1, /* ts6 */ - 0, /* CIDR channelbans */ "$$", /* TLD Prefix for Global */ 4, /* Max number of modes we can send per line */ } @@ -626,26 +625,20 @@ bool event_bmask(const Anope::string &source, const std::vector<Anope::string> & if (c) { + ChannelMode *ban = ModeManager::FindChannelModeByName(CMODE_BAN), + *except = ModeManager::FindChannelModeByName(CMODE_EXCEPT), + *invex = ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE); Anope::string bans = params[3]; int count = myNumToken(bans, ' '), i; for (i = 0; i <= count - 1; ++i) { Anope::string b = myStrGetToken(bans, ' ', i); - if (params[2].equals_cs("b")) - { - ChannelModeList *cml = debug_cast<ChannelModeList *>(ModeManager::FindChannelModeByChar('b')); - cml->AddMask(c, b); - } - else if (params[2].equals_cs("e")) - { - ChannelModeList *cml = debug_cast<ChannelModeList *>(ModeManager::FindChannelModeByChar('e')); - cml->AddMask(c, b); - } - if (params[2].equals_cs("I")) - { - ChannelModeList *cml = debug_cast<ChannelModeList *>(ModeManager::FindChannelModeByChar('I')); - cml->AddMask(c, b); - } + if (ban && params[2].equals_cs("b")) + c->SetModeInternal(ban, b); + else if (except && params[2].equals_cs("e")) + c->SetModeInternal(except, b); + if (invex && params[2].equals_cs("I")) + c->SetModeInternal(invex, b); } } return true; diff --git a/modules/protocol/unreal32.cpp b/modules/protocol/unreal32.cpp index 074bd5f62..70e03cf55 100644 --- a/modules/protocol/unreal32.cpp +++ b/modules/protocol/unreal32.cpp @@ -37,7 +37,6 @@ IRCDVar myIrcd[] = { 1, /* Can remove User Channel Modes with SVSMODE */ 0, /* Sglines are not enforced until user reconnects */ 0, /* ts6 */ - 0, /* CIDR channelbans */ "$", /* TLD Prefix for Global */ 12, /* Max number of modes we can send per line */ } @@ -986,36 +985,30 @@ bool event_sjoin(const Anope::string &source, const std::vector<Anope::string> & c->SetModesInternal(NULL, modes); } + ChannelMode *ban = ModeManager::FindChannelModeByName(CMODE_BAN), + *except = ModeManager::FindChannelModeByName(CMODE_EXCEPT), + *invex = ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE); spacesepstream sep(params[params.size() - 1]); Anope::string buf; while (sep.GetToken(buf)) { /* Ban */ - if (keep_their_modes && buf[0] == '&') + if (keep_their_modes && ban && buf[0] == '&') { buf.erase(buf.begin()); - ChannelModeList *cml = debug_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_BAN)); - - if (cml->IsValid(buf)) - cml->AddMask(c, buf); + c->SetModeInternal(ban, buf); } /* Except */ - else if (keep_their_modes && buf[0] == '"') + else if (keep_their_modes && except && buf[0] == '"') { buf.erase(buf.begin()); - ChannelModeList *cml = debug_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_EXCEPT)); - - if (cml->IsValid(buf)) - cml->AddMask(c, buf); + c->SetModeInternal(except, buf); } /* Invex */ - else if (keep_their_modes && buf[0] == '\'') + else if (keep_their_modes && invex && buf[0] == '\'') { buf.erase(buf.begin()); - ChannelModeList *cml = debug_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE)); - - if (cml->IsValid(buf)) - cml->AddMask(c, buf); + c->SetModeInternal(invex, buf); } else { diff --git a/src/actions.cpp b/src/actions.cpp index 4bb3563e5..6b3a96a24 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -71,28 +71,29 @@ void kill_user(const Anope::string &source, const Anope::string &user, const Ano */ void common_unban(ChannelInfo *ci, const Anope::string &nick) { - //uint32 ip = 0; - User *u; - Entry *ban, *next; - if (!ci || !ci->c || nick.empty()) return; - if (!(u = finduser(nick))) + User *u = finduser(nick); + if (!u) return; - if (!ci->c->bans || !ci->c->bans->count) + if (!ci->c->HasMode(CMODE_BAN)) return; if (ircd->svsmode_unban) ircdproto->SendBanDel(ci->c, nick); else - for (ban = ci->c->bans->entries; ban; ban = next) + { + std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> bans = ci->c->GetModeList(CMODE_BAN); + for (; bans.first != bans.second;) { - next = ban->next; - if (entry_match(ban, u->nick, u->GetIdent(), u->host, /*ip XXX */ 0) || entry_match(ban, u->nick, u->GetIdent(), u->GetDisplayedHost(), /*ip XXX */0)) - ci->c->RemoveMode(NULL, CMODE_BAN, ban->mask); + Entry ban(bans.first->second); + ++bans.first; + if (ban.Matches(u)) + ci->c->RemoveMode(NULL, CMODE_BAN, ban.GetMask()); } + } } /*************************************************************************/ diff --git a/src/bots.cpp b/src/bots.cpp index 9b2cfddb6..3d57afe6e 100644 --- a/src/bots.cpp +++ b/src/bots.cpp @@ -141,28 +141,24 @@ void BotInfo::Join(Channel *c, bool update_ts) { if (Config->BSSmartJoin) { + std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> bans = c->GetModeList(CMODE_BAN); + /* We check for bans */ - if (c->bans && c->bans->count) + for (; bans.first != bans.second; ++bans.first) { - Entry *ban, *next; - - for (ban = c->bans->entries; ban; ban = next) - { - next = ban->next; - - if (entry_match(ban, this->nick, this->GetIdent(), this->host, 0)) - c->RemoveMode(NULL, CMODE_BAN, ban->mask); - } + Entry ban(bans.first->second); + if (ban.Matches(this)) + c->RemoveMode(NULL, CMODE_BAN, ban.GetMask()); + } - Anope::string Limit; - unsigned limit = 0; - if (c->GetParam(CMODE_LIMIT, Limit) && Limit.is_pos_number_only()) - limit = convertTo<unsigned>(Limit); + Anope::string Limit; + unsigned limit = 0; + if (c->GetParam(CMODE_LIMIT, Limit) && Limit.is_pos_number_only()) + limit = convertTo<unsigned>(Limit); - /* Should we be invited? */ - if (c->HasMode(CMODE_INVITE) || (limit && c->users.size() >= limit)) - ircdproto->SendNoticeChanops(this, c, "%s invited %s into the channel.", this->nick.c_str(), this->nick.c_str()); - } + /* Should we be invited? */ + if (c->HasMode(CMODE_INVITE) || (limit && c->users.size() >= limit)) + ircdproto->SendNoticeChanops(this, c, "%s invited %s into the channel.", this->nick.c_str(), this->nick.c_str()); ModeManager::ProcessModes(); } diff --git a/src/channels.cpp b/src/channels.cpp index 72e573029..27d804c18 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -28,7 +28,6 @@ Channel::Channel(const Anope::string &nname, time_t ts) ChannelList[this->name] = this; this->creation_time = ts; - this->bans = this->excepts = this->invites = NULL; this->server_modetime = this->chanserv_modetime = 0; this->server_modecount = this->chanserv_modecount = this->bouncy_modes = this->topic_time = 0; @@ -57,27 +56,12 @@ Channel::~Channel() if (this->ci) this->ci->c = NULL; - if (this->bans && this->bans->count) - while (this->bans->entries) - entry_delete(this->bans, this->bans->entries); - - if (ModeManager::FindChannelModeByName(CMODE_EXCEPT) && this->excepts && this->excepts->count) - while (this->excepts->entries) - entry_delete(this->excepts, this->excepts->entries); - - if (ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE) && this->invites && this->invites->count) - while (this->invites->entries) - entry_delete(this->invites, this->invites->entries); - ChannelList.erase(this->name); } void Channel::Reset() { - this->ClearModes(NULL, false); - this->ClearBans(NULL, false); - this->ClearExcepts(NULL, false); - this->ClearInvites(NULL, false); + this->modes.clear(); for (CUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it) { @@ -294,11 +278,27 @@ bool Channel::HasUserStatus(User *u, ChannelModeName Name) const /** * See if a channel has a mode * @param Name The mode name - * @return true or false + * @param param The optional mode param + * @return The number of modes set */ -bool Channel::HasMode(ChannelModeName Name) const +size_t Channel::HasMode(ChannelModeName Name, const Anope::string ¶m) { - return modes.HasFlag(Name); + if (param.empty()) + return modes.count(Name); + std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> its = this->GetModeList(Name); + for (; its.first != its.second; ++its.first) + if (its.first->second == param) + return 1; + return 0; +} + +/** Get a list of modes on a channel + * @param Name A mode name to get the list of + * @return a pair of iterators for the beginning and end of the list + */ +std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> Channel::GetModeList(ChannelModeName Name) +{ + return std::make_pair(this->modes.find(Name), this->modes.upper_bound(Name)); } /** Set a mode internally on a channel, this is not sent out to the IRCd @@ -346,36 +346,21 @@ void Channel::SetModeInternal(ChannelMode *cm, const Anope::string ¶m, bool chan_set_correct_modes(u, this, 0); return; } - /* Setting b/e/I etc */ - else if (cm->Type == MODE_LIST) - { - if (param.empty()) - { - Log() << "Channel::SetModeInternal() mode " << cm->ModeChar << " with no parameter for channel " << this->name; - return; - } - ChannelModeList *cml = debug_cast<ChannelModeList *>(cm); - cml->AddMask(this, param); + if (cm->Type != MODE_LIST) + this->modes.erase(cm->Name); + this->modes.insert(std::make_pair(cm->Name, param)); + + if (param.empty() && cm->Type != MODE_REGULAR) + { + Log() << "Channel::SetModeInternal() mode " << cm->ModeChar << " for " << this->name << " with a paramater, but its not a param mode"; return; } - modes.SetFlag(cm->Name); - - if (!param.empty()) + if (cm->Type == MODE_LIST) { - if (cm->Type != MODE_PARAM) - { - Log() << "Channel::SetModeInternal() mode " << cm->ModeChar << " for " << this->name << " with a paramater, but its not a param mode"; - return; - } - - /* They could be resetting the mode to change its params */ - std::map<ChannelModeName, Anope::string>::iterator it = Params.find(cm->Name); - if (it != Params.end()) - Params.erase(it); - - Params.insert(std::make_pair(cm->Name, param)); + ChannelModeList *cml = debug_cast<ChannelModeList *>(cm); + cml->OnAdd(this, param); } /* Channel mode +P or so was set, mark this channel as persistant */ @@ -398,33 +383,34 @@ void Channel::SetModeInternal(ChannelMode *cm, const Anope::string ¶m, bool if (!ci) return; - /* If this channel has this mode locked negative */ - if (ci->HasMLock(cm->Name, false)) + ModeLock *ml = ci->GetMLock(cm->Name, param); + if (ml) { - /* Remove the mode */ - if (cm->Type == MODE_PARAM) + if (ml->set && cm->Type == MODE_PARAM) { Anope::string cparam; - GetParam(cm->Name, cparam); - RemoveMode(NULL, cm, cparam); + this->GetParam(cm->Name, cparam); + + /* We have the wrong param set */ + if (cparam.empty() || ml->param.empty() || !cparam.equals_cs(ml->param)) + /* Reset the mode with the correct param */ + this->SetMode(NULL, cm, ml->param); + } + else if (!ml->set) + { + if (cm->Type == MODE_REGULAR) + this->RemoveMode(NULL, cm); + else if (cm->Type == MODE_PARAM) + { + Anope::string cparam; + this->GetParam(cm->Name, cparam); + this->RemoveMode(NULL, cm, cparam); + } + else if (cm->Type == MODE_LIST) + { + this->RemoveMode(NULL, cm, param); + } } - 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 = debug_cast<ChannelModeParam *>(cm); - Anope::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.equals_cs(ciparam)) - /* Reset the mode with the correct param */ - SetMode(NULL, cm, ciparam); } } @@ -475,29 +461,29 @@ void Channel::RemoveModeInternal(ChannelMode *cm, const Anope::string ¶m, bo this->SetMode(bi, cm, bi->nick); } + /* Enforce secureops, etc */ + if (EnforceMLock) + chan_set_correct_modes(u, this, 1); return; } - /* Setting b/e/I etc */ - else if (cm->Type == MODE_LIST) - { - if (param.empty()) - { - Log() << "Channel::RemoveModeInternal() mode " << cm->ModeChar << " with no parameter for channel " << this->name; - return; - } - ChannelModeList *cml = debug_cast<ChannelModeList *>(cm); - cml->DelMask(this, param); - return; + if (cm->Type == MODE_LIST && !param.empty()) + { + std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> its = this->GetModeList(cm->Name); + for (; its.first != its.second; ++its.first) + if (Anope::Match(param, its.first->second)) + { + this->modes.erase(its.first); + break; + } } - - modes.UnsetFlag(cm->Name); - - if (cm->Type == MODE_PARAM) + else + this->modes.erase(cm->Name); + + if (cm->Type == MODE_LIST) { - std::map<ChannelModeName, Anope::string>::iterator it = Params.find(cm->Name); - if (it != Params.end()) - Params.erase(it); + ChannelModeList *cml = debug_cast<ChannelModeList *>(cm); + cml->OnDel(this, param); } if (cm->Name == CMODE_PERM) @@ -525,22 +511,14 @@ void Channel::RemoveModeInternal(ChannelMode *cm, const Anope::string ¶m, bo if (!ci || !EnforceMLock || MOD_RESULT == EVENT_STOP) return; + ModeLock *ml = ci->GetMLock(cm->Name, param); /* This channel has this the mode locked on */ - if (ci->HasMLock(cm->Name, true)) + if (ml && ml->set) { if (cm->Type == MODE_REGULAR) - { - /* Set the mode */ - SetMode(NULL, cm); - } - /* This is a param mode */ - else if (cm->Type == MODE_PARAM) - { - Anope::string cparam; - /* Get the param stored in mlock for this mode */ - if (ci->GetParam(cm->Name, cparam)) - SetMode(NULL, cm, cparam); - } + this->SetMode(NULL, cm); + else if (cm->Type == MODE_PARAM || cm->Type == MODE_LIST) + this->SetMode(NULL, cm, ml->param); } } @@ -557,8 +535,12 @@ void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶m, /* Don't set modes already set */ if (cm->Type == MODE_REGULAR && HasMode(cm->Name)) return; - else if (cm->Type == MODE_PARAM && HasMode(cm->Name)) + else if (cm->Type == MODE_PARAM) { + ChannelModeParam *cmp = debug_cast<ChannelModeParam *>(cm); + if (!cmp->IsValid(param)) + return; + Anope::string cparam; if (GetParam(cm->Name, cparam) && cparam.equals_cs(param)) return; @@ -571,7 +553,9 @@ void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶m, } else if (cm->Type == MODE_LIST) { - // XXX this needs rewritten + ChannelModeList *cml = debug_cast<ChannelModeList *>(cm); + if (this->HasMode(cm->Name, param) || !cml->IsValid(param)) + return; } ModeManager::StackerAdd(bi, this, cm, true, param); @@ -612,20 +596,22 @@ void Channel::RemoveMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶ } else if (cm->Type == MODE_LIST) { - // XXX this needs to be rewritten sometime + if (!this->HasMode(cm->Name, param)) + return; } - /* If this mode needs no param when being unset, empty the param */ - bool SendParam = true; + /* Get the param to send, if we need it */ + Anope::string realparam = param; if (cm->Type == MODE_PARAM) { + realparam.clear(); ChannelModeParam *cmp = debug_cast<ChannelModeParam *>(cm); - if (cmp->MinusNoArg) - SendParam = false; + if (!cmp->MinusNoArg) + this->GetParam(cmp->Name, realparam); } - ModeManager::StackerAdd(bi, this, cm, false, param); - RemoveModeInternal(cm, SendParam ? param : "", EnforceMLock); + ModeManager::StackerAdd(bi, this, cm, false, realparam); + RemoveModeInternal(cm, realparam, EnforceMLock); } /** @@ -647,11 +633,11 @@ void Channel::RemoveMode(BotInfo *bi, ChannelModeName Name, const Anope::string */ bool Channel::GetParam(ChannelModeName Name, Anope::string &Target) const { - std::map<ChannelModeName, Anope::string>::const_iterator it = Params.find(Name); + std::multimap<ChannelModeName, Anope::string>::const_iterator it = this->modes.find(Name); Target.clear(); - if (it != Params.end()) + if (it != this->modes.end()) { Target = it->second; return true; @@ -660,121 +646,8 @@ bool Channel::GetParam(ChannelModeName Name, Anope::string &Target) const return false; } -/** Check if a mode is set and has a param - * @param Name The mode - */ -bool Channel::HasParam(ChannelModeName Name) const -{ - std::map<ChannelModeName, Anope::string>::const_iterator it = Params.find(Name); - - if (it != Params.end()) - return true; - - return false; -} - /*************************************************************************/ -/** Clear all the modes from the channel - * @param bi The client setting the modes - * @param internal Only remove the modes internally - */ -void Channel::ClearModes(BotInfo *bi, bool internal) -{ - for (size_t n = CMODE_BEGIN + 1; n != CMODE_END; ++n) - { - ChannelMode *cm = ModeManager::FindChannelModeByName(static_cast<ChannelModeName>(n)); - - if (cm && this->HasMode(cm->Name)) - { - if (cm->Type == MODE_REGULAR) - { - if (!internal) - this->RemoveMode(NULL, cm); - else - this->RemoveModeInternal(cm); - } - else if (cm->Type == MODE_PARAM) - { - Anope::string param; - this->GetParam(cm->Name, param); - if (!internal) - this->RemoveMode(NULL, cm, param); - else - this->RemoveModeInternal(cm, param); - } - } - } - - modes.ClearFlags(); -} - -/** Clear all the bans from the channel - * @param bi The client setting the modes - * @param internal Only remove the modes internally - */ -void Channel::ClearBans(BotInfo *bi, bool internal) -{ - Entry *entry, *nexte; - - ChannelModeList *cml = debug_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_BAN)); - - if (cml && this->bans && this->bans->count) - for (entry = this->bans->entries; entry; entry = nexte) - { - nexte = entry->next; - - if (!internal) - this->RemoveMode(bi, cml, entry->mask); - else - this->RemoveModeInternal(cml, entry->mask); - } -} - -/** Clear all the excepts from the channel - * @param bi The client setting the modes - * @param internal Only remove the modes internally - */ -void Channel::ClearExcepts(BotInfo *bi, bool internal) -{ - Entry *entry, *nexte; - - ChannelModeList *cml = debug_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_EXCEPT)); - - if (cml && this->excepts && this->excepts->count) - for (entry = this->excepts->entries; entry; entry = nexte) - { - nexte = entry->next; - - if (!internal) - this->RemoveMode(bi, cml, entry->mask); - else - this->RemoveModeInternal(cml, entry->mask); - } -} - -/** Clear all the invites from the channel - * @param bi The client setting the modes - * @param internal Only remove the modes internally - */ -void Channel::ClearInvites(BotInfo *bi, bool internal) -{ - Entry *entry, *nexte; - - ChannelModeList *cml = debug_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE)); - - if (cml && this->invites && this->invites->count) - for (entry = this->invites->entries; entry; entry = nexte) - { - nexte = entry->next; - - if (!internal) - this->RemoveMode(bi, cml, entry->mask); - else - this->RemoveModeInternal(cml, 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 @@ -980,45 +853,26 @@ bool Channel::Kick(BotInfo *bi, User *u, const char *reason, ...) Anope::string Channel::GetModes(bool complete, bool plus) { - Anope::string res; + Anope::string res, params; - if (this->HasModes()) + for (std::multimap<ChannelModeName, Anope::string>::const_iterator it = this->modes.begin(), it_end = this->modes.end(); it != it_end; ++it) { - Anope::string params; - for (std::map<Anope::string, Mode *>::const_iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) - { - if (it->second->Class != MC_CHANNEL) - continue; + ChannelMode *cm = ModeManager::FindChannelModeByName(it->first); + if (!cm || cm->Type == MODE_LIST) + continue; - ChannelMode *cm = debug_cast<ChannelMode *>(it->second); + res += cm->ModeChar; - if (this->HasMode(cm->Name)) - { - res += cm->ModeChar; + if (complete && !it->second.empty()) + { + ChannelModeParam *cmp = debug_cast<ChannelModeParam *>(cm); - if (complete) - { - if (cm->Type == MODE_PARAM) - { - ChannelModeParam *cmp = debug_cast<ChannelModeParam *>(cm); - - if (plus || !cmp->MinusNoArg) - { - Anope::string param; - this->GetParam(cmp->Name, param); - - if (!param.empty()) - params += " " + param; - } - } - } - } + if (plus || !cmp->MinusNoArg) + params += " " + it->second; } - - res += params; } - return res; + return res + params; } void Channel::ChangeTopicInternal(const Anope::string &user, const Anope::string &newtopic, time_t ts) @@ -1083,17 +937,6 @@ void get_channel_stats(long *nrec, long *memuse) mem += sizeof(*chan); if (!chan->topic.empty()) mem += chan->topic.length() + 1; - if (chan->GetParam(CMODE_KEY, buf)) - mem += buf.length() + 1; - if (chan->GetParam(CMODE_FLOOD, buf)) - mem += buf.length() + 1; - if (chan->GetParam(CMODE_REDIRECT, buf)) - mem += buf.length() + 1; - mem += get_memuse(chan->bans); - if (ModeManager::FindChannelModeByName(CMODE_EXCEPT)) - mem += get_memuse(chan->excepts); - if (ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE)) - mem += get_memuse(chan->invites); for (CUserList::iterator it = chan->users.begin(), it_end = chan->users.end(); it != it_end; ++it) { mem += sizeof(*it); @@ -1355,6 +1198,26 @@ void chan_set_correct_modes(User *user, Channel *c, int give_modes) if (halfop && c->HasUserStatus(user, CMODE_HALFOP) && !check_access(user, ci, CA_AUTOHALFOP) && !check_access(user, ci, CA_HALFOPME)) c->RemoveMode(NULL, CMODE_HALFOP, user->nick); } + + // Check mlock + for (std::multimap<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) + { + const ModeLock &ml = it->second; + ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); + if (!cm || cm->Type != MODE_STATUS) + continue; + + if (Anope::Match(user->nick, ml.param) || Anope::Match(user->GetDisplayedMask(), ml.param)) + { + if ((ml.set && !c->HasUserStatus(user, ml.name)) || (!ml.set && c->HasUserStatus(user, ml.name))) + { + if (ml.set && give_modes) + c->SetMode(NULL, cm, user->nick, false); + else if (!ml.set && !give_modes) + c->RemoveMode(NULL, cm, user->nick, false); + } + } + } } /*************************************************************************/ @@ -1376,382 +1239,137 @@ void MassChannelModes(BotInfo *bi, const Anope::string &modes) } } -/*************************************************************************/ - -/** - * This handles creating a new Entry. - * This function destroys and free's the given mask as a side effect. - * @param mask Host/IP/CIDR mask to convert to an entry - * @return Entry struct for the given mask, NULL if creation failed +/** Constructor + * @param _host A full nick!ident@host/cidr mask */ -Entry *entry_create(const Anope::string &mask) +Entry::Entry(const Anope::string &_host) { - Entry *entry; - Anope::string cidrhost; - uint32 ip, cidr; - - entry = new Entry; - entry->SetFlag(ENTRYTYPE_NONE); - entry->prev = NULL; - entry->next = NULL; - entry->mask = mask; - - Anope::string newmask = mask, host, nick, user; + this->SetFlag(ENTRYTYPE_NONE); + this->cidr_len = 0; + this->mask = _host; - size_t at = newmask.find('@'); + Anope::string _nick, _user, _realhost; + size_t at = _host.find('@'); if (at != Anope::string::npos) { - host = newmask.substr(at + 1); - newmask = newmask.substr(0, at); - /* If the user is purely a wildcard, ignore it */ - if (!str_is_pure_wildcard(newmask)) + _realhost = _host.substr(at + 1); + Anope::string _nickident = _host.substr(0, at); + + size_t ex = _nickident.find('!'); + if (ex != Anope::string::npos) { - /* There might be a nick too */ - //user = strchr(mask, '!'); - size_t ex = newmask.find('!'); - if (ex != Anope::string::npos) - { - user = newmask.substr(ex + 1); - newmask = newmask.substr(0, ex); - /* If the nick is purely a wildcard, ignore it */ - if (!str_is_pure_wildcard(newmask)) - nick = newmask; - } - else - user = newmask; + _user = _nickident.substr(ex + 1); + _nick = _nickident.substr(0, ex); } + else + _user = _nickident; } else - /* It is possibly an extended ban/invite mask, but we do - * not support these at this point.. ~ Viper */ - /* If there's no user in the mask, assume a pure wildcard */ - host = newmask; - - if (!nick.empty()) + _realhost = _host; + + if (!_nick.empty() && !str_is_pure_wildcard(_nick)) { - entry->nick = nick; - /* Check if we have a wildcard user */ - if (str_is_wildcard(nick)) - entry->SetFlag(ENTRYTYPE_NICK_WILD); + this->nick = _nick; + if (str_is_wildcard(_nick)) + this->SetFlag(ENTRYTYPE_NICK_WILD); else - entry->SetFlag(ENTRYTYPE_NICK); + this->SetFlag(ENTRYTYPE_NICK); } - if (!user.empty()) + if (!_user.empty() && !str_is_pure_wildcard(_user)) { - entry->user = user; - /* Check if we have a wildcard user */ - if (str_is_wildcard(user)) - entry->SetFlag(ENTRYTYPE_USER_WILD); + this->user = _user; + if (str_is_wildcard(_user)) + this->SetFlag(ENTRYTYPE_USER_WILD); else - entry->SetFlag(ENTRYTYPE_USER); + this->SetFlag(ENTRYTYPE_USER); } - /* Only check the host if it's not a pure wildcard */ - if (!host.empty() && !str_is_pure_wildcard(host)) + if (!_realhost.empty() && !str_is_pure_wildcard(_realhost)) { - if (ircd->cidrchanbei && str_is_cidr(host, ip, cidr, cidrhost)) - { - entry->cidr_ip = ip; - entry->cidr_mask = cidr; - entry->SetFlag(ENTRYTYPE_CIDR4); - host = cidrhost; - } - else if (ircd->cidrchanbei && host.find('/') != Anope::string::npos) + size_t sl = _realhost.find_last_of('/'); + if (sl != Anope::string::npos) { - /* Most IRCd's don't enforce sane bans therefore it is not - * so unlikely we will encounter this. - * Currently we only support strict CIDR without taking into - * account quirks of every single ircd (nef) that ignore everything - * after the first /cidr. To add this, sanitaze before sending to - * str_is_cidr() as this expects a standard cidr. - * Add it to the internal list (so it is included in for example clear) - * but do not use if during matching.. ~ Viper */ - entry->ClearFlags(); - entry->SetFlag(ENTRYTYPE_NONE); - } - else - { - entry->host = host; - if (str_is_wildcard(host)) - entry->SetFlag(ENTRYTYPE_HOST_WILD); - else - entry->SetFlag(ENTRYTYPE_HOST); - } - } - - return entry; -} - -/** - * Create an entry and add it at the beginning of given list. - * @param list The List the mask should be added to - * @param mask The mask to parse and add to the list - * @return Pointer to newly added entry. NULL if it fails. - */ -Entry *entry_add(EList *list, const Anope::string &mask) -{ - Entry *e; - - e = entry_create(mask); - - if (!e) - return NULL; - - e->next = list->entries; - e->prev = NULL; - - if (list->entries) - list->entries->prev = e; - list->entries = e; - ++list->count; - - return e; -} - -/** - * Delete the given entry from a given list. - * @param list Linked list from which entry needs to be removed. - * @param e The entry to be deleted, must be member of list. - */ -void entry_delete(EList *list, Entry *e) -{ - if (!list || !e) - return; - - if (e->next) - e->next->prev = e->prev; - if (e->prev) - e->prev->next = e->next; - - if (list->entries == e) - list->entries = e->next; - - delete e; - - --list->count; -} - -/** - * Create and initialize a new entrylist - * @return Pointer to the created EList object - **/ -EList *list_create() -{ - EList *list; - - list = new EList; - list->entries = NULL; - list->count = 0; - - return list; -} - -/** - * Match the given Entry to the given user/host and optional IP addy - * @param e Entry struct to match against - * @param nick Nick to match against - * @param user User to match against - * @param host Host to match against - * @param ip IP to match against, set to 0 to not match this - * @return 1 for a match, 0 for no match - */ -int entry_match(Entry *e, const Anope::string &nick, const Anope::string &user, const Anope::string &host, uint32 ip) -{ - /* If we don't get an entry, or it s an invalid one, no match ~ Viper */ - if (!e || !e->FlagCount()) - return 0; - - if (ircd->cidrchanbei && e->HasFlag(ENTRYTYPE_CIDR4) && (!ip || (ip && (ip & e->cidr_mask) != e->cidr_ip))) - return 0; - if (e->HasFlag(ENTRYTYPE_NICK) && (nick.empty() || !e->nick.equals_ci(nick))) - return 0; - if (e->HasFlag(ENTRYTYPE_USER) && (user.empty() || !e->user.equals_ci(user))) - return 0; - if (e->HasFlag(ENTRYTYPE_HOST) && (host.empty() || !e->host.equals_ci(host))) - return 0; - if (e->HasFlag(ENTRYTYPE_NICK_WILD) && !Anope::Match(nick, e->nick)) - return 0; - if (e->HasFlag(ENTRYTYPE_USER_WILD) && !Anope::Match(user, e->user)) - return 0; - if (e->HasFlag(ENTRYTYPE_HOST_WILD) && !Anope::Match(host, e->host)) - return 0; - - return 1; -} - -/** - * Match the given Entry to the given hostmask and optional IP addy. - * @param e Entry struct to match against - * @param mask Hostmask to match against - * @param ip IP to match against, set to 0 to not match this - * @return 1 for a match, 0 for no match - */ -int entry_match_mask(Entry *e, const Anope::string &mask, uint32 ip) -{ - int res; - - Anope::string hostmask = mask, host, user, nick; + try + { + sockaddrs addr; + bool ipv6 = _realhost.substr(0, sl).find(':') != Anope::string::npos; + addr.pton(ipv6 ? AF_INET6 : AF_INET, _realhost.substr(0, sl)); + /* If we got here, _realhost is a valid IP */ - size_t at = hostmask.find('@'); - if (at != Anope::string::npos) - { - host = hostmask.substr(at + 1); - hostmask = hostmask.substr(0, at); - size_t ex = hostmask.find('!'); - if (ex != Anope::string::npos) - { - user = hostmask.substr(ex + 1); - nick = hostmask.substr(0, ex); + Anope::string cidr_range = _realhost.substr(sl + 1); + if (cidr_range.is_pos_number_only()) + { + _realhost = _realhost.substr(0, sl); + this->cidr_len = convertTo<unsigned int>(cidr_range); + this->SetFlag(ENTRYTYPE_CIDR); + Log(LOG_DEBUG) << "Ban " << _realhost << " has cidr " << static_cast<unsigned int>(this->cidr_len); + } + } + catch (const SocketException &) { } } - else - user = hostmask; - } - else - host = hostmask; - - res = entry_match(e, nick, user, host, ip); - - return res; -} - -/** - * Match a nick, user, host, and ip to a list entry - * @param e List that should be matched against - * @param nick The nick to match - * @param user The user to match - * @param host The host to match - * @param ip The ip to match - * @return Returns the first matching entry, if none, NULL is returned. - */ -Entry *elist_match(EList *list, const Anope::string &nick, const Anope::string &user, const Anope::string &host, uint32 ip) -{ - Entry *e; - - if (!list || !list->entries) - return NULL; - - for (e = list->entries; e; e = e->next) - if (entry_match(e, nick, user, host, ip)) - return e; - - /* We matched none */ - return NULL; -} -/** - * Match a mask and ip to a list. - * @param list EntryList that should be matched against - * @param mask The nick!user@host mask to match - * @param ip The ip to match - * @return Returns the first matching entry, if none, NULL is returned. - */ -Entry *elist_match_mask(EList *list, const Anope::string &mask, uint32 ip) -{ - Entry *res; - - if (!list || !list->entries || mask.empty()) - return NULL; + this->host = _realhost; - Anope::string hostmask = mask, host, user, nick; - - size_t at = hostmask.find('@'); - if (at != Anope::string::npos) - { - host = hostmask.substr(at + 1); - hostmask = hostmask.substr(0, at); - size_t ex = hostmask.find('!'); - if (ex != Anope::string::npos) + if (!this->HasFlag(ENTRYTYPE_CIDR)) { - user = hostmask.substr(ex + 1); - nick = hostmask.substr(0, ex); + if (str_is_wildcard(_realhost)) + this->SetFlag(ENTRYTYPE_HOST_WILD); + else + this->SetFlag(ENTRYTYPE_HOST); } - else - user = hostmask; } - else - host = hostmask; - - res = elist_match(list, nick, user, host, ip); - - return res; } -/** - * Check if a user matches an entry on a list. - * @param list EntryList that should be matched against - * @param user The user to match against the entries - * @return Returns the first matching entry, if none, NULL is returned. +/** Get the banned mask for this entry + * @return The mask */ -Entry *elist_match_user(EList *list, User *u) +const Anope::string Entry::GetMask() { - Entry *res; - //uint32 ip = 0; - - if (!list || !list->entries || !u) - return NULL; - - /* Match what we ve got against the lists.. */ - res = elist_match(list, u->nick, u->GetIdent(), u->host, /*ip XXX*/0); - if (!res) - res = elist_match(list, u->nick, u->GetIdent(), u->GetDisplayedHost(), /*ip XXX*/0); - if (!res && !u->GetCloakedHost().empty() && !u->GetCloakedHost().equals_cs(u->GetDisplayedHost())) - res = elist_match(list, u->nick, u->GetIdent(), u->GetCloakedHost(), /*ip XXX*/ 0); - - return res; + return this->mask; } -/** - * Find a entry identical to the given mask.. - * @param list EntryList that should be matched against - * @param mask The *!*@* mask to match - * @return Returns the first matching entry, if none, NULL is returned. - */ -Entry *elist_find_mask(EList *list, const Anope::string &mask) -{ - Entry *e; - - if (!list || !list->entries || mask.empty()) - return NULL; - - for (e = list->entries; e; e = e->next) - if (e->mask.equals_ci(mask)) - return e; - - return NULL; -} - -/** - * Gets the total memory use of an entrylit. - * @param list The list we should estimate the mem use of. - * @return Returns the memory useage of the given list. +/** Check if this entry matches a user + * @param u The user + * @return true on match */ -long get_memuse(EList *list) +bool Entry::Matches(User *u) const { - Entry *e; - long mem = 0; - - if (!list) + if (!this->FlagCount()) return 0; + + Anope::string _nick = u->nick; + Anope::string _user = u->GetVIdent(); + Anope::string _host = u->GetDisplayedHost(); - mem += sizeof(EList *); - mem += sizeof(Entry *) * list->count; - if (list->entries) + if (this->HasFlag(ENTRYTYPE_CIDR)) { - for (e = list->entries; e; e = e->next) + try + { + cidr cidr_mask(this->host, this->cidr_len); + if (!u->ip() || !cidr_mask.match(u->ip)) + { + return false; + } + } + catch (const SocketException &) { - if (!e->nick.empty()) - mem += e->nick.length() + 1; - if (!e->user.empty()) - mem += e->user.length() + 1; - if (!e->host.empty()) - mem += e->host.length() + 1; - if (!e->mask.empty()) - mem += e->mask.length() + 1; + return false; } } + if (this->HasFlag(ENTRYTYPE_NICK) && (_nick.empty() || !this->nick.equals_ci(_nick))) + return false; + if (this->HasFlag(ENTRYTYPE_USER) && (_user.empty() || !this->user.equals_ci(_user))) + return false; + if (this->HasFlag(ENTRYTYPE_HOST) && (_host.empty() || !this->host.equals_ci(_host))) + return false; + if (this->HasFlag(ENTRYTYPE_NICK_WILD) && !Anope::Match(_nick, this->nick)) + return false; + if (this->HasFlag(ENTRYTYPE_USER_WILD) && !Anope::Match(_user, this->user)) + return false; + if (this->HasFlag(ENTRYTYPE_HOST_WILD) && !Anope::Match(_host, this->host)) + return false; - return mem; + return true; } -/*************************************************************************/ diff --git a/src/chanserv.cpp b/src/chanserv.cpp index ca37f0cc7..ef3de90cd 100644 --- a/src/chanserv.cpp +++ b/src/chanserv.cpp @@ -24,7 +24,6 @@ static int def_levels[][2] = { { CA_INVITE, 5 }, { CA_AKICK, 10 }, { CA_SET, ACCESS_QOP }, - { CA_CLEAR, ACCESS_FOUNDER }, { CA_UNBAN, 5 }, { CA_OPDEOP, 5 }, { CA_ACCESS_LIST, 1 }, @@ -52,6 +51,7 @@ static int def_levels[][2] = { { CA_BANME, 5 }, { CA_BAN, 5 }, { CA_TOPIC, ACCESS_FOUNDER }, + { CA_MODE, ACCESS_FOUNDER }, { CA_INFO, ACCESS_QOP }, { CA_AUTOOWNER, ACCESS_QOP }, { CA_OWNER, ACCESS_FOUNDER }, @@ -74,7 +74,6 @@ LevelInfo levelinfo[] = { { CA_SET, "SET", CHAN_LEVEL_SET }, { CA_BAN, "BAN", CHAN_LEVEL_BAN }, { CA_BANME, "BANME", CHAN_LEVEL_BANME }, - { CA_CLEAR, "CLEAR", CHAN_LEVEL_CLEAR }, { CA_GETKEY, "GETKEY", CHAN_LEVEL_GETKEY }, { CA_HALFOP, "HALFOP", CHAN_LEVEL_HALFOP }, { CA_HALFOPME, "HALFOPME", CHAN_LEVEL_HALFOPME }, @@ -87,6 +86,7 @@ LevelInfo levelinfo[] = { { CA_PROTECT, "PROTECT", CHAN_LEVEL_PROTECT }, { CA_PROTECTME, "PROTECTME", CHAN_LEVEL_PROTECTME }, { CA_TOPIC, "TOPIC", CHAN_LEVEL_TOPIC }, + { CA_MODE, "MODE", CHAN_LEVEL_MODE }, { CA_UNBAN, "UNBAN", CHAN_LEVEL_UNBAN }, { CA_VOICE, "VOICE", CHAN_LEVEL_VOICE }, { CA_VOICEME, "VOICEME", CHAN_LEVEL_VOICEME }, @@ -111,59 +111,30 @@ int levelinfo_maxwidth = 0; Anope::string get_mlock_modes(ChannelInfo *ci, int complete) { - ChannelMode *cm; - ChannelModeParam *cmp; - std::map<char, ChannelMode *>::iterator it, it_end; - Anope::string res, param; + Anope::string pos = "+", neg = "-", params; - if (ci->GetMLockCount(true) || ci->GetMLockCount(false)) + for (std::map<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) { - if (ci->GetMLockCount(true)) - { - res += '+'; - - for (it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) - { - cm = it->second; - - if (ci->HasMLock(cm->Name, true)) - res += it->first; - } - } - - if (ci->GetMLockCount(false)) - { - res += '-'; - - for (it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) - { - cm = it->second; - - if (ci->HasMLock(cm->Name, false)) - res += it->first; - } - } - - if (ci->GetMLockCount(true) && complete) - { - for (it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) - { - cm = it->second; - - if (cm->Type == MODE_PARAM) - { - cmp = debug_cast<ChannelModeParam *>(cm); - - ci->GetParam(cmp->Name, param); - - if (!param.empty()) - res += " " + param; - } - } - } + const ModeLock &ml = it->second; + ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); + if (!cm) + continue; + + if (ml.set) + pos += cm->ModeChar; + else + neg += cm->ModeChar; + + if (complete && !ml.param.empty() && (cm->Type == MODE_PARAM || cm->Type == MODE_LIST)) + params += " " + ml.param; } - return res; + if (pos.length() == 1) + pos.clear(); + if (neg.length() == 1) + neg.clear(); + + return pos + neg + params; } /*************************************************************************/ @@ -173,7 +144,7 @@ Anope::string get_mlock_modes(ChannelInfo *ci, int complete) void get_chanserv_stats(long *nrec, long *memuse) { long count = 0, mem = 0; - Anope::string param; + ModeLock *ml; for (registered_channel_map::const_iterator it = RegisteredChannelList.begin(), it_end = RegisteredChannelList.end(); it != it_end; ++it) { @@ -186,14 +157,17 @@ void get_chanserv_stats(long *nrec, long *memuse) mem += ci->GetAccessCount() * sizeof(ChanAccess); mem += ci->GetAkickCount() * sizeof(AutoKick); - if (ci->GetParam(CMODE_KEY, param)) - mem += param.length() + 1; + ml = ci->GetMLock(CMODE_KEY); + if (ml && !ml->param.empty()) + mem += ml->param.length() + 1; - if (ci->GetParam(CMODE_FLOOD, param)) - mem += param.length() + 1; + ml = ci->GetMLock(CMODE_FLOOD); + if (ml && !ml->param.empty()) + mem += ml->param.length() + 1; - if (ci->GetParam(CMODE_REDIRECT, param)) - mem += param.length() + 1; + ml = ci->GetMLock(CMODE_REDIRECT); + if (ml && !ml->param.empty()) + mem += ml->param.length() + 1; if (!ci->last_topic.empty()) mem += ci->last_topic.length() + 1; @@ -237,11 +211,6 @@ void cs_init() void check_modes(Channel *c) { - ChannelInfo *ci; - ChannelMode *cm; - std::map<char, ChannelMode *>::iterator it, it_end; - Anope::string param, ciparam; - if (!c) { Log() << "check_modes called with NULL values"; @@ -268,61 +237,52 @@ void check_modes(Channel *c) c->chanserv_modecount++; /* Check if the channel is registered; if not remove mode -r */ - if (!(ci = c->ci)) + ChannelInfo *ci = c->ci; + if (!ci) { if (c->HasMode(CMODE_REGISTERED)) c->RemoveMode(NULL, CMODE_REGISTERED); return; } - for (it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + for (std::map<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) { - cm = it->second; + const ModeLock &ml = it->second; + ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); + if (!cm) + continue; - /* If this channel does not have the mode and the mode is mlocked */ - if (cm->Type == MODE_REGULAR && !c->HasMode(cm->Name) && ci->HasMLock(cm->Name, true)) + if (cm->Type == MODE_REGULAR) { - /* Add the eventual parameter and modify the Channel structure */ - if (cm->Type == MODE_PARAM) - { - if (ci->GetParam(cm->Name, ciparam)) - c->SetMode(NULL, cm, ciparam); - } - else + if (!c->HasMode(cm->Name) && ml.set) c->SetMode(NULL, cm); + else if (c->HasMode(cm->Name) && !ml.set) + c->RemoveMode(NULL, cm); } - /* If this is a param mode and its mlocked, check to ensure it is set and set to the correct value */ - else if (cm->Type == MODE_PARAM && ci->HasMLock(cm->Name, true)) + else if (cm->Type == MODE_PARAM) { + Anope::string param; c->GetParam(cm->Name, param); - ci->GetParam(cm->Name, ciparam); /* If the channel doesnt have the mode, or it does and it isn't set correctly */ - if (!c->HasMode(cm->Name) || (!param.empty() && !ciparam.empty() && !param.equals_cs(ciparam))) - c->SetMode(NULL, cm, ciparam); - } - } - - for (it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) - { - cm = it->second; - - /* If the channel has the mode */ - if (c->HasMode(cm->Name) && ci->HasMLock(cm->Name, false)) - { - /* Add the eventual parameter */ - if (cm->Type == MODE_PARAM) + if (ml.set) { - ChannelModeParam *cmp = debug_cast<ChannelModeParam *>(cm); - - if (!cmp->MinusNoArg) - { - if (c->GetParam(cmp->Name, param)) - c->RemoveMode(NULL, cm, param); - } + if (!c->HasMode(cm->Name) || (!param.empty() && !ml.param.empty() && !param.equals_cs(ml.param))) + c->SetMode(NULL, cm, ml.param); } else - c->RemoveMode(NULL, cm); + { + if (c->HasMode(cm->Name)) + c->RemoveMode(NULL, cm); + } + + } + else if (cm->Type == MODE_LIST) // XXX we still need better list code... + { + if (ml.set) + c->SetMode(NULL, cm, ml.param); + else + c->RemoveMode(NULL, cm, ml.param); } } } diff --git a/src/config.cpp b/src/config.cpp index 818021efb..6dddd7691 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -167,7 +167,7 @@ ServerConfig::ServerConfig() : errstr(""), config_data() } } - this->WallOper = this->WallBadOS = this->WallOSGlobal = this->WallOSMode = this->WallOSClearmodes = this->WallOSKick = this->WallOSAkill = this->WallOSSNLine = this->WallOSSQLine = + this->WallOper = this->WallBadOS = this->WallOSGlobal = this->WallOSMode = this->WallOSKick = this->WallOSAkill = this->WallOSSNLine = this->WallOSSQLine = this->WallOSSZLine = this->WallOSNoOp = this->WallOSJupe = this->WallAkillExpire = this->WallSNLineExpire = this->WallSQLineExpire = this->WallSZLineExpire = this->WallExceptionExpire = this->WallGetpass = this->WallSetpass = this->WallForbid = this->WallDrop = false; if (!OSNotifications.empty()) diff --git a/src/language.cpp b/src/language.cpp index 3ef010034..31eb1f1f8 100644 --- a/src/language.cpp +++ b/src/language.cpp @@ -769,6 +769,8 @@ const char *const language_strings[LANG_STRING_COUNT] = { _("Allowed to use BAN command"), /* CHAN_LEVEL_TOPIC */ _("Allowed to use TOPIC command"), + /* CHAN_LEVEL_MODE */ + _("Allowed to use MODE command"), /* CHAN_LEVEL_INFO */ _("Allowed to use INFO command with ALL option"), /* CHAN_LEVEL_AUTOOWNER */ @@ -1294,8 +1296,10 @@ const char *const language_strings[LANG_STRING_COUNT] = { _("%s has been unbanned from %s."), /* CHAN_TOPIC_SYNTAX */ _("TOPIC channel [topic]"), - /* CHAN_CLEARUSERS */ + /* CHAN_CLEARUSERS_SYNTAX */ _("CLEARUSERS \037channel\037"), + /* CHAN_CLEARED_USERS */ + _("All users have been kicked from \2%s\2."), /* CHAN_CLONED */ _("All settings from \002%s\002 have been transferred to \002%s\002"), /* CHAN_CLONED_ACCESS */ @@ -1366,6 +1370,24 @@ const char *const language_strings[LANG_STRING_COUNT] = { _("KICK #channel nick [reason]"), /* CHAN_BAN_SYNTAX */ _("BAN #channel nick [reason]"), + /* CHAN_MODE_SYNTAX */ + _("MODE \037channel\037 {LOCK|SET} [\037modes\037 | {ADD|DEL|LIST} [\037what\037]]"), + /* CHAN_MODE_LOCK_UNKNOWN */ + _("Unknown mode character %c ignored."), + /* CHAN_MODE_LOCK_MISSING_PARAM */ + _("Missing parameter for mode %c."), + /* CHAN_MODE_LOCK_NONE */ + _("Channel %s has no mode locks."), + /* CHAN_MODE_LOCK_HEADER */ + _("Mode locks for %s:"), + /* CHAN_MODE_LOCKED */ + _("%c%c%s locked on %s"), + /* CHAN_MODE_NOT_LOCKED */ + _("%c is not locked on %s."), + /* CHAN_MODE_UNLOCKED */ + _("%c%c%s has been unlocked from %s."), + /* CHAN_MODE_LIST_FMT */ + _("%c%c%s, by %s on %s"), /* MEMO_HAVE_NEW_MEMO */ _("You have 1 new memo."), /* MEMO_HAVE_NEW_MEMOS */ @@ -3338,6 +3360,8 @@ const char *const language_strings[LANG_STRING_COUNT] = { _(" DEOP Deops a selected nick on a channel"), /* CHAN_HELP_CMD_CLONE */ _(" CLONE Copy all settings from one channel to another"), + /* CHAN_HELP_CMD_MODE */ + _(" MODE Control modes and mode locks on a channel"), /* CHAN_HELP */ _("%S allows you to register and control various\n" "aspects of channels. %S can often prevent\n" @@ -4062,6 +4086,26 @@ const char *const language_strings[LANG_STRING_COUNT] = { "target channel. If access, akick, or badwords is specified then only\n" "the respective settings are transferred. You must have founder level\n" "access to \037channel\037 and \037target\037."), + /* CHAN_HELP_MODE */ + _("Syntax: \002MODE \037channel\037 LOCK {ADD|DEL|LIST} [\037what\037]\002\n" + " \002MODE \037channel\037 SET \037modes\037\002\n" + " \n" + "Mainly controls mode locks and mode access (which is different from channel access)\n" + "on a channel.\n" + " \n" + "The \002MODE LOCK\002 command allows you to add, delete, and view mode locks on a channel.\n" + "If a mode is locked on or off, services will not allow that mode to be changed.\n" + "Example:\n" + " \002MODE #channel LOCK ADD +bmnt *!*@*aol*\002\n" + " \n" + "The \002MODE SET\002 command allows you to set modes through services. Wildcards * and ? may\n" + "be given as parameters for list and status modes.\n" + "Example:\n" + " \002MODE #channel SET +v *\002\n" + " Sets voice status to all users in the channel.\n" + " \n" + " \002MODE #channel SET -b ~c:*\n" + " Clears all extended bans that start with ~c:"), /* CHAN_SERVADMIN_HELP */ _(" \n" "Services Operators can also drop any channel without needing\n" diff --git a/src/misc.cpp b/src/misc.cpp index 7e02cc072..c885188f8 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -831,6 +831,74 @@ char *str_signed(unsigned char *str) return nstr; } +bool Anope::Match(const Anope::string &str, const Anope::string &mask, bool case_sensitive) +{ + size_t s = 0, m = 0, str_len = str.length(), mask_len = mask.length(); + + while (s < str_len && m < mask_len && mask[m] != '*') + { + char string = str[s], wild = mask[m]; + if (case_sensitive) + { + if (wild != string && wild != '?') + return false; + } + else + { + if (tolower(wild) != tolower(string) && wild != '?') + return false; + } + + ++m; + ++s; + } + + size_t sp = Anope::string::npos, mp = Anope::string::npos; + while (s < str_len) + { + char string = str[s], wild = mask[m]; + if (wild == '*') + { + if (++m == mask_len) + return 1; + + mp = m; + sp = s + 1; + } + else if (case_sensitive) + { + if (wild == string || wild == '?') + { + ++m; + ++s; + } + else + { + m = mp; + s = sp++; + } + } + else + { + if (tolower(wild) == tolower(string) || wild == '?') + { + ++m; + ++s; + } + else + { + m = mp; + s = sp++; + } + } + } + + if (mask[m] == '*') + ++m; + + return m == mask_len; +} + /* * strlcat and strlcpy were ripped from openssh 2.5.1p2 * They had the following Copyright info: @@ -1107,11 +1175,7 @@ uint16 netmask_to_cidr(uint32 mask) */ bool str_is_wildcard(const Anope::string &str) { - for (Anope::string::const_iterator c = str.begin(), c_end = str.end(); c != c_end; ++c) - if (*c == '*' || *c == '?') - return true; - - return false; + return str.find_first_of("*?") != Anope::string::npos; } /** @@ -1121,11 +1185,7 @@ bool str_is_wildcard(const Anope::string &str) */ bool str_is_pure_wildcard(const Anope::string &str) { - for (Anope::string::const_iterator c = str.begin(), c_end = str.end(); c != c_end; ++c) - if (*c != '*') - return false; - - return true; + return str.find_first_not_of('*') == Anope::string::npos; } /*************************************************************************/ diff --git a/src/modes.cpp b/src/modes.cpp index 6c6d43ad9..4d31f2232 100644 --- a/src/modes.cpp +++ b/src/modes.cpp @@ -27,53 +27,42 @@ std::map<ChannelModeName, ChannelMode *> ModeManager::ChannelModesByName; /* Number of generic modes we support */ unsigned GenericChannelModes = 0, GenericUserModes = 0; -/* Default mlocked modes on */ -Flags<ChannelModeName, CMODE_END * 2> DefMLockOn; -/* Default mlocked modes off */ -Flags<ChannelModeName, CMODE_END * 2> DefMLockOff; -/* Map for default mlocked mode parameters */ -std::map<ChannelModeName, Anope::string> DefMLockParams; +/* Default mlocked modes */ +std::multimap<ChannelModeName, ModeLock> def_mode_locks; /** Parse the mode string from the config file and set the default mlocked modes */ void SetDefaultMLock(ServerConfig *config) { - DefMLockOn.ClearFlags(); - DefMLockOff.ClearFlags(); - DefMLockParams.clear(); - Flags<ChannelModeName, CMODE_END * 2> *ptr = NULL; + def_mode_locks.clear(); - Anope::string modes, param; + Anope::string modes; spacesepstream sep(config->MLock); sep.GetToken(modes); + int adding = -1; for (unsigned i = 0, end_mode = modes.length(); i < end_mode; ++i) { if (modes[i] == '+') - ptr = &DefMLockOn; + adding = 1; else if (modes[i] == '-') - ptr = &DefMLockOff; - else + adding = 0; + else if (adding != -1) { - if (!ptr) - continue; - ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]); - if (cm && (cm->Type == MODE_REGULAR || cm->Type == MODE_PARAM)) + if (cm && cm->Type != MODE_STATUS) { - ptr->SetFlag(cm->Name); - - if (ptr == &DefMLockOn && cm->Type == MODE_PARAM) + Anope::string param; + if (adding == 1 && cm->Type != MODE_REGULAR && !sep.GetToken(param)) // MODE_LIST OR MODE_PARAM { - if (sep.GetToken(param)) - DefMLockParams.insert(std::make_pair(cm->Name, param)); - else - { - Log() << "Warning: Got default mlock mode " << cm->ModeChar << " with no param?"; - ptr->UnsetFlag(cm->Name); - } + Log() << "Warning: Got default mlock mode " << cm->ModeChar << " with no param?"; + continue; } + + if (cm->Type != MODE_LIST) // Only MODE_LIST can have duplicates + def_mode_locks.erase(cm->Name); + def_mode_locks.insert(std::make_pair(cm->Name, ModeLock(adding == 1, cm->Name, param))); } } } @@ -298,36 +287,20 @@ bool ChannelModeRegistered::CanSet(User *u) const * @param chan The channel * @param mask The ban */ -void ChannelModeBan::AddMask(Channel *chan, const Anope::string &mask) +void ChannelModeBan::OnAdd(Channel *chan, const Anope::string &mask) { /* check for NULL values otherwise we will segfault */ if (!chan || mask.empty()) - { - Log() << "add_ban called with NULL values"; return; - } - - /* Check if the list already exists, if not create it. - * Create a new ban and add it to the list.. ~ Viper */ - if (!chan->bans) - chan->bans = list_create(); - Entry *ban = entry_add(chan->bans, mask); - if (!ban) - throw CoreException("Creating new ban entry failed"); - - /* Check whether it matches a botserv bot after adding internally - * and parsing it through cidr support. ~ Viper */ + /* Check whether it matches a botserv bot */ if (!Config->s_BotServ.empty() && Config->BSSmartJoin && chan->ci && chan->ci->bi && chan->FindUser(chan->ci->bi)) { BotInfo *bi = chan->ci->bi; - if (entry_match(ban, bi->nick, bi->GetIdent(), bi->host, 0)) - { - ircdproto->SendMode(bi, chan, "-b %s", mask.c_str()); - entry_delete(chan->bans, ban); - return; - } + Entry ban(mask); + if (ban.Matches(bi)) + chan->RemoveMode(NULL, CMODE_BAN, mask); } Log(LOG_DEBUG) << "Added ban " << mask << " to channel " << chan->name; @@ -337,41 +310,22 @@ void ChannelModeBan::AddMask(Channel *chan, const Anope::string &mask) * @param chan The channel * @param mask The ban */ -void ChannelModeBan::DelMask(Channel *chan, const Anope::string &mask) +void ChannelModeBan::OnDel(Channel *chan, const Anope::string &mask) { - /* Sanity check as it seems some IRCD will just send -b without a mask */ - if (mask.empty() || !chan->bans || !chan->bans->count) + if (!chan || mask.empty()) return; - Entry *ban = elist_find_mask(chan->bans, mask); - if (ban) - { - entry_delete(chan->bans, ban); - - Log(LOG_DEBUG) << "Deleted ban " << mask << " from channel " << chan->name; - } + Log(LOG_DEBUG) << "Deleted ban " << mask << " from channel " << chan->name; } /** Add an except to the channel * @param chan The channel * @param mask The except */ -void ChannelModeExcept::AddMask(Channel *chan, const Anope::string &mask) +void ChannelModeExcept::OnAdd(Channel *chan, const Anope::string &mask) { if (!chan || mask.empty()) - { - Log() << "add_exception called with NULL values"; return; - } - - /* Check if the list already exists, if not create it. - * Create a new exception and add it to the list.. ~ Viper */ - if (!chan->excepts) - chan->excepts = list_create(); - - Entry *exception = entry_add(chan->excepts, mask); - if (!exception) - throw CoreException("Creating new exception entry failed"); Log(LOG_DEBUG) << "Added except " << mask << " to channel " << chan->name; } @@ -380,40 +334,22 @@ void ChannelModeExcept::AddMask(Channel *chan, const Anope::string &mask) * @param chan The channel * @param mask The except */ -void ChannelModeExcept::DelMask(Channel *chan, const Anope::string &mask) +void ChannelModeExcept::OnDel(Channel *chan, const Anope::string &mask) { - /* Sanity check as it seems some IRCD will just send -e without a mask */ - if (mask.empty() || !chan->excepts || !chan->excepts->count) + if (!chan || mask.empty()) return; - Entry *exception = elist_find_mask(chan->excepts, mask); - if (exception) - { - entry_delete(chan->excepts, exception); - Log(LOG_DEBUG) << "Deleted except " << mask << " to channel " << chan->name; - } + Log(LOG_DEBUG) << "Deleted except " << mask << " to channel " << chan->name; } /** Add an invex to the channel * @param chan The channel * @param mask The invex */ -void ChannelModeInvex::AddMask(Channel *chan, const Anope::string &mask) +void ChannelModeInvex::OnAdd(Channel *chan, const Anope::string &mask) { if (!chan || mask.empty()) - { - Log() << "add_invite called with NULL values"; return; - } - - /* Check if the list already exists, if not create it. - * Create a new invite and add it to the list.. ~ Viper */ - if (!chan->invites) - chan->invites = list_create(); - - Entry *invite = entry_add(chan->invites, mask); - if (!invite) - throw CoreException("Creating new invex entry failed"); Log(LOG_DEBUG) << "Added invite " << mask << " to channel " << chan->name; @@ -423,18 +359,12 @@ void ChannelModeInvex::AddMask(Channel *chan, const Anope::string &mask) * @param chan The channel * @param mask The index */ -void ChannelModeInvex::DelMask(Channel *chan, const Anope::string &mask) +void ChannelModeInvex::OnDel(Channel *chan, const Anope::string &mask) { - /* Sanity check as it seems some IRCD will just send -I without a mask */ - if (mask.empty() || !chan->invites || !chan->invites->count) + if (!chan || mask.empty()) return; - Entry *invite = elist_find_mask(chan->invites, mask); - if (invite) - { - entry_delete(chan->invites, invite); - Log(LOG_DEBUG) << "Deleted invite " << mask << " to channel " << chan->name; - } + Log(LOG_DEBUG) << "Deleted invite " << mask << " to channel " << chan->name; } void StackerInfo::AddMode(Mode *mode, bool Set, const Anope::string &Param) diff --git a/src/operserv.cpp b/src/operserv.cpp index 5f6f8c2be..727432585 100644 --- a/src/operserv.cpp +++ b/src/operserv.cpp @@ -428,7 +428,18 @@ XLine *XLineManager::Check(User *u) if (!x->GetUser().empty() && !Anope::Match(u->GetIdent(), x->GetUser())) continue; - if (x->GetHost().empty() || (u->ip() && Anope::Match(u->ip.addr(), x->GetHost())) || Anope::Match(u->host, x->GetHost()) || (!u->chost.empty() && Anope::Match(u->chost, x->GetHost())) || (!u->vhost.empty() && Anope::Match(u->vhost, x->GetHost()))) + if (u->ip() && !x->GetHost().empty()) + { + try + { + cidr cidr_ip(x->GetHost()); + if (cidr_ip.match(u->ip)) + return x; + } + catch (const SocketException &) { } + } + + if (x->GetHost().empty() || (Anope::Match(u->host, x->GetHost()) || (!u->chost.empty() && Anope::Match(u->chost, x->GetHost())) || (!u->vhost.empty() && Anope::Match(u->vhost, x->GetHost())))) { OnMatch(u, x); return x; diff --git a/src/regchannel.cpp b/src/regchannel.cpp index b4c42cb82..8228e4ffb 100644 --- a/src/regchannel.cpp +++ b/src/regchannel.cpp @@ -33,9 +33,7 @@ ChannelInfo::ChannelInfo(const Anope::string &chname) this->name = chname; - this->mlock_on = DefMLockOn; - this->mlock_off = DefMLockOff; - this->Params = DefMLockParams; + this->mode_locks = def_mode_locks; size_t t; /* Set default channel flags */ @@ -392,7 +390,9 @@ void ChannelInfo::LoadMLock() std::vector<Anope::string> modenames_on, modenames_off; // Force +r - this->SetMLock(CMODE_REGISTERED, true); + ChannelMode *chm = ModeManager::FindChannelModeByName(CMODE_REGISTERED); + if (chm) + this->SetMLock(chm, true); this->GetExtRegular("db_mlock_modes_on", modenames_on); this->GetExtRegular("db_mlock_modes_off", modenames_off); @@ -405,7 +405,7 @@ void ChannelInfo::LoadMLock() if (m && m->NameAsString.equals_cs(*it)) { ChannelMode *cm = debug_cast<ChannelMode *>(m); - this->SetMLock(cm->Name, true); + this->SetMLock(cm, true); } } for (std::vector<Anope::string>::iterator it = modenames_off.begin(), it_end = modenames_off.end(); it != it_end; ++it) @@ -415,7 +415,7 @@ void ChannelInfo::LoadMLock() if (m && m->NameAsString.equals_cs(*it)) { ChannelMode *cm = debug_cast<ChannelMode *>(m); - this->SetMLock(cm->Name, false); + this->SetMLock(cm, false); } } } @@ -429,15 +429,28 @@ void ChannelInfo::LoadMLock() if (m && m->Class == MC_CHANNEL) { ChannelMode *cm = debug_cast<ChannelMode *>(m); - this->SetMLock(cm->Name, true, it->second); + this->SetMLock(cm, true, it->second); } } } + if (this->GetExtRegular("db_mlp_off", params)) + { + for (std::vector<std::pair<Anope::string, Anope::string> >::iterator it = params.begin(), it_end = params.end(); it != it_end; ++it) + { + Mode *m = ModeManager::FindModeByName(it->first); + if (m && m->Class == MC_CHANNEL) + { + ChannelMode *cm = debug_cast<ChannelMode *>(m); + this->SetMLock(cm, false, it->second); + } + } + } this->Shrink("db_mlock_modes_on"); this->Shrink("db_mlock_modes_off"); this->Shrink("db_mlp"); + this->Shrink("db_mlp_off"); /* Create perm channel */ if (this->HasFlag(CI_PERSIST) && !this->c) @@ -453,132 +466,135 @@ void ChannelInfo::LoadMLock() } /** Check if a mode is mlocked - * @param Name The mode + * @param mode The mode * @param status True to check mlock on, false for mlock off * @return true on success, false on fail */ -bool ChannelInfo::HasMLock(ChannelModeName Name, bool status) const +bool ChannelInfo::HasMLock(ChannelMode *mode, const Anope::string ¶m, bool status) const { - if (status) - return this->mlock_on.HasFlag(Name); - else - return this->mlock_off.HasFlag(Name); + std::map<ChannelModeName, ModeLock>::const_iterator it = this->mode_locks.find(mode->Name); + + if (it != this->mode_locks.end()) + { + if (mode->Type != MODE_REGULAR) + { + std::map<ChannelModeName, ModeLock>::const_iterator it_end = this->mode_locks.upper_bound(mode->Name); + for (; it != it_end; ++it) + { + const ModeLock &ml = it->second; + if (ml.param == param) + return true; + } + } + else + return it->second.set == status; + } + return false; } /** Set a mlock - * @param Name The mode + * @param mode The mode * @param status True for mlock on, false for mlock off * @param param The param to use for this mode, if required * @return true on success, false on failure (module blocking) */ -bool ChannelInfo::SetMLock(ChannelModeName Name, bool status, const Anope::string ¶m) +bool ChannelInfo::SetMLock(ChannelMode *mode, bool status, const Anope::string ¶m, const Anope::string &setter, time_t created) { - if (!status && !param.empty()) - throw CoreException("Was told to mlock a mode negatively with a param?"); + std::pair<ChannelModeName, ModeLock> ml = std::make_pair(mode->Name, ModeLock(status, mode->Name, param, setter, created)); EventReturn MOD_RESULT; - FOREACH_RESULT(I_OnMLock, OnMLock(this, Name, status, param)); + FOREACH_RESULT(I_OnMLock, OnMLock(this, &ml.second)); if (MOD_RESULT == EVENT_STOP) return false; - /* First, remove this everywhere */ - this->mlock_on.UnsetFlag(Name); - this->mlock_off.UnsetFlag(Name); - - std::map<ChannelModeName, Anope::string>::iterator it = Params.find(Name); - if (it != Params.end()) - Params.erase(it); - - if (status) - this->mlock_on.SetFlag(Name); - else - this->mlock_off.SetFlag(Name); - - if (status && !param.empty()) - this->Params.insert(std::make_pair(Name, param)); + /* First, remove this */ + this->RemoveMLock(mode, param); + + this->mode_locks.insert(ml); return true; } /** Remove a mlock - * @param Name The mode - * @return true on success, false on failure (module blocking) + * @param mode The mode + * @param param The param of the mode, required if it is a list or status mode + * @return true on success, false on failure */ -bool ChannelInfo::RemoveMLock(ChannelModeName Name) +bool ChannelInfo::RemoveMLock(ChannelMode *mode, const Anope::string ¶m) { EventReturn MOD_RESULT; - FOREACH_RESULT(I_OnUnMLock, OnUnMLock(this, Name)); + FOREACH_RESULT(I_OnUnMLock, OnUnMLock(this, mode, param)); if (MOD_RESULT == EVENT_STOP) return false; - this->mlock_on.UnsetFlag(Name); - this->mlock_off.UnsetFlag(Name); - - std::map<ChannelModeName, Anope::string>::iterator it = Params.find(Name); - if (it != Params.end()) - this->Params.erase(it); + if (mode->Type == MODE_REGULAR || mode->Type == MODE_PARAM) + return this->mode_locks.erase(mode->Name) > 0; + else + { + // For list or status modes, we must check the parameter + std::multimap<ChannelModeName, ModeLock>::iterator it = this->mode_locks.find(mode->Name), it_end = this->mode_locks.upper_bound(mode->Name); + for (; it != it_end; ++it) + { + const ModeLock &ml = it->second; + if (ml.param == param) + { + this->mode_locks.erase(it); + return true; + } + } - return true; + return false; + } } /** Clear all mlocks on the channel */ void ChannelInfo::ClearMLock() { - this->mlock_on.ClearFlags(); - this->mlock_off.ClearFlags(); + this->mode_locks.clear(); } -/** Get the number of mlocked modes for this channel - * @param status true for mlock on, false for mlock off - * @return The number of mlocked modes +/** Get all of the mlocks for this channel + * @return The mlocks */ -size_t ChannelInfo::GetMLockCount(bool status) const +const std::multimap<ChannelModeName, ModeLock> &ChannelInfo::GetMLock() const { - if (status) - return this->mlock_on.FlagCount(); - else - return this->mlock_off.FlagCount(); + return this->mode_locks; } -/** Get a param from the channel - * @param Name The mode - * @param Target a string to put the param into - * @return true on success +/** Get a list of modes on a channel + * @param Name The mode name to get a list of + * @return a pair of iterators for the beginning and end of the list */ -bool ChannelInfo::GetParam(ChannelModeName Name, Anope::string &Target) const +std::pair<ChannelInfo::ModeList::iterator, ChannelInfo::ModeList::iterator> ChannelInfo::GetModeList(ChannelModeName Name) { - std::map<ChannelModeName, Anope::string>::const_iterator it = this->Params.find(Name); - - Target.clear(); - - if (it != this->Params.end()) - { - Target = it->second; - return true; - } - - return false; + return std::make_pair(this->mode_locks.find(Name), this->mode_locks.upper_bound(Name)); } -/** Check if a mode is set and has a param - * @param Name The mode +/** Get details for a specific mlock + * @param name The mode name + * @param param An optional param to match with + * @return The MLock, if any */ -bool ChannelInfo::HasParam(ChannelModeName Name) const +ModeLock *ChannelInfo::GetMLock(ChannelModeName name, const Anope::string ¶m) { - std::map<ChannelModeName, Anope::string>::const_iterator it = this->Params.find(Name); - - if (it != this->Params.end()) - return true; - - return false; -} + std::multimap<ChannelModeName, ModeLock>::iterator it = this->mode_locks.find(name); + if (it != this->mode_locks.end()) + { + if (param.empty()) + return &it->second; + else + { + std::multimap<ChannelModeName, ModeLock>::iterator it_end = this->mode_locks.upper_bound(name); + for (; it != it_end; ++it) + { + if (Anope::Match(param, it->second.param)) + return &it->second; + } + } + } -/** Clear all the params from the channel - */ -void ChannelInfo::ClearParams() -{ - Params.clear(); + return NULL; } /** Check whether a user is permitted to be on this channel diff --git a/src/sockets.cpp b/src/sockets.cpp index 9e32f85eb..0eb7733cf 100644 --- a/src/sockets.cpp +++ b/src/sockets.cpp @@ -171,6 +171,80 @@ void sockaddrs::ntop(int type, const void *src) throw CoreException("Invalid socket type"); } +cidr::cidr(const Anope::string &ip) +{ + if (ip.find_first_not_of("01234567890:./") != Anope::string::npos) + throw SocketException("Invalid IP"); + + bool ipv6 = ip.find(':') != Anope::string::npos; + size_t sl = ip.find_last_of('/'); + if (sl == Anope::string::npos) + { + this->cidr_ip = ip; + this->cidr_len = ipv6 ? 128 : 32; + this->addr.pton(ipv6 ? AF_INET6 : AF_INET, ip); + } + else + { + Anope::string real_ip = ip.substr(0, sl); + Anope::string cidr_range = ip.substr(sl + 1); + if (!cidr_range.is_pos_number_only()) + throw SocketException("Invalid CIDR range"); + + this->cidr_ip = real_ip; + this->cidr_len = convertTo<unsigned int>(cidr_range); + this->addr.pton(ipv6 ? AF_INET6 : AF_INET, real_ip); + } +} + +cidr::cidr(const Anope::string &ip, unsigned char len) +{ + bool ipv6 = ip.find(':') != Anope::string::npos; + this->addr.pton(ipv6 ? AF_INET6 : AF_INET, ip); + this->cidr_ip = ip; + this->cidr_len = len; +} + +Anope::string cidr::mask() const +{ + return this->cidr_ip + "/" + this->cidr_len; +} + +bool cidr::match(sockaddrs &other) +{ + if (this->addr.sa.sa_family != other.sa.sa_family) + return false; + + unsigned char *ip, *their_ip, byte; + + switch (this->addr.sa.sa_family) + { + case AF_INET: + ip = reinterpret_cast<unsigned char *>(&this->addr.sa4.sin_addr); + byte = this->cidr_len / 8; + their_ip = reinterpret_cast<unsigned char *>(&other.sa4.sin_addr); + break; + case AF_INET6: + ip = reinterpret_cast<unsigned char *>(&this->addr.sa6.sin6_addr); + byte = this->cidr_len / 8; + their_ip = reinterpret_cast<unsigned char *>(&other.sa6.sin6_addr); + break; + default: + throw SocketException("Invalid address type"); + } + + if (memcmp(ip, their_ip, byte)) + return false; + + ip += byte; + their_ip += byte; + byte = this->cidr_len % 8; + if ((*ip & byte) != (*their_ip & byte)) + return false; + + return true; +} + /** Default constructor */ SocketEngineBase::SocketEngineBase() diff --git a/src/users.cpp b/src/users.cpp index 27426819b..ac16c61ac 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -165,6 +165,11 @@ Anope::string User::GetMask() const return this->nick + "!" + this->ident + "@" + this->host; } +Anope::string User::GetDisplayedMask() const +{ + return this->nick + "!" + this->GetVIdent() + "@" + this->GetDisplayedHost(); +} + void User::SetRealname(const Anope::string &srealname) { if (srealname.empty()) @@ -921,7 +926,16 @@ bool is_excepted(ChannelInfo *ci, User *user) if (!ci->c || !ModeManager::FindChannelModeByName(CMODE_EXCEPT)) return false; - return elist_match_user(ci->c->excepts, user); + + std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> modes = ci->c->GetModeList(CMODE_EXCEPT); + for (; modes.first != modes.second; ++modes.first) + { + Entry e(modes.first->second); + if (e.Matches(user)) + return true; + } + + return false; } /*************************************************************************/ @@ -932,7 +946,14 @@ bool is_excepted_mask(ChannelInfo *ci, const Anope::string &mask) if (!ci->c || !ModeManager::FindChannelModeByName(CMODE_EXCEPT)) return false; - return elist_match_mask(ci->c->excepts, mask, 0); + std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> modes = ci->c->GetModeList(CMODE_EXCEPT); + for (; modes.first != modes.second; ++modes.first) + { + if (Anope::Match(modes.first->second, mask)) + return true; + } + + return false; } /*************************************************************************/ diff --git a/src/wildcard.cpp b/src/wildcard.cpp deleted file mode 100644 index c6883a4bc..000000000 --- a/src/wildcard.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "services.h" - -bool Anope::Match(const Anope::string &str, const Anope::string &mask, bool case_sensitive) -{ - size_t s = 0, m = 0, str_len = str.length(), mask_len = mask.length(); - - while (s < str_len && m < mask_len && mask[m] != '*') - { - char string = str[s], wild = mask[m]; - if (case_sensitive) - { - if (wild != string && wild != '?') - return false; - } - else - { - if (tolower(wild) != tolower(string) && wild != '?') - return false; - } - - ++m; - ++s; - } - - size_t sp = 0, mp = 0; - while (s < str_len) - { - char string = str[s], wild = mask[m]; - if (wild == '*') - { - if (++m == mask_len) - return 1; - - mp = m; - sp = s + 1; - } - else - { - if (case_sensitive) - { - if (wild == string || wild == '?') - { - ++m; - ++s; - } - else - { - m = mp; - s = sp++; - } - } - else - { - if (tolower(wild) == tolower(string) || wild == '?') - { - ++m; - ++s; - } - else - { - m = mp; - s = sp++; - } - } - } - } - - if (mask[m] == '*') - ++m; - - return m == mask_len; -} |