diff options
90 files changed, 3994 insertions, 3567 deletions
diff --git a/data/botserv.example.conf b/data/botserv.example.conf index 1bd450123..299289416 100644 --- a/data/botserv.example.conf +++ b/data/botserv.example.conf @@ -100,13 +100,6 @@ module #smartjoin = yes /* - * Defines the prefixes for fantasy commands in channels. One of these characters will have to be prepended - * to all fantasy commands. If you choose "!", for example, fantasy commands will be "!kick", - * "!op", etc. This directive is optional, if left out, the default fantasy character is "!". - */ - #fantasycharacter = "!." - - /* * Modes to set on service bots when they join channels, comment this out for no modes * * This directive is optional. @@ -137,13 +130,17 @@ command { service = "BotServ"; name = "HELP"; command = "generic/help"; } /* * bs_assign * - * Provides the commands botserv/assign and botserv/unassign. + * Provides the commands: + * botserv/assign - Used to assign BotServ bots to channels + * botserv/unassign - Used to unassign BotServ bots + * botserv/set/nobot - Used to prohibit channels from being assigned BotServ bots. * * Used for assigning and unassigning bots to channels. */ module { name = "bs_assign" } command { service = "BotServ"; name = "ASSIGN"; command = "botserv/assign"; } command { service = "BotServ"; name = "UNASSIGN"; command = "botserv/unassign"; } +command { service = "BotServ"; name = "SET NOBOT"; command = "botserv/set/nobot"; permission = "botserv/set/nobot"; } /* * bs_autoassign @@ -240,6 +237,8 @@ command { service = "BotServ"; name = "INFO"; command = "botserv/info"; } * botserv/kick/repeat - Configures BotServ's repeat kicker. * botserv/kick/reverses - Configures BotServ's reverse kicker. * botserv/kick/underlines - Configures BotServ's reverse kicker. + * botserv/set/dontkickops - Used for preventing BotServ from kicking channel operators. + * botserv/set/dontkickvoices - Used for preventing BotServ from kicking voices. * * Used for configuring what bots should kick for. */ @@ -275,30 +274,71 @@ command { service = "BotServ"; name = "KICK REPEAT"; command = "botserv/kick/rep command { service = "BotServ"; name = "KICK REVERSES"; command = "botserv/kick/reverses"; } command { service = "BotServ"; name = "KICK UNDERLINES"; command = "botserv/kick/underlines"; } +command { service = "BotServ"; name = "SET DONTKICKOPS"; command = "botserv/set/dontkickops"; } +command { service = "BotServ"; name = "SET DONTKICKVOICES"; command = "botserv/set/dontkickvoices"; } + /* * bs_set * * Provides the commands: - * botserv/set/dontkickops - Used for preventing BotServ from kicking channel operators. - * botserv/set/dontkickvoices - Used for preventing BotServ from kicking voices. - * botserv/set/fantasy - Used for enabling or disabling BotServ's fantasist commands. - * botserv/set/greet - Used for enabling or disabling BotServ's greet messages in a channel. - * botserv/set/nobot - Used to prohibit specific channels from being assigned BotServ bots. * botserv/set/private - Used to prohibit specific BotServ bots from being assigned to channels. - * - * Used for setting options such as kickers and fantasy replies. */ module { name = "bs_set" } command { service = "BotServ"; name = "SET"; command = "botserv/set"; } command { service = "BotServ"; name = "SET BANEXPIRE"; command = "botserv/set/banexpire"; } -command { service = "BotServ"; name = "SET DONTKICKOPS"; command = "botserv/set/dontkickops"; } -command { service = "BotServ"; name = "SET DONTKICKVOICES"; command = "botserv/set/dontkickvoices"; } -command { service = "BotServ"; name = "SET FANTASY"; command = "botserv/set/fantasy"; } -command { service = "BotServ"; name = "SET GREET"; command = "botserv/set/greet"; } -command { service = "BotServ"; name = "SET NOBOT"; command = "botserv/set/nobot"; permission = "botserv/set/nobot"; } command { service = "BotServ"; name = "SET PRIVATE"; command = "botserv/set/private"; permission = "botserv/set/private"; } /* + * greet + * + * Provides the commands: + * botserv/set/greet - Used for enabling or disabling BotServ's greet messages in a channel. + * nickserv/set/greet, nickserv/saset/greet - Used for changing a users greet message, which is displayed when they enter channels. + */ +module { name = "greet" } +command { service = "BotServ"; name = "SET GREET"; command = "botserv/set/greet"; } +command { service = "NickServ"; name = "SET GREET"; command = "nickserv/set/greet"; } +command { service = "NickServ"; name = "SASET GREET"; command = "nickserv/saset/greet"; permission = "nickserv/saset/greet"; } + +/* + * GREET privilege. + * + * Used by 'greet'. + * + * Users with this privilege have their greet shown when they join channels. + */ +privilege +{ + name = "GREET" + rank = 40 + level = 5 + flag = "g" + xop = "AOP" +} + + +/* + * fantasy + * + * Allows 'fantaisist' commands to be used in channels. + * + * Provides the commands: + * botserv/set/fantasy - Used for enabling or disabling BotServ's fantasist commands. + */ +module +{ + name = "fantasy" + + /* + * Defines the prefixes for fantasy commands in channels. One of these characters will have to be prepended + * to all fantasy commands. If you choose "!", for example, fantasy commands will be "!kick", + * "!op", etc. This directive is optional, if left out, the default fantasy character is "!". + */ + #fantasycharacter = "!." +} +command { service = "BotServ"; name = "SET FANTASY"; command = "botserv/set/fantasy"; } + +/* * Fantasy commands * * Fantasy commands can be executed in channels that have a BotServ bot by prefixing the diff --git a/data/chanserv.example.conf b/data/chanserv.example.conf index 6dc40991a..184c170fd 100644 --- a/data/chanserv.example.conf +++ b/data/chanserv.example.conf @@ -74,9 +74,9 @@ module * - keeptopic: Retain topic when the channel is not in use * - peace: Disallow users from kicking or removing modes from others who are of the same * access level or superior - * - private: Hide the channel from ChanServ's LIST command + * - cs_private: Hide the channel from ChanServ's LIST command * - restricted: Kick/ban users who are restricted from the channel - * - secure: Enable channel security, requiring the user to be identified with NickServ in + * - cs_secure: Enable channel security, requiring the user to be identified with NickServ in * order to be considered for being on the access list of the channel * - secureops: Only allow operator status to be given if the user is on the access list * - securefounder: Only allow the real founder of the channel to drop the channel, change it's @@ -89,10 +89,10 @@ module * - noautoop: Disables autoop on the channel * - none: No defaults * - * This directive is optional, if left blank, the options will default to keeptopic, secure, securefounder, + * This directive is optional, if left blank, the options will default to keeptopic, cs_secure, securefounder, * and signkick. If you really want no defaults, use "none" by itself as the option. */ - defaults = "keeptopic peace secure securefounder signkick" + defaults = "keeptopic peace cs_secure securefounder signkick" /* * The maximum number of channels which may be registered to a single nickname. @@ -111,18 +111,6 @@ module expire = 14d /* - * The default ban type for newly registered channels. - * - * defbantype can be: - * - * 0: ban in the form of *!user@host - * 1: ban in the form of *!*user@host - * 2: ban in the form of *!*@host - * 3: ban in the form of *!*user@*.domain - */ - defbantype = 2 - - /* * The maximum number of entries on a channel's access list. */ accessmax = 1024 @@ -424,22 +412,6 @@ privilege } /* - * GREET privilege. - * - * Used by botserv/main. - * - * Users with this permission get their greet shown on join. - */ -privilege -{ - name = "GREET" - rank = 40 - level = 5 - flag = "g" - xop = "AOP" -} - -/* * HALFOP privilege. * * Used by chanserv/mode, chanserv/halfop and chanserv/dehalfop. @@ -983,9 +955,9 @@ command { service = "ChanServ"; name = "KICK"; command = "chanserv/kick"; } /* * cs_list * - * Provides the command chanserv/list. - * - * Used for retrieving and searching the registered channel list. + * Provides the commands: + * chanserv/list - Used for retrieving and searching the registered channel list. + * chanserv/set/private - Used for setting whether channels should show up in chanserv/list. */ module { @@ -998,6 +970,7 @@ module } command { service = "ChanServ"; name = "LIST"; command = "chanserv/list"; permission = "chanserv/list"; group = "chanserv/admin"; } +command { service = "ChanServ"; name = "SET PRIVATE"; command = "chanserv/set/private"; } /* * cs_log @@ -1057,10 +1030,8 @@ cs_seen * chanserv/set/bantype - Used for controlling what format of bans are placed on channels. * chanserv/set/description - Used for changing channels descriptions. * chanserv/set/founder - Used for changing a channel's founder. - * chanserv/set/keeptopic - Used for configuring if ChanServ is to restore the channel topic when a channel is created. * chanserv/set/peace - Used for configuring if users are able to kick other users with higher access than them. * chanserv/set/persist - Used for setting whether ChanServ should stay in channels after the last user leaves. - * chanserv/set/private - Used for setting whether channels should show up in chanserv/list. * chanserv/set/restricted - Used for setting whether users not on a channel's access list can join. * chanserv/set/secure - Used for setting whether users who are recognized for accounts should have their access in channels. * chanserv/set/securefounder - Used for setting whether users with founder level access in channels have true founder or not. @@ -1071,7 +1042,22 @@ cs_seen * * This is a dummy command to provide a help wrapper for the various SET commands. */ -module { name = "cs_set" } +module +{ + name = "cs_set" + + /* + * The default ban type for newly registered channels. + * + * defbantype can be: + * + * 0: ban in the form of *!user@host + * 1: ban in the form of *!*user@host + * 2: ban in the form of *!*@host + * 3: ban in the form of *!*user@*.domain + */ + defbantype = 2 +} command { service = "ChanServ"; name = "SET"; command = "chanserv/set"; group = "chanserv/management"; } command { service = "ChanServ"; name = "SET AUTOOP"; command = "chanserv/set/autoop"; } @@ -1079,10 +1065,8 @@ command { service = "ChanServ"; name = "SET BANTYPE"; command = "chanserv/set/ba command { service = "ChanServ"; name = "SET DESCRIPTION"; command = "chanserv/set/description"; } command { service = "ChanServ"; name = "SET DESC"; command = "chanserv/set/description"; } command { service = "ChanServ"; name = "SET FOUNDER"; command = "chanserv/set/founder"; } -command { service = "ChanServ"; name = "SET KEEPTOPIC"; command = "chanserv/set/keeptopic"; } command { service = "ChanServ"; name = "SET PEACE"; command = "chanserv/set/peace"; } command { service = "ChanServ"; name = "SET PERSIST"; command = "chanserv/set/persist"; } -command { service = "ChanServ"; name = "SET PRIVATE"; command = "chanserv/set/private"; } command { service = "ChanServ"; name = "SET RESTRICTED"; command = "chanserv/set/restricted"; } command { service = "ChanServ"; name = "SET SECURE"; command = "chanserv/set/secure"; } command { service = "ChanServ"; name = "SET SECUREFOUNDER"; command = "chanserv/set/securefounder"; } @@ -1149,12 +1133,14 @@ command { service = "ChanServ"; name = "SYNC"; command = "chanserv/sync"; group /* * cs_topic * - * Provides the command chanserv/topic. + * Provides the commands: + * chanserv/topic - Used for changing the channel topic. Useful in conjunction with chanserv/set/topiclock. + * chanserv/set/keeptopic - Used for configuring if ChanServ is to restore the channel topic when a channel is created. * - * Used for changing the channel topic. Useful in conjunction with chanserv/set/topiclock. */ module { name = "cs_topic" } command { service = "ChanServ"; name = "TOPIC"; command = "chanserv/topic"; group = "chanserv/management"; } +command { service = "ChanServ"; name = "SET KEEPTOPIC"; command = "chanserv/set/keeptopic"; } /* * cs_unban diff --git a/data/example.conf b/data/example.conf index b8ec96a9c..41a1a0163 100644 --- a/data/example.conf +++ b/data/example.conf @@ -1109,6 +1109,7 @@ mail * [DEPRECATED] db_plain * * This is the flatfile database format from Anope-1.9.2 to Anope-1.9.5. + * This module only loads this database, and will NOT save it. * To convert from this format, load both this and db_flatfile. Be sure to name db_flatfile's * target database to something else. Start Anope then shut down so the new database will be written. * Then unload this and restart Anope, loading from the new database. diff --git a/data/nickserv.example.conf b/data/nickserv.example.conf index 36eec61e1..dab48996a 100644 --- a/data/nickserv.example.conf +++ b/data/nickserv.example.conf @@ -94,9 +94,9 @@ module * - killprotect: Kill nick if not identified within 60 seconds * - kill_quick: Kill nick if not identified within 20 seconds, this one overrides the above * option and the above must be specified with this one - * - secure: Enable nickname security, requiring the nick's password before any operations + * - ns_secure: Enable nickname security, requiring the nick's password before any operations * can be done on it - * - private: Hide the nick from NickServ's LIST command + * - ns_private: Hide the nick from NickServ's LIST command * - hide_email: Hide's the nick's e-mail address from NickServ's INFO command * - hide_mask: Hide's the nick's last or current user@host from NickServ's INFO command * - hide_quit: Hide's the nick's last quit message @@ -106,10 +106,10 @@ module * - msg: Services messages will be sent as PRIVMSGs instead of NOTICEs, requires * options:useprivmsg to be enabled as well * - * This directive is optional, if left blank, the options will default to secure, memo_signon, and + * This directive is optional, if left blank, the options will default to ns_secure, memo_signon, and * memo_receive. If you really want no defaults, use "none" by itself as the option. */ - defaults = "secure private hide_email hide_mask memo_signon memo_receive autoop" + defaults = "ns_secure ns_private hide_email hide_mask memo_signon memo_receive autoop" /* * The minimum length of time between consecutive uses of NickServ's REGISTER command. This @@ -125,14 +125,6 @@ module expire = 21d /* - * The length of time a user using an unconfirmed account has - * before the account will be released for general use again. - * - * This directive is only required if the e-mail registration option is enabled. - */ - #unconfirmedexpire = 1d - - /* * Prevents the use of the ACCESS (excluding the LIST subcommand), DROP, FORBID, SUSPEND, * GETPASS and SET PASSWORD commands by services operators on other services operators. * @@ -350,19 +342,24 @@ command { service = "NickServ"; name = "IDENTIFY"; command = "nickserv/identify" /* * ns_info * - * Provides the command nickserv/info. + * Provides the commands: + * nickserv/info. - Used for gathering information about an account. + * nickserv/set/hide, nickserv/saset/hide - Used for configuring which options are publically shown in nickserv/info. * - * Used for gathering information about an account. */ module { name = "ns_info" } command { service = "NickServ"; name = "INFO"; command = "nickserv/info"; } +command { service = "NickServ"; name = "SET HIDE"; command = "nickserv/set/hide"; } +command { service = "NickServ"; name = "SASET HIDE"; command = "nickserv/saset/hide"; permission = "nickserv/saset/hide"; } + /* * ns_list * - * Provides the command nickserv/list. + * Provides the commands: + * nickserv/list - Used for retrieving and searching the registered account list. + * nickserv/set/private, nickserv/saset/private - Used for configuring whether or a users account shows up in nickserv/list. * - * Used for retrieving and searching the registered account list. */ module { @@ -375,6 +372,9 @@ module } command { service = "NickServ"; name = "LIST"; command = "nickserv/list"; group = "nickserv/admin"; } +command { service = "NickServ"; name = "SET PRIVATE"; command = "nickserv/set/private"; } +command { service = "NickServ"; name = "SASET PRIVATE"; command = "nickserv/saset/private"; permission = "nickserv/saset/private"; } + /* * ns_logout * @@ -441,6 +441,12 @@ module * This directive is optional. */ #nickregdelay = 30s + + /* + * The length of time a user using an unconfirmed account has + * before the account will be released for general use again. + */ + #unconfirmedexpire = 1d } command { service = "NickServ"; name = "CONFIRM"; command = "nickserv/confirm"; } @@ -465,17 +471,12 @@ command { service = "NickServ"; name = "RESETPASS"; command = "nickserv/resetpas * nickserv/set/autoop, nickserv/saset/autoop - Determines whether or not modes are automatically set users when joining a channel. * nickserv/set/display, nickserv/saset/display - Used for setting a users display name. * nickserv/set/email, nickserv/saset/email - Used for setting a users email address. - * nickserv/set/greet, nickserv/saset/greet - Used for changing a users greet message, which is displayed when they enter channels. - * nicksrev/set/hide, nickserv/saset/hide - Used for configuring which options are publically shown in nickserv/info for users account. * nickserv/set/kill, nickserv/saset/kill - Used for configuring nickname protection. * nickserv/set/language, nickserv/saset/language - Used for configuring what language services use. * nickserv/set/message, nickserv/saset/message - Used to configure how services send messages to you. - * nickserv/set/password, nickserv/saset/password - Used for changing a users greet password. - * nickserv/set/private, nickserv/saset/private - Used for configuring whether or a users account shows up in nickserv/list. + * nickserv/set/password, nickserv/saset/password - Used for changing a users password. * nickserv/set/secure, nickserv/saset/secure - Used for configuring whether a user can identify by simply being recognized by nickserv/access. * nickserv/saset/noexpire - Used for configuring noexpire, which prevents nicks from expiring. - * - * This is a dummy command to provide a help wrapper for the various SET and SASET commands. */ module { @@ -502,12 +503,6 @@ command { service = "NickServ"; name = "SASET DISPLAY"; command = "nickserv/sase command { service = "NickServ"; name = "SET EMAIL"; command = "nickserv/set/email"; } command { service = "NickServ"; name = "SASET EMAIL"; command = "nickserv/saset/email"; permission = "nickserv/saset/email"; } -command { service = "NickServ"; name = "SET GREET"; command = "nickserv/set/greet"; } -command { service = "NickServ"; name = "SASET GREET"; command = "nickserv/saset/greet"; permission = "nickserv/saset/greet"; } - -command { service = "NickServ"; name = "SET HIDE"; command = "nickserv/set/hide"; } -command { service = "NickServ"; name = "SASET HIDE"; command = "nickserv/saset/hide"; permission = "nickserv/saset/hide"; } - command { service = "NickServ"; name = "SET KILL"; command = "nickserv/set/kill"; } command { service = "NickServ"; name = "SASET KILL"; command = "nickserv/saset/kill"; permission = "nickserv/saset/kill"; } @@ -520,9 +515,6 @@ command { service = "NickServ"; name = "SASET MESSAGE"; command = "nickserv/sase command { service = "NickServ"; name = "SET PASSWORD"; command = "nickserv/set/password"; } command { service = "NickServ"; name = "SASET PASSWORD"; command = "nickserv/saset/password"; permission = "nickserv/saset/password"; } -command { service = "NickServ"; name = "SET PRIVATE"; command = "nickserv/set/private"; } -command { service = "NickServ"; name = "SASET PRIVATE"; command = "nickserv/saset/private"; permission = "nickserv/saset/private"; } - command { service = "NickServ"; name = "SET SECURE"; command = "nickserv/set/secure"; } command { service = "NickServ"; name = "SASET SECURE"; command = "nickserv/saset/secure"; permission = "nickserv/saset/secure"; } diff --git a/include/account.h b/include/account.h index 4d6bd714f..15fc0f20f 100644 --- a/include/account.h +++ b/include/account.h @@ -27,15 +27,6 @@ extern CoreExport Serialize::Checker<nickcore_map> NickCoreList; /* A registered nickname. * It matters that Base is here before Extensible (it is inherited by Serializable) - * - * Possible flags: - * NO_EXPIRE - Nick never expires - * HELD - This nick is being held after a kill by an enforcer client - * or is being SVSHeld. - * COLLIDED - We are taking over this nick, either by SVSNICK or KILL - * and are waiting for the confirmation of either of these actions to - * proceed. This is checked in NickAlias::OnCancel - * */ class CoreExport NickAlias : public Serializable, public Extensible { @@ -112,26 +103,6 @@ class CoreExport NickAlias : public Serializable, public Extensible /* A registered account. Each account must have a NickAlias with the same nick as the * account's display. * It matters that Base is here before Extensible (it is inherited by Serializable) - * - * Possible flags: - * KILLPROTECT - Kill other users who try to take this nick - * SECURE - Don't recognize unless identified - * MSG - Use PRIVMSG instead of notice - * MEMO_HARDMAX - Don't allow user to change memo limit - * MEMO_SIGNON - Notify of memos at signon and unaway - * MEMO_RECEIEVE - Notify of new memos when sent - * PRIVATE - Don't show in LIST to non-servadmins - * HIDE_EMAIL - Don't show email in INFO - * HIDE_MASK - Don't show last seen address in INFO - * HIDE_QUIT - Don't show last quit message in INFO - * KILL_QUICK - Kill quicker - * KILL_IMMED - Kill immediately - * MEMO_MAIL - User gets email on memo - * HIDE_STATUS - Don't show services access status - * SUSPEND - Nickname is suspended - * AUTOOP - Autoop nickname in channels - * UNCONFIRMED - Account has not had email address confirmed - * STATS - ChanStats is enabled for this user */ class CoreExport NickCore : public Serializable, public Extensible { @@ -143,15 +114,11 @@ class CoreExport NickCore : public Serializable, public Extensible /* User password in form of hashm:data */ Anope::string pass; Anope::string email; - /* Greet associated with the account, sometimes sent when the user joins a channel */ - Anope::string greet; /* Locale name of the language of the user. Empty means default language */ Anope::string language; /* Access list, contains user@host masks of users who get certain privileges based * on if NI_SECURE is set and what (if any) kill protection is enabled. */ std::vector<Anope::string> access; - /* SSL certificate list. Users who have a matching certificate may be automatically logged in */ - std::vector<Anope::string> cert; MemoInfo memos; /* Nicknames registered that are grouped to this account. @@ -242,46 +209,6 @@ class CoreExport NickCore : public Serializable, public Extensible */ bool IsOnAccess(const User *u) const; - /** Add an entry to the nick's certificate list - * - * @param entry The fingerprint to add to the cert list - * - * Adds a new entry into the cert list. - */ - void AddCert(const Anope::string &entry); - - /** Get an entry from the nick's cert list by index - * - * @param entry Index in the certificaate list vector to retrieve - * @return The fingerprint entry of the given index if within bounds, an empty string if the vector is empty or the index is out of bounds - * - * Retrieves an entry from the certificate list corresponding to the given index. - */ - Anope::string GetCert(unsigned entry) const; - - /** Find an entry in the nick's cert list - * - * @param entry The fingerprint to search for - * @return True if the fingerprint is found in the cert list, false otherwise - * - * Search for an fingerprint within the cert list. - */ - bool FindCert(const Anope::string &entry) const; - - /** Erase a fingerprint from the nick's certificate list - * - * @param entry The fingerprint to remove - * - * Removes the specified fingerprint from the cert list. - */ - void EraseCert(const Anope::string &entry); - - /** Clears the entire nick's cert list - * - * Deletes all the memory allocated in the certificate list vector and then clears the vector. - */ - void ClearCert(); - /** Finds an account * @param nick The account name to find * @return The account, if it exists diff --git a/include/channels.h b/include/channels.h index bdc273415..377b4eebf 100644 --- a/include/channels.h +++ b/include/channels.h @@ -48,6 +48,8 @@ class CoreExport Channel : public Base, public Extensible time_t creation_time; /* If the channel has just been created in a netjoin */ bool syncing; + /* Is configured in the conf as a channel bots should be in */ + bool botchannel; /* Users in the channel */ typedef std::map<User *, ChanUserContainer *> ChanUserList; diff --git a/include/defs.h b/include/defs.h index e1c7613bc..fc0ad8e6a 100644 --- a/include/defs.h +++ b/include/defs.h @@ -32,7 +32,6 @@ class InfoFormatter; class IRCDProto; class ListenSocket; class Log; -class LogInfo; class Memo; class MessageSource; class Module; diff --git a/include/extensible.h b/include/extensible.h index d47690da6..bd92e5635 100644 --- a/include/extensible.h +++ b/include/extensible.h @@ -12,109 +12,242 @@ #include "anope.h" #include "serialize.h" +#include "service.h" +#include "logger.h" -/* All items added to Extensible must inherit from this. - */ -class CoreExport ExtensibleItem +class Extensible; + +class CoreExport ExtensibleBase : public Service { + protected: + std::map<Extensible *, void *> items; + + ExtensibleBase(Module *m, const Anope::string &n); + ~ExtensibleBase(); + public: - virtual ~ExtensibleItem() { } + virtual void Unset(Extensible *obj) = 0; - virtual const Anope::string *Serialize() { return NULL; } + /* called when an object we are keep track of is serializing */ + virtual void ExtensibleSerialize(const Extensible *, const Serializable *, Serialize::Data &) const { } + virtual void ExtensibleUnserialize(Extensible *, Serializable *, Serialize::Data &) { } }; -/** Common class used to Extensible::Extend as it inherits from both ExtensibleItem - * and whatever basic object you're trying to store. - * Eg, obj->Extend(key, new ExtensibleItemClass<Anope::string>(value)); - */ -template<typename T> struct CoreExport ExtensibleItemClass : T, ExtensibleItem +class CoreExport Extensible { - ExtensibleItemClass(const T& t) : T(t) { } -}; + public: + std::set<ExtensibleBase *> extension_items; -/* Used to attach metadata to this object that is automatically saved - * when the object is saved (assuming the object's Serialize method - * correcly calls Extensible::ExtensibleSerialize). - */ -struct CoreExport ExtensibleMetadata : ExtensibleItemClass<Anope::string> -{ - ExtensibleMetadata(const Anope::string &t) : ExtensibleItemClass<Anope::string>(t) { } + virtual ~Extensible(); - const Anope::string *Serialize() anope_override { return this; } + template<typename T> T* GetExt(const Anope::string &name) const; + bool HasExt(const Anope::string &name) const; + + template<typename T> T* Extend(const Anope::string &name, const T &what); + template<typename T> T* Extend(const Anope::string &name); + template<typename T> T* Require(const Anope::string &name); + template<typename T> void Shrink(const Anope::string &name); + + static void ExtensibleSerialize(const Extensible *, const Serializable *, Serialize::Data &data); + static void ExtensibleUnserialize(Extensible *, Serializable *, Serialize::Data &data); }; -/* Used to attach arbitrary objects to this object using unique keys */ -class CoreExport Extensible +template<typename T> +class BaseExtensibleItem : public ExtensibleBase { - private: - typedef std::map<Anope::string, ExtensibleItem *> extensible_map; - extensible_map *extension_items; + protected: + virtual T *Create(Extensible *) = 0; public: - /** Default constructor - */ - Extensible(); + BaseExtensibleItem(Module *m, const Anope::string &n) : ExtensibleBase(m, n) { } - /** Destructor, deletes all of the extensible items in this object - * then clears the map - */ - virtual ~Extensible(); - - /** Extend an Extensible class. - * - * @param key The key parameter is an arbitary string which identifies the extension data - * @param p This parameter is a pointer to an ExtensibleItem or ExtensibleItemBase derived class - * - * You must provide a key to store the data as via the parameter 'key'. - * The data will be inserted into the map. If the data already exists, it will be overwritten. - */ - void Extend(const Anope::string &key, ExtensibleItem *p = NULL); - - void ExtendMetadata(const Anope::string &key, const Anope::string &value = ""); - - /** Shrink an Extensible class. - * - * @param key The key parameter is an arbitary string which identifies the extension data - * - * You must provide a key name. The given key name will be removed from the classes data. If - * you provide a nonexistent key (case is important) then the function will return false. - * @return Returns true on success. - */ - bool Shrink(const Anope::string &key); - - /** Get an extension item. - * - * @param key The key parameter is an arbitary string which identifies the extension data - * @return The item found - */ - template<typename T> T GetExt(const Anope::string &key) const + ~BaseExtensibleItem() { - if (this->extension_items) + for (std::map<Extensible *, void *>::iterator it = items.begin(); it != items.end(); ++it) { - extensible_map::const_iterator it = this->extension_items->find(key); - if (it != this->extension_items->end()) - return anope_dynamic_static_cast<T>(it->second); + T *value = static_cast<T *>(it->second); + + items.erase(it->first); + it->first->extension_items.erase(this); + delete value; } + } + + T* Set(Extensible *obj, const T &value) + { + T* t = Set(obj); + *t = value; + return t; + } + + T* Set(Extensible *obj) + { + T* t = Create(obj); + Unset(obj); + items[obj] = t; + obj->extension_items.insert(this); + return t; + } + + void Unset(Extensible *obj) anope_override + { + T *value = Get(obj); + items.erase(obj); + obj->extension_items.erase(this); + delete value; + } + T* Get(const Extensible *obj) const + { + std::map<Extensible *, void *>::const_iterator it = items.find(const_cast<Extensible *>(obj)); + if (it != items.end()) + return static_cast<T *>(it->second); return NULL; } - /** Check if an extension item exists. - * - * @param key The key parameter is an arbitary string which identifies the extension data - * @return True if the item was found. - */ - bool HasExt(const Anope::string &key) const; - - /** Get a list of all extension items names. - * @param list A deque of strings to receive the list - * @return This function writes a list of all extension items stored - * in this object by name into the given deque and returns void. - */ - void GetExtList(std::deque<Anope::string> &list) const; - - void ExtensibleSerialize(Serialize::Data &data) const; - void ExtensibleUnserialize(Serialize::Data &data); + bool HasExt(const Extensible *obj) const + { + return items.find(const_cast<Extensible *>(obj)) != items.end(); + } + + T* Require(Extensible *obj) + { + T* t = Get(obj); + if (t) + return t; + + return Set(obj); + } +}; + +template<typename T> +class ExtensibleItem : public BaseExtensibleItem<T> +{ + protected: + T* Create(Extensible *obj) anope_override + { + return new T(obj); + } + public: + ExtensibleItem(Module *m, const Anope::string &n) : BaseExtensibleItem<T>(m, n) { } }; +template<typename T> +class PrimitiveExtensibleItem : public BaseExtensibleItem<T> +{ + protected: + T* Create(Extensible *obj) anope_override + { + return new T(); + } + public: + PrimitiveExtensibleItem(Module *m, const Anope::string &n) : BaseExtensibleItem<T>(m, n) { } +}; + +template<> +class PrimitiveExtensibleItem<bool> : public BaseExtensibleItem<bool> +{ + protected: + bool* Create(Extensible *) anope_override + { + return NULL; + } + public: + PrimitiveExtensibleItem(Module *m, const Anope::string &n) : BaseExtensibleItem<bool>(m, n) { } +}; + +template<typename T> +class SerializableExtensibleItem : public PrimitiveExtensibleItem<T> +{ + public: + SerializableExtensibleItem(Module *m, const Anope::string &n) : PrimitiveExtensibleItem<T>(m, n) { } + + void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const anope_override + { + T* t = this->Get(e); + data[this->name] << *t; + } + + void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) anope_override + { + T* t = this->Require(e); + data[this->name] >> *t; + } +}; + +template<> +class SerializableExtensibleItem<bool> : public PrimitiveExtensibleItem<bool> +{ + public: + SerializableExtensibleItem(Module *m, const Anope::string &n) : PrimitiveExtensibleItem<bool>(m, n) { } + + void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const anope_override + { + data[this->name] << true; + } + + void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) anope_override + { + bool b; + data[this->name] >> b; + if (b) + this->Set(e); + } +}; + +template<typename T> +struct ExtensibleRef : ServiceReference<BaseExtensibleItem<T> > +{ + ExtensibleRef(const Anope::string &n) : ServiceReference<BaseExtensibleItem<T> >("Extensible", n) { } +}; + +template<typename T> +T* Extensible::GetExt(const Anope::string &name) const +{ + ExtensibleRef<T> ref(name); + if (ref) + return ref->Get(this); + + Log(LOG_DEBUG) << "GetExt for nonexistent type " << name << " on " << static_cast<const void *>(this); + return NULL; +} + +template<typename T> +T* Extensible::Extend(const Anope::string &name, const T &what) +{ + T* t = Extend<T>(name); + *t = what; + return t; +} + +template<typename T> +T* Extensible::Extend(const Anope::string &name) +{ + ExtensibleRef<T> ref(name); + if (ref) + return ref->Set(this); + + Log(LOG_DEBUG) << "Extend for nonexistent type " << name << " on " << static_cast<void *>(this); + return NULL; +} + +template<typename T> +T* Extensible::Require(const Anope::string &name) +{ + if (HasExt(name)) + return GetExt<T>(name); + else + return Extend<T>(name); +} + +template<typename T> +void Extensible::Shrink(const Anope::string &name) +{ + ExtensibleRef<T> ref(name); + if (ref) + ref->Unset(this); + else + Log(LOG_DEBUG) << "Shrink for nonexistent type " << name << " on " << static_cast<void *>(this); +} + #endif // EXTENSIBLE_H diff --git a/include/lists.h b/include/lists.h index 667c643b6..37b3d61a8 100644 --- a/include/lists.h +++ b/include/lists.h @@ -87,6 +87,7 @@ class CoreExport InfoFormatter InfoFormatter(NickCore *nc); void Process(std::vector<Anope::string> &); Anope::string &operator[](const Anope::string &key); + void AddOption(const Anope::string &opt); }; #endif // LISTS_H diff --git a/include/modules.h b/include/modules.h index c430767db..ffb8bbcc7 100644 --- a/include/modules.h +++ b/include/modules.h @@ -626,9 +626,10 @@ class CoreExport Module : public Extensible virtual void OnLevelChange(CommandSource &source, ChannelInfo *ci, const Anope::string &priv, int16_t what) { throw NotImplementedException(); } /** Called right before a channel is dropped + * @param source The user dropping the channel * @param ci The channel */ - virtual void OnChanDrop(ChannelInfo *ci) { throw NotImplementedException(); } + virtual EventReturn OnChanDrop(CommandSource &source, ChannelInfo *ci) { throw NotImplementedException(); } /** Called when a channel is registered * @param ci The channel @@ -823,6 +824,10 @@ class CoreExport Module : public Extensible */ virtual void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) { throw NotImplementedException(); } + /** Called when a user uses botserv/info on a bot or channel. + */ + virtual void OnBotInfo(CommandSource &source, BotInfo *bi, ChannelInfo *ci, InfoFormatter &info) { throw NotImplementedException(); } + /** Check whether a username and password is correct * @param u The user trying to identify, if applicable. * @param req The login request @@ -887,20 +892,20 @@ class CoreExport Module : public Extensible /** Called when a mode is set on a channel * @param c The channel * @param setter The user or server that is setting the mode - * @param mname The mode name + * @param mode The mode * @param param The mode param, if there is one * @return EVENT_STOP to make mlock/secureops etc checks not happen */ - virtual EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, const Anope::string &mname, const Anope::string ¶m) { throw NotImplementedException(); } + virtual EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) { throw NotImplementedException(); } /** Called when a mode is unset on a channel * @param c The channel * @param setter The user or server that is unsetting the mode - * @param mname The mode name + * @param mode The mode * @param param The mode param, if there is one * @return EVENT_STOP to make mlock/secureops etc checks not happen */ - virtual EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, const Anope::string &mname, const Anope::string ¶m) { throw NotImplementedException(); } + virtual EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) { throw NotImplementedException(); } /** Called when a mode is set on a user * @param u The user @@ -1053,6 +1058,14 @@ class CoreExport Module : public Extensible * channels, etc. */ virtual void OnExpireTick() { throw NotImplementedException(); } + + /** Called when a nick is validated. That is, to determine if a user is permissted + * to be on the given nick. + * @param u The user + * @param na The nick they are on + * @return EVENT_STOP to force the user off of the nick + */ + virtual EventReturn OnNickValidate(User *u, NickAlias *na) { throw NotImplementedException(); } }; /** Used to manage modules. diff --git a/include/modules/bs_badwords.h b/include/modules/bs_badwords.h new file mode 100644 index 000000000..4275226cc --- /dev/null +++ b/include/modules/bs_badwords.h @@ -0,0 +1,70 @@ +/* BotServ core functions + * + * (C) 2003-2013 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. + * + * + */ + +/** Flags for badwords + */ +enum BadWordType +{ + /* Always kicks if the word is said */ + BW_ANY, + /* User must way the entire word */ + BW_SINGLE, + /* The word has to start with the badword */ + BW_START, + /* The word has to end with the badword */ + BW_END +}; + +/* Structure used to contain bad words. */ +struct BadWord +{ + Anope::string chan; + Anope::string word; + BadWordType type; + + protected: + BadWord() { } +}; + +struct BadWords +{ + /** Add a badword to the badword list + * @param word The badword + * @param type The type (SINGLE START END) + * @return The badword + */ + virtual BadWord* AddBadWord(const Anope::string &word, BadWordType type) = 0; + + /** Get a badword structure by index + * @param index The index + * @return The badword + */ + virtual BadWord* GetBadWord(unsigned index) const = 0; + + /** Get how many badwords are on this channel + * @return The number of badwords in the vector + */ + virtual unsigned GetBadWordCount() const = 0; + + /** Remove a badword + * @param index The index of the badword + */ + virtual void EraseBadWord(unsigned index) = 0; + + /** Clear all badwords from the channel + */ + virtual void ClearBadWords() = 0; + + virtual void Check() = 0; +}; + diff --git a/include/modules/bs_kick.h b/include/modules/bs_kick.h new file mode 100644 index 000000000..e1c43cc8c --- /dev/null +++ b/include/modules/bs_kick.h @@ -0,0 +1,45 @@ +/* BotServ core functions + * + * (C) 2003-2013 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. + * + * + */ + +/* Indices for TTB (Times To Ban) */ +enum +{ + TTB_BOLDS, + TTB_COLORS, + TTB_REVERSES, + TTB_UNDERLINES, + TTB_BADWORDS, + TTB_CAPS, + TTB_FLOOD, + TTB_REPEAT, + TTB_ITALICS, + TTB_AMSGS, + TTB_SIZE +}; + +struct KickerData +{ + bool amsgs, badwords, bolds, caps, colors, flood, italics, repeat, reverses, underlines; + int16_t ttb[TTB_SIZE]; /* Times to ban for each kicker */ + int16_t capsmin, capspercent; /* For CAPS kicker */ + int16_t floodlines, floodsecs; /* For FLOOD kicker */ + int16_t repeattimes; /* For REPEAT kicker */ + + bool dontkickops, dontkickvoices; + + protected: + KickerData() { } + + public: + virtual void Check(ChannelInfo *ci) = 0; +}; diff --git a/include/modules/cs_log.h b/include/modules/cs_log.h new file mode 100644 index 000000000..555a44e50 --- /dev/null +++ b/include/modules/cs_log.h @@ -0,0 +1,41 @@ +/* ChanServ core functions + * + * (C) 2003-2013 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. + */ + +struct LogSetting +{ + Anope::string chan; + /* Our service name of the command */ + Anope::string service_name; + /* The name of the client the command is on */ + Anope::string command_service; + /* Name of the command to the user, can have spaces */ + Anope::string command_name; + Anope::string method, extra; + Anope::string creator; + time_t created; + + protected: + LogSetting() { } +}; + +struct LogSettings : Serialize::Checker<std::vector<LogSetting *> > +{ + typedef std::vector<LogSetting *>::iterator iterator; + + protected: + LogSettings() : Serialize::Checker<std::vector<LogSetting *> >("LogSetting") + { + } + + public: + virtual LogSetting *Create() = 0; +}; + diff --git a/include/modules/cs_mode.h b/include/modules/cs_mode.h new file mode 100644 index 000000000..4d016e672 --- /dev/null +++ b/include/modules/cs_mode.h @@ -0,0 +1,87 @@ +/* ChanServ core functions + * + * (C) 2003-2013 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. + */ + +struct ModeLock +{ + Anope::string ci; + bool set; + Anope::string name; + Anope::string param; + Anope::string setter; + time_t created; + + protected: + ModeLock() { } +}; + +struct ModeLocks +{ + typedef std::vector<ModeLock *> ModeList; + + /** Check if a mode is mlocked + * @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 + */ + virtual bool HasMLock(ChannelMode *mode, const Anope::string ¶m, bool status) const = 0; + + /** Set a mlock + * @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) + */ + virtual bool SetMLock(ChannelMode *mode, bool status, const Anope::string ¶m = "", Anope::string setter = "", time_t created = Anope::CurTime) = 0; + + /** Remove a mlock + * @param mode The mode + * @param status True for mlock on, false for mlock off + * @param param The param of the mode, required if it is a list or status mode + * @return true on success, false on failure + */ + virtual bool RemoveMLock(ChannelMode *mode, bool status, const Anope::string ¶m = "") = 0; + + virtual void RemoveMLock(ModeLock *mlock) = 0; + + /** Clear all mlocks on the channel + */ + virtual void ClearMLock() = 0; + + /** Get all of the mlocks for this channel + * @return The mlocks + */ + virtual const ModeList &GetMLock() const = 0; + + /** Get a list of mode locks on a channel + * @param name The mode name to get a list of + * @return a list of mlocks for the given mode + */ + virtual std::list<ModeLock *> GetModeLockList(const Anope::string &name) = 0; + + /** Get details for a specific mlock + * @param mname The mode name + * @param An optional param to match with + * @return The MLock, if any + */ + virtual const ModeLock *GetMLock(const Anope::string &mname, const Anope::string ¶m = "") = 0; + + /** Get the current mode locks as a string + * @param complete True to show mlock parameters aswell + * @return A string of mode locks, eg: +nrt + */ + virtual Anope::string GetMLockAsString(bool complete) const = 0; + + virtual void Check() = 0; +}; + diff --git a/include/modules/cs_suspend.h b/include/modules/cs_suspend.h new file mode 100644 index 000000000..dbdd3b9e9 --- /dev/null +++ b/include/modules/cs_suspend.h @@ -0,0 +1,19 @@ +/* ChanServ core functions + * + * (C) 2003-2013 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. + */ + +struct CSSuspendInfo +{ + Anope::string chan, by, reason; + time_t time, expires; + + protected: + CSSuspendInfo() { } +}; diff --git a/include/modules/ns_cert.h b/include/modules/ns_cert.h new file mode 100644 index 000000000..8587cdfb2 --- /dev/null +++ b/include/modules/ns_cert.h @@ -0,0 +1,61 @@ +/* NickServ core functions + * + * (C) 2003-2013 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. + */ + +struct NSCertList +{ + protected: + NSCertList() { } + public: + + /** Add an entry to the nick's certificate list + * + * @param entry The fingerprint to add to the cert list + * + * Adds a new entry into the cert list. + */ + virtual void AddCert(const Anope::string &entry) = 0; + + /** Get an entry from the nick's cert list by index + * + * @param entry Index in the certificaate list vector to retrieve + * @return The fingerprint entry of the given index if within bounds, an empty string if the vector is empty or the index is out of bounds + * + * Retrieves an entry from the certificate list corresponding to the given index. + */ + virtual Anope::string GetCert(unsigned entry) const = 0; + + virtual unsigned GetCertCount() const = 0; + + /** Find an entry in the nick's cert list + * + * @param entry The fingerprint to search for + * @return True if the fingerprint is found in the cert list, false otherwise + * + * Search for an fingerprint within the cert list. + */ + virtual bool FindCert(const Anope::string &entry) const = 0; + + /** Erase a fingerprint from the nick's certificate list + * + * @param entry The fingerprint to remove + * + * Removes the specified fingerprint from the cert list. + */ + virtual void EraseCert(const Anope::string &entry) = 0; + + /** Clears the entire nick's cert list + * + * Deletes all the memory allocated in the certificate list vector and then clears the vector. + */ + virtual void ClearCert() = 0; + + virtual void Check() = 0; +}; diff --git a/include/modules/ns_suspend.h b/include/modules/ns_suspend.h new file mode 100644 index 000000000..59f3d5d58 --- /dev/null +++ b/include/modules/ns_suspend.h @@ -0,0 +1,19 @@ +/* NickServ core functions + * + * (C) 2003-2013 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. + */ + +struct NSSuspendInfo +{ + Anope::string nick, by, reason; + time_t when, expires; + + protected: + NSSuspendInfo() { } +}; diff --git a/include/regchannel.h b/include/regchannel.h index 65d3236ef..f04156d89 100644 --- a/include/regchannel.h +++ b/include/regchannel.h @@ -22,49 +22,6 @@ typedef Anope::hash_map<ChannelInfo *> registered_channel_map; extern CoreExport Serialize::Checker<registered_channel_map> RegisteredChannelList; -/* Indices for TTB (Times To Ban) */ -enum -{ - TTB_BOLDS, - TTB_COLORS, - TTB_REVERSES, - TTB_UNDERLINES, - TTB_BADWORDS, - TTB_CAPS, - TTB_FLOOD, - TTB_REPEAT, - TTB_ITALICS, - TTB_AMSGS, - TTB_SIZE -}; - -/** Flags for badwords - */ -enum BadWordType -{ - /* Always kicks if the word is said */ - BW_ANY, - /* User must way the entire word */ - BW_SINGLE, - /* The word has to start with the badword */ - BW_START, - /* The word has to end with the badword */ - BW_END -}; - -/* Structure used to contain bad words. */ -struct CoreExport BadWord : Serializable -{ - Serialize::Reference<ChannelInfo> ci; - Anope::string word; - BadWordType type; - - BadWord(); - ~BadWord(); - void Serialize(Serialize::Data &data) const anope_override; - static Serializable* Unserialize(Serializable *obj, Serialize::Data &); -}; - /* AutoKick data. */ class CoreExport AutoKick : public Serializable { @@ -86,74 +43,7 @@ class CoreExport AutoKick : public Serializable static Serializable* Unserialize(Serializable *obj, Serialize::Data &); }; -struct CoreExport ModeLock : Serializable -{ - public: - Serialize::Reference<ChannelInfo> ci; - bool set; - Anope::string name; - Anope::string param; - Anope::string setter; - time_t created; - - ModeLock(ChannelInfo *ch, bool s, const Anope::string &n, const Anope::string &p, const Anope::string &se = "", time_t c = Anope::CurTime); - ~ModeLock(); - - void Serialize(Serialize::Data &data) const anope_override; - static Serializable* Unserialize(Serializable *obj, Serialize::Data &); -}; - -struct CoreExport LogSetting : Serializable -{ - Serialize::Reference<ChannelInfo> ci; - /* Our service name of the command */ - Anope::string service_name; - /* The name of the client the command is on */ - Anope::string command_service; - /* Name of the command to the user, can have spaces */ - Anope::string command_name; - Anope::string method, extra; - Anope::string creator; - time_t created; - - LogSetting() : Serializable("LogSetting") { } - void Serialize(Serialize::Data &data) const anope_override; - static Serializable* Unserialize(Serializable *obj, Serialize::Data &); -}; - /* It matters that Base is here before Extensible (it is inherited by Serializable) - * - * Possible flags: - * TOPICLOCK - Topic can only be changed by TOPIC SET - * RESTRICTED - Only users on the access list may join - * PEACE - Don't allow ChanServ and BotServ commands to do bad things to users with higher access levels - * SECURE - Don't allow any privileges - * NO_EXPIRE - Channel does not expire - * MEMO_HARDMAX - Channel memo limit may not be changed - * SECUREFOUNDER - Stricter control of channel founder status - * SIGNKICK - Sign kicks with the user who did the kick - * SIGNKICK_LEVEL - Sign kicks if level is < than the one defined by the SIGNKICK level - * SUSPENDED - Channel is suepended - * PERSIST - Channel still exists when empited (perm channel mode or leaving a botserv bot). - * STATS - Chanstats are enabled - * NOAUTOOP - If set users are not auto given any status on join - * - * BotServ flags: - * BS_DONTKICKOPS - BotServ won't kick ops - * BS_DONTKICKVOICES - BotServ won't kick voices - * BS_FANTASY - BotServ bot accepts fantasy commands - * BS_GREET - BotServ should show greets - * BS_NOBOT - BotServ bots are not allowed to be in this channel - * BS_KICK_BOLDS - BotServ kicks for bolds - * BS_KICK_COLORS - BotServ kicks for colors - * BS_KICK_REVERSES - BotServ kicks for reverses - * BS_KICK_UNDERLINES - BotServ kicks for underlines - * BS_KICK_BADWORD - BotServ kicks for badwords - * BS_KICK_CAPS - BotServ kicks for caps - * BS_KICK_FLOOD - BotServ kicks for flood - * BS_KICK_REPEAT - BotServ kicks for repeating - * BS_KICK_ITALICS - BotServ kicks for italics - * BS_KICK_AMSGS - BotServ kicks for amsgs */ class CoreExport ChannelInfo : public Serializable, public Extensible { @@ -162,17 +52,11 @@ class CoreExport ChannelInfo : public Serializable, public Extensible Serialize::Reference<NickCore> successor; /* Who gets the channel if the founder nick is dropped or expires */ Serialize::Checker<std::vector<ChanAccess *> > access; /* List of authorized users */ Serialize::Checker<std::vector<AutoKick *> > akick; /* List of users to kickban */ - Serialize::Checker<std::vector<BadWord *> > badwords; /* List of badwords */ Anope::map<int16_t> levels; public: friend class ChanAccess; friend class AutoKick; - friend struct BadWord; - - typedef std::multimap<Anope::string, ModeLock *> ModeList; - Serialize::Checker<ModeList> mode_locks; - Serialize::Checker<std::vector<LogSetting *> > log_settings; Anope::string name; /* Channel name */ Anope::string desc; @@ -192,11 +76,6 @@ class CoreExport ChannelInfo : public Serializable, public Extensible /* For BotServ */ Serialize::Reference<BotInfo> bi; /* Bot used on this channel */ - int16_t ttb[TTB_SIZE]; /* Times to ban for each kicker */ - - int16_t capsmin, capspercent; /* For CAPS kicker */ - int16_t floodlines, floodsecs; /* For FLOOD kicker */ - int16_t repeattimes; /* For REPEAT kicker */ time_t banexpire; /* Time bans expire in */ @@ -206,7 +85,7 @@ class CoreExport ChannelInfo : public Serializable, public Extensible ChannelInfo(const Anope::string &chname); /** Copy constructor - * @param ci The ChannelInfo to copy settings to + * @param ci The ChannelInfo to copy settings from */ ChannelInfo(const ChannelInfo &ci); @@ -310,89 +189,6 @@ class CoreExport ChannelInfo : public Serializable, public Extensible */ void ClearAkick(); - /** Add a badword to the badword list - * @param word The badword - * @param type The type (SINGLE START END) - * @return The badword - */ - BadWord* AddBadWord(const Anope::string &word, BadWordType type); - - /** Get a badword structure by index - * @param index The index - * @return The badword - */ - BadWord* GetBadWord(unsigned index) const; - - /** Get how many badwords are on this channel - * @return The number of badwords in the vector - */ - unsigned GetBadWordCount() const; - - /** Remove a badword - * @param index The index of the badword - */ - void EraseBadWord(unsigned index); - - /** Clear all badwords from the channel - */ - void ClearBadWords(); - - /** Check if a mode is mlocked - * @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(ChannelMode *mode, const Anope::string ¶m, bool status) const; - - /** Set a mlock - * @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(ChannelMode *mode, bool status, const Anope::string ¶m = "", Anope::string setter = "", time_t created = Anope::CurTime); - - /** Remove a mlock - * @param mode The mode - * @param status True for mlock on, false for mlock off - * @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(ChannelMode *mode, bool status, const Anope::string ¶m = ""); - - void RemoveMLock(ModeLock *mlock); - - /** Clear all mlocks on the channel - */ - void ClearMLock(); - - /** Get all of the mlocks for this channel - * @return The mlocks - */ - const ModeList &GetMLock() const; - - /** 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 - */ - std::pair<ModeList::iterator, ModeList::iterator> GetModeList(const Anope::string &name); - - /** Get details for a specific mlock - * @param mname The mode name - * @param An optional param to match with - * @return The MLock, if any - */ - const ModeLock *GetMLock(const Anope::string &mname, const Anope::string ¶m = ""); - - /** Get the current mode locks as a string - * @param complete True to show mlock parameters aswell - * @return A string of mode locks, eg: +nrt - */ - Anope::string GetMLockAsString(bool complete) const; - /** Get the level for a privilege * @param priv The privilege name * @return the level diff --git a/include/service.h b/include/service.h index 545d1b363..b4b9ea9cd 100644 --- a/include/service.h +++ b/include/service.h @@ -15,7 +15,7 @@ #include "services.h" #include "anope.h" -#include "modules.h" +#include "base.h" /** Anything that inherits from this class can be referred to * using ServiceReference. Any interfaces provided by modules, diff --git a/modules/commands/bs_assign.cpp b/modules/commands/bs_assign.cpp index 7b241f09e..ba925ad80 100644 --- a/modules/commands/bs_assign.cpp +++ b/modules/commands/bs_assign.cpp @@ -145,14 +145,69 @@ class CommandBSUnassign : public Command } }; +class CommandBSSetNoBot : public Command +{ + public: + CommandBSSetNoBot(Module *creator, const Anope::string &sname = "botserv/set/nobot") : Command(creator, sname, 2, 2) + { + this->SetDesc(_("Prevent a bot from being assigned to a channel")); + this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + ChannelInfo *ci = ChannelInfo::Find(params[0]); + const Anope::string &value = params[1]; + + if (ci == NULL) + { + source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + return; + } + + if (value.equals_ci("ON")) + { + Log(LOG_ADMIN, source, this, ci) << "to enable nobot"; + + ci->Extend<bool>("BS_NOBOT"); + if (ci->bi) + ci->bi->UnAssign(source.GetUser(), ci); + source.Reply(_("No-bot mode is now \002on\002 on channel %s."), ci->name.c_str()); + } + else if (value.equals_ci("OFF")) + { + Log(LOG_ADMIN, source, this, ci) << "to disable nobot"; + + ci->Shrink<bool>("BS_NOBOT"); + source.Reply(_("No-bot mode is now \002off\002 on channel %s."), ci->name.c_str()); + } + else + this->OnSyntaxError(source, source.command); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(_(" \n" + "This option makes a channel be unassignable. If a bot\n" + "is already assigned to the channel, it is unassigned\n" + "automatically when you enable the option.")); + return true; + } +}; + class BSAssign : public Module { + ExtensibleItem<bool> nobot; + CommandBSAssign commandbsassign; CommandBSUnassign commandbsunassign; + CommandBSSetNoBot commandbssetnobot; public: BSAssign(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandbsassign(this), commandbsunassign(this) + nobot(this, "BS_NOBOT"), + commandbsassign(this), commandbsunassign(this), commandbssetnobot(this) { } @@ -163,7 +218,7 @@ class BSAssign : public Module return; AccessGroup access = c->ci->AccessFor(source); - if (c->ci->HasExt("BS_NOBOT") || (!access.HasPriv("ASSIGN") && !source->HasPriv("botserv/administration"))) + if (nobot.HasExt(c->ci) || (!access.HasPriv("ASSIGN") && !source->HasPriv("botserv/administration"))) { targ->SendMessage(bi, ACCESS_DENIED); return; @@ -184,6 +239,12 @@ class BSAssign : public Module bi->Assign(source, c->ci); targ->SendMessage(bi, _("Bot \002%s\002 has been assigned to %s."), bi->nick.c_str(), c->name.c_str()); } + + void OnBotInfo(CommandSource &source, BotInfo *bi, ChannelInfo *ci, InfoFormatter &info) anope_override + { + if (nobot.HasExt(ci)) + info.AddOption(_("No bot")); + } }; MODULE_INIT(BSAssign) diff --git a/modules/commands/bs_badwords.cpp b/modules/commands/bs_badwords.cpp index 22fa74714..ff9707778 100644 --- a/modules/commands/bs_badwords.cpp +++ b/modules/commands/bs_badwords.cpp @@ -10,11 +10,132 @@ */ #include "module.h" +#include "modules/bs_badwords.h" + +struct BadWordImpl : BadWord, Serializable +{ + BadWordImpl() : Serializable("BadWord") { } + ~BadWordImpl(); + + void Serialize(Serialize::Data &data) const anope_override + { + data["ci"] << this->chan; + data["word"] << this->word; + data.SetType("type", Serialize::Data::DT_INT); data["type"] << this->type; + } + + static Serializable* Unserialize(Serializable *obj, Serialize::Data &); +}; + +struct BadWordsImpl : BadWords +{ + Serialize::Reference<ChannelInfo> ci; + typedef std::vector<BadWordImpl *> list; + Serialize::Checker<list> badwords; + + BadWordsImpl(Extensible *obj) : ci(anope_dynamic_static_cast<ChannelInfo *>(obj)), badwords("BadWord") { } + + BadWord* AddBadWord(const Anope::string &word, BadWordType type) anope_override + { + BadWordImpl *bw = new BadWordImpl(); + bw->chan = ci->name; + bw->word = word; + bw->type = type; + + this->badwords->push_back(bw); + + FOREACH_MOD(OnBadWordAdd, (ci, bw)); + + return bw; + } + + BadWord* GetBadWord(unsigned index) const anope_override + { + if (this->badwords->empty() || index >= this->badwords->size()) + return NULL; + + BadWordImpl *bw = (*this->badwords)[index]; + bw->QueueUpdate(); + return bw; + } + + unsigned GetBadWordCount() const anope_override + { + return this->badwords->size(); + } + + void EraseBadWord(unsigned index) anope_override + { + if (this->badwords->empty() || index >= this->badwords->size()) + return; + + FOREACH_MOD(OnBadWordDel, (ci, (*this->badwords)[index])); + + delete this->badwords->at(index); + } + + void ClearBadWords() anope_override + { + while (!this->badwords->empty()) + delete this->badwords->back(); + } + + void Check() anope_override + { + if (this->badwords->empty()) + ci->Shrink<BadWords>("badwords"); + } +}; + +BadWordImpl::~BadWordImpl() +{ + ChannelInfo *ci = ChannelInfo::Find(chan); + if (ci) + { + BadWordsImpl *badwords = ci->GetExt<BadWordsImpl>("badwords"); + if (badwords) + { + BadWordsImpl::list::iterator it = std::find(badwords->badwords->begin(), badwords->badwords->end(), this); + if (it != badwords->badwords->end()) + badwords->badwords->erase(it); + } + } +} + +Serializable* BadWordImpl::Unserialize(Serializable *obj, Serialize::Data &data) +{ + Anope::string sci, sword; + + data["ci"] >> sci; + data["word"] >> sword; + + ChannelInfo *ci = ChannelInfo::Find(sci); + if (!ci) + return NULL; + + unsigned int n; + data["type"] >> n; + + BadWordImpl *bw; + if (obj) + bw = anope_dynamic_static_cast<BadWordImpl *>(obj); + else + bw = new BadWordImpl(); + bw->chan = sci; + bw->word = sword; + bw->type = static_cast<BadWordType>(n); + + BadWordsImpl *bws = ci->Require<BadWordsImpl>("badwords"); + bws->badwords->push_back(bw); + + return bw; +} class BadwordsDelCallback : public NumberList { CommandSource &source; ChannelInfo *ci; + BadWords *bw; Command *c; unsigned deleted; bool override; @@ -23,6 +144,7 @@ class BadwordsDelCallback : public NumberList { if (!source.AccessFor(ci).HasPriv("BADWORDS") && source.HasPriv("botserv/administration")) this->override = true; + bw = ci->Require<BadWords>("badwords"); } ~BadwordsDelCallback() @@ -37,12 +159,12 @@ class BadwordsDelCallback : public NumberList void HandleNumber(unsigned Number) anope_override { - if (!Number || Number > ci->GetBadWordCount()) + if (!bw || !Number || Number > bw->GetBadWordCount()) return; - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "DEL " << ci->GetBadWord(Number - 1)->word; + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "DEL " << bw->GetBadWord(Number - 1)->word; ++deleted; - ci->EraseBadWord(Number - 1); + bw->EraseBadWord(Number - 1); } }; @@ -54,10 +176,11 @@ class CommandBSBadwords : public Command bool override = !source.AccessFor(ci).HasPriv("BADWORDS"); Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "LIST"; ListFormatter list; + BadWords *bw = ci->GetExt<BadWords>("badwords"); list.AddColumn("Number").AddColumn("Word").AddColumn("Type"); - if (!ci->GetBadWordCount()) + if (!bw || !bw->GetBadWordCount()) { source.Reply(_("%s bad words list is empty."), ci->name.c_str()); return; @@ -68,40 +191,41 @@ class CommandBSBadwords : public Command { ListFormatter &list; ChannelInfo *ci; + BadWords *bw; public: - BadwordsListCallback(ListFormatter &_list, ChannelInfo *_ci, const Anope::string &numlist) : NumberList(numlist, false), list(_list), ci(_ci) + BadwordsListCallback(ListFormatter &_list, ChannelInfo *_ci, BadWords *_bw, const Anope::string &numlist) : NumberList(numlist, false), list(_list), ci(_ci), bw(_bw) { } void HandleNumber(unsigned Number) anope_override { - if (!Number || Number > ci->GetBadWordCount()) + if (!Number || Number > bw->GetBadWordCount()) return; - const BadWord *bw = ci->GetBadWord(Number - 1); + const BadWord *b = bw->GetBadWord(Number - 1); ListFormatter::ListEntry entry; entry["Number"] = stringify(Number); - entry["Word"] = bw->word; - entry["Type"] = bw->type == BW_SINGLE ? "(SINGLE)" : (bw->type == BW_START ? "(START)" : (bw->type == BW_END ? "(END)" : "")); + entry["Word"] = b->word; + entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : "")); this->list.AddEntry(entry); } } - nl_list(list, ci, word); + nl_list(list, ci, bw, word); nl_list.Process(); } else { - for (unsigned i = 0, end = ci->GetBadWordCount(); i < end; ++i) + for (unsigned i = 0, end = bw->GetBadWordCount(); i < end; ++i) { - const BadWord *bw = ci->GetBadWord(i); + const BadWord *b = bw->GetBadWord(i); - if (!word.empty() && !Anope::Match(bw->word, word)) + if (!word.empty() && !Anope::Match(b->word, word)) continue; ListFormatter::ListEntry entry; entry["Number"] = stringify(i + 1); - entry["Word"] = bw->word; - entry["Type"] = bw->type == BW_SINGLE ? "(SINGLE)" : (bw->type == BW_START ? "(START)" : (bw->type == BW_END ? "(END)" : "")); + entry["Word"] = b->word; + entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : "")); list.AddEntry(entry); } } @@ -127,6 +251,7 @@ class CommandBSBadwords : public Command size_t pos = word.rfind(' '); BadWordType bwtype = BW_ANY; Anope::string realword = word; + BadWords *badwords = ci->Require<BadWords>("badwords"); if (pos != Anope::string::npos) { @@ -144,7 +269,7 @@ class CommandBSBadwords : public Command } unsigned badwordsmax = Config->GetModule(this->module)->Get<unsigned>("badwordsmax"); - if (ci->GetBadWordCount() >= badwordsmax) + if (badwords->GetBadWordCount() >= badwordsmax) { source.Reply(_("Sorry, you can only have %d bad words entries on a channel."), badwordsmax); return; @@ -152,9 +277,9 @@ class CommandBSBadwords : public Command bool casesensitive = Config->GetModule("botserv")->Get<bool>("casesensitive"); - for (unsigned i = 0, end = ci->GetBadWordCount(); i < end; ++i) + for (unsigned i = 0, end = badwords->GetBadWordCount(); i < end; ++i) { - const BadWord *bw = ci->GetBadWord(i); + const BadWord *bw = badwords->GetBadWord(i); if ((casesensitive && realword.equals_cs(bw->word)) || (!casesensitive && realword.equals_ci(bw->word))) { @@ -165,13 +290,21 @@ class CommandBSBadwords : public Command bool override = !source.AccessFor(ci).HasPriv("BADWORDS"); Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "ADD " << realword; - ci->AddBadWord(realword, bwtype); + badwords->AddBadWord(realword, bwtype); source.Reply(_("\002%s\002 added to %s bad words list."), realword.c_str(), ci->name.c_str()); } void DoDelete(CommandSource &source, ChannelInfo *ci, const Anope::string &word) { + BadWords *badwords = ci->GetExt<BadWords>("badwords"); + + if (!badwords || !badwords->GetBadWordCount()) + { + source.Reply(_("%s bad words list is empty."), ci->name.c_str()); + return; + } + /* Special case: is it a number/list? Only do search if it isn't. */ if (!word.empty() && isdigit(word[0]) && word.find_first_not_of("1234567890,-") == Anope::string::npos) { @@ -183,9 +316,9 @@ class CommandBSBadwords : public Command unsigned i, end; const BadWord *badword; - for (i = 0, end = ci->GetBadWordCount(); i < end; ++i) + for (i = 0, end = badwords->GetBadWordCount(); i < end; ++i) { - badword = ci->GetBadWord(i); + badword = badwords->GetBadWord(i); if (word.equals_ci(badword->word)) break; @@ -202,10 +335,10 @@ class CommandBSBadwords : public Command source.Reply(_("\002%s\002 deleted from %s bad words list."), badword->word.c_str(), ci->name.c_str()); - ci->EraseBadWord(i); + badwords->EraseBadWord(i); } - return; + badwords->Check(); } void DoClear(CommandSource &source, ChannelInfo *ci) @@ -213,7 +346,9 @@ class CommandBSBadwords : public Command bool override = !source.AccessFor(ci).HasPriv("BADWORDS"); Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "CLEAR"; - ci->ClearBadWords(); + BadWords *badwords = ci->GetExt<BadWords>("badwords"); + if (badwords) + badwords->ClearBadWords(); source.Reply(_("Bad words list is now empty.")); } @@ -309,10 +444,12 @@ class CommandBSBadwords : public Command class BSBadwords : public Module { CommandBSBadwords commandbsbadwords; + ExtensibleItem<BadWordsImpl> badwords; + Serialize::Type badword_type; public: BSBadwords(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandbsbadwords(this) + commandbsbadwords(this), badwords(this, "badwords"), badword_type("BadWord", BadWordImpl::Unserialize) { } }; diff --git a/modules/commands/bs_info.cpp b/modules/commands/bs_info.cpp index 8bbfd0b18..a3eb9ce2d 100644 --- a/modules/commands/bs_info.cpp +++ b/modules/commands/bs_info.cpp @@ -36,16 +36,6 @@ class CommandBSInfo : public Command buffers.push_back(buf); } - void CheckOptStr(Anope::string &buf, const Anope::string &flag, const char *option, Extensible *flags, const NickCore *nc) - { - if (flags->HasExt(flag)) - { - if (!buf.empty()) - buf += ", "; - buf += Language::Translate(nc, option); - } - } - public: CommandBSInfo(Module *creator) : Command(creator, "botserv/info", 1, 1) { @@ -57,8 +47,8 @@ class CommandBSInfo : public Command { const Anope::string &query = params[0]; - const BotInfo *bi = BotInfo::Find(query, true); - ChannelInfo *ci; + BotInfo *bi = BotInfo::Find(query, true); + ChannelInfo *ci = ChannelInfo::Find(query); InfoFormatter info(source.nc); if (bi) @@ -70,6 +60,8 @@ class CommandBSInfo : public Command info[_("Options")] = bi->oper_only ? _("Private") : _("None"); info[_("Used on")] = stringify(bi->GetChannelCount()) + " channel(s)"; + FOREACH_MOD(OnBotInfo, (source, bi, ci, info)); + std::vector<Anope::string> replies; info.Process(replies); @@ -85,7 +77,7 @@ class CommandBSInfo : public Command } } - else if ((ci = ChannelInfo::Find(query))) + else if (ci) { if (!source.AccessFor(ci).HasPriv("INFO") && !source.HasPriv("botserv/administration")) { @@ -99,114 +91,7 @@ class CommandBSInfo : public Command Anope::string enabled = Language::Translate(source.nc, _("Enabled")); Anope::string disabled = Language::Translate(source.nc, _("Disabled")); - if (ci->HasExt("BS_KICK_BADWORDS")) - { - if (ci->ttb[TTB_BADWORDS]) - info[_("Bad words kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), ci->ttb[TTB_BADWORDS]); - else - info[_("Bad words kicker")] = enabled; - } - else - info[_("Bad words kicker")] = disabled; - - if (ci->HasExt("BS_KICK_BOLDS")) - { - if (ci->ttb[TTB_BOLDS]) - info[_("Bolds kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), ci->ttb[TTB_BOLDS]); - else - info[_("Bolds kicker")] = enabled; - } - else - info[_("Bolds kicker")] = disabled; - - if (ci->HasExt("BS_KICK_CAPS")) - { - if (ci->ttb[TTB_CAPS]) - info[_("Caps kicker")] = Anope::printf(_("%s (%d kick(s) to ban; minimum %d/%d%%"), enabled.c_str(), ci->ttb[TTB_CAPS], ci->capsmin, ci->capspercent); - else - info[_("Caps kicker")] = Anope::printf(_("%s (minimum %d/%d%%)"), enabled.c_str(), ci->capsmin, ci->capspercent); - } - else - info[_("Caps kicker")] = disabled; - - if (ci->HasExt("BS_KICK_COLORS")) - { - if (ci->ttb[TTB_COLORS]) - info[_("Colors kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), ci->ttb[TTB_COLORS]); - else - info[_("Colors kicker")] = enabled; - } - else - info[_("Colors kicker")] = disabled; - - if (ci->HasExt("BS_KICK_FLOOD")) - { - if (ci->ttb[TTB_FLOOD]) - info[_("Flood kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d lines in %ds"), enabled.c_str(), ci->ttb[TTB_FLOOD], ci->floodlines, ci->floodsecs); - else - info[_("Flood kicker")] = Anope::printf(_("%s (%d lines in %ds)"), enabled.c_str(), ci->floodlines, ci->floodsecs); - } - else - info[_("Flood kicker")] = disabled; - - if (ci->HasExt("BS_KICK_REPEAT")) - { - if (ci->ttb[TTB_REPEAT]) - info[_("Repeat kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d times)"), enabled.c_str(), ci->ttb[TTB_REPEAT], ci->repeattimes); - else - info[_("Repeat kicker")] = Anope::printf(_("%s (%d times)"), enabled.c_str(), ci->repeattimes); - } - else - info[_("Repeat kicker")] = disabled; - - if (ci->HasExt("BS_KICK_REVERSES")) - { - if (ci->ttb[TTB_REVERSES]) - info[_("Reverses kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), ci->ttb[TTB_REVERSES]); - else - info[_("Reverses kicker")] = enabled; - } - else - info[_("Reverses kicker")] = disabled; - - if (ci->HasExt("BS_KICK_UNDERLINES")) - { - if (ci->ttb[TTB_UNDERLINES]) - info[_("Underlines kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), ci->ttb[TTB_UNDERLINES]); - else - info[_("Underlines kicker")] = enabled; - } - else - info[_("Underlines kicker")] = disabled; - - if (ci->HasExt("BS_KICK_ITALICS")) - { - if (ci->ttb[TTB_ITALICS]) - info[_("Italics kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), ci->ttb[TTB_ITALICS]); - else - info[_("Italics kicker")] = enabled; - } - else - info[_("Italics kicker")] = disabled; - - if (ci->HasExt("BS_KICK_AMSGS")) - { - if (ci->ttb[TTB_AMSGS]) - info[_("AMSG kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), ci->ttb[TTB_AMSGS]); - else - info[_("AMSG kicker")] = enabled; - } - else - info[_("AMSG kicker")] = disabled; - - Anope::string flags; - CheckOptStr(flags, "BS_DONTKICKOPS", _("Ops protection"), ci, source.nc); - CheckOptStr(flags, "BS_DONTKICKVOICES", _("Voices protection"), ci, source.nc); - CheckOptStr(flags, "BS_FANTASY", _("Fantasy"), ci, source.nc); - CheckOptStr(flags, "BS_GREET", _("Greet"), ci, source.nc); - CheckOptStr(flags, "BS_NOBOT", _("No bot"), ci, source.nc); - - info[_("Options")] = flags.empty() ? _("None") : flags; + FOREACH_MOD(OnBotInfo, (source, bi, ci, info)); std::vector<Anope::string> replies; info.Process(replies); diff --git a/modules/commands/bs_kick.cpp b/modules/commands/bs_kick.cpp index 50d4a0e5f..b22dd9ccb 100644 --- a/modules/commands/bs_kick.cpp +++ b/modules/commands/bs_kick.cpp @@ -12,9 +12,107 @@ */ #include "module.h" +#include "modules/bs_kick.h" +#include "modules/bs_badwords.h" static Module *me; +struct KickerDataImpl : KickerData +{ + KickerDataImpl(Extensible *obj) + { + amsgs = badwords = bolds = caps = colors = flood = italics = repeat = reverses = underlines = false; + for (int16_t i = 0; i < TTB_SIZE; ++i) + ttb[i] = 0; + capsmin = capspercent = 0; + floodlines = floodsecs = 0; + repeattimes = 0; + + dontkickops = dontkickvoices = false; + } + + void Check(ChannelInfo *ci) anope_override + { + if (amsgs || badwords || bolds || caps || colors || flood || italics || repeat || reverses || underlines) + return; + + ci->Shrink<KickerData>("kickerdata"); + } + + struct ExtensibleItem : ::ExtensibleItem<KickerDataImpl> + { + ExtensibleItem(Module *m, const Anope::string &name) : ::ExtensibleItem<KickerDataImpl>(m, name) { } + + void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const anope_override + { + if (s->GetSerializableType()->GetName() != "ChannelInfo") + return; + + const ChannelInfo *ci = anope_dynamic_static_cast<const ChannelInfo *>(e); + KickerData *kd = this->Get(ci); + if (kd == NULL) + return; + + data["kickerdata:amsgs"] << kd->amsgs; + data["kickerdata:badwords"] << kd->badwords; + data["kickerdata:bolds"] << kd->bolds; + data["kickerdata:caps"] << kd->caps; + data["kickerdata:colors"] << kd->colors; + data["kickerdata:flood"] << kd->flood; + data["kickerdata:italics"] << kd->italics; + data["kickerdata:repeat"] << kd->repeat; + data["kickerdata:reverses"] << kd->reverses; + data["kickerdata:underlines"] << kd->underlines; + + data.SetType("capsmin", Serialize::Data::DT_INT); data["capsmin"] << kd->capsmin; + data.SetType("capspercent", Serialize::Data::DT_INT); data["capspercent"] << kd->capspercent; + data.SetType("floodlines", Serialize::Data::DT_INT); data["floodlines"] << kd->floodlines; + data.SetType("floodsecs", Serialize::Data::DT_INT); data["floodsecs"] << kd->floodsecs; + data.SetType("repeattimes", Serialize::Data::DT_INT); data["repeattimes"] << kd->repeattimes; + for (int16_t i = 0; i < TTB_SIZE; ++i) + data["ttb"] << kd->ttb[i] << " "; + } + + void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) anope_override + { + if (s->GetSerializableType()->GetName() != "ChannelInfo") + return; + + ChannelInfo *ci = anope_dynamic_static_cast<ChannelInfo *>(e); + KickerData *kd = ci->Require<KickerData>("kickerdata"); + + data["kickerdata:amsgs"] >> kd->amsgs; + data["kickerdata:badwords"] >> kd->badwords; + data["kickerdata:bolds"] >> kd->bolds; + data["kickerdata:caps"] >> kd->caps; + data["kickerdata:colors"] >> kd->colors; + data["kickerdata:flood"] >> kd->flood; + data["kickerdata:italics"] >> kd->italics; + data["kickerdata:repeat"] >> kd->repeat; + data["kickerdata:reverses"] >> kd->reverses; + data["kickerdata:underlines"] >> kd->underlines; + + data["capsmin"] >> kd->capsmin; + data["capspercent"] >> kd->capspercent; + data["floodlines"] >> kd->floodlines; + data["floodsecs"] >> kd->floodsecs; + data["repeattimes"] >> kd->repeattimes; + + Anope::string ttb, tok; + data["ttb"] >> ttb; + spacesepstream sep(ttb); + for (int i = 0; sep.GetToken(tok) && i < TTB_SIZE; ++i) + try + { + ttb[i] = convertTo<int16_t>(tok); + } + catch (const ConvertException &) { } + + kd->Check(ci); + } + }; +}; + class CommandBSKick : public Command { public: @@ -99,7 +197,7 @@ class CommandBSKickBase : public Command return false; } - void Process(CommandSource &source, ChannelInfo *ci, const Anope::string ¶m, const Anope::string &ttb, size_t ttb_idx, const Anope::string &optname, const Anope::string &mdname) + void Process(CommandSource &source, ChannelInfo *ci, const Anope::string ¶m, const Anope::string &ttb, size_t ttb_idx, const Anope::string &optname, KickerData *kd, bool &val) { if (param.equals_ci("ON")) { @@ -119,15 +217,15 @@ class CommandBSKickBase : public Command return; } - ci->ttb[ttb_idx] = i; + kd->ttb[ttb_idx] = i; } else - ci->ttb[ttb_idx] = 0; + kd->ttb[ttb_idx] = 0; - ci->ExtendMetadata(mdname); - if (ci->ttb[ttb_idx]) + val = true; + if (kd->ttb[ttb_idx]) source.Reply(_("Bot will now kick for \002%s\002, and will place a ban\n" - "after %d kicks for the same user."), optname.c_str(), ci->ttb[ttb_idx]); + "after %d kicks for the same user."), optname.c_str(), kd->ttb[ttb_idx]); else source.Reply(_("Bot will now kick for \002%s\002."), optname.c_str()); @@ -139,7 +237,7 @@ class CommandBSKickBase : public Command bool override = !source.AccessFor(ci).HasPriv("SET"); Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable the " << optname << "kicker"; - ci->Shrink(mdname); + val = false; source.Reply(_("Bot won't kick for \002%s\002 anymore."), optname.c_str()); } else @@ -160,7 +258,11 @@ class CommandBSKickAMSG : public CommandBSKickBase { ChannelInfo *ci; if (CheckArguments(source, params, ci)) - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_AMSGS, "AMSG", "BS_KICK_AMSGS"); + { + KickerData *kd = ci->Require<KickerData>("kickerdata"); + Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_AMSGS, "AMSG", kd, kd->amsgs); + kd->Check(ci); + } } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -188,7 +290,12 @@ class CommandBSKickBadwords : public CommandBSKickBase { ChannelInfo *ci; if (CheckArguments(source, params, ci)) - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_BADWORDS, "badwords", "BS_KICK_BADWORDS"); + { + KickerData *kd = ci->Require<KickerData>("kickerdata"); + Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_BADWORDS, "badwords", kd, kd->badwords); + kd->Check(ci); + } + } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -219,7 +326,11 @@ class CommandBSKickBolds : public CommandBSKickBase { ChannelInfo *ci; if (CheckArguments(source, params, ci)) - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_BOLDS, "bolds", "BS_KICK_BOLDS"); + { + KickerData *kd = ci->Require<KickerData>("kickerdata"); + Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_BOLDS, "bolds", kd, kd->bolds); + kd->Check(ci); + } } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -248,6 +359,8 @@ class CommandBSKickCaps : public CommandBSKickBase if (!CheckArguments(source, params, ci)) return; + KickerData *kd = ci->Require<KickerData>("kickerdata"); + if (params[1].equals_ci("ON")) { const Anope::string &ttb = params.size() > 2 ? params[2] : "", @@ -258,52 +371,54 @@ class CommandBSKickCaps : public CommandBSKickBase { try { - ci->ttb[TTB_CAPS] = convertTo<int16_t>(ttb); - if (ci->ttb[TTB_CAPS] < 0) + kd->ttb[TTB_CAPS] = convertTo<int16_t>(ttb); + if (kd->ttb[TTB_CAPS] < 0) throw ConvertException(); } catch (const ConvertException &) { - ci->ttb[TTB_CAPS] = 0; + kd->ttb[TTB_CAPS] = 0; source.Reply(_("\002%s\002 cannot be taken as times to ban."), ttb.c_str()); return; } } else - ci->ttb[TTB_CAPS] = 0; + kd->ttb[TTB_CAPS] = 0; - ci->capsmin = 10; + kd->capsmin = 10; try { - ci->capsmin = convertTo<int16_t>(min); + kd->capsmin = convertTo<int16_t>(min); } catch (const ConvertException &) { } - if (ci->capsmin < 1) - ci->capsmin = 10; + if (kd->capsmin < 1) + kd->capsmin = 10; - ci->capspercent = 25; + kd->capspercent = 25; try { - ci->capspercent = convertTo<int16_t>(percent); + kd->capspercent = convertTo<int16_t>(percent); } catch (const ConvertException &) { } - if (ci->capspercent < 1 || ci->capspercent > 100) - ci->capspercent = 25; + if (kd->capspercent < 1 || kd->capspercent > 100) + kd->capspercent = 25; - ci->ExtendMetadata("BS_KICK_CAPS"); - if (ci->ttb[TTB_CAPS]) + kd->caps = true; + if (kd->ttb[TTB_CAPS]) source.Reply(_("Bot will now kick for \002caps\002 (they must constitute at least\n" "%d characters and %d%% of the entire message), and will\n" - "place a ban after %d kicks for the same user."), ci->capsmin, ci->capspercent, ci->ttb[TTB_CAPS]); + "place a ban after %d kicks for the same user."), kd->capsmin, kd->capspercent, kd->ttb[TTB_CAPS]); else source.Reply(_("Bot will now kick for \002caps\002 (they must constitute at least\n" - "%d characters and %d%% of the entire message)."), ci->capsmin, ci->capspercent); + "%d characters and %d%% of the entire message)."), kd->capsmin, kd->capspercent); } else { - ci->Shrink("BS_KICK_CAPS"); + kd->caps = false; source.Reply(_("Bot won't kick for \002caps\002 anymore.")); } + + kd->Check(ci); } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -335,7 +450,11 @@ class CommandBSKickColors : public CommandBSKickBase { ChannelInfo *ci; if (CheckArguments(source, params, ci)) - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_COLORS, "colors", "BS_KICK_COLORS"); + { + KickerData *kd = ci->Require<KickerData>("kickerdata"); + Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_COLORS, "colors", kd, kd->colors); + kd->Check(ci); + } } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -364,6 +483,8 @@ class CommandBSKickFlood : public CommandBSKickBase if (!CheckArguments(source, params, ci)) return; + KickerData *kd = ci->Require<KickerData>("kickerdata"); + if (params[1].equals_ci("ON")) { const Anope::string &ttb = params.size() > 2 ? params[2] : "", @@ -386,45 +507,47 @@ class CommandBSKickFlood : public CommandBSKickBase return; } - ci->ttb[TTB_FLOOD] = i; + kd->ttb[TTB_FLOOD] = i; } else - ci->ttb[TTB_FLOOD] = 0; + kd->ttb[TTB_FLOOD] = 0; - ci->floodlines = 6; + kd->floodlines = 6; try { - ci->floodlines = convertTo<int16_t>(lines); + kd->floodlines = convertTo<int16_t>(lines); } catch (const ConvertException &) { } - if (ci->floodlines < 2) - ci->floodlines = 6; + if (kd->floodlines < 2) + kd->floodlines = 6; - ci->floodsecs = 10; + kd->floodsecs = 10; try { - ci->floodsecs = convertTo<int16_t>(secs); + kd->floodsecs = convertTo<int16_t>(secs); } catch (const ConvertException &) { } - if (ci->floodsecs < 1) - ci->floodsecs = 10; - if (ci->floodsecs > Config->GetModule(me)->Get<time_t>("keepdata")) - ci->floodsecs = Config->GetModule(me)->Get<time_t>("keepdata"); + if (kd->floodsecs < 1) + kd->floodsecs = 10; + if (kd->floodsecs > Config->GetModule(me)->Get<time_t>("keepdata")) + kd->floodsecs = Config->GetModule(me)->Get<time_t>("keepdata"); - ci->ExtendMetadata("BS_KICK_FLOOD"); - if (ci->ttb[TTB_FLOOD]) + kd->flood = true; + if (kd->ttb[TTB_FLOOD]) source.Reply(_("Bot will now kick for \002flood\002 (%d lines in %d seconds\n" - "and will place a ban after %d kicks for the same user."), ci->floodlines, ci->floodsecs, ci->ttb[TTB_FLOOD]); + "and will place a ban after %d kicks for the same user."), kd->floodlines, kd->floodsecs, kd->ttb[TTB_FLOOD]); else - source.Reply(_("Bot will now kick for \002flood\002 (%d lines in %d seconds)."), ci->floodlines, ci->floodsecs); + source.Reply(_("Bot will now kick for \002flood\002 (%d lines in %d seconds)."), kd->floodlines, kd->floodsecs); } else if (params[1].equals_ci("OFF")) { - ci->Shrink("BS_KICK_FLOOD"); + kd->flood = false; source.Reply(_("Bot won't kick for \002flood\002 anymore.")); } else this->OnSyntaxError(source, params[1]); + + kd->Check(ci); } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -454,7 +577,11 @@ class CommandBSKickItalics : public CommandBSKickBase { ChannelInfo *ci; if (CheckArguments(source, params, ci)) - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_ITALICS, "italics", "BS_KICK_ITALICS"); + { + KickerData *kd = ci->Require<KickerData>("kickerdata"); + Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_ITALICS, "italics", kd, kd->italics); + kd->Check(ci); + } } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -483,6 +610,8 @@ class CommandBSKickRepeat : public CommandBSKickBase if (!CheckArguments(source, params, ci)) return; + KickerData *kd = ci->Require<KickerData>("kickerdata"); + if (params[1].equals_ci("ON")) { const Anope::string &ttb = params[2], @@ -504,36 +633,38 @@ class CommandBSKickRepeat : public CommandBSKickBase return; } - ci->ttb[TTB_REPEAT] = i; + kd->ttb[TTB_REPEAT] = i; } else - ci->ttb[TTB_REPEAT] = 0; + kd->ttb[TTB_REPEAT] = 0; - ci->repeattimes = 3; + kd->repeattimes = 3; try { - ci->repeattimes = convertTo<int16_t>(times); + kd->repeattimes = convertTo<int16_t>(times); } catch (const ConvertException &) { } - if (ci->repeattimes < 2) - ci->repeattimes = 3; + if (kd->repeattimes < 2) + kd->repeattimes = 3; - ci->ExtendMetadata("BS_KICK_REPEAT"); - if (ci->ttb[TTB_REPEAT]) + kd->repeat = true; + if (kd->ttb[TTB_REPEAT]) source.Reply(_("Bot will now kick for \002repeats\002 (users that say the\n" "same thing %d times), and will place a ban after %d\n" - "kicks for the same user."), ci->repeattimes, ci->ttb[TTB_REPEAT]); + "kicks for the same user."), kd->repeattimes, kd->ttb[TTB_REPEAT]); else source.Reply(_("Bot will now kick for \002repeats\002 (users that say the\n" - "same thing %d times)."), ci->repeattimes); + "same thing %d times)."), kd->repeattimes); } else if (params[1].equals_ci("OFF")) { - ci->Shrink("BS_KICK_REPEAT"); + kd->repeat = false; source.Reply(_("Bot won't kick for \002repeats\002 anymore.")); } else this->OnSyntaxError(source, params[1]); + + kd->Check(ci); } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -562,7 +693,11 @@ class CommandBSKickReverses : public CommandBSKickBase { ChannelInfo *ci; if (CheckArguments(source, params, ci)) - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_ITALICS, "italics", "BS_KICK_ITALICS"); + { + KickerData *kd = ci->Require<KickerData>("kickerdata"); + Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_REVERSES, "reverses", kd, kd->reverses); + kd->Check(ci); + } } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -589,7 +724,11 @@ class CommandBSKickUnderlines : public CommandBSKickBase { ChannelInfo *ci; if (CheckArguments(source, params, ci)) - Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_ITALICS, "italics", "BS_KICK_ITALICS"); + { + KickerData *kd = ci->Require<KickerData>("kickerdata"); + Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_UNDERLINES, "underlines", kd, kd->underlines); + kd->Check(ci); + } } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -603,7 +742,137 @@ class CommandBSKickUnderlines : public CommandBSKickBase } }; -struct BanData : ExtensibleItem +class CommandBSSetDontKickOps : public Command +{ + public: + CommandBSSetDontKickOps(Module *creator, const Anope::string &sname = "botserv/set/dontkickops") : Command(creator, sname, 2, 2) + { + this->SetDesc(_("To protect ops against bot kicks")); + this->SetSyntax(_("\037channel\037 {ON | OFF}")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + ChannelInfo *ci = ChannelInfo::Find(params[0]); + if (ci == NULL) + { + source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + return; + } + + AccessGroup access = source.AccessFor(ci); + if (!source.HasPriv("botserv/administration") && !access.HasPriv("SET")) + { + source.Reply(ACCESS_DENIED); + return; + } + + if (Anope::ReadOnly) + { + source.Reply(_("Sorry, bot option setting is temporarily disabled.")); + return; + } + + KickerData *kd = ci->Require<KickerData>("kickerdata"); + if (params[1].equals_ci("ON")) + { + bool override = !access.HasPriv("SET"); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable dontkickops"; + + kd->dontkickops = true; + source.Reply(_("Bot \002won't kick ops\002 on channel %s."), ci->name.c_str()); + } + else if (params[1].equals_ci("OFF")) + { + bool override = !access.HasPriv("SET"); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable dontkickops"; + + kd->dontkickops = false; + source.Reply(_("Bot \002will kick ops\002 on channel %s."), ci->name.c_str()); + } + else + this->OnSyntaxError(source, source.command); + + kd->Check(ci); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(_(" \n" + "Enables or disables \002ops protection\002 mode on a channel.\n" + "When it is enabled, ops won't be kicked by the bot\n" + "even if they don't match the NOKICK level.")); + return true; + } +}; + +class CommandBSSetDontKickVoices : public Command +{ + public: + CommandBSSetDontKickVoices(Module *creator, const Anope::string &sname = "botserv/set/dontkickvoices") : Command(creator, sname, 2, 2) + { + this->SetDesc(_("To protect voices against bot kicks")); + this->SetSyntax(_("\037channel\037 {ON | OFF}")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + ChannelInfo *ci = ChannelInfo::Find(params[0]); + if (ci == NULL) + { + source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + return; + } + + AccessGroup access = source.AccessFor(ci); + if (!source.HasPriv("botserv/administration") && !access.HasPriv("SET")) + { + source.Reply(ACCESS_DENIED); + return; + } + + if (Anope::ReadOnly) + { + source.Reply(_("Sorry, bot option setting is temporarily disabled.")); + return; + } + + KickerData *kd = ci->Require<KickerData>("kickerdata"); + if (params[1].equals_ci("ON")) + { + bool override = !access.HasPriv("SET"); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable dontkickvoices"; + + kd->dontkickvoices = true; + source.Reply(_("Bot \002won't kick voices\002 on channel %s."), ci->name.c_str()); + } + else if (params[1].equals_ci("OFF")) + { + bool override = !access.HasPriv("SET"); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable dontkickvoices"; + + kd->dontkickvoices = false; + source.Reply(_("Bot \002will kick voices\002 on channel %s."), ci->name.c_str()); + } + else + this->OnSyntaxError(source, source.command); + + kd->Check(ci); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(_(" \n" + "Enables or disables \002voices protection\002 mode on a channel.\n" + "When it is enabled, voices won't be kicked by the bot\n" + "even if they don't match the NOKICK level.")); + return true; + } +}; + +struct BanData { struct Data { @@ -613,11 +882,6 @@ struct BanData : ExtensibleItem Data() { - this->Clear(); - } - - void Clear() - { last_use = 0; for (int i = 0; i < TTB_SIZE; ++i) this->ttb[i] = 0; @@ -625,10 +889,12 @@ struct BanData : ExtensibleItem }; private: - typedef std::map<Anope::string, Data, ci::less> data_type; + typedef Anope::map<Data> data_type; data_type data_map; public: + BanData(Extensible *) { } + Data &get(const Anope::string &key) { return this->data_map[key]; @@ -654,14 +920,9 @@ struct BanData : ExtensibleItem } }; -struct UserData : ExtensibleItem +struct UserData { - UserData() - { - this->Clear(); - } - - void Clear() + UserData(Extensible *) { last_use = last_start = Anope::CurTime; lines = times = 0; @@ -682,7 +943,6 @@ struct UserData : ExtensibleItem Anope::string lastline; }; - class BanDataPurger : public Timer { public: @@ -696,12 +956,12 @@ class BanDataPurger : public Timer { Channel *c = it->second; - BanData *bd = c->GetExt<BanData *>("bs_main_bandata"); + BanData *bd = c->GetExt<BanData>("bandata"); if (bd != NULL) { bd->purge(); if (bd->empty()) - c->Shrink("bs_main_bandata"); + c->Shrink<BanData>("bandata"); } } } @@ -709,6 +969,10 @@ class BanDataPurger : public Timer class BSKick : public Module { + ExtensibleItem<BanData> bandata; + ExtensibleItem<UserData> userdata; + KickerDataImpl::ExtensibleItem kickerdata; + CommandBSKick commandbskick; CommandBSKickAMSG commandbskickamsg; CommandBSKickBadwords commandbskickbadwords; @@ -721,17 +985,14 @@ class BSKick : public Module CommandBSKickReverses commandbskickreverse; CommandBSKickUnderlines commandbskickunderlines; + CommandBSSetDontKickOps commandbssetdontkickops; + CommandBSSetDontKickVoices commandbssetdontkickvoices; + BanDataPurger purger; BanData::Data &GetBanData(User *u, Channel *c) { - BanData *bd = c->GetExt<BanData *>("bs_main_bandata"); - if (bd == NULL) - { - bd = new BanData(); - c->Extend("bs_main_bandata", bd); - } - + BanData *bd = bandata.Require(c); return bd->get(u->GetMask()); } @@ -741,17 +1002,11 @@ class BSKick : public Module if (uc == NULL) return NULL; - UserData *ud = uc->GetExt<UserData *>("bs_main_userdata"); - if (ud == NULL) - { - ud = new UserData(); - uc->Extend("bs_main_userdata", ud); - } - + UserData *ud = userdata.Require(uc); return ud; } - void check_ban(ChannelInfo *ci, User *u, int ttbtype) + void check_ban(ChannelInfo *ci, User *u, KickerData *kd, int ttbtype) { /* Don't ban ulines */ if (u->server->IsULined()) @@ -760,9 +1015,9 @@ class BSKick : public Module BanData::Data &bd = this->GetBanData(u, ci->c); ++bd.ttb[ttbtype]; - if (ci->ttb[ttbtype] && bd.ttb[ttbtype] >= ci->ttb[ttbtype]) + if (kd->ttb[ttbtype] && bd.ttb[ttbtype] >= kd->ttb[ttbtype]) { - /* Should not use == here because bd.ttb[ttbtype] could possibly be > ci->ttb[ttbtype] + /* Should not use == here because bd.ttb[ttbtype] could possibly be > kd->ttb[ttbtype] * if the TTB was changed after it was not set (0) before and the user had already been * kicked a few times. Bug #1056 - Adam */ @@ -793,26 +1048,136 @@ class BSKick : public Module public: BSKick(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), + bandata(this, "bandata"), + userdata(this, "userdata"), + kickerdata(this, "kickerdata"), + commandbskick(this), commandbskickamsg(this), commandbskickbadwords(this), commandbskickbolds(this), commandbskickcaps(this), commandbskickcolors(this), commandbskickflood(this), commandbskickitalics(this), commandbskickrepeat(this), commandbskickreverse(this), commandbskickunderlines(this), + commandbssetdontkickops(this), commandbssetdontkickvoices(this), + purger(this) { me = this; } - ~BSKick() + void OnBotInfo(CommandSource &source, BotInfo *bi, ChannelInfo *ci, InfoFormatter &info) anope_override { - for (channel_map::const_iterator cit = ChannelList.begin(), cit_end = ChannelList.end(); cit != cit_end; ++cit) + if (!ci) + return; + + Anope::string enabled = Language::Translate(source.nc, _("Enabled")); + Anope::string disabled = Language::Translate(source.nc, _("Disabled")); + KickerData *kd = kickerdata.Get(ci); + + if (kd && kd->badwords) + { + if (kd->ttb[TTB_BADWORDS]) + info[_("Bad words kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BADWORDS]); + else + info[_("Bad words kicker")] = enabled; + } + else + info[_("Bad words kicker")] = disabled; + + if (kd && kd->bolds) + { + if (kd->ttb[TTB_BOLDS]) + info[_("Bolds kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BOLDS]); + else + info[_("Bolds kicker")] = enabled; + } + else + info[_("Bolds kicker")] = disabled; + + if (kd && kd->caps) + { + if (kd->ttb[TTB_CAPS]) + info[_("Caps kicker")] = Anope::printf(_("%s (%d kick(s) to ban; minimum %d/%d%%"), enabled.c_str(), kd->ttb[TTB_CAPS], kd->capsmin, kd->capspercent); + else + info[_("Caps kicker")] = Anope::printf(_("%s (minimum %d/%d%%)"), enabled.c_str(), kd->capsmin, kd->capspercent); + } + else + info[_("Caps kicker")] = disabled; + + if (kd && kd->colors) + { + if (kd->ttb[TTB_COLORS]) + info[_("Colors kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_COLORS]); + else + info[_("Colors kicker")] = enabled; + } + else + info[_("Colors kicker")] = disabled; + + if (kd && kd->flood) + { + if (kd->ttb[TTB_FLOOD]) + info[_("Flood kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d lines in %ds"), enabled.c_str(), kd->ttb[TTB_FLOOD], kd->floodlines, kd->floodsecs); + else + info[_("Flood kicker")] = Anope::printf(_("%s (%d lines in %ds)"), enabled.c_str(), kd->floodlines, kd->floodsecs); + } + else + info[_("Flood kicker")] = disabled; + + if (kd && kd->repeat) { - Channel *c = cit->second; - for (Channel::ChanUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end; ++it) - it->second->Shrink("bs_main_userdata"); - c->Shrink("bs_main_bandata"); + if (kd->ttb[TTB_REPEAT]) + info[_("Repeat kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d times)"), enabled.c_str(), kd->ttb[TTB_REPEAT], kd->repeattimes); + else + info[_("Repeat kicker")] = Anope::printf(_("%s (%d times)"), enabled.c_str(), kd->repeattimes); + } + else + info[_("Repeat kicker")] = disabled; + + if (kd && kd->reverses) + { + if (kd->ttb[TTB_REVERSES]) + info[_("Reverses kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_REVERSES]); + else + info[_("Reverses kicker")] = enabled; } + else + info[_("Reverses kicker")] = disabled; + + if (kd && kd->underlines) + { + if (kd->ttb[TTB_UNDERLINES]) + info[_("Underlines kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_UNDERLINES]); + else + info[_("Underlines kicker")] = enabled; + } + else + info[_("Underlines kicker")] = disabled; + + if (kd && kd->italics) + { + if (kd->ttb[TTB_ITALICS]) + info[_("Italics kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_ITALICS]); + else + info[_("Italics kicker")] = enabled; + } + else + info[_("Italics kicker")] = disabled; + + if (kd && kd->amsgs) + { + if (kd->ttb[TTB_AMSGS]) + info[_("AMSG kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_AMSGS]); + else + info[_("AMSG kicker")] = enabled; + } + else + info[_("AMSG kicker")] = disabled; + + if (kd && kd->dontkickops) + info.AddOption(_("Ops Protection")); + if (kd && kd->dontkickvoices) + info.AddOption(_("Voices Protection")); } void OnPrivmsg(User *u, Channel *c, Anope::string &msg) anope_override @@ -828,12 +1193,15 @@ class BSKick : public Module ChannelInfo *ci = c->ci; if (ci == NULL) return; + KickerData *kd = kickerdata.Get(ci); + if (kd == NULL) + return; if (ci->AccessFor(u).HasPriv("NOKICK")) return; - else if (ci->HasExt("BS_DONTKICKOPS") && (c->HasUserStatus(u, "HALFOP") || c->HasUserStatus(u, "OP") || c->HasUserStatus(u, "PROTECT") || c->HasUserStatus(u, "OWNER"))) + else if (kd->dontkickops && (c->HasUserStatus(u, "HALFOP") || c->HasUserStatus(u, "OP") || c->HasUserStatus(u, "PROTECT") || c->HasUserStatus(u, "OWNER"))) return; - else if (ci->HasExt("BS_DONTKICKVOICES") && c->HasUserStatus(u, "VOICE")) + else if (kd->dontkickvoices && c->HasUserStatus(u, "VOICE")) return; Anope::string realbuf = msg; @@ -851,47 +1219,47 @@ class BSKick : public Module return; /* Bolds kicker */ - if (ci->HasExt("BS_KICK_BOLDS") && realbuf.find(2) != Anope::string::npos) + if (kd->bolds && realbuf.find(2) != Anope::string::npos) { - check_ban(ci, u, TTB_BOLDS); + check_ban(ci, u, kd, TTB_BOLDS); bot_kick(ci, u, _("Don't use bolds on this channel!")); return; } /* Color kicker */ - if (ci->HasExt("BS_KICK_COLORS") && realbuf.find(3) != Anope::string::npos) + if (kd->colors && realbuf.find(3) != Anope::string::npos) { - check_ban(ci, u, TTB_COLORS); + check_ban(ci, u, kd, TTB_COLORS); bot_kick(ci, u, _("Don't use colors on this channel!")); return; } /* Reverses kicker */ - if (ci->HasExt("BS_KICK_REVERSES") && realbuf.find(22) != Anope::string::npos) + if (kd->reverses && realbuf.find(22) != Anope::string::npos) { - check_ban(ci, u, TTB_REVERSES); + check_ban(ci, u, kd, TTB_REVERSES); bot_kick(ci, u, _("Don't use reverses on this channel!")); return; } /* Italics kicker */ - if (ci->HasExt("BS_KICK_ITALICS") && realbuf.find(29) != Anope::string::npos) + if (kd->italics && realbuf.find(29) != Anope::string::npos) { - check_ban(ci, u, TTB_ITALICS); + check_ban(ci, u, kd, TTB_ITALICS); bot_kick(ci, u, _("Don't use italics on this channel!")); return; } /* Underlines kicker */ - if (ci->HasExt("BS_KICK_UNDERLINES") && realbuf.find(31) != Anope::string::npos) + if (kd->underlines && realbuf.find(31) != Anope::string::npos) { - check_ban(ci, u, TTB_UNDERLINES); + check_ban(ci, u, kd, TTB_UNDERLINES); bot_kick(ci, u, _("Don't use underlines on this channel!")); return; } /* Caps kicker */ - if (ci->HasExt("BS_KICK_CAPS") && realbuf.length() >= static_cast<unsigned>(ci->capsmin)) + if (kd->caps && realbuf.length() >= static_cast<unsigned>(kd->capsmin)) { int i = 0, l = 0; @@ -908,26 +1276,27 @@ class BSKick : public Module * percentage of caps to kick for; the rest is ignored. -GD */ - if ((i || l) && i >= ci->capsmin && i * 100 / (i + l) >= ci->capspercent) + if ((i || l) && i >= kd->capsmin && i * 100 / (i + l) >= kd->capspercent) { - check_ban(ci, u, TTB_CAPS); + check_ban(ci, u, kd, TTB_CAPS); bot_kick(ci, u, _("Turn caps lock OFF!")); return; } } /* Bad words kicker */ - if (ci->HasExt("BS_KICK_BADWORDS")) + if (kd->badwords) { bool mustkick = false; + BadWords *badwords = ci->GetExt<BadWords>("badwords"); /* Normalize the buffer */ Anope::string nbuf = Anope::NormalizeBuffer(realbuf); bool casesensitive = Config->GetModule("botserv")->Get<bool>("casesensitive"); - for (unsigned i = 0, end = ci->GetBadWordCount(); i < end; ++i) + for (unsigned i = 0; badwords && i < badwords->GetBadWordCount(); ++i) { - const BadWord *bw = ci->GetBadWord(i); + const BadWord *bw = badwords->GetBadWord(i); if (bw->type == BW_ANY && ((casesensitive && nbuf.find(bw->word) != Anope::string::npos) || (!casesensitive && nbuf.find_ci(bw->word) != Anope::string::npos))) mustkick = true; @@ -983,7 +1352,7 @@ class BSKick : public Module if (mustkick) { - check_ban(ci, u, TTB_BADWORDS); + check_ban(ci, u, kd, TTB_BADWORDS); if (Config->GetModule(me)->Get<bool>("gentlebadwordreason")) bot_kick(ci, u, _("Watch your language!")); else @@ -999,34 +1368,34 @@ class BSKick : public Module if (ud) { /* Flood kicker */ - if (ci->HasExt("BS_KICK_FLOOD")) + if (kd->flood) { - if (Anope::CurTime - ud->last_start > ci->floodsecs) + if (Anope::CurTime - ud->last_start > kd->floodsecs) { ud->last_start = Anope::CurTime; ud->lines = 0; } ++ud->lines; - if (ud->lines >= ci->floodlines) + if (ud->lines >= kd->floodlines) { - check_ban(ci, u, TTB_FLOOD); + check_ban(ci, u, kd, TTB_FLOOD); bot_kick(ci, u, _("Stop flooding!")); return; } } /* Repeat kicker */ - if (ci->HasExt("BS_KICK_REPEAT")) + if (kd->repeat) { if (!ud->lastline.equals_ci(realbuf)) ud->times = 0; else ++ud->times; - if (ud->times >= ci->repeattimes) + if (ud->times >= kd->repeattimes) { - check_ban(ci, u, TTB_REPEAT); + check_ban(ci, u, kd, TTB_REPEAT); bot_kick(ci, u, _("Stop repeating yourself!")); return; } @@ -1039,9 +1408,9 @@ class BSKick : public Module Channel *chan = it->second->chan; ++it; - if (chan->ci && chan->ci->HasExt("BS_KICK_AMSGS") && !chan->ci->AccessFor(u).HasPriv("NOKICK")) + if (chan->ci && kd->amsgs && !chan->ci->AccessFor(u).HasPriv("NOKICK")) { - check_ban(chan->ci, u, TTB_AMSGS); + check_ban(chan->ci, u, kd, TTB_AMSGS); bot_kick(chan->ci, u, _("Don't use AMSGs!")); } } diff --git a/modules/commands/bs_set.cpp b/modules/commands/bs_set.cpp index fa2bd716f..4e1e77ad1 100644 --- a/modules/commands/bs_set.cpp +++ b/modules/commands/bs_set.cpp @@ -127,314 +127,6 @@ class CommandBSSetBanExpire : public Command } }; -class CommandBSSetDontKickOps : public Command -{ - public: - CommandBSSetDontKickOps(Module *creator, const Anope::string &sname = "botserv/set/dontkickops") : Command(creator, sname, 2, 2) - { - this->SetDesc(_("To protect ops against bot kicks")); - this->SetSyntax(_("\037channel\037 {ON | OFF}")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci = ChannelInfo::Find(params[0]); - if (ci == NULL) - { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); - return; - } - - AccessGroup access = source.AccessFor(ci); - if (!source.HasPriv("botserv/administration") && !access.HasPriv("SET")) - { - source.Reply(ACCESS_DENIED); - return; - } - - if (Anope::ReadOnly) - { - source.Reply(_("Sorry, bot option setting is temporarily disabled.")); - return; - } - - if (params[1].equals_ci("ON")) - { - bool override = !access.HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable dontkickops"; - - ci->ExtendMetadata("BS_DONTKICKOPS"); - source.Reply(_("Bot \002won't kick ops\002 on channel %s."), ci->name.c_str()); - } - else if (params[1].equals_ci("OFF")) - { - bool override = !access.HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable dontkickops"; - - ci->Shrink("BS_DONTKICKOPS"); - source.Reply(_("Bot \002will kick ops\002 on channel %s."), ci->name.c_str()); - } - else - this->OnSyntaxError(source, source.command); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(_(" \n" - "Enables or disables \002ops protection\002 mode on a channel.\n" - "When it is enabled, ops won't be kicked by the bot\n" - "even if they don't match the NOKICK level.")); - return true; - } -}; - -class CommandBSSetDontKickVoices : public Command -{ - public: - CommandBSSetDontKickVoices(Module *creator, const Anope::string &sname = "botserv/set/dontkickvoices") : Command(creator, sname, 2, 2) - { - this->SetDesc(_("To protect voices against bot kicks")); - this->SetSyntax(_("\037channel\037 {ON | OFF}")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci = ChannelInfo::Find(params[0]); - if (ci == NULL) - { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); - return; - } - - AccessGroup access = source.AccessFor(ci); - if (!source.HasPriv("botserv/administration") && !access.HasPriv("SET")) - { - source.Reply(ACCESS_DENIED); - return; - } - - if (Anope::ReadOnly) - { - source.Reply(_("Sorry, bot option setting is temporarily disabled.")); - return; - } - - if (params[1].equals_ci("ON")) - { - bool override = !access.HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable dontkickvoices"; - - ci->ExtendMetadata("BS_DONTKICKVOICES"); - source.Reply(_("Bot \002won't kick voices\002 on channel %s."), ci->name.c_str()); - } - else if (params[1].equals_ci("OFF")) - { - bool override = !access.HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable dontkickvoices"; - - ci->Shrink("BS_DONTKICKVOICES"); - source.Reply(_("Bot \002will kick voices\002 on channel %s."), ci->name.c_str()); - } - else - this->OnSyntaxError(source, source.command); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(_(" \n" - "Enables or disables \002voices protection\002 mode on a channel.\n" - "When it is enabled, voices won't be kicked by the bot\n" - "even if they don't match the NOKICK level.")); - return true; - } -}; - -class CommandBSSetFantasy : public Command -{ - public: - CommandBSSetFantasy(Module *creator, const Anope::string &sname = "botserv/set/fantasy") : Command(creator, sname, 2, 2) - { - this->SetDesc(_("Enable fantaisist commands")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci = ChannelInfo::Find(params[0]); - const Anope::string &value = params[1]; - - if (ci == NULL) - { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); - return; - } - - if (!source.HasPriv("botserv/administration") && !source.AccessFor(ci).HasPriv("SET")) - { - source.Reply(ACCESS_DENIED); - return; - } - - if (Anope::ReadOnly) - { - source.Reply(_("Sorry, bot option setting is temporarily disabled.")); - return; - } - - if (value.equals_ci("ON")) - { - bool override = !source.AccessFor(ci).HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable fantasy"; - - ci->ExtendMetadata("BS_FANTASY"); - source.Reply(_("Fantasy mode is now \002on\002 on channel %s."), ci->name.c_str()); - } - else if (value.equals_ci("OFF")) - { - bool override = !source.AccessFor(ci).HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable fantasy"; - - ci->Shrink("BS_FANTASY"); - source.Reply(_("Fantasy mode is now \002off\002 on channel %s."), ci->name.c_str()); - } - else - this->OnSyntaxError(source, source.command); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(_(" \n" - "Enables or disables \002fantasy\002 mode on a channel.\n" - "When it is enabled, users will be able to use\n" - "fantasy commands on a channel when prefixed\n" - "with one of the following fantasy characters: \002%s\002\n" - " \n" - "Note that users wanting to use fantaisist\n" - "commands MUST have enough access for both\n" - "the FANTASIA and the command they are executing."), - Config->GetModule("botserv")->Get<const Anope::string>("fantasycharacter", "!").c_str()); - return true; - } -}; - -class CommandBSSetGreet : public Command -{ - public: - CommandBSSetGreet(Module *creator, const Anope::string &sname = "botserv/set/greet") : Command(creator, sname, 2, 2) - { - this->SetDesc(_("Enable greet messages")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci = ChannelInfo::Find(params[0]); - const Anope::string &value = params[1]; - - if (ci == NULL) - { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); - return; - } - - if (!source.HasPriv("botserv/administration") && !source.AccessFor(ci).HasPriv("SET")) - { - source.Reply(ACCESS_DENIED); - return; - } - - if (Anope::ReadOnly) - { - source.Reply(_("Sorry, bot option setting is temporarily disabled.")); - return; - } - - if (value.equals_ci("ON")) - { - bool override = !source.AccessFor(ci).HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable greets"; - - ci->ExtendMetadata("BS_GREET"); - source.Reply(_("Greet mode is now \002on\002 on channel %s."), ci->name.c_str()); - } - else if (value.equals_ci("OFF")) - { - bool override = !source.AccessFor(ci).HasPriv("SET"); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable greets"; - - ci->Shrink("BS_GREET"); - source.Reply(_("Greet mode is now \002off\002 on channel %s."), ci->name.c_str()); - } - else - this->OnSyntaxError(source, source.command); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(_(" \n" - "Enables or disables \002greet\002 mode on a channel.\n" - "When it is enabled, the bot will display greet\n" - "messages of users joining the channel, provided\n" - "they have enough access to the channel.")); - return true; - } -}; - -class CommandBSSetNoBot : public Command -{ - public: - CommandBSSetNoBot(Module *creator, const Anope::string &sname = "botserv/set/nobot") : Command(creator, sname, 2, 2) - { - this->SetDesc(_("Prevent a bot from being assigned to a channel")); - this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci = ChannelInfo::Find(params[0]); - const Anope::string &value = params[1]; - - if (ci == NULL) - { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); - return; - } - - if (value.equals_ci("ON")) - { - Log(LOG_ADMIN, source, this, ci) << "to enable nobot"; - - ci->ExtendMetadata("BS_NOBOT"); - if (ci->bi) - ci->bi->UnAssign(source.GetUser(), ci); - source.Reply(_("No-bot mode is now \002on\002 on channel %s."), ci->name.c_str()); - } - else if (value.equals_ci("OFF")) - { - Log(LOG_ADMIN, source, this, ci) << "to disable nobot"; - - ci->Shrink("BS_NOBOT"); - source.Reply(_("No-bot mode is now \002off\002 on channel %s."), ci->name.c_str()); - } - else - this->OnSyntaxError(source, source.command); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(_(" \n" - "This option makes a channel be unassignable. If a bot\n" - "is already assigned to the channel, it is unassigned\n" - "automatically when you enable the option.")); - return true; - } -}; - class CommandBSSetPrivate : public Command { public: @@ -483,17 +175,12 @@ class BSSet : public Module { CommandBSSet commandbsset; CommandBSSetBanExpire commandbssetbanexpire; - CommandBSSetDontKickOps commandbssetdontkickops; - CommandBSSetDontKickVoices commandbssetdontkickvoices; - CommandBSSetFantasy commandbssetfantasy; - CommandBSSetGreet commandbssetgreet; - CommandBSSetNoBot commandbssetnobot; CommandBSSetPrivate commandbssetprivate; public: BSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandbsset(this), commandbssetbanexpire(this), commandbssetdontkickops(this), commandbssetdontkickvoices(this), - commandbssetfantasy(this), commandbssetgreet(this), commandbssetnobot(this), commandbssetprivate(this) + commandbsset(this), commandbssetbanexpire(this), + commandbssetprivate(this) { } diff --git a/modules/commands/cs_akick.cpp b/modules/commands/cs_akick.cpp index 17a20a0dd..3764c54fc 100644 --- a/modules/commands/cs_akick.cpp +++ b/modules/commands/cs_akick.cpp @@ -20,8 +20,8 @@ class CommandCSAKick : public Command const NickAlias *na = NickAlias::Find(mask); NickCore *nc = NULL; const AutoKick *akick; - unsigned reasonmax = Config->GetModule("chanserv")->Get<unsigned>("reasonmax", "200"); + if (reason.length() > reasonmax) reason = reason.substr(0, reasonmax); diff --git a/modules/commands/cs_clone.cpp b/modules/commands/cs_clone.cpp index d9ba97894..a1b04d103 100644 --- a/modules/commands/cs_clone.cpp +++ b/modules/commands/cs_clone.cpp @@ -10,6 +10,7 @@ */ #include "module.h" +#include "modules/bs_badwords.h" class CommandCSClone : public Command { @@ -125,12 +126,16 @@ public: } else if (what.equals_ci("BADWORDS")) { - target_ci->ClearBadWords(); - for (unsigned i = 0; i < ci->GetBadWordCount(); ++i) - { - const BadWord *bw = ci->GetBadWord(i); - target_ci->AddBadWord(bw->word, bw->type); - } + BadWords *target_badwords = target_ci->GetExt<BadWords>("badwords"), + *badwords = ci->Require<BadWords>("badwords"); + if (target_badwords) + target_badwords->ClearBadWords(); + if (badwords) + for (unsigned i = 0; i < badwords->GetBadWordCount(); ++i) + { + const BadWord *bw = badwords->GetBadWord(i); + target_badwords->AddBadWord(bw->word, bw->type); + } source.Reply(_("All badword entries from \002%s\002 have been cloned to \002%s\002."), channel.c_str(), target.c_str()); } @@ -141,8 +146,6 @@ public: } Log(LOG_COMMAND, source, this, ci) << "to clone " << (what.empty() ? "everything from it" : what) << " to " << target_ci->name; - - return; } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override diff --git a/modules/commands/cs_drop.cpp b/modules/commands/cs_drop.cpp index 3f14aea65..adbe1f2ca 100644 --- a/modules/commands/cs_drop.cpp +++ b/modules/commands/cs_drop.cpp @@ -37,23 +37,20 @@ class CommandCSDrop : public Command return; } - if (ci->HasExt("SUSPENDED") && !source.HasCommand("chanserv/drop")) - { - source.Reply(CHAN_X_SUSPENDED, chan.c_str()); - return; - } - if ((ci->HasExt("SECUREFOUNDER") ? !source.IsFounder(ci) : !source.AccessFor(ci).HasPriv("FOUNDER")) && !source.HasCommand("chanserv/drop")) { source.Reply(ACCESS_DENIED); return; } + EventReturn MOD_RESULT; + FOREACH_RESULT(OnChanDrop, MOD_RESULT, (source, ci)); + if (MOD_RESULT == EVENT_STOP) + return; + bool override = (ci->HasExt("SECUREFOUNDER") ? !source.IsFounder(ci) : !source.AccessFor(ci).HasPriv("FOUNDER")); Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "(founder was: " << (ci->GetFounder() ? ci->GetFounder()->display : "none") << ")"; - FOREACH_MOD(OnChanDrop, (ci)); - Reference<Channel> c = ci->c; delete ci; diff --git a/modules/commands/cs_enforce.cpp b/modules/commands/cs_enforce.cpp index e40676186..b683332f5 100644 --- a/modules/commands/cs_enforce.cpp +++ b/modules/commands/cs_enforce.cpp @@ -27,7 +27,7 @@ class CommandCSEnforce : public Command * if it's off. */ bool hadsecureops = ci->HasExt("SECUREOPS"); - ci->ExtendMetadata("SECUREOPS"); + ci->Extend<bool>("SECUREOPS"); for (Channel::ChanUserList::iterator it = ci->c->users.begin(), it_end = ci->c->users.end(); it != it_end; ++it) { @@ -37,7 +37,7 @@ class CommandCSEnforce : public Command } if (!hadsecureops) - ci->Shrink("SECUREOPS"); + ci->Shrink<bool>("SECUREOPS"); source.Reply(_("Secureops enforced on %s."), ci->name.c_str()); } diff --git a/modules/commands/cs_entrymsg.cpp b/modules/commands/cs_entrymsg.cpp index f94aca44c..d3d3bb71b 100644 --- a/modules/commands/cs_entrymsg.cpp +++ b/modules/commands/cs_entrymsg.cpp @@ -37,9 +37,9 @@ struct EntryMsg : Serializable static Serializable* Unserialize(Serializable *obj, Serialize::Data &data); }; -struct EntryMessageList : Serialize::Checker<std::vector<EntryMsg *> >, ExtensibleItem +struct EntryMessageList : Serialize::Checker<std::vector<EntryMsg *> > { - EntryMessageList() : Serialize::Checker<std::vector<EntryMsg *> >("EntryMsg") { } + EntryMessageList(Extensible *) : Serialize::Checker<std::vector<EntryMsg *> >("EntryMsg") { } ~EntryMessageList() { @@ -71,12 +71,9 @@ Serializable* EntryMsg::Unserialize(Serializable *obj, Serialize::Data &data) return msg; } - EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg"); + EntryMessageList *messages = ci->GetExt<EntryMessageList>("entrymsg"); if (messages == NULL) - { - messages = new EntryMessageList(); - ci->Extend("cs_entrymsg", messages); - } + messages = ci->Extend<EntryMessageList>("entrymsg"); data["when"] >> swhen; @@ -90,12 +87,9 @@ class CommandEntryMessage : public Command private: void DoList(CommandSource &source, ChannelInfo *ci) { - EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg"); + EntryMessageList *messages = ci->GetExt<EntryMessageList>("entrymsg"); if (messages == NULL) - { - messages = new EntryMessageList(); - ci->Extend("cs_entrymsg", messages); - } + messages = ci->Extend<EntryMessageList>("entrymsg"); if ((*messages)->empty()) { @@ -129,12 +123,9 @@ class CommandEntryMessage : public Command void DoAdd(CommandSource &source, ChannelInfo *ci, const Anope::string &message) { - EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg"); + EntryMessageList *messages = ci->GetExt<EntryMessageList>("entrymsg"); if (messages == NULL) - { - messages = new EntryMessageList(); - ci->Extend("cs_entrymsg", messages); - } + messages = ci->Extend<EntryMessageList>("entrymsg"); if ((*messages)->size() >= Config->GetModule(this->owner)->Get<unsigned>("maxentries")) source.Reply(_("The entry message list for \002%s\002 is full."), ci->name.c_str()); @@ -148,12 +139,9 @@ class CommandEntryMessage : public Command void DoDel(CommandSource &source, ChannelInfo *ci, const Anope::string &message) { - EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg"); + EntryMessageList *messages = ci->GetExt<EntryMessageList>("entrymsg"); if (messages == NULL) - { - messages = new EntryMessageList(); - ci->Extend("cs_entrymsg", messages); - } + messages = ci->Extend<EntryMessageList>("entrymsg"); if (!message.is_pos_number_only()) source.Reply(("Entry message \002%s\002 not found on channel \002%s\002."), message.c_str(), ci->name.c_str()); @@ -169,7 +157,7 @@ class CommandEntryMessage : public Command delete (*messages)->at(i - 1); (*messages)->erase((*messages)->begin() + i - 1); if ((*messages)->empty()) - ci->Shrink("cs_entrymsg"); + ci->Shrink<EntryMessageList>("entrymsg"); Log(source.IsFounder(ci) ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to remove a message"; source.Reply(_("Entry message \002%i\002 for \002%s\002 deleted."), i, ci->name.c_str()); } @@ -185,14 +173,7 @@ class CommandEntryMessage : public Command void DoClear(CommandSource &source, ChannelInfo *ci) { - EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg"); - if (messages != NULL) - { - for (unsigned i = 0; i < (*messages)->size(); ++i) - delete (*messages)->at(i); - (*messages)->clear(); - ci->Shrink("cs_entrymsg"); - } + ci->Shrink<EntryMessageList>("entrymsg"); Log(source.IsFounder(ci) ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to remove all messages"; source.Reply(_("Entry messages for \002%s\002 have been cleared."), ci->name.c_str()); @@ -267,9 +248,10 @@ class CSEntryMessage : public Module { Serialize::Type entrymsg_type; CommandEntryMessage commandentrymsg; + ExtensibleItem<EntryMessageList> eml; public: - CSEntryMessage(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), entrymsg_type("EntryMsg", EntryMsg::Unserialize), commandentrymsg(this) + CSEntryMessage(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), entrymsg_type("EntryMsg", EntryMsg::Unserialize), commandentrymsg(this), eml(this, "entrymsg") { } @@ -278,7 +260,7 @@ class CSEntryMessage : public Module { if (u && c && c->ci && u->server->IsSynced()) { - EntryMessageList *messages = c->ci->GetExt<EntryMessageList *>("cs_entrymsg"); + EntryMessageList *messages = c->ci->GetExt<EntryMessageList>("entrymsg"); if (messages != NULL) for (unsigned i = 0; i < (*messages)->size(); ++i) diff --git a/modules/commands/cs_info.cpp b/modules/commands/cs_info.cpp index 0d3623c00..8f910fc83 100644 --- a/modules/commands/cs_info.cpp +++ b/modules/commands/cs_info.cpp @@ -13,17 +13,6 @@ class CommandCSInfo : public Command { - void CheckOptStr(Anope::string &buf, const Anope::string &opt, const char *str, const ChannelInfo *ci, const NickCore *nc) - { - if (ci->HasExt(opt)) - { - if (!buf.empty()) - buf += ", "; - - buf += Language::Translate(nc, str); - } - } - public: CommandCSInfo(Module *creator) : Command(creator, "chanserv/info", 1, 2) { @@ -66,43 +55,9 @@ class CommandCSInfo : public Command info["Registered"] = Anope::strftime(ci->time_registered); info["Last used"] = Anope::strftime(ci->last_used); - const ModeLock *secret = ci->GetMLock("SECRET"); - if (!ci->last_topic.empty() && (show_all || ((!secret || secret->set == false) && (!ci->c || !ci->c->HasMode("SECRET"))))) - { - info["Last topic"] = ci->last_topic; - info["Topic set by"] = ci->last_topic_setter; - } - if (show_all) { info["Ban type"] = stringify(ci->bantype); - - Anope::string optbuf; - CheckOptStr(optbuf, "KEEPTOPIC", _("Topic Retention"), ci, nc); - CheckOptStr(optbuf, "PEACE", _("Peace"), ci, nc); - CheckOptStr(optbuf, "PRIVATE", _("Private"), ci, nc); - CheckOptStr(optbuf, "RESTRICTED", _("Restricted Access"), ci, nc); - CheckOptStr(optbuf, "SECURE", _("Secure"), ci, nc); - CheckOptStr(optbuf, "SECUREFOUNDER", _("Secure Founder"), ci, nc); - CheckOptStr(optbuf, "SECUREOPS", _("Secure Ops"), ci, nc); - if (ci->HasExt("SIGNKICK")) - CheckOptStr(optbuf, "SIGNKICK", _("Signed kicks"), ci, nc); - else - CheckOptStr(optbuf, "SIGNKICK_LEVEL", _("Signed kicks"), ci, nc); - CheckOptStr(optbuf, "TOPICLOCK", _("Topic Lock"), ci, nc); - CheckOptStr(optbuf, "PERSIST", _("Persistent"), ci, nc); - CheckOptStr(optbuf, "NO_EXPIRE", _("No expire"), ci, nc); - CheckOptStr(optbuf, "STATS", _("Chanstats"), ci, nc); - - info["Options"] = optbuf.empty() ? _("None") : optbuf; - - const Anope::string &ml = ci->GetMLockAsString(true); - if (!ml.empty()) - info["Mode lock"] = ml; - - time_t chanserv_expire = Config->GetModule("chanserv")->Get<time_t>("expire", "14d"); - if (!ci->HasExt("NO_EXPIRE") && chanserv_expire && !Anope::NoExpire) - info["Expires on"] = Anope::strftime(ci->last_used + chanserv_expire); } FOREACH_MOD(OnChanInfo, (source, ci, info, show_all)); diff --git a/modules/commands/cs_list.cpp b/modules/commands/cs_list.cpp index 9e2df0a62..a92729b61 100644 --- a/modules/commands/cs_list.cpp +++ b/modules/commands/cs_list.cpp @@ -81,11 +81,11 @@ class CommandCSList : public Command { const ChannelInfo *ci = it->second; - if (!is_servadmin && (ci->HasExt("PRIVATE") || ci->HasExt("SUSPENDED"))) + if (!is_servadmin && (ci->HasExt("CS_PRIVATE") || ci->HasExt("SUSPENDED"))) continue; else if (suspended && !ci->HasExt("SUSPENDED")) continue; - else if (channoexpire && !ci->HasExt("NO_EXPIRE")) + else if (channoexpire && !ci->HasExt("CS_NO_EXPIRE")) continue; if (pattern.equals_ci(ci->name) || ci->name.equals_ci(spattern) || Anope::Match(ci->name, pattern, false, true) || Anope::Match(ci->name, spattern, false, true)) @@ -93,7 +93,7 @@ class CommandCSList : public Command if (((count + 1 >= from && count + 1 <= to) || (!from && !to)) && ++nchans <= listmax) { bool isnoexpire = false; - if (is_servadmin && (ci->HasExt("NO_EXPIRE"))) + if (is_servadmin && (ci->HasExt("CS_NO_EXPIRE"))) isnoexpire = true; ListFormatter::ListEntry entry; @@ -159,14 +159,89 @@ class CommandCSList : public Command } }; +class CommandCSSetPrivate : public Command +{ + public: + CommandCSSetPrivate(Module *creator, const Anope::string &cname = "chanserv/set/private") : Command(creator, cname, 2, 2) + { + this->SetDesc(_("Hide channel from the LIST command")); + this->SetSyntax(_("\037channel\037 {ON | OFF}")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + ChannelInfo *ci = ChannelInfo::Find(params[0]); + if (ci == NULL) + { + source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + return; + } + + EventReturn MOD_RESULT; + FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); + if (MOD_RESULT == EVENT_STOP) + return; + + if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) + { + source.Reply(ACCESS_DENIED); + return; + } + + if (params[1].equals_ci("ON")) + { + Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable private"; + ci->Extend<bool>("CS_PRIVATE"); + source.Reply(_("Private option for %s is now \002on\002."), ci->name.c_str()); + } + else if (params[1].equals_ci("OFF")) + { + Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable private"; + ci->Shrink<bool>("CS_PRIVATE"); + source.Reply(_("Private option for %s is now \002off\002."), ci->name.c_str()); + } + else + this->OnSyntaxError(source, "PRIVATE"); + + return; + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Enables or disables the \002private\002 option for a channel.")); + + BotInfo *bi; + Anope::string cmd; + if (Command::FindCommandFromService("chanserv/list", bi, cmd)) + source.Reply(_("When \002private\002 is set, the channel will not appear in\n" + "%s's %s command."), bi->nick.c_str(), cmd.c_str()); + return true; + } +}; + class CSList : public Module { CommandCSList commandcslist; + CommandCSSetPrivate commandcssetprivate; + + SerializableExtensibleItem<bool> priv; public: - CSList(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandcslist(this) + CSList(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), + commandcslist(this), commandcssetprivate(this), priv(this, "CS_PRIVATE") { } + + void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_all) anope_override + { + if (!show_all) + return; + + if (priv.HasExt(ci)) + info.AddOption(_("Private")); + } }; MODULE_INIT(CSList) diff --git a/modules/commands/cs_log.cpp b/modules/commands/cs_log.cpp index 969ebe5ab..bc6ba73c6 100644 --- a/modules/commands/cs_log.cpp +++ b/modules/commands/cs_log.cpp @@ -10,6 +10,77 @@ */ #include "module.h" +#include "modules/cs_log.h" + +struct LogSettingImpl : LogSetting, Serializable +{ + LogSettingImpl() : Serializable("LogSetting") + { + } + + ~LogSettingImpl() + { + ChannelInfo *ci = ChannelInfo::Find(chan); + if (ci) + { + LogSettings *ls = ci->Require<LogSettings>("logsettings"); + LogSettings::iterator it = std::find((*ls)->begin(), (*ls)->end(), this); + if (it != (*ls)->end()) + (*ls)->erase(it); + } + } + + void Serialize(Serialize::Data &data) const anope_override + { + data["ci"] << chan; + data["service_name"] << service_name; + data["command_service"] << command_service; + data["command_name"] << command_name; + data["method"] << method; + data["extra"] << extra; + data["creator"] << creator; + data.SetType("created", Serialize::Data::DT_INT); data["created"] << created; + } + + static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) + { + Anope::string sci; + data["ci"] >> sci; + + ChannelInfo *ci = ChannelInfo::Find(sci); + if (ci == NULL) + return NULL; + + LogSetting *ls; + if (obj) + ls = anope_dynamic_static_cast<LogSettingImpl *>(obj); + else + { + LogSettings *lsettings = ci->Require<LogSettings>("logsettings"); + ls = new LogSettingImpl(); + (*lsettings)->push_back(ls); + } + + ls->chan = ci->name; + data["service_name"] >> ls->service_name; + data["command_service"] >> ls->command_service; + data["command_name"] >> ls->command_name; + data["method"] >> ls->method; + data["extra"] >> ls->extra; + data["creator"] >> ls->creator; + data["created"] >> ls->created; + } +}; + +struct LogSettingsImpl : LogSettings +{ + LogSettingsImpl(Extensible *) { } + + LogSetting *Create() anope_override + { + return new LogSettingImpl(); + } +}; class CommandCSLog : public Command { @@ -32,16 +103,17 @@ public: source.Reply(ACCESS_DENIED); else if (params.size() == 1) { - if (ci->log_settings->empty()) + LogSettings *ls = ci->Require<LogSettings>("logsettings"); + if (!ls || (*ls)->empty()) source.Reply(_("There currently are no logging configurations for %s."), ci->name.c_str()); else { ListFormatter list; list.AddColumn("Number").AddColumn("Service").AddColumn("Command").AddColumn("Method").AddColumn(""); - for (unsigned i = 0; i < ci->log_settings->size(); ++i) + for (unsigned i = 0; i < (*ls)->size(); ++i) { - const LogSetting *log = ci->log_settings->at(i); + const LogSetting *log = (*ls)->at(i); ListFormatter::ListEntry entry; entry["Number"] = stringify(i + 1); @@ -63,6 +135,7 @@ public: } else if (params.size() > 2) { + LogSettings *ls = ci->Require<LogSettings>("logsettings"); const Anope::string &command = params[1]; const Anope::string &method = params[2]; const Anope::string &extra = params.size() > 3 ? params[3] : ""; @@ -106,16 +179,15 @@ public: bool override = !source.AccessFor(ci).HasPriv("SET"); - for (unsigned i = ci->log_settings->size(); i > 0; --i) + for (unsigned i = (*ls)->size(); i > 0; --i) { - LogSetting *log = ci->log_settings->at(i - 1); + LogSetting *log = (*ls)->at(i - 1); if (log->service_name == bi->commands[command_name].name && log->method.equals_ci(method)) { if (log->extra == extra) { delete log; - ci->log_settings->erase(ci->log_settings->begin() + i - 1); Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to remove logging for " << command << " with method " << method << (extra == "" ? "" : " ") << extra; source.Reply(_("Logging for command %s on %s with log method %s%s%s has been removed."), command_name.c_str(), bi->nick.c_str(), method.c_str(), extra.empty() ? "" : " ", extra.empty() ? "" : extra.c_str()); } @@ -129,8 +201,8 @@ public: } } - LogSetting *log = new LogSetting(); - log->ci = ci; + LogSetting *log = new LogSettingImpl(); + log->chan = ci->name; log->service_name = bi->commands[command_name].name; log->command_service = bi->nick; log->command_name = command_name; @@ -139,7 +211,8 @@ public: log->created = Anope::CurTime; log->creator = source.GetNick(); - ci->log_settings->push_back(log); + (*ls)->push_back(log); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to log " << command << " with method " << method << (extra == "" ? "" : " ") << extra; source.Reply(_("Logging is now active for command %s on %s, using log method %s%s%s."), command_name.c_str(), bi->nick.c_str(), method.c_str(), extra.empty() ? "" : " ", extra.empty() ? "" : extra.c_str()); @@ -180,10 +253,13 @@ class CSLog : public Module { ServiceReference<MemoServService> MSService; CommandCSLog commandcslog; + ExtensibleItem<LogSettingsImpl> logsettings; + Serialize::Type logsetting_type; public: CSLog(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - MSService("MemoServService", "MemoServ"), commandcslog(this) + MSService("MemoServService", "MemoServ"), commandcslog(this), logsettings(this, "logsettings"), + logsetting_type("LogSetting", LogSettingImpl::Unserialize) { } @@ -193,25 +269,27 @@ class CSLog : public Module if (l->type != LOG_COMMAND || l->u == NULL || l->c == NULL || l->ci == NULL || !Me || !Me->IsSynced()) return; - for (unsigned i = l->ci->log_settings->size(); i > 0; --i) - { - const LogSetting *log = l->ci->log_settings->at(i - 1); - - if (log->service_name == l->c->name) + LogSettings *ls = logsettings.Get(l->ci); + if (ls) + for (unsigned i = 0; i < (*ls)->size(); ++i) { - Anope::string buffer = l->u->nick + " used " + log->command_name + " " + l->buf.str(); + const LogSetting *log = (*ls)->at(i); - if (log->method.equals_ci("MESSAGE") && l->ci->c && l->ci->bi && l->ci->c->FindUser(l->ci->bi) != NULL) + if (log->service_name == l->c->name) { - IRCD->SendPrivmsg(l->ci->bi, log->extra + l->ci->c->name, "%s", buffer.c_str()); - l->ci->bi->lastmsg = Anope::CurTime; + Anope::string buffer = l->u->nick + " used " + log->command_name + " " + l->buf.str(); + + if (log->method.equals_ci("MESSAGE") && l->ci->c && l->ci->bi && l->ci->c->FindUser(l->ci->bi) != NULL) + { + IRCD->SendPrivmsg(l->ci->bi, log->extra + l->ci->c->name, "%s", buffer.c_str()); + l->ci->bi->lastmsg = Anope::CurTime; + } + else if (log->method.equals_ci("NOTICE") && l->ci->c && l->ci->bi && l->ci->c->FindUser(l->ci->bi) != NULL) + IRCD->SendNotice(l->ci->bi, log->extra + l->ci->c->name, "%s", buffer.c_str()); + else if (log->method.equals_ci("MEMO") && MSService && l->ci->WhoSends() != NULL) + MSService->Send(l->ci->WhoSends()->nick, l->ci->name, buffer, true); } - else if (log->method.equals_ci("NOTICE") && l->ci->c && l->ci->bi && l->ci->c->FindUser(l->ci->bi) != NULL) - IRCD->SendNotice(l->ci->bi, log->extra + l->ci->c->name, "%s", buffer.c_str()); - else if (log->method.equals_ci("MEMO") && MSService && l->ci->WhoSends() != NULL) - MSService->Send(l->ci->WhoSends()->nick, l->ci->name, buffer, true); } - } } }; diff --git a/modules/commands/cs_mode.cpp b/modules/commands/cs_mode.cpp index 895bd3d5b..1299bc543 100644 --- a/modules/commands/cs_mode.cpp +++ b/modules/commands/cs_mode.cpp @@ -10,6 +10,234 @@ */ #include "module.h" +#include "modules/cs_mode.h" + +struct ModeLockImpl : ModeLock, Serializable +{ + ModeLockImpl() : Serializable("ModeLock") + { + } + + ~ModeLockImpl() + { + ChannelInfo *chan = ChannelInfo::Find(ci); + if (chan) + { + ModeLocks *ml = chan->GetExt<ModeLocks>("modelocks"); + if (ml) + ml->RemoveMLock(this); + } + } + + void Serialize(Serialize::Data &data) const anope_override; + static Serializable* Unserialize(Serializable *obj, Serialize::Data &data); +}; + +struct ModeLocksImpl : ModeLocks +{ + Serialize::Reference<ChannelInfo> ci; + Serialize::Checker<ModeList> mlocks; + + ModeLocksImpl(Extensible *obj) : ci(anope_dynamic_static_cast<ChannelInfo *>(obj)), mlocks("ModeLock") + { + } + + bool HasMLock(ChannelMode *mode, const Anope::string ¶m, bool status) const anope_override + { + if (!mode) + return false; + + for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it) + { + const ModeLock *ml = *it; + + if (ml->name == mode->name && ml->set == status && ml->param == param) + return true; + } + + return false; + } + + bool SetMLock(ChannelMode *mode, bool status, const Anope::string ¶m, Anope::string setter, time_t created = Anope::CurTime) anope_override + { + if (!mode) + return false; + + RemoveMLock(mode, status, param); + + if (setter.empty()) + setter = ci->GetFounder() ? ci->GetFounder()->display : "Unknown"; + + ModeLock *ml = new ModeLockImpl(); + ml->ci = ci->name; + ml->set = status; + ml->name = mode->name; + ml->param = param; + ml->setter = setter; + ml->created = created; + + EventReturn MOD_RESULT; + FOREACH_RESULT(OnMLock, MOD_RESULT, (this->ci, ml)); + if (MOD_RESULT == EVENT_STOP) + { + delete ml; + return false; + } + + this->mlocks->push_back(ml); + return true; + } + + bool RemoveMLock(ChannelMode *mode, bool status, const Anope::string ¶m = "") anope_override + { + if (!mode) + return false; + + for (ModeList::iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it) + { + ModeLock *m = *it; + + if (m->name == mode->name) + { + // For list or status modes, we must check the parameter + if (mode->type == MODE_LIST || mode->type == MODE_STATUS) + if (m->param != param) + continue; + + EventReturn MOD_RESULT; + FOREACH_RESULT(OnUnMLock, MOD_RESULT, (this->ci, m)); + if (MOD_RESULT == EVENT_STOP) + break; + + delete m; + return true; + } + } + + return false; + } + + void RemoveMLock(ModeLock *mlock) anope_override + { + ModeList::iterator it = std::find(this->mlocks->begin(), this->mlocks->end(), mlock); + if (it != this->mlocks->end()) + this->mlocks->erase(it); + } + + void ClearMLock() anope_override + { + ModeList ml; + this->mlocks->swap(ml); + for (unsigned i = 0; i < ml.size(); ++i) + delete ml[i]; + } + + const ModeList &GetMLock() const anope_override + { + return this->mlocks; + } + + std::list<ModeLock *> GetModeLockList(const Anope::string &name) anope_override + { + std::list<ModeLock *> mlist; + for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it) + { + ModeLock *m = *it; + if (m->name == name) + mlist.push_back(m); + } + return mlist; + } + + const ModeLock *GetMLock(const Anope::string &mname, const Anope::string ¶m = "") anope_override + { + for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it) + { + ModeLock *m = *it; + + if (m->name == mname && m->param == param) + return m; + } + + return NULL; + } + + Anope::string GetMLockAsString(bool complete) const anope_override + { + Anope::string pos = "+", neg = "-", params; + + for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it) + { + const ModeLock *ml = *it; + ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name); + + if (!cm || cm->type == MODE_LIST || cm->type == MODE_STATUS) + continue; + + if (ml->set) + pos += cm->mchar; + else + neg += cm->mchar; + + if (complete && ml->set && !ml->param.empty() && cm->type == MODE_PARAM) + params += " " + ml->param; + } + + if (pos.length() == 1) + pos.clear(); + if (neg.length() == 1) + neg.clear(); + + return pos + neg + params; + } + + void Check() anope_override + { + if (this->mlocks->empty()) + ci->Shrink<ModeLocks>("modelocks"); + } +}; + +void ModeLockImpl::Serialize(Serialize::Data &data) const +{ + data["ci"] << this->ci; + data["set"] << this->set; + data["name"] << this->name; + data["param"] << this->param; + data["setter"] << this->setter; + data.SetType("created", Serialize::Data::DT_INT); data["created"] << this->created; +} + +Serializable* ModeLockImpl::Unserialize(Serializable *obj, Serialize::Data &data) +{ + Anope::string sci; + + data["ci"] >> sci; + + ChannelInfo *ci = ChannelInfo::Find(sci); + if (!ci) + return NULL; + + ModeLockImpl *ml; + if (obj) + ml = anope_dynamic_static_cast<ModeLockImpl *>(obj); + else + { + ml = new ModeLockImpl(); + ml->ci = ci->name; + } + + data["set"] >> ml->set; + data["created"] >> ml->created; + data["setter"] >> ml->setter; + data["name"] >> ml->name; + data["param"] >> ml->param; + + if (!obj) + ci->Require<ModeLocksImpl>("modelocks")->mlocks->push_back(ml); + + return ml; +} class CommandCSMode : public Command { @@ -28,21 +256,20 @@ class CommandCSMode : public Command const Anope::string ¶m = params.size() > 3 ? params[3] : ""; bool override = !source.AccessFor(ci).HasPriv("MODE"); + ModeLocks *modelocks = ci->Require<ModeLocks>("modelocks"); if ((subcommand.equals_ci("ADD") || subcommand.equals_ci("SET")) && !param.empty()) { /* If setting, remove the existing locks */ if (subcommand.equals_ci("SET")) { - const ChannelInfo::ModeList &mlocks = ci->GetMLock(); - for (ChannelInfo::ModeList::const_iterator it = mlocks.begin(), it_next; it != mlocks.end(); it = it_next) + const ModeLocks::ModeList mlocks = modelocks->GetMLock(); + for (ModeLocks::ModeList::const_iterator it = mlocks.begin(); it != mlocks.end(); ++it) { - const ModeLock *ml = it->second; + const ModeLock *ml = *it; ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name); - it_next = it; - ++it_next; if (cm && cm->CanSet(source.GetUser())) - ci->RemoveMLock(cm, ml->set, ml->param); + modelocks->RemoveMLock(cm, ml->set, ml->param); } } @@ -86,7 +313,7 @@ class CommandCSMode : public Command source.Reply(_("List for mode %c is full."), cm->mchar); else { - ci->SetMLock(cm, adding, mode_param, source.GetNick()); + modelocks->SetMLock(cm, adding, mode_param, source.GetNick()); if (adding) { @@ -110,8 +337,8 @@ class CommandCSMode : public Command neg.clear(); Anope::string reply = pos + neg + pos_params + neg_params; - source.Reply(_("%s locked on %s."), ci->GetMLockAsString(true).c_str(), ci->name.c_str()); - Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to lock " << ci->GetMLockAsString(true); + source.Reply(_("%s locked on %s."), modelocks->GetMLockAsString(true).c_str(), ci->name.c_str()); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to lock " << modelocks->GetMLockAsString(true); if (ci->c) ci->c->CheckModes(); @@ -154,7 +381,7 @@ class CommandCSMode : public Command source.Reply(_("Missing parameter for mode %c."), cm->mchar); else { - if (ci->RemoveMLock(cm, adding, mode_param)) + if (modelocks->RemoveMLock(cm, adding, mode_param)) { if (!mode_param.empty()) mode_param = " " + mode_param; @@ -169,7 +396,7 @@ class CommandCSMode : public Command } else if (subcommand.equals_ci("LIST")) { - const ChannelInfo::ModeList &mlocks = ci->GetMLock(); + const ModeLocks::ModeList mlocks = modelocks->GetMLock(); if (mlocks.empty()) { source.Reply(_("Channel %s has no mode locks."), ci->name.c_str()); @@ -179,9 +406,9 @@ class CommandCSMode : public Command ListFormatter list; list.AddColumn("Mode").AddColumn("Param").AddColumn("Creator").AddColumn("Created"); - for (ChannelInfo::ModeList::const_iterator it = mlocks.begin(), it_end = mlocks.end(); it != it_end; ++it) + for (ModeLocks::ModeList::const_iterator it = mlocks.begin(), it_end = mlocks.end(); it != it_end; ++it) { - const ModeLock *ml = it->second; + const ModeLock *ml = *it; ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name); if (!cm) continue; @@ -481,12 +708,125 @@ class CommandCSMode : public Command class CSMode : public Module { CommandCSMode commandcsmode; + ExtensibleItem<ModeLocksImpl> modelocks; + Serialize::Type modelocks_type; public: CSMode(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandcsmode(this) + commandcsmode(this), modelocks(this, "modelocks"), modelocks_type("ModeLock", ModeLockImpl::Unserialize) + { + + } + + EventReturn OnCheckModes(Channel *c) anope_override + { + if (!c->ci) + return EVENT_CONTINUE; + + ModeLocks *ml = modelocks.Get(c->ci); + if (ml) + for (ModeLocks::ModeList::const_iterator it = ml->GetMLock().begin(), it_end = ml->GetMLock().end(); it != it_end; ++it) + { + const ModeLock *ml = *it; + ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name); + if (!cm) + continue; + + if (cm->type == MODE_REGULAR) + { + if (!c->HasMode(cm->name) && ml->set) + c->SetMode(NULL, cm); + else if (c->HasMode(cm->name) && !ml->set) + c->RemoveMode(NULL, cm); + } + else if (cm->type == MODE_PARAM) + { + /* If the channel doesnt have the mode, or it does and it isn't set correctly */ + if (ml->set) + { + Anope::string param; + c->GetParam(cm->name, param); + + if (!c->HasMode(cm->name) || (!param.empty() && !ml->param.empty() && !param.equals_cs(ml->param))) + c->SetMode(NULL, cm, ml->param); + } + else + { + if (c->HasMode(cm->name)) + c->RemoveMode(NULL, cm); + } + + } + else if (cm->type == MODE_LIST) + { + if (ml->set) + c->SetMode(NULL, cm, ml->param); + else + c->RemoveMode(NULL, cm, ml->param); + } + } + } + + EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) anope_override + { + if (!c->ci) + return EVENT_CONTINUE; + + ModeLocks *ml = modelocks.Get(c->ci); + if (!ml) + return EVENT_CONTINUE; + + if (ml->HasMLock(mode, param, false)) + c->RemoveMode(c->ci->WhoSends(), mode, param); + } + + EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) anope_override + { + if (!c->ci) + return EVENT_CONTINUE; + + ModeLocks *ml = modelocks.Get(c->ci); + if (!ml) + return EVENT_CONTINUE; + + if (ml->HasMLock(mode, param, true)) + c->SetMode(c->ci->WhoSends(), mode, param); + } + + void OnCreateChan(ChannelInfo *ci) anope_override + { + ModeLocks *ml = modelocks.Require(ci); + Anope::string modes; + spacesepstream sep(Config->GetModule(this)->Get<const Anope::string>("mlock", "+nrt")); + if (sep.GetToken(modes)) + { + bool add = true; + for (unsigned i = 0; i < modes.length(); ++i) + { + if (modes[i] == '+') + add = true; + else if (modes[i] == '-') + add = false; + else + { + ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]); + Anope::string param; + if (cm && (cm->type == MODE_REGULAR || sep.GetToken(param))) + ml->SetMLock(cm, add, param); + } + } + } + ml->Check(); + } + + void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_hidden) anope_override { + if (!show_hidden) + return; + ModeLocks *ml = modelocks.Get(ci); + if (ml) + info[_("Mode lock")] = ml->GetMLockAsString(true); } }; diff --git a/modules/commands/cs_seen.cpp b/modules/commands/cs_seen.cpp index 877fc31b7..9c0b6abfb 100644 --- a/modules/commands/cs_seen.cpp +++ b/modules/commands/cs_seen.cpp @@ -95,7 +95,7 @@ static bool ShouldHide(const Anope::string &channel, User *u) if (targetchan && targetchan->HasMode("SECRET")) return true; - else if (targetchan_ci && targetchan_ci->HasExt("PRIVATE")) + else if (targetchan_ci && targetchan_ci->HasExt("CS_PRIVATE")) return true; else if (u && u->HasMode("PRIV")) return true; diff --git a/modules/commands/cs_set.cpp b/modules/commands/cs_set.cpp index d07e544cc..d392f6b1d 100644 --- a/modules/commands/cs_set.cpp +++ b/modules/commands/cs_set.cpp @@ -10,6 +10,7 @@ */ #include "module.h" +#include "modules/cs_mode.h" class CommandCSSet : public Command { @@ -86,13 +87,13 @@ class CommandCSSetAutoOp : public Command if (params[1].equals_ci("ON")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable autoop"; - ci->Shrink("NOAUTOOP"); + ci->Shrink<bool>("NOAUTOOP"); source.Reply(_("Services will now automatically give modes to users in \002%s\002."), ci->name.c_str()); } else if (params[1].equals_ci("OFF")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable autoop"; - ci->ExtendMetadata("NOAUTOOP"); + ci->Extend<bool>("NOAUTOOP"); source.Reply(_("Services will no longer automatically give modes to users in \002%s\002."), ci->name.c_str()); } else @@ -203,14 +204,14 @@ class CommandCSSetChanstats : public Command if (params[1].equals_ci("ON")) { - ci->ExtendMetadata("STATS"); + ci->Extend<bool>("CS_STATS"); source.Reply(_("Chanstats statistics are now enabled for this channel.")); Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable chanstats"; } else if (params[1].equals_ci("OFF")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable chanstats"; - ci->Shrink("STATS"); + ci->Shrink<bool>("CS_STATS"); source.Reply(_("Chanstats statistics are now disabled for this channel.")); } else @@ -344,64 +345,6 @@ class CommandCSSetFounder : public Command } }; -class CommandCSSetKeepTopic : public Command -{ - public: - CommandCSSetKeepTopic(Module *creator, const Anope::string &cname = "chanserv/set/keeptopic") : Command(creator, cname, 2, 2) - { - this->SetDesc(_("Retain topic when channel is not in use")); - this->SetSyntax(_("\037channel\037 {ON | OFF}")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci = ChannelInfo::Find(params[0]); - if (ci == NULL) - { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); - return; - } - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); - if (MOD_RESULT == EVENT_STOP) - return; - - if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) - { - source.Reply(ACCESS_DENIED); - return; - } - - if (params[1].equals_ci("ON")) - { - Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable keeptopic"; - ci->ExtendMetadata("KEEPTOPIC"); - source.Reply(_("Topic retention option for %s is now \002on\002."), ci->name.c_str()); - } - else if (params[1].equals_ci("OFF")) - { - Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable keeptopic"; - ci->Shrink("KEEPTOPIC"); - source.Reply(_("Topic retention option for %s is now \002off\002."), ci->name.c_str()); - } - else - this->OnSyntaxError(source, "KEEPTOPIC"); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Enables or disables the \002topic retention\002 option for a\n" - "channel. When \002%s\002 is set, the topic for the\n" - "channel will be remembered by %s even after the\n" - "last user leaves the channel, and will be restored the\n" - "next time the channel is created."), this->name.c_str(), source.service->nick.c_str()); - return true; - } -}; - class CommandCSSetPeace : public Command { public: @@ -433,13 +376,13 @@ class CommandCSSetPeace : public Command if (params[1].equals_ci("ON")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable peace"; - ci->ExtendMetadata("PEACE"); + ci->Extend<bool>("PEACE"); source.Reply(_("Peace option for %s is now \002on\002."), ci->name.c_str()); } else if (params[1].equals_ci("OFF")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable peace"; - ci->Shrink("PEACE"); + ci->Shrink<bool>("PEACE"); source.Reply(_("Peace option for %s is now \002off\002."), ci->name.c_str()); } else @@ -495,7 +438,7 @@ class CommandCSSetPersist : public Command { if (!ci->HasExt("PERSIST")) { - ci->ExtendMetadata("PERSIST"); + ci->Extend<bool>("PERSIST"); /* Channel doesn't exist, create it */ if (!ci->c) @@ -535,7 +478,9 @@ class CommandCSSetPersist : public Command if (ci->c && !ci->c->HasMode("PERM")) ci->c->SetMode(NULL, cm); /* Add it to the channels mlock */ - ci->SetMLock(cm, true); + ModeLocks *ml = ci->Require<ModeLocks>("modelocks"); + if (ml) + ml->SetMLock(cm, true); } } @@ -546,7 +491,7 @@ class CommandCSSetPersist : public Command { if (ci->HasExt("PERSIST")) { - ci->Shrink("PERSIST"); + ci->Shrink<bool>("PERSIST"); /* Unset perm mode */ if (cm) @@ -554,7 +499,9 @@ class CommandCSSetPersist : public Command if (ci->c && ci->c->HasMode("PERM")) ci->c->RemoveMode(NULL, cm); /* Remove from mlock */ - ci->RemoveMLock(cm, true); + ModeLocks *ml = ci->GetExt<ModeLocks>("modelocks"); + if (ml) + ml->RemoveMLock(cm, true); } /* No channel mode, no BotServ, but using ChanServ as the botserv bot @@ -608,68 +555,6 @@ class CommandCSSetPersist : public Command } }; -class CommandCSSetPrivate : public Command -{ - public: - CommandCSSetPrivate(Module *creator, const Anope::string &cname = "chanserv/set/private") : Command(creator, cname, 2, 2) - { - this->SetDesc(_("Hide channel from the LIST command")); - this->SetSyntax(_("\037channel\037 {ON | OFF}")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - ChannelInfo *ci = ChannelInfo::Find(params[0]); - if (ci == NULL) - { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); - return; - } - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); - if (MOD_RESULT == EVENT_STOP) - return; - - if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) - { - source.Reply(ACCESS_DENIED); - return; - } - - if (params[1].equals_ci("ON")) - { - Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable private"; - ci->ExtendMetadata("PRIVATE"); - source.Reply(_("Private option for %s is now \002on\002."), ci->name.c_str()); - } - else if (params[1].equals_ci("OFF")) - { - Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable private"; - ci->Shrink("PRIVATE"); - source.Reply(_("Private option for %s is now \002off\002."), ci->name.c_str()); - } - else - this->OnSyntaxError(source, "PRIVATE"); - - return; - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Enables or disables the \002private\002 option for a channel.")); - - BotInfo *bi; - Anope::string cmd; - if (Command::FindCommandFromService("chanserv/list", bi, cmd)) - source.Reply(_("When \002private\002 is set, the channel will not appear in\n" - "%s's %s command."), bi->nick.c_str(), cmd.c_str()); - return true; - } -}; - class CommandCSSetRestricted : public Command { public: @@ -702,13 +587,13 @@ class CommandCSSetRestricted : public Command if (params[1].equals_ci("ON")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable restricted"; - ci->ExtendMetadata("RESTRICTED"); + ci->Extend<bool>("RESTRICTED"); source.Reply(_("Restricted access option for %s is now \002on\002."), ci->name.c_str()); } else if (params[1].equals_ci("OFF")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable restricted"; - ci->Shrink("RESTRICTED"); + ci->Shrink<bool>("RESTRICTED"); source.Reply(_("Restricted access option for %s is now \002off\002."), ci->name.c_str()); } else @@ -758,13 +643,13 @@ class CommandCSSetSecure : public Command if (params[1].equals_ci("ON")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable secure"; - ci->ExtendMetadata("SECURE"); + ci->Extend<bool>("CS_SECURE"); source.Reply(_("Secure option for %s is now \002on\002."), ci->name.c_str()); } else if (params[1].equals_ci("OFF")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable secure"; - ci->Shrink("SECURE"); + ci->Shrink<bool>("CS_SECURE"); source.Reply(_("Secure option for %s is now \002off\002."), ci->name.c_str()); } else @@ -816,13 +701,13 @@ class CommandCSSetSecureFounder : public Command if (params[1].equals_ci("ON")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable secure founder"; - ci->ExtendMetadata("SECUREFOUNDER"); + ci->Extend<bool>("SECUREFOUNDER"); source.Reply(_("Secure founder option for %s is now \002on\002."), ci->name.c_str()); } else if (params[1].equals_ci("OFF")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable secure founder"; - ci->Shrink("SECUREFOUNDER"); + ci->Shrink<bool>("SECUREFOUNDER"); source.Reply(_("Secure founder option for %s is now \002off\002."), ci->name.c_str()); } else @@ -874,13 +759,13 @@ class CommandCSSetSecureOps : public Command if (params[1].equals_ci("ON")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable secure ops"; - ci->ExtendMetadata("SECUREOPS"); + ci->Extend<bool>("SECUREOPS"); source.Reply(_("Secure ops option for %s is now \002on\002."), ci->name.c_str()); } else if (params[1].equals_ci("OFF")) { Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable secure ops"; - ci->Shrink("SECUREOPS"); + ci->Shrink<bool>("SECUREOPS"); source.Reply(_("Secure ops option for %s is now \002off\002."), ci->name.c_str()); } else @@ -904,7 +789,7 @@ class CommandCSSetSignKick : public Command CommandCSSetSignKick(Module *creator, const Anope::string &cname = "chanserv/set/signkick") : Command(creator, cname, 2, 2) { this->SetDesc(_("Sign kicks that are done with the KICK command")); - this->SetSyntax(_("\037channel\037 SIGNKICK {ON | LEVEL | OFF}")); + this->SetSyntax(_("\037channel\037 {ON | LEVEL | OFF}")); } void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override @@ -929,23 +814,23 @@ class CommandCSSetSignKick : public Command if (params[1].equals_ci("ON")) { - ci->ExtendMetadata("SIGNKICK"); - ci->Shrink("SIGNKICK_LEVEL"); + ci->Extend<bool>("SIGNKICK"); + ci->Shrink<bool>("SIGNKICK_LEVEL"); source.Reply(_("Signed kick option for %s is now \002on\002."), ci->name.c_str()); Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable sign kick"; } else if (params[1].equals_ci("LEVEL")) { - ci->ExtendMetadata("SIGNKICK_LEVEL"); - ci->Shrink("SIGNKICK"); + ci->Extend<bool>("SIGNKICK_LEVEL"); + ci->Shrink<bool>("SIGNKICK"); source.Reply(_("Signed kick option for %s is now \002on\002, but depends of the\n" "level of the user that is using the command."), ci->name.c_str()); Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable sign kick level"; } else if (params[1].equals_ci("OFF")) { - ci->Shrink("SIGNKICK"); - ci->Shrink("SIGNKICK_LEVEL"); + ci->Shrink<bool>("SIGNKICK"); + ci->Shrink<bool>("SIGNKICK_LEVEL"); source.Reply(_("Signed kick option for %s is now \002off\002."), ci->name.c_str()); Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable sign kick"; } @@ -1075,13 +960,13 @@ class CommandCSSetNoexpire : public Command if (params[1].equals_ci("ON")) { Log(LOG_ADMIN, source, this, ci) << "to enable noexpire"; - ci->ExtendMetadata("NO_EXPIRE"); + ci->Extend<bool>("CS_NO_EXPIRE"); source.Reply(_("Channel %s \002will not\002 expire."), ci->name.c_str()); } else if (params[1].equals_ci("OFF")) { Log(LOG_ADMIN, source, this, ci) << "to disable noexpire"; - ci->Shrink("NO_EXPIRE"); + ci->Shrink<bool>("CS_NO_EXPIRE"); source.Reply(_("Channel %s \002will\002 expire."), ci->name.c_str()); } else @@ -1102,16 +987,17 @@ class CommandCSSetNoexpire : public Command class CSSet : public Module { + SerializableExtensibleItem<bool> persist, noautoop, stats, peace, securefounder, + restricted, secure, secureops, signkick, signkick_level, noexpire; + CommandCSSet commandcsset; CommandCSSetAutoOp commandcssetautoop; CommandCSSetBanType commandcssetbantype; CommandCSSetChanstats commandcssetchanstats; CommandCSSetDescription commandcssetdescription; CommandCSSetFounder commandcssetfounder; - CommandCSSetKeepTopic commandcssetkeeptopic; CommandCSSetPeace commandcssetpeace; CommandCSSetPersist commandcssetpersist; - CommandCSSetPrivate commandcssetprivate; CommandCSSetRestricted commandcssetrestricted; CommandCSSetSecure commandcssetsecure; CommandCSSetSecureFounder commandcssetsecurefounder; @@ -1122,17 +1008,27 @@ class CSSet : public Module public: CSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), + persist(this, "PERSIST"), noautoop(this, "NOAUTOOP"), stats(this, "CS_STATS"), peace(this, "PEACE"), + securefounder(this, "SECUREFOUNDER"), restricted(this, "RESTRICTED"), + secure(this, "CS_SECURE"), secureops(this, "SECUREOPS"), signkick(this, "SIGNKICK"), + signkick_level(this, "SIGNKICK_LEVEL"), noexpire(this, "CS_NO_EXPIRE"), + commandcsset(this), commandcssetautoop(this), commandcssetbantype(this), commandcssetchanstats(this), - commandcssetdescription(this), commandcssetfounder(this), commandcssetkeeptopic(this), - commandcssetpeace(this), commandcssetpersist(this), commandcssetprivate(this), commandcssetrestricted(this), + commandcssetdescription(this), commandcssetfounder(this), + commandcssetpeace(this), commandcssetpersist(this), commandcssetrestricted(this), commandcssetsecure(this), commandcssetsecurefounder(this), commandcssetsecureops(this), commandcssetsignkick(this), commandcssetsuccessor(this), commandcssetnoexpire(this) { } + void OnCreateChan(ChannelInfo *ci) anope_override + { + ci->bantype = Config->GetModule(this)->Get<int>("defbantype", "2"); + } + EventReturn OnCheckKick(User *u, Channel *c, Anope::string &mask, Anope::string &reason) anope_override { - if (!c->ci || !c->ci->HasExt("RESTRICTED") || c->MatchesList(u, "EXCEPT")) + if (!c->ci || !restricted.HasExt(c->ci) || c->MatchesList(u, "EXCEPT")) return EVENT_CONTINUE; if (c->ci->AccessFor(u).empty() && (!c->ci->GetFounder() || u->Account() != c->ci->GetFounder())) @@ -1143,30 +1039,30 @@ class CSSet : public Module void OnDelChan(ChannelInfo *ci) anope_override { - if (ci->c && ci->HasExt("PERSIST")) + if (ci->c && persist.HasExt(ci)) ci->c->RemoveMode(ci->WhoSends(), "PERM", "", false); - ci->Shrink("PERSIST"); + persist.Unset(ci); } - EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, const Anope::string &mname, const Anope::string ¶m) anope_override + EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) anope_override { /* Channel mode +P or so was set, mark this channel as persistent */ - if (mname == "PERM" && c->ci) + if (mode->name == "PERM" && c->ci) { - c->ci->ExtendMetadata("PERSIST"); + persist.Set(c->ci, true); } return EVENT_CONTINUE; } - EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, const Anope::string &mname, const Anope::string ¶m) anope_override + EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) anope_override { - if (mname == "PERM") + if (mode->name == "PERM") { if (c->ci) - c->ci->Shrink("PERSIST"); + persist.Unset(c->ci); - if (c->users.empty() && !c->syncing && c->CheckDelete()) + if (c->CheckDelete()) { delete c; return EVENT_STOP; @@ -1178,14 +1074,14 @@ class CSSet : public Module EventReturn OnCheckDelete(Channel *c) anope_override { - if (c->ci && c->ci->HasExt("PERSIST")) + if (c->ci && persist.HasExt(c->ci)) return EVENT_STOP; return EVENT_CONTINUE; } void OnJoinChannel(User *u, Channel *c) anope_override { - if (c->ci && c->ci->HasExt("PERSIST") && c->creation_time > c->ci->time_registered) + if (c->ci && persist.HasExt(c->ci) && c->creation_time > c->ci->time_registered) { Log(LOG_DEBUG) << "Changing TS of " << c->name << " from " << c->creation_time << " to " << c->ci->time_registered; c->creation_time = c->ci->time_registered; @@ -1198,10 +1094,47 @@ class CSSet : public Module { if (chan->ci) { - give_modes &= !chan->ci->HasExt("NOAUTOOP"); - take_modes |= chan->ci->HasExt("SECUREOPS"); + if (noautoop.HasExt(chan->ci)) + give_modes = false; + if (secureops.HasExt(chan->ci)) + take_modes = true; } } + + void OnPreChanExpire(ChannelInfo *ci, bool &expire) anope_override + { + if (noexpire.HasExt(ci)) + expire = false; + } + + void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_all) anope_override + { + if (!show_all) + return; + + if (peace.HasExt(ci)) + info.AddOption(_("Peace")); + if (restricted.HasExt(ci)) + info.AddOption(_("Restricted Access")); + if (secure.HasExt(ci)) + info.AddOption(_("Secure")); + if (securefounder.HasExt(ci)) + info.AddOption(_("Secure Founder")); + if (secureops.HasExt(ci)) + info.AddOption(_("Secure Ops")); + if (signkick.HasExt(ci) || signkick_level.HasExt(ci)) + info.AddOption(_("Signed kicks")); + if (persist.HasExt(ci)) + info.AddOption(_("Persistent")); + if (noexpire.HasExt(ci)) + info.AddOption(_("No expire")); + if (stats.HasExt(ci)) + info.AddOption(_("Chanstats")); + + time_t chanserv_expire = Config->GetModule(this)->Get<time_t>("expire", "14d"); + if (!noexpire.HasExt(ci) && chanserv_expire && !Anope::NoExpire) + info["Expires on"] = Anope::strftime(ci->last_used + chanserv_expire); + } }; MODULE_INIT(CSSet) diff --git a/modules/commands/cs_set_misc.cpp b/modules/commands/cs_set_misc.cpp index 21ebec815..5467e2b4e 100644 --- a/modules/commands/cs_set_misc.cpp +++ b/modules/commands/cs_set_misc.cpp @@ -10,14 +10,24 @@ #include "module.h" +static Module *me; + static std::map<Anope::string, Anope::string> descriptions; -struct CSMiscData : ExtensibleItem, Serializable +struct CSMiscData; +static Anope::map<ExtensibleItem<CSMiscData> *> items; +static ExtensibleItem<CSMiscData> *GetItem(const Anope::string &name); + +struct CSMiscData : Serializable { Serialize::Reference<ChannelInfo> ci; Anope::string name; Anope::string data; + CSMiscData(Extensible *obj) : Serializable("CSMiscData"), ci(anope_dynamic_static_cast<ChannelInfo *>(obj)) + { + } + CSMiscData(ChannelInfo *c, const Anope::string &n, const Anope::string &d) : Serializable("CSMiscData"), ci(c), name(n), data(d) { } @@ -41,7 +51,7 @@ struct CSMiscData : ExtensibleItem, Serializable if (ci == NULL) return NULL; - CSMiscData *d; + CSMiscData *d = NULL; if (obj) { d = anope_dynamic_static_cast<CSMiscData *>(obj); @@ -51,14 +61,27 @@ struct CSMiscData : ExtensibleItem, Serializable } else { - d = new CSMiscData(ci, sname, sdata); - ci->Extend(sname, d); + ExtensibleItem<CSMiscData> *item = GetItem(sname); + if (item) + d = item->Set(ci, CSMiscData(ci, sname, sdata)); } return d; } }; +static ExtensibleItem<CSMiscData> *GetItem(const Anope::string &name) +{ + ExtensibleItem<CSMiscData>* &it = items[name]; + if (!it) + try + { + it = new ExtensibleItem<CSMiscData>(me, name); + } + catch (const ModuleException &) { } + return it; +} + static Anope::string GetAttribute(const Anope::string &command) { size_t sp = command.rfind(' '); @@ -97,14 +120,20 @@ class CommandCSSetMisc : public Command Anope::string scommand = GetAttribute(source.command); Anope::string key = "cs_set_misc:" + scommand; - ci->Shrink(key); + ExtensibleItem<CSMiscData> *item = GetItem(key); + if (item == NULL) + return; + if (params.size() > 1) { - ci->Extend(key, new CSMiscData(ci, key, params[1])); + item->Set(ci, CSMiscData(ci, key, params[1])); source.Reply(CHAN_SETTING_CHANGED, scommand.c_str(), ci->name.c_str(), params[1].c_str()); } else + { + item->Unset(ci); source.Reply(CHAN_SETTING_UNSET, scommand.c_str(), ci->name.c_str()); + } } void OnServHelp(CommandSource &source) anope_override @@ -136,6 +165,7 @@ class CSSetMisc : public Module CSSetMisc(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), csmiscdata_type("CSMiscData", CSMiscData::Unserialize), commandcssetmisc(this) { + me = this; } void OnReload(Configuration::Conf *conf) anope_override @@ -161,17 +191,14 @@ class CSSetMisc : public Module void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool ShowHidden) anope_override { - std::deque<Anope::string> list; - ci->GetExtList(list); - - for (unsigned i = 0; i < list.size(); ++i) + Anope::map<ExtensibleItem<CSMiscData> *> items; + for (Anope::map<ExtensibleItem<CSMiscData> *>::iterator it = items.begin(); it != items.end(); ++it) { - if (list[i].find("cs_set_misc:") != 0) - continue; - - CSMiscData *data = ci->GetExt<CSMiscData *>(list[i]); + ExtensibleItem<CSMiscData> *e = it->second; + CSMiscData *data = e->Get(ci); + if (data != NULL) - info[list[i].substr(12).replace_all_cs("_", " ")] = data->data; + info[e->name.substr(12).replace_all_cs("_", " ")] = data->data; } } }; diff --git a/modules/commands/cs_suspend.cpp b/modules/commands/cs_suspend.cpp index e366e5dc0..b7ffccda6 100644 --- a/modules/commands/cs_suspend.cpp +++ b/modules/commands/cs_suspend.cpp @@ -10,6 +10,45 @@ */ #include "module.h" +#include "modules/cs_suspend.h" + +struct CSSuspendInfoImpl : CSSuspendInfo, Serializable +{ + CSSuspendInfoImpl(Extensible *) : Serializable("CSSuspendInfo") { } + + void Serialize(Serialize::Data &data) const anope_override + { + data["chan"] << chan; + data["by"] << by; + data["reason"] << reason; + data["time"] << time; + data["expires"] << expires; + } + + static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) + { + Anope::string schan; + data["chan"] >> schan; + + CSSuspendInfoImpl *si; + if (obj) + si = anope_dynamic_static_cast<CSSuspendInfoImpl *>(obj); + else + { + ChannelInfo *ci = ChannelInfo::Find(schan); + if (!ci) + return NULL; + si = ci->Extend<CSSuspendInfoImpl>("cs_suspend"); + data["chan"] >> si->chan; + } + + data["bi"] >> si->by; + data["reason"] >> si->reason; + data["time"] >> si->time; + data["expires"] >> si->expires; + return si; + } +}; class CommandCSSuspend : public Command { @@ -46,11 +85,12 @@ class CommandCSSuspend : public Command return; } - ci->ExtendMetadata("SUSPENDED"); - ci->ExtendMetadata("suspend:by", source.GetNick()); - if (!reason.empty()) - ci->ExtendMetadata("suspend:reason", reason); - ci->ExtendMetadata("suspend:time", stringify(Anope::CurTime)); + CSSuspendInfo *si = ci->Extend<CSSuspendInfo>("cs_suspend"); + si->chan = ci->name; + si->by = source.GetNick(); + si->reason = reason; + si->time = Anope::CurTime; + si->expires = expiry_secs ? expiry_secs + Anope::CurTime : 0; if (ci->c) { @@ -68,15 +108,10 @@ class CommandCSSuspend : public Command ci->c->Kick(NULL, users[i], "%s", !reason.empty() ? reason.c_str() : Language::Translate(users[i], _("This channel has been suspended."))); } - if (expiry_secs > 0) - ci->ExtendMetadata("suspend:expire", stringify(Anope::CurTime + expiry_secs)); - Log(LOG_ADMIN, source, this, ci) << (!reason.empty() ? reason : "No reason") << ", expires in " << (expiry_secs ? Anope::strftime(Anope::CurTime + expiry_secs) : "never"); source.Reply(_("Channel \002%s\002 is now suspended."), ci->name.c_str()); FOREACH_MOD(OnChanSuspend, (ci)); - - return; } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -118,21 +153,16 @@ class CommandCSUnSuspend : public Command } /* Only UNSUSPEND already suspended channels */ - if (!ci->HasExt("SUSPENDED")) + CSSuspendInfo *si = ci->GetExt<CSSuspendInfo>("cs_suspend"); + if (!si) { source.Reply(_("Channel \002%s\002 isn't suspended."), ci->name.c_str()); return; } - Anope::string *by = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:by"), *reason = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:reason"); - if (by != NULL) - Log(LOG_ADMIN, source, this, ci) << " which was suspended by " << *by << " for: " << (reason && !reason->empty() ? *reason : "No reason"); + Log(LOG_ADMIN, source, this, ci) << " which was suspended by " << si->by << " for: " << (!si->reason.empty() ? si->reason : "No reason"); - ci->Shrink("SUSPENDED"); - ci->Shrink("suspend:by"); - ci->Shrink("suspend:reason"); - ci->Shrink("suspend:expire"); - ci->Shrink("suspend:time"); + ci->Shrink<CSSuspendInfo>("cs_suspend"); source.Reply(_("Channel \002%s\002 is now released."), ci->name.c_str()); @@ -155,66 +185,73 @@ class CSSuspend : public Module { CommandCSSuspend commandcssuspend; CommandCSUnSuspend commandcsunsuspend; + ExtensibleItem<CSSuspendInfoImpl> suspend; + Serialize::Type suspend_type; public: CSSuspend(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandcssuspend(this), commandcsunsuspend(this) + commandcssuspend(this), commandcsunsuspend(this), suspend(this, "cs_suspend"), + suspend_type("CSSuspendInfo", CSSuspendInfoImpl::Unserialize) { - } void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_hidden) anope_override { - if (ci->HasExt("SUSPENDED")) + CSSuspendInfo *si = suspend.Get(ci); + if (si) { - Anope::string *by = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:by"), *reason = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:reason"), *t = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:time"); info["Suspended"] = "This channel is \2suspended\2."; - if (by) - info["Suspended by"] = *by; - if (reason) - info["Suspend reason"] = *reason; - if (t) - info["Suspended on"] = Anope::strftime(convertTo<time_t>(*t), source.GetAccount(), true); + if (!si->by.empty()) + info["Suspended by"] = si->by; + if (!si->reason.empty()) + info["Suspend reason"] = si->reason; + if (si->time) + info["Suspended on"] = Anope::strftime(si->time, source.GetAccount(), true); + if (si->expires) + info["Suspended expires"] = Anope::strftime(si->expires, source.GetAccount(), true); } } void OnPreChanExpire(ChannelInfo *ci, bool &expire) anope_override { - if (!ci->HasExt("SUSPENDED")) + CSSuspendInfo *si = suspend.Get(ci); + if (!si) return; expire = false; - Anope::string *str = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:expire"); - if (str == NULL) + if (!si->expires) return; - try + if (si->expires < Anope::CurTime) { - time_t when = convertTo<time_t>(*str); - if (when < Anope::CurTime) - { - ci->last_used = Anope::CurTime; - ci->Shrink("SUSPENDED"); - ci->Shrink("suspend:expire"); - ci->Shrink("suspend:by"); - ci->Shrink("suspend:reason"); - ci->Shrink("suspend:time"); - - Log(this) << "Expiring suspend for " << ci->name; - } + ci->last_used = Anope::CurTime; + suspend.Unset(ci); + + Log(this) << "Expiring suspend for " << ci->name; } - catch (const ConvertException &) { } } EventReturn OnCheckKick(User *u, Channel *c, Anope::string &mask, Anope::string &reason) anope_override { - if (u->HasMode("OPER") || !c->ci || !c->ci->HasExt("SUSPENDED")) + if (u->HasMode("OPER") || !c->ci || !suspend.HasExt(c->ci)) return EVENT_CONTINUE; reason = Language::Translate(u, _("This channel may not be used.")); return EVENT_STOP; } + + EventReturn OnChanDrop(CommandSource &source, ChannelInfo *ci) anope_override + { + CSSuspendInfo *si = suspend.Get(ci); + if (si && !source.HasCommand("chanserv/drop")) + { + source.Reply(CHAN_X_SUSPENDED, ci->name.c_str()); + return EVENT_STOP; + } + + return EVENT_CONTINUE; + } }; MODULE_INIT(CSSuspend) diff --git a/modules/commands/cs_topic.cpp b/modules/commands/cs_topic.cpp index 294689864..39ddfe8f9 100644 --- a/modules/commands/cs_topic.cpp +++ b/modules/commands/cs_topic.cpp @@ -10,9 +10,70 @@ */ #include "module.h" +#include "modules/cs_mode.h" + +class CommandCSSetKeepTopic : public Command +{ + public: + CommandCSSetKeepTopic(Module *creator, const Anope::string &cname = "chanserv/set/keeptopic") : Command(creator, cname, 2, 2) + { + this->SetDesc(_("Retain topic when channel is not in use")); + this->SetSyntax(_("\037channel\037 {ON | OFF}")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + ChannelInfo *ci = ChannelInfo::Find(params[0]); + if (ci == NULL) + { + source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + return; + } + + EventReturn MOD_RESULT; + FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); + if (MOD_RESULT == EVENT_STOP) + return; + + if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) + { + source.Reply(ACCESS_DENIED); + return; + } + + if (params[1].equals_ci("ON")) + { + Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable keeptopic"; + ci->Extend<bool>("KEEPTOPIC"); + source.Reply(_("Topic retention option for %s is now \002on\002."), ci->name.c_str()); + } + else if (params[1].equals_ci("OFF")) + { + Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable keeptopic"; + ci->Shrink<bool>("KEEPTOPIC"); + source.Reply(_("Topic retention option for %s is now \002off\002."), ci->name.c_str()); + } + else + this->OnSyntaxError(source, "KEEPTOPIC"); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Enables or disables the \002topic retention\002 option for a\n" + "channel. When \002%s\002 is set, the topic for the\n" + "channel will be remembered by %s even after the\n" + "last user leaves the channel, and will be restored the\n" + "next time the channel is created."), source.command.c_str(), source.service->nick.c_str()); + return true; + } +}; class CommandCSTopic : public Command { + ExtensibleRef<bool> topiclock; + void Lock(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms) { EventReturn MOD_RESULT; @@ -20,7 +81,7 @@ class CommandCSTopic : public Command if (MOD_RESULT == EVENT_STOP) return; - ci->ExtendMetadata("TOPICLOCK"); + topiclock->Set(ci, true); source.Reply(_("Topic lock option for %s is now \002on\002."), ci->name.c_str()); } @@ -31,7 +92,7 @@ class CommandCSTopic : public Command if (MOD_RESULT == EVENT_STOP) return; - ci->Shrink("TOPICLOCK"); + topiclock->Unset(ci); source.Reply(_("Topic lock option for %s is now \002off\002."), ci->name.c_str()); } @@ -39,11 +100,11 @@ class CommandCSTopic : public Command { const Anope::string &topic = params.size() > 2 ? params[2] : ""; - bool has_topiclock = ci->HasExt("TOPICLOCK"); - ci->Shrink("TOPICLOCK"); + bool *has_topiclock = topiclock->Get(ci); + topiclock->Unset(ci); ci->c->ChangeTopic(source.GetNick(), topic, Anope::CurTime); if (has_topiclock) - ci->ExtendMetadata("TOPICLOCK"); + topiclock->Set(ci, *has_topiclock); bool override = !source.AccessFor(ci).HasPriv("TOPIC"); Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << (!topic.empty() ? "to change the topic to: " : "to unset the topic") << (!topic.empty() ? topic : ""); @@ -71,7 +132,8 @@ class CommandCSTopic : public Command } public: - CommandCSTopic(Module *creator) : Command(creator, "chanserv/topic", 2, 3) + CommandCSTopic(Module *creator) : Command(creator, "chanserv/topic", 2, 3), + topiclock("TOPICLOCK") { this->SetDesc(_("Manipulate the topic of the specified channel")); this->SetSyntax(_("\037channel\037 SET [\037topic\037]")); @@ -120,13 +182,66 @@ class CommandCSTopic : public Command class CSTopic : public Module { CommandCSTopic commandcstopic; + CommandCSSetKeepTopic commandcssetkeeptopic; + + SerializableExtensibleItem<bool> topiclock, keeptopic; public: CSTopic(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandcstopic(this) + commandcstopic(this), commandcssetkeeptopic(this), topiclock(this, "TOPICLOCK"), keeptopic(this, "KEEPTOPIC") { } + + void OnChannelSync(Channel *c) anope_override + { + if (Me && Me->IsSynced() && c->ci) + { + /* Update channel topic */ + if ((topiclock.HasExt(c->ci) || keeptopic.HasExt(c->ci)) && c->ci->last_topic != c->topic) + { + c->ChangeTopic(!c->ci->last_topic_setter.empty() ? c->ci->last_topic_setter : c->ci->WhoSends()->nick, c->ci->last_topic, c->ci->last_topic_time ? c->ci->last_topic_time : Anope::CurTime); + } + } + } + + void OnTopicUpdated(Channel *c, const Anope::string &user, const Anope::string &topic) anope_override + { + if (!c->ci) + return; + + /* We only compare the topics here, not the time or setter. This is because some (old) IRCds do not + * allow us to set the topic as someone else, meaning we have to bump the TS and change the setter to us. + * This desyncs what is really set with what we have stored, and we end up resetting the topic often when + * it is not required + */ + if (topiclock.HasExt(c->ci) && c->ci->last_topic != c->topic) + { + c->ChangeTopic(c->ci->last_topic_setter, c->ci->last_topic, c->ci->last_topic_time); + } + else + { + c->ci->last_topic = c->topic; + c->ci->last_topic_setter = c->topic_setter; + c->ci->last_topic_time = c->topic_ts; + } + } + + void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_all) + { + if (keeptopic.HasExt(ci)) + info.AddOption(_("Topic Retention")); + if (topiclock.HasExt(ci)) + info.AddOption(_("Topic Lock")); + + ModeLocks *ml = ci->GetExt<ModeLocks>("modelocks"); + const ModeLock *secret = ml ? ml->GetMLock("SECRET") : NULL; + if (!ci->last_topic.empty() && (show_all || ((!secret || secret->set == false) && (!ci->c || !ci->c->HasMode("SECRET"))))) + { + info["Last topic"] = ci->last_topic; + info["Topic set by"] = ci->last_topic_setter; + } + } }; MODULE_INIT(CSTopic) diff --git a/modules/commands/greet.cpp b/modules/commands/greet.cpp new file mode 100644 index 000000000..dd3fce66f --- /dev/null +++ b/modules/commands/greet.cpp @@ -0,0 +1,210 @@ +/* + * + * (C) 2003-2013 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 CommandBSSetGreet : public Command +{ + public: + CommandBSSetGreet(Module *creator, const Anope::string &sname = "botserv/set/greet") : Command(creator, sname, 2, 2) + { + this->SetDesc(_("Enable greet messages")); + this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + ChannelInfo *ci = ChannelInfo::Find(params[0]); + const Anope::string &value = params[1]; + + if (ci == NULL) + { + source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + return; + } + + if (!source.HasPriv("botserv/administration") && !source.AccessFor(ci).HasPriv("SET")) + { + source.Reply(ACCESS_DENIED); + return; + } + + if (Anope::ReadOnly) + { + source.Reply(_("Sorry, bot option setting is temporarily disabled.")); + return; + } + + if (value.equals_ci("ON")) + { + bool override = !source.AccessFor(ci).HasPriv("SET"); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable greets"; + + ci->Extend<bool>("BS_GREET"); + source.Reply(_("Greet mode is now \002on\002 on channel %s."), ci->name.c_str()); + } + else if (value.equals_ci("OFF")) + { + bool override = !source.AccessFor(ci).HasPriv("SET"); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable greets"; + + ci->Shrink<bool>("BS_GREET"); + source.Reply(_("Greet mode is now \002off\002 on channel %s."), ci->name.c_str()); + } + else + this->OnSyntaxError(source, source.command); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(_(" \n" + "Enables or disables \002greet\002 mode on a channel.\n" + "When it is enabled, the bot will display greet\n" + "messages of users joining the channel, provided\n" + "they have enough access to the channel.")); + return true; + } +}; + +class CommandNSSetGreet : public Command +{ + public: + CommandNSSetGreet(Module *creator, const Anope::string &sname = "nickserv/set/greet", size_t min = 0) : Command(creator, sname, min, min + 1) + { + this->SetDesc(_("Associate a greet message with your nickname")); + this->SetSyntax(_("\037message\037")); + } + + void Run(CommandSource &source, const Anope::string &user, const Anope::string ¶m) + { + const NickAlias *na = NickAlias::Find(user); + if (!na) + { + source.Reply(NICK_X_NOT_REGISTERED, user.c_str()); + return; + } + NickCore *nc = na->nc; + + EventReturn MOD_RESULT; + FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param)); + if (MOD_RESULT == EVENT_STOP) + return; + + if (!param.empty()) + { + Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change the greet of " << nc->display; + nc->Extend<Anope::string>("greet", param); + source.Reply(_("Greet message for \002%s\002 changed to \002%s\002."), nc->display.c_str(), param.c_str()); + } + else + { + Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to unset the greet of " << nc->display; + nc->Shrink<Anope::string>("greet"); + source.Reply(_("Greet message for \002%s\002 unset."), nc->display.c_str()); + } + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + this->Run(source, source.nc->display, params.size() > 0 ? params[0] : ""); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Makes the given message the greet of your nickname, that\n" + "will be displayed when joining a channel that has GREET\n" + "option enabled, provided that you have the necessary\n" + "access on it.")); + return true; + } +}; + +class CommandNSSASetGreet : public CommandNSSetGreet +{ + public: + CommandNSSASetGreet(Module *creator) : CommandNSSetGreet(creator, "nickserv/saset/greet", 1) + { + this->ClearSyntax(); + this->SetSyntax(_("\037nickname\037 \037message\037")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + this->Run(source, params[0], params.size() > 1 ? params[1] : ""); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Makes the given message the greet of the nickname, that\n" + "will be displayed when joining a channel that has GREET\n" + "option enabled, provided that the user has the necessary\n" + "access on it.")); + return true; + } +}; + +class Greet : public Module +{ + /* channel setting for whether or not greet should be shown */ + SerializableExtensibleItem<bool> bs_greet; + /* user greets */ + SerializableExtensibleItem<Anope::string> ns_greet; + + CommandBSSetGreet commandbssetgreet; + CommandNSSetGreet commandnssetgreet; + CommandNSSASetGreet commandnssasetgreet; + + public: + Greet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), + bs_greet(this, "BS_GREET"), + ns_greet(this, "greet"), + commandbssetgreet(this), + commandnssetgreet(this), commandnssasetgreet(this) + { + } + + void OnJoinChannel(User *user, Channel *c) anope_override + { + /* Only display the greet if the main uplink we're connected + * to has synced, or we'll get greet-floods when the net + * recovers from a netsplit. -GD + */ + if (!c->ci || !c->ci->bi || !user->server->IsSynced() || !user->Account()) + return; + + Anope::string *greet = ns_greet.Get(user->Account()); + if (bs_greet.HasExt(c->ci) && greet != NULL && !greet->empty() && c->FindUser(c->ci->bi) && c->ci->AccessFor(user).HasPriv("GREET")) + { + IRCD->SendPrivmsg(c->ci->bi, c->name, "[%s] %s", user->Account()->display.c_str(), greet->c_str()); + c->ci->bi->lastmsg = Anope::CurTime; + } + } + + void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) anope_override + { + Anope::string *greet = ns_greet.Get(na->nc); + if (greet != NULL) + info[_("Greet")] = *greet; + } + + void OnBotInfo(CommandSource &source, BotInfo *bi, ChannelInfo *ci, InfoFormatter &info) anope_override + { + if (bs_greet.HasExt(ci)) + info.AddOption(_("Greet")); + } +}; + +MODULE_INIT(Greet) diff --git a/modules/commands/hs_request.cpp b/modules/commands/hs_request.cpp index 2b1299f93..5203b086b 100644 --- a/modules/commands/hs_request.cpp +++ b/modules/commands/hs_request.cpp @@ -21,14 +21,14 @@ static ServiceReference<MemoServService> memoserv("MemoServService", "MemoServ") static void req_send_memos(Module *me, CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost); -struct HostRequest : ExtensibleItem, Serializable +struct HostRequest : Serializable { Anope::string nick; Anope::string ident; Anope::string host; time_t time; - HostRequest() : Serializable("HostRequest") { } + HostRequest(Extensible *) : Serializable("HostRequest") { } void Serialize(Serialize::Data &data) const anope_override { @@ -51,14 +51,15 @@ struct HostRequest : ExtensibleItem, Serializable if (obj) req = anope_dynamic_static_cast<HostRequest *>(obj); else - req = new HostRequest; - req->nick = na->nick; - data["ident"] >> req->ident; - data["host"] >> req->host; - data["time"] >> req->time; - - if (!obj) - na->Extend("hs_request", req); + req = na->Extend<HostRequest>("hostrequest"); + if (req) + { + req->nick = na->nick; + data["ident"] >> req->ident; + data["host"] >> req->host; + data["time"] >> req->time; + } + return req; } }; @@ -148,12 +149,12 @@ class CommandHSRequest : public Command return; } - HostRequest *req = new HostRequest; - req->nick = source.GetNick(); - req->ident = user; - req->host = host; - req->time = Anope::CurTime; - na->Extend("hs_request", req); + HostRequest req(na); + req.nick = source.GetNick(); + req.ident = user; + req.host = host; + req.time = Anope::CurTime; + na->Extend<HostRequest>("hostrequest", req); source.Reply(_("Your vHost has been requested.")); req_send_memos(owner, source, user, host); @@ -186,7 +187,7 @@ class CommandHSActivate : public Command const Anope::string &nick = params[0]; NickAlias *na = NickAlias::Find(nick); - HostRequest *req = na ? na->GetExt<HostRequest *>("hs_request") : NULL; + HostRequest *req = na ? na->GetExt<HostRequest>("hostrequest") : NULL; if (req) { na->SetVhost(req->ident, req->host, source.GetNick(), req->time); @@ -197,7 +198,7 @@ class CommandHSActivate : public Command source.Reply(_("vHost for %s has been activated."), na->nick.c_str()); Log(LOG_COMMAND, source, this) << "for " << na->nick << " for vhost " << (!req->ident.empty() ? req->ident + "@" : "") << req->host; - na->Shrink("hs_request"); + na->Shrink<HostRequest>("hostrequest"); } else source.Reply(_("No request for nick %s found."), nick.c_str()); @@ -231,10 +232,10 @@ class CommandHSReject : public Command const Anope::string &reason = params.size() > 1 ? params[1] : ""; NickAlias *na = NickAlias::Find(nick); - HostRequest *req = na ? na->GetExt<HostRequest *>("hs_request") : NULL; + HostRequest *req = na ? na->GetExt<HostRequest>("hostrequest") : NULL; if (req) { - na->Shrink("hs_request"); + na->Shrink<HostRequest>("hostrequest"); if (Config->GetModule(this->owner)->Get<bool>("memouser") && memoserv) { @@ -244,7 +245,7 @@ class CommandHSReject : public Command else message = _("[auto memo] Your requested vHost has been rejected."); - memoserv->Send(source.service->nick, nick, message, true); + memoserv->Send(source.service->nick, nick, Language::Translate(source.GetAccount(), message.c_str()), true); } source.Reply(_("vHost for %s has been rejected."), nick.c_str()); @@ -252,8 +253,6 @@ class CommandHSReject : public Command } else source.Reply(_("No request for nick %s found."), nick.c_str()); - - return; } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -287,7 +286,7 @@ class CommandHSWaiting : public Command for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it) { const NickAlias *na = it->second; - HostRequest *hr = na->GetExt<HostRequest *>("hs_request"); + HostRequest *hr = na->GetExt<HostRequest>("hostrequest"); if (!hr) continue; @@ -334,24 +333,17 @@ class HSRequest : public Module CommandHSActivate commandhsactive; CommandHSReject commandhsreject; CommandHSWaiting commandhswaiting; + ExtensibleItem<HostRequest> hostrequest; public: HSRequest(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - request_type("HostRequest", HostRequest::Unserialize), commandhsrequest(this), commandhsactive(this), commandhsreject(this), commandhswaiting(this) + request_type("HostRequest", HostRequest::Unserialize), commandhsrequest(this), commandhsactive(this), + commandhsreject(this), commandhswaiting(this), hostrequest(this, "hostrequest") { if (!IRCD || !IRCD->CanSetVHost) throw ModuleException("Your IRCd does not support vhosts"); } - - ~HSRequest() - { - for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it) - { - NickAlias *na = it->second; - na->Shrink("hs_request"); - } - } }; static void req_send_memos(Module *me, CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost) diff --git a/modules/commands/ms_info.cpp b/modules/commands/ms_info.cpp index 67a504117..909ff4c82 100644 --- a/modules/commands/ms_info.cpp +++ b/modules/commands/ms_info.cpp @@ -27,7 +27,7 @@ class CommandMSInfo : public Command const NickAlias *na = NULL; ChannelInfo *ci = NULL; const Anope::string &nname = !params.empty() ? params[0] : ""; - int hardmax = 0; + bool hardmax; if (!nname.empty() && nname[0] != '#' && source.HasPriv("memoserv/info")) { @@ -38,7 +38,7 @@ class CommandMSInfo : public Command return; } mi = &na->nc->memos; - hardmax = na->nc->HasExt("MEMO_HARDMAX") ? 1 : 0; + hardmax = na->nc->HasExt("MEMO_HARDMAX"); } else if (!nname.empty() && nname[0] == '#') { @@ -54,7 +54,7 @@ class CommandMSInfo : public Command return; } mi = &ci->memos; - hardmax = ci->HasExt("MEMO_HARDMAX") ? 1 : 0; + hardmax = ci->HasExt("MEMO_HARDMAX"); } else if (!nname.empty()) /* It's not a chan and we aren't services admin */ { @@ -64,7 +64,7 @@ class CommandMSInfo : public Command else { mi = &nc->memos; - hardmax = nc->HasExt("MEMO_HARDMAX") ? 1 : 0; + hardmax = nc->HasExt("MEMO_HARDMAX"); } if (!nname.empty() && (ci || na->nc != nc)) @@ -178,7 +178,6 @@ class CommandMSInfo : public Command else source.Reply(_("You will not be notified of new memos.")); } - return; } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override diff --git a/modules/commands/ms_set.cpp b/modules/commands/ms_set.cpp index 9bf63b15d..e6d48d08a 100644 --- a/modules/commands/ms_set.cpp +++ b/modules/commands/ms_set.cpp @@ -25,27 +25,27 @@ class CommandMSSet : public Command if (param.equals_ci("ON")) { - nc->ExtendMetadata("MEMO_SIGNON"); - nc->ExtendMetadata("MEMO_RECEIVE"); + nc->Extend<bool>("MEMO_SIGNON"); + nc->Extend<bool>("MEMO_RECEIVE"); source.Reply(_("%s will now notify you of memos when you log on and when they are sent to you."), MemoServ->nick.c_str()); } else if (param.equals_ci("LOGON")) { - nc->ExtendMetadata("MEMO_SIGNON"); - nc->Shrink("MEMO_RECEIVE"); + nc->Extend<bool>("MEMO_SIGNON"); + nc->Shrink<bool>("MEMO_RECEIVE"); source.Reply(_("%s will now notify you of memos when you log on or unset /AWAY."), MemoServ->nick.c_str()); } else if (param.equals_ci("NEW")) { - nc->Shrink("MEMO_SIGNON"); - nc->ExtendMetadata("MEMO_RECEIVE"); + nc->Shrink<bool>("MEMO_SIGNON"); + nc->Extend<bool>("MEMO_RECEIVE"); source.Reply(_("%s will now notify you of memos when they are sent to you."), MemoServ->nick.c_str()); } else if (param.equals_ci("MAIL")) { if (!nc->email.empty()) { - nc->ExtendMetadata("MEMO_MAIL"); + nc->Extend<bool>("MEMO_MAIL"); source.Reply(_("You will now be informed about new memos via email.")); } else @@ -53,20 +53,18 @@ class CommandMSSet : public Command } else if (param.equals_ci("NOMAIL")) { - nc->Shrink("MEMO_MAIL"); + nc->Shrink<bool>("MEMO_MAIL"); source.Reply(_("You will no longer be informed via email.")); } else if (param.equals_ci("OFF")) { - nc->Shrink("MEMO_SIGNON"); - nc->Shrink("MEMO_RECEIVE"); - nc->Shrink("MEMO_MAIL"); + nc->Shrink<bool>("MEMO_SIGNON"); + nc->Shrink<bool>("MEMO_RECEIVE"); + nc->Shrink<bool>("MEMO_MAIL"); source.Reply(_("%s will not send you any notification of memos."), MemoServ->nick.c_str()); } else this->OnSyntaxError(source, ""); - - return; } void DoLimit(CommandSource &source, const std::vector<Anope::string> ¶ms, MemoInfo *mi) @@ -125,16 +123,16 @@ class CommandMSSet : public Command if (!chan.empty()) { if (!p2.empty()) - ci->ExtendMetadata("MEMO_HARDMAX"); + ci->Extend<bool>("MEMO_HARDMAX"); else - ci->Shrink("MEMO_HARDMAX"); + ci->Shrink<bool>("MEMO_HARDMAX"); } else { if (!p2.empty()) - nc->ExtendMetadata("MEMO_HARDMAX"); + nc->Extend<bool>("MEMO_HARDMAX"); else - nc->Shrink("MEMO_HARDMAX"); + nc->Shrink<bool>("MEMO_HARDMAX"); } limit = -1; try @@ -301,10 +299,12 @@ class CommandMSSet : public Command class MSSet : public Module { CommandMSSet commandmsset; + PrimitiveExtensibleItem<bool> memo_signon, memo_receive, memo_mail, memo_hardmax; public: MSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandmsset(this) + commandmsset(this), memo_signon(this, "MEMO_SIGNON"), memo_receive(this, "MEMO_RECEIVE"), memo_mail(this, "MEMO_MAIL"), + memo_hardmax(this, "MEMO_HARDMAX") { } diff --git a/modules/commands/ns_ajoin.cpp b/modules/commands/ns_ajoin.cpp index 0304c7394..79d7fdf4a 100644 --- a/modules/commands/ns_ajoin.cpp +++ b/modules/commands/ns_ajoin.cpp @@ -13,9 +13,9 @@ struct AJoinEntry; -struct AJoinList : Serialize::Checker<std::vector<AJoinEntry *> >, ExtensibleItem +struct AJoinList : Serialize::Checker<std::vector<AJoinEntry *> > { - AJoinList() : Serialize::Checker<std::vector<AJoinEntry *> >("AJoinEntry") { } + AJoinList(Extensible *) : Serialize::Checker<std::vector<AJoinEntry *> >("AJoinEntry") { } ~AJoinList(); }; @@ -25,7 +25,7 @@ struct AJoinEntry : Serializable Anope::string channel; Anope::string key; - AJoinEntry() : Serializable("AJoinEntry") { } + AJoinEntry(Extensible *) : Serializable("AJoinEntry") { } void Serialize(Serialize::Data &sd) const anope_override { @@ -52,7 +52,7 @@ struct AJoinEntry : Serializable aj = anope_dynamic_static_cast<AJoinEntry *>(obj); else { - aj = new AJoinEntry(); + aj = new AJoinEntry(nc); aj->owner = nc; } @@ -61,12 +61,7 @@ struct AJoinEntry : Serializable if (!obj) { - AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels"); - if (channels == NULL) - { - channels = new AJoinList(); - nc->Extend("ns_ajoin_channels", channels); - } + AJoinList *channels = nc->Require<AJoinList>("ajoinlist"); (*channels)->push_back(aj); } @@ -84,12 +79,7 @@ class CommandNSAJoin : public Command { void DoList(CommandSource &source, NickCore *nc) { - AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels"); - if (channels == NULL) - { - channels = new AJoinList(); - nc->Extend("ns_ajoin_channels", channels); - } + AJoinList *channels = nc->Require<AJoinList>("ajoinlist"); if ((*channels)->empty()) source.Reply(_("%s's auto join list is empty."), nc->display.c_str()); @@ -119,12 +109,7 @@ class CommandNSAJoin : public Command void DoAdd(CommandSource &source, NickCore *nc, const Anope::string &chan, const Anope::string &key) { - AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels"); - if (channels == NULL) - { - channels = new AJoinList(); - nc->Extend("ns_ajoin_channels", channels); - } + AJoinList *channels = nc->Require<AJoinList>("ajoinlist"); unsigned i = 0; for (; i < (*channels)->size(); ++i) @@ -139,7 +124,7 @@ class CommandNSAJoin : public Command source.Reply(CHAN_X_INVALID, chan.c_str()); else { - AJoinEntry *entry = new AJoinEntry(); + AJoinEntry *entry = new AJoinEntry(nc); entry->owner = nc; entry->channel = chan; entry->key = key; @@ -150,12 +135,7 @@ class CommandNSAJoin : public Command void DoDel(CommandSource &source, NickCore *nc, const Anope::string &chan) { - AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels"); - if (channels == NULL) - { - channels = new AJoinList(); - nc->Extend("ns_ajoin_channels", channels); - } + AJoinList *channels = nc->Require<AJoinList>("ajoinlist"); unsigned i = 0; for (; i < (*channels)->size(); ++i) @@ -170,6 +150,9 @@ class CommandNSAJoin : public Command (*channels)->erase((*channels)->begin() + i); source.Reply(_("%s was removed from %s's auto join list."), chan.c_str(), nc->display.c_str()); } + + if ((*channels)->empty()) + nc->Shrink<AJoinList>("ajoinlist"); } public: @@ -233,10 +216,11 @@ class NSAJoin : public Module { Serialize::Type ajoinentry_type; CommandNSAJoin commandnsajoin; + ExtensibleItem<AJoinList> ajoinlist; public: NSAJoin(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - ajoinentry_type("AJoinEntry", AJoinEntry::Unserialize), commandnsajoin(this) + ajoinentry_type("AJoinEntry", AJoinEntry::Unserialize), commandnsajoin(this), ajoinlist(this, "ajoinlist") { if (!IRCD->CanSVSJoin) @@ -250,12 +234,9 @@ class NSAJoin : public Module if (!NickServ) return; - AJoinList *channels = u->Account()->GetExt<AJoinList *>("ns_ajoin_channels"); + AJoinList *channels = u->Account()->GetExt<AJoinList>("ajoinlist"); if (channels == NULL) - { - channels = new AJoinList(); - u->Account()->Extend("ns_ajoin_channels", channels); - } + channels = u->Account()->Extend<AJoinList>("ajoinlist"); for (unsigned i = 0; i < (*channels)->size(); ++i) { @@ -284,7 +265,7 @@ class NSAJoin : public Module continue; else if (c->HasMode("ADMINONLY") && !u->HasMode("ADMIN")) continue; - else if (c->HasMode("SSL") && !(u->HasMode("SSL") || u->HasExt("SSL"))) + else if (c->HasMode("SSL") && !(u->HasMode("SSL") || u->HasExt("ssl"))) continue; else if (c->MatchesList(u, "BAN") == true && c->MatchesList(u, "EXCEPT") == false) need_invite = true; diff --git a/modules/commands/ns_alist.cpp b/modules/commands/ns_alist.cpp index 591af44c3..2d7b02cfd 100644 --- a/modules/commands/ns_alist.cpp +++ b/modules/commands/ns_alist.cpp @@ -62,7 +62,7 @@ class CommandNSAList : public Command { ++chan_count; entry["Number"] = stringify(chan_count); - entry["Channel"] = (ci->HasExt("NO_EXPIRE") ? "!" : "") + ci->name; + entry["Channel"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name; entry["Access"] = "Founder"; list.AddEntry(entry); continue; @@ -72,7 +72,7 @@ class CommandNSAList : public Command { ++chan_count; entry["Number"] = stringify(chan_count); - entry["Channel"] = (ci->HasExt("NO_EXPIRE") ? "!" : "") + ci->name; + entry["Channel"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name; entry["Access"] = "Successor"; list.AddEntry(entry); continue; @@ -85,7 +85,7 @@ class CommandNSAList : public Command ++chan_count; entry["Number"] = stringify(chan_count); - entry["Channel"] = (ci->HasExt("NO_EXPIRE") ? "!" : "") + ci->name; + entry["Channel"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name; for (unsigned j = 0; j < access.size(); ++j) entry["Access"] = entry["Access"] + ", " + access[j]->AccessSerialize(); entry["Access"] = entry["Access"].substr(2); diff --git a/modules/commands/ns_cert.cpp b/modules/commands/ns_cert.cpp index dc877e467..c87ff7179 100644 --- a/modules/commands/ns_cert.cpp +++ b/modules/commands/ns_cert.cpp @@ -10,15 +10,135 @@ */ #include "module.h" +#include "modules/ns_cert.h" -static unsigned accessmax; +struct NSCertListImpl : NSCertList +{ + Serialize::Reference<NickCore> nc; + std::vector<Anope::string> certs; + + public: + NSCertListImpl(Extensible *obj) : nc(anope_dynamic_static_cast<NickCore *>(obj)) { } + + /** Add an entry to the nick's certificate list + * + * @param entry The fingerprint to add to the cert list + * + * Adds a new entry into the cert list. + */ + void AddCert(const Anope::string &entry) anope_override + { + this->certs.push_back(entry); + FOREACH_MOD(OnNickAddCert, (this->nc, entry)); + } + + /** Get an entry from the nick's cert list by index + * + * @param entry Index in the certificaate list vector to retrieve + * @return The fingerprint entry of the given index if within bounds, an empty string if the vector is empty or the index is out of bounds + * + * Retrieves an entry from the certificate list corresponding to the given index. + */ + Anope::string GetCert(unsigned entry) const anope_override + { + if (entry >= this->certs.size()) + return ""; + return this->certs[entry]; + } + + unsigned GetCertCount() const anope_override + { + return this->certs.size(); + } + + /** Find an entry in the nick's cert list + * + * @param entry The fingerprint to search for + * @return True if the fingerprint is found in the cert list, false otherwise + * + * Search for an fingerprint within the cert list. + */ + bool FindCert(const Anope::string &entry) const anope_override + { + return std::find(this->certs.begin(), this->certs.end(), entry) != this->certs.end(); + } + + /** Erase a fingerprint from the nick's certificate list + * + * @param entry The fingerprint to remove + * + * Removes the specified fingerprint from the cert list. + */ + void EraseCert(const Anope::string &entry) anope_override + { + std::vector<Anope::string>::iterator it = std::find(this->certs.begin(), this->certs.end(), entry); + if (it != this->certs.end()) + { + FOREACH_MOD(OnNickEraseCert, (this->nc, entry)); + this->certs.erase(it); + } + } + + /** Clears the entire nick's cert list + * + * Deletes all the memory allocated in the certificate list vector and then clears the vector. + */ + void ClearCert() anope_override + { + FOREACH_MOD(OnNickClearCert, (this->nc)); + this->certs.clear(); + } + + void Check() anope_override + { + if (this->certs.empty()) + nc->Shrink<NSCertList>("certificates"); + } + + struct ExtensibleItem : ::ExtensibleItem<NSCertListImpl> + { + ExtensibleItem(Module *m, const Anope::string &name) : ::ExtensibleItem<NSCertListImpl>(m, name) { } + + void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const anope_override + { + if (s->GetSerializableType()->GetName() != "NickCore") + return; + + const NickCore *nc = anope_dynamic_static_cast<const NickCore *>(e); + NSCertList *certs = this->Get(nc); + if (certs == NULL || !certs->GetCertCount()) + return; + + for (unsigned i = 0; i < certs->GetCertCount(); ++i) + data["cert"] << certs->GetCert(i) << " "; + } + + void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) anope_override + { + if (s->GetSerializableType()->GetName() != "NickCore") + return; + + NickCore *nc = anope_dynamic_static_cast<NickCore *>(e); + NSCertListImpl *certs = this->Require(nc); + + Anope::string buf; + data["cert"] >> buf; + spacesepstream sep(buf); + certs->certs.clear(); + while (sep.GetToken(buf)) + certs->certs.push_back(buf); + } + }; +}; class CommandNSCert : public Command { private: void DoServAdminList(CommandSource &source, const NickCore *nc) { - if (nc->cert.empty()) + NSCertList *cl = nc->GetExt<NSCertList>("certificates"); + + if (!cl || !cl->GetCertCount()) { source.Reply(_("Certificate list for \002%s\002 is empty."), nc->display.c_str()); return; @@ -33,9 +153,9 @@ class CommandNSCert : public Command ListFormatter list; list.AddColumn("Certificate"); - for (unsigned i = 0, end = nc->cert.size(); i < end; ++i) + for (unsigned i = 0; i < cl->GetCertCount(); ++i) { - Anope::string fingerprint = nc->GetCert(i); + const Anope::string &fingerprint = cl->GetCert(i); ListFormatter::ListEntry entry; entry["Certificate"] = fingerprint; list.AddEntry(entry); @@ -47,74 +167,74 @@ class CommandNSCert : public Command list.Process(replies); for (unsigned i = 0; i < replies.size(); ++i) source.Reply(replies[i]); - - return; } void DoAdd(CommandSource &source, NickCore *nc, const Anope::string &mask) { + NSCertList *cl = nc->Require<NSCertList>("certificates"); - if (nc->cert.size() >= Config->GetModule(this->owner)->Get<unsigned>("accessmax")) + if (cl->GetCertCount() >= Config->GetModule(this->owner)->Get<unsigned>("accessmax")) { source.Reply(_("Sorry, you can only have %d certificate entries for a nickname."), Config->GetModule(this->owner)->Get<unsigned>("accessmax")); return; } - if (source.GetUser() && !source.GetUser()->fingerprint.empty() && !nc->FindCert(source.GetUser()->fingerprint)) - { - nc->AddCert(source.GetUser()->fingerprint); - source.Reply(_("\002%s\002 added to your certificate list."), source.GetUser()->fingerprint.c_str()); - return; - } - if (mask.empty()) { - this->OnSyntaxError(source, "ADD"); + if (source.GetUser() && !source.GetUser()->fingerprint.empty() && !cl->FindCert(source.GetUser()->fingerprint)) + { + cl->AddCert(source.GetUser()->fingerprint); + source.Reply(_("\002%s\002 added to your certificate list."), source.GetUser()->fingerprint.c_str()); + } + else + this->OnSyntaxError(source, "ADD"); + return; } - if (nc->FindCert(mask)) + if (cl->FindCert(mask)) { source.Reply(_("Fingerprint \002%s\002 already present on your certificate list."), mask.c_str()); return; } - nc->AddCert(mask); + cl->AddCert(mask); source.Reply(_("\002%s\002 added to your certificate list."), mask.c_str()); - return; } void DoDel(CommandSource &source, NickCore *nc, const Anope::string &mask) { - if (source.GetUser() && !source.GetUser()->fingerprint.empty() && nc->FindCert(source.GetUser()->fingerprint)) - { - nc->EraseCert(source.GetUser()->fingerprint); - source.Reply(_("\002%s\002 deleted from your certificate list."), source.GetUser()->fingerprint.c_str()); - return; - } + NSCertList *cl = nc->Require<NSCertList>("certificates"); if (mask.empty()) { - this->OnSyntaxError(source, "DEL"); + if (source.GetUser() && !source.GetUser()->fingerprint.empty() && cl->FindCert(source.GetUser()->fingerprint)) + { + cl->EraseCert(source.GetUser()->fingerprint); + source.Reply(_("\002%s\002 deleted from your certificate list."), source.GetUser()->fingerprint.c_str()); + } + else + this->OnSyntaxError(source, "DEL"); + return; } - if (!nc->FindCert(mask)) + if (!cl->FindCert(mask)) { source.Reply(_("\002%s\002 not found on your certificate list."), mask.c_str()); return; } source.Reply(_("\002%s\002 deleted from your certificate list."), mask.c_str()); - nc->EraseCert(mask); - - return; + cl->EraseCert(mask); + cl->Check(); } void DoList(CommandSource &source, const NickCore *nc) { + NSCertList *cl = nc->GetExt<NSCertList>("certificates"); - if (nc->cert.empty()) + if (!cl || !cl->GetCertCount()) { source.Reply(_("Your certificate list is empty.")); return; @@ -123,10 +243,10 @@ class CommandNSCert : public Command ListFormatter list; list.AddColumn("Certificate"); - for (unsigned i = 0, end = nc->cert.size(); i < end; ++i) + for (unsigned i = 0; i < cl->GetCertCount(); ++i) { ListFormatter::ListEntry entry; - entry["Certificate"] = nc->GetCert(i); + entry["Certificate"] = cl->GetCert(i); list.AddEntry(entry); } @@ -197,8 +317,17 @@ class CommandNSCert : public Command class NSCert : public Module { CommandNSCert commandnscert; + NSCertListImpl::ExtensibleItem certs; + + public: + NSCert(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), + commandnscert(this), certs(this, "certificates") + { + if (!IRCD || !IRCD->CanCertFP) + throw ModuleException("Your IRCd does not support ssl client certificates"); + } - void DoAutoIdentify(User *u) + void OnFingerprint(User *u) anope_override { NickAlias *na = NickAlias::Find(u->nick); BotInfo *NickServ = Config->GetClient("NickServ"); @@ -208,29 +337,28 @@ class NSCert : public Module return; if (na->nc->HasExt("SUSPENDED")) return; - if (!na->nc->FindCert(u->fingerprint)) + + NSCertList *cl = certs.Get(na->nc); + if (!cl || !cl->FindCert(u->fingerprint)) return; u->Identify(na); u->SendMessage(NickServ, _("SSL Fingerprint accepted. You are now identified.")); - Log(u) << "automatically identified for account " << na->nc->display << " using a valid SSL fingerprint"; - return; + Log(u) << "automatically identified for account " << na->nc->display << " via SSL certificate fingerprint"; } - public: - NSCert(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandnscert(this) + EventReturn OnNickValidate(User *u, NickAlias *na) anope_override { + NSCertList *cl = certs.Get(na->nc); + if (!u->fingerprint.empty() && cl && cl->FindCert(u->fingerprint)) + { + u->Identify(na); + u->SendMessage(Config->GetClient("NickServ"), _("SSL fingerprint accepted, you are now identified.")); + Log(u) << "automatically identified for account " << na->nc->display << " via SSL fingerprint."; + return EVENT_ALLOW; + } - if (!IRCD || !IRCD->CanCertFP) - throw ModuleException("Your IRCd does not support ssl client certificates"); - - - } - - void OnFingerprint(User *u) anope_override - { - DoAutoIdentify(u); + return EVENT_CONTINUE; } }; diff --git a/modules/commands/ns_group.cpp b/modules/commands/ns_group.cpp index 989fc1385..160980bc9 100644 --- a/modules/commands/ns_group.cpp +++ b/modules/commands/ns_group.cpp @@ -10,6 +10,7 @@ */ #include "module.h" +#include "modules/ns_cert.h" class NSGroupRequest : public IdentifyRequest { @@ -43,7 +44,6 @@ class NSGroupRequest : public IdentifyRequest na->time_registered = na->last_seen = Anope::CurTime; u->Login(target->nc); - IRCD->SendLogin(u); FOREACH_MOD(OnNickGroup, (u, target)); Log(LOG_COMMAND, source, cmd) << "makes " << nick << " join group of " << target->nick << " (" << target->nc->display << ") (email: " << (!target->nc->email.empty() ? target->nc->email : "none") << ")"; @@ -141,7 +141,9 @@ class CommandNSGroup : public Command bool ok = false; if (!na && u->Account()) ok = true; - else if (!u->fingerprint.empty() && target->nc->FindCert(u->fingerprint)) + + NSCertList *cl = target->nc->GetExt<NSCertList>("certificates"); + if (!u->fingerprint.empty() && cl && cl->FindCert(u->fingerprint)) ok = true; if (ok == false && !pass.empty()) @@ -236,8 +238,6 @@ class CommandNSUngroup : public Command nc->pass = oldcore->pass; if (!oldcore->email.empty()) nc->email = oldcore->email; - if (!oldcore->greet.empty()) - nc->greet = oldcore->greet; nc->language = oldcore->language; source.Reply(_("Nick %s has been ungrouped from %s."), na->nick.c_str(), oldcore->display.c_str()); @@ -303,7 +303,7 @@ class CommandNSGList : public Command ListFormatter::ListEntry entry; entry["Nick"] = na2->nick; - entry["Expires"] = (na2->HasExt("NO_EXPIRE") || !nickserv_expire || Anope::NoExpire) ? "Does not expire" : ("expires in " + Anope::strftime(na2->last_seen + nickserv_expire)); + entry["Expires"] = (na2->HasExt("NS_NO_EXPIRE") || !nickserv_expire || Anope::NoExpire) ? "Does not expire" : ("expires in " + Anope::strftime(na2->last_seen + nickserv_expire)); list.AddEntry(entry); } diff --git a/modules/commands/ns_info.cpp b/modules/commands/ns_info.cpp index 864136cd8..8fc5aa639 100644 --- a/modules/commands/ns_info.cpp +++ b/modules/commands/ns_info.cpp @@ -13,17 +13,6 @@ class CommandNSInfo : public Command { - private: - void CheckOptStr(NickCore *core, Anope::string &buf, const Anope::string &opt, const char *str, const Extensible *e, bool reverse_logic = false) - { - if (reverse_logic != e->HasExt(opt)) - { - if (!buf.empty()) - buf += ", "; - - buf += Language::Translate(core, str); - } - } public: CommandNSInfo(Module *creator) : Command(creator, "nickserv/info", 0, 2) { @@ -105,34 +94,6 @@ class CommandNSInfo : public Command else info[_("VHost")] = na->GetVhostHost(); } - - if (!na->nc->greet.empty()) - info[_("Greet")] = na->nc->greet; - - Anope::string optbuf; - - CheckOptStr(source.nc, optbuf, "KILLPROTECT", _("Protection"), na->nc); - CheckOptStr(source.nc, optbuf, "SECURE", _("Security"), na->nc); - CheckOptStr(source.nc, optbuf, "PRIVATE", _("Private"), na->nc); - CheckOptStr(source.nc, optbuf, "MSG", _("Message mode"), na->nc); - CheckOptStr(source.nc, optbuf, "AUTOOP", _("Auto-op"), na->nc); - CheckOptStr(source.nc, optbuf, "SUSPENDED", _("Suspended"), na->nc); - CheckOptStr(source.nc, optbuf, "STATS", _("Chanstats"), na->nc); - CheckOptStr(source.nc, optbuf, "NO_EXPIRE", _("No expire"), na); - - info[_("Options")] = optbuf.empty() ? _("None") : optbuf; - - if (na->nc->HasExt("UNCONFIRMED") == false) - { - time_t nickserv_expire = Config->GetModule("nickserv")->Get<time_t>("expire"); - if (!na->HasExt("NO_EXPIRE") && nickserv_expire && !Anope::NoExpire) - info[_("Expires")] = Anope::strftime(na->last_seen + nickserv_expire); - } - else - { - time_t unconfirmed_expire = Config->GetModule("nickserv")->Get<time_t>("unconfirmedexpire", "1d"); - info[_("Expires")] = Anope::strftime(na->time_registered + unconfirmed_expire); - } } FOREACH_MOD(OnNickInfo, (source, na, info, show_hidden)); @@ -159,13 +120,142 @@ class CommandNSInfo : public Command } }; + +class CommandNSSetHide : public Command +{ + public: + CommandNSSetHide(Module *creator, const Anope::string &sname = "nickserv/set/hide", size_t min = 2) : Command(creator, sname, min, min + 1) + { + this->SetDesc(_("Hide certain pieces of nickname information")); + this->SetSyntax(_("{EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}")); + } + + void Run(CommandSource &source, const Anope::string &user, const Anope::string ¶m, const Anope::string &arg) + { + const NickAlias *na = NickAlias::Find(user); + if (!na) + { + source.Reply(NICK_X_NOT_REGISTERED, user.c_str()); + return; + } + NickCore *nc = na->nc; + + EventReturn MOD_RESULT; + FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param)); + if (MOD_RESULT == EVENT_STOP) + return; + + Anope::string onmsg, offmsg, flag; + + if (param.equals_ci("EMAIL")) + { + flag = "HIDE_EMAIL"; + onmsg = _("The E-mail address of \002%s\002 will now be hidden from %s INFO displays."); + offmsg = _("The E-mail address of \002%s\002 will now be shown in %s INFO displays."); + } + else if (param.equals_ci("USERMASK")) + { + flag = "HIDE_MASK"; + onmsg = _("The last seen user@host mask of \002%s\002 will now be hidden from %s INFO displays."); + offmsg = _("The last seen user@host mask of \002%s\002 will now be shown in %s INFO displays."); + } + else if (param.equals_ci("STATUS")) + { + flag = "HIDE_STATUS"; + onmsg = _("The services access status of \002%s\002 will now be hidden from %s INFO displays."); + offmsg = _("The services access status of \002%s\002 will now be shown in %s INFO displays."); + } + else if (param.equals_ci("QUIT")) + { + flag = "HIDE_QUIT"; + onmsg = _("The last quit message of \002%s\002 will now be hidden from %s INFO displays."); + offmsg = _("The last quit message of \002%s\002 will now be shown in %s INFO displays."); + } + else + { + this->OnSyntaxError(source, "HIDE"); + return; + } + + if (arg.equals_ci("ON")) + { + Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change hide " << param << " to " << arg << " for " << nc->display; + nc->Extend<bool>(flag); + source.Reply(onmsg.c_str(), nc->display.c_str(), source.service->nick.c_str()); + } + else if (arg.equals_ci("OFF")) + { + Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change hide " << param << " to " << arg << " for " << nc->display; + nc->Shrink<bool>(flag); + source.Reply(offmsg.c_str(), nc->display.c_str(), source.service->nick.c_str()); + } + else + this->OnSyntaxError(source, "HIDE"); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + this->Run(source, source.nc->display, params[0], params[1]); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Allows you to prevent certain pieces of information from\n" + "being displayed when someone does a %s \002INFO\002 on your\n" + "nick. You can hide your E-mail address (\002EMAIL\002), last seen\n" + "user@host mask (\002USERMASK\002), your services access status\n" + "(\002STATUS\002) and last quit message (\002QUIT\002).\n" + "The second parameter specifies whether the information should\n" + "be displayed (\002OFF\002) or hidden (\002ON\002)."), source.service->nick.c_str()); + return true; + } +}; + +class CommandNSSASetHide : public CommandNSSetHide +{ + public: + CommandNSSASetHide(Module *creator) : CommandNSSetHide(creator, "nickserv/saset/hide", 3) + { + this->SetSyntax("\037nickname\037 {EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}"); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + this->ClearSyntax(); + this->Run(source, params[0], params[1], params[2]); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Allows you to prevent certain pieces of information from\n" + "being displayed when someone does a %s \002INFO\002 on the\n" + "nick. You can hide the E-mail address (\002EMAIL\002), last seen\n" + "user@host mask (\002USERMASK\002), the services access status\n" + "(\002STATUS\002) and last quit message (\002QUIT\002).\n" + "The second parameter specifies whether the information should\n" + "be displayed (\002OFF\002) or hidden (\002ON\002)."), source.service->nick.c_str()); + return true; + } +}; + class NSInfo : public Module { CommandNSInfo commandnsinfo; + CommandNSSetHide commandnssethide; + CommandNSSASetHide commandnssasethide; + + SerializableExtensibleItem<bool> hide_email, hide_usermask, hide_status, hide_quit; + public: NSInfo(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandnsinfo(this) + commandnsinfo(this), commandnssethide(this), commandnssasethide(this), + hide_email(this, "HIDE_EMAIL"), hide_usermask(this, "HIDE_MASK"), hide_status(this, "HIDE_STATUS"), + hide_quit(this, "HIDE_QUIT") { } diff --git a/modules/commands/ns_list.cpp b/modules/commands/ns_list.cpp index a4e73e857..b1ab19971 100644 --- a/modules/commands/ns_list.cpp +++ b/modules/commands/ns_list.cpp @@ -83,9 +83,9 @@ class CommandNSList : public Command const NickAlias *na = it->second; /* Don't show private nicks to non-services admins. */ - if (na->nc->HasExt("PRIVATE") && !is_servadmin && na->nc != mync) + if (na->nc->HasExt("NS_PRIVATE") && !is_servadmin && na->nc != mync) continue; - else if (nsnoexpire && !na->HasExt("NO_EXPIRE")) + else if (nsnoexpire && !na->HasExt("NS_NO_EXPIRE")) continue; else if (suspended && !na->nc->HasExt("SUSPENDED")) continue; @@ -101,7 +101,7 @@ class CommandNSList : public Command if (((count + 1 >= from && count + 1 <= to) || (!from && !to)) && ++nnicks <= listmax) { bool isnoexpire = false; - if (is_servadmin && na->HasExt("NO_EXPIRE")) + if (is_servadmin && na->HasExt("NS_NO_EXPIRE")) isnoexpire = true; ListFormatter::ListEntry entry; @@ -177,14 +177,118 @@ class CommandNSList : public Command } }; + +class CommandNSSetPrivate : public Command +{ + public: + CommandNSSetPrivate(Module *creator, const Anope::string &sname = "nickserv/set/private", size_t min = 1) : Command(creator, sname, min, min + 1) + { + this->SetDesc(_("Prevent the nickname from appearing in the LIST command")); + this->SetSyntax(_("{ON | OFF}")); + } + + void Run(CommandSource &source, const Anope::string &user, const Anope::string ¶m) + { + const NickAlias *na = NickAlias::Find(user); + if (!na) + { + source.Reply(NICK_X_NOT_REGISTERED, user.c_str()); + return; + } + NickCore *nc = na->nc; + + EventReturn MOD_RESULT; + FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param)); + if (MOD_RESULT == EVENT_STOP) + return; + + if (param.equals_ci("ON")) + { + Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable private for " << nc->display; + nc->Extend<bool>("NS_PRIVATE"); + source.Reply(_("Private option is now \002on\002 for \002%s\002."), nc->display.c_str()); + } + else if (param.equals_ci("OFF")) + { + Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable private for " << nc->display; + nc->Shrink<bool>("NS_PRIVATE"); + source.Reply(_("Private option is now \002off\002 for \002%s\002."), nc->display.c_str()); + } + else + this->OnSyntaxError(source, "PRIVATE"); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + this->Run(source, source.nc->display, params[0]); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Turns %s's privacy option on or off for your nick.\n" + "With \002PRIVATE\002 set, your nickname will not appear in\n" + "nickname lists generated with %s's \002LIST\002 command.\n" + "(However, anyone who knows your nickname can still get\n" + "information on it using the \002INFO\002 command.)"), + source.service->nick.c_str(), source.service->nick.c_str()); + return true; + } +}; + +class CommandNSSASetPrivate : public CommandNSSetPrivate +{ + public: + CommandNSSASetPrivate(Module *creator) : CommandNSSetPrivate(creator, "nickserv/saset/private", 2) + { + this->ClearSyntax(); + this->SetSyntax(_("\037nickname\037 {ON | OFF}")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + this->Run(source, params[0], params[1]); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Turns %s's privacy option on or off for the nick.\n" + "With \002PRIVATE\002 set, the nickname will not appear in\n" + "nickname lists generated with %s's \002LIST\002 command.\n" + "(However, anyone who knows the nickname can still get\n" + "information on it using the \002INFO\002 command.)"), + source.service->nick.c_str(), source.service->nick.c_str()); + return true; + } +}; + + class NSList : public Module { CommandNSList commandnslist; + CommandNSSetPrivate commandnssetprivate; + CommandNSSASetPrivate commandnssasetprivate; + + SerializableExtensibleItem<bool> priv; + public: NSList(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandnslist(this) + commandnslist(this), commandnssetprivate(this), commandnssasetprivate(this), + priv(this, "NS_PRIVATE") + { + } + + void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_all) anope_override { + if (!show_all) + return; + + if (priv.HasExt(na->nc)) + info.AddOption(_("Private")); } }; diff --git a/modules/commands/ns_recover.cpp b/modules/commands/ns_recover.cpp index 224b4e2ed..48c625ace 100644 --- a/modules/commands/ns_recover.cpp +++ b/modules/commands/ns_recover.cpp @@ -10,10 +10,11 @@ */ #include "module.h" +#include "modules/ns_cert.h" static ServiceReference<NickServService> nickserv("NickServService", "NickServ"); -struct NSRecoverExtensibleInfo : ExtensibleItem, std::map<Anope::string, ChannelStatus> { }; +typedef std::map<Anope::string, ChannelStatus> NSRecoverInfo; class NSRecoverRequest : public IdentifyRequest { @@ -50,7 +51,7 @@ class NSRecoverRequest : public IdentifyRequest // same person that is executing the command, so kill them off (old GHOST command). else if (u->Account() == na->nc) { - if (!source.GetAccount() && na->nc->HasExt("SECURE")) + if (!source.GetAccount() && na->nc->HasExt("NS_SECURE")) { source.GetUser()->Login(u->Account()); Log(LOG_COMMAND, source, cmd) << "and was automatically identified to " << u->Account()->display; @@ -60,11 +61,9 @@ class NSRecoverRequest : public IdentifyRequest { if (!u->chans.empty()) { - NSRecoverExtensibleInfo *ei = new NSRecoverExtensibleInfo; + NSRecoverInfo *ei = source.GetUser()->Extend<NSRecoverInfo>("recover"); for (User::ChanUserList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it) (*ei)[it->first->name] = it->second->status; - - source.GetUser()->Extend("ns_recover_info", ei); } } @@ -83,7 +82,7 @@ class NSRecoverRequest : public IdentifyRequest /* User is not identified or not identified to the same account as the person using this command */ else { - if (!source.GetAccount() && na->nc->HasExt("SECURE")) + if (!source.GetAccount() && na->nc->HasExt("NS_SECURE")) { source.GetUser()->Login(na->nc); // Identify the user using the command if they arent identified Log(LOG_COMMAND, source, cmd) << "and was automatically identified to " << na->nick << " (" << na->nc->display << ")"; @@ -161,9 +160,11 @@ class CommandNSRecover : public Command bool ok = false; if (source.GetAccount() == na->nc) ok = true; - else if (!na->nc->HasExt("SECURE") && source.GetUser() && na->nc->IsOnAccess(source.GetUser())) + else if (!na->nc->HasExt("NS_SECURE") && source.GetUser() && na->nc->IsOnAccess(source.GetUser())) ok = true; - else if (source.GetUser() && !source.GetUser()->fingerprint.empty() && na->nc->FindCert(source.GetUser()->fingerprint)) + + NSCertList *cl = na->nc->GetExt<NSCertList>("certificates"); + if (source.GetUser() && !source.GetUser()->fingerprint.empty() && cl && cl->FindCert(source.GetUser()->fingerprint)) ok = true; if (ok == false && !pass.empty()) @@ -200,10 +201,11 @@ class CommandNSRecover : public Command class NSRecover : public Module { CommandNSRecover commandnsrecover; + PrimitiveExtensibleItem<NSRecoverInfo> recover; public: NSRecover(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandnsrecover(this) + commandnsrecover(this), recover(this, "recover") { if (Config->GetBlock("options")->Get<bool>("nonicknameownership")) @@ -211,34 +213,15 @@ class NSRecover : public Module } - ~NSRecover() - { - for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) - it->second->Shrink("ns_recover_info"); - - OnShutdown(); - } - - void OnShutdown() anope_override - { - /* On shutdown, restart, or mod unload, remove all of our holds for nicks (svshold or qlines) - * because some IRCds do not allow us to have these automatically expire - */ - for (nickalias_map::const_iterator it = NickAliasList->begin(); it != NickAliasList->end(); ++it) - nickserv->Release(it->second); - } - - void OnRestart() anope_override { OnShutdown(); } - void OnUserNickChange(User *u, const Anope::string &oldnick) anope_override { if (Config->GetModule(this)->Get<bool>("restoreonrecover")) { - NSRecoverExtensibleInfo *ei = u->GetExt<NSRecoverExtensibleInfo *>("ns_recover_info"); + NSRecoverInfo *ei = recover.Get(u); BotInfo *NickServ = Config->GetClient("NickServ"); if (ei != NULL && NickServ != NULL) - for (std::map<Anope::string, ChannelStatus>::iterator it = ei->begin(), it_end = ei->end(); it != it_end;) + for (NSRecoverInfo::iterator it = ei->begin(), it_end = ei->end(); it != it_end;) { Channel *c = Channel::Find(it->first); const Anope::string &cname = it->first; @@ -257,11 +240,11 @@ class NSRecover : public Module { if (Config->GetModule(this)->Get<bool>("restoreonrecover")) { - NSRecoverExtensibleInfo *ei = u->GetExt<NSRecoverExtensibleInfo *>("ns_recover_info"); + NSRecoverInfo *ei = recover.Get(u); if (ei != NULL) { - std::map<Anope::string, ChannelStatus>::iterator it = ei->find(c->name); + NSRecoverInfo::iterator it = ei->find(c->name); if (it != ei->end()) { for (size_t i = 0; i < it->second.Modes().length(); ++i) @@ -269,7 +252,7 @@ class NSRecover : public Module ei->erase(it); if (ei->empty()) - u->Shrink("ns_recover_info"); + recover.Unset(u); } } } diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp index 4064ce924..e8adec549 100644 --- a/modules/commands/ns_register.cpp +++ b/modules/commands/ns_register.cpp @@ -36,27 +36,27 @@ class CommandNSConfirm : public Command source.Reply(_("Nick \002%s\002 is already confirmed."), na->nick.c_str()); else { - na->nc->Shrink("UNCONFIRMED"); + na->nc->Shrink<bool>("UNCONFIRMED"); Log(LOG_ADMIN, source, this) << "to confirm nick " << na->nick << " (" << na->nc->display << ")"; source.Reply(_("Nick \002%s\002 has been confirmed."), na->nick.c_str()); } } else if (source.nc) { - Anope::string *code = source.nc->GetExt<ExtensibleItemClass<Anope::string> *>("ns_register_passcode"); + Anope::string *code = source.nc->GetExt<Anope::string>("passcode"); if (code != NULL && *code == passcode) { NickCore *nc = source.nc; - nc->Shrink("ns_register_passcode"); + nc->Shrink<Anope::string>("passcode"); Log(LOG_COMMAND, source, this) << "to confirm their email"; source.Reply(_("Your email address of \002%s\002 has been confirmed."), source.nc->email.c_str()); - nc->Shrink("UNCONFIRMED"); + nc->Shrink<bool>("UNCONFIRMED"); if (source.GetUser()) { IRCD->SendLogin(source.GetUser()); const NickAlias *na = NickAlias::Find(source.GetNick()); - if (!Config->GetBlock("options")->Get<bool>("nonicknameownership") && na != NULL && na->nc == source.GetAccount() && na->nc->HasExt("UNCONFIRMED") == false) + if (!Config->GetBlock("options")->Get<bool>("nonicknameownership") && na != NULL && na->nc == source.GetAccount() && !na->nc->HasExt("UNCONFIRMED")) source.GetUser()->SetMode(source.service, "REGISTERED"); } } @@ -207,12 +207,12 @@ class CommandNSRegister : public Command if (nsregister.equals_ci("admin")) { - nc->ExtendMetadata("UNCONFIRMED"); + nc->Extend<bool>("UNCONFIRMED"); source.Reply(_("All new accounts must be validated by an administrator. Please wait for your registration to be confirmed.")); } else if (nsregister.equals_ci("mail")) { - nc->ExtendMetadata("UNCONFIRMED"); + nc->Extend<bool>("UNCONFIRMED"); if (SendRegmail(u, na, source.service)) { time_t unconfirmed_expire = Config->GetModule("nickserv")->Get<time_t>("unconfirmedexpire", "1d"); @@ -292,7 +292,7 @@ class CommandNSResend : public Command if (na == NULL) source.Reply(NICK_NOT_REGISTERED); - else if (na->nc != source.GetAccount() || source.nc->HasExt("UNCONFIRMED") == false) + else if (na->nc != source.GetAccount() || !source.nc->HasExt("UNCONFIRMED")) source.Reply(_("Your account is already confirmed.")); else { @@ -336,23 +336,55 @@ class NSRegister : public Module CommandNSConfirm commandnsconfirm; CommandNSResend commandnsrsend; + PrimitiveExtensibleItem<bool> unconfirmed; + PrimitiveExtensibleItem<Anope::string> passcode; + public: NSRegister(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandnsregister(this), commandnsconfirm(this), commandnsrsend(this) + commandnsregister(this), commandnsconfirm(this), commandnsrsend(this), unconfirmed(this, "UNCONFIRMED"), + passcode(this, "passcode") { if (Config->GetModule(this)->Get<const Anope::string>("registration").equals_ci("disable")) throw ModuleException("Module " + this->name + " will not load with registration disabled."); } + + void OnNickIdentify(User *u) anope_override + { + BotInfo *NickServ; + if (unconfirmed.HasExt(u->Account()) && (NickServ = Config->GetClient("NickServ"))) + { + const Anope::string &nsregister = Config->GetModule(this)->Get<const Anope::string>("registration"); + if (nsregister.equals_ci("admin")) + u->SendMessage(NickServ, _("All new accounts must be validated by an administrator. Please wait for your registration to be confirmed.")); + else + u->SendMessage(NickServ, _("Your email address is not confirmed. To confirm it, follow the instructions that were emailed to you when you registered.")); + const NickAlias *this_na = NickAlias::Find(u->Account()->display); + time_t time_registered = Anope::CurTime - this_na->time_registered; + time_t unconfirmed_expire = Config->GetModule(this)->Get<time_t>("unconfirmedexpire", "1d"); + if (unconfirmed_expire > time_registered) + u->SendMessage(NickServ, _("Your account will expire, if not confirmed, in %s"), Anope::Duration(unconfirmed_expire - time_registered).c_str()); + } + } + + void OnPreNickExpire(NickAlias *na, bool &expire) anope_override + { + if (unconfirmed.HasExt(na->nc)) + { + time_t unconfirmed_expire = Config->GetModule(this)->Get<time_t>("unconfirmedexpire", "1d"); + if (unconfirmed_expire && Anope::CurTime - na->time_registered >= unconfirmed_expire) + expire = true; + } + } }; static bool SendRegmail(User *u, const NickAlias *na, const BotInfo *bi) { NickCore *nc = na->nc; - Anope::string *code = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("ns_register_passcode"); - Anope::string codebuf; + Anope::string *code = na->nc->GetExt<Anope::string>("passcode"); if (code == NULL) { + code = na->nc->Extend<Anope::string>("passcode"); int chars[] = { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', @@ -362,22 +394,19 @@ static bool SendRegmail(User *u, const NickAlias *na, const BotInfo *bi) }; int idx, min = 1, max = 62; for (idx = 0; idx < 9; ++idx) - codebuf += chars[1 + static_cast<int>((static_cast<float>(max - min)) * static_cast<uint16_t>(rand()) / 65536.0) + min]; - nc->Extend("ns_register_passcode", new ExtensibleItemClass<Anope::string>(codebuf)); + *code += chars[1 + static_cast<int>((static_cast<float>(max - min)) * static_cast<uint16_t>(rand()) / 65536.0) + min]; } - else - codebuf = *code; Anope::string subject = Language::Translate(na->nc, Config->GetBlock("mail")->Get<const Anope::string>("registration_subject").c_str()), message = Language::Translate(na->nc, Config->GetBlock("mail")->Get<const Anope::string>("registration_message").c_str()); subject = subject.replace_all_cs("%n", na->nick); subject = subject.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname")); - subject = subject.replace_all_cs("%c", codebuf); + subject = subject.replace_all_cs("%c", *code); message = message.replace_all_cs("%n", na->nick); message = message.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname")); - message = message.replace_all_cs("%c", codebuf); + message = message.replace_all_cs("%c", *code); return Mail::Send(u, nc, bi, subject, message); } diff --git a/modules/commands/ns_resetpass.cpp b/modules/commands/ns_resetpass.cpp index 9b15e53ac..871864b6d 100644 --- a/modules/commands/ns_resetpass.cpp +++ b/modules/commands/ns_resetpass.cpp @@ -53,7 +53,7 @@ class CommandNSResetPass : public Command } }; -struct ResetInfo : ExtensibleItem +struct ResetInfo { Anope::string code; time_t time; @@ -62,21 +62,14 @@ struct ResetInfo : ExtensibleItem class NSResetPass : public Module { CommandNSResetPass commandnsresetpass; + PrimitiveExtensibleItem<ResetInfo> reset; public: NSResetPass(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandnsresetpass(this) + commandnsresetpass(this), reset(this, "reset") { if (!Config->GetBlock("mail")->Get<bool>("usemail")) throw ModuleException("Not using mail."); - - - } - - ~NSResetPass() - { - for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it) - it->second->Shrink("ns_resetpass"); } EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> ¶ms) anope_override @@ -85,24 +78,23 @@ class NSResetPass : public Module { NickAlias *na = NickAlias::Find(params[0]); - ResetInfo *ri = na ? na->nc->GetExt<ResetInfo *>("ns_resetpass") : NULL; + ResetInfo *ri = na ? reset.Get(na->nc) : NULL; if (na && ri) { NickCore *nc = na->nc; const Anope::string &passcode = params[1]; if (ri->time < Anope::CurTime - 3600) { - nc->Shrink("ns_resetpass"); + reset.Unset(nc); source.Reply(_("Your password reset request has expired.")); } else if (passcode.equals_cs(ri->code)) { - nc->Shrink("ns_resetpass"); + reset.Unset(nc); + nc->Shrink<bool>("UNCONFIRMED"); Log(LOG_COMMAND, source, &commandnsresetpass) << "confirmed RESETPASS to forcefully identify as " << na->nick; - nc->Shrink("UNCONFIRMED"); - if (source.GetUser()) { source.GetUser()->Identify(na); @@ -147,13 +139,11 @@ static bool SendResetEmail(User *u, const NickAlias *na, const BotInfo *bi) message = message.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname")); message = message.replace_all_cs("%c", passcode); - ResetInfo *ri = new ResetInfo; + ResetInfo *ri = na->nc->Extend<ResetInfo>("reset"); ri->code = passcode; ri->time = Anope::CurTime; - NickCore *nc = na->nc; - nc->Extend("ns_resetpass", ri); - return Mail::Send(u, nc, bi, subject, message); + return Mail::Send(u, na->nc, bi, subject, message); } MODULE_INIT(NSResetPass) diff --git a/modules/commands/ns_set.cpp b/modules/commands/ns_set.cpp index 7b0de5565..08cf3966a 100644 --- a/modules/commands/ns_set.cpp +++ b/modules/commands/ns_set.cpp @@ -191,8 +191,6 @@ class CommandNSSASetPassword : public Command source.Reply(_("Password for \002%s\002 changed to \002%s\002."), nc->display.c_str(), tmp_pass.c_str()); else source.Reply(_("Password for \002%s\002 changed."), nc->display.c_str()); - - return; } bool OnHelp(CommandSource &source, const Anope::string &) anope_override @@ -231,13 +229,13 @@ class CommandNSSetAutoOp : public Command if (param.equals_ci("ON")) { Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable autoop for " << na->nc->display; - nc->ExtendMetadata("AUTOOP"); + nc->Extend<bool>("AUTOOP"); source.Reply(_("Services will from now on set status modes on %s in channels."), nc->display.c_str()); } else if (param.equals_ci("OFF")) { Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable autoop for " << na->nc->display; - nc->Shrink("AUTOOP"); + nc->Shrink<bool>("AUTOOP"); source.Reply(_("Services will no longer set status modes on %s in channels."), nc->display.c_str()); } else @@ -313,19 +311,17 @@ class CommandNSSetChanstats : public Command if (param.equals_ci("ON")) { Log(na->nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable chanstats for " << na->nc->display; - na->nc->ExtendMetadata("STATS"); + na->nc->Extend<bool>("NS_STATS"); source.Reply(_("Chanstat statistics are now enabled for your nick.")); } else if (param.equals_ci("OFF")) { Log(na->nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable chanstats for " << na->nc->display; - na->nc->Shrink("STATS"); + na->nc->Shrink<bool>("NS_STATS"); source.Reply(_("Chanstat statistics are now disabled for your nick.")); } else this->OnSyntaxError(source, "CHANSTATS"); - - return; } void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override @@ -446,7 +442,7 @@ class CommandNSSASetDisplay : public CommandNSSetDisplay class CommandNSSetEmail : public Command { - static bool SendConfirmMail(User *u, const BotInfo *bi) + static bool SendConfirmMail(User *u, const BotInfo *bi, const Anope::string &new_email) { int chars[] = { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', @@ -460,7 +456,9 @@ class CommandNSSetEmail : public Command for (idx = 0; idx < 9; ++idx) code += chars[1 + static_cast<int>((static_cast<float>(max - min)) * static_cast<uint16_t>(rand()) / 65536.0) + min]; - u->Account()->Extend("ns_set_email_passcode", new ExtensibleItemClass<Anope::string>(code)); + std::pair<Anope::string, Anope::string> *n = u->Account()->Extend<std::pair<Anope::string, Anope::string> >("ns_set_email"); + n->first = new_email; + n->second = code; Anope::string subject = Config->GetBlock("mail")->Get<const Anope::string>("emailchange_subject"), message = Config->GetBlock("mail")->Get<const Anope::string>("emailchange_message"); @@ -473,7 +471,11 @@ class CommandNSSetEmail : public Command message = message.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname")); message = message.replace_all_cs("%c", code); - return Mail::Send(u, u->Account(), bi, subject, message); + Anope::string old = u->Account()->email; + u->Account()->email = new_email; + bool b = Mail::Send(u, u->Account(), bi, subject, message); + u->Account()->email = old; + return b; } public: @@ -516,12 +518,8 @@ class CommandNSSetEmail : public Command if (!param.empty() && Config->GetModule("nickserv")->Get<bool>("forceemail", "yes") && !source.IsServicesOper()) { - source.nc->Extend("ns_set_email", new ExtensibleItemClass<Anope::string>(param)); - Anope::string old = source.nc->email; - source.nc->email = param; - if (SendConfirmMail(source.GetUser(), source.service)) + if (SendConfirmMail(source.GetUser(), source.service, param)) source.Reply(_("A confirmation e-mail has been sent to \002%s\002. Follow the instructions in it to change your e-mail address."), param.c_str()); - source.nc->email = old; } else { @@ -579,212 +577,6 @@ class CommandNSSASetEmail : public CommandNSSetEmail } }; -class CommandNSSetGreet : public Command -{ - public: - CommandNSSetGreet(Module *creator, const Anope::string &sname = "nickserv/set/greet", size_t min = 0) : Command(creator, sname, min, min + 1) - { - this->SetDesc(_("Associate a greet message with your nickname")); - this->SetSyntax(_("\037message\037")); - } - - void Run(CommandSource &source, const Anope::string &user, const Anope::string ¶m) - { - const NickAlias *na = NickAlias::Find(user); - if (!na) - { - source.Reply(NICK_X_NOT_REGISTERED, user.c_str()); - return; - } - NickCore *nc = na->nc; - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param)); - if (MOD_RESULT == EVENT_STOP) - return; - - if (!param.empty()) - { - Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change the greet of " << nc->display; - nc->greet = param; - source.Reply(_("Greet message for \002%s\002 changed to \002%s\002."), nc->display.c_str(), nc->greet.c_str()); - } - else - { - Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to unset the greet of " << nc->display; - nc->greet.clear(); - source.Reply(_("Greet message for \002%s\002 unset."), nc->display.c_str()); - } - - return; - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - this->Run(source, source.nc->display, params.size() > 0 ? params[0] : ""); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Makes the given message the greet of your nickname, that\n" - "will be displayed when joining a channel that has GREET\n" - "option enabled, provided that you have the necessary\n" - "access on it.")); - return true; - } -}; - -class CommandNSSASetGreet : public CommandNSSetGreet -{ - public: - CommandNSSASetGreet(Module *creator) : CommandNSSetGreet(creator, "nickserv/saset/greet", 1) - { - this->ClearSyntax(); - this->SetSyntax(_("\037nickname\037 \037message\037")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - this->Run(source, params[0], params.size() > 1 ? params[1] : ""); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Makes the given message the greet of the nickname, that\n" - "will be displayed when joining a channel that has GREET\n" - "option enabled, provided that the user has the necessary\n" - "access on it.")); - return true; - } -}; - -class CommandNSSetHide : public Command -{ - public: - CommandNSSetHide(Module *creator, const Anope::string &sname = "nickserv/set/hide", size_t min = 2) : Command(creator, sname, min, min + 1) - { - this->SetDesc(_("Hide certain pieces of nickname information")); - this->SetSyntax(_("{EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}")); - } - - void Run(CommandSource &source, const Anope::string &user, const Anope::string ¶m, const Anope::string &arg) - { - const NickAlias *na = NickAlias::Find(user); - if (!na) - { - source.Reply(NICK_X_NOT_REGISTERED, user.c_str()); - return; - } - NickCore *nc = na->nc; - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param)); - if (MOD_RESULT == EVENT_STOP) - return; - - Anope::string onmsg, offmsg, flag; - - if (param.equals_ci("EMAIL")) - { - flag = "HIDE_EMAIL"; - onmsg = _("The E-mail address of \002%s\002 will now be hidden from %s INFO displays."); - offmsg = _("The E-mail address of \002%s\002 will now be shown in %s INFO displays."); - } - else if (param.equals_ci("USERMASK")) - { - flag = "HIDE_MASK"; - onmsg = _("The last seen user@host mask of \002%s\002 will now be hidden from %s INFO displays."); - offmsg = _("The last seen user@host mask of \002%s\002 will now be shown in %s INFO displays."); - } - else if (param.equals_ci("STATUS")) - { - flag = "HIDE_STATUS"; - onmsg = _("The services access status of \002%s\002 will now be hidden from %s INFO displays."); - offmsg = _("The services access status of \002%s\002 will now be shown in %s INFO displays."); - } - else if (param.equals_ci("QUIT")) - { - flag = "HIDE_QUIT"; - onmsg = _("The last quit message of \002%s\002 will now be hidden from %s INFO displays."); - offmsg = _("The last quit message of \002%s\002 will now be shown in %s INFO displays."); - } - else - { - this->OnSyntaxError(source, "HIDE"); - return; - } - - if (arg.equals_ci("ON")) - { - Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change hide " << param << " to " << arg << " for " << nc->display; - nc->ExtendMetadata(flag); - source.Reply(onmsg.c_str(), nc->display.c_str(), source.service->nick.c_str()); - } - else if (arg.equals_ci("OFF")) - { - Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change hide " << param << " to " << arg << " for " << nc->display; - nc->Shrink(flag); - source.Reply(offmsg.c_str(), nc->display.c_str(), source.service->nick.c_str()); - } - else - this->OnSyntaxError(source, "HIDE"); - - return; - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - this->Run(source, source.nc->display, params[0], params[1]); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Allows you to prevent certain pieces of information from\n" - "being displayed when someone does a %s \002INFO\002 on your\n" - "nick. You can hide your E-mail address (\002EMAIL\002), last seen\n" - "user@host mask (\002USERMASK\002), your services access status\n" - "(\002STATUS\002) and last quit message (\002QUIT\002).\n" - "The second parameter specifies whether the information should\n" - "be displayed (\002OFF\002) or hidden (\002ON\002)."), source.service->nick.c_str()); - return true; - } -}; - -class CommandNSSASetHide : public CommandNSSetHide -{ - public: - CommandNSSASetHide(Module *creator) : CommandNSSetHide(creator, "nickserv/saset/hide", 3) - { - this->SetSyntax("\037nickname\037 {EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}"); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - this->ClearSyntax(); - this->Run(source, params[0], params[1], params[2]); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Allows you to prevent certain pieces of information from\n" - "being displayed when someone does a %s \002INFO\002 on the\n" - "nick. You can hide the E-mail address (\002EMAIL\002), last seen\n" - "user@host mask (\002USERMASK\002), the services access status\n" - "(\002STATUS\002) and last quit message (\002QUIT\002).\n" - "The second parameter specifies whether the information should\n" - "be displayed (\002OFF\002) or hidden (\002ON\002)."), source.service->nick.c_str()); - return true; - } -}; - class CommandNSSetKill : public Command { public: @@ -817,17 +609,17 @@ class CommandNSSetKill : public Command if (param.equals_ci("ON")) { - nc->ExtendMetadata("KILLPROTECT"); - nc->Shrink("KILL_QUICK"); - nc->Shrink("KILL_IMMED"); + nc->Extend<bool>("KILLPROTECT"); + nc->Shrink<bool>("KILL_QUICK"); + nc->Shrink<bool>("KILL_IMMED"); Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill on for " << nc->display; source.Reply(_("Protection is now \002on\002 for \002%s\002."), nc->display.c_str()); } else if (param.equals_ci("QUICK")) { - nc->ExtendMetadata("KILLPROTECT"); - nc->ExtendMetadata("KILL_QUICK"); - nc->Shrink("KILL_IMMED"); + nc->Extend<bool>("KILLPROTECT"); + nc->Extend<bool>("KILL_QUICK"); + nc->Shrink<bool>("KILL_IMMED"); Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill quick for " << nc->display; source.Reply(_("Protection is now \002on\002 for \002%s\002, with a reduced delay."), nc->display.c_str()); } @@ -835,9 +627,9 @@ class CommandNSSetKill : public Command { if (Config->GetModule(this->owner)->Get<bool>("allowkillimmed")) { - nc->ExtendMetadata("KILLPROTECT"); - nc->ExtendMetadata("KILL_IMMED"); - nc->Shrink("KILL_QUICK"); + nc->Extend<bool>("KILLPROTECT"); + nc->Shrink<bool>("KILL_QUICK"); + nc->Extend<bool>("KILL_IMMED"); Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill immed for " << nc->display; source.Reply(_("Protection is now \002on\002 for \002%s\002, with no delay."), nc->display.c_str()); } @@ -846,9 +638,9 @@ class CommandNSSetKill : public Command } else if (param.equals_ci("OFF")) { - nc->Shrink("KILLPROTECT"); - nc->Shrink("KILL_QUICK"); - nc->Shrink("KILL_IMMED"); + nc->Shrink<bool>("KILLPROTECT"); + nc->Shrink<bool>("KILL_QUICK"); + nc->Shrink<bool>("KILL_IMMED"); Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable kill for " << nc->display; source.Reply(_("Protection is now \002off\002 for \002%s\002."), nc->display.c_str()); } @@ -1053,19 +845,17 @@ class CommandNSSetMessage : public Command if (param.equals_ci("ON")) { Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable " << source.command << " for " << nc->display; - nc->ExtendMetadata("MSG"); + nc->Extend<bool>("MSG"); source.Reply(_("Services will now reply to \002%s\002 with \002messages\002."), nc->display.c_str()); } else if (param.equals_ci("OFF")) { Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable " << source.command << " for " << nc->display; - nc->Shrink("MSG"); + nc->Shrink<bool>("MSG"); source.Reply(_("Services will now reply to \002%s\002 with \002notices\002."), nc->display.c_str()); } else this->OnSyntaxError(source, "MSG"); - - return; } void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override @@ -1115,95 +905,6 @@ class CommandNSSASetMessage : public CommandNSSetMessage } }; -class CommandNSSetPrivate : public Command -{ - public: - CommandNSSetPrivate(Module *creator, const Anope::string &sname = "nickserv/set/private", size_t min = 1) : Command(creator, sname, min, min + 1) - { - this->SetDesc(_("Prevent the nickname from appearing in the LIST command")); - this->SetSyntax(_("{ON | OFF}")); - } - - void Run(CommandSource &source, const Anope::string &user, const Anope::string ¶m) - { - const NickAlias *na = NickAlias::Find(user); - if (!na) - { - source.Reply(NICK_X_NOT_REGISTERED, user.c_str()); - return; - } - NickCore *nc = na->nc; - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param)); - if (MOD_RESULT == EVENT_STOP) - return; - - if (param.equals_ci("ON")) - { - Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable private for " << nc->display; - nc->ExtendMetadata("PRIVATE"); - source.Reply(_("Private option is now \002on\002 for \002%s\002."), nc->display.c_str()); - } - else if (param.equals_ci("OFF")) - { - Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable private for " << nc->display; - nc->Shrink("PRIVATE"); - source.Reply(_("Private option is now \002off\002 for \002%s\002."), nc->display.c_str()); - } - else - this->OnSyntaxError(source, "PRIVATE"); - - return; - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - this->Run(source, source.nc->display, params[0]); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Turns %s's privacy option on or off for your nick.\n" - "With \002PRIVATE\002 set, your nickname will not appear in\n" - "nickname lists generated with %s's \002LIST\002 command.\n" - "(However, anyone who knows your nickname can still get\n" - "information on it using the \002INFO\002 command.)"), - source.service->nick.c_str(), source.service->nick.c_str()); - return true; - } -}; - -class CommandNSSASetPrivate : public CommandNSSetPrivate -{ - public: - CommandNSSASetPrivate(Module *creator) : CommandNSSetPrivate(creator, "nickserv/saset/private", 2) - { - this->ClearSyntax(); - this->SetSyntax(_("\037nickname\037 {ON | OFF}")); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override - { - this->Run(source, params[0], params[1]); - } - - bool OnHelp(CommandSource &source, const Anope::string &) anope_override - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Turns %s's privacy option on or off for the nick.\n" - "With \002PRIVATE\002 set, the nickname will not appear in\n" - "nickname lists generated with %s's \002LIST\002 command.\n" - "(However, anyone who knows the nickname can still get\n" - "information on it using the \002INFO\002 command.)"), - source.service->nick.c_str(), source.service->nick.c_str()); - return true; - } -}; - class CommandNSSetSecure : public Command { public: @@ -1231,13 +932,13 @@ class CommandNSSetSecure : public Command if (param.equals_ci("ON")) { Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable secure for " << nc->display; - nc->ExtendMetadata("SECURE"); + nc->Extend<bool>("NS_SECURE"); source.Reply(_("Secure option is now \002on\002 for \002%s\002."), nc->display.c_str()); } else if (param.equals_ci("OFF")) { Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable secure for " << nc->display; - nc->Shrink("SECURE"); + nc->Shrink<bool>("NS_SECURE"); source.Reply(_("Secure option is now \002off\002 for \002%s\002."), nc->display.c_str()); } else @@ -1316,13 +1017,13 @@ class CommandNSSASetNoexpire : public Command if (param.equals_ci("ON")) { Log(LOG_ADMIN, source, this) << "to enable noexpire " << na->nc->display; - na->ExtendMetadata("NO_EXPIRE"); + na->Extend<bool>("NS_NO_EXPIRE"); source.Reply(_("Nick %s \002will not\002 expire."), na->nick.c_str()); } else if (param.equals_ci("OFF")) { Log(LOG_ADMIN, source, this) << "to disable noexpire " << na->nc->display; - na->Shrink("NO_EXPIRE"); + na->Shrink<bool>("NS_NO_EXPIRE"); source.Reply(_("Nick %s \002will\002 expire."), na->nick.c_str()); } else @@ -1355,12 +1056,6 @@ class NSSet : public Module CommandNSSetEmail commandnssetemail; CommandNSSASetEmail commandnssasetemail; - - CommandNSSetGreet commandnssetgreet; - CommandNSSASetGreet commandnssasetgreet; - - CommandNSSetHide commandnssethide; - CommandNSSASetHide commandnssasethide; CommandNSSetKill commandnssetkill; CommandNSSASetKill commandnssasetkill; @@ -1374,14 +1069,17 @@ class NSSet : public Module CommandNSSetPassword commandnssetpassword; CommandNSSASetPassword commandnssasetpassword; - CommandNSSetPrivate commandnssetprivate; - CommandNSSASetPrivate commandnssasetprivate; - CommandNSSetSecure commandnssetsecure; CommandNSSASetSecure commandnssasetsecure; CommandNSSASetNoexpire commandnssasetnoexpire; + SerializableExtensibleItem<bool> autoop, chanstats, killprotect, kill_quick, kill_immed, + message, secure, noexpire; + + /* email, passcode */ + PrimitiveExtensibleItem<std::pair<Anope::string, Anope::string > > ns_set_email; + public: NSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandnsset(this), commandnssaset(this), @@ -1389,15 +1087,18 @@ class NSSet : public Module commandnssetchanstats(this), commandnssasetchanstats(this), commandnssetdisplay(this), commandnssasetdisplay(this), commandnssetemail(this), commandnssasetemail(this), - commandnssetgreet(this), commandnssasetgreet(this), - commandnssethide(this), commandnssasethide(this), commandnssetkill(this), commandnssasetkill(this), commandnssetlanguage(this), commandnssasetlanguage(this), commandnssetmessage(this), commandnssasetmessage(this), commandnssetpassword(this), commandnssasetpassword(this), - commandnssetprivate(this), commandnssasetprivate(this), commandnssetsecure(this), commandnssasetsecure(this), - commandnssasetnoexpire(this) + commandnssasetnoexpire(this), + + autoop(this, "AUTOOP"), chanstats(this, "NS_STATS"), killprotect(this, "KILLPROTECT"), + kill_quick(this, "KILL_QUICK"), kill_immed(this, "KILL_IMMED"), message(this, "MSG"), + secure(this, "NS_SECURE"), noexpire(this, "NS_NO_EXPIRE"), + + ns_set_email(this, "ns_set_email") { } @@ -1408,16 +1109,15 @@ class NSSet : public Module if (command->name == "nickserv/confirm" && !params.empty() && uac) { - Anope::string *new_email = uac->GetExt<ExtensibleItemClass<Anope::string> *>("ns_set_email"), *passcode = uac->GetExt<ExtensibleItemClass<Anope::string> *>("ns_set_email_passcode"); - if (new_email && passcode) + std::pair<Anope::string, Anope::string> *n = ns_set_email.Get(uac); + if (n) { - if (params[0] == *passcode) + if (params[0] == n->second) { - uac->email = *new_email; + uac->email = n->first; Log(LOG_COMMAND, source, command) << "to confirm their email address change to " << uac->email; source.Reply(_("Your email address has been changed to \002%s\002."), uac->email.c_str()); - uac->Shrink("ns_set_email"); - uac->Shrink("ns_set_email_passcode"); + ns_set_email.Unset(uac); return EVENT_STOP; } } @@ -1431,9 +1131,34 @@ class NSSet : public Module if (chan->ci) { /* Only give modes if autoop is set */ - give_modes &= !user->Account() || user->Account()->HasExt("AUTOOP"); + give_modes &= !user->Account() || autoop.HasExt(user->Account()); } } + + void OnPreNickExpire(NickAlias *na, bool &expire) anope_override + { + if (noexpire.HasExt(na)) + expire = false; + } + + void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) anope_override + { + if (!show_hidden) + return; + + if (killprotect.HasExt(na->nc)) + info.AddOption(_("Protection")); + if (secure.HasExt(na->nc)) + info.AddOption(_("Security")); + if (message.HasExt(na->nc)) + info.AddOption(_("Message mode")); + if (autoop.HasExt(na->nc)) + info.AddOption(_("Auto-op")); + if (chanstats.HasExt(na->nc)) + info.AddOption(_("Chanstats")); + if (noexpire.HasExt(na->nc)) + info.AddOption(_("No expire")); + } }; MODULE_INIT(NSSet) diff --git a/modules/commands/ns_set_misc.cpp b/modules/commands/ns_set_misc.cpp index 15fb0ed33..5dfba99cb 100644 --- a/modules/commands/ns_set_misc.cpp +++ b/modules/commands/ns_set_misc.cpp @@ -11,14 +11,24 @@ #include "module.h" +static Module *me; + static std::map<Anope::string, Anope::string> descriptions; -struct NSMiscData : ExtensibleItem, Serializable +struct NSMiscData; +static Anope::map<ExtensibleItem<NSMiscData> *> items; +static ExtensibleItem<NSMiscData> *GetItem(const Anope::string &name); + +struct NSMiscData : Serializable { Serialize::Reference<NickCore> nc; Anope::string name; Anope::string data; + NSMiscData(Extensible *obj) : Serializable("NSMiscData"), nc(anope_dynamic_static_cast<NickCore *>(obj)) + { + } + NSMiscData(NickCore *ncore, const Anope::string &n, const Anope::string &d) : Serializable("NSMiscData"), nc(ncore), name(n), data(d) { } @@ -52,14 +62,27 @@ struct NSMiscData : ExtensibleItem, Serializable } else { - d = new NSMiscData(nc, sname, sdata); - nc->Extend(sname, d); + ExtensibleItem<NSMiscData> *item = GetItem(sname); + if (item) + d = item->Set(nc, NSMiscData(nc, sname, sdata)); } return d; } }; +static ExtensibleItem<NSMiscData> *GetItem(const Anope::string &name) +{ + ExtensibleItem<NSMiscData>* &it = items[name]; + if (!it) + try + { + it = new ExtensibleItem<NSMiscData>(me, name); + } + catch (const ModuleException &) { } + return it; +} + static Anope::string GetAttribute(const Anope::string &command) { size_t sp = command.rfind(' '); @@ -93,16 +116,20 @@ class CommandNSSetMisc : public Command Anope::string scommand = GetAttribute(source.command); Anope::string key = "ns_set_misc:" + scommand; - nc->Shrink(key); + ExtensibleItem<NSMiscData> *item = GetItem(key); + if (item == NULL) + return; + if (!param.empty()) { - nc->Extend(key, new NSMiscData(nc, key, param)); + item->Set(nc, NSMiscData(nc, key, param)); source.Reply(CHAN_SETTING_CHANGED, scommand.c_str(), nc->display.c_str(), param.c_str()); } else + { + item->Unset(nc); source.Reply(CHAN_SETTING_UNSET, scommand.c_str(), nc->display.c_str()); - - return; + } } void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override @@ -155,6 +182,7 @@ class NSSetMisc : public Module NSSetMisc(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), nsmiscdata_type("NSMiscData", NSMiscData::Unserialize), commandnssetmisc(this), commandnssasetmisc(this) { + me = this; } void OnReload(Configuration::Conf *conf) anope_override @@ -182,17 +210,14 @@ class NSSetMisc : public Module void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool ShowHidden) anope_override { - std::deque<Anope::string> list; - na->nc->GetExtList(list); - - for (unsigned i = 0; i < list.size(); ++i) + Anope::map<ExtensibleItem<NSMiscData> *> items; + for (Anope::map<ExtensibleItem<NSMiscData> *>::iterator it = items.begin(); it != items.end(); ++it) { - if (list[i].find("ns_set_misc:") != 0) - continue; + ExtensibleItem<NSMiscData> *e = it->second; + NSMiscData *data = e->Get(na->nc); - NSMiscData *data = na->nc->GetExt<NSMiscData *>(list[i]); - if (data) - info[list[i].substr(12).replace_all_cs("_", " ")] = data->data; + if (data != NULL) + info[e->name.substr(12).replace_all_cs("_", " ")] = data->data; } } }; diff --git a/modules/commands/ns_suspend.cpp b/modules/commands/ns_suspend.cpp index 0db7cd951..76c195a34 100644 --- a/modules/commands/ns_suspend.cpp +++ b/modules/commands/ns_suspend.cpp @@ -10,9 +10,48 @@ */ #include "module.h" +#include "modules/ns_suspend.h" static ServiceReference<NickServService> nickserv("NickServService", "NickServ"); +struct NSSuspendInfoImpl : NSSuspendInfo, Serializable +{ + NSSuspendInfoImpl(Extensible *) : Serializable("NSSuspendInfo") { } + + void Serialize(Serialize::Data &data) const anope_override + { + data["nick"] << nick; + data["by"] << by; + data["reason"] << reason; + data["time"] << when; + data["expires"] << expires; + } + + static Serializable* Unserialize(Serializable *obj, Serialize::Data &data) + { + Anope::string snick; + data["nick"] >> snick; + + NSSuspendInfoImpl *si; + if (obj) + si = anope_dynamic_static_cast<NSSuspendInfoImpl *>(obj); + else + { + NickAlias *na = NickAlias::Find(snick); + if (!na) + return NULL; + si = na->Extend<NSSuspendInfoImpl>("SUSPENDED"); + data["nick"] >> si->nick; + } + + data["bi"] >> si->by; + data["reason"] >> si->reason; + data["time"] >> si->when; + data["expires"] >> si->expires; + return si; + } +}; + class CommandNSSuspend : public Command { public: @@ -60,18 +99,12 @@ class CommandNSSuspend : public Command NickCore *nc = na->nc; - nc->ExtendMetadata("SUSPENDED"); - nc->ExtendMetadata("SECURE"); - nc->Shrink("KILLPROTECT"); - nc->Shrink("KILL_QUICK"); - nc->Shrink("KILL_IMMED"); - - nc->ExtendMetadata("suspend:by", source.GetNick()); - if (!reason.empty()) - nc->ExtendMetadata("suspend:reason", reason); - if (expiry_secs > 0) - nc->ExtendMetadata("suspend:expire", stringify(Anope::CurTime + expiry_secs)); - nc->ExtendMetadata("suspend:time", stringify(Anope::CurTime)); + NSSuspendInfo *si = nc->Extend<NSSuspendInfo>("SUSPENDED"); + si->nick = nc->display; + si->by = source.GetNick(); + si->reason = reason; + si->when = Anope::CurTime; + si->expires = expiry_secs ? expiry_secs + Anope::CurTime : 0; for (unsigned i = 0; i < nc->aliases->size(); ++i) { @@ -81,7 +114,7 @@ class CommandNSSuspend : public Command { na2->last_quit = reason; - User *u2 = User::Find(na2->nick); + User *u2 = User::Find(na2->nick, true); if (u2) { u2->Logout(); @@ -141,18 +174,12 @@ class CommandNSUnSuspend : public Command return; } - na->nc->Shrink("SUSPENDED"); - na->nc->Shrink("suspend:expire"); - na->nc->Shrink("suspend:by"); - na->nc->Shrink("suspend:reason"); - na->nc->Shrink("suspend:time"); + na->nc->Shrink<NSSuspendInfo>("SUSPENDED"); Log(LOG_ADMIN, source, this) << "for " << na->nick; source.Reply(_("Nick %s is now released."), nick.c_str()); FOREACH_MOD(OnNickUnsuspended, (na)); - - return; } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -168,55 +195,61 @@ class NSSuspend : public Module { CommandNSSuspend commandnssuspend; CommandNSUnSuspend commandnsunsuspend; + ExtensibleItem<NSSuspendInfoImpl> suspend; + Serialize::Type suspend_type; public: NSSuspend(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandnssuspend(this), commandnsunsuspend(this) + commandnssuspend(this), commandnsunsuspend(this), suspend(this, "SUSPENDED"), + suspend_type("NSSuspendInfo", NSSuspendInfoImpl::Unserialize) { } void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) anope_override { - if (na->nc->HasExt("SUSPENDED")) + NSSuspendInfo *s = suspend.Get(na->nc); + if (s) { - Anope::string *by = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:by"), *reason = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:reason"), *t = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:time"); info["Suspended"] = "This nickname is \2suspended\2."; - if (by) - info["Suspended by"] = *by; - if (reason) - info["Suspend reason"] = *reason; - if (t) - info["Suspended on"] = Anope::strftime(convertTo<time_t>(*t), source.GetAccount(), true); + if (!s->by.empty()) + info["Suspended by"] = s->by; + if (!s->reason.empty()) + info["Suspend reason"] = s->reason; + if (s->when) + info["Suspended on"] = Anope::strftime(s->when, source.GetAccount(), true); + if (s->expires) + info["Suspended expires"] = Anope::strftime(s->expires, source.GetAccount(), true); } } void OnPreNickExpire(NickAlias *na, bool &expire) anope_override { - if (!na->nc->HasExt("SUSPENDED")) + NSSuspendInfo *s = suspend.Get(na->nc); + if (!s) return; expire = false; - Anope::string *str = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:expire"); - if (str == NULL) + if (!s->expires) return; - try + if (s->expires < Anope::CurTime) { - time_t when = convertTo<time_t>(*str); - if (when < Anope::CurTime) - { - na->last_seen = Anope::CurTime; - na->nc->Shrink("SUSPENDED"); - na->nc->Shrink("suspend:expire"); - na->nc->Shrink("suspend:by"); - na->nc->Shrink("suspend:reason"); - na->nc->Shrink("suspend:time"); - - Log(LOG_NORMAL, "expire", Config->GetClient("NickServ")) << "Expiring suspend for " << na->nick; - } + na->last_seen = Anope::CurTime; + suspend.Unset(na->nc); + + Log(LOG_NORMAL, "expire", Config->GetClient("NickServ")) << "Expiring suspend for " << na->nick; } - catch (const ConvertException &) { } + } + + EventReturn OnNickValidate(User *u, NickAlias *na) anope_override + { + NSSuspendInfo *s = suspend.Get(na->nc); + if (!s) + return EVENT_CONTINUE; + + u->SendMessage(Config->GetClient("NickServ"), NICK_X_SUSPENDED, u->nick.c_str()); + return EVENT_STOP; } }; diff --git a/modules/commands/os_defcon.cpp b/modules/commands/os_defcon.cpp index 8bea10d0f..58d18558b 100644 --- a/modules/commands/os_defcon.cpp +++ b/modules/commands/os_defcon.cpp @@ -407,13 +407,11 @@ class OSDefcon : public Module this->ParseModeString(); } - EventReturn OnChannelModeSet(Channel *c, MessageSource &, const Anope::string &mname, const Anope::string ¶m) anope_override + EventReturn OnChannelModeSet(Channel *c, MessageSource &, ChannelMode *mode, const Anope::string ¶m) anope_override { - ChannelMode *cm = ModeManager::FindChannelModeByName(mname); - - if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && cm && DConfig.DefConModesOff.count(mname)) + if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && DConfig.DefConModesOff.count(mode->name)) { - c->RemoveMode(Config->GetClient("OperServ"), cm, param); + c->RemoveMode(Config->GetClient("OperServ"), mode, param); return EVENT_STOP; } @@ -421,18 +419,16 @@ class OSDefcon : public Module return EVENT_CONTINUE; } - EventReturn OnChannelModeUnset(Channel *c, MessageSource &, const Anope::string &mname, const Anope::string &) anope_override + EventReturn OnChannelModeUnset(Channel *c, MessageSource &, ChannelMode *mode, const Anope::string &) anope_override { - ChannelMode *cm = ModeManager::FindChannelModeByName(mname); - - if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && cm && DConfig.DefConModesOn.count(mname)) + if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && DConfig.DefConModesOn.count(mode->name)) { Anope::string param; - if (DConfig.GetDefConParam(mname, param)) - c->SetMode(Config->GetClient("OperServ"), cm, param); + if (DConfig.GetDefConParam(mode->name, param)) + c->SetMode(Config->GetClient("OperServ"), mode, param); else - c->SetMode(Config->GetClient("OperServ"), cm); + c->SetMode(Config->GetClient("OperServ"), mode); return EVENT_STOP; diff --git a/modules/commands/os_login.cpp b/modules/commands/os_login.cpp index 9d666188a..6c1edecfb 100644 --- a/modules/commands/os_login.cpp +++ b/modules/commands/os_login.cpp @@ -31,7 +31,7 @@ class CommandOSLogin : public Command source.Reply(_("No oper block for your nick.")); else if (o->password.empty()) source.Reply(_("Your oper block doesn't require logging in.")); - else if (u->HasExt("os_login_password_correct")) + else if (u->HasExt("os_login")) source.Reply(_("You are already identified.")); else if (o->password != password) { @@ -41,11 +41,9 @@ class CommandOSLogin : public Command else { Log(LOG_ADMIN, source, this) << "and successfully identified to " << source.service->nick; - u->Extend("os_login_password_correct"); + u->Extend<bool>("os_login"); source.Reply(_("Password accepted.")); } - - return; } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override @@ -80,12 +78,12 @@ class CommandOSLogout : public Command source.Reply(_("No oper block for your nick.")); else if (o->password.empty()) source.Reply(_("Your oper block doesn't require logging in.")); - else if (!u->HasExt("os_login_password_correct")) + else if (!u->HasExt("os_login")) source.Reply(_("You are not identified.")); else { Log(LOG_ADMIN, source, this); - u->Shrink("os_login_password_correct"); + u->Shrink<bool>("os_login"); source.Reply(_("You have been logged out.")); } } @@ -110,25 +108,20 @@ class OSLogin : public Module { CommandOSLogin commandoslogin; CommandOSLogout commandoslogout; + ExtensibleItem<bool> os_login; public: OSLogin(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandoslogin(this), commandoslogout(this) + commandoslogin(this), commandoslogout(this), os_login(this, "os_login") { } - ~OSLogin() - { - for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) - it->second->Shrink("os_login_password_correct"); - } - EventReturn IsServicesOper(User *u) anope_override { if (!u->Account()->o->password.empty()) { - if (u->HasExt("os_login_password_correct")) + if (os_login.HasExt(u)) return EVENT_ALLOW; return EVENT_STOP; } diff --git a/modules/commands/os_noop.cpp b/modules/commands/os_noop.cpp index 171b11c94..0b5dc74d9 100644 --- a/modules/commands/os_noop.cpp +++ b/modules/commands/os_noop.cpp @@ -35,7 +35,7 @@ class CommandOSNOOP : public Command { /* Remove the O:lines */ IRCD->SendSVSNOOP(s, true); - s->Extend("noop", new ExtensibleItemClass<Anope::string>(source.GetNick())); + s->Extend<Anope::string>("noop", source.GetNick()); Log(LOG_ADMIN, source, this) << "SET on " << s->GetName(); source.Reply(_("All operators from \002%s\002 have been removed."), s->GetName().c_str()); @@ -52,7 +52,7 @@ class CommandOSNOOP : public Command } else if (cmd.equals_ci("REVOKE")) { - s->Shrink("noop"); + s->Shrink<Anope::string>("noop"); IRCD->SendSVSNOOP(s, false); Log(LOG_ADMIN, source, this) << "REVOKE on " << s->GetName(); source.Reply(_("All O:lines of \002%s\002 have been reset."), s->GetName().c_str()); @@ -76,25 +76,23 @@ class CommandOSNOOP : public Command class OSNOOP : public Module { CommandOSNOOP commandosnoop; + PrimitiveExtensibleItem<Anope::string> noop; public: OSNOOP(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), - commandosnoop(this) + commandosnoop(this), noop(this, "noop") { } void OnUserModeSet(User *u, const Anope::string &mname) anope_override { - if (mname == "OPER" && u->server->HasExt("noop")) + Anope::string *setter; + if (mname == "OPER" && (setter = noop.Get(u->server))) { - Anope::string *setter = u->server->GetExt<ExtensibleItemClass<Anope::string> *>("noop"); - if (setter) - { - Anope::string reason = "NOOP command used by " + *setter; - BotInfo *OperServ = Config->GetClient("OperServ"); - u->Kill(OperServ ? OperServ->nick : "", reason); - } + Anope::string reason = "NOOP command used by " + *setter; + BotInfo *OperServ = Config->GetClient("OperServ"); + u->Kill(OperServ ? OperServ->nick : "", reason); } } }; diff --git a/modules/database/db_old.cpp b/modules/database/db_old.cpp index 053a49110..10b2d56e7 100644 --- a/modules/database/db_old.cpp +++ b/modules/database/db_old.cpp @@ -10,6 +10,9 @@ #include "module.h" #include "modules/os_session.h" +#include "modules/bs_kick.h" +#include "modules/cs_mode.h" +#include "modules/bs_badwords.h" #define READ(x) \ if (true) \ @@ -81,13 +84,6 @@ else \ #define OLD_BS_KICK_FLOOD 0x02000000 #define OLD_BS_KICK_REPEAT 0x01000000 -struct ExtensibleItemUint32 : ExtensibleItem -{ - uint32_t u; - ExtensibleItemUint32(uint32_t i) : u(i) { } -}; - - static struct mlock_info { char c; @@ -139,12 +135,13 @@ enum static void process_mlock(ChannelInfo *ci, uint32_t lock, bool status) { + ModeLocks *ml = ci->Require<ModeLocks>("modelocks"); for (unsigned i = 0; i < (sizeof(mlock_infos) / sizeof(mlock_info)); ++i) if (lock & mlock_infos[i].m) { ChannelMode *cm = ModeManager::FindChannelModeByChar(mlock_infos[i].c); - if (cm) - ci->SetMLock(cm, status); + if (cm && ml) + ml->SetMLock(cm, status); } } @@ -448,7 +445,7 @@ static void LoadNicks() nc->email = buffer; READ(read_string(buffer, f)); - nc->greet = buffer; + nc->Extend<Anope::string>("greet", buffer); uint32_t uint; READ(read_uint32(&uint, f)); @@ -459,37 +456,37 @@ static void LoadNicks() READ(read_uint32(&uint, f)); if (uint & OLD_NI_KILLPROTECT) - nc->ExtendMetadata("KILLPROTECT"); + nc->Extend<bool>("KILLPROTECT"); if (uint & OLD_NI_SECURE) - nc->ExtendMetadata("SECURE"); + nc->Extend<bool>("NS_SECURE"); if (uint & OLD_NI_MSG) - nc->ExtendMetadata("MSG"); + nc->Extend<bool>("MSG"); if (uint & OLD_NI_MEMO_HARDMAX) - nc->ExtendMetadata("MEMO_HARDMAX"); + nc->Extend<bool>("MEMO_HARDMAX"); if (uint & OLD_NI_MEMO_SIGNON) - nc->ExtendMetadata("MEMO_SIGNON"); + nc->Extend<bool>("MEMO_SIGNON"); if (uint & OLD_NI_MEMO_RECEIVE) - nc->ExtendMetadata("MEMO_RECEIVE"); + nc->Extend<bool>("MEMO_RECEIVE"); if (uint & OLD_NI_PRIVATE) - nc->ExtendMetadata("PRIVATE"); + nc->Extend<bool>("NS_PRIVATE"); if (uint & OLD_NI_HIDE_EMAIL) - nc->ExtendMetadata("HIDE_EMAIL"); + nc->Extend<bool>("HIDE_EMAIL"); if (uint & OLD_NI_HIDE_MASK) - nc->ExtendMetadata("HIDE_MASK"); + nc->Extend<bool>("HIDE_MASK"); if (uint & OLD_NI_HIDE_QUIT) - nc->ExtendMetadata("HIDE_QUIT"); + nc->Extend<bool>("HIDE_QUIT"); if (uint & OLD_NI_KILL_QUICK) - nc->ExtendMetadata("KILL_QUICK"); + nc->Extend<bool>("KILL_QUICK"); if (uint & OLD_NI_KILL_IMMED) - nc->ExtendMetadata("KILL_IMMED"); + nc->Extend<bool>("KILL_IMMED"); if (uint & OLD_NI_MEMO_MAIL) - nc->ExtendMetadata("MEMO_MAIL"); + nc->Extend<bool>("MEMO_MAIL"); if (uint & OLD_NI_HIDE_STATUS) - nc->ExtendMetadata("HIDE_STATUS"); + nc->Extend<bool>("HIDE_STATUS"); if (uint & OLD_NI_SUSPENDED) - nc->ExtendMetadata("SUSPENDED"); + nc->Extend<bool>("SUSPENDED"); if (!(uint & OLD_NI_AUTOOP)) - nc->ExtendMetadata("AUTOOP"); + nc->Extend<bool>("AUTOOP"); uint16_t u16; READ(read_uint16(&u16, f)); @@ -607,7 +604,7 @@ static void LoadNicks() na->last_seen = last_seen; if (tmpu16 & OLD_NS_NO_EXPIRE) - na->ExtendMetadata("NO_EXPIRE"); + na->Extend<bool>("NS_NO_EXPIRE"); Log(LOG_DEBUG) << "Loaded NickAlias " << na->nick; } @@ -728,31 +725,31 @@ static void LoadChannels() // Temporary flags cleanup tmpu32 &= ~0x80000000; if (tmpu32 & OLD_CI_KEEPTOPIC) - ci->ExtendMetadata("KEEPTOPIC"); + ci->Extend<bool>("KEEPTOPIC"); if (tmpu32 & OLD_CI_SECUREOPS) - ci->ExtendMetadata("SECUREOPS"); + ci->Extend<bool>("SECUREOPS"); if (tmpu32 & OLD_CI_PRIVATE) - ci->ExtendMetadata("PRIVATE"); + ci->Extend<bool>("CS_PRIVATE"); if (tmpu32 & OLD_CI_TOPICLOCK) - ci->ExtendMetadata("TOPICLOCK"); + ci->Extend<bool>("TOPICLOCK"); if (tmpu32 & OLD_CI_RESTRICTED) - ci->ExtendMetadata("RESTRICTED"); + ci->Extend<bool>("RESTRICTED"); if (tmpu32 & OLD_CI_PEACE) - ci->ExtendMetadata("PEACE"); + ci->Extend<bool>("PEACE"); if (tmpu32 & OLD_CI_SECURE) - ci->ExtendMetadata("SECURE"); + ci->Extend<bool>("CS_SECURE"); if (tmpu32 & OLD_CI_NO_EXPIRE) - ci->ExtendMetadata("NO_EXPIRE"); + ci->Extend<bool>("CI_NO_EXPIRE"); if (tmpu32 & OLD_CI_MEMO_HARDMAX) - ci->ExtendMetadata("MEMO_HARDMAX"); + ci->Extend<bool>("MEMO_HARDMAX"); if (tmpu32 & OLD_CI_SECUREFOUNDER) - ci->ExtendMetadata("SECUREFOUNDER"); + ci->Extend<bool>("SECUREFOUNDER"); if (tmpu32 & OLD_CI_SIGNKICK) - ci->ExtendMetadata("SIGNKICK"); + ci->Extend<bool>("SIGNKICK"); if (tmpu32 & OLD_CI_SIGNKICK_LEVEL) - ci->ExtendMetadata("SIGNKICK_LEVEL"); + ci->Extend<bool>("SIGNKICK_LEVEL"); if (tmpu32 & OLD_CI_SUSPENDED) - ci->ExtendMetadata("SUSPENDED"); + ci->Extend<bool>("SUSPENDED"); READ(read_string(buffer, f)); READ(read_string(buffer, f)); @@ -773,7 +770,7 @@ static void LoadChannels() level = ACCESS_FOUNDER; if (j == 10 && level < 0) // NOJOIN - ci->Shrink("RESTRICTED"); // If CSDefRestricted was enabled this can happen + ci->Shrink<bool>("RESTRICTED"); // If CSDefRestricted was enabled this can happen ci->SetLevel(GetLevelName(j), level); } @@ -831,9 +828,9 @@ static void LoadChannels() } READ(read_uint32(&tmpu32, f)); // mlock on - ci->Extend("mlock_on", new ExtensibleItemUint32(tmpu32)); + ci->Extend<uint32_t>("mlock_on", tmpu32); READ(read_uint32(&tmpu32, f)); // mlock off - ci->Extend("mlock_off", new ExtensibleItemUint32(tmpu32)); + ci->Extend<uint32_t>("mlock_off", tmpu32); READ(read_uint32(&tmpu32, f)); // mlock limit READ(read_string(buffer, f)); READ(read_string(buffer, f)); @@ -863,52 +860,63 @@ static void LoadChannels() READ(read_int32(&tmp32, f)); if (tmp32 & OLD_BS_DONTKICKOPS) - ci->ExtendMetadata("BS_DONTKICKOPS"); + ci->Extend<bool>("BS_DONTKICKOPS"); if (tmp32 & OLD_BS_DONTKICKVOICES) - ci->ExtendMetadata("BS_DONTKICKVOICES"); + ci->Extend<bool>("BS_DONTKICKVOICES"); if (tmp32 & OLD_BS_FANTASY) - ci->ExtendMetadata("BS_FANTASY"); + ci->Extend<bool>("BS_FANTASY"); if (tmp32 & OLD_BS_GREET) - ci->ExtendMetadata("BS_GREET"); + ci->Extend<bool>("BS_GREET"); if (tmp32 & OLD_BS_NOBOT) - ci->ExtendMetadata("BS_NOBOT"); - if (tmp32 & OLD_BS_KICK_BOLDS) - ci->ExtendMetadata("BS_KICK_BOLDS"); - if (tmp32 & OLD_BS_KICK_COLORS) - ci->ExtendMetadata("BS_KICK_COLORS"); - if (tmp32 & OLD_BS_KICK_REVERSES) - ci->ExtendMetadata("BS_KICK_REVERSES"); - if (tmp32 & OLD_BS_KICK_UNDERLINES) - ci->ExtendMetadata("BS_KICK_UNDERLINES"); - if (tmp32 & OLD_BS_KICK_BADWORDS) - ci->ExtendMetadata("BS_KICK_BADWORDS"); - if (tmp32 & OLD_BS_KICK_CAPS) - ci->ExtendMetadata("BS_KICK_CAPS"); - if (tmp32 & OLD_BS_KICK_FLOOD) - ci->ExtendMetadata("BS_KICK_FLOOD"); - if (tmp32 & OLD_BS_KICK_REPEAT) - ci->ExtendMetadata("BS_KICK_REPEAT"); + ci->Extend<bool>("BS_NOBOT"); + + KickerData *kd = ci->Require<KickerData>("kickerdata"); + if (kd) + { + if (tmp32 & OLD_BS_KICK_BOLDS) + kd->bolds = true; + if (tmp32 & OLD_BS_KICK_COLORS) + kd->colors = true; + if (tmp32 & OLD_BS_KICK_REVERSES) + kd->reverses = true; + if (tmp32 & OLD_BS_KICK_UNDERLINES) + kd->underlines = true; + if (tmp32 & OLD_BS_KICK_BADWORDS) + kd->badwords = true; + if (tmp32 & OLD_BS_KICK_CAPS) + kd->caps = true; + if (tmp32 & OLD_BS_KICK_FLOOD) + kd->flood = true; + if (tmp32 & OLD_BS_KICK_REPEAT) + kd->repeat = true; + } READ(read_int16(&tmp16, f)); for (int16_t j = 0; j < tmp16; ++j) { int16_t ttb; READ(read_int16(&ttb, f)); - if (j < TTB_SIZE) - ci->ttb[j] = ttb; + if (j < TTB_SIZE && kd) + kd->ttb[j] = ttb; } READ(read_int16(&tmp16, f)); - ci->capsmin = tmp16; + if (kd) + kd->capsmin = tmp16; READ(read_int16(&tmp16, f)); - ci->capspercent = tmp16; + if (kd) + kd->capspercent = tmp16; READ(read_int16(&tmp16, f)); - ci->floodlines = tmp16; + if (kd) + kd->floodlines = tmp16; READ(read_int16(&tmp16, f)); - ci->floodsecs = tmp16; + if (kd) + kd->floodsecs = tmp16; READ(read_int16(&tmp16, f)); - ci->repeattimes = tmp16; + if (kd) + kd->repeattimes = tmp16; + BadWords *bw = ci->Require<BadWords>("badwords"); READ(read_uint16(&tmpu16, f)); for (uint16_t j = 0; j < tmpu16; ++j) { @@ -928,7 +936,8 @@ static void LoadChannels() else if (type == 3) bwtype = BW_END; - ci->AddBadWord(buffer, bwtype); + if (bw) + bw->AddBadWord(buffer, bwtype); } } @@ -1089,8 +1098,11 @@ static void LoadExceptions() class DBOld : public Module { + PrimitiveExtensibleItem<uint32_t> mlock_on, mlock_off; + public: - DBOld(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR) + DBOld(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR), + mlock_on(this, "mlock_on"), mlock_off(this, "mlock_off") { @@ -1114,22 +1126,21 @@ class DBOld : public Module void OnUplinkSync(Server *s) anope_override { - ExtensibleItemUint32 *mlock; for (registered_channel_map::iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it) { ChannelInfo *ci = it->second; - if (ci->HasExt("mlock_on")) + + uint32_t *u = mlock_on.Get(ci); + if (u) { - mlock = ci->GetExt<ExtensibleItemUint32 *>("mlock_on"); - process_mlock(ci, mlock->u, true); - ci->Shrink("mlock_on"); + process_mlock(ci, *u, true); + mlock_on.Unset(ci); } - if (ci->HasExt("mlock_off")) + u = mlock_off.Get(ci); { - mlock = ci->GetExt<ExtensibleItemUint32 *>("mlock_off"); - process_mlock(ci, mlock->u, false); - ci->Shrink("mlock_off"); + process_mlock(ci, *u, false); + mlock_off.Unset(ci); } } } diff --git a/modules/database/db_plain.cpp b/modules/database/db_plain.cpp index 1e4586a11..62ecaaaa0 100644 --- a/modules/database/db_plain.cpp +++ b/modules/database/db_plain.cpp @@ -10,6 +10,11 @@ #include "module.h" #include "modules/os_session.h" +#include "modules/cs_suspend.h" +#include "modules/bs_kick.h" +#include "modules/cs_log.h" +#include "modules/cs_mode.h" +#include "modules/bs_badwords.h" Anope::string DatabaseFile; Anope::string BackupFile; @@ -71,15 +76,13 @@ EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const else if (key.equals_ci("EMAIL")) nc->email = params[0]; else if (key.equals_ci("GREET")) - nc->greet = params[0]; + nc->Extend<Anope::string>("greet", params[0]); else if (key.equals_ci("ACCESS")) nc->AddAccess(params[0]); - else if (key.equals_ci("CERT")) - nc->AddCert(params[0]); else if (key.equals_ci("FLAGS")) { for (unsigned i = 0; i < params.size(); ++i) - nc->ExtendMetadata(params[i]); + nc->Extend<bool>(params[i]); } else if (key.equals_ci("MI")) { @@ -118,7 +121,7 @@ EventReturn OnDatabaseReadMetadata(NickAlias *na, const Anope::string &key, cons na->last_quit = params[0]; else if (key.equals_ci("FLAGS")) for (unsigned i = 0; i < params.size(); ++i) - na->ExtendMetadata(params[i]); + na->Extend<bool>(params[i]); else if (key.equals_ci("VHOST")) na->SetVhost(params.size() > 3 ? params[3] : "", params[2], params[0], params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0); return EVENT_CONTINUE; @@ -131,6 +134,7 @@ EventReturn OnDatabaseReadMetadata(BotInfo *bi, const Anope::string &key, const EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> ¶ms) { + KickerData *kd = ci->GetExt<KickerData>("kickerdata"); try { if (key.equals_ci("BANTYPE")) @@ -153,7 +157,7 @@ EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, co } else if (key.equals_ci("FLAGS")) for (unsigned i = 0; i < params.size(); ++i) - ci->ExtendMetadata(params[i]); + ci->Extend<bool>(params[i]); else if (key.equals_ci("DESC")) ci->desc = params[0]; else if (key.equals_ci("TOPIC")) @@ -164,8 +168,9 @@ EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, co } else if (key.equals_ci("SUSPEND")) { - ci->ExtendMetadata("suspend:by", params[0]); - ci->ExtendMetadata("suspend:reason", params[1]); + CSSuspendInfo *si = ci->Extend<CSSuspendInfo>("suspend"); + si->by = params[0]; + si->reason = params[1]; } else if (key.equals_ci("ACCESS")) // Older access system, from Anope 1.9.4. { @@ -220,18 +225,22 @@ EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, co } else if (key.equals_ci("LOG")) { - LogSetting *l = new LogSetting(); - - l->ci = ci; - l->service_name = params[0]; - l->command_service = params[1]; - l->command_name = params[2]; - l->method = params[3]; - l->creator = params[4]; - l->created = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime; - l->extra = params.size() > 6 ? params[6] : ""; - - ci->log_settings->push_back(l); + LogSettings *ls = ci->Require<LogSettings>("logsettings"); + if (ls) + { + LogSetting *l = ls->Create(); + + l->chan = ci->name; + l->service_name = params[0]; + l->command_service = params[1]; + l->command_name = params[2]; + l->method = params[3]; + l->creator = params[4]; + l->created = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime; + l->extra = params.size() > 6 ? params[6] : ""; + + (*ls)->push_back(l); + } } else if (key.equals_ci("MLOCK")) { @@ -240,7 +249,9 @@ EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, co Anope::string setter = params[2]; time_t mcreated = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : Anope::CurTime; Anope::string param = params.size() > 4 ? params[4] : ""; - ci->mode_locks->insert(std::make_pair(mode_name, new ModeLock(ci, set, mode_name, param, setter, mcreated))); + ModeLocks *ml = ci->Require<ModeLocks>("modelocks"); + if (ml) + ml->SetMLock(ModeManager::FindChannelModeByName(mode_name), set, param, setter, mcreated); } else if (key.equals_ci("MI")) { @@ -265,44 +276,44 @@ EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, co ci->bi = BotInfo::Find(params[1]); else if (params[0].equals_ci("FLAGS")) for (unsigned i = 0; i < params.size(); ++i) - ci->ExtendMetadata(params[i]); + ci->Extend<bool>(params[i]); else if (params[0].equals_ci("TTB")) { - for (unsigned j = 1, end = params.size(); j < end; j += 2) + for (unsigned j = 1, end = params.size(); j < end &&& kd; j += 2) { if (params[j].equals_ci("BOLDS")) - ci->ttb[0] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; + kd->ttb[0] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; else if (params[j].equals_ci("COLORS")) - ci->ttb[1] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; + kd->ttb[1] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; else if (params[j].equals_ci("REVERSES")) - ci->ttb[2] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; + kd->ttb[2] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; else if (params[j].equals_ci("UNDERLINES")) - ci->ttb[3] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; + kd->ttb[3] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; else if (params[j].equals_ci("BADWORDS")) - ci->ttb[4] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; + kd->ttb[4] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; else if (params[j].equals_ci("CAPS")) - ci->ttb[5] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; + kd->ttb[5] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; else if (params[j].equals_ci("FLOOD")) - ci->ttb[6] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; + kd->ttb[6] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; else if (params[j].equals_ci("REPEAT")) - ci->ttb[7] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; + kd->ttb[7] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; else if (params[j].equals_ci("ITALICS")) - ci->ttb[8] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; + kd->ttb[8] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; else if (params[j].equals_ci("AMSGS")) - ci->ttb[9] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; + kd->ttb[9] = params[j + 1].is_pos_number_only() ? convertTo<int16_t>(params[j + 1]) : 0; } } - else if (params[0].equals_ci("CAPSMIN")) - ci->capsmin = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0; - else if (params[0].equals_ci("CAPSPERCENT")) - ci->capspercent = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0; - else if (params[0].equals_ci("FLOODLINES")) - ci->floodlines = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0; - else if (params[0].equals_ci("FLOODSECS")) - ci->floodsecs = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0; - else if (params[0].equals_ci("REPEATTIMES")) - ci->repeattimes = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0; - else if (params[0].equals_ci("BADWORD")) + else if (kd && params[0].equals_ci("CAPSMIN")) + kd->capsmin = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0; + else if (kd && params[0].equals_ci("CAPSPERCENT")) + kd->capspercent = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0; + else if (kd && params[0].equals_ci("FLOODLINES")) + kd->floodlines = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0; + else if (kd && params[0].equals_ci("FLOODSECS")) + kd->floodsecs = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0; + else if (kd && params[0].equals_ci("REPEATTIMES")) + kd->repeattimes = params[1].is_pos_number_only() ? convertTo<int16_t>(params[1]) : 0; + else if (kd && params[0].equals_ci("BADWORD")) { BadWordType Type; if (params[1].equals_ci("SINGLE")) @@ -313,7 +324,9 @@ EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, co Type = BW_END; else Type = BW_ANY; - ci->AddBadWord(params[2], Type); + BadWords *bw = ci->Require<BadWords>("badwords"); + if (bw) + bw->AddBadWord(params[2], Type); } } } @@ -467,11 +480,6 @@ static void ReadDatabase(Module *m = NULL) static void LoadNickCore(const std::vector<Anope::string> ¶ms) { NickCore *nc = new NickCore(params[0]); - /* Clear default flags */ - std::deque<Anope::string> list; - nc->GetExtList(list); - for (unsigned i = 0; i < list.size(); ++i) - nc->Shrink(list[i]); nc->pass = params.size() > 1 ? params[1] : ""; @@ -512,13 +520,6 @@ static void LoadBotInfo(const std::vector<Anope::string> ¶ms) static void LoadChanInfo(const std::vector<Anope::string> ¶ms) { ChannelInfo *ci = new ChannelInfo(params[0]); - /* CLear default mlock */ - ci->ClearMLock(); - /* Remove default channel flags */ - std::deque<Anope::string> list; - ci->GetExtList(list); - for (unsigned i = 0; i < list.size(); ++i) - ci->Shrink(list[i]); ci->time_registered = params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0; @@ -645,230 +646,6 @@ class DBPlain : public Module return EVENT_STOP; } - - - void OnSaveDatabase() anope_override - { - BackupDatabase(); - - db_buffer << "VER 2" << endl; - - for (nickcore_map::const_iterator nit = NickCoreList->begin(), nit_end = NickCoreList->end(); nit != nit_end; ++nit) - { - const NickCore *nc = nit->second; - - db_buffer << "NC " << nc->display << " " << nc->pass << endl; - - db_buffer << "MD MEMOMAX " << nc->memos.memomax << endl; - - if (!nc->language.empty()) - db_buffer << "MD LANGUAGE " << nc->language << endl; - if (!nc->email.empty()) - db_buffer << "MD EMAIL " << nc->email << endl; - if (!nc->greet.empty()) - db_buffer << "MD GREET :" << nc->greet << endl; - - if (!nc->access.empty()) - { - for (std::vector<Anope::string>::const_iterator it = nc->access.begin(), it_end = nc->access.end(); it != it_end; ++it) - db_buffer << "MD ACCESS " << *it << endl; - } - if (!nc->cert.empty()) - { - for (std::vector<Anope::string>::const_iterator it = nc->cert.begin(), it_end = nc->cert.end(); it != it_end; ++it) - db_buffer << "MD CERT " << *it << endl; - } - db_buffer << "MD FLAGS "; - std::deque<Anope::string> list; - nc->GetExtList(list); - for (unsigned i = 0; i < list.size(); ++i) - db_buffer << list[i] << " "; - db_buffer << std::endl; - const MemoInfo *mi = &nc->memos; - for (unsigned k = 0, end = mi->memos->size(); k < end; ++k) - { - const Memo *m = mi->GetMemo(k); - db_buffer << "MD MI " << m->time << " " << m->sender; - if (m->unread) - db_buffer << " UNREAD"; - if (m->receipt) - db_buffer << " RECEIPT"; - db_buffer << " :" << m->text << endl; - } - for (unsigned k = 0, end = mi->ignores.size(); k < end; ++k) - db_buffer << "MD MIG " << Anope::string(mi->ignores[k]) << endl; - //FOREACH_MOD(OnDatabaseWriteMetadata, (WriteMetadata, nc)); - } - - for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it) - { - const NickAlias *na = it->second; - - db_buffer << "NA " << na->nc->display << " " << na->nick << " " << na->time_registered << " " << na->last_seen << endl; - if (!na->last_usermask.empty()) - db_buffer << "MD LAST_USERMASK " << na->last_usermask << endl; - if (!na->last_realhost.empty()) - db_buffer << "MD LAST_REALHOST " << na->last_realhost << endl; - if (!na->last_realname.empty()) - db_buffer << "MD LAST_REALNAME :" << na->last_realname << endl; - if (!na->last_quit.empty()) - db_buffer << "MD LAST_QUIT :" << na->last_quit << endl; - db_buffer << "MD FLAGS "; - std::deque<Anope::string> list; - na->GetExtList(list); - for (unsigned i = 0; i < list.size(); ++i) - db_buffer << list[i] << " "; - db_buffer << std::endl; - if (na->HasVhost()) - db_buffer << "MD VHOST " << na->GetVhostCreator() << " " << na->GetVhostCreated() << " " << na->GetVhostHost() << " :" << na->GetVhostIdent() << endl; - - //FOREACH_MOD(OnDatabaseWriteMetadata, (WriteMetadata, na)); - } - - for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) - { - BotInfo *bi = it->second; - - if (bi->HasExt("CONF")) - continue; - - db_buffer << "BI " << bi->nick << " " << bi->GetIdent() << " " << bi->host << " " << bi->created << " " << bi->GetChannelCount() << " :" << bi->realname << endl; - db_buffer << "MD FLAGS "; - std::deque<Anope::string> list; - bi->GetExtList(list); - for (unsigned i = 0; i < list.size(); ++i) - db_buffer << list[i] << " "; - db_buffer << std::endl; - } - - for (registered_channel_map::const_iterator cit = RegisteredChannelList->begin(), cit_end = RegisteredChannelList->end(); cit != cit_end; ++cit) - { - const ChannelInfo *ci = cit->second; - - db_buffer << "CH " << ci->name << " " << ci->time_registered << " " << ci->last_used << endl; - db_buffer << "MD BANTYPE " << ci->bantype << endl; - db_buffer << "MD MEMOMAX " << ci->memos.memomax << endl; - if (ci->GetFounder()) - db_buffer << "MD FOUNDER " << ci->GetFounder()->display << endl; - if (ci->GetSuccessor()) - db_buffer << "MD SUCCESSOR " << ci->GetSuccessor()->display << endl; - if (!ci->desc.empty()) - db_buffer << "MD DESC :" << ci->desc << endl; - if (!ci->last_topic.empty()) - db_buffer << "MD TOPIC " << ci->last_topic_setter << " " << ci->last_topic_time << " :" << ci->last_topic << endl; - db_buffer << "MD LEVELS"; - const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges(); - for (unsigned i = 0; i < privs.size(); ++i) - { - const Privilege &p = privs[i]; - db_buffer << p.name << " " << ci->GetLevel(p.name); - } - db_buffer << endl; - std::deque<Anope::string> list; - ci->GetExtList(list); - for (unsigned i = 0; i < list.size(); ++i) - db_buffer << list[i]; - db_buffer << std::endl; - if (ci->HasExt("SUSPENDED")) - { - Anope::string *by = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend_by"), *reason = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend_reason"); - if (by && reason) - db_buffer << "MD SUSPEND " << *by << " :" << *reason << endl; - } - for (unsigned k = 0, end = ci->GetAccessCount(); k < end; ++k) - { - const ChanAccess *access = ci->GetAccess(k); - db_buffer << "MD ACCESS2 " << access->provider->name << " " << access->mask << " " << access->AccessSerialize() << " " << access->last_seen << " " << access->creator << " " << access->created << endl; - } - for (unsigned k = 0, end = ci->GetAkickCount(); k < end; ++k) - { - db_buffer << "MD AKICK 0 " << (ci->GetAkick(k)->nc ? "NICK " : "MASK ") << - (ci->GetAkick(k)->nc ? ci->GetAkick(k)->nc->display : ci->GetAkick(k)->mask) << " " << ci->GetAkick(k)->creator << " " << ci->GetAkick(k)->addtime << " " << ci->last_used << " :"; - if (!ci->GetAkick(k)->reason.empty()) - db_buffer << ci->GetAkick(k)->reason; - db_buffer << endl; - } - for (unsigned k = 0, end = ci->log_settings->size(); k < end; ++k) - { - const LogSetting &l = *ci->log_settings->at(k); - - db_buffer << "MD LOG " << l.service_name << " " << l.command_service << " " << l.command_name << " " << l.method << " " << l.creator << " " << l.created << " " << l.extra << endl; - } - for (ChannelInfo::ModeList::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 != NULL) - db_buffer << "MD MLOCK " << (ml.set ? 1 : 0) << " " << cm->name << " " << ml.setter << " " << ml.created << " " << ml.param << endl; - } - const MemoInfo *memos = &ci->memos; - for (unsigned k = 0, end = memos->memos->size(); k < end; ++k) - { - const Memo *m = memos->GetMemo(k); - db_buffer << "MD MI " << m->time << " " << m->sender; - if (m->unread) - db_buffer << " UNREAD"; - if (m->receipt) - db_buffer << " RECEIPT"; - db_buffer << " :" << m->text << endl; - } - for (unsigned k = 0, end = memos->ignores.size(); k < end; ++k) - db_buffer << "MD MIG " << Anope::string(memos->ignores[k]) << endl; - if (ci->bi) - db_buffer << "MD BI NAME " << ci->bi->nick << endl; - db_buffer << "MD BI TTB BOLDS " << ci->ttb[0] << " COLORS " << ci->ttb[1] << " REVERSES " << ci->ttb[2] << " UNDERLINES " << ci->ttb[3] << " BADWORDS " << ci->ttb[4] << " CAPS " << ci->ttb[5] << " FLOOD " << ci->ttb[6] << " REPEAT " << ci->ttb[7] << " ITALICS " << ci->ttb[8] << " AMSGS " << ci->ttb[9] << endl; - if (ci->capsmin) - db_buffer << "MD BI CAPSMIN " << ci->capsmin << endl; - if (ci->capspercent) - db_buffer << "MD BI CAPSPERCENT " << ci->capspercent << endl; - if (ci->floodlines) - db_buffer << "MD BI FLOODLINES " << ci->floodlines << endl; - if (ci->floodsecs) - db_buffer << "MD BI FLOODSECS " << ci->floodsecs << endl; - if (ci->repeattimes) - db_buffer << "MD BI REPEATTIMES " << ci->repeattimes << endl; - for (unsigned k = 0, end = ci->GetBadWordCount(); k < end; ++k) - db_buffer << "MD BI BADWORD " << (ci->GetBadWord(k)->type == BW_ANY ? "ANY " : "") << (ci->GetBadWord(k)->type == BW_SINGLE ? "SINGLE " : "") << (ci->GetBadWord(k)->type == BW_START ? "START " : "") << - (ci->GetBadWord(k)->type == BW_END ? "END " : "") << ":" << ci->GetBadWord(k)->word << endl; - - //FOREACH_MOD(OnDatabaseWriteMetadata, (WriteMetadata, ci)); - } - - db_buffer << "OS STATS " << MaxUserCount << " " << MaxUserTime << endl; - - for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it) - { - XLineManager *xl = *it; - for (unsigned i = 0, end = xl->GetCount(); i < end; ++i) - { - const XLine *x = xl->GetEntry(i); - db_buffer << "OS SXLINE " << xl->Type() << " " << x->GetUser() << " " << x->GetHost() << " " << x->by << " " << x->created << " " << x->expires << " :" << x->reason << endl; - } - } - - if (session_service) - for (SessionService::ExceptionVector::iterator it = session_service->GetExceptions().begin(); it != session_service->GetExceptions().end(); ++it) - { - Exception *e = *it; - db_buffer << "OS EXCEPTION " << e->mask << " " << e->limit << " " << e->who << " " << e->time << " " << e->expires << " " << e->reason << endl; - } - - //FOREACH_MOD(OnDatabaseWrite, (Write)); - - std::fstream db; - db.open(DatabaseFile.c_str(), std::ios_base::out | std::ios_base::trunc); - - if (!db.is_open()) - { - IRCD->SendGlobops(NULL, "Unable to open %s for writing!", DatabaseFile.c_str()); - return; - } - - db << db_buffer.str(); - db_buffer.str(""); - - db.close(); - } }; MODULE_INIT(DBPlain) diff --git a/modules/extra/m_chanstats.cpp b/modules/extra/m_chanstats.cpp index 9a3c5dfaf..4ff4d55e3 100644 --- a/modules/extra/m_chanstats.cpp +++ b/modules/extra/m_chanstats.cpp @@ -56,7 +56,7 @@ class MChanstats : public Module const Anope::string GetDisplay(User *u) { - if (u && u->Account() && u->Account()->HasExt("STATS")) + if (u && u->Account() && u->Account()->HasExt("NS_STATS")) return u->Account()->display; else return ""; @@ -357,7 +357,7 @@ class MChanstats : public Module void OnTopicUpdated(Channel *c, const Anope::string &user, const Anope::string &topic) anope_override { User *u = User::Find(user); - if (!u || !u->Account() || !c->ci || !c->ci->HasExt("STATS")) + if (!u || !u->Account() || !c->ci || !c->ci->HasExt("CS_STATS")) return; query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);"; query.SetValue("channel", c->name); @@ -365,13 +365,13 @@ class MChanstats : public Module this->RunQuery(query); } - EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, const Anope::string &, const Anope::string ¶m) anope_override + EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) anope_override { this->OnModeChange(c, setter.GetUser()); return EVENT_CONTINUE; } - EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, const Anope::string &, const Anope::string ¶m) anope_override + EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *, const Anope::string ¶m) anope_override { this->OnModeChange(c, setter.GetUser()); return EVENT_CONTINUE; @@ -380,7 +380,7 @@ class MChanstats : public Module private: void OnModeChange(Channel *c, User *u) { - if (!u || !u->Account() || !c->ci || !c->ci->HasExt("STATS")) + if (!u || !u->Account() || !c->ci || !c->ci->HasExt("CS_STATS")) return; query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);"; @@ -391,7 +391,7 @@ class MChanstats : public Module public: void OnPreUserKicked(MessageSource &source, ChanUserContainer *cu, const Anope::string &kickmsg) anope_override { - if (!cu->chan->ci || !cu->chan->ci->HasExt("STATS")) + if (!cu->chan->ci || !cu->chan->ci->HasExt("CS_STATS")) return; query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0);"; @@ -406,7 +406,7 @@ class MChanstats : public Module } void OnPrivmsg(User *u, Channel *c, Anope::string &msg) anope_override { - if (!c->ci || !c->ci->HasExt("STATS")) + if (!c->ci || !c->ci->HasExt("CS_STATS")) return; size_t letters = msg.length(); @@ -452,7 +452,7 @@ class MChanstats : public Module query.SetValue("new_display", newdisplay); this->RunQuery(query); } - void OnChanDrop(ChannelInfo *ci) anope_override + void OnDelChan(ChannelInfo *ci) anope_override { query = "DELETE FROM `" + prefix + "chanstats` WHERE `chan` = @channel@;"; query.SetValue("channel", ci->name); diff --git a/modules/extra/m_ldap_authentication.cpp b/modules/extra/m_ldap_authentication.cpp index d64987ed6..7fe44b8e0 100644 --- a/modules/extra/m_ldap_authentication.cpp +++ b/modules/extra/m_ldap_authentication.cpp @@ -111,7 +111,7 @@ class IdentifyInterface : public LDAPInterface // encrypt and store the password in the nickcore Anope::Encrypt(ii->req->GetPassword(), na->nc->pass); - na->nc->Extend("m_ldap_authentication_dn", new ExtensibleItemClass<Anope::string>(ii->dn)); + na->nc->Extend<Anope::string>("m_ldap_authentication_dn", ii->dn); ii->req->Success(me); } break; @@ -207,12 +207,15 @@ class NSIdentifyLDAP : public Module OnIdentifyInterface oninterface; OnRegisterInterface orinterface; + PrimitiveExtensibleItem<Anope::string> dn; + Anope::string password_attribute; Anope::string disable_register_reason; Anope::string disable_email_reason; public: NSIdentifyLDAP(const Anope::string &modname, const Anope::string &creator) : - Module(modname, creator, EXTRA | VENDOR), ldap("LDAPProvider", "ldap/main"), iinterface(this), oninterface(this), orinterface(this) + Module(modname, creator, EXTRA | VENDOR), ldap("LDAPProvider", "ldap/main"), iinterface(this), oninterface(this), orinterface(this), + dn(this, "m_ldap_authentication_dn") { me = this; @@ -274,16 +277,16 @@ class NSIdentifyLDAP : public Module void OnNickIdentify(User *u) anope_override { - if (email_attribute.empty() || !this->ldap || !u->Account()->HasExt("m_ldap_authentication_dn")) + if (email_attribute.empty() || !this->ldap) return; - Anope::string *dn = u->Account()->GetExt<ExtensibleItemClass<Anope::string> *>("m_ldap_authentication_dn"); - if (!dn || dn->empty()) + Anope::string *d = dn.Get(u->Account()); + if (!d || d->empty()) return; try { - LDAPQuery id = this->ldap->Search(&this->oninterface, *dn, "(" + email_attribute + "=*)"); + LDAPQuery id = this->ldap->Search(&this->oninterface, *d, "(" + email_attribute + "=*)"); this->oninterface.Add(id, u->nick); } catch (const LDAPException &ex) diff --git a/modules/extra/webcpanel/pages/chanserv/set.cpp b/modules/extra/webcpanel/pages/chanserv/set.cpp index 20026a08a..cf3784d62 100644 --- a/modules/extra/webcpanel/pages/chanserv/set.cpp +++ b/modules/extra/webcpanel/pages/chanserv/set.cpp @@ -32,57 +32,57 @@ bool WebCPanel::ChanServ::Set::OnRequest(HTTPProvider *server, const Anope::stri if (ci->HasExt("KEEPTOPIC") != message.post_data.count("keeptopic")) { if (!ci->HasExt("KEEPTOPIC")) - ci->ExtendMetadata("KEEPTOPIC"); + ci->Extend<bool>("KEEPTOPIC"); else - ci->Shrink("KEEPTOPIC"); + ci->Shrink<bool>("KEEPTOPIC"); replacements["MESSAGES"] = "Secure updated"; } if (ci->HasExt("PEACE") != message.post_data.count("peace")) { if (!ci->HasExt("PEACE")) - ci->ExtendMetadata("PEACE"); + ci->Extend<bool>("PEACE"); else - ci->Shrink("PEACE"); + ci->Shrink<bool>("PEACE"); replacements["MESSAGES"] = "Peace updated"; } - if (ci->HasExt("PRIVATE") != message.post_data.count("private")) + if (ci->HasExt("CS_PRIVATE") != message.post_data.count("private")) { - if (!ci->HasExt("PRIVATE")) - ci->ExtendMetadata("PRIVATE"); + if (!ci->HasExt("CS_PRIVATE")) + ci->Extend<bool>("CS_PRIVATE"); else - ci->Shrink("PRIVATE"); + ci->Shrink<bool>("CS_PRIVATE"); replacements["MESSAGES"] = "Private updated"; } if (ci->HasExt("RESTRICTED") != message.post_data.count("restricted")) { if (!ci->HasExt("RESTRICTED")) - ci->ExtendMetadata("RESTRICTED"); + ci->Extend<bool>("RESTRICTED"); else - ci->Shrink("RESTRICTED"); + ci->Shrink<bool>("RESTRICTED"); replacements["MESSAGES"] = "Restricted updated"; } - if (ci->HasExt("SECURE") != message.post_data.count("secure")) + if (ci->HasExt("CS_SECURE") != message.post_data.count("secure")) { - if (!ci->HasExt("SECURE")) - ci->ExtendMetadata("SECURE"); + if (!ci->HasExt("CS_SECURE")) + ci->Extend<bool>("CS_SECURE"); else - ci->Shrink("SECURE"); + ci->Shrink<bool>("CS_SECURE"); replacements["MESSAGES"] = "Secure updated"; } if (ci->HasExt("SECUREOPS") != message.post_data.count("secureops")) { if (!ci->HasExt("SECUREOPS")) - ci->ExtendMetadata("SECUREOPS"); + ci->Extend<bool>("SECUREOPS"); else - ci->Shrink("SECUREOPS"); + ci->Shrink<bool>("SECUREOPS"); replacements["MESSAGES"] = "Secureops updated"; } if (ci->HasExt("TOPICLOCK") != message.post_data.count("topiclock")) { if (!ci->HasExt("TOPICLOCK")) - ci->ExtendMetadata("TOPICLOCK"); + ci->Extend<bool>("TOPICLOCK"); else - ci->Shrink("TOPICLOCK"); + ci->Shrink<bool>("TOPICLOCK"); replacements["MESSAGES"] = "Topiclock updated"; } } @@ -108,13 +108,13 @@ bool WebCPanel::ChanServ::Set::OnRequest(HTTPProvider *server, const Anope::stri if (ci->HasExt("PEACE")) replacements["PEACE"]; - if (ci->HasExt("PRIVATE")) + if (ci->HasExt("CS_PRIVATE")) replacements["PRIVATE"]; if (ci->HasExt("RESTRICTED")) replacements["RESTRICTED"]; - if (ci->HasExt("SECURE")) + if (ci->HasExt("CS_SECURE")) replacements["SECURE"]; if (ci->HasExt("SECUREOPS")) diff --git a/modules/extra/webcpanel/pages/index.cpp b/modules/extra/webcpanel/pages/index.cpp index 51b908b13..be4bbbc6d 100644 --- a/modules/extra/webcpanel/pages/index.cpp +++ b/modules/extra/webcpanel/pages/index.cpp @@ -40,8 +40,8 @@ class WebpanelRequest : public IdentifyRequest id += c; } - na->Extend("webcpanel_id", new ExtensibleItemClass<Anope::string>(id)); - na->Extend("webcpanel_ip", new ExtensibleItemClass<Anope::string>(client->GetIP())); + na->Extend<Anope::string>("webcpanel_id", id); + na->Extend<Anope::string>("webcpanel_ip", client->GetIP()); { HTTPReply::cookie c; diff --git a/modules/extra/webcpanel/pages/logout.cpp b/modules/extra/webcpanel/pages/logout.cpp index 14e1c24b5..8fafdcd4e 100644 --- a/modules/extra/webcpanel/pages/logout.cpp +++ b/modules/extra/webcpanel/pages/logout.cpp @@ -13,8 +13,8 @@ WebCPanel::Logout::Logout(const Anope::string &u) : WebPanelProtectedPage("", u) bool WebCPanel::Logout::OnRequest(HTTPProvider *server, const Anope::string &page_name, HTTPClient *client, HTTPMessage &message, HTTPReply &reply, NickAlias *na, TemplateFileServer::Replacements &replacements) { - na->Shrink("webcpanel_id"); - na->Shrink("webcpanel_ip"); + na->Shrink<Anope::string>("webcpanel_id"); + na->Shrink<Anope::string>("webcpanel_ip"); reply.error = HTTP_FOUND; reply.headers["Location"] = Anope::string("http") + (use_ssl ? "s" : "") + "://" + message.headers["Host"] + "/"; diff --git a/modules/extra/webcpanel/pages/nickserv/alist.cpp b/modules/extra/webcpanel/pages/nickserv/alist.cpp index 0afe2a4f3..a0568f5b4 100644 --- a/modules/extra/webcpanel/pages/nickserv/alist.cpp +++ b/modules/extra/webcpanel/pages/nickserv/alist.cpp @@ -24,7 +24,7 @@ bool WebCPanel::NickServ::Alist::OnRequest(HTTPProvider *server, const Anope::st ++chan_count; replacements["NUMBERS"] = stringify(chan_count); - replacements["CHANNELS"] = (ci->HasExt("NO_EXPIRE") ? "!" : "") + ci->name; + replacements["CHANNELS"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name; replacements["ACCESSES"] = "Founder"; continue; } @@ -36,7 +36,7 @@ bool WebCPanel::NickServ::Alist::OnRequest(HTTPProvider *server, const Anope::st ++chan_count; replacements["NUMBERS"] = stringify(chan_count); - replacements["CHANNELS"] = (ci->HasExt("NO_EXPIRE") ? "!" : "") + ci->name; + replacements["CHANNELS"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name; Anope::string access_str; for (unsigned i = 0; i < access.size(); ++i) access_str += ", " + access[i]->AccessSerialize(); diff --git a/modules/extra/webcpanel/pages/nickserv/cert.cpp b/modules/extra/webcpanel/pages/nickserv/cert.cpp index 9ac95453a..ff9885405 100644 --- a/modules/extra/webcpanel/pages/nickserv/cert.cpp +++ b/modules/extra/webcpanel/pages/nickserv/cert.cpp @@ -6,6 +6,7 @@ */ #include "../../webcpanel.h" +#include "modules/ns_cert.h" WebCPanel::NickServ::Cert::Cert(const Anope::string &cat, const Anope::string &u) : WebPanelProtectedPage(cat, u) { @@ -30,8 +31,10 @@ bool WebCPanel::NickServ::Cert::OnRequest(HTTPProvider *server, const Anope::str WebPanel::RunCommand(na->nc->display, na->nc, "NickServ", "nickserv/cert", params, replacements); } - for (unsigned i = 0; i < na->nc->cert.size(); ++i) - replacements["CERTS"] = na->nc->cert[i]; + NSCertList *cl = na->nc->GetExt<NSCertList>("certificates"); + if (cl) + for (unsigned i = 0; i < cl->GetCertCount(); ++i) + replacements["CERTS"] = cl->GetCert(i); TemplateFileServer page("nickserv/cert.html"); page.Serve(server, page_name, client, message, reply, replacements); diff --git a/modules/extra/webcpanel/pages/nickserv/info.cpp b/modules/extra/webcpanel/pages/nickserv/info.cpp index 35a4a8a0a..65f0e4c8a 100644 --- a/modules/extra/webcpanel/pages/nickserv/info.cpp +++ b/modules/extra/webcpanel/pages/nickserv/info.cpp @@ -30,52 +30,56 @@ bool WebCPanel::NickServ::Info::OnRequest(HTTPProvider *server, const Anope::str } if (message.post_data.count("greet") > 0) { - if (message.post_data["greet"].replace_all_cs("+", " ") != na->nc->greet) - { - na->nc->greet = HTTPUtils::URLDecode(message.post_data["greet"]); - replacements["MESSAGES"] = "Greet updated"; - } + Anope::string *greet = na->nc->GetExt<Anope::string>("greet"); + const Anope::string &post_greet = HTTPUtils::URLDecode(message.post_data["greet"].replace_all_cs("+", " ")); + + if (post_greet.empty()) + na->nc->Shrink<Anope::string>("greet"); + else if (!greet || post_greet != *greet) + na->nc->Extend<Anope::string>("greet", post_greet); + + replacements["MESSAGES"] = "Greet updated"; } if (na->nc->HasExt("AUTOOP") != message.post_data.count("autoop")) { if (!na->nc->HasExt("AUTOOP")) - na->nc->ExtendMetadata("AUTOOP"); + na->nc->Extend<bool>("AUTOOP"); else - na->nc->Shrink("AUTOOP"); + na->nc->Shrink<bool>("AUTOOP"); replacements["MESSAGES"] = "Autoop updated"; } - if (na->nc->HasExt("PRIVATE") != message.post_data.count("private")) + if (na->nc->HasExt("NS_PRIVATE") != message.post_data.count("private")) { - if (!na->nc->HasExt("PRIVATE")) - na->nc->ExtendMetadata("PRIVATE"); + if (!na->nc->HasExt("NS_PRIVATE")) + na->nc->Extend<bool>("NS_PRIVATE"); else - na->nc->Shrink("PRIVATE"); + na->nc->Shrink<bool>("NS_PRIVATE"); replacements["MESSAGES"] = "Private updated"; } - if (na->nc->HasExt("SECURE") != message.post_data.count("secure")) + if (na->nc->HasExt("NS_SECURE") != message.post_data.count("secure")) { - if (!na->nc->HasExt("SECURE")) - na->nc->ExtendMetadata("SECURE"); + if (!na->nc->HasExt("NS_SECURE")) + na->nc->Extend<bool>("NS_SECURE"); else - na->nc->Shrink("SECURE"); + na->nc->Shrink<bool>("NS_SECURE"); replacements["MESSAGES"] = "Secure updated"; } if (message.post_data["kill"] == "on" && !na->nc->HasExt("KILLPROTECT")) { - na->nc->ExtendMetadata("KILLPROTECT"); - na->nc->Shrink("KILL_QUICK"); + na->nc->Extend<bool>("KILLPROTECT"); + na->nc->Shrink<bool>("KILL_QUICK"); replacements["MESSAGES"] = "Kill updated"; } else if (message.post_data["kill"] == "quick" && !na->nc->HasExt("KILL_QUICK")) { - na->nc->Shrink("KILLPROTECT"); - na->nc->ExtendMetadata("KILL_QUICK"); + na->nc->Shrink<bool>("KILLPROTECT"); + na->nc->Extend<bool>("KILL_QUICK"); replacements["MESSAGES"] = "Kill updated"; } else if (message.post_data["kill"] == "off" && (na->nc->HasExt("KILLPROTECT") || na->nc->HasExt("KILL_QUICK"))) { - na->nc->Shrink("KILLPROTECT"); - na->nc->Shrink("KILL_QUICK"); + na->nc->Shrink<bool>("KILLPROTECT"); + na->nc->Shrink<bool>("KILL_QUICK"); replacements["MESSAGES"] = "Kill updated"; } } @@ -91,12 +95,14 @@ bool WebCPanel::NickServ::Info::OnRequest(HTTPProvider *server, const Anope::str else replacements["VHOST"] = na->GetVhostHost(); } - replacements["GREET"] = HTTPUtils::Escape(na->nc->greet); + Anope::string *greet = na->nc->GetExt<Anope::string>("greet"); + if (greet) + replacements["GREET"] = HTTPUtils::Escape(*greet); if (na->nc->HasExt("AUTOOP")) replacements["AUTOOP"]; - if (na->nc->HasExt("PRIVATE")) + if (na->nc->HasExt("NS_PRIVATE")) replacements["PRIVATE"]; - if (na->nc->HasExt("SECURE")) + if (na->nc->HasExt("NS_SECURE")) replacements["SECURE"]; if (na->nc->HasExt("KILLPROTECT")) replacements["KILL_ON"]; diff --git a/modules/extra/webcpanel/webcpanel.cpp b/modules/extra/webcpanel/webcpanel.cpp index 4610c6235..c8926a150 100644 --- a/modules/extra/webcpanel/webcpanel.cpp +++ b/modules/extra/webcpanel/webcpanel.cpp @@ -15,6 +15,7 @@ class ModuleWebCPanel : public Module { ServiceReference<HTTPProvider> provider; Panel panel; + PrimitiveExtensibleItem<Anope::string> id, ip; StaticFileServer style_css, logo_png, favicon_ico; @@ -43,7 +44,7 @@ class ModuleWebCPanel : public Module public: ModuleWebCPanel(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), - panel(this, "webcpanel"), + panel(this, "webcpanel"), id(this, "webcpanel_id"), ip(this, "webcpanel_ip"), style_css("style.css", "/static/style.css", "text/css"), logo_png("logo.png", "/static/logo.png", "image/png"), favicon_ico("favicon.ico", "/favicon.ico", "image/x-icon"), index("/"), logout("/logout"), _register("/register"), confirm("/confirm"), nickserv_info("NickServ", "/nickserv/info"), nickserv_cert("NickServ", "/nickserv/cert"), nickserv_access("NickServ", "/nickserv/access"), nickserv_alist("NickServ", "/nickserv/alist"), diff --git a/modules/extra/webcpanel/webcpanel.h b/modules/extra/webcpanel/webcpanel.h index 359bde32b..638a7c1c9 100644 --- a/modules/extra/webcpanel/webcpanel.h +++ b/modules/extra/webcpanel/webcpanel.h @@ -50,7 +50,7 @@ class Panel : public Section, public Service if (na == NULL) return NULL; - Anope::string *n_id = na->GetExt<ExtensibleItemClass<Anope::string> *>("webcpanel_id"), *n_ip = na->GetExt<ExtensibleItemClass<Anope::string> *>("webcpanel_ip"); + Anope::string *n_id = na->GetExt<Anope::string>("webcpanel_id"), *n_ip = na->GetExt<Anope::string>("webcpanel_ip"); if (n_id == NULL || n_ip == NULL) return NULL; else if (id != *n_id) diff --git a/modules/fantasy.cpp b/modules/fantasy.cpp new file mode 100644 index 000000000..01271392b --- /dev/null +++ b/modules/fantasy.cpp @@ -0,0 +1,200 @@ +/* Fantasy functionality + * + * (C) 2003-2013 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 CommandBSSetFantasy : public Command +{ + public: + CommandBSSetFantasy(Module *creator, const Anope::string &sname = "botserv/set/fantasy") : Command(creator, sname, 2, 2) + { + this->SetDesc(_("Enable fantaisist commands")); + this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + ChannelInfo *ci = ChannelInfo::Find(params[0]); + const Anope::string &value = params[1]; + + if (ci == NULL) + { + source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + return; + } + + if (!source.HasPriv("botserv/administration") && !source.AccessFor(ci).HasPriv("SET")) + { + source.Reply(ACCESS_DENIED); + return; + } + + if (Anope::ReadOnly) + { + source.Reply(_("Sorry, bot option setting is temporarily disabled.")); + return; + } + + if (value.equals_ci("ON")) + { + bool override = !source.AccessFor(ci).HasPriv("SET"); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable fantasy"; + + ci->Extend<bool>("BS_FANTASY"); + source.Reply(_("Fantasy mode is now \002on\002 on channel %s."), ci->name.c_str()); + } + else if (value.equals_ci("OFF")) + { + bool override = !source.AccessFor(ci).HasPriv("SET"); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable fantasy"; + + ci->Shrink<bool>("BS_FANTASY"); + source.Reply(_("Fantasy mode is now \002off\002 on channel %s."), ci->name.c_str()); + } + else + this->OnSyntaxError(source, source.command); + } + + bool OnHelp(CommandSource &source, const Anope::string &) anope_override + { + this->SendSyntax(source); + source.Reply(_(" \n" + "Enables or disables \002fantasy\002 mode on a channel.\n" + "When it is enabled, users will be able to use\n" + "fantasy commands on a channel when prefixed\n" + "with one of the following fantasy characters: \002%s\002\n" + " \n" + "Note that users wanting to use fantaisist\n" + "commands MUST have enough access for both\n" + "the FANTASIA and the command they are executing."), + Config->GetModule(this->owner)->Get<const Anope::string>("fantasycharacter", "!").c_str()); + return true; + } +}; + +class Fantasy : public Module +{ + SerializableExtensibleItem<bool> fantasy; + + CommandBSSetFantasy commandbssetfantasy; + + public: + Fantasy(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), + fantasy(this, "BS_FANTASY"), commandbssetfantasy(this) + { + } + + void OnPrivmsg(User *u, Channel *c, Anope::string &msg) anope_override + { + if (!u || !c || !c->ci || !c->ci->bi || msg.empty() || msg[0] == '\1') + return; + + if (!fantasy.HasExt(c->ci)) + return; + + std::vector<Anope::string> params; + spacesepstream(msg).GetTokens(params); + + if (!msg.find(c->ci->bi->nick)) + params.erase(params.begin()); + else if (!msg.find_first_of(Config->GetModule(this)->Get<const Anope::string>("fantasycharacter", "!"))) + params[0].erase(params[0].begin()); + else + return; + + if (params.empty()) + return; + + CommandInfo::map::const_iterator it = Config->Fantasy.end(); + unsigned count = 0; + for (unsigned max = params.size(); it == Config->Fantasy.end() && max > 0; --max) + { + Anope::string full_command; + for (unsigned i = 0; i < max; ++i) + full_command += " " + params[i]; + full_command.erase(full_command.begin()); + + ++count; + it = Config->Fantasy.find(full_command); + } + + if (it == Config->Fantasy.end()) + return; + + const CommandInfo &info = it->second; + ServiceReference<Command> cmd("Command", info.name); + if (!cmd) + { + Log(LOG_DEBUG) << "Fantasy command " << it->first << " exists for nonexistant service " << info.name << "!"; + return; + } + + for (unsigned i = 0, j = params.size() - (count - 1); i < j; ++i) + params.erase(params.begin()); + + /* Some commands take the channel as a first parameter */ + if (info.prepend_channel) + params.insert(params.begin(), c->name); + + while (cmd->max_params > 0 && params.size() > cmd->max_params) + { + params[cmd->max_params - 1] += " " + params[cmd->max_params]; + params.erase(params.begin() + cmd->max_params); + } + + // Command requires registered users only + if (!cmd->AllowUnregistered() && !u->Account()) + return; + + if (params.size() < cmd->min_params) + return; + + CommandSource source(u->nick, u, u->Account(), u, c->ci->bi); + source.c = c; + source.command = it->first; + source.permission = info.permission; + + EventReturn MOD_RESULT; + if (c->ci->AccessFor(u).HasPriv("FANTASIA")) + { + FOREACH_RESULT(OnBotFantasy, MOD_RESULT, (source, cmd, c->ci, params)); + } + else + { + FOREACH_RESULT(OnBotNoFantasyAccess, MOD_RESULT, (source, cmd, c->ci, params)); + } + + if (MOD_RESULT == EVENT_STOP || !c->ci->AccessFor(u).HasPriv("FANTASIA")) + return; + + if (MOD_RESULT != EVENT_ALLOW && !info.permission.empty() && !source.HasCommand(info.permission)) + return; + + FOREACH_RESULT(OnPreCommand, MOD_RESULT, (source, cmd, params)); + if (MOD_RESULT == EVENT_STOP) + return; + + Reference<NickCore> nc_reference(u->Account()); + cmd->Execute(source, params); + if (!nc_reference) + source.nc = NULL; + FOREACH_MOD(OnPostCommand, (source, cmd, params)); + } + + void OnBotInfo(CommandSource &source, BotInfo *bi, ChannelInfo *ci, InfoFormatter &info) + { + if (fantasy.HasExt(ci)) + info.AddOption(_("Fantasy")); + } +}; + +MODULE_INIT(Fantasy) + diff --git a/modules/m_dnsbl.cpp b/modules/m_dnsbl.cpp index 8a238889f..b12476515 100644 --- a/modules/m_dnsbl.cpp +++ b/modules/m_dnsbl.cpp @@ -34,7 +34,7 @@ class DNSBLResolver : public Request void OnLookupComplete(const Query *record) anope_override { - if (!user || user->HasExt("m_dnsbl_akilled")) + if (!user || user->Quitting()) return; const ResourceRecord &ans_record = record->answers[0]; @@ -54,8 +54,6 @@ class DNSBLResolver : public Request record_reason = this->blacklist.replies[result]; } - user->Extend("m_dnsbl_akilled"); - Anope::string reason = this->blacklist.reason; reason = reason.replace_all_cs("%n", user->nick); reason = reason.replace_all_cs("%u", user->GetIdent()); diff --git a/modules/m_helpchan.cpp b/modules/m_helpchan.cpp index 7739fbcd5..0a3d68fae 100644 --- a/modules/m_helpchan.cpp +++ b/modules/m_helpchan.cpp @@ -14,9 +14,9 @@ class HelpChannel : public Module { } - EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, const Anope::string &mname, const Anope::string ¶m) anope_override + EventReturn OnChannelModeSet(Channel *c, MessageSource &, ChannelMode *mode, const Anope::string ¶m) anope_override { - if (mname == "OP" && c && c->ci && c->name.equals_ci(Config->GetModule(this)->Get<const Anope::string>("helpchannel"))) + if (mode->name == "OP" && c && c->ci && c->name.equals_ci(Config->GetModule(this)->Get<const Anope::string>("helpchannel"))) { User *u = User::Find(param); diff --git a/modules/protocol/charybdis.cpp b/modules/protocol/charybdis.cpp index cc9f8a58b..7d34da8d2 100644 --- a/modules/protocol/charybdis.cpp +++ b/modules/protocol/charybdis.cpp @@ -10,6 +10,7 @@ */ #include "module.h" +#include "modules/cs_mode.h" static bool sasl = true; static Anope::string UplinkSID; @@ -435,19 +436,24 @@ class ProtoCharybdis : public Module void OnChannelSync(Channel *c) anope_override { - if (use_server_side_mlock && c->ci && Servers::Capab.count("MLOCK") > 0) + if (!c->ci) + return; + + ModeLocks *modelocks = c->ci->GetExt<ModeLocks>("modelocks"); + if (use_server_side_mlock && modelocks && Servers::Capab.count("MLOCK") > 0) { - Anope::string modes = c->ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); + Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(c->creation_time) << " " << c->ci->name << " " << modes; } } EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) anope_override { + ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); - if (use_server_side_mlock && cm && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) + if (use_server_side_mlock && cm && ci->c && modelocks && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) { - Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar; + Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar; UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; } @@ -456,10 +462,11 @@ class ProtoCharybdis : public Module EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) anope_override { + ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); - if (use_server_side_mlock && cm && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) + if (use_server_side_mlock && cm && modelocks && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) { - Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, ""); + Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, ""); UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; } diff --git a/modules/protocol/inspircd12.cpp b/modules/protocol/inspircd12.cpp index 3a2eb2d8a..876d387d1 100644 --- a/modules/protocol/inspircd12.cpp +++ b/modules/protocol/inspircd12.cpp @@ -947,7 +947,7 @@ struct IRCDMessageMetadata : IRCDMessage User *u = User::Find(params[0]); if (!u) return; - u->Extend("SSL"); + u->Extend<bool>("ssl"); Anope::string data = params[2].c_str(); size_t pos1 = data.find(' ') + 1; size_t pos2 = data.find(' ', pos1); @@ -1271,6 +1271,7 @@ struct IRCDMessageEncap : IRCDMessage class ProtoInspIRCd : public Module { InspIRCd12Proto ircd_proto; + ExtensibleItem<bool> ssl; /* Core message handlers */ Message::Away message_away; @@ -1311,7 +1312,7 @@ class ProtoInspIRCd : public Module public: ProtoInspIRCd(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL | VENDOR), - ircd_proto(this), + ircd_proto(this), ssl(this, "ssl"), message_away(this), message_error(this), message_invite(this), message_join(this), message_kick(this), message_kill(this), message_motd(this), message_part(this), message_ping(this), message_privmsg(this), message_quit(this), message_squit(this), message_stats(this), message_topic(this), diff --git a/modules/protocol/inspircd20.cpp b/modules/protocol/inspircd20.cpp index 73f573e5b..c251b93b8 100644 --- a/modules/protocol/inspircd20.cpp +++ b/modules/protocol/inspircd20.cpp @@ -10,6 +10,7 @@ */ #include "module.h" +#include "modules/cs_mode.h" static unsigned int spanningtree_proto_ver = 0; @@ -137,7 +138,7 @@ class InspIRCdExtBan : public ChannelModeList { Anope::string real_mask = mask.substr(2); - if (Anope::Match(u->fingerprint, real_mask)) + if (!u->fingerprint.empty() && Anope::Match(u->fingerprint, real_mask)) return true; } @@ -759,9 +760,10 @@ class ProtoInspIRCd : public Module void OnChanRegistered(ChannelInfo *ci) anope_override { - if (use_server_side_mlock && ci->c && !ci->GetMLockAsString(false).empty()) + ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); + if (use_server_side_mlock && ci->c && modelocks && !modelocks->GetMLockAsString(false).empty()) { - Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); + Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); SendChannelMetadata(ci->c, "mlock", modes); } @@ -783,10 +785,11 @@ class ProtoInspIRCd : public Module EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) anope_override { + ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); - if (use_server_side_mlock && cm && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM)) + if (use_server_side_mlock && cm && ci->c && modelocks && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM)) { - Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar; + Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar; SendChannelMetadata(ci->c, "mlock", modes); } @@ -795,10 +798,11 @@ class ProtoInspIRCd : public Module EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) anope_override { + ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); - if (use_server_side_mlock && cm && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM)) + if (use_server_side_mlock && cm && ci->c && modelocks && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM)) { - Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, ""); + Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, ""); SendChannelMetadata(ci->c, "mlock", modes); } diff --git a/modules/protocol/unreal.cpp b/modules/protocol/unreal.cpp index 5e6534409..856a4aeb4 100644 --- a/modules/protocol/unreal.cpp +++ b/modules/protocol/unreal.cpp @@ -10,6 +10,7 @@ */ #include "module.h" +#include "modules/cs_mode.h" static bool sasl = true; @@ -1226,18 +1227,23 @@ class ProtoUnreal : public Module void OnChannelSync(Channel *c) anope_override { - if (use_server_side_mlock && Servers::Capab.count("MLOCK") > 0 && c->ci) + if (!c->ci) + return; + + ModeLocks *modelocks = c->ci->GetExt<ModeLocks>("modelocks"); + if (use_server_side_mlock && Servers::Capab.count("MLOCK") > 0 && modelocks) { - Anope::string modes = c->ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); + Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(c->creation_time) << " " << c->ci->name << " " << modes; } } void OnChanRegistered(ChannelInfo *ci) anope_override { - if (!ci->c || !use_server_side_mlock || !Servers::Capab.count("MLOCK")) + ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); + if (!ci->c || !use_server_side_mlock || !modelocks || !Servers::Capab.count("MLOCK")) return; - Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); + Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", ""); UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; } @@ -1250,10 +1256,11 @@ class ProtoUnreal : public Module EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) anope_override { + ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); - if (use_server_side_mlock && cm && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) + if (use_server_side_mlock && cm && modelocks && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) { - Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar; + Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar; UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; } @@ -1262,10 +1269,11 @@ class ProtoUnreal : public Module EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) anope_override { + ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks"); ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); - if (use_server_side_mlock && cm && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) + if (use_server_side_mlock && cm && modelocks && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0) { - Anope::string modes = ci->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, ""); + Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, ""); UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes; } diff --git a/modules/pseudoclients/botserv.cpp b/modules/pseudoclients/botserv.cpp index 8322ad3c3..e8452de13 100644 --- a/modules/pseudoclients/botserv.cpp +++ b/modules/pseudoclients/botserv.cpp @@ -14,9 +14,11 @@ class BotServCore : public Module { Reference<BotInfo> BotServ; + ExtensibleRef<bool> persist, inhabit; public: - BotServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR) + BotServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR), + persist("persist"), inhabit("inhabit") { } @@ -54,121 +56,6 @@ class BotServCore : public Module } } - void OnPrivmsg(User *u, Channel *c, Anope::string &msg) anope_override - { - if (!u || !c || !c->ci || !c->ci->bi || msg.empty()) - return; - - /* Answer to ping if needed */ - if (msg.substr(0, 6).equals_ci("\1PING ") && msg[msg.length() - 1] == '\1') - { - Anope::string ctcp = msg; - ctcp.erase(ctcp.begin()); - ctcp.erase(ctcp.length() - 1); - IRCD->SendCTCP(c->ci->bi, u->nick, "%s", ctcp.c_str()); - } - - Anope::string realbuf = msg; - - if (realbuf.substr(0, 8).equals_ci("\1ACTION ") && realbuf[realbuf.length() - 1] == '\1') - { - realbuf.erase(0, 8); - realbuf.erase(realbuf.length() - 1); - return; - } - - if (realbuf.empty() || !c->ci->HasExt("BS_FANTASY")) - return; - - std::vector<Anope::string> params; - spacesepstream(realbuf).GetTokens(params); - - if (!realbuf.find(c->ci->bi->nick)) - params.erase(params.begin()); - else if (!realbuf.find_first_of(Config->GetModule(this)->Get<const Anope::string>("fantasycharacter", "!"))) - params[0].erase(params[0].begin()); - else - return; - - if (params.empty()) - return; - - CommandInfo::map::const_iterator it = Config->Fantasy.end(); - unsigned count = 0; - for (unsigned max = params.size(); it == Config->Fantasy.end() && max > 0; --max) - { - Anope::string full_command; - for (unsigned i = 0; i < max; ++i) - full_command += " " + params[i]; - full_command.erase(full_command.begin()); - - ++count; - it = Config->Fantasy.find(full_command); - } - - if (it == Config->Fantasy.end()) - return; - - const CommandInfo &info = it->second; - ServiceReference<Command> cmd("Command", info.name); - if (!cmd) - { - Log(LOG_DEBUG) << "Fantasy command " << it->first << " exists for nonexistant service " << info.name << "!"; - return; - } - - for (unsigned i = 0, j = params.size() - (count - 1); i < j; ++i) - params.erase(params.begin()); - - /* Some commands take the channel as a first parameter */ - if (info.prepend_channel) - params.insert(params.begin(), c->name); - - while (cmd->max_params > 0 && params.size() > cmd->max_params) - { - params[cmd->max_params - 1] += " " + params[cmd->max_params]; - params.erase(params.begin() + cmd->max_params); - } - - // Command requires registered users only - if (!cmd->AllowUnregistered() && !u->Account()) - return; - - if (params.size() < cmd->min_params) - return; - - CommandSource source(u->nick, u, u->Account(), u, c->ci->bi); - source.c = c; - source.command = it->first; - source.permission = info.permission; - - EventReturn MOD_RESULT; - if (c->ci->AccessFor(u).HasPriv("FANTASIA")) - { - FOREACH_RESULT(OnBotFantasy, MOD_RESULT, (source, cmd, c->ci, params)); - } - else - { - FOREACH_RESULT(OnBotNoFantasyAccess, MOD_RESULT, (source, cmd, c->ci, params)); - } - - if (MOD_RESULT == EVENT_STOP || !c->ci->AccessFor(u).HasPriv("FANTASIA")) - return; - - if (MOD_RESULT != EVENT_ALLOW && !info.permission.empty() && !source.HasCommand(info.permission)) - return; - - FOREACH_RESULT(OnPreCommand, MOD_RESULT, (source, cmd, params)); - if (MOD_RESULT == EVENT_STOP) - return; - - Reference<NickCore> nc_reference(u->Account()); - cmd->Execute(source, params); - if (!nc_reference) - source.nc = NULL; - FOREACH_MOD(OnPostCommand, (source, cmd, params)); - } - void OnJoinChannel(User *user, Channel *c) anope_override { if (!Config || !IRCD) @@ -221,22 +108,13 @@ class BotServCore : public Module ChannelStatus status(Config->GetModule(this)->Get<const Anope::string>("botmodes")); c->ci->bi->Join(c, &status); } - /* Only display the greet if the main uplink we're connected - * to has synced, or we'll get greet-floods when the net - * recovers from a netsplit. -GD - */ - if (c->FindUser(c->ci->bi) && c->ci->HasExt("BS_GREET") && user->Account() && !user->Account()->greet.empty() && c->ci->AccessFor(user).HasPriv("GREET") && user->server->IsSynced()) - { - IRCD->SendPrivmsg(c->ci->bi, c->name, "[%s] %s", user->Account()->display.c_str(), user->Account()->greet.c_str()); - c->ci->bi->lastmsg = Anope::CurTime; - } } } void OnLeaveChannel(User *u, Channel *c) anope_override { /* Channel is persistent, it shouldn't be deleted and the service bot should stay */ - if (c->ci && c->ci->HasExt("PERSIST")) + if (c->ci && persist && persist->Get(c->ci)) return; /* Channel is syncing from a netburst, don't destroy it as more users are probably wanting to join immediatly @@ -246,7 +124,7 @@ class BotServCore : public Module return; /* Additionally, do not delete this channel if ChanServ/a BotServ bot is inhabiting it */ - if (c->HasExt("INHABIT")) + if (inhabit && inhabit->Get(c)) return; /* This is called prior to removing the user from the channnel, so c->users.size() - 1 should be safe */ @@ -304,9 +182,9 @@ class BotServCore : public Module "one of the following characters: %s"), fantasycharacters.c_str()); } - EventReturn OnChannelModeSet(Channel *c, MessageSource &, const Anope::string &mname, const Anope::string ¶m) anope_override + EventReturn OnChannelModeSet(Channel *c, MessageSource &, ChannelMode *mode, const Anope::string ¶m) anope_override { - if (Config->GetModule(this)->Get<bool>("smartjoin") && mname == "BAN" && c->ci && c->ci->bi && c->FindUser(c->ci->bi)) + if (Config->GetModule(this)->Get<bool>("smartjoin") && mode->name == "BAN" && c->ci && c->ci->bi && c->FindUser(c->ci->bi)) { BotInfo *bi = c->ci->bi; @@ -323,7 +201,7 @@ class BotServCore : public Module /* Set default bot flags */ spacesepstream sep(Config->GetModule(this)->Get<const Anope::string>("defaults", "greet fantasy")); for (Anope::string token; sep.GetToken(token);) - ci->ExtendMetadata("BS_" + token.upper()); + ci->Extend<bool>("BS_" + token.upper()); } void OnUserKicked(MessageSource &source, User *target, const Anope::string &channel, ChannelStatus &status, const Anope::string &kickmsg) anope_override diff --git a/modules/pseudoclients/chanserv.cpp b/modules/pseudoclients/chanserv.cpp index a6871189c..2f7147cc6 100644 --- a/modules/pseudoclients/chanserv.cpp +++ b/modules/pseudoclients/chanserv.cpp @@ -10,15 +10,18 @@ */ #include "module.h" +#include "modules/cs_mode.h" class ChanServCore : public Module, public ChanServService { Reference<BotInfo> ChanServ; std::vector<Anope::string> defaults; + ExtensibleItem<bool> inhabit; + ExtensibleRef<bool> persist; public: ChanServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR), - ChanServService(this) + ChanServService(this), inhabit(this, "inhabit"), persist("PERSIST") { } @@ -30,17 +33,18 @@ class ChanServCore : public Module, public ChanServService class ChanServTimer : public Timer { Reference<BotInfo> &ChanServ; + ExtensibleItem<bool> &inhabit; Reference<Channel> c; public: /** Constructor * @param chan The channel */ - ChanServTimer(Reference<BotInfo> &cs, Module *m, Channel *chan) : Timer(m, Config->GetModule(m)->Get<time_t>("inhabit", "15s")), ChanServ(cs), c(chan) + ChanServTimer(Reference<BotInfo> &cs, ExtensibleItem<bool> &i, Module *m, Channel *chan) : Timer(m, Config->GetModule(m)->Get<time_t>("inhabit", "15s")), ChanServ(cs), inhabit(i), c(chan) { if (!ChanServ || !c) return; - c->Extend("INHABIT"); + inhabit.Set(c, true); if (!c->ci || !c->ci->bi) ChanServ->Join(c); else if (!c->FindUser(c->ci->bi)) @@ -61,7 +65,7 @@ class ChanServCore : public Module, public ChanServService if (!c) return; - c->Shrink("INHABIT"); + inhabit.Unset(c); if (!c->ci || !c->ci->bi) { @@ -73,10 +77,10 @@ class ChanServCore : public Module, public ChanServService } }; - if (c->HasExt("INHABIT")) + if (inhabit.HasExt(c)) return; - new ChanServTimer(ChanServ, this->owner, c); + new ChanServTimer(ChanServ, inhabit, this->owner, c); } void OnReload(Configuration::Conf *conf) anope_override @@ -96,7 +100,7 @@ class ChanServCore : public Module, public ChanServService if (defaults.empty()) { defaults.push_back("KEEPTOPIC"); - defaults.push_back("SECURE"); + defaults.push_back("CS_SECURE"); defaults.push_back("SECUREFOUNDER"); defaults.push_back("SIGNKICK"); } @@ -243,34 +247,9 @@ class ChanServCore : public Module, public ChanServService void OnCreateChan(ChannelInfo *ci) anope_override { - ci->bantype = Config->GetModule(this)->Get<int>("defbantype", "2"); - /* Set default chan flags */ for (unsigned i = 0; i < defaults.size(); ++i) - ci->ExtendMetadata(defaults[i].upper()); - - { - Anope::string modes; - spacesepstream sep(Config->GetModule(this)->Get<const Anope::string>("mlock", "+nrt")); - if (sep.GetToken(modes)) - { - bool add = true; - for (unsigned i = 0; i < modes.length(); ++i) - { - if (modes[i] == '+') - add = true; - else if (modes[i] == '-') - add = false; - else - { - ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]); - Anope::string param; - if (cm && (cm->type == MODE_REGULAR || sep.GetToken(param))) - ci->SetMLock(cm, add, param); - } - } - } - } + ci->Extend<bool>(defaults[i].upper()); } EventReturn OnCanSet(User *u, const ChannelMode *cm) anope_override @@ -283,21 +262,13 @@ class ChanServCore : public Module, public ChanServService void OnChannelSync(Channel *c) anope_override { - bool perm = c->HasMode("PERM") || (c->ci && c->ci->HasExt("PERSIST")); - if (!perm && !c->HasExt("BOTCHANNEL") && (c->users.empty() || (c->users.size() == 1 && c->users.begin()->second->user->server == Me))) + bool perm = c->HasMode("PERM") || (c->ci && persist && persist->Get(c->ci)); + if (!perm && !c->botchannel && (c->users.empty() || (c->users.size() == 1 && c->users.begin()->second->user->server == Me))) { this->Hold(c); } c->CheckModes(); - if (Me && Me->IsSynced() && c->ci) - { - /* Update channel topic */ - if ((c->ci->HasExt("KEEPTOPIC") || c->ci->HasExt("TOPICLOCK")) && c->ci->last_topic != c->topic) - { - c->ChangeTopic(!c->ci->last_topic_setter.empty() ? c->ci->last_topic_setter : c->ci->WhoSends()->nick, c->ci->last_topic, c->ci->last_topic_time ? c->ci->last_topic_time : Anope::CurTime); - } - } } EventReturn OnBotKick(BotInfo *bi, Channel *c, User *u, const Anope::string &reason) @@ -307,7 +278,7 @@ class ChanServCore : public Module, public ChanServService * ChanServ always enforces channels like this to keep people from deleting bots etc * that are holding channels. */ - if (c->ci && c->users.size() == (c->ci->bi && c->FindUser(c->ci->bi) ? 2 : 1) && !c->HasExt("INHABIT") && !c->syncing) + if (c->ci && c->users.size() == (c->ci->bi && c->FindUser(c->ci->bi) ? 2 : 1) && !inhabit.HasExt(c) && !c->syncing) { /* Join ChanServ and set a timer for this channel to part ChanServ later */ this->Hold(c); @@ -349,18 +320,11 @@ class ChanServCore : public Module, public ChanServService expire = true; } - if (ci->HasExt("NO_EXPIRE")) - expire = false; - FOREACH_MOD(OnPreChanExpire, (ci, expire)); if (expire) { - Anope::string extra; - if (ci->HasExt("SUSPENDED")) - extra = "suspended "; - - Log(LOG_NORMAL, "chanserv/expire") << "Expiring " << extra << "channel " << ci->name << " (founder: " << (ci->GetFounder() ? ci->GetFounder()->display : "(none)") << ")"; + Log(LOG_NORMAL, "chanserv/expire") << "Expiring channel " << ci->name << " (founder: " << (ci->GetFounder() ? ci->GetFounder()->display : "(none)") << ")"; FOREACH_MOD(OnChanExpire, (ci)); delete ci; } @@ -370,11 +334,11 @@ class ChanServCore : public Module, public ChanServService EventReturn OnCheckDelete(Channel *c) anope_override { /* Do not delete this channel if ChanServ/a BotServ bot is inhabiting it */ - if (c->HasExt("INHABIT")) + if (inhabit.HasExt(c)) return EVENT_STOP; /* Channel is persistent, it shouldn't be deleted and the service bot should stay */ - if (c->ci && c->ci->HasExt("PERSIST")) + if (c->ci && persist && persist->Get(c->ci)) return EVENT_STOP; return EVENT_CONTINUE; @@ -382,11 +346,13 @@ class ChanServCore : public Module, public ChanServService void OnPreUplinkSync(Server *serv) anope_override { + if (!persist) + return; /* Find all persistent channels and create them, as we are about to finish burst to our uplink */ for (registered_channel_map::iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it) { ChannelInfo *ci = it->second; - if (ci->HasExt("PERSIST")) + if (persist->Get(ci)) { bool created; ci->c = Channel::FindOrCreate(ci->name, created, ci->time_registered); @@ -414,35 +380,15 @@ class ChanServCore : public Module, public ChanServService void OnChanRegistered(ChannelInfo *ci) anope_override { + if (!persist) + return; /* Mark the channel as persistent */ if (ci->c->HasMode("PERM")) - ci->ExtendMetadata("PERSIST"); + persist->Unset(ci); /* Persist may be in def cflags, set it here */ - else if (ci->HasExt("PERSIST")) + else if (persist->Get(ci)) ci->c->SetMode(NULL, "PERM"); } - - void OnTopicUpdated(Channel *c, const Anope::string &user, const Anope::string &topic) anope_override - { - if (!c->ci) - return; - - /* We only compare the topics here, not the time or setter. This is because some (old) IRCds do not - * allow us to set the topic as someone else, meaning we have to bump the TS and change the setter to us. - * This desyncs what is really set with what we have stored, and we end up resetting the topic often when - * it is not required - */ - if (c->ci->HasExt("TOPICLOCK") && c->ci->last_topic != c->topic) - { - c->ChangeTopic(c->ci->last_topic_setter, c->ci->last_topic, c->ci->last_topic_time); - } - else - { - c->ci->last_topic = c->topic; - c->ci->last_topic_setter = c->topic_setter; - c->ci->last_topic_time = c->topic_ts; - } - } }; MODULE_INIT(ChanServCore) diff --git a/modules/pseudoclients/nickserv.cpp b/modules/pseudoclients/nickserv.cpp index f306b1b51..6730e91b9 100644 --- a/modules/pseudoclients/nickserv.cpp +++ b/modules/pseudoclients/nickserv.cpp @@ -46,12 +46,13 @@ class NickServHeld : public Timer public: NickServHeld(NickAlias *n, long l) : Timer(l), na(n), nick(na->nick) { + n->Extend<bool>("HELD"); } void Tick(time_t) { if (na) - na->Shrink("HELD"); + na->Shrink<bool>("HELD"); } }; @@ -95,13 +96,13 @@ class NickServCore : public Module, public NickServService { Reference<BotInfo> NickServ; std::vector<Anope::string> defaults; + ExtensibleItem<bool> held, collided; void OnCancel(User *u, NickAlias *na) { - if (na->HasExt("COLLIDED")) + if (collided.HasExt(na)) { - na->Extend("HELD"); - na->Shrink("COLLIDED"); + collided.Unset(na); new NickServHeld(na, Config->GetBlock("options")->Get<time_t>("releasetimeout")); @@ -113,36 +114,48 @@ class NickServCore : public Module, public NickServService } public: - NickServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR), NickServService(this) + NickServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR), + NickServService(this), held(this, "HELD"), collided(this, "COLLIDED") { } + ~NickServCore() + { + OnShutdown(); + } + + void OnShutdown() anope_override + { + /* On shutdown, restart, or mod unload, remove all of our holds for nicks (svshold or qlines) + * because some IRCds do not allow us to have these automatically expire + */ + for (nickalias_map::const_iterator it = NickAliasList->begin(); it != NickAliasList->end(); ++it) + this->Release(it->second); + } + + void OnRestart() anope_override + { + OnShutdown(); + } + void Validate(User *u) anope_override { NickAlias *na = NickAlias::Find(u->nick); if (!na) return; - if (na->nc->HasExt("SUSPENDED")) + EventReturn MOD_RESULT; + FOREACH_RESULT(OnNickValidate, MOD_RESULT, (u, na)); + if (MOD_RESULT == EVENT_STOP) { - u->SendMessage(NickServ, NICK_X_SUSPENDED, u->nick.c_str()); this->Collide(u, na); return; } - if (!(u->Account() == na->nc) && !u->fingerprint.empty() && na->nc->FindCert(u->fingerprint)) - { - u->SendMessage(NickServ, _("SSL Fingerprint accepted, you are now identified.")); - Log(u) << "automatically identified for account " << na->nc->display << " using a valid SSL fingerprint."; - u->Identify(na); - return; - } - - if (!na->nc->HasExt("SECURE") && u->IsRecognized()) + if (!na->nc->HasExt("NS_SECURE") && u->IsRecognized()) { na->last_seen = Anope::CurTime; - Anope::string last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost(); - na->last_usermask = last_usermask; + na->last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost(); na->last_realname = u->realname; return; } @@ -150,15 +163,16 @@ class NickServCore : public Module, public NickServService if (Config->GetBlock("options")->Get<bool>("nonicknameownership")) return; - if (u->IsRecognized(false) || !na->nc->HasExt("KILL_IMMED")) + bool on_access = u->IsRecognized(false); + + if (on_access || !na->nc->HasExt("KILL_IMMED")) { - if (na->nc->HasExt("SECURE")) + if (na->nc->HasExt("NS_SECURE")) u->SendMessage(NickServ, NICK_IS_SECURE, Config->StrictPrivmsg.c_str(), NickServ->nick.c_str()); else u->SendMessage(NickServ, NICK_IS_REGISTERED, Config->StrictPrivmsg.c_str(), NickServ->nick.c_str()); } - - if (na->nc->HasExt("KILLPROTECT") && !u->IsRecognized(false)) + if (na->nc->HasExt("KILLPROTECT") && !on_access) { if (na->nc->HasExt("KILL_IMMED")) { @@ -184,14 +198,14 @@ class NickServCore : public Module, public NickServService void OnUserLogin(User *u) anope_override { NickAlias *na = NickAlias::Find(u->nick); - if (na && *na->nc == u->Account() && !Config->GetBlock("options")->Get<bool>("nonicknameownership") && na->nc->HasExt("UNCONFIRMED") == false) + if (na && *na->nc == u->Account() && !Config->GetBlock("options")->Get<bool>("nonicknameownership") && !na->nc->HasExt("UNCONFIRMED")) u->SetMode(NickServ, "REGISTERED"); } void Collide(User *u, NickAlias *na) anope_override { if (na) - na->Extend("COLLIDED"); + collided.Set(na); if (IRCD->CanSVSNick) { @@ -221,7 +235,7 @@ class NickServCore : public Module, public NickServService void Release(NickAlias *na) anope_override { - if (na->HasExt("HELD")) + if (held.HasExt(na)) { if (IRCD->CanSVSHold) IRCD->SendSVSHoldDel(na->nick); @@ -234,7 +248,7 @@ class NickServCore : public Module, public NickServService } } - na->Shrink("HELD"); + held.Unset(na); } } @@ -251,10 +265,10 @@ class NickServCore : public Module, public NickServService NickServ = bi; - spacesepstream(conf->GetModule(this)->Get<const Anope::string>("defaults", "secure memo_signon memo_receive")).GetTokens(defaults); + spacesepstream(conf->GetModule(this)->Get<const Anope::string>("defaults", "ns_secure memo_signon memo_receive")).GetTokens(defaults); if (defaults.empty()) { - defaults.push_back("SECURE"); + defaults.push_back("NS_SECURE"); defaults.push_back("MEMO_SIGNON"); defaults.push_back("MEMO_RECEIVE"); } @@ -296,14 +310,8 @@ class NickServCore : public Module, public NickServService { Configuration::Block *block = Config->GetModule(this); - if (!Config->GetBlock("options")->Get<bool>("nonicknameownership")) - { - const NickAlias *this_na = NickAlias::Find(u->nick); - if (this_na && this_na->nc == u->Account() && u->Account()->HasExt("UNCONFIRMED") == false) - u->SetMode(NickServ, "REGISTERED"); - } - if (block->Get<bool>("modeonid", "yes")) + for (User::ChanUserList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it) { ChanUserContainer *cc = it->second; @@ -325,25 +333,11 @@ class NickServCore : public Module, public NickServService "Your privacy is respected; this e-mail won't be given to\n" "any third-party person."), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str()); } - - if (u->Account()->HasExt("UNCONFIRMED")) - { - const Anope::string &nsregister = Config->GetModule("ns_register")->Get<const Anope::string>("registration"); - if (nsregister.equals_ci("admin"))
- u->SendMessage(NickServ, _("All new accounts must be validated by an administrator. Please wait for your registration to be confirmed."));
- else - u->SendMessage(NickServ, _("Your email address is not confirmed. To confirm it, follow the instructions that were emailed to you when you registered.")); - const NickAlias *this_na = NickAlias::Find(u->Account()->display); - time_t time_registered = Anope::CurTime - this_na->time_registered; - time_t unconfirmed_expire = Config->GetModule(this)->Get<time_t>("unconfirmedexpire", "1d"); - if (unconfirmed_expire > time_registered) - u->SendMessage(NickServ, _("Your account will expire, if not confirmed, in %s"), Anope::Duration(unconfirmed_expire - time_registered).c_str()); - } } void OnNickGroup(User *u, NickAlias *target) anope_override { - if (target->nc->HasExt("UNCONFIRMED") == false) + if (!target->nc->HasExt("UNCONFIRMED")) u->SetMode(NickServ, "REGISTERED"); } @@ -404,7 +398,7 @@ class NickServCore : public Module, public NickServService { /* Reset +r and re-send account (even though it really should be set at this point) */ IRCD->SendLogin(u); - if (!Config->GetBlock("options")->Get<bool>("nonicknameownership") && na->nc == u->Account() && na->nc->HasExt("UNCONFIRMED") == false) + if (!Config->GetBlock("options")->Get<bool>("nonicknameownership") && na->nc == u->Account() && !na->nc->HasExt("UNCONFIRMED")) u->SetMode(NickServ, "REGISTERED"); Log(NickServ) << u->GetMask() << " automatically identified for group " << u->Account()->display; } @@ -467,7 +461,7 @@ class NickServCore : public Module, public NickServService { /* Set default flags */ for (unsigned i = 0; i < defaults.size(); ++i) - nc->ExtendMetadata(defaults[i].upper()); + nc->Extend<bool>(defaults[i].upper()); } void OnUserQuit(User *u, const Anope::string &msg) @@ -489,7 +483,6 @@ class NickServCore : public Module, public NickServService if (Anope::NoExpire || Anope::ReadOnly) return; - time_t unconfirmed_expire = Config->GetModule(this)->Get<time_t>("unconfirmedexpire", "1d"); time_t nickserv_expire = Config->GetModule(this)->Get<time_t>("expire"); for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ) @@ -498,32 +491,39 @@ class NickServCore : public Module, public NickServService ++it; User *u = User::Find(na->nick); - if (u && (na->nc->HasExt("SECURE") ? u->IsIdentified(true) : u->IsRecognized())) + if (u && (na->nc->HasExt("NS_SECURE") ? u->IsIdentified(true) : u->IsRecognized())) na->last_seen = Anope::CurTime; bool expire = false; - if (na->nc->HasExt("UNCONFIRMED")) - if (unconfirmed_expire && Anope::CurTime - na->time_registered >= unconfirmed_expire) - expire = true; if (nickserv_expire && Anope::CurTime - na->last_seen >= nickserv_expire) expire = true; - if (na->HasExt("NO_EXPIRE")) - expire = false; FOREACH_MOD(OnPreNickExpire, (na, expire)); if (expire) { - Anope::string extra; - if (na->nc->HasExt("SUSPENDED")) - extra = "suspended "; - Log(LOG_NORMAL, "expire") << "Expiring " << extra << "nickname " << na->nick << " (group: " << na->nc->display << ") (e-mail: " << (na->nc->email.empty() ? "none" : na->nc->email) << ")"; + Log(LOG_NORMAL, "expire") << "Expiring nickname " << na->nick << " (group: " << na->nc->display << ") (e-mail: " << (na->nc->email.empty() ? "none" : na->nc->email) << ")"; FOREACH_MOD(OnNickExpire, (na)); delete na; } } } + + void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) anope_override + { + if (!na->nc->HasExt("UNCONFIRMED")) + { + time_t nickserv_expire = Config->GetModule(this)->Get<time_t>("expire"); + if (!na->HasExt("NS_NO_EXPIRE") && nickserv_expire && !Anope::NoExpire) + info[_("Expires")] = Anope::strftime(na->last_seen + nickserv_expire); + } + else + { + time_t unconfirmed_expire = Config->GetModule(this)->Get<time_t>("unconfirmedexpire", "1d"); + info[_("Expires")] = Anope::strftime(na->time_registered + unconfirmed_expire); + } + } }; MODULE_INIT(NickServCore) diff --git a/src/bots.cpp b/src/bots.cpp index 2ff4f5340..0a65393bb 100644 --- a/src/bots.cpp +++ b/src/bots.cpp @@ -80,7 +80,7 @@ void BotInfo::Serialize(Serialize::Data &data) const data["created"] << this->created; data["oper_only"] << this->oper_only; - this->ExtensibleSerialize(data); + Extensible::ExtensibleSerialize(this, this, data); } Serializable* BotInfo::Unserialize(Serializable *obj, Serialize::Data &data) @@ -101,7 +101,7 @@ Serializable* BotInfo::Unserialize(Serializable *obj, Serialize::Data &data) data["created"] >> bi->created; data["oper_only"] >> bi->oper_only; - bi->ExtensibleUnserialize(data); + Extensible::ExtensibleUnserialize(bi, bi, data); return bi; } diff --git a/src/channels.cpp b/src/channels.cpp index 9fdc44a49..0b790e54e 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -35,7 +35,7 @@ Channel::Channel(const Anope::string &nname, time_t ts) this->name = nname; this->creation_time = ts; - this->syncing = false; + this->syncing = this->botchannel = false; this->server_modetime = this->chanserv_modetime = 0; this->server_modecount = this->chanserv_modecount = this->bouncy_modes = this->topic_ts = this->topic_time = 0; @@ -108,48 +108,6 @@ void Channel::CheckModes() FOREACH_RESULT(OnCheckModes, MOD_RESULT, (this)); if (MOD_RESULT == EVENT_STOP) return; - - if (this->ci) - for (ChannelInfo::ModeList::const_iterator it = this->ci->GetMLock().begin(), it_end = this->ci->GetMLock().end(); it != it_end; ++it) - { - const ModeLock *ml = it->second; - ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name); - if (!cm) - continue; - - if (cm->type == MODE_REGULAR) - { - if (!this->HasMode(cm->name) && ml->set) - this->SetMode(NULL, cm); - else if (this->HasMode(cm->name) && !ml->set) - this->RemoveMode(NULL, cm); - } - else if (cm->type == MODE_PARAM) - { - /* If the channel doesnt have the mode, or it does and it isn't set correctly */ - if (ml->set) - { - Anope::string param; - this->GetParam(cm->name, param); - - if (!this->HasMode(cm->name) || (!param.empty() && !ml->param.empty() && !param.equals_cs(ml->param))) - this->SetMode(NULL, cm, ml->param); - } - else - { - if (this->HasMode(cm->name)) - this->RemoveMode(NULL, cm); - } - - } - else if (cm->type == MODE_LIST) - { - if (ml->set) - this->SetMode(NULL, cm, ml->param); - else - this->RemoveMode(NULL, cm, ml->param); - } - } } bool Channel::CheckDelete() @@ -312,7 +270,7 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *cm, const Anop if (cc) cc->status.AddMode(cm->mchar); - FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm->name, param)); + FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, param)); /* Enforce secureops, etc */ if (enforce_mlock && MOD_RESULT != EVENT_STOP) @@ -336,7 +294,7 @@ void Channel::SetModeInternal(MessageSource &setter, ChannelMode *cm, const Anop cml->OnAdd(this, param); } - FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm->name, param)); + FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, param)); /* Check if we should enforce mlock */ if (!enforce_mlock || MOD_RESULT == EVENT_STOP) @@ -377,7 +335,7 @@ void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *cm, const A if (cc) cc->status.DelMode(cm->mchar); - FOREACH_RESULT(OnChannelModeUnset, MOD_RESULT, (this, setter, cm->name, param)); + FOREACH_RESULT(OnChannelModeUnset, MOD_RESULT, (this, setter, cm, param)); if (enforce_mlock && MOD_RESULT != EVENT_STOP) this->SetCorrectModes(u, false); @@ -404,7 +362,7 @@ void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *cm, const A cml->OnDel(this, param); } - FOREACH_RESULT(OnChannelModeUnset, MOD_RESULT, (this, setter, cm->name, param)); + FOREACH_RESULT(OnChannelModeUnset, MOD_RESULT, (this, setter, cm, param)); /* Check for mlock */ if (!enforce_mlock || MOD_RESULT == EVENT_STOP) @@ -865,26 +823,6 @@ void Channel::SetCorrectModes(User *user, bool give_modes) this->RemoveMode(NULL, cm, user->GetUID()); } } - - // Check mlock - for (ChannelInfo::ModeList::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 != this->HasUserStatus(user, ml->name)) - { - if (ml->set) - this->SetMode(NULL, cm, user->GetUID(), false); - else if (!ml->set) - this->RemoveMode(NULL, cm, user->GetUID(), false); - } - } - } } bool Channel::Unban(User *u, bool full) diff --git a/src/config.cpp b/src/config.cpp index 4b16d8e97..8ba56bda2 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -339,7 +339,7 @@ Conf::Conf() : Block("") if (!c) continue; // Can't happen - c->Extend("BOTCHANNEL"); + c->botchannel = true; /* Remove all existing modes */ ChanUserContainer *cu = c->FindUser(bi); @@ -377,7 +377,7 @@ Conf::Conf() : Block("") Channel *c = Channel::Find(chname); if (c) { - c->Shrink("BOTCHANNEL"); + c->botchannel = false; bi->Part(c); } } diff --git a/src/extensible.cpp b/src/extensible.cpp index 25fa7938c..9284bdbf2 100644 --- a/src/extensible.cpp +++ b/src/extensible.cpp @@ -10,96 +10,63 @@ #include "extensible.h" -Extensible::Extensible() : extension_items(NULL) -{ -} +static std::set<ExtensibleBase *> extensible_items; -Extensible::~Extensible() +ExtensibleBase::ExtensibleBase(Module *m, const Anope::string &n) : Service(m, "Extensible", n) { - if (extension_items) - { - for (extensible_map::iterator it = extension_items->begin(), it_end = extension_items->end(); it != it_end; ++it) - delete it->second; - delete extension_items; - } + extensible_items.insert(this); } -void Extensible::Extend(const Anope::string &key, ExtensibleItem *p) +ExtensibleBase::~ExtensibleBase() { - this->Shrink(key); - if (!extension_items) - extension_items = new extensible_map(); - (*this->extension_items)[key] = p; + extensible_items.erase(this); } -void Extensible::ExtendMetadata(const Anope::string &key, const Anope::string &value) +Extensible::~Extensible() { - this->Extend(key, new ExtensibleMetadata(!value.empty() ? value : "1")); + for (std::set<ExtensibleBase *>::iterator it = extension_items.begin(); it != extension_items.end(); ++it) + (*it)->Unset(this); } -bool Extensible::Shrink(const Anope::string &key) +bool Extensible::HasExt(const Anope::string &name) const { - if (!extension_items) - return false; - - extensible_map::iterator it = this->extension_items->find(key); - if (it != this->extension_items->end()) - { - delete it->second; - /* map::size_type map::erase( const key_type& key ); - * returns the number of elements removed, std::map - * is single-associative so this should only be 0 or 1 - */ - return this->extension_items->erase(key) > 0; - } + ExtensibleRef<void *> ref(name); + if (ref) + return ref->HasExt(this); + Log(LOG_DEBUG) << "HasExt for nonexistent type " << name << " on " << static_cast<const void *>(this); return false; } -bool Extensible::HasExt(const Anope::string &key) const +void Extensible::ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) { - return this->extension_items != NULL && this->extension_items->count(key) > 0; + for (std::set<ExtensibleBase *>::iterator it = e->extension_items.begin(); it != e->extension_items.end(); ++it) + { + ExtensibleBase *eb = *it; + eb->ExtensibleSerialize(e, s, data); + } } -void Extensible::GetExtList(std::deque<Anope::string> &list) const +void Extensible::ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) { - if (extension_items) - for (extensible_map::const_iterator it = extension_items->begin(), it_end = extension_items->end(); it != it_end; ++it) - list.push_back(it->first); -} + while (!e->extension_items.empty()) + (*e->extension_items.begin())->Unset(e); -void Extensible::ExtensibleSerialize(Serialize::Data &data) const -{ - if (extension_items) - for (extensible_map::const_iterator it = extension_items->begin(), it_end = extension_items->end(); it != it_end; ++it) - if (it->second && it->second->Serialize()) - data["extensible:" + it->first] << *it->second->Serialize(); -} - -void Extensible::ExtensibleUnserialize(Serialize::Data &data) -{ - /* Shrink existing extensible metadata items */ - std::deque<Anope::string> list; - this->GetExtList(list); - for (unsigned i = 0; i < list.size(); ++i) + for (std::set<ExtensibleBase *>::iterator it = extensible_items.begin(); it != extensible_items.end(); ++it) { - ExtensibleItem *item = extension_items->at(list[i]); - if (item && item->Serialize()) - this->Shrink(list[i]); + ExtensibleBase *eb = *it; + eb->ExtensibleUnserialize(e, s, data); } - - std::set<Anope::string> keys = data.KeySet(); - for (std::set<Anope::string>::iterator it = keys.begin(), it_end = keys.end(); it != it_end; ++it) - if (it->find("extensible:") == 0) - { - if (!extension_items) - extension_items = new extensible_map(); +} - Anope::string str; - data[*it] >> str; +template<> +bool* Extensible::Extend(const Anope::string &name, const bool &what) +{ + ExtensibleRef<bool> ref(name); + if (ref) + return ref->Set(this); - if (!str.empty()) - this->ExtendMetadata(it->substr(11), str); - } + Log(LOG_DEBUG) << "Shrink for nonexistant type " << name << " on " << static_cast<void *>(this); + return NULL; } diff --git a/src/misc.cpp b/src/misc.cpp index fd08ffb2a..c9e18dc66 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -220,7 +220,7 @@ void InfoFormatter::Process(std::vector<Anope::string> &buffer) Anope::string s; for (unsigned i = it->first.length(); i < this->longest; ++i) s += " "; - s += Anope::string(Language::Translate(this->nc, it->first.c_str())) + ": " + it->second; + s += Anope::string(Language::Translate(this->nc, it->first.c_str())) + ": " + Language::Translate(this->nc, it->second.c_str()); buffer.push_back(s); } @@ -234,6 +234,25 @@ Anope::string& InfoFormatter::operator[](const Anope::string &key) return this->replies.back().second; } +void InfoFormatter::AddOption(const Anope::string &opt) +{ + Anope::string *optstr = NULL; + for (std::vector<std::pair<Anope::string, Anope::string> >::iterator it = this->replies.begin(), it_end = this->replies.end(); it != it_end; ++it) + { + if (it->first == "Options") + { + optstr = &it->second; + break; + } + } + if (!optstr) + optstr = &(*this)["Options"]; + + if (!optstr->empty()) + *optstr += ", "; + *optstr += Language::Translate(nc, opt.c_str()); +} + bool Anope::IsFile(const Anope::string &filename) { struct stat fileinfo; diff --git a/src/nickalias.cpp b/src/nickalias.cpp index 1595987e4..a50284cf4 100644 --- a/src/nickalias.cpp +++ b/src/nickalias.cpp @@ -140,7 +140,7 @@ void NickAlias::Serialize(Serialize::Data &data) const data.SetType("time_registered", Serialize::Data::DT_INT); data["time_registered"] << this->time_registered; data.SetType("time_registered", Serialize::Data::DT_INT); data["last_seen"] << this->last_seen; data["nc"] << this->nc->display; - this->ExtensibleSerialize(data); + Extensible::ExtensibleSerialize(this, this, data); if (this->HasVhost()) { @@ -189,7 +189,7 @@ Serializable* NickAlias::Unserialize(Serializable *obj, Serialize::Data &data) data["last_realhost"] >> na->last_realhost; data["time_registered"] >> na->time_registered; data["last_seen"] >> na->last_seen; - na->ExtensibleUnserialize(data); + Extensible::ExtensibleUnserialize(na, na, data); Anope::string vhost_ident, vhost_host, vhost_creator; time_t vhost_time; @@ -201,15 +201,6 @@ Serializable* NickAlias::Unserialize(Serializable *obj, Serialize::Data &data) na->SetVhost(vhost_ident, vhost_host, vhost_creator, vhost_time); - /* Compat */ - Anope::string sflags; - data["flags"] >> sflags; - spacesepstream sep(sflags); - Anope::string tok; - while (sep.GetToken(tok)) - na->ExtendMetadata(tok); - /* End compat */ - return na; } diff --git a/src/nickcore.cpp b/src/nickcore.cpp index 5779767dd..9bbaae959 100644 --- a/src/nickcore.cpp +++ b/src/nickcore.cpp @@ -67,13 +67,10 @@ void NickCore::Serialize(Serialize::Data &data) const data["display"] << this->display; data["pass"] << this->pass; data["email"] << this->email; - data["greet"] << this->greet; data["language"] << this->language; - this->ExtensibleSerialize(data); + Extensible::ExtensibleSerialize(this, this, data); for (unsigned i = 0; i < this->access.size(); ++i) data["access"] << this->access[i] << " "; - for (unsigned i = 0; i < this->cert.size(); ++i) - data["cert"] << this->cert[i] << " "; data["memomax"] << this->memos.memomax; for (unsigned i = 0; i < this->memos.ignores.size(); ++i) data["memoignores"] << this->memos.ignores[i] << " "; @@ -94,9 +91,8 @@ Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &data) data["pass"] >> nc->pass; data["email"] >> nc->email; - data["greet"] >> nc->greet; data["language"] >> nc->language; - nc->ExtensibleUnserialize(data); + Extensible::ExtensibleUnserialize(nc, nc, data); { Anope::string buf; data["access"] >> buf; @@ -105,14 +101,6 @@ Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &data) while (sep.GetToken(buf)) nc->access.push_back(buf); } - { - Anope::string buf; - data["cert"] >> buf; - spacesepstream sep(buf); - nc->cert.clear(); - while (sep.GetToken(buf)) - nc->cert.push_back(buf); - } data["memomax"] >> nc->memos.memomax; { Anope::string buf; @@ -123,14 +111,15 @@ Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &data) nc->memos.ignores.push_back(buf); } - /* Compat */ - Anope::string sflags; - data["flags"] >> sflags; - spacesepstream sep(sflags); - Anope::string tok; - while (sep.GetToken(tok)) - nc->ExtendMetadata(tok); - /* End compat */ + /* compat */ + bool b; + data["extensible:SECURE"] >> b; + if (b) + nc->Extend<bool>("NS_SECURE"); + data["extensible:PRIVATE"] >> b; + if (b) + nc->Extend<bool>("NS_PRIVATE"); + /* end compat */ return nc; } @@ -216,45 +205,6 @@ bool NickCore::IsOnAccess(const User *u) const return false; } -void NickCore::AddCert(const Anope::string &entry) -{ - this->cert.push_back(entry); - FOREACH_MOD(OnNickAddCert, (this, entry)); -} - -Anope::string NickCore::GetCert(unsigned entry) const -{ - if (this->cert.empty() || entry >= this->cert.size()) - return ""; - return this->cert[entry]; -} - -bool NickCore::FindCert(const Anope::string &entry) const -{ - for (unsigned i = 0, end = this->cert.size(); i < end; ++i) - if (this->cert[i] == entry) - return true; - - return false; -} - -void NickCore::EraseCert(const Anope::string &entry) -{ - for (unsigned i = 0, end = this->cert.size(); i < end; ++i) - if (this->cert[i] == entry) - { - FOREACH_MOD(OnNickEraseCert, (this, entry)); - this->cert.erase(this->cert.begin() + i); - break; - } -} - -void NickCore::ClearCert() -{ - FOREACH_MOD(OnNickClearCert, (this)); - this->cert.clear(); -} - void NickCore::AddChannelReference(ChannelInfo *ci) { ++(*this->chanaccess)[ci]; diff --git a/src/regchannel.cpp b/src/regchannel.cpp index b1f056b27..e06f53690 100644 --- a/src/regchannel.cpp +++ b/src/regchannel.cpp @@ -22,54 +22,6 @@ Serialize::Checker<registered_channel_map> RegisteredChannelList("ChannelInfo"); -BadWord::BadWord() : Serializable("BadWord") -{ -} - -BadWord::~BadWord() -{ - if (this->ci) - { - std::vector<BadWord *>::iterator it = std::find(this->ci->badwords->begin(), this->ci->badwords->end(), this); - if (it != this->ci->badwords->end()) - this->ci->badwords->erase(it); - } -} - -void BadWord::Serialize(Serialize::Data &data) const -{ - data["ci"] << this->ci->name; - data["word"] << this->word; - data.SetType("type", Serialize::Data::DT_INT); data["type"] << this->type; -} - -Serializable* BadWord::Unserialize(Serializable *obj, Serialize::Data &data) -{ - Anope::string sci, sword; - - data["ci"] >> sci; - data["word"] >> sword; - - ChannelInfo *ci = ChannelInfo::Find(sci); - if (!ci) - return NULL; - - unsigned int n; - data["type"] >> n; - - BadWord *bw; - if (obj) - { - bw = anope_dynamic_static_cast<BadWord *>(obj); - data["word"] >> bw->word; - bw->type = static_cast<BadWordType>(n); - } - else - bw = ci->AddBadWord(sword, static_cast<BadWordType>(n)); - - return bw; -} - AutoKick::AutoKick() : Serializable("AutoKick") { } @@ -145,122 +97,8 @@ Serializable* AutoKick::Unserialize(Serializable *obj, Serialize::Data &data) return ak; } -ModeLock::ModeLock(ChannelInfo *ch, bool s, const Anope::string &n, const Anope::string &p, const Anope::string &se, time_t c) : Serializable("ModeLock"), ci(ch), set(s), name(n), param(p), setter(se), created(c) -{ -} - -ModeLock::~ModeLock() -{ - if (this->ci) - this->ci->RemoveMLock(this); -} - -void ModeLock::Serialize(Serialize::Data &data) const -{ - if (!this->ci) - return; - - data["ci"] << this->ci->name; - data["set"] << this->set; - data["name"] << this->name; - data["param"] << this->param; - data["setter"] << this->setter; - data.SetType("created", Serialize::Data::DT_INT); data["created"] << this->created; -} - -Serializable* ModeLock::Unserialize(Serializable *obj, Serialize::Data &data) -{ - Anope::string sci; - - data["ci"] >> sci; - - ChannelInfo *ci = ChannelInfo::Find(sci); - if (!ci) - return NULL; - - ModeLock *ml; - if (obj) - { - ml = anope_dynamic_static_cast<ModeLock *>(obj); - - data["set"] >> ml->set; - data["name"] >> ml->name; - data["param"] >> ml->param; - data["setter"] >> ml->setter; - data["created"] >> ml->created; - return ml; - } - else - { - bool set; - data["set"] >> set; - - time_t created; - data["created"] >> created; - - Anope::string setter; - data["setter"] >> setter; - - Anope::string sname; - data["name"] >> sname; - - ml = new ModeLock(ci, set, sname, "", setter, created); - data["param"] >> ml->param; - - ci->mode_locks->insert(std::make_pair(ml->name, ml)); - return ml; - } -} - -void LogSetting::Serialize(Serialize::Data &data) const -{ - if (!ci) - return; - - data["ci"] << ci->name; - data["service_name"] << service_name; - data["command_service"] << command_service; - data["command_name"] << command_name; - data["method"] << method; - data["extra"] << extra; - data["creator"] << creator; - data.SetType("created", Serialize::Data::DT_INT); data["created"] << created; -} - -Serializable* LogSetting::Unserialize(Serializable *obj, Serialize::Data &data) -{ - Anope::string sci; - - data["ci"] >> sci; - - ChannelInfo *ci = ChannelInfo::Find(sci); - if (ci == NULL) - return NULL; - - LogSetting *ls; - if (obj) - ls = anope_dynamic_static_cast<LogSetting *>(obj); - else - { - ls = new LogSetting(); - ci->log_settings->push_back(ls); - } - - ls->ci = ci; - data["service_name"] >> ls->service_name; - data["command_service"] >> ls->command_service; - data["command_name"] >> ls->command_name; - data["method"] >> ls->method; - data["extra"] >> ls->extra; - data["creator"] >> ls->creator; - data["created"] >> ls->created; - - return ls; -} - ChannelInfo::ChannelInfo(const Anope::string &chname) : Serializable("ChannelInfo"), - access("ChanAccess"), akick("AutoKick"), - badwords("BadWord"), mode_locks("ModeLock"), log_settings("LogSetting") + access("ChanAccess"), akick("AutoKick") { if (chname.empty()) throw CoreException("Empty channel passed to ChannelInfo constructor"); @@ -270,9 +108,6 @@ ChannelInfo::ChannelInfo(const Anope::string &chname) : Serializable("ChannelInf this->c = Channel::Find(chname); if (this->c) this->c->ci = this; - this->capsmin = this->capspercent = 0; - this->floodlines = this->floodsecs = 0; - this->repeattimes = 0; this->banexpire = 0; this->bi = NULL; this->last_topic_time = 0; @@ -283,9 +118,6 @@ ChannelInfo::ChannelInfo(const Anope::string &chname) : Serializable("ChannelInf this->memos.memomax = 0; this->last_used = this->time_registered = Anope::CurTime; - for (int i = 0; i < TTB_SIZE; ++i) - this->ttb[i] = 0; - size_t old = RegisteredChannelList->size(); (*RegisteredChannelList)[this->name] = this; if (old == RegisteredChannelList->size()) @@ -295,8 +127,7 @@ ChannelInfo::ChannelInfo(const Anope::string &chname) : Serializable("ChannelInf } ChannelInfo::ChannelInfo(const ChannelInfo &ci) : Serializable("ChannelInfo"), - access("ChanAccess"), akick("AutoKick"), - badwords("BadWord"), mode_locks("ModeLock"), log_settings("LogSetting") + access("ChanAccess"), akick("AutoKick") { *this = ci; @@ -305,10 +136,6 @@ ChannelInfo::ChannelInfo(const ChannelInfo &ci) : Serializable("ChannelInfo"), this->access->clear(); this->akick->clear(); - this->badwords->clear(); - - for (int i = 0; i < TTB_SIZE; ++i) - this->ttb[i] = ci.ttb[i]; for (unsigned i = 0; i < ci.GetAccessCount(); ++i) { @@ -334,18 +161,6 @@ ChannelInfo::ChannelInfo(const ChannelInfo &ci) : Serializable("ChannelInfo"), else this->AddAkick(takick->creator, takick->mask, takick->reason, takick->addtime, takick->last_used); } - for (unsigned i = 0; i < ci.GetBadWordCount(); ++i) - { - const BadWord *bw = ci.GetBadWord(i); - this->AddBadWord(bw->word, bw->type); - } - - for (unsigned i = 0; i < ci.log_settings->size(); ++i) - { - LogSetting *l = new LogSetting(*ci.log_settings->at(i)); - l->ci = this; - this->log_settings->push_back(l); - } FOREACH_MOD(OnCreateChan, (this)); } @@ -379,14 +194,6 @@ ChannelInfo::~ChannelInfo() this->ClearAccess(); this->ClearAkick(); - this->ClearBadWords(); - - for (unsigned i = 0; i < this->log_settings->size(); ++i) - delete this->log_settings->at(i); - this->log_settings->clear(); - - while (!this->mode_locks->empty()) - delete this->mode_locks->begin()->second; if (!this->memos.memos->empty()) { @@ -413,7 +220,7 @@ void ChannelInfo::Serialize(Serialize::Data &data) const data["last_topic_setter"] << this->last_topic_setter; data.SetType("last_topic_time", Serialize::Data::DT_INT); data["last_topic_time"] << this->last_topic_time; data.SetType("bantype", Serialize::Data::DT_INT); data["bantype"] << this->bantype; - this->ExtensibleSerialize(data); + Extensible::ExtensibleSerialize(this, this, data); { Anope::string levels_buffer; for (Anope::map<int16_t>::const_iterator it = this->levels.begin(), it_end = this->levels.end(); it != it_end; ++it) @@ -422,13 +229,6 @@ void ChannelInfo::Serialize(Serialize::Data &data) const } if (this->bi) data["bi"] << this->bi->nick; - for (int i = 0; i < TTB_SIZE; ++i) - data["ttb"] << this->ttb[i] << " "; - data.SetType("capsmin", Serialize::Data::DT_INT); data["capsmin"] << this->capsmin; - data.SetType("capspercent", Serialize::Data::DT_INT); data["capspercent"] << this->capspercent; - data.SetType("floodlines", Serialize::Data::DT_INT); data["floodlines"] << this->floodlines; - data.SetType("floodsecs", Serialize::Data::DT_INT); data["floodsecs"] << this->floodsecs; - data.SetType("repeattimes", Serialize::Data::DT_INT); data["repeattimes"] << this->repeattimes; data.SetType("banexpire", Serialize::Data::DT_INT); data["banexpire"] << this->banexpire; data["memomax"] << this->memos.memomax; for (unsigned i = 0; i < this->memos.ignores.size(); ++i) @@ -451,7 +251,7 @@ Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data) else ci = new ChannelInfo(sname); - ci->ExtensibleUnserialize(data); + Extensible::ExtensibleUnserialize(ci, ci, data); ci->SetFounder(NickCore::Find(sfounder)); ci->SetSuccessor(NickCore::Find(ssuccessor)); @@ -477,23 +277,6 @@ Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data) else if (ci->bi) ci->bi->UnAssign(NULL, ci); } - { - Anope::string ttb, tok; - data["ttb"] >> ttb; - spacesepstream sep(ttb); - for (int i = 0; sep.GetToken(tok) && i < TTB_SIZE; ++i) - try - { - ci->ttb[i] = convertTo<int16_t>(tok); - } - catch (const ConvertException &) { } - - } - data["capsmin"] >> ci->capsmin; - data["capspercent"] >> ci->capspercent; - data["floodlines"] >> ci->floodlines; - data["floodsecs"] >> ci->floodsecs; - data["repeattimes"] >> ci->repeattimes; data["banexpire"] >> ci->banexpire; data["memomax"] >> ci->memos.memomax; { @@ -505,18 +288,15 @@ Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data) ci->memos.ignores.push_back(buf); } - /* Compat */ - Anope::string sflags, sbotflags; - data["flags"] >> sflags; - data["botflags"] >> sbotflags; - spacesepstream sep(sflags); - Anope::string tok; - while (sep.GetToken(tok)) - ci->ExtendMetadata(tok); - spacesepstream sep2(sbotflags); - while (sep2.GetToken(tok)) - ci->ExtendMetadata("BS_" + tok); - /* End compat */ + /* compat */ + bool b; + data["extensible:SECURE"] >> b; + if (b) + ci->Extend<bool>("CS_SECURE"); + data["extensible:PRIVATE"] >> b; + if (b) + ci->Extend<bool>("CS_PRIVATE"); + /* end compat */ return ci; } @@ -603,7 +383,7 @@ AccessGroup ChannelInfo::AccessFor(const User *u) return group; const NickCore *nc = u->Account(); - if (nc == NULL && !this->HasExt("SECURE") && u->IsRecognized()) + if (nc == NULL && !this->HasExt("NS_SECURE") && u->IsRecognized()) { const NickAlias *na = NickAlias::Find(u->nick); if (na != NULL) @@ -756,256 +536,6 @@ void ChannelInfo::ClearAkick() delete this->akick->back(); } -BadWord* ChannelInfo::AddBadWord(const Anope::string &word, BadWordType type) -{ - BadWord *bw = new BadWord(); - bw->ci = this; - bw->word = word; - bw->type = type; - - this->badwords->push_back(bw); - - FOREACH_MOD(OnBadWordAdd, (this, bw)); - - return bw; -} - -BadWord* ChannelInfo::GetBadWord(unsigned index) const -{ - if (this->badwords->empty() || index >= this->badwords->size()) - return NULL; - - BadWord *bw = (*this->badwords)[index]; - bw->QueueUpdate(); - return bw; -} - -unsigned ChannelInfo::GetBadWordCount() const -{ - return this->badwords->size(); -} - -void ChannelInfo::EraseBadWord(unsigned index) -{ - if (this->badwords->empty() || index >= this->badwords->size()) - return; - - FOREACH_MOD(OnBadWordDel, (this, (*this->badwords)[index])); - - delete this->badwords->at(index); -} - -void ChannelInfo::ClearBadWords() -{ - while (!this->badwords->empty()) - delete this->badwords->back(); -} - -bool ChannelInfo::HasMLock(ChannelMode *mode, const Anope::string ¶m, bool status) const -{ - if (!mode) - return false; - - std::multimap<Anope::string, ModeLock *>::const_iterator it = this->mode_locks->find(mode->name); - - if (it != this->mode_locks->end()) - { - if (mode->type != MODE_REGULAR) - { - std::multimap<Anope::string, 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; -} - -bool ChannelInfo::SetMLock(ChannelMode *mode, bool status, const Anope::string ¶m, Anope::string setter, time_t created) -{ - if (!mode) - return false; - - if (setter.empty()) - setter = this->founder ? this->founder->display : "Unknown"; - std::pair<Anope::string, ModeLock *> ml = std::make_pair(mode->name, new ModeLock(this, status, mode->name, param, setter, created)); - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnMLock, MOD_RESULT, (this, ml.second)); - if (MOD_RESULT == EVENT_STOP) - return false; - - /* First, remove this */ - if (mode->type == MODE_REGULAR || mode->type == MODE_PARAM) - { - for (ChannelInfo::ModeList::const_iterator it; (it = this->mode_locks->find(mode->name)) != this->mode_locks->end();) - delete it->second; - this->mode_locks->erase(mode->name); - } - else - { - // For list or status modes, we must check the parameter - ChannelInfo::ModeList::iterator it = this->mode_locks->find(mode->name); - if (it != this->mode_locks->end()) - { - ChannelInfo::ModeList::iterator it_end = this->mode_locks->upper_bound(mode->name); - for (; it != it_end; ++it) - { - const ModeLock *modelock = it->second; - if (modelock->param == param) - { - delete it->second; - break; - } - } - } - } - - this->mode_locks->insert(ml); - - return true; -} - -bool ChannelInfo::RemoveMLock(ChannelMode *mode, bool status, const Anope::string ¶m) -{ - if (!mode) - return false; - - if (mode->type == MODE_REGULAR || mode->type == MODE_PARAM) - { - ChannelInfo::ModeList::iterator it = this->mode_locks->find(mode->name), it_end = this->mode_locks->upper_bound(mode->name), it_next = it; - if (it != this->mode_locks->end()) - for (; it != it_end; it = it_next) - { - const ModeLock *ml = it->second; - ++it_next; - - if (status != ml->set) - continue; - - EventReturn MOD_RESULT; - FOREACH_RESULT(OnUnMLock, MOD_RESULT, (this, it->second)); - if (MOD_RESULT != EVENT_STOP) - { - delete it->second; - return true; - } - } - return false; - } - else - { - // For list or status modes, we must check the parameter - ChannelInfo::ModeList::iterator it = this->mode_locks->find(mode->name); - if (it != this->mode_locks->end()) - { - ChannelInfo::ModeList::iterator it_end = this->mode_locks->upper_bound(mode->name); - for (; it != it_end; ++it) - { - const ModeLock *ml = it->second; - if (ml->set == status && ml->param == param) - { - EventReturn MOD_RESULT; - FOREACH_RESULT(OnUnMLock, MOD_RESULT, (this, it->second)); - if (MOD_RESULT == EVENT_STOP) - return false; - delete it->second; - return true; - } - } - } - - return false; - } -} - -void ChannelInfo::RemoveMLock(ModeLock *mlock) -{ - ChannelInfo::ModeList::iterator it = this->mode_locks->find(mlock->name); - if (it != this->mode_locks->end()) - for (; it != this->mode_locks->upper_bound(mlock->name); ++it) - if (it->second == mlock) - { - this->mode_locks->erase(it); - break; - } -} - -void ChannelInfo::ClearMLock() -{ - while (!this->mode_locks->empty()) - delete this->mode_locks->begin()->second; - this->mode_locks->clear(); -} - -const ChannelInfo::ModeList &ChannelInfo::GetMLock() const -{ - return this->mode_locks; -} - -std::pair<ChannelInfo::ModeList::iterator, ChannelInfo::ModeList::iterator> ChannelInfo::GetModeList(const Anope::string &mname) -{ - ChannelInfo::ModeList::iterator it = this->mode_locks->find(mname), it_end = it; - if (it != this->mode_locks->end()) - it_end = this->mode_locks->upper_bound(mname); - return std::make_pair(it, it_end); -} - -const ModeLock *ChannelInfo::GetMLock(const Anope::string &mname, const Anope::string ¶m) -{ - ChannelInfo::ModeList::iterator it = this->mode_locks->find(mname); - if (it != this->mode_locks->end()) - { - if (param.empty()) - return it->second; - else - { - ChannelInfo::ModeList::iterator it_end = this->mode_locks->upper_bound(mname); - for (; it != it_end; ++it) - { - if (Anope::Match(param, it->second->param)) - return it->second; - } - } - } - - return NULL; -} - -Anope::string ChannelInfo::GetMLockAsString(bool complete) const -{ - Anope::string pos = "+", neg = "-", params; - - for (ChannelInfo::ModeList::const_iterator it = this->GetMLock().begin(), it_end = this->GetMLock().end(); it != it_end; ++it) - { - const ModeLock *ml = it->second; - ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name); - if (!cm || cm->type == MODE_LIST || cm->type == MODE_STATUS) - continue; - - if (ml->set) - pos += cm->mchar; - else - neg += cm->mchar; - - if (complete && !ml->param.empty() && cm->type == MODE_PARAM) - params += " " + ml->param; - } - - if (pos.length() == 1) - pos.clear(); - if (neg.length() == 1) - neg.clear(); - - return pos + neg + params; -} - int16_t ChannelInfo::GetLevel(const Anope::string &priv) const { if (PrivilegeManager::FindPrivilege(priv) == NULL) diff --git a/src/serialize.cpp b/src/serialize.cpp index ef79bc396..a957f3046 100644 --- a/src/serialize.cpp +++ b/src/serialize.cpp @@ -30,9 +30,8 @@ std::list<Serializable *> *Serializable::SerializableItems; void Serialize::RegisterTypes() { static Type nc("NickCore", NickCore::Unserialize), na("NickAlias", NickAlias::Unserialize), bi("BotInfo", BotInfo::Unserialize), - ci("ChannelInfo", ChannelInfo::Unserialize), access("ChanAccess", ChanAccess::Unserialize), logsetting("LogSetting", LogSetting::Unserialize), - modelock("ModeLock", ModeLock::Unserialize), akick("AutoKick", AutoKick::Unserialize), badword("BadWord", BadWord::Unserialize), - memo("Memo", Memo::Unserialize), xline("XLine", XLine::Unserialize); + ci("ChannelInfo", ChannelInfo::Unserialize), access("ChanAccess", ChanAccess::Unserialize), + akick("AutoKick", AutoKick::Unserialize), memo("Memo", Memo::Unserialize), xline("XLine", XLine::Unserialize); } void Serialize::CheckTypes() diff --git a/src/sockets.cpp b/src/sockets.cpp index e136324f9..e3065a1e8 100644 --- a/src/sockets.cpp +++ b/src/sockets.cpp @@ -259,7 +259,7 @@ bool cidr::match(const sockaddrs &other) if (byte) { uint8_t m = ~0 << (8 - byte); - return *ip & m == *their_ip & m; + return (*ip & m) == (*their_ip & m); } return true; diff --git a/src/users.cpp b/src/users.cpp index cd3c6b50f..7f9a49049 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -301,7 +301,6 @@ void User::Identify(NickAlias *na) } this->Login(na->nc); - IRCD->SendLogin(this); FOREACH_MOD(OnNickIdentify, (this)); @@ -336,6 +335,8 @@ void User::Login(NickCore *core) this->UpdateHost(); + IRCD->SendLogin(this); + if (this->server->IsSynced()) Log(this, "account") << "is now identified as " << this->nc->display; @@ -378,7 +379,7 @@ bool User::IsRecognized(bool check_secure) const { const NickAlias *na = NickAlias::Find(this->nick); - if (!na || na->nc->HasExt("SECURE")) + if (!na || na->nc->HasExt("NS_SECURE")) return false; } |