1
0
mirror of https://github.com/anope/anope.git synced 2026-06-17 02:04:47 +02:00

Compare commits

...

185 Commits

Author SHA1 Message Date
Sadie Powell b51c6453ae Release 2.1.14. 2025-05-02 09:52:40 +01:00
Sadie Powell 8a44b9c0ea Update the change logs. 2025-05-02 09:52:40 +01:00
Sadie Powell 0dd5430c94 Deduplicate code in cs_access. 2025-04-27 20:58:35 +01:00
Sadie Powell 046fa5c848 Show the reason why a config file failed to open. 2025-04-27 14:16:10 +01:00
Sadie Powell 551f3504c8 Fix broken handling of colour codes in LineWrapper.
Closes #504.
2025-04-27 13:01:29 +01:00
Sadie Powell c11638db98 Allow disabling the timestamp in os_news messages. 2025-04-25 13:08:26 +01:00
Sadie Powell 9ca69a7b49 Fix a typo in ns_alist. 2025-04-24 15:01:54 +01:00
Sadie Powell 459c7947ce Fix skipping lone $ values within config values. 2025-04-24 12:48:48 +01:00
Sadie Powell fad0a4a0e8 Add support for hashing operator passwords in the config.
Closes #327.
2025-04-24 12:46:58 +01:00
Sadie Powell 1630ccedb1 Remove some double lookups in User::BadPassword. 2025-04-24 11:59:21 +01:00
Sadie Powell 36d69b1e5c Update the change logs. 2025-04-23 17:34:33 +01:00
Sadie Powell 627b89ec7b Fix a minor regression in serialising channel data. 2025-04-23 17:33:01 +01:00
Sadie Powell 9373677610 Respect NEVEROP in chanserv/set/{founder,successor}. 2025-04-23 03:21:08 +01:00
Sadie Powell bbb65ddc33 When deleting a single list item show the deleted item not a count.
Closes #487.
2025-04-23 01:57:02 +01:00
Sadie Powell 508bbe11e6 Show all privileges in nickserv/alist.
Closes #502.
2025-04-23 00:33:48 +01:00
Sadie Powell 095ed3c8c8 Allow users to unmark themselves as a channel successor.
Closes #501.
2025-04-22 22:53:40 +01:00
Sadie Powell f3743cd37d Remove hardcoded command names from most messages. 2025-04-22 18:56:26 +01:00
Sadie Powell 0c155e0c05 Replace hard linebreaks in RPC and webcpanel messages. 2025-04-22 18:16:31 +01:00
Sadie Powell f362959834 Fix splitting in the middle of some command names. 2025-04-22 18:16:31 +01:00
Sadie Powell f5a85c69d2 Remove time from the name of some variables where its obvious. 2025-04-19 22:53:49 +01:00
Sadie Powell c8b3819767 Add the anope.account and anope.listAccounts RPC events. 2025-04-19 22:31:49 +01:00
Sadie Powell e6a1982922 Fix various typos in the rpc_data docs. 2025-04-19 21:49:33 +01:00
Sadie Powell 40a1dc9536 Document the rpc_data result better. 2025-04-19 17:22:06 +01:00
Sadie Powell 70bf013ef0 Allow syntax messages to take a predicate. 2025-04-19 16:54:26 +01:00
Sadie Powell 18dfa62626 Add expanded data to the rpc_data list events. 2025-04-19 15:16:07 +01:00
Sadie Powell d815906393 Get rid of the internal block wrapper.
This only existed for compatibility with old 2.0 modules and 2.1
has already broken compatibility with them.
2025-04-19 12:49:06 +01:00
Sadie Powell 452e62c050 Add support for local password comparison in sql_authentication. 2025-04-19 12:38:32 +01:00
Sadie Powell 4916e1dbfc Use windows-2025 for the Windows CI.
[skip alpine ci]
[skip ubuntu ci]
2025-04-18 12:53:47 +01:00
Sadie Powell fa7ed12aad Use a duration string when telling people to wait before emailing. 2025-04-16 03:00:52 +01:00
Sadie Powell 94c20f3084 Use duration strings when reporting the expiry period. 2025-04-16 02:52:31 +01:00
Sadie Powell 597d4a1aee Update the change logs. 2025-04-16 02:45:53 +01:00
Sadie Powell 1e95d0f536 Fix some text strings that should be marked as translatable. 2025-04-16 02:19:17 +01:00
Sadie Powell ad0b4d1aa0 Rename TextSplitter to LineWrapper. 2025-04-16 01:53:50 +01:00
Sadie Powell 74e9a9d2fe Automatically wrap the help output. 2025-04-16 01:50:59 +01:00
Sadie Powell d2aee394ea Fix a compiler warning on Clang. 2025-04-16 00:14:46 +01:00
Sadie Powell 3e696fae0f Reduce the maximum line length from 120 to 100.
This should fit on user screens a bit better.
2025-04-16 00:07:33 +01:00
Sadie Powell ce362854a3 Update as many messages as possible for automatic line wrapping. 2025-04-16 00:04:30 +01:00
Sadie Powell a883b616a1 Automatically line wrap messages sent by services. 2025-04-15 19:30:59 +01:00
Sadie Powell b421ba258e Show the protection time in the INFO output. 2025-04-15 19:26:32 +01:00
Sadie Powell 3691887297 Add / to the default vhost chars. 2025-04-15 18:18:15 +01:00
Sadie Powell 75e2501500 Allow unbanning virtual modes, add the !unmute fantasy command. 2025-04-15 15:59:51 +01:00
Sadie Powell 1c6db37681 Fix a typo in cs_unban. 2025-04-15 15:29:59 +01:00
Sadie Powell 5c2fc1cedd Allow clearing other list modes using ClearBans. 2025-04-15 15:00:25 +01:00
Sadie Powell d891f2bcbd Sync the GitHub templates with the ones InspIRCd uses. 2025-04-15 13:51:51 +01:00
Sadie Powell 5eb13f4420 Use Anope::Template in db_json. 2025-04-15 13:04:09 +01:00
Sadie Powell bd9d3b0f7d Add support for monthly backups to db_json. 2025-04-15 13:00:34 +01:00
Sadie Powell cbb41241d4 Merge branch '2.0' into 2.1. 2025-04-15 11:42:49 +01:00
Sadie Powell b9acaa6d51 Ask people to file PRs on GitHub as well as emailing team@. 2025-04-15 10:05:51 +01:00
Sadie Powell 9d18fdf0f6 Update the change logs. 2025-04-14 11:56:40 +01:00
Sadie Powell d04a312d0d Add Anope::Templace and switch all template strings to use it. 2025-04-14 11:31:19 +01:00
Sadie Powell 099f0ce43a Purge the seen database after 90 days. 2025-04-14 01:51:40 +01:00
Sadie Powell 07bd1bbec9 Switch enc_sha2 default from sha256 to sha512. 2025-04-14 01:01:24 +01:00
Sadie Powell aa0a687a58 Fix a typo in the example config. 2025-04-14 01:00:17 +01:00
Sadie Powell b89cc47642 Resort the Implementation list. 2025-04-13 16:05:06 +01:00
Sadie Powell d87fa4d781 Add a matcher for the InspIRCd oper name extban. 2025-04-13 13:15:05 +01:00
Sadie Powell 9351debd73 Expand GetQueryCommand to take a command name. 2025-04-10 13:34:25 +01:00
Sadie Powell 40d558ef21 Make the length of confirmation codes configurable. 2025-04-07 12:27:45 +01:00
Sadie Powell e1224ac486 Ignore the SLOG message on UnrealIRCd. 2025-04-05 07:13:08 +01:00
Sadie Powell ddd33e65b4 Add a log message for when we receive a weirdly targeted message. 2025-04-05 07:11:54 +01:00
Sadie Powell e4f88d44cd Deduplicate checks in ns_cert. 2025-04-05 06:53:40 +01:00
Sadie Powell 063b4a9918 Merge branch '2.0' into 2.1. 2025-04-02 23:01:04 +01:00
Sadie Powell c6065ff0f3 Update the change log. 2025-04-02 23:00:12 +01:00
Sadie Powell a5aae4f41d Fix building in a post-CMP0082 world. 2025-04-02 23:00:12 +01:00
Sadie Powell d019da673d Replace NormalizeBuffer implementation with the one from InspIRCd.
This is more robust and will handle more formatting code types.
2025-04-02 17:04:47 +01:00
Sadie Powell 4d7adbf2b7 Fix an unnecessary substr in irc2sql. 2025-04-02 16:37:49 +01:00
Sadie Powell 404bf77ef5 Add a message handler for messages that can be safely ignored. 2025-04-02 13:17:38 +01:00
Sadie Powell 69393a5f14 Fix building in a post-CMP0082 world. 2025-04-02 13:12:19 +01:00
Sadie Powell 97c63822fc Bump the minimum CMake version to 3.20.
This should hopefully prevent us from being burned by CMake
dropping old version compatibility for a long time.
2025-04-02 10:11:21 +01:00
Sadie Powell 698dd78ef8 Merge branch '2.0' into 2.1. 2025-04-02 10:09:58 +01:00
Sadie Powell 0b36ddfaf3 Fix building on old versions of RHEL. 2025-04-02 09:58:49 +01:00
Sadie Powell 947ddc9e1b Fix building on CMake 4.
This is a partial backport from 2.1.
2025-04-02 09:53:10 +01:00
Sadie Powell 59d516d5b0 Refactor and document the rest of the SASL header. 2025-04-01 16:57:28 +01:00
Sadie Powell 2ecb667d1c Bump the minimum CMake version in the docs. 2025-04-01 16:29:11 +01:00
Sadie Powell c21f6ac597 Bump for 2.1.14-git. 2025-04-01 11:06:38 +01:00
Sadie Powell 390d0482fc Release 2.1.13. 2025-04-01 11:04:29 +01:00
Sadie Powell 65bb0a374b Move SASL::IdentifyRequest to ns_sasl.
This is only useful for plain authentication and doesn't need to
be in the header.
2025-03-31 16:58:22 +01:00
Sadie Powell ea4877dc16 Update the changelogs. 2025-03-30 13:06:48 +01:00
Sadie Powell 4024598bd8 Execute SQL updates atomically.
If the Serialize call alters any tables they would have previously
been missed here.
2025-03-30 13:01:13 +01:00
Sadie Powell a154532e98 Use insert_or_assign when creating ChannelInfo instances. 2025-03-30 12:42:18 +01:00
Sadie Powell 665b0fdef8 Refuse to import data that already exists in db_atheme. 2025-03-30 12:17:23 +01:00
Sadie Powell 0802d9d3ff Reference accounts in the database by their id not their nick. 2025-03-30 11:57:47 +01:00
Sadie Powell 8d3b8c08b3 Add NickAlias::FindId. 2025-03-30 11:04:46 +01:00
Sadie Powell f3e5ccf353 Initialize ChannelInfo in the Modern C++ way. 2025-03-26 11:23:05 +00:00
Sadie Powell b5213d5a81 Initialize Channel in the Modern C++ way. 2025-03-26 11:08:02 +00:00
Sadie Powell dc09408f1a Add a typedef for the serializable id. 2025-03-26 10:22:42 +00:00
Sadie Powell 49d86527ef Initialize the db_flatfile LoadData stream reference from the ctor. 2025-03-26 09:32:29 +00:00
Sadie Powell 65183c3c49 Update the change logs. 2025-03-26 09:18:56 +00:00
Sadie Powell c60477384c Add the db_json module. 2025-03-26 09:08:55 +00:00
Sadie Powell 25c3fd51b7 Fix a missing format argument in ns_maxemail. 2025-03-22 21:45:29 +00:00
Sadie Powell a40eaeb2a3 Use a plural form translation for the ns_maxemail error. 2025-03-22 21:04:25 +00:00
Sadie Powell e14a650cb9 Read the ns_maxemail limit as unsigned instead of int. 2025-03-22 21:02:52 +00:00
Sadie Powell 6401e328bb Merge branch '2.0' into 2.1. 2025-03-22 20:52:25 +00:00
Sadie Powell 43dc6f7509 Fix ns_maxemail miscounting email addresses in some cases. 2025-03-22 20:19:50 +00:00
Sadie Powell 8f0ee6f383 Update more messages to use gettext plural forms. 2025-03-22 08:58:24 +00:00
Sadie Powell 1adbce61cb Fix a semicolon that was missing from the previous commit. 2025-03-22 08:43:38 +00:00
Sadie Powell fe60c9a085 Fix an unclear message in gl_queue. 2025-03-22 08:36:57 +00:00
Sadie Powell 39bb5825ad Deduplicate requirename code in os_shutdown. 2025-03-22 08:33:21 +00:00
Sadie Powell 602ff60e21 Document the migration path for removed config options.
Also resort the config changelog so it is listed alphabetically.
2025-03-22 08:17:28 +00:00
Sadie Powell 8d0399e356 Document the default value for new config options in the changelog. 2025-03-22 08:04:55 +00:00
Sadie Powell a4d0213bcb Update the changelogs. 2025-03-22 07:59:54 +00:00
Sadie Powell ecbf53ba6c Allow customising the length at which lines are wrapped after.
Closes #485.
2025-03-22 07:33:02 +00:00
Sadie Powell 6d72fd67d8 Improve logging about the protocol module on startup. 2025-03-19 13:37:11 +00:00
Sadie Powell 0a11bc7693 Merge branch '2.0' into 2.1. 2025-03-19 13:08:14 +00:00
Sadie Powell e86fa67e38 Use a set instead of a vector for storing memo ignores. 2025-03-19 10:12:02 +00:00
Sadie Powell 1fc2642034 Make it clear that an ignore list is for memos in ms_ignore.
Closes #484.
2025-03-19 09:55:32 +00:00
Sadie Powell 1641f6415a RPC::service is not necessary anymore. 2025-03-17 19:06:14 +00:00
Sadie Powell bb1f93f150 Switch RPC event registration to use the service system. 2025-03-17 12:58:22 +00:00
Sadie Powell 85fbc500d8 Simplify the requirename logic. 2025-03-17 11:23:19 +00:00
Sadie Powell 99bcc6d3b7 Improve the error reporting in os_shutdown. 2025-03-16 20:21:34 +00:00
Sadie Powell 5fd2145821 Update author list. 2025-03-16 12:16:02 +00:00
Sadie Powell 4700d48b35 Import a slightly modified version of mkauthors from InspIRCd. 2025-03-16 12:16:02 +00:00
Sadie Powell 019b2aafef Update the mailmap. 2025-03-16 12:16:01 +00:00
Sadie Powell 3744649320 Move the RPC service interface to the RPC header. 2025-03-15 23:49:58 +00:00
Sadie Powell 30593321f4 Fix getting the IP of a user in CommandSource. 2025-03-15 21:08:49 +00:00
Sadie Powell 3b35199a53 Add NickCore::FindId for finding an account by its id. 2025-03-15 21:08:26 +00:00
Sadie Powell 5ac5e1068e Use custom-cloak when setting the SASL hostname too. 2025-03-15 00:17:18 +00:00
Sadie Powell 0ebc43f0dc Refactor the InspIRCd METADATA handler to actually be readable. 2025-03-14 23:21:42 +00:00
Sadie Powell 5ff86ea2c5 Implement support for the new way of setting vhosts on InspIRCd. 2025-03-14 19:45:43 +00:00
Sadie Powell 1bdc9c0a64 Fix {nickserv}:defaults still documenting the old nick protection. 2025-03-14 12:13:13 +00:00
Sadie Powell d0d46408bc Improve JSON-RPC error messages. 2025-03-14 11:49:01 +00:00
Sadie Powell fdc33b0f6d Warn if enc_bcrypt is the first module and maxpasslen is >72. 2025-03-14 11:09:35 +00:00
Sadie Powell 6a43370e13 Deduplicate response building code in the jsonrpc module. 2025-03-13 16:01:16 +00:00
Sadie Powell 1fcd045aff Fix the jsonrpc not having a root element one is not specified. 2025-03-13 15:49:33 +00:00
Sadie Powell b4d068b01a Fix the messageUser function in the JavaScript library. 2025-03-13 15:27:07 +00:00
Sadie Powell 23d548336a Document the required RPC modules in the JavaScript library. 2025-03-13 15:24:48 +00:00
Sadie Powell 82371dc279 Update the changelogs. 2025-03-13 15:17:08 +00:00
Sadie Powell fd6770373f Add the rpc_message module, remove the notice RPC event. 2025-03-13 15:12:47 +00:00
Sadie Powell 645f969d70 Fix sending global messages with the default sender. 2025-03-13 15:12:47 +00:00
Sadie Powell 3187233783 Fix setting keepbackups to 0 in db_flatfile. 2025-03-13 13:37:54 +00:00
Sadie Powell 8b932dc459 Fix a crash in the ns_sasl module.
Closes #481.
2025-03-13 12:52:50 +00:00
Sadie Powell a357ba38fb Fix deleting old db_flatfile database backups. 2025-03-13 12:14:17 +00:00
Sadie Powell 9f8525e3b2 Refactor the TIME handler. 2025-03-13 10:47:18 +00:00
Sadie Powell ace82596d8 Fix a warning on Clang. 2025-03-13 10:43:37 +00:00
Sadie Powell 09e10d2a02 Add an ALLTIME handler on InspIRCd. 2025-03-13 10:39:14 +00:00
Sadie Powell 9ec3f6abd6 Refactor and redocument Serialize::Type. 2025-03-12 16:52:46 +00:00
Sadie Powell e7b18609f6 Add defines for the core serialisation type names. 2025-03-12 15:53:52 +00:00
Sadie Powell cdcf0e2f9a Move serialization from Serializable to a Serialize::Type child. 2025-03-12 15:53:52 +00:00
Sadie Powell 718f2e922a Const correct Serialize::Type::GetName(). 2025-03-12 01:00:02 +00:00
Sadie Powell 2b2b6f75a1 Fix the id data type in db_flatfile. 2025-03-12 00:55:21 +00:00
Sadie Powell 883367c1d2 Fix importing some data from 1.8. 2025-03-12 00:33:41 +00:00
Sadie Powell 2276c62ff0 Move serialization data type logic from sql.h to the core. 2025-03-12 00:16:15 +00:00
Sadie Powell fb0ee27df0 Save the databases on SIGUSR1. 2025-03-12 00:16:15 +00:00
Sadie Powell b14befc77c Fix an outdated comment. 2025-03-10 13:10:13 +00:00
Sadie Powell 64fd5a862a Add an XML-RPC method to rpc_system for debugging RPC responses. 2025-03-10 13:03:29 +00:00
Sadie Powell 0ff170c671 Add a config option for disabling the i8 XML-RPC extension. 2025-03-10 12:48:13 +00:00
Sadie Powell ea0d5c4d70 Add a config option for disabling the nil XML-RPC extension. 2025-03-10 12:48:13 +00:00
Sadie Powell b96dbfc9ba Fix a memory leak in the xmlrpc module. 2025-03-10 11:07:29 +00:00
Sadie Powell e221c7642a Update the changelogs. 2025-03-09 20:14:03 +00:00
Sadie Powell b8c28419da Add a missing override keyword. 2025-03-09 19:49:28 +00:00
Sadie Powell 1c4f9042e7 Simplify some weird logic in bs_bot. 2025-03-09 19:31:58 +00:00
Sadie Powell a3f483ad87 Fix a forward declaration on Clang. 2025-03-09 18:58:49 +00:00
Sadie Powell 6e90a8ea55 Don't tell users that services is shutting down when its restarting. 2025-03-09 18:56:27 +00:00
Sadie Powell 6d7fe69cdf Add support for oper-only quit messages.
This currently only works on InspIRCd but I believe that other
servers also support this.
2025-03-09 18:51:03 +00:00
Sadie Powell 314ef60900 Fix a compiler warning on Clang. 2025-03-09 14:36:57 +00:00
Sadie Powell 1e8ac58bb4 Sync the chanserv defaults between the code and config. 2025-03-09 14:33:29 +00:00
Sadie Powell badcf31499 Make config variables a lot more useful.
- Config variables now no longer conflict with regular values.

- Config variables can now be read from the environment.
  (e.g. ${env.USER}).

- Config variables can now be used as partial values
  (e.g. support@${network.domain})
2025-03-09 14:20:34 +00:00
Sadie Powell c98602bf19 Fix various webcpanel bugs relating to nickname protection. 2025-03-08 14:45:26 +00:00
Sadie Powell 50bec959e5 Turn on channel persistence by default. 2025-03-08 14:25:08 +00:00
Sadie Powell 62bfa33464 Rework how nickname protection works.
- Rename the command and module from kill to protect (this command
  hasn't actually killed users in a long time).
- Replace QUICK/IMMED with a duration option.
2025-03-08 14:07:15 +00:00
Sadie Powell b4ab7dadb9 Use a C++11 lambda instead of a channel sorting method. 2025-03-08 12:41:22 +00:00
Sadie Powell df0cd3ef3e Move some headers around. 2025-03-08 12:22:07 +00:00
Sadie Powell 9e37a643f1 Fix some minor issues with db_atheme error messages. 2025-03-07 12:34:19 +00:00
Sadie Powell b30bfb5d2b Import misc channel and user metadata in db_atheme. 2025-03-07 12:31:42 +00:00
Sadie Powell cccdf0431b Don't warn when importing an external auth account from Atheme.
This happens when Atheme was using LDAP to authenticate users. We
will replace the temporary password at a later date if Anope is set
up to use LDAP too.
2025-03-06 23:31:56 +00:00
Sadie Powell 0005ebbbc3 Import logon and oper news from Atheme. 2025-03-06 23:05:38 +00:00
Sadie Powell 161841925d Force the MySQL module to use UTC for connections.
This prevents conversion issues when the MySQL server is in a
different timezone to the services server.
2025-03-06 20:51:13 +00:00
Sadie Powell e099180d8f Fix a REPRODUCIBLE_BUILD check after the previous commit. 2025-03-06 11:29:47 +00:00
Sadie Powell 2091dc68bc Move REPRODUCIBLE_BUILD to sysconf. 2025-03-06 01:24:39 +00:00
Sadie Powell 9926ac5a05 Fix reading the config of some modules. 2025-03-05 16:25:17 +00:00
Sadie Powell 14342f6375 Fix the on start library version logging to include the module. 2025-03-05 16:03:23 +00:00
Sadie Powell a0a9d433dc Blacklist an old UnrealIRCd contrib module that breaks Anope. 2025-03-04 17:15:07 +00:00
Sadie Powell c88fac1a20 Document {ns_sasl}:agent. 2025-03-04 00:50:20 +00:00
Sadie Powell 64d26f7c61 Remove GetAgent and SendMechs from the SASL interface.
These are only used by ns_sasl.
2025-03-04 00:43:06 +00:00
Sadie Powell 34896cefe9 Misc cleanup of ns_sasl and sasl.h. 2025-03-03 23:57:12 +00:00
Sadie Powell c0c7046a6d Check if users really want to use 2.1 in Config. 2025-03-03 23:29:53 +00:00
Sadie Powell 937ea7dab4 SASL::ProtocolInterface should not be exported. 2025-03-03 22:53:16 +00:00
Sadie Powell bfd2b0fa8e Merge branch '2.0' into 2.1. 2025-03-03 22:48:23 +00:00
Sadie Powell 7f2c281121 Fix a compiler warning on newer versions of MSVC. 2025-03-03 22:46:12 +00:00
Sadie Powell 224caf32c7 Rename sasl to ns_sasl, move to nickserv.example.conf. 2025-03-03 22:02:48 +00:00
Sadie Powell 5828cdba45 Move SASL protocol messages to the SASL header. 2025-03-03 21:45:59 +00:00
Sadie Powell 4526fbed96 Add a helper method for getting a description of an uplink. 2025-03-02 15:42:25 +00:00
Sadie Powell f9911dde52 Return references instead of pointers from the config system.
We used to return NULL from these methods but now we return an empty
block so this can never actually be null now.
2025-03-02 15:27:47 +00:00
Sadie Powell a5e5eb5eb0 Return EmptyBlock instead of NULL from GetModule. 2025-03-02 14:43:57 +00:00
Sadie Powell 82aecd6c7e Bump for 2.1.13-git. 2025-02-28 16:11:40 +00:00
Robby b448a20f40 Update the dutch language file. 2025-02-23 04:22:33 +01:00
265 changed files with 9421 additions and 6670 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Thanks for taking the time to fill out this bug report! Please make sure to answer the questions properly and don't just enter the same text into every field as this will make it harder for us to fix your bug.
If you're looking for help with setting up your services please post on [our support forum](https://github.com/orgs/anope/discussions/categories/support) instead.
+13
View File
@@ -24,3 +24,16 @@ I have tested this pull request on:
**Operating system name and version:** <!-- e.g. Linux 3.11 -->
**Compiler name and version:** <!-- e.g. GCC 4.2.0 -->
## Checks
<!--
Tick the boxes for the checks you have made.
-->
I have ensured that:
- [ ] The code I am submitting is my own work and/or I have permission from the author to share it.
- [ ] Generative AI (Copilot, ChatGPT, etc) was not used to create any part of this pull request.
- [ ] I have documented any features added by this pull request.
- [ ] This pull request does not introduce any incompatible API changes (stable branches only, delete if not applicable).
+25 -3
View File
@@ -10,10 +10,18 @@ on:
jobs:
build:
if: "!contains(github.event.head_commit.message, '[skip windows ci]')"
runs-on: windows-2019
runs-on: windows-2025
env:
BUILD_TYPE: ${{ github.event_name == 'release' && 'Release' || 'Debug' }}
CONAN_USER_HOME: ${{ github.workspace }}/win/build
CONAN_USER_HOME_SHORT: None
steps:
- uses: actions/checkout@v4
- name: Setup NSIS
run: |-
choco install nsis
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2
@@ -22,20 +30,34 @@ jobs:
with:
version: 1.64.0
- name: Try to restore libraries from the cache
uses: actions/cache/restore@v4
id: library-cache
with:
key: conan-${{ hashFiles('src/win32/conanfile.txt') }}
path: ${{ env.CONAN_USER_HOME }}/.conan
- name: Install libraries
run: |
conan install ${{ github.workspace }}\src\win32 --build=missing
- name: Save libraries to the cache
if: ${{ steps.library-cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v4
with:
key: ${{ steps.library-cache.outputs.cache-primary-key }}
path: ${{ env.CONAN_USER_HOME }}/.conan
- name: Run CMake
run: |
mkdir ${{ github.workspace }}\build
cd ${{ github.workspace }}\build
cmake -A "x64" -D "CMAKE_BUILD_TYPE=${{ github.event_name == 'release' && 'Release' || 'Debug' }}" -G "Visual Studio 16 2019" ..
cmake -A x64 -D "CMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }}" -G "Visual Studio 17 2022" ..
- name: Build Anope
working-directory: ${{ github.workspace }}\build
run: |
msbuild PACKAGE.vcxproj /M:3 /P:Configuration=${{ github.event_name == 'release' && 'Release' || 'Debug' }} /P:Platform=x64 /VERBOSITY:MINIMAL
msbuild PACKAGE.vcxproj /M:5 /P:Configuration=${{ env.BUILD_TYPE }} /P:Platform=x64 /VERBOSITY:MINIMAL
- name: Upload installer
if: "${{ github.event_name == 'release' }}"
+13 -3
View File
@@ -12,39 +12,49 @@ Charles Kingsley <chaz@anope.org>
Charles Kingsley <chaz@anope.org> <sjaz@5417fbe8-f217-4b02-8779-1006273d7864>
Cronus <cronus@nite-serv.com>
Daniel Engel <dane@zero.org> <dane dane@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864>
David Robson <rob@anope.org> <robbeh@5417fbe8-f217-4b02-8779-1006273d7864>
David Robson <rob@anope.org> <rob rob@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864>
David Robson <rob@anope.org> <robbeh@5417fbe8-f217-4b02-8779-1006273d7864>
Dennis Friis <peavey@inspircd.org> <peavey peavey@inspircd.org@5417fbe8-f217-4b02-8779-1006273d7864>
Dragone2 <dragone2@risposteinformatiche.it> <davide.paolini8@gmail.com>
Fabio Scotoni <cculex@gmail.com>
Filippo Cortigiani <simos@simosnap.org> <devel@devel.crtnet.it>
Filippo Cortigiani <simos@simosnap.org> <simos@H7-25.fritz.box>
Florian Schulze <certus@anope.org> <certus certus@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864>
Gabriel Acevedo H. <drstein@anope.org> <drstein drstein@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864>
Harakiri <harakiri@overstack.fr>
Hendrik Jäger <gitcommit@henk.geekmail.org> <github@henk.geekmail.org>
Jan Milants <viper@anope.org>
Jan Milants <viper@anope.org> <jantje_85@5417fbe8-f217-4b02-8779-1006273d7864>
Jan Milants <viper@anope.org> <viper viper@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864>
Jens Voss <dukepyrolator@anope.org> <anope@s15355730.onlinehome-server.info>
Jens Voss <dukepyrolator@anope.org> <DukePyrolator@5417fbe8-f217-4b02-8779-1006273d7864>
Jens Voss <dukepyrolator@anope.org> <DukePyrolator@anope.org>
Jens Voss <dukepyrolator@anope.org> Jens Voß <jens@pyrobook.(none)>
Jens Voss <dukepyrolator@anope.org> <jens@pyrobook.(none)>
k4be <k4be@pirc.pl> <34816207+k4bek4be@users.noreply.github.com>
Lee Holmes <lethality@anope.org>
Lee Holmes <lethality@anope.org> <lee@lethality.me.uk>
Mark Summers <mark@goopler.net> <mark mark@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864>
Matt Schatz <genius3000@g3k.solutions>
Matt Ullman <matt@airraidsirens.com> <blindsight@gamesurge.net>
Michael Hazell <michaelhazell@hotmail.com> <Techman-@users.noreply.github.com>
Michael Stapelberg <michael@robustirc.net> <stapelberg@users.noreply.github.com>
Michael Wobst <wobst.michael@web.de>
Michael Wobst <wobst.michael@web.de> <michael@static.163.129.251.148.clients.your-server.de>
Michael Wobst <wobst.michael@web.de> <michael@wobst.at>
Naram Qashat <cyberbotx@anope.org> <cyberbotx@5417fbe8-f217-4b02-8779-1006273d7864>
Naram Qashat <cyberbotx@anope.org> <cyberbotx@cyberbotx.com>
Naram Qashat <cyberbotx@anope.org> <Naram Qashat cyberbotx@cyberbotx.com@5417fbe8-f217-4b02-8779-1006273d7864>
PeGaSuS <droider.pc@gmail.com>
PeGaSuS <droider.pc@gmail.com> <25697531+TehPeGaSuS@users.noreply.github.com>
Pieter Bootsma <geniusdex@anope.org> <geniusdex geniusdex@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864>
Robby <robby@chatbelgie.be> <robby@anope.org>
Robby <robby@chatbelgie.be> <robby@chat.be>
Robert Scheck <robert@fedoraproject.org> <robert-scheck@users.noreply.github.com>
Robin Burchell <w00t@inspircd.org> <rburchell@5417fbe8-f217-4b02-8779-1006273d7864>
Robin Burchell <w00t@inspircd.org> <Robin Burchell w00t@inspircd.org@5417fbe8-f217-4b02-8779-1006273d7864>
Sadie Powell <sadie@witchery.services> Peter Powell <petpow@saberuk.com>
Sadie Powell <sadie@witchery.services> <petpow@saberuk.com>
Sebastian Barfurth <github@afreshmelon.com>
Sebastian V. <hal9000@denorastats.org>
Sebastian V. <hal9000@denorastats.org> <pimpmylinux@5417fbe8-f217-4b02-8779-1006273d7864>
Trystan S. Lee <trystan@nomadirc.net> <trystan trystan@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864>
Val Lorentz <progval+git@progval.net> <progval+git@progval.net>
+10 -15
View File
@@ -1,5 +1,5 @@
# This usage of CMake requires at least version 3.8
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
# This usage of CMake requires at least version 3.20
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
# Set the project as C++ primarily, but have C enabled for the checks required later
project(Anope CXX)
@@ -142,11 +142,6 @@ include_directories(
${Anope_SOURCE_DIR}/vendor
)
# Pass on REPRODUCIBLE_BUILD
if(REPRODUCIBLE_BUILD)
add_definitions(-DREPRODUCIBLE_BUILD)
endif()
if(WIN32)
# If using Windows, include the windows specific folder for anope_windows.h
include_directories(${Anope_SOURCE_DIR}/src/win32)
@@ -321,14 +316,6 @@ if(${Anope_SOURCE_DIR} STREQUAL ${Anope_BINARY_DIR})
endif()
endif()
# Go into the following directories and run their CMakeLists.txt as well
add_subdirectory(data)
add_subdirectory(docs)
add_subdirectory(language)
add_subdirectory(src)
add_subdirectory(modules)
add_subdirectory(include)
# Get the filename of the Anope binary, to use later
set(SERVICES_BINARY "$<TARGET_FILE:${PROGRAM_NAME}>")
get_filename_component(SERVICES_BINARY ${SERVICES_BINARY} NAME)
@@ -401,3 +388,11 @@ if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
set(CPACK_MONOLITHIC_INSTALL TRUE)
include(CPack)
endif()
# Go into the following directories and run their CMakeLists.txt as well
add_subdirectory(data)
add_subdirectory(docs)
add_subdirectory(language)
add_subdirectory(src)
add_subdirectory(modules)
add_subdirectory(include)
+30 -1
View File
@@ -113,6 +113,7 @@ while [ $# -ge 1 ] ; do
exit 0
elif [ $1 = "-devel" ] ; then
DEBUG="yes"
DEVEL="yes"
INSTDIR="$SOURCE_DIR/run"
elif [ $1 = "-nocache" ] ; then
IGNORE_CACHE="1"
@@ -138,7 +139,7 @@ done
cmake --version 2>&1 > /dev/null
if [ $? -ne 0 ] ; then
clear
echo "Anope requires CMake 3.8 or newer, which can be downloaded at https://cmake.org/ or through your system's package manager."
echo "Anope requires CMake 3.20 or newer, which can be downloaded at https://cmake.org/ or through your system's package manager."
echo "If you have installed CMake already, ensure it is in your PATH environment variable."
exit 0
fi
@@ -171,6 +172,33 @@ export ok INPUT
####
TEMP_YN="n"
if [ "$DEVEL" = "yes" ] ; then
TEMP_YN="y"
fi
echo "You are building the 2.1 development branch. This branch is not as well tested"
echo "as the 2.0 stable branch and may have compatibility breaks without notice. Are"
echo "you sure you want to use this version?"
echo -n "[$TEMP_YN] "
read YN
if [ "$YN" ] ; then
if [ "$YN" = "y" ] ; then
DEVEL="yes"
else
DEVEL="no"
fi
fi
echo ""
if [ "$DEVEL" != "yes" ] ; then
echo "If you are building from Git you can run \`git checkout 2.0\` to get the latest"
echo "stable code. Otherwise, you can download the latest 2.0 release tarball from"
echo "https://github.com/anope/anope/releases/latest"
exit 1
fi
####
ok=0
echo "In what directory should Anope be installed?"
while [ $ok -eq 0 ] ; do
@@ -337,6 +365,7 @@ INSTDIR="$INSTDIR"
RUNGROUP="$RUNGROUP"
UMASK=$UMASK
DEBUG="$DEBUG"
DEVEL="$DEVEL"
EXTRA_INCLUDE_DIRS="$EXTRA_INCLUDE_DIRS"
EXTRA_LIB_DIRS="$EXTRA_LIB_DIRS"
EXTRA_CONFIG_ARGS="$EXTRA_CONFIG_ARGS"
+126 -42
View File
@@ -79,13 +79,16 @@
/*
* [OPTIONAL] Defines
*
* You can define values to other values, which can be used to easily change
* many values in the configuration at once.
* You can use defines for repeated information, which can be used to easily change many
* values in the configuration at once.
*
* To use a define called foo.bar you use ${foo.bar} in your config file. You can also use
* environment variables by prefixing their name with "env." like ${env.USER}.
*/
/*
* The services.host define is used in multiple different locations throughout the
* configuration for services clients hostnames.
* configuration for the server name and pseudoclient hostnames.
*/
define
{
@@ -211,7 +214,7 @@ serverinfo
* other server names on the rest of your IRC network. Note that it does not have
* to be an existing hostname, just one that isn't on your network already.
*/
name = "services.example.com"
name = "${services.host}"
/*
* The text which should appear as the server's information in /WHOIS and similar
@@ -328,7 +331,7 @@ networkinfo
*
* It is recommended you DON'T change this.
*/
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-/"
/*
* If set to true, allows vHosts to not contain dots (.).
@@ -476,6 +479,26 @@ options
*/
didyoumeandifference = 4
/*
* The length of codes used for confirming actions like dropping a channel or a
* nickname.
*
* Defaults to 15 if not set.
*/
codelength = 15
/*
* If set, the maximum number of bytes after which to wrap services messages. This
* can be set a bit higher than the default but should be well under the maximum
* message length imposed by your IRC server or messages will end up truncated.
*
* NOTE: this currently only applies to tables but will be expanded to all messages
* in a later release.
*
* Defaults to 100 if not set.
*/
linelength = 100
/* The regex engine to use, as provided by the regex modules.
* Leave commented to disable regex matching.
*
@@ -746,8 +769,8 @@ log
* nickserv/getemail nickserv/suspend nickserv/ajoin nickserv/list
*
* nickserv/saset/autoop nickserv/saset/display nickserv/saset/email nickserv/saset/greet
* nickserv/saset/kill nickserv/saset/keepmodes nickserv/saset/language nickserv/saset/message
* nickserv/saset/neverop nickserv/saset/noexpire nickserv/saset/password nickserv/saset/private
* nickserv/saset/keepmodes nickserv/saset/language nickserv/saset/message nickserv/saset/neverop
* nickserv/saset/noexpire nickserv/saset/password nickserv/saset/private nickserv/saset/protect
* nickserv/saset/url
*
* hostserv/set hostserv/del hostserv/list
@@ -852,6 +875,16 @@ opertype
/* An optional password. If defined, the user must login using "/OPERSERV LOGIN" first */
#password = "secret"
/*
* The algorithm which the above password is hashed with. If this is not set then services will
* assume the above password is not hashed.
*
* You will need to have the appropriate encryption module (e.g. enc_bcrypt) loaded in order
* for this to work.
*
*/
#password_hash = "bcrypt"
/* An optional SSL fingerprint. If defined, it's required to be able to use this opertype. */
#certfp = "ed3383b3f7d74e89433ddaa4a6e5b2d7"
@@ -952,76 +985,76 @@ mail
* The subject and message of emails sent to users when they register accounts.
*
* Available tokens for this template are:
* %n - Gets replaced with the nickname
* %N - Gets replaced with the network name
* %c - Gets replaced with the confirmation code
* {nick} - Gets replaced with the nickname
* {network} - Gets replaced with the network name
* {code} - Gets replaced with the confirmation code
*/
registration_subject = "Nickname registration for %n"
registration_subject = "Nickname registration for {nick}"
registration_message = "Hi,
You have requested to register the nickname %n on %N.
Please type \" /msg NickServ CONFIRM %c \" to complete registration.
You have requested to register the nickname {nick} on {network}.
Please type \" /msg NickServ CONFIRM {code} \" to complete registration.
If you don't know why this mail was sent to you, please ignore it silently.
%N administrators."
{network} administrators."
/*
* The subject and message of emails sent to users when they request a new password.
*
* Available tokens for this template are:
* %n - Gets replaced with the nickname
* %N - Gets replaced with the network name
* %c - Gets replaced with the confirmation code
* {nick} - Gets replaced with the nickname
* {network} - Gets replaced with the network name
* {code} - Gets replaced with the confirmation code
*/
reset_subject = "Reset password request for %n"
reset_subject = "Reset password request for {nick}"
reset_message = "Hi,
You have requested to have the password for %n reset.
To reset your password, type \" /msg NickServ CONFIRM %n %c \"
You have requested to have the password for {nick} reset.
To reset your password, type \" /msg NickServ CONFIRM {nick} {code} \"
If you don't know why this mail was sent to you, please ignore it silently.
%N administrators."
{network} administrators."
/*
* The subject and message of emails sent to users when they request a new email address.
*
* Available tokens for this template are:
* %e - Gets replaced with the old email address
* %E - Gets replaced with the new email address
* %n - Gets replaced with the nickname
* %N - Gets replaced with the network name
* %c - Gets replaced with the confirmation code
* {old_email} - Gets replaced with the old email address
* {new_email} - Gets replaced with the new email address
* {account} - Gets replaced with the nickname
* {network} - Gets replaced with the network name
* {code} - Gets replaced with the confirmation code
*/
emailchange_subject = "Email confirmation"
emailchange_message = "Hi,
You have requested to change your email address from %e to %E.
Please type \" /msg NickServ CONFIRM %c \" to confirm this change.
You have requested to change your email address from {old_email} to {new_email}.
Please type \" /msg NickServ CONFIRM {code} \" to confirm this change.
If you don't know why this mail was sent to you, please ignore it silently.
%N administrators."
{network} administrators."
/*
* The subject and message of emails sent to users when they receive a new memo.
*
* Available tokens for this template are:
* %n - Gets replaced with the nickname
* %s - Gets replaced with the sender's nickname
* %d - Gets replaced with the memo number
* %t - Gets replaced with the memo text
* %N - Gets replaced with the network name
* {receiver} - Gets replaced with the receiver's nickname
* {sender} - Gets replaced with the sender's nickname
* {number} - Gets replaced with the memo number
* {text} - Gets replaced with the memo text
* {network} - Gets replaced with the network name
*/
memo_subject = "New memo"
memo_message = "Hi %n,
memo_message = "Hi {receiver},
You've just received a new memo from %s. This is memo number %d.
You've just received a new memo from {sender}. This is memo number {number}.
Memo text:
%t"
{text}"
}
/*
@@ -1087,11 +1120,9 @@ module
* Sets the number of days backups of databases are kept. If you don't give it,
* or if you set it to 0, Anope won't backup the databases.
*
* NOTE: Anope must run 24 hours a day for this feature to work.
*
* This directive is optional, but recommended.
*/
keepbackups = 3
keepbackups = 7
/*
* Allows Anope to continue file write operations (i.e. database saving)
@@ -1116,6 +1147,59 @@ module
fork = no
}
/*
* db_json
*
* Stores your data in a JSON file. This is currently experimental and has not
* been fully tested so make sure you have db_flatfile loaded as a secondary
* database module if you use this.
*/
#module
{
name = "db_json"
/*
* The file that db_json will write your main database to.
*
* This is relative to your data directory.
*/
database = "anope.json"
/*
* The file that db_json will write third-party databases to.
*
* {name} will be replaced with the name of the module.
*
* This is relative to your data directory.
*/
module_database = "{name}.module.json"
/*
* Sets how many days and months worth of backups should be kept.
*
* It is recommended that at the very least you keep one backup. Failure to
* do so may result in total data loss if you ever run out of disk space or
* have a power failure during a database write. However, if you're *REALLY*
* sure this won't happen you can disable backups by setting these to 0.
*/
daily_backups = 7
monthly_backups = 3
/*
* The directory in which backups are kept.
*
* This is relative to your data directory.
*/
backup_directory = "backups"
/*
* Allows Anope to continue writing the database even if the original can
* not be backed up. This is not recommended as it may result in total data
* loss during the circumstances described above.
*/
#ignore_backup_failure = yes
}
/*
* db_sql and db_sql_live
*
@@ -1207,9 +1291,9 @@ module
name = "enc_sha2"
/** The sub-algorithm to use. Can be set to sha224 for SHA-224, sha256 for
* SHA-256, sha284 for SHA-384, or sha512 for SHA-512. Defaults to sha256.
* SHA-256, sha384 for SHA-384, or sha512 for SHA-512. Defaults to sha512.
*/
#algorithm = "sha256"
#algorithm = "sha512"
}
/*
+2 -1
View File
@@ -31,7 +31,7 @@ service
/*
* The hostname of the BotServ client.
*/
host = "services.host"
host = "${services.host}"
/*
* The realname of the BotServ client.
@@ -410,6 +410,7 @@ fantasy { name = "SUSPEND"; command = "chanserv/suspend"; permission = "chanserv
fantasy { name = "SYNC"; command = "chanserv/sync"; }
fantasy { name = "TOPIC"; command = "chanserv/topic"; }
fantasy { name = "UNBAN"; command = "chanserv/unban"; }
fantasy { name = "UNMUTE"; command = "chanserv/unban"; mode = "QUIET"; }
fantasy { name = "UNSUSPEND"; command = "chanserv/unsuspend"; permission = "chanserv/suspend"; }
fantasy { name = "UP"; command = "chanserv/up"; }
fantasy { name = "VOICE"; command = "chanserv/modes"; }
+8 -8
View File
@@ -21,7 +21,7 @@ service
/*
* The hostname of the ChanServ client.
*/
host = "services.host"
host = "${services.host}"
/*
* The realname of the ChanServ client.
@@ -102,10 +102,10 @@ module
* to be a registered nick, otherwise the channel will be dropped.
* - none: No defaults
*
* This directive is optional, if left blank, the options will default to keeptopic, peace,
* securefounder, and signkick. If you really want no defaults, use "none" by itself as the option.
* This directive is optional, if left blank, the options will default to cs_keep_modes, keeptopic, peace,
* persist, securefounder, and signkick. If you really want no defaults, use "none" by itself as the option.
*/
defaults = "keeptopic peace securefounder signkick"
defaults = "cs_keep_modes keeptopic peace persist securefounder signkick"
/*
* The maximum number of channels which may be registered to a single nickname.
@@ -163,10 +163,10 @@ module
/*
* The message formatting to use for signed kick messages.
* %n is the nick of the kicker
* %m is the message specified
* {nick} is the nick of the kicker
* {message} is the message specified
*/
signkickformat = "%m (%n)"
signkickformat = "{message} ({nick})"
/*
* If set, prevents channel access entries from containing hostmasks.
@@ -1182,7 +1182,7 @@ module
simple = false
/* Sets the time to keep seen entries in the seen database. */
purgetime = "30d"
purgetime = 90d
}
command { service = "OperServ"; name = "SEEN"; command = "operserv/seen"; permission = "operserv/seen"; }
+1 -1
View File
@@ -21,7 +21,7 @@ service
/*
* The hostname of the Global client.
*/
host = "services.host"
host = "${services.host}"
/*
* The realname of the Global client.
+1 -1
View File
@@ -21,7 +21,7 @@ service
/*
* The hostname of the HostServ client.
*/
host = "services.host"
host = "${services.host}"
/*
* The realname of the HostServ client.
+1 -1
View File
@@ -18,7 +18,7 @@ service
/*
* The hostname of the StatServ client.
*/
host = "stats.host"
host = "${services.host}"
/*
* The realname of the StatServ client.
+1 -1
View File
@@ -21,7 +21,7 @@ service
/*
* The hostname of the MemoServ client.
*/
host = "services.host"
host = "${services.host}"
/*
* The realname of the MemoServ client.
+65 -29
View File
@@ -119,15 +119,15 @@ module { name = "help" }
time = 4h
/* Reason for akill.
* %n is the nick of the user
* %u is the ident/username of the user
* %g is the realname of the user
* %h is the hostname of the user
* %i is the IP of the user
* %r is the reply reason (configured below). Will be nothing if not configured.
* %N is the network name set in networkinfo:networkname
* {nick} is the nick of the user
* {user} is the ident/username of the user
* {real} is the realname of the user
* {host} is the hostname of the user
* {ip} is the IP of the user
* {reply} is the reply reason (configured below). Will be nothing if not configured.
* {network} is the network name set in networkinfo:networkname
*/
reason = "You are listed in the EFnet RBL, visit https://rbl.efnetrbl.org/?i=%i for info"
reason = "You are listed in the EFnet RBL, visit https://rbl.efnetrbl.org/?i={ip} for info"
/* Replies to ban and their reason. If no replies are configured, all replies get banned. */
reply
@@ -171,7 +171,7 @@ module { name = "help" }
{
name = "dnsbl.dronebl.org"
time = 4h
reason = "You have a host listed in the DroneBL. For more information, visit https://dronebl.org/lookup_branded?ip=%i&network=%N"
reason = "You have a host listed in the DroneBL. For more information, visit https://dronebl.org/lookup?ip={ip}&network={network}"
}
/* Exempt localhost from DNSBL checks */
@@ -270,10 +270,10 @@ module { name = "help" }
/*
* The search filter used to look up users's accounts.
* %account is replaced with the user's account.
* %object_class is replaced with the object_class configured below.
* {account} is replaced with the user's account.
* {object_class} is replaced with the object_class configured below.
*/
search_filter = "(&(uid=%account)(objectClass=%object_class))"
search_filter = "(&(uid={account})(objectClass={object_class}))"
/*
* The object class used by LDAP to store user account information.
@@ -327,7 +327,7 @@ module { name = "help" }
/*
* An optional binddn to use when searching for groups.
* %a is replaced with the account name of the user.
* {account} is replaced with the account name of the user.
*/
#binddn = "cn=Manager,dc=anope,dc=org"
@@ -343,9 +343,9 @@ module { name = "help" }
/*
* The filter to use when searching for users.
* %a is replaced with the account name of the user.
* {account} is replaced with the account name of the user.
*/
filter = "(member=uid=%a,ou=users,dc=anope,dc=org)"
filter = "(member=uid={account},ou=users,dc=anope,dc=org)"
/*
* The attribute of the group that is the name of the opertype.
@@ -550,24 +550,14 @@ module
/*
* The reason to ban the user for.
* %h is replaced with the type of proxy found.
* %i is replaced with the IP of proxy found.
* %p is replaced with the port.
* {type} is replaced with the type of proxy found.
* {ip} is replaced with the IP of proxy found.
* {port} is replaced with the port.
*/
reason = "You have an open proxy running on your host (%t:%i:%p)"
reason = "You have an open proxy running on your host ({type}:{ip}:{port})"
}
}
/*
* sasl
*
* Some IRCds allow "SASL" authentication to let users identify to services
* during the IRCd user registration process. If this module is loaded, Anope will allow
* authenticating users through this mechanism. Supported mechanisms are:
* PLAIN, EXTERNAL.
*/
module { name = "sasl" }
/*
* ssl_gnutls [EXTRA]
*
@@ -680,6 +670,23 @@ module { name = "sasl" }
*/
query = "SELECT `email_addr` AS `email` FROM `my_users` WHERE `username` = @a@ AND `password` = MD5(CONCAT('salt', @p@))"
/*
* If your database uses a password hashing algorithm that can not be compared using a simple
* comparison function then you can specify it here to compare locally.
*
* You will need to have the appropriate encryption module (e.g. enc_bcrypt) loaded in order
* for this to work.
*/
#password_hash = "bcrypt"
/*
* If using the password_hash field (above) you will need to specify the name of the field to
* fetch the password from.
*
* Defaults to "password" if not set.
*/
#password_field = "password"
/*
* If set, the reason to give the users who try to "/msg NickServ REGISTER".
* If not set, then registration is not blocked.
@@ -815,6 +822,20 @@ module { name = "sasl" }
/* Web service to use. Requires httpd. */
server = "httpd/main"
/*
* Whether to enable the use of XML-RPC extensions.
*
* By default Anope will use some extended XML-RPC types. If your XML-RPC
* client can not handle these you will need to disable them.
*
* If i8 is disabled a string will be used for values outside of the range
* supported by the 32-bit int data type.
*
* If nil is disabled an empty struct will be used instead.
*/
#enable_i8 = no
#enable_nil = no
}
/*
@@ -822,6 +843,7 @@ module { name = "sasl" }
*
* Adds support for the following RPC methods:
*
* anope.listAccounts anope.account
* anope.listChannels anope.channel
* anope.listOpers anope.oper
* anope.listServers anope.server
@@ -841,6 +863,20 @@ module { name = "sasl" }
*/
#module { name = "rpc_main" }
/*
* rpc_message
*
* Adds support for the following RPC methods:
*
* anope.messageNetwork anope.messageServer
* anope.messageUser
*
* Requires either the jsonrpc or xmlrpc module.
*
* See docs/RPC/rpc_message.md for API documentation.
*/
#module { name = "rpc_message" }
/*
* rpc_system
*
+60 -35
View File
@@ -21,7 +21,7 @@ service
/*
* The hostname of the NickServ client.
*/
host = "services.host"
host = "${services.host}"
/*
* The realname of the NickServ client.
@@ -93,7 +93,7 @@ module
#confirmemailchanges = yes
/*
* A message sent to users on connect if they use an unregistered nick. %n will be replaced with the user's nickname.
* A message sent to users on connect if they use an unregistered nick. {nick} will be replaced with the user's nickname.
*
* This directive is optional.
*/
@@ -105,11 +105,6 @@ module
* by spaces.
*
* The options are:
* - killprotect: Kill nick if not identified within 60 seconds
* - kill_quick: Kill nick if not identified within 20 seconds, this one overrides the killprotect
* option and the killprotect option must be specified with this one
* - kill_immed: Kill nick immediately if not identified, this one overrides both the killprotect
* and kill_quick options and the killprotect option must be specified with this one
* - ns_private: Hide the nick from NickServ's LIST command
* - hide_email: Hide the nick's email address from NickServ's INFO command
* - hide_mask: Hide the nick's last or current user@host from NickServ's INFO command
@@ -122,11 +117,12 @@ module
* - neverop: User can not be added to access lists
* - msg: Messages will be sent as PRIVMSGs instead of NOTICEs
* - ns_keep_modes: Enables keepmodes, which retains user modes across sessions
* - protect: Protects the registered nickname from use by unidentified users.
*
* This directive is optional, if left blank, the options will default to memo_signon, and
* memo_receive. If you really want no defaults, use "none" by itself as the option.
*/
defaults = "killprotect ns_private hide_email hide_mask memo_signon memo_receive autoop"
defaults = "autoop hide_email hide_mask memo_receive memo_signon ns_private protect"
/*
* The minimum length of time between consecutive uses of NickServ's REGISTER command. This
@@ -171,11 +167,25 @@ module
hidenetsplitquit = no
/*
* If set, is the length of time NickServ's killquick and kill options wait before
* forcing users off of protected nicknames.
* The default period to force users to stop using a protected nickname after.
*
* Defaults to 1 minute.
*/
killquick = 20s
kill = 60s
defaultprotect = 1m
/*
* The minimum period that a user can have a user forced off their protected nickname after.
*
* Defaults to 10 seconds.
*/
minprotect = 10s
/*
* The maximum period that a user can have a user forced off their protected nickname after.
*
* Defaults to 10 minutes.
*/
maxprotect = 10m
/*
* If set, forbids the registration of nicks that contain an existing
@@ -196,7 +206,7 @@ module
* hold a nickname.
*/
enforceruser = "enforcer"
enforcerhost = "services.host"
enforcerhost = "${services.host}"
/*
* The length of time Anope should hold nicknames for.
@@ -519,6 +529,27 @@ command { service = "NickServ"; name = "RESEND"; command = "nickserv/resend"; }
module { name = "ns_resetpass" }
command { service = "NickServ"; name = "RESETPASS"; command = "nickserv/resetpass"; }
/*
* ns_sasl
*
* Provides support for authentication to services via IRCv3 SASL. This is a standardised
* alternative to ns_identify that is supported by several IRCds.
*
* You will need to configure your IRCd to use SASL. See the following links for details:
*
* InspIRCd: https://docs.inspircd.org/4/modules/sasl/
* UnrealIRCd: https://www.unrealircd.org/docs/SASL#Enabling_SASL_on_the_server
*/
module
{
name = "ns_sasl"
/*
* The nick of the client which operates as the SASL agent.
*/
#agent = "NickServ"
}
/*
* ns_set
*
@@ -575,28 +606,6 @@ module
command { service = "NickServ"; name = "SET KEEPMODES"; command = "nickserv/set/keepmodes"; }
command { service = "NickServ"; name = "SASET KEEPMODES"; command = "nickserv/saset/keepmodes"; permission = "nickserv/saset/keepmodes"; }
/*
* ns_set_kill
*
* Provides the commands nickserv/set/kill and kickserv/saset/kill.
*
* Used for configuring nickname protection.
*/
module
{
name = "ns_set_kill"
/*
* Allow the use of the IMMED option in the NickServ SET KILL command.
*
* This directive is optional.
*/
#allowkillimmed = yes
}
command { service = "NickServ"; name = "SET KILL"; command = "nickserv/set/kill"; }
command { service = "NickServ"; name = "SASET KILL"; command = "nickserv/saset/kill"; permission = "nickserv/saset/kill"; }
/*
* ns_set_language
*
@@ -641,6 +650,22 @@ command { service = "NickServ"; name = "SASET URL"; command = "nickserv/saset/mi
#command { service = "NickServ"; name = "SET TIMEZONE"; command = "nickserv/set/misc"; misc_description = _("Associate a time zone with your account"); }
#command { service = "NickServ"; name = "SASET TIMEZONE"; command = "nickserv/saset/misc"; misc_description = _("Associate a time zone with this account"); permission = "nickserv/saset/timezone"; group = "nickserv/admin"; }
/*
* ns_set_protect
*
* Provides the commands nickserv/set/protect and kickserv/saset/protect.
*
* Used for configuring nickname protection.
*/
module { name = "ns_set_protect" }
command { service = "NickServ"; name = "SET PROTECT"; command = "nickserv/set/protect"; }
command { service = "NickServ"; name = "SASET PROTECT"; command = "nickserv/saset/protect"; permission = "nickserv/saset/kill"; }
# For compatibility with Anope 2.0.
command { service = "NickServ"; name = "SET KILL"; command = "nickserv/set/protect"; hide = true; }
command { service = "NickServ"; name = "SASET KILL"; command = "nickserv/saset/protect"; permission = "nickserv/saset/protect"; hide = true; }
/*
* ns_suspend
*
+9 -2
View File
@@ -21,7 +21,7 @@ service
/*
* The hostname of the OperServ client.
*/
host = "services.host"
host = "${services.host}"
/*
* The realname of the OperServ client.
@@ -502,6 +502,13 @@ module
* This directive is optional, if not set it will default to 3.
*/
#newscount = 3
/*
* Whether to show the datetime at which the news entry was added.
*
* This directive is optional, if not set it will default to yes.
*/
#showdate = yes
}
command { service = "OperServ"; name = "LOGONNEWS"; command = "operserv/logonnews"; permission = "operserv/news"; }
command { service = "OperServ"; name = "OPERNEWS"; command = "operserv/opernews"; permission = "operserv/news"; }
@@ -580,7 +587,7 @@ module
*
* This directive is optional, if not set, nothing will be sent.
*/
sessionlimitexceeded = "The session limit for your IP %IP% has been exceeded."
sessionlimitexceeded = "The session limit for your IP {ip} has been exceeded."
/*
* Same as above, but should be used to provide a website address where users can find out more
+9 -6
View File
@@ -79,17 +79,20 @@
/*
* [OPTIONAL] Defines
*
* You can define values to other values, which can be used to easily change
* many values in the configuration at once.
* You can use defines for repeated information, which can be used to easily change many
* values in the configuration at once.
*
* To use a define called foo.bar you use ${foo.bar} in your config file. You can also use
* environment variables by prefixing their name with "env." like ${env.USER}.
*/
/*
* The stats.host define is used in multiple different locations throughout the
* configuration for the stats client hostname.
* The services.host define is used in multiple different locations throughout the
* configuration for the server name and pseudoclient hostnames.
*/
define
{
name = "stats.host"
name = "services.host"
value = "stats.example.com"
}
@@ -208,7 +211,7 @@ serverinfo
* other server names on the rest of your IRC network. Note that it does not have
* to be an existing hostname, just one that isn't on your network already.
*/
name = "stats.example.com"
name = "${services.host}"
/*
* The text which should appear as the server's information in /WHOIS and similar
+92
View File
@@ -0,0 +1,92 @@
Since the first commit in March 2004 88 people have submitted patches, commits,
and other useful contributions to Anope. These people, ordered by the number of
contributions they have made, are:
* Adam <adam@anope.org>
* Sadie Powell <sadie@witchery.services>
* Robin Burchell <w00t@inspircd.org>
* Naram Qashat <cyberbotx@anope.org>
* Pieter Bootsma <geniusdex@anope.org>
* Jens Voss <dukepyrolator@anope.org>
* David Robson <rob@anope.org>
* Florian Schulze <certus@anope.org>
* Daniel Engel <dane@zero.org>
* Trystan S. Lee <trystan@nomadirc.net>
* Robby <robby@chatbelgie.be>
* Charles Kingsley <chaz@anope.org>
* Lee Holmes <lethality@anope.org>
* Gabriel Acevedo H. <drstein@anope.org>
* Jan Milants <viper@anope.org>
* Adam Kramer <ribosome@anope.org>
* Attila Molnar <attilamolnar@hush.com>
* Michael Wobst <wobst.michael@web.de>
* Mark Summers <mark@goopler.net>
* Matt Schatz <genius3000@g3k.solutions>
* Daniel Vassdal <shutter@canternet.org>
* MatthewM <mcm@they-got.us>
* PeGaSuS <droider.pc@gmail.com>
* Sebastian V. <hal9000@denorastats.org>
* Alvaro Toledo <atoledo@keldon.org>
* Dragone2 <dragone2@risposteinformatiche.it>
* Björn Stiddien <keeper@anope.org>
* n0kS Phr33d0m <god@politeia.in>
* Hendrik Jäger <gitcommit@henk.geekmail.org>
* k4be <k4be@pirc.pl>
* Thomas Fargeix <t.fargeix@gmail.com>
* Bram Matthys <syzop@vulnscan.org>
* Federico G. Schwindt <fgsch@lodoss.net>
* Val Lorentz <progval+git@progval.net>
* Alexander Barton <alex@barton.de>
* CaPa CuL <capacul@gmail.com>
* Cronus <cronus@nite-serv.com>
* H7-25 <simos@simosnap.org>
* Jyzee <jyzee.git@gmail.com>
* Sebastian Barfurth <github@afreshmelon.com>
* Zantox <jyoerger10@msn.com>
* Zoddo <zoddo.ino@gmail.com>
* Dominic Hargreaves <dom@earth.li>
* Michael Hazell <michaelhazell@hotmail.com>
* Robert Scheck <robert@fedoraproject.org>
* Dennis Friis <peavey@inspircd.org>
* Filippo Cortigiani <simos@simosnap.org>
* Michał Zegan <webczat_200@poczta.onet.pl>
* AlphaTech <alphat3ch@icloud.com>
* Austin Ellis <siniStar@IRC4Fun.net>
* bonnedav <theD_2011@hotmail.com>
* Denis M. (Phr33d0m) <god@politeia.in>
* Harakiri <harakiri@overstack.fr>
* Marcin Łabanowski <marcin@6irc.net>
* Matt Ullman <matt@airraidsirens.com>
* Michael Stapelberg <michael@robustirc.net>
* Alexander Maassen <outsider@twingoversum.scarynet.org>
* artemiiav <artemiiav@gmail.com>
* blackbeard420 <blackbeard@blackbeard420.me>
* BoGu5 <bogus@onzin.org>
* Chris Langsenkamp <chris@langsenkamp.com>
* Clem Morton
* Daniel Oaks <danneh@danneh.net>
* Fabio Scotoni <cculex@gmail.com>
* ItsOnlyBinary
* Jason Foster <retsofaj@gmail.com>
* Jeremy <jeremy@ssnet.ca>
* Josh Soref
* KindOne <ineedalifetoday@live.com>
* linuxdaemon
* Mantas Mikulėnas <grawity@gmail.com>
* Matthew Beeching <jobe@mdbnet.co.uk>
* Michael <michaelhazell@hotmail.com>
* Mingjie Shen <shen497@purdue.edu>
* nekoswag
* Peter Tseng <pht24@cornell.edu>
* Romain Rivière <lecoyote@lecoyote.org>
* Sam James (sam_c) <sam@cmpct.info>
* ShutterQuick <shutter@canternet.org>
* Sketch <denverfreeburn@outlook.com>
* Tim Gunter <tim@vanillaforums.com>
* Toni Kaija <diftraku@gmail.com>
* Victor Coss <gtaxl@gtaxl.net>
* VisioN <vision@myirc.us>
* westor <westor7@gmail.com>
* Wilson Birney <wpb@360scada.com>
* Yann Sionneau <yann@sionneau.net>
* Zach Bloomquist <zrbq@live.com>
+59
View File
@@ -1,3 +1,62 @@
Anope Version 2.1.14-git
------------------------
Added a detail specifier to the anope.list{Channels,Opers,Servers,Users} RPC methods.
Added a matcher for the InspIRCd oper extban.
Added support for hashed operator passwords.
Added support for hiding the date news was added in os_news.
Added support for local password comparison to the sql_authentication module.
Added support for monthly backups to db_json.
Added support for unbanning virtual modes using cs_unban.
Added the !unmute fantasy command.
Added the anope.account and anope.listAccounts RPC methods to the rpc_data module.
Added the protection time to the INFO output.
Allowed unprivileged channel successors to remove themselves from succession.
Bumped the minimum required CMake version to 3.20.
Changed deletion callbacks to specify the mask that was deleted if only one was.
Changed nickserv/alist to show all permissions not just the highest ranked one.
Fixed NEVEROP not being respected in chanserv/set/founder and chanserv/set/successor.
Fixed stripping IRC formatting codes from messages.
Messages are now automatically line wrapped to options:linelength.
Redocumented the ns_sasl module.
Removed hardcoded command names from several messages.
Updated the Windows CI to Windows Server 2025 and Visual Studio 2022.
Anope Version 2.1.13
--------------------
Added a Config check to ensure users actually want to use the development branch.
Added a flag to the version string when Anope is compiled in reproducible mode.
Added a warning on rehash when the max password is longer than the maximum bcrypt password length.
Added an ALLTIME handler on InspIRCd.
Added an opt-out for extended XML-RPC types.
Added RPC messages for sending global messages.
Added support for importing cs_set_misc and ns_set_misc data from Atheme.
Added support for importing news from Atheme.
Added support for oper-only quit messages.
Added support for the experimental "services cloak" system from the InspIRCd development branch.
Added support for using defines from the environment.
Added support for using defines within the value of a variable.
Blacklisted an old version of an UnrealIRCd module that is known to send malformed S2S messages.
Changed RPC events to be registered as core services.
Changed the database to refer to accounts by their account identifier instead of their display nick.
Changed the syntax of defines from "foo" to "${foo}".
Deduplicated JSON generation code in the jsonrpc module.
Fixed a warning when importing an Atheme account that uses external authentication.
Fixed counting email addresses in ns_maxemail.
Fixed db_atheme creating duplicate accounts, bots, and nicks when importing over an existing database.
Fixed deleting old database backups after Anope has been restarted.
Fixed importing user metadata from Anope 1.8.
Fixed including a port in uplink messages when connecting to a UNIX socket endpoint.
Fixed memo ignores being erroneously case sensitive.
Fixed modules with third-party dependencies writing generic log messages instead of module log messages.
Fixed not performing SQL database updates in some rare circumstances.
Fixed sending global messages with the default sender.
Imported mkauthors from InspIRCd and used it to generate docs/AUTHORS.txt
Moved around a bunch of module headers.
Moved database serialization from the serializable to the serializable type.
Moved the SASL protocol interface to its own service.
Refactored handling S2S metadata on InspIRCd.
Updated more messages to use gettext plural forms.
Anope Version 2.1.12
--------------------
Added an example JavaScript library for accessing the RPC interface.
+54 -23
View File
@@ -1,3 +1,35 @@
Anope Version 2.1.14-git
------------------------
Added oper:password_hash.
Added options:codelength (defaults to 15).
Added {os_news}:showdate (defaults to yes).
Added {sql_authentication}:password_field (defaults to "password").
Added {sql_authentication}:password_hash.
Changed the default value for options:linelength to "100".
Changed the default value for {enc_sha2}:algorithm to "sha512".
Changed the default value for {ns_seen}:purgetime to "90d".
Changed the syntax for template variables in mail:emailchange_message, mail:emailchange_subject, mail:memo_message, mail:memo_subject, mail:registration_message, mail:registration_subject,, mail:reset_message, mail:reset_subject, {chanserv}:signkickformat, {dnsbl}:blacklist:reason, {ldap_authentication}:search_filter, {ldap_oper}:binddn, {ldap_oper}:search_filter, {nickserv}:unregistered_notice, {os_session}:sessionlimitexceeded, {proxyscan}:proxyscan:reason.
Anope Version 2.1.13
--------------------
Added options:linelength (defaults to 120).
Added the db_json module.
Added the rpc_message module.
Added {nickserv}:defaultprotect (defaults to 1m).
Added {nickserv}:maxprotect (defaults to 10m).
Added {nickserv}:minprotect (defaults to 10s)
Added {xmlrpc}:enable_i8 (defaults to yes).
Added {xmlrpc}:enable_nil (defaults to yes).
Changed the syntax for using defines (all existing defines will need to be updated).
Removed {nickserv}:kill (replaced by custom protection timer durations).
Removed {nickserv}:killquick (replaced by custom protection timer durations).
Removed {ns_set_kill}:allowkillimmed (replaced by custom protection timer durations).
Renamed the nickserv/saset/kill command to nickserv/saset/protect.
Renamed the nickserv/saset/kill oper privilege to nickserv/saset/protect.
Renamed the nickserv/set/kill command to nickserv/set/protect.
Renamed the ns_set_kill module to ns_set_protect.
Renamed the sasl module to ns_sasl and moved it to nickserv.example.conf.
Anope Version 2.1.12
--------------------
Added the jsonrpc module.
@@ -11,16 +43,16 @@ Renamed the xmlrpc_main module to rpc_main.
Anope Version 2.1.11
--------------------
Moved {ns_set}:allowkillimmed to {ns_set_kill}:allowkillimmed.
Moved nickserv/set/kill and nickserv/saset/kill to the ns_set_kill module.
Replaced {nickserv}:guestnickprefix with {nickserv}:guestnick.
Moved {ns_set}:allowkillimmed to {ns_set_kill}:allowkillimmed.
Replaced {nickserv}:guestnickprefix with {nickserv}:guestnick (defaults to Guest####).
Anope Version 2.1.10
--------------------
Added options:servicealias.
Added options:servicealias (defaults to no)
Moved nickserv/set/message and nickserv/saset/message to the ns_set_message module.
Removed options:useprivmsg.
Removed options:usestrictprivmsg.
Removed options:useprivmsg (replaced by loading the ns_set_message module to enable).
Removed options:usestrictprivmsg (feature unusable on modern servers, consider migrating to options:servicealias instead).
Anope Version 2.1.9
-------------------
@@ -28,14 +60,14 @@ No significant changes.
Anope Version 2.1.8
-------------------
Added {nickserv}:preservedisplay.
Added the nickserv/drop/display oper privilege.
Added {nickserv}:preservedisplay (defaults to no).
Anope Version 2.1.7
-------------------
Moved nickserv/set/language and nickserv/saset/language to the ns_set_language module.
Renamed the FANTASIA channel privilege to FANTASY.
Renamed {cs_suspend}:expire to {cs_suspend}:suspendexpire.
Renamed the FANTASIA privilege to FANTASY.
Anope Version 2.1.6
-------------------
@@ -55,8 +87,8 @@ Added the enc_posix module.
Added the enc_sha2 module.
Added the gl_queue module.
Added the gl_server module.
Added the global/queue operator privilege.
Added the global/server operator privilege.
Added the global/queue oper privilege.
Added the global/server oper privilege.
Changed serverinfo:motd to be relative to the config directory.
Changed serverinfo:pid to be relative to the data directory.
Changed the default value of mail:sendmailpath to "/usr/sbin/sendmail -it".
@@ -64,13 +96,12 @@ Changed the default value of {chanserv}:accessmax to 1000.
Changed the default value of {chanserv}:inhabit to 1 minute.
Changed the default value of {cs_mode}:max to 50.
Changed the default value of {ms_ignore}:max to 50.
Removed options:seed.
Replaced {webcpanel}:template with {webcpanel}:template_dir.
Removed options:seed (not needed with modern random number generation).
Replaced {webcpanel}:template with {webcpanel}:template_dir (defaults to webcpanel/templates/default).
Anope Version 2.1.3
-------------------
Added options:didyoumeandifference.
Added options:didyoumeandifference (defaults to 4).
Added support for multiple SSL fingerprints in oper:certfp.
Added the chanserv/cert oper privilege for modifying other user's certificate lists.
Changed networkinfo:chanlen to default to 32 if not set.
@@ -80,21 +111,21 @@ Changed networkinfo:nicklen to default to 31 if not set.
Changed networkinfo:userlen to default to 10 if not set.
Increased the default maximum password length to 50 characters.
Increased the default minimum password length to 10 characters.
Removed the cs_secure option in {chanserv}:defaults (now always enabled).
Removed the nickserv/saset/secure command.
Removed the nickserv/saset/secure oper privilege.
Removed the nickserv/set/secure command.
Removed the nickserv/status command.
Removed the ns_access module.
Removed the ns_secure option in {nickserv}:defaults (now always enabled).
Removed the cs_secure option in {chanserv}:defaults (now always enabled as support for nick access lists has been removed).
Removed the nickserv/saset/secure command (support for nick access lists has been removed).
Removed the nickserv/saset/secure oper privilege (support for nick access lists has been removed).
Removed the nickserv/set/secure command (support for nick access lists has been removed).
Removed the nickserv/status command (obsolete with modern IRCv3 extensions and the removal of nick access lists).
Removed the ns_access module (support for nick access lists has been removed).
Removed the ns_secure option in {nickserv}:defaults (now always enabled as support for nick access lists has been removed).
Anope Version 2.1.2
-------------------
Added {ssl_openssl}:tlsv10 for configuring whether TLSv1.0 is usable (defaults to no).
Added {ssl_openssl}:tlsv11 for configuring whether TLSv1.1 is usable (defaults to yes).
Added {ssl_openssl}:tlsv12 for configuring whether TLSv1.2 is usable (defaults to yes).
Removed {ssl_openssl}:sslv3 (now always disabled).
Removed the m_ prefix from the names of the chanstats, dns, dnsbl, helpchan, httpd, ldap, ldap_oper, mysql, proxyscan, redis, regex_pcre2, regex_posix, regex_stdlib, regex_tre, rewrite, sasl, sql_log, sql_oper, sqlite, ssl_gnutls, ssl_openssl, xmlrpc, and xmlrpc_main modules.
Removed {ssl_openssl}:sslv3 (now always disabled).
Anope Version 2.1.1
-------------------
@@ -104,7 +135,7 @@ Removed the m_regex_pcre module (use m_regex_pcre2 instead).
Anope Version 2.1.0
-------------------
Added nickserv:minpasslen for configuring the minimum password length (defaults to 8).
Removed nickserv:strictpasswords as it is obsolete now nickserv:minpasslen exists.
Removed nickserv:strictpasswords (obsolete now nickserv:minpasslen exists).
Removed the inspircd12 and inspircd20 modules (use inspircd instead).
Removed the ns_getpass module (no supported encryption modules).
Removed the os_oline module (no supported IRCds).
@@ -113,4 +144,4 @@ Renamed nickserv:passlen to nickserv:maxpasslen.
Renamed the charybdis module to solanum.
Renamed the inspircd3 module to inspircd.
Renamed the unreal4 module to unrealircd.
Replaced uplink:ipv6 with uplink:protocol.
Replaced uplink:ipv6 with uplink:protocol (defaults to ipv4).
+1 -1
View File
@@ -27,7 +27,7 @@ Note: You should also read the README and FAQ files!
cmake --version
If it's installed, you will get a line that says something similar to
"cmake version 2.8.12.2". If the version is less than 2.4 or you get
"cmake version 3.28.3". If the version is less than 3.20.0 or you get
an error saying the command was not found, you will not be able to use
CMake unless you install it yourself into your home directory. CMake
can be downloaded from:
+1 -1
View File
@@ -27,7 +27,7 @@ Note : Vous devrez également lire les fichiers README et FAQ !
cmake --version
Si CMake est installé, vous aurez une ligne qui dit quelque chose comme
"cmake version 2.8.12.2". Si la version est inférieure à 2.4 ou si vous
"cmake version 3.28.3". Si la version est inférieure à 3.20.0 ou si vous
obtenez une erreur disant que la commande n'a pas été trouvée, vous ne
pourrez pas utiliser CMake à moins de l'installer vous-même dans votre
répertoire home. CMake peut être téléchargé ici :
+3 -4
View File
@@ -34,10 +34,9 @@ Anope Multi Language Support
Poedit (https://poedit.net/) is a popular po file editor, and we recommend using it or another editor designed to edit
po files (especially on Windows).
If you have finished a language file translation and you want others to use it, please send it to team@anope.org
(don't forget to mention clearly your (nick)name, your email and the language name). You'll of course get full credit for it.
NOTE: There is no guarantee we will use your work so please do not be offended if we say no thanks.
If you have finished a language file translation and you want others to use it, please file a pull request on GitHub
or send it to team@anope.org (don't forget to mention clearly your (nick)name, your email and the language name).
You'll of course get full credit for it.
3) Using languages with modules
-2
View File
@@ -13,8 +13,6 @@ command - Takes three parameters, a service name (BotServ, ChanServ, NickServ),
stats - Takes no parameters, returns miscellaneous stats that can be found in the /operserv stats command.
notice - Takes three parameters, source user, target user, and message. Sends a message to the user.
RPC was designed to be used with db_sql, and will not return any information that can be pulled from the SQL
database, such as accounts and registered channel information. It is instead used for pulling realtime data such
as users and channels currently online. For examples on how to use these calls in PHP, see xmlrpc.php in docs/RPC.
+88 -8
View File
@@ -44,18 +44,47 @@ class AnopeRPC {
return null;
}
/**
* Retrieves a list of accounts.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of account names.
*/
listAccounts(detail = "name") {
return this.run("anope.listAccounts", detail);
}
/**
* Retrieves information about the specified account.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} name The name of the account.
* @returns {object} An object containing information about the account.
*/
account(name) {
return this.run("anope.account", name);
}
/**
* Retrieves a list of channels.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of channel names.
*/
listChannels() {
return this.run("anope.listChannels");
listChannels(detail = "name") {
return this.run("anope.listChannels", detail);
}
/**
* Retrieves information about the specified channel.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} name The name of the channel.
* @returns {object} An object containing information about the channel.
*/
@@ -66,15 +95,20 @@ class AnopeRPC {
/**
* Retrieves a list of services operators.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of channel names.
*/
listOpers() {
return this.run("anope.listOpers");
listOpers(detail = "name") {
return this.run("anope.listOpers", detail);
}
/**
* Retrieves information about the specified services operator.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} name The name of the services operator.
* @returns {object} An object containing information about the services operator.
*/
@@ -85,15 +119,20 @@ class AnopeRPC {
/**
* Retrieves a list of servers.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of servers names.
*/
listServers() {
return this.run("anope.listServers");
listServers(detail = "name") {
return this.run("anope.listServers", detail);
}
/**
* Retrieves information about the specified server.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} name The name of the server.
* @returns {object} An object containing information about the server.
*/
@@ -104,21 +143,62 @@ class AnopeRPC {
/**
* Retrieves a list of users.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of channel names.
*/
listUsers() {
return this.run("anope.listUsers");
listUsers(detail = "name") {
return this.run("anope.listUsers", detail);
}
/**
* Retrieves information about the specified user.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} nick The nick of the user.
* @returns {object} An object containing information about the user.
*/
user(nick) {
return this.run("anope.user", nick);
}
/**
* Sends a message to every user on the network.
*
* Requires the rpc_message module to be loaded.
*
* @param {...*} messages One or more messages to send.
*/
messageNetwork(...messages) {
return this.run("anope.messageNetwork", ...messages);
}
/**
* Sends a message to every user on the specified server.
*
* Requires the rpc_message module to be loaded.
*
* @param {string} name The name of the server.
* @param {...*} messages One or more messages to send.
*/
messageServer(server, ...messages) {
return this.run("anope.messageServer", server, ...messages);
}
/**
* Sends a message to the specified user.
*
* Requires the rpc_message module to be loaded.
*
* @param {string} source The source pseudoclient to send the message from.
* @param {string} target The target user to send the message to.
* @param {...*} messages One or more messages to send.
*/
messageUser(source, target, ...messages) {
return this.run("anope.messageUser", source, target, ...messages);
}
}
/*
+1 -1
View File
@@ -132,7 +132,7 @@ class AnopeRPC
*/
public function notice($source, $target, $message)
{
return $this->run("notice", [$source, $target, $message]);
return $this->run("anope.messageUser", [$source, $target, $message]);
}
/**
+165 -17
View File
@@ -1,20 +1,151 @@
# Anope `rpc_data` RPC interface
## `anope.listAccounts`
Lists all accounts that exist on the network.
### Parameters
Index | Description
----- | -----------
0 | If specified then the level of detail to retrieve. Can be set to "full" to retrieve all information or "name" to just retrieve the account names. Defaults to "name".
### Errors
Code | Description
------ | -----------
-32099 | The specified detail level does not exist.
### Result
If the detail level is not specified or is "name" then an array of account names.
If the detail level is "full" then a mapping of account names to information about the account. See `anope.account` for more information on the data structure.
#### Example
```json
["account1", "account2", "account3"]
```
## `anope.account`
Retrieves information about the specified account.
### Parameters
Index | Description
----- | -----------
0 | A nickname belonging to the account.
### Errors
Code | Description
------ | -----------
-32099 | The specified account does not exist.
### Result
Returns a map containing information about the account.
Key | Type | Description
--- | ---- | -----------
display | string | The display nickname of the account.
email | string or null | The email address associated with the account or null if one has not been specified.
extensions | map | A key-value map of the extensions set on this account by modules.
language | string or null | The language associated with the account or null if the account uses the default language.
lastmail | int | The time at which an email was last sent for this account.
nicks | map | Information about nicknames that belong to the account keyed by the nickname.
nicks.\*.extensions | map | A key-value map of the extensions set on this nickname by modules.
nicks.\*.lastseen | int | The time at which this nickname was last used.
nicks.\*.registered | int | The time at which this nickname was registered.
nicks.\*.vhost | map or null | The vhost associated with the account or null if the user has no vhost.
nicks.\*.vhost.created | int | The time at which the vhost was created.
nicks.\*.vhost.creator | string | The nickname of the creator of the vhost.
nicks.\*.vhost.host | string | The host segment of the vhost.
nicks.\*.vhost.ident | string or null | The ident segment of the vhost or null if there is not one.
nicks.\*.vhost.mask | string | The user@host or host mask of the vhost.
opertype | map or null | The oper type associated with the account or null if they are not a services operator.
opertype.commands | array[string] | The commands that the services operator type can use.
opertype.name | string | The name of the services operator type.
opertype.privileges | array[string] | The privileges that the services operator type has.
registered | int | The time at which the account was registered.
uniqueid | uint | The unique immutable identifier of the account.
users | array[string] | The IRC users who are currently logged in to this account.
#### Example
```json
{
"display": "foo",
"email": "example@example.com",
"extensions": {
"AUTOOP": true,
"HIDE_EMAIL": true,
"HIDE_MASK": true,
"MEMO_RECEIVE": true,
"MEMO_SIGNON": true,
"NS_PRIVATE": true,
"PROTECT": true,
"PROTECT_AFTER": 69
},
"language": null,
"lastmail": 1745071858,
"nicks": {
"foo": {
"extensions": {
"NS_NO_EXPIRE": true
},
"lastseen": 1745074153,
"registered": 1745071857,
"vhost": null
},
"bar": {
"extensions": {},
"lastseen": 1745072602,
"registered": 1745071857,
"vhost": {
"created": 1745072653,
"creator": "foo",
"host": "bar.baz",
"ident": "foo",
"mask": "foo@bar.baz"
}
}
},
"opertype": {
"commands": ["hostserv/*", "operserv/session"],
"name": "Helper",
"privileges": ["chanserv/no-register-limit"]
},
"registered": 1745071857,
"uniqueid": 11085415958920757000,
"users": [
"foo"
]
}
```
## `anope.listChannels`
Lists all channels that exist on the network.
### Parameters
*None*
Index | Description
----- | -----------
0 | If specified then the level of detail to retrieve. Can be set to "full" to retrieve all information or "name" to just retrieve the channel names. Defaults to "name".
### Errors
*Only standard RPC errors*
Code | Description
------ | -----------
-32099 | The specified detail level does not exist.
### Result
Returns an array of channel names.
If the detail level is not specified or is "name" then an array of channel names.
If the detail level is "full" then a mapping of channel names to information about the channel. See `anope.channel` for more information on the data structure.
#### Example
@@ -44,13 +175,13 @@ Returns a map containing information about the channel.
Key | Type | Description
--- | ---- | -----------
created | uint | The UNIX time at which the channel was originally created.
created | int | The UNIX time at which the channel was originally created.
listmodes | map | List modes which are set on the channel keyed by the mode character.
modes | array[string] | Flag and parameter modes which are set on the channel.
name | string | The name of the channel.
registered | boolean | Whether the channel is registered.
topic | map or null | The channel topic or null if no topic is set.
topic.setat | uint | The time at which the topic was set.
topic.setat | int | The time at which the topic was set.
topic.setby | string | The nick or nuh of the user who set the topic.
topic.value | string | The text of the topic.
users | array[string] | The users that are current in the channel prefixed by their status mode prefixes.
@@ -81,15 +212,21 @@ Lists all services operators that exist on the network.
### Parameters
*None*
Index | Description
----- | -----------
0 | If specified then the level of detail to retrieve. Can be set to "full" to retrieve all information or "name" to just retrieve the services operator nicknames. Defaults to "name".
### Errors
*Only standard RPC errors*
Code | Description
------ | -----------
-32099 | The specified detail level does not exist.
### Result
Returns an array of services operator names.
If the detail level is not specified or is "name" then an array of services operator names.
If the detail level is "full" then a mapping of services operator names to information about the services operator. See `anope.oper` for more information on the data structure.
#### Example
@@ -123,7 +260,7 @@ fingerprints | array[string] or null | The client certificate fingerprint
hosts | array[string] or null | The user@ip and user@ip masks that a user must be connecting from to log in as this services operator or null if there are no host restrictions.
name | string | The name of the services operator.
operonly | boolean | Whether a user has to be a server operator to log in as this services operator.
opertype | map | The oper type associated with the services operator opertype.
opertype | map | The oper type associated with the services operator.
opertype.commands | array[string] | The commands that the services operator type can use.
opertype.name | string | The name of the services operator type.
opertype.privileges | array[string] | The privileges that the services operator type has.
@@ -154,15 +291,21 @@ Lists all servers that exist on the network.
### Parameters
*None*
Index | Description
----- | -----------
0 | If specified then the level of detail to retrieve. Can be set to "full" to retrieve all information or "name" to just retrieve the server names. Defaults to "name".
### Errors
*Only standard RPC errors*
Code | Description
------ | -----------
-32099 | The specified detail level does not exist.
### Result
Returns an array of server names.
If the detail level is not specified or is "name" then an array of server names.
If the detail level is "full" then a mapping of server names to information about the server. See `anope.server` for more information on the data structure.
#### Example
@@ -222,16 +365,21 @@ Lists all users that exist on the network.
### Parameters
*None*
Index | Description
----- | -----------
0 | If specified then the level of detail to retrieve. Can be set to "full" to retrieve all information or "name" to just retrieve the user nicknames. Defaults to "name".
### Errors
*Only standard RPC errors*
Code | Description
------ | -----------
-32099 | The specified detail level does not exist.
### Result
Returns an array of user nicknames.
If the detail level is not specified or is "name" then an array of user nicknames.
If the detail level is "full" then a mapping of user nicknames to information about the user. See `anope.user` for more information on the data structure.
#### Example
@@ -273,10 +421,10 @@ host | string | The real hostname of the user.
ident | string | The username (ident) of the user.
modes | array[string] | Flag and parameter modes which are set on the user.
nick | string | The nickname of the user.
nickchanged | uint | The time at which the user last changed their nickname.
nickchanged | int | The time at which the user last changed their nickname.
real | string | The real name of the user.
server | string | The server that the user is connected to.
signon | uint | The time at which the user connected to the network.
signon | int | The time at which the user connected to the network.
uid | string or null | The unique immutable identifier of the user or null if the IRCd does not use UIDs.
vhost | string or null | The virtual host of the user or null if they have no vhost.
vident | string or null | The virtual ident (username) of the user or null if they have no vident.
+67
View File
@@ -0,0 +1,67 @@
# Anope `rpc_message` RPC interface
## `anope.messageNetwork`
Sends a message to all users on the network.
### Parameters
Index | Description
----- | -----------
0+ | One or more messages to send.
### Errors
Code | Description
------ | -----------
-32099 | The global service is not available.
### Result
This procedure returns no result.
## `anope.messageServer`
Sends a message to all users on the specified server.
### Parameters
Index | Description
----- | -----------
0 | The name of the server to message users on.
1+ | One or more messages to send.
### Errors
Code | Description
------ | -----------
-32099 | The global service is not available.
-32098 | The specified server does not exist.
### Result
This procedure returns no result.
## `anope.messageUser`
Sends a message to the specified user.
### Parameters
Index | Description
----- | -----------
0 | The source pseudoclient to send the message from.
1 | The target user to send the message to.
2+ | One or more messages to send.
### Errors
Code | Description
------ | -----------
-32099 | The specified source does not exist.
-32098 | The specified target does not exist.
### Result
This procedure returns no result.
+10 -3
View File
@@ -74,6 +74,16 @@ public:
class CoreExport ChanAccess
: public Serializable
{
public:
struct Type final
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
private:
Anope::string mask;
/* account this access entry is for, if any */
Serialize::Reference<NickCore> nc;
@@ -97,9 +107,6 @@ public:
const Anope::string &Mask() const;
NickCore *GetAccount() const;
void Serialize(Serialize::Data &data) const override;
static Serializable *Unserialize(Serializable *obj, Serialize::Data &);
static const unsigned int MAX_DEPTH = 4;
/** Check if this access entry matches the given user or account
+24 -8
View File
@@ -32,6 +32,16 @@ class CoreExport NickAlias final
: public Serializable
, public Extensible
{
public:
struct Type final
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
private:
Anope::string vhost_ident, vhost_host, vhost_creator;
time_t vhost_created = 0;
@@ -43,7 +53,7 @@ public:
Anope::string last_usermask;
/* Last uncloaked usermask, requires nickserv/auspex to see */
Anope::string last_realhost;
time_t time_registered = Anope::CurTime;
time_t registered = Anope::CurTime;
time_t last_seen = Anope::CurTime;
/* Account this nick is tied to. Multiple nicks can be tied to a single account. */
@@ -56,9 +66,6 @@ public:
NickAlias(const Anope::string &nickname, NickCore *nickcore);
~NickAlias();
void Serialize(Serialize::Data &data) const override;
static Serializable *Unserialize(Serializable *obj, Serialize::Data &);
/** Set a vhost for the user
* @param ident The ident
* @param host The host
@@ -106,6 +113,7 @@ public:
* @return the nick, if found
*/
static NickAlias *Find(const Anope::string &nick);
static NickAlias *FindId(uint64_t id);
};
/* A registered account. Each account must have a NickAlias with the same nick as the
@@ -116,6 +124,16 @@ class CoreExport NickCore final
: public Serializable
, public Extensible
{
public:
struct Type final
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
private:
/* Channels which reference this core in some way (this is on their access list, akick list, is founder, successor, etc) */
Serialize::Checker<std::map<ChannelInfo *, int> > chanaccess;
/* Unique identifier for the account. */
@@ -131,7 +149,7 @@ public:
/* Last time an email was sent to this user */
time_t lastmail = 0;
/* The time this account was registered */
time_t time_registered = Anope::CurTime;
time_t registered = Anope::CurTime;
MemoInfo memos;
std::map<Anope::string, Anope::string> last_modes;
@@ -159,9 +177,6 @@ public:
NickCore(const Anope::string &nickdisplay, uint64_t nickid = 0);
~NickCore();
void Serialize(Serialize::Data &data) const override;
static Serializable *Unserialize(Serializable *obj, Serialize::Data &);
/** Changes the display for this account
* @param na The new display, must be grouped to this account.
*/
@@ -180,6 +195,7 @@ public:
* @return The account, if it exists
*/
static NickCore *Find(const Anope::string &nick);
static NickCore *FindId(uint64_t id);
void AddChannelReference(ChannelInfo *ci);
void RemoveChannelReference(ChannelInfo *ci);
+16 -1
View File
@@ -221,6 +221,14 @@ namespace Anope
inline bool is_number_only() const { return this->find_first_not_of("0123456789.-") == npos; }
inline bool is_pos_number_only() const { return this->find_first_not_of("0123456789.") == npos; }
/**
* In IRC messages we use a substitute (ASCII 0x1A) instead of a space
* (ASCII 0x20) so it doesn't get line wrapped when put into a message.
* The line wrapper will convert this to a space before it is sent to
* clients.
*/
inline Anope::string nobreak() const { return this->replace_all_cs("\x20", "\x1A"); }
/**
* Replace parts of the string.
*/
@@ -346,7 +354,7 @@ namespace Anope
template<typename T>
using unordered_map = std::unordered_map<string, T, hash_ci, compare>;
#ifndef REPRODUCIBLE_BUILD
#if !REPRODUCIBLE_BUILD
static const char *const compiled = __TIME__ " " __DATE__;
#endif
@@ -608,6 +616,13 @@ namespace Anope
* @return True if the message was a well formed CTCP; otherwise, false.
*/
extern CoreExport bool ParseCTCP(const Anope::string &text, Anope::string &name, Anope::string &body);
/** Replaces template variables within a string with values from a map.
* @param str The string to template from.
* @param vars The variables to replace within the string.
* @return The specified string with all variables replaced within it.
*/
extern CoreExport Anope::string Template(const Anope::string &str, const Anope::map<Anope::string> &vars);
}
/** sepstream allows for splitting token separated lists.
+11 -1
View File
@@ -23,6 +23,16 @@ class CoreExport BotInfo final
: public User
, public Serializable
{
public:
struct Type final
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
private:
/* Channels this bot is assigned to */
Serialize::Checker<std::set<ChannelInfo *> > channels;
public:
@@ -129,7 +139,7 @@ public:
CommandInfo *GetCommand(const Anope::string &cname);
/** Get the command that users can use to send a message to this bot. */
Anope::string GetQueryCommand() const;
Anope::string GetQueryCommand(const Anope::string &command = "", const Anope::string &extra = "") const;
/** Find a bot by nick
* @param nick The nick
+10 -10
View File
@@ -48,11 +48,11 @@ public:
/* Set if this channel is registered. ci->c == this. Contains information relevant to the registered channel */
Serialize::Reference<ChannelInfo> ci;
/* When the channel was created */
time_t creation_time;
time_t created;
/* If the channel has just been created in a netjoin */
bool syncing;
bool syncing = false;
/* Is configured in the conf as a channel bots should be in */
bool botchannel;
bool botchannel = false;
/* Users in the channel */
typedef std::map<User *, ChanUserContainer *> ChanUserList;
@@ -66,15 +66,15 @@ public:
* This is the time the topic was *originally set*. When we restore the topic we want to change the TS back
* to this, but we can only do this on certain IRCds.
*/
time_t topic_ts;
time_t topic_ts = 0;
/* The actual time the topic was set, probably close to Anope::CurTime */
time_t topic_time;
time_t topic_time = 0;
time_t server_modetime; /* Time of last server MODE */
time_t chanserv_modetime; /* Time of last check_modes() */
int16_t server_modecount; /* Number of server MODEs this second */
int16_t chanserv_modecount; /* Number of check_mode()'s this sec */
int16_t bouncy_modes; /* Did we fail to set modes here? */
time_t server_modetime = 0; /* Time of last server MODE */
time_t chanserv_modetime = 0; /* Time of last check_modes() */
int16_t server_modecount = 0; /* Number of server MODEs this second */
int16_t chanserv_modecount = 0; /* Number of check_mode()'s this sec */
bool bouncy_modes = false; /* Did we fail to set modes here? */
private:
/** Constructor
+5 -4
View File
@@ -14,6 +14,7 @@
#include "service.h"
#include "anope.h"
#include "channels.h"
#include "textproc.h"
struct CommandGroup final
{
@@ -96,7 +97,7 @@ class CoreExport Command
: public Service
{
Anope::string desc;
std::vector<Anope::string> syntax;
std::vector<std::pair<Anope::string, std::function<bool(CommandSource&)>>> syntax;
/* Allow unregistered users to use this command */
bool allow_unregistered;
/* Command requires that a user is executing it */
@@ -128,7 +129,7 @@ protected:
void SetDesc(const Anope::string &d);
void ClearSyntax();
void SetSyntax(const Anope::string &s);
void SetSyntax(const Anope::string &s, const std::function<bool(CommandSource&)> &p = nullptr);
void SendSyntax(CommandSource &);
void AllowUnregistered(bool b);
@@ -150,10 +151,10 @@ public:
*/
virtual void Execute(CommandSource &source, const std::vector<Anope::string> &params) = 0;
/** Called when HELP is requested for the client this command is on.
/** Called when help is requested for the client this command is on.
* @param source The source
*/
virtual void OnServHelp(CommandSource &source);
virtual void OnServHelp(CommandSource &source, HelpWrapper &help);
/** Requested when the user is requesting help on this command. Help on this command should be sent to the user.
* @param source The source
+13 -13
View File
@@ -18,11 +18,9 @@
namespace Configuration
{
namespace Internal
{
class CoreExport Block
{
friend struct Configuration::Conf;
friend class Configuration::Conf;
public:
typedef Anope::map<Anope::string> item_map;
@@ -41,7 +39,7 @@ namespace Configuration
Block(const Anope::string &);
const Anope::string &GetName() const;
int CountBlock(const Anope::string &name) const;
const Block *GetBlock(const Anope::string &name, int num = 0) const;
const Block &GetBlock(const Anope::string &name, int num = 0) const;
Block *GetMutableBlock(const Anope::string &name, int num = 0);
template<typename T> T Get(const Anope::string &tag, const Anope::string &def = "") const
@@ -56,10 +54,6 @@ namespace Configuration
template<> CoreExport const Anope::string Block::Get(const Anope::string &tag, const Anope::string &def) const;
template<> CoreExport time_t Block::Get(const Anope::string &tag, const Anope::string &def) const;
template<> CoreExport bool Block::Get(const Anope::string &tag, const Anope::string &def) const;
} // namespace Internal
typedef const Internal::Block Block;
typedef Internal::Block MutableBlock;
/** Represents a configuration file
*/
@@ -83,9 +77,14 @@ namespace Configuration
struct Uplink;
struct CoreExport Conf final
: Block
class CoreExport Conf final
: public Block
{
private:
/** Replaces defined variables within a string. */
Anope::string ReplaceVars(const Anope::string &str, const File &file, int linenumber);
public:
/* options:readtimeout */
time_t ReadTimeout;
/* If we should default to privmsging clients */
@@ -126,12 +125,12 @@ namespace Configuration
void LoadConf(File &file);
void Post(Conf *old);
Block *GetModule(const Module *);
Block *GetModule(const Anope::string &name);
Block &GetModule(const Module *);
Block &GetModule(const Anope::string &name);
BotInfo *GetClient(const Anope::string &name);
const Block *GetCommand(CommandSource &);
const Block &GetCommand(CommandSource &);
};
struct Uplink final
@@ -144,6 +143,7 @@ namespace Configuration
Uplink(const Anope::string &_host, int _port, const Anope::string &_password, int _protocol) : host(_host), port(_port), password(_password), protocol(_protocol) { }
inline bool operator==(const Uplink &other) const { return host == other.host && port == other.port && password == other.password && protocol == other.protocol; }
inline bool operator!=(const Uplink &other) const { return !(*this == other); }
Anope::string str() const;
};
}
+1 -1
View File
@@ -23,7 +23,7 @@ struct ChanUserContainer;
class ClientSocket;
class Command;
class CommandSource;
namespace Configuration { struct Conf; }
namespace Configuration { class Conf; }
class ConnectionSocket;
namespace DNS { struct Query; }
class Entry;
+11 -11
View File
@@ -100,18 +100,18 @@ namespace Language
} // namespace Language
/* Commonly used language strings */
#define CONFIRM_DROP _("Please confirm that you want to drop \002%s\002 with \002%s DROP %s %s\002")
#define CONFIRM_DROP _("Please confirm that you want to drop \002%s\002 with \002%s\032%s\032%s\002")
#define SERVICE_UNAVAILABLE _("Sorry, %s is temporarily unavailable.")
#define MORE_INFO _("\002%s HELP %s\002 for more information.")
#define MORE_INFO _("\002%s\002 for more information.")
#define BAD_USERHOST_MASK _("Mask must be in the form \037user\037@\037host\037.")
#define BAD_EXPIRY_TIME _("Invalid expiry time.")
#define USERHOST_MASK_TOO_WIDE _("%s coverage is too wide; Please use a more specific mask.")
#define READ_ONLY_MODE _("Services are temporarily in read-only mode.")
#define PASSWORD_INCORRECT _("Password incorrect.")
#define ACCESS_DENIED _("Access denied.")
#define MORE_OBSCURE_PASSWORD _("Please try again with a more obscure password. Passwords should not be\n" \
"something that could be easily guessed (e.g. your real name or your nick) and\n" \
"cannot contain the space or tab characters.\n")
#define MORE_OBSCURE_PASSWORD _("Please try again with a more obscure password. Passwords should not be " \
"something that could be easily guessed (e.g. your real name or your nick) and " \
"cannot contain the space or tab characters.")
#define PASSWORD_TOO_SHORT _("Your password is too short. It must be longer than %u characters.")
#define PASSWORD_TOO_LONG _("Your password is too long. It must be shorter than %u characters.")
#define NICK_NOT_REGISTERED _("Your nick isn't registered.")
@@ -127,8 +127,8 @@ namespace Language
#define UNKNOWN _("<unknown>")
#define NO_EXPIRE _("does not expire")
#define LIST_INCORRECT_RANGE _("Incorrect range specified. The correct syntax is \002#\037from\037-\037to\037\002.")
#define NICK_IS_SECURE _("This nickname is registered and protected. If it is your\n" \
"nick, type \002%s IDENTIFY \037password\037\002. Otherwise,\n" \
#define NICK_IS_SECURE _("This nickname is registered and protected. If it is your " \
"nick, type \002%s\032\037password\037\002. Otherwise, " \
"please choose a different nick.")
#define FORCENICKCHANGE_NOW _("This nickname has been registered; you may not use it.")
#define NICK_CANNOT_BE_REGISTERED _("Nickname \002%s\002 may not be registered.")
@@ -145,10 +145,10 @@ namespace Language
#define CHAN_ACCESS_LEVEL_RANGE _("Access level must be between %d and %d inclusive.")
#define CHAN_INFO_HEADER _("Information about channel \002%s\002:")
#define CHAN_EXCEPTED _("\002%s\002 matches an except on %s and cannot be banned until the except has been removed.")
#define MEMO_NEW_X_MEMO_ARRIVED _("There is a new memo on channel %s.\n" \
"Type \002%s READ %s %zu\002 to read it.")
#define MEMO_NEW_MEMO_ARRIVED _("You have a new memo from %s.\n" \
"Type \002%s READ %zu\002 to read it.")
#define MEMO_NEW_X_MEMO_ARRIVED _("There is a new memo on channel %s. " \
"Type \002%s\032%s\032%zu\002 to read it.")
#define MEMO_NEW_MEMO_ARRIVED _("You have a new memo from %s. " \
"Type \002%s\032%zu\002 to read it.")
#define MEMO_HAVE_NO_MEMOS _("You have no memos.")
#define MEMO_X_HAS_NO_MEMOS _("%s has no memos.")
#define MEMO_HAVE_NO_NEW_MEMOS _("You have no new memos.")
+9 -4
View File
@@ -18,15 +18,20 @@ class CoreExport Memo final
: public Serializable
{
public:
struct Type final
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
MemoInfo *mi;
bool unread;
bool receipt;
Memo();
~Memo();
void Serialize(Serialize::Data &data) const override;
static Serializable *Unserialize(Serializable *obj, Serialize::Data &);
Anope::string owner;
/* When it was sent */
time_t time;
@@ -41,7 +46,7 @@ struct CoreExport MemoInfo final
{
int16_t memomax = 0;
Serialize::Checker<std::vector<Memo *> > memos;
std::vector<Anope::string> ignores;
std::set<Anope::string, ci::less> ignores;
MemoInfo();
Memo *GetMemo(unsigned index) const;
+7
View File
@@ -45,6 +45,13 @@ namespace Message
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override;
};
struct CoreExport Ignore final
: IRCDMessage
{
Ignore(Module *creator, const Anope::string &mname);
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override;
};
struct CoreExport Invite
: IRCDMessage
{
+4 -4
View File
@@ -45,7 +45,7 @@
#include "users.h"
#include "xline.h"
#include "modules/pseudoclients/chanserv.h"
#include "modules/pseudoclients/global.h"
#include "modules/pseudoclients/memoserv.h"
#include "modules/pseudoclients/nickserv.h"
#include "modules/chanserv/service.h"
#include "modules/global/service.h"
#include "modules/memoserv/service.h"
#include "modules/nickserv/service.h"
+133 -22
View File
@@ -305,7 +305,7 @@ public:
* @param conf The config that is being built now and will replace the global Config object
* @throws A ConfigException to abort the config (re)loading process.
*/
virtual void OnReload(Configuration::Conf *conf) ATTR_NOT_NULL(2) { throw NotImplementedException(); }
virtual void OnReload(Configuration::Conf &conf) { throw NotImplementedException(); }
/** Called before a bot is assigned to a channel.
* @param sender The user assigning the bot
@@ -1068,28 +1068,139 @@ public:
enum Implementation
{
I_IsServicesOper,
I_OnAccessAdd,
I_OnAccessClear,
I_OnAccessDel,
I_OnAddXLine,
I_OnAkickAdd,
I_OnAkickDel,
I_OnBadWordAdd,
I_OnBadWordDel,
I_OnBotAssign,
I_OnBotBan,
I_OnBotChange,
I_OnBotCreate,
I_OnBotDelete,
I_OnBotFantasy,
I_OnBotInfo,
I_OnBotKick,
I_OnBotNoFantasyAccess,
I_OnBotNotice,
I_OnBotPrivmsg,
I_OnBotUnAssign,
I_OnCanSet,
I_OnChanDrop,
I_OnChanExpire,
I_OnChangeCoreDisplay,
I_OnChanInfo,
I_OnChannelCreate,
I_OnChannelDelete,
I_OnChannelModeAdd,
I_OnChannelModeSet,
I_OnChannelModeUnset,
I_OnChannelSync,
I_OnChanRegistered,
I_OnChanSuspend,
I_OnChanUnsuspend,
I_OnCheckAuthentication,
I_OnCheckDelete,
I_OnCheckKick,
I_OnCheckModes,
I_OnCheckPriv,
I_OnCreateBot,
I_OnCreateChan,
I_OnDecrypt,
I_OnDefconLevel,
I_OnDelBot,
I_OnDelChan,
I_OnDelCore,
I_OnDeleteVHost,
I_OnDelNick,
I_OnDelXLine,
I_OnDnsRequest,
I_OnEncrypt,
I_OnExceptionAdd,
I_OnExceptionDel,
I_OnExpireTick,
I_OnFingerprint,
I_OnGroupCheckPriv,
I_OnInvite,
I_OnJoinChannel,
I_OnLeaveChannel,
I_OnLevelChange,
I_OnLoadDatabase,
I_OnLog,
I_OnLogMessage,
I_OnMemoDel,
I_OnMemoSend,
I_OnMessage,
I_OnMLock,
I_OnModuleLoad,
I_OnModuleUnload,
I_OnNewServer,
I_OnNickAddCert,
I_OnNickClearCert,
I_OnNickConfirm,
I_OnNickCoreCreate,
I_OnNickDrop,
I_OnNickEraseCert,
I_OnNickExpire,
I_OnNickGroup,
I_OnNickIdentify,
I_OnNickInfo,
I_OnNickLogout,
I_OnNickRegister,
I_OnNickSuspend,
I_OnNickUnsuspended,
I_OnNickUpdate,
I_OnNickValidate,
I_OnPartChannel,
I_OnPostCommand,
I_OnPostHelp,
I_OnPostInit,
I_OnPreUserKicked, I_OnUserKicked, I_OnReload, I_OnPreBotAssign, I_OnBotAssign, I_OnBotUnAssign, I_OnUserConnect,
I_OnNewServer, I_OnUserNickChange, I_OnPreHelp, I_OnPostHelp, I_OnPreCommand, I_OnPostCommand, I_OnSaveDatabase,
I_OnLoadDatabase, I_OnEncrypt, I_OnDecrypt, I_OnBotFantasy, I_OnBotNoFantasyAccess, I_OnBotBan, I_OnBadWordAdd,
I_OnBadWordDel, I_OnCreateBot, I_OnDelBot, I_OnBotKick, I_OnPrePartChannel, I_OnPartChannel, I_OnLeaveChannel,
I_OnJoinChannel, I_OnTopicUpdated, I_OnPreChanExpire, I_OnChanExpire, I_OnPreServerConnect, I_OnServerConnect,
I_OnPreUplinkSync, I_OnServerDisconnect, I_OnRestart, I_OnShutdown, I_OnPreNickExpire, I_OnNickExpire, I_OnDefconLevel,
I_OnExceptionAdd, I_OnExceptionDel, I_OnAddXLine, I_OnDelXLine, I_IsServicesOper, I_OnServerQuit, I_OnUserQuit,
I_OnPreUserLogoff, I_OnPostUserLogoff, I_OnBotCreate, I_OnBotChange, I_OnBotDelete, I_OnAccessDel, I_OnAccessAdd,
I_OnAccessClear, I_OnLevelChange, I_OnChanDrop, I_OnChanRegistered, I_OnChanSuspend, I_OnChanUnsuspend,
I_OnCreateChan, I_OnDelChan, I_OnChannelCreate, I_OnChannelDelete, I_OnAkickAdd, I_OnAkickDel, I_OnCheckKick,
I_OnChanInfo, I_OnCheckPriv, I_OnGroupCheckPriv, I_OnNickDrop, I_OnNickGroup, I_OnNickIdentify,
I_OnUserLogin, I_OnNickLogout, I_OnNickRegister, I_OnNickConfirm, I_OnNickSuspend, I_OnNickUnsuspended, I_OnDelNick, I_OnNickCoreCreate,
I_OnDelCore, I_OnChangeCoreDisplay, I_OnNickClearCert,
I_OnNickAddCert, I_OnNickEraseCert, I_OnNickInfo, I_OnBotInfo, I_OnCheckAuthentication, I_OnNickUpdate,
I_OnFingerprint, I_OnUserAway, I_OnInvite, I_OnDeleteVHost, I_OnSetVHost, I_OnSetDisplayedHost, I_OnMemoSend, I_OnMemoDel,
I_OnChannelModeSet, I_OnChannelModeUnset, I_OnUserModeSet, I_OnUserModeUnset, I_OnChannelModeAdd, I_OnUserModeAdd,
I_OnMLock, I_OnUnMLock, I_OnModuleLoad, I_OnModuleUnload, I_OnServerSync, I_OnUplinkSync, I_OnBotPrivmsg, I_OnBotNotice,
I_OnPrivmsg, I_OnLog, I_OnLogMessage, I_OnDnsRequest, I_OnCheckModes, I_OnChannelSync, I_OnSetCorrectModes,
I_OnSerializeCheck, I_OnSerializableConstruct, I_OnSerializableDestruct, I_OnSerializableUpdate,
I_OnSerializeTypeCreate, I_OnSetChannelOption, I_OnSetNickOption, I_OnMessage, I_OnCanSet, I_OnCheckDelete,
I_OnExpireTick, I_OnNickValidate,
I_OnPostUserLogoff,
I_OnPreBotAssign,
I_OnPreChanExpire,
I_OnPreCommand,
I_OnPreHelp,
I_OnPreNickExpire,
I_OnPrePartChannel,
I_OnPreServerConnect,
I_OnPreUplinkSync,
I_OnPreUserKicked,
I_OnPreUserLogoff,
I_OnPrivmsg,
I_OnReload,
I_OnRestart,
I_OnSaveDatabase,
I_OnSerializableConstruct,
I_OnSerializableDestruct,
I_OnSerializableUpdate,
I_OnSerializeCheck,
I_OnSerializeTypeCreate,
I_OnServerConnect,
I_OnServerDisconnect,
I_OnServerQuit,
I_OnServerSync,
I_OnSetChannelOption,
I_OnSetCorrectModes,
I_OnSetDisplayedHost,
I_OnSetNickOption,
I_OnSetVHost,
I_OnShutdown,
I_OnTopicUpdated,
I_OnUnMLock,
I_OnUplinkSync,
I_OnUserAway,
I_OnUserConnect,
I_OnUserKicked,
I_OnUserLogin,
I_OnUserModeAdd,
I_OnUserModeSet,
I_OnUserModeUnset,
I_OnUserNickChange,
I_OnUserQuit,
I_SIZE
};
+195
View File
@@ -0,0 +1,195 @@
/*
*
* (C) 2014-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*/
#pragma once
namespace SASL
{
class Mechanism;
struct Message;
class ProtocolInterface;
struct Service;
struct Session;
/** The SASL interface implemented by the protocol modules. */
static ServiceReference<SASL::ProtocolInterface> protocol_interface("SASL::ProtocolInterface", "sasl");
/** The SASL interface implemented by ns_sasl. */
static ServiceReference<SASL::Service> service("SASL::Service", "sasl");
}
/** Represents a single SASL message. */
struct SASL::Message final
{
/** The source UID or name. */
Anope::string source;
/** The target UID or name. */
Anope::string target;
/** The type of message. */
Anope::string type;
/** One or more data parameters. */
std::vector<Anope::string> data;
};
/** Sends IRCd messages used by the SASL module. */
class SASL::ProtocolInterface
: public ::Service
{
protected:
ProtocolInterface(Module *o)
: ::Service(o, "SASL::ProtocolInterface", "sasl")
{
}
public:
/** Sends the list of SASL mechanisms to the IRCd
* @param mechs The list of SASL mechanisms.
*/
virtual void SendSASLMechanisms(std::vector<Anope::string> &mechs) { };
/** Sends a SASL message to the IRCd.
* @param message The SASL message to send.
*/
virtual void SendSASLMessage(const SASL::Message &message) = 0;
/** Sends a login or logout for \p uid to \p na.
* @param uid The uid of the user to log in.
* @param na The nick alias to log the user in as or logout if nullptr.
*/
virtual void SendSVSLogin(const Anope::string &uid, NickAlias *na) = 0;
};
/** SASL service interface. */
struct SASL::Service
: ::Service
{
Service(Module *o)
: ::Service(o, "SASL::Service", "sasl")
{
}
virtual void DeleteSessions(Mechanism *mech, bool da = false) = 0;
/** Fails a SASL session. This notifies the client and increments the
* failed attempt counter which may kill the client if the bad password
* limit has been reached.
*
* @param sess The session to fail.
*/
virtual void Fail(Session *sess) = 0;
/** Retrieves the session for the specified user identifier. */
virtual Session *GetSession(const Anope::string &uid) = 0;
/** Processes a SASL authentication message from the uplink.
* @param m The message to process.
*/
virtual void ProcessMessage(const Message &m) = 0;
/** Removes the specified SASL session from the service.
* @param sess The session to remove.
*/
virtual void RemoveSession(Session *sess) = 0;
/** Sends a SASL message for the specified session.
* @param type The type of message to send.
* @param data The contents of the SASL message.
*/
virtual void SendMessage(SASL::Session *sess, const Anope::string &type, const Anope::string &data) = 0;
/** Completes a successful authentication.
* @param sess The session which finished authentication.
* @param nc The account which has been logged into.
*/
virtual void Succeed(Session *sess, NickCore *nc) = 0;
};
/** Represents a single SASL session. */
struct SASL::Session
{
/** The time at which the session was created. */
const time_t created;
/** The hostname and IP address of the authenticating user. */
Anope::string hostname, ip;
/** A reference to the mechanism that the session is authenticating using. */
Reference<Mechanism> mech;
/** The unique identifier of the authenticating user. */
const Anope::string uid;
/** Creates a new authentication session.
* @param m The mechanism that the session is authenticating with.
* @param u The unique identifier of the authenticating user.
*/
Session(Mechanism *m, const Anope::string &u)
: created(Anope::CurTime)
, mech(m)
, uid(u)
{
}
virtual ~Session()
{
if (service)
service->RemoveSession(this);
}
/** Retrieves a description of the user this session is associated with. */
inline Anope::string GetUserInfo()
{
auto *u = User::Find(uid);
if (u)
return u->GetMask();
if (!hostname.empty() && !ip.empty())
return Anope::printf("%s (%s)", hostname.c_str(), ip.c_str());
return "A user";
};
};
/* Represents an authentication mechanism. */
class SASL::Mechanism
: public ::Service
{
protected:
/** Creates a new authentication mechanism.
* @param o The module that owns this instance.
* @param sname The name of the authentication mechanism (e.g. PLAIN).
*/
Mechanism(Module *o, const Anope::string &sname)
: Service(o, "SASL::Mechanism", sname)
{
}
public:
virtual ~Mechanism()
{
if (service)
service->DeleteSessions(this, true);
}
/** Creates a new SASL session.
* @param uid The unique identifier of the authenticating user.
*/
virtual Session *CreateSession(const Anope::string &uid)
{
return new Session(this, uid);
}
/** Processes an authentication message from the authenticating user.
* @param session The session for which the message applies.
* @param m The message sent by the user.
* @return True if the message was processed successfully or false if
* the session should be aborted.
*/
virtual bool ProcessMessage(Session *sess, const Message &m) = 0;
};
+16
View File
@@ -0,0 +1,16 @@
/*
*
* (C) 2011-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*/
#pragma once
struct MyOper final
: Oper
, Serializable
{
MyOper(const Anope::string &n, OperType *o) : Oper(n, o), Serializable("Oper") { }
};
@@ -28,8 +28,6 @@ struct Exception final
time_t expires; /* Time when it expires. 0 == no expiry */
Exception() : Serializable("Exception") { }
void Serialize(Serialize::Data &data) const override;
static Serializable *Unserialize(Serializable *obj, Serialize::Data &data);
};
class SessionService
@@ -59,35 +57,3 @@ public:
};
static ServiceReference<SessionService> session_service("SessionService", "session");
void Exception::Serialize(Serialize::Data &data) const
{
data.Store("mask", this->mask);
data.Store("limit", this->limit);
data.Store("who", this->who);
data.Store("reason", this->reason);
data.Store("time", this->time);
data.Store("expires", this->expires);
}
Serializable *Exception::Unserialize(Serializable *obj, Serialize::Data &data)
{
if (!session_service)
return NULL;
Exception *ex;
if (obj)
ex = anope_dynamic_static_cast<Exception *>(obj);
else
ex = new Exception;
data["mask"] >> ex->mask;
data["limit"] >> ex->limit;
data["who"] >> ex->who;
data["reason"] >> ex->reason;
data["time"] >> ex->time;
data["expires"] >> ex->expires;
if (!obj)
session_service->AddException(ex);
return ex;
}
-46
View File
@@ -1,46 +0,0 @@
/*
*
* (C) 2011-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*/
#pragma once
struct MyOper final
: Oper
, Serializable
{
MyOper(const Anope::string &n, OperType *o) : Oper(n, o), Serializable("Oper") { }
void Serialize(Serialize::Data &data) const override
{
data.Store("name", this->name);
data.Store("type", this->ot->GetName());
}
static Serializable *Unserialize(Serializable *obj, Serialize::Data &data)
{
Anope::string stype, sname;
data["type"] >> stype;
data["name"] >> sname;
OperType *ot = OperType::Find(stype);
if (ot == NULL)
return NULL;
NickCore *nc = NickCore::Find(sname);
if (nc == NULL)
return NULL;
MyOper *myo;
if (obj)
myo = anope_dynamic_static_cast<MyOper *>(obj);
else
myo = new MyOper(nc->display, ot);
nc->o = myo;
Log(LOG_NORMAL, "operserv/oper") << "Tied oper " << nc->display << " to type " << ot->GetName();
return myo;
}
};
+7 -16
View File
@@ -21,9 +21,6 @@ namespace RPC
class ServiceInterface;
class Value;
/** Represents a list of registered events. */
using Events = Anope::map<Event *>;
/** Represents possible types of RPC value. */
using ValueUnion = std::variant<Array, Map, Anope::string, std::nullptr_t, bool, double, int64_t, uint64_t>;
@@ -169,15 +166,17 @@ public:
inline const auto &GetRoot() const { return this->root; }
};
#define RPC_EVENT "RPC::Event"
class RPC::Event
: public Service
{
private:
Anope::string event;
size_t minparams;
protected:
Event(const Anope::string& e, size_t mp = 0)
: event(e)
Event(Module *o, const Anope::string& e, size_t mp = 0)
: Service(o, RPC_EVENT, e)
, minparams(mp)
{
}
@@ -185,8 +184,6 @@ protected:
public:
virtual ~Event() = default;
const auto &GetEvent() const { return event; }
const auto &GetMinParams() const { return minparams; }
virtual bool Run(ServiceInterface *iface, HTTPClient *client, Request &request) = 0;
@@ -196,17 +193,11 @@ class RPC::ServiceInterface
: public Service
{
public:
ServiceInterface(Module *creator, const Anope::string &sname)
: Service(creator, "RPCServiceInterface", sname)
ServiceInterface(Module *creator)
: Service(creator, "RPC::ServiceInterface", "rpc")
{
}
virtual const Events &GetEvents() = 0;
virtual bool Register(Event *event) = 0;
virtual bool Unregister(Event *event) = 0;
virtual void Reply(Request &request) = 0;
};
-161
View File
@@ -1,161 +0,0 @@
/*
*
* (C) 2014-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*/
#pragma once
namespace SASL
{
struct Message final
{
Anope::string source;
Anope::string target;
Anope::string type;
std::vector<Anope::string> data;
};
class Mechanism;
struct Session;
class Service
: public ::Service
{
public:
Service(Module *o) : ::Service(o, "SASL::Service", "sasl") { }
virtual void ProcessMessage(const Message &) = 0;
virtual Anope::string GetAgent() = 0;
virtual Session *GetSession(const Anope::string &uid) = 0;
virtual void SendMessage(SASL::Session *session, const Anope::string &type, const Anope::string &data) = 0;
virtual void Succeed(Session *, NickCore *) = 0;
virtual void Fail(Session *) = 0;
virtual void SendMechs(Session *) = 0;
virtual void DeleteSessions(Mechanism *, bool = false) = 0;
virtual void RemoveSession(Session *) = 0;
};
static ServiceReference<SASL::Service> sasl("SASL::Service", "sasl");
struct Session
{
time_t created;
Anope::string uid;
Anope::string hostname, ip;
Reference<Mechanism> mech;
Session(Mechanism *m, const Anope::string &u) : created(Anope::CurTime), uid(u), mech(m) { }
inline Anope::string GetUserInfo()
{
auto *u = User::Find(uid);
if (u)
return u->GetMask();
if (!hostname.empty() && !ip.empty())
return Anope::printf("%s (%s)", hostname.c_str(), ip.c_str());
return "A user";
};
virtual ~Session()
{
if (sasl)
sasl->RemoveSession(this);
}
};
/* PLAIN, EXTERNAL, etc */
class Mechanism
: public ::Service
{
public:
Mechanism(Module *o, const Anope::string &sname) : Service(o, "SASL::Mechanism", sname) { }
virtual Session *CreateSession(const Anope::string &uid) { return new Session(this, uid); }
virtual bool ProcessMessage(Session *session, const Message &) = 0;
virtual ~Mechanism()
{
if (sasl)
sasl->DeleteSessions(this, true);
}
};
class IdentifyRequest
: public ::IdentifyRequest
{
Anope::string uid;
Anope::string hostname;
inline Anope::string GetUserInfo()
{
auto *u = User::Find(uid);
if (u)
return u->GetMask();
if (!hostname.empty() && !GetAddress().empty())
return Anope::printf("%s (%s)", hostname.c_str(), GetAddress().c_str());
return "A user";
};
public:
IdentifyRequest(Module *m, const Anope::string &id, const Anope::string &acc, const Anope::string &pass, const Anope::string &h, const Anope::string &i)
: ::IdentifyRequest(m, acc, pass, i)
, uid(id)
, hostname(h)
{
}
void OnSuccess() override
{
if (!sasl)
return;
NickAlias *na = NickAlias::Find(GetAccount());
if (!na || na->nc->HasExt("NS_SUSPENDED") || na->nc->HasExt("UNCONFIRMED"))
return OnFail();
unsigned int maxlogins = Config->GetModule("ns_identify")->Get<unsigned int>("maxlogins");
if (maxlogins && na->nc->users.size() >= maxlogins)
return OnFail();
Session *s = sasl->GetSession(uid);
if (s)
{
Log(this->GetOwner(), "sasl", Config->GetClient("NickServ")) << GetUserInfo() << " identified to account " << this->GetAccount() << " using SASL";
sasl->Succeed(s, na->nc);
delete s;
}
}
void OnFail() override
{
if (!sasl)
return;
Session *s = sasl->GetSession(uid);
if (s)
{
sasl->Fail(s);
delete s;
}
Anope::string accountstatus;
NickAlias *na = NickAlias::Find(GetAccount());
if (!na)
accountstatus = "nonexistent ";
else if (na->nc->HasExt("NS_SUSPENDED"))
accountstatus = "suspended ";
else if (na->nc->HasExt("UNCONFIRMED"))
accountstatus = "unconfirmed ";
Log(this->GetOwner(), "sasl", Config->GetClient("NickServ")) << GetUserInfo() << " failed to identify for " << accountstatus << "account " << this->GetAccount() << " using SASL";
}
};
}
-14
View File
@@ -19,7 +19,6 @@ namespace SQL
public:
typedef std::map<Anope::string, std::stringstream *> Map;
Map data;
std::map<Anope::string, Serialize::DataType> types;
~Data()
{
@@ -59,19 +58,6 @@ namespace SQL
delete value;
this->data.clear();
}
void SetType(const Anope::string &key, Serialize::DataType dt) override
{
this->types[key] = dt;
}
Serialize::DataType GetType(const Anope::string &key) const override
{
auto it = this->types.find(key);
if (it != this->types.end())
return it->second;
return Serialize::DataType::TEXT;
}
};
/** A SQL exception, can be thrown at various points
+1
View File
@@ -23,6 +23,7 @@ struct CoreExport Oper
/* Whether the user must be an IRC operator (umode +o) to be considered a services operator */
bool require_oper = true;
Anope::string password;
Anope::string password_hash;
std::vector<Anope::string> certfp;
/* Hosts allowed to use this operator block */
std::vector<Anope::string> hosts;
+5 -9
View File
@@ -107,8 +107,8 @@ public:
/* If this IRCd has unique ids, whether the IDs and nicknames are ambiguous */
bool AmbiguousID = false;
/** Can we ask the server to unban a user? */
bool CanClearBans = false;
/** Can we ask the server to remove list modes matching a user? */
std::set<Anope::string> CanClearModes;
/** Can we send tag messages? */
bool CanTagMessage = false;
@@ -222,7 +222,7 @@ public:
virtual void SendContextNotice(BotInfo *bi, User *target, Channel *context, const Anope::string &msg);
virtual void SendContextPrivmsg(BotInfo *bi, User *target, Channel *context, const Anope::string &msg);
virtual void SendQuit(User *u, const Anope::string &msg);
virtual void SendQuit(User *u, const Anope::string &msg = "", const Anope::string &opermsg = "");
virtual void SendPing(const Anope::string &servname, const Anope::string &who);
virtual void SendPong(const Anope::string &servname, const Anope::string &who);
@@ -304,11 +304,7 @@ public:
*/
virtual void SendOper(User *u);
virtual void SendClearBans(const MessageSource &user, Channel *c, User* u) { }
virtual void SendSASLMechanisms(std::vector<Anope::string> &) { }
virtual void SendSASLMessage(const SASL::Message &) { }
virtual void SendSVSLogin(const Anope::string &uid, NickAlias *na) { }
virtual void SendClearModes(const MessageSource &user, Channel *c, User* u, const Anope::string &mode) { }
virtual bool IsNickValid(const Anope::string &);
virtual bool IsChannelValid(const Anope::string &);
@@ -366,7 +362,7 @@ public:
FLAG_MAX,
};
private:
protected:
/** The name of the message (e.g. PRIVMSG). */
const Anope::string name;
+22 -10
View File
@@ -25,6 +25,14 @@ class CoreExport AutoKick final
: public Serializable
{
public:
struct Type final
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
/* Channel this autokick is on */
Serialize::Reference<ChannelInfo> ci;
@@ -38,8 +46,6 @@ public:
AutoKick();
~AutoKick();
void Serialize(Serialize::Data &data) const override;
static Serializable *Unserialize(Serializable *obj, Serialize::Data &);
};
/* It matters that Base is here before Extensible (it is inherited by Serializable)
@@ -48,9 +54,18 @@ class CoreExport ChannelInfo final
: public Serializable
, public Extensible
{
public:
struct Type final
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
private:
/* channels who reference this one */
Anope::map<int> references;
private:
Serialize::Reference<NickCore> founder; /* Channel founder */
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 */
@@ -64,16 +79,16 @@ public:
Anope::string name; /* Channel name */
Anope::string desc;
time_t time_registered;
time_t registered;
time_t last_used;
Anope::string last_topic; /* The last topic that was set on this channel */
Anope::string last_topic_setter; /* Setter */
time_t last_topic_time; /* Time */
time_t last_topic_time = 0; /* Time */
Channel::ModeList last_modes; /* The last modes set on this channel */
int16_t bantype;
int16_t bantype = 2;
MemoInfo memos;
@@ -82,7 +97,7 @@ public:
/* For BotServ */
Serialize::Reference<BotInfo> bi; /* Bot used on this channel */
time_t banexpire; /* Time bans expire in */
time_t banexpire = 0; /* Time bans expire in */
/** Constructor
* @param chname The channel name
@@ -97,9 +112,6 @@ public:
~ChannelInfo();
ChannelInfo &operator=(const ChannelInfo &) = default;
void Serialize(Serialize::Data &data) const override;
static Serializable *Unserialize(Serializable *obj, Serialize::Data &);
/** Change the founder of the channel
* @params nc The new founder
*/
+93 -57
View File
@@ -16,6 +16,16 @@
#include "anope.h"
#include "base.h"
/** Names of serialization types implemented in the core. */
#define AUTOKICK_TYPE "AutoKick"
#define BOTINFO_TYPE "BotInfo"
#define CHANACCESS_TYPE "ChanAccess"
#define CHANNELINFO_TYPE "ChannelInfo"
#define MEMO_TYPE "Memo"
#define NICKALIAS_TYPE "NickAlias"
#define NICKCORE_TYPE "NickCore"
#define XLINE_TYPE "XLine"
namespace Serialize
{
enum class DataType
@@ -28,8 +38,11 @@ namespace Serialize
UINT,
};
class Data
class CoreExport Data
{
protected:
std::map<Anope::string, Serialize::DataType> types;
public:
virtual ~Data() = default;
@@ -54,8 +67,8 @@ namespace Serialize
virtual size_t Hash() const { throw CoreException("Not supported"); }
virtual void SetType(const Anope::string &key, DataType dt) { }
virtual DataType GetType(const Anope::string &key) const { return DataType::TEXT; }
Serialize::DataType GetType(const Anope::string &key) const;
void SetType(const Anope::string &key, Serialize::DataType dt);
};
extern void RegisterTypes();
@@ -97,10 +110,11 @@ protected:
Serializable &operator=(const Serializable &);
public:
using Id = uint64_t;
virtual ~Serializable();
/* Unique ID (per type, not globally) for this object */
uint64_t id = 0;
Id id = 0;
/* Only used by redis, to ignore updates */
unsigned short redis_ignore = 0;
@@ -120,82 +134,104 @@ public:
*/
Serialize::Type *GetSerializableType() const { return this->s_type; }
virtual void Serialize(Serialize::Data &data) const = 0;
static const std::list<Serializable *> &GetItems();
};
/* A serializable type. There should be one of these classes for each type
* of class that inherits from Serializable. Used for unserializing objects
* of this type, as it requires a function pointer to a static member function.
/* A serializable type. There should be a single instance of a subclass of this
* for each subclass of Serializable as this is what is used to serialize and
* deserialize data from the database.
*/
class CoreExport Serialize::Type final
class CoreExport Serialize::Type
: public Base
{
typedef Serializable *(*unserialize_func)(Serializable *obj, Serialize::Data &);
static std::vector<Anope::string> TypeOrder;
static std::map<Anope::string, Serialize::Type *> Types;
/* The name of this type, should be a class name */
private:
/** The name of this type in the database (e.g. NickAlias). */
Anope::string name;
unserialize_func unserialize;
/* Owner of this type. Used for placing objects of this type in separate databases
* based on what module, if any, owns it.
/** The module which owns this type, or nullptr if it belongs to the core.
* Some database backends use this to put third-party module data into their
* own database.
*/
Module *owner;
/* The timestamp for this type. All objects of this type are as up to date as
* this timestamp. if curtime == timestamp then we have the most up to date
* version of every object of this type.
/** The time at which this type was last synchronised with the database.
* Only used by live database backends like db_sql_live.
*/
time_t timestamp = 0;
public:
/* Map of Serializable::id to Serializable objects */
std::map<uint64_t, Serializable *> objects;
/* The names of currently registered types in order of registration. */
static std::vector<Anope::string> TypeOrder;
/** Creates a new serializable type
* @param n Type name
* @param f Func to unserialize objects
* @param owner Owner of this type. Leave NULL for the core.
/** The currently registered types. */
static std::map<Anope::string, Serialize::Type *> Types;
protected:
/** Creates a new serializable type.
* @param n The name of the type . This should match the value passed in the
* constructor of the equivalent Serializable type.
* @param o The module which owns this type, or nullptr if it belongs to the
* core.
*/
Type(const Anope::string &n, unserialize_func f, Module *owner = NULL);
Type(const Anope::string &n, Module *o = nullptr);
public:
/* Map of Serializable objects of this type keyed by their object id. */
std::map<Serializable::Id, Serializable *> objects;
/** Destroys a serializable type. */
~Type();
/** Gets the name for this type
* @return The name, eg "NickAlias"
*/
const Anope::string &GetName() { return this->name; }
/** Unserialized an object.
* @param obj NULL if this object doesn't yet exist. If this isn't NULL, instead
* update the contents of this object.
* @param data The data to unserialize
* @return The unserialized object. If obj != NULL this should be obj.
*/
Serializable *Unserialize(Serializable *obj, Serialize::Data &data);
/** Check if this object type has any pending changes and update them.
*/
/** Checks for and applies any pending object updates for this type. */
void Check();
/** Gets the timestamp for the object type. That is, the time we know
* all objects of this type are updated at least to.
/** Attempts to find a serializable type with the specified name.
* @param n The name of the serializable type to find.
*/
time_t GetTimestamp() const;
static Serialize::Type *Find(const Anope::string &n);
/** Bumps object type timestamp to current time
/** Retrieves the name of this type in the database (e.g. NickAlias). */
inline const auto &GetName() const { return this->name; }
/** Retrieves the module which owns this type, or nullptr if it belongs to
* the core. Some database backends use this to put third-party module data
* into their own database.
*/
inline auto *GetOwner() const { return this->owner; }
/** Retrieves the time at which this type was last synchronised with the
* database. Only used by live database backends like db_sql_live.
*/
inline auto GetTimestamp() const { return this->timestamp; };
/** Retrieves the names of currently registered types in order of
* registration.
*/
inline static const auto &GetTypeOrder() { return TypeOrder; }
/** Retrieves the currently registered types. */
inline static const auto &GetTypes() { return Types; }
/** Serializes the specified object to the database.
* @param obj The object to serialise. This is guaranteed to be the correct
* type so you can cast it without any checks.
* @param data The database to serialize to.
*/
virtual void Serialize(const Serializable *obj, Serialize::Data &data) const = 0;
/** Unserializes the specified object from the database.
* @param obj The object to unserialize into. If the object has not been
* unserialized yet this will be nullptr. This is guaranteed to
* be the correct type so you can cast it without any checks.
* @param data The database to unserialize from.
* @return The object specified in obj or a new object it if was nullptr.
*/
virtual Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const = 0;
/** Updates the time at which this type was last synchronised with the
* database to the current time. Only used by live database backends like
* db_sql_live.
*/
void UpdateTimestamp();
Module *GetOwner() const { return this->owner; }
static Serialize::Type *Find(const Anope::string &name);
static const std::vector<Anope::string> &GetTypeOrder();
static const std::map<Anope::string, Serialize::Type *>& GetTypes();
};
/** Should be used to hold lists and other objects of a specific type,
+1
View File
@@ -23,6 +23,7 @@
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iostream>
#include <list>
#include <map>
+3
View File
@@ -44,6 +44,9 @@
// Whether the umask() function is available.
#cmakedefine01 HAVE_UMASK
// Whether Anope was built in a reproducible way.
#cmakedefine01 REPRODUCIBLE_BUILD
#ifdef _WIN32
# define popen _popen
# define pclose _pclose
+36
View File
@@ -0,0 +1,36 @@
/*
*
* (C) 2003-2025 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.
*/
#pragma once
class CoreExport HelpWrapper final
{
private:
std::vector<std::pair<Anope::string, Anope::string>> entries;
size_t longest = 0;
public:
void AddEntry(const Anope::string &name, const Anope::string &desc);
void SendTo(CommandSource &source);
};
class CoreExport LineWrapper final
{
private:
std::vector<Anope::string> formatting;
const size_t max_length;
Anope::string text;
public:
LineWrapper(const Anope::string &t, size_t ml = 0);
bool GetLine(Anope::string &out);
};
+1 -1
View File
@@ -50,7 +50,7 @@ protected:
Serialize::Reference<NickCore> nc;
/* # of invalid password attempts */
unsigned short invalid_pw_count;
unsigned invalid_pw_count;
/* Time of last invalid password */
time_t invalid_pw_time;
+10 -3
View File
@@ -16,6 +16,16 @@
class CoreExport XLine final
: public Serializable
{
public:
struct Type final
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
private:
void Init();
Anope::string nick, user, host, real;
public:
@@ -43,9 +53,6 @@ public:
bool HasNickOrReal() const;
bool IsRegex() const;
void Serialize(Serialize::Data &data) const override;
static Serializable *Unserialize(Serializable *obj, Serialize::Data &data);
};
/* Managers XLines. There is one XLineManager per type of XLine. */
+815 -1805
View File
File diff suppressed because it is too large Load Diff
+58 -40
View File
@@ -23,9 +23,9 @@ public:
{
}
void OnReload(Configuration::Conf *conf) override
void OnReload(Configuration::Conf &conf) override
{
const Anope::string &bsnick = conf->GetModule(this)->Get<const Anope::string>("client");
const Anope::string &bsnick = conf.GetModule(this).Get<const Anope::string>("client");
BotServ = BotInfo::Find(bsnick, true);
}
@@ -34,7 +34,7 @@ public:
/* Do not allow removing bot modes on our service bots */
if (chan->ci && chan->ci->bi == user)
{
const Anope::string &botmodes = Config->GetModule(this)->Get<const Anope::string>("botmodes");
const Anope::string &botmodes = Config->GetModule(this).Get<const Anope::string>("botmodes");
for (auto botmode : botmodes)
chan->SetMode(chan->ci->bi, ModeManager::FindChannelModeByChar(botmode), chan->ci->bi->GetUID());
}
@@ -42,9 +42,9 @@ public:
void OnBotAssign(User *sender, ChannelInfo *ci, BotInfo *bi) override
{
if (ci->c && ci->c->users.size() >= Config->GetModule(this)->Get<unsigned>("minusers"))
if (ci->c && ci->c->users.size() >= Config->GetModule(this).Get<unsigned>("minusers"))
{
ChannelStatus status(Config->GetModule(this)->Get<const Anope::string>("botmodes"));
ChannelStatus status(Config->GetModule(this).Get<const Anope::string>("botmodes"));
bi->Join(ci->c, &status);
}
}
@@ -55,12 +55,12 @@ public:
return;
BotInfo *bi = user->server == Me ? dynamic_cast<BotInfo *>(user) : NULL;
if (bi && Config->GetModule(this)->Get<bool>("smartjoin"))
if (bi && Config->GetModule(this).Get<bool>("smartjoin"))
{
if (IRCD->CanClearBans)
if (IRCD->CanClearModes.count("BAN"))
{
// We can ask the IRCd to clear bans.
IRCD->SendClearBans(bi, c, bi);
IRCD->SendClearModes(bi, c, bi, "BAN");
}
else
{
@@ -99,9 +99,9 @@ public:
* legit users - Rob
**/
/* This is before the user has joined the channel, so check usercount + 1 */
if (c->users.size() + 1 >= Config->GetModule(this)->Get<unsigned>("minusers") && !c->FindUser(c->ci->bi))
if (c->users.size() + 1 >= Config->GetModule(this).Get<unsigned>("minusers") && !c->FindUser(c->ci->bi))
{
ChannelStatus status(Config->GetModule(this)->Get<const Anope::string>("botmodes"));
ChannelStatus status(Config->GetModule(this).Get<const Anope::string>("botmodes"));
c->ci->bi->Join(c, &status);
}
}
@@ -124,7 +124,7 @@ public:
return;
/* This is called prior to removing the user from the channel, so c->users.size() - 1 should be safe */
if (c->ci && c->ci->bi && u != *c->ci->bi && c->users.size() - 1 <= Config->GetModule(this)->Get<unsigned>("minusers") && c->FindUser(c->ci->bi))
if (c->ci && c->ci->bi && u != *c->ci->bi && c->users.size() - 1 <= Config->GetModule(this).Get<unsigned>("minusers") && c->FindUser(c->ci->bi))
c->ci->bi->Part(c->ci->c);
}
@@ -135,29 +135,41 @@ public:
if (source.c)
{
source.Reply(_("\002%s\002 allows you to execute \"fantasy\" commands in the channel.\n"
"Fantasy commands are commands that can be executed from messaging a\n"
"channel, and provide a more convenient way to execute commands. Commands that\n"
"require a channel as a parameter will automatically have that parameter\n"
"given.\n"), source.service->nick.c_str());
const Anope::string &fantasycharacters = Config->GetModule("fantasy")->Get<const Anope::string>("fantasycharacter", "!");
source.Reply(_(
"\002%s\002 allows you to execute \"fantasy\" commands in the channel. "
"Fantasy commands are commands that can be executed from messaging a "
"channel, and provide a more convenient way to execute commands. Commands that "
"require a channel as a parameter will automatically have that parameter "
"given."
),
source.service->nick.c_str());
const Anope::string &fantasycharacters = Config->GetModule("fantasy").Get<const Anope::string>("fantasycharacter", "!");
if (!fantasycharacters.empty())
source.Reply(_(" \n"
"Fantasy commands may be prefixed with one of the following characters: %s\n"), fantasycharacters.c_str());
source.Reply(_(" \n"
"Available commands are:"));
{
source.Reply(" ");
source.Reply(_("Fantasy commands may be prefixed with one of the following characters: %s"),
fantasycharacters.c_str());
}
source.Reply(" ");
source.Reply(_("Available commands are:"));
}
else if (*source.service == BotServ)
{
source.Reply(_("\002%s\002 allows you to have a bot on your own channel.\n"
"It has been created for users that can't host or\n"
"configure a bot, or for use on networks that don't\n"
"allow user bots. Available commands are listed\n"
"below; to use them, type \002%s \037command\037\002. For\n"
"more information on a specific command, type\n"
"\002%s %s \037command\037\002.\n"),
BotServ->nick.c_str(), BotServ->GetQueryCommand().c_str(),
BotServ->GetQueryCommand().c_str(), source.command.c_str());
source.Reply(_(
"\002%s\002 allows you to have a bot on your own channel. "
"It has been created for users that can't host or "
"configure a bot, or for use on networks that don't "
"allow user bots. Available commands are listed "
"below; to use them, type \002%s\032\037command\037\002. For "
"more information on a specific command, type "
"\002%s\032\037command\037\002."
),
BotServ->nick.c_str(),
BotServ->GetQueryCommand().c_str(),
BotServ->GetQueryCommand({}, source.command).c_str());
source.Reply(" ");
}
return EVENT_CONTINUE;
@@ -168,19 +180,25 @@ public:
if (!params.empty() || source.c || source.service != *BotServ)
return;
source.Reply(_(" \n"
"Bot will join a channel whenever there is at least\n"
"\002%d\002 user(s) on it."), Config->GetModule(this)->Get<unsigned>("minusers"));
const Anope::string &fantasycharacters = Config->GetModule("fantasy")->Get<const Anope::string>("fantasycharacter", "!");
source.Reply(" ");
source.Reply(_("Bot will join a channel whenever there is at least \002%d\002 user(s) on it."),
Config->GetModule(this).Get<unsigned>("minusers"));
const Anope::string &fantasycharacters = Config->GetModule("fantasy").Get<const Anope::string>("fantasycharacter", "!");
if (!fantasycharacters.empty())
source.Reply(_("Additionally, if fantasy is enabled fantasy commands\n"
"can be executed by prefixing the command name with\n"
"one of the following characters: %s"), fantasycharacters.c_str());
{
source.Reply(_(
"Additionally, if fantasy is enabled fantasy commands "
"can be executed by prefixing the command name with "
"one of the following characters: %s"
),
fantasycharacters.c_str());
}
}
EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const Anope::string &param) override
{
if (source.GetUser() && !source.GetBot() && Config->GetModule(this)->Get<bool>("smartjoin") && mode->name == "BAN" && c->ci && c->ci->bi && c->FindUser(c->ci->bi))
if (source.GetUser() && !source.GetBot() && Config->GetModule(this).Get<bool>("smartjoin") && mode->name == "BAN" && c->ci && c->ci->bi && c->FindUser(c->ci->bi))
{
BotInfo *bi = c->ci->bi;
@@ -195,7 +213,7 @@ public:
void OnCreateChan(ChannelInfo *ci) override
{
/* Set default bot flags */
spacesepstream sep(Config->GetModule(this)->Get<const Anope::string>("defaults", "greet fantasy"));
spacesepstream sep(Config->GetModule(this).Get<const Anope::string>("defaults", "greet fantasy"));
for (Anope::string token; sep.GetToken(token);)
ci->Extend<bool>("BS_" + token.upper());
}
@@ -211,7 +229,7 @@ public:
void OnCreateBot(BotInfo *bi) override
{
if (bi->botmodes.empty())
bi->botmodes = Config->GetModule(this)->Get<const Anope::string>("botumodes");
bi->botmodes = Config->GetModule(this).Get<const Anope::string>("botumodes");
}
};
+18 -12
View File
@@ -76,9 +76,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Assigns the specified bot to a channel. You\n"
"can then configure the bot for the channel so it fits\n"
"your needs."));
source.Reply(_(
"Assigns the specified bot to a channel. You "
"can then configure the bot for the channel so it fits "
"your needs."
));
return true;
}
};
@@ -138,11 +140,13 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Unassigns a bot from a channel. When you use this command,\n"
"the bot won't join the channel anymore. However, bot\n"
"configuration for the channel is kept, so you will always\n"
"be able to reassign a bot later without having to reconfigure\n"
"it entirely."));
source.Reply(_(
"Unassigns a bot from a channel. When you use this command, "
"the bot won't join the channel anymore. However, bot "
"configuration for the channel is kept, so you will always "
"be able to reassign a bot later without having to reconfigure "
"it entirely."
));
return true;
}
};
@@ -197,10 +201,12 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(_(" \n"
"This option makes a channel unassignable. If a bot\n"
"is already assigned to the channel, it is unassigned\n"
"automatically when you enable it."));
source.Reply(" ");
source.Reply(_(
"This option makes a channel unassignable. If a bot "
"is already assigned to the channel, it is unassigned "
"automatically when you enable it."
));
return true;
}
};
+1 -1
View File
@@ -19,7 +19,7 @@ public:
void OnChanRegistered(ChannelInfo *ci) override
{
const Anope::string &bot = Config->GetModule(this)->Get<const Anope::string>("bot");
const Anope::string &bot = Config->GetModule(this).Get<const Anope::string>("bot");
if (bot.empty())
return;
+71 -45
View File
@@ -10,7 +10,7 @@
*/
#include "module.h"
#include "modules/bs_badwords.h"
#include "modules/botserv/badwords.h"
struct BadWordImpl final
: BadWord
@@ -18,15 +18,25 @@ struct BadWordImpl final
{
BadWordImpl() : Serializable("BadWord") { }
~BadWordImpl() override;
};
void Serialize(Serialize::Data &data) const override
struct BadWordTypeImpl final
: Serialize::Type
{
BadWordTypeImpl()
: Serialize::Type("BadWord")
{
data.Store("ci", this->chan);
data.Store("word", this->word);
data.Store("type", this->type);
}
static Serializable *Unserialize(Serializable *obj, Serialize::Data &);
void Serialize(const Serializable *obj, Serialize::Data &data) const override
{
const auto *bw = static_cast<const BadWordImpl *>(obj);
data.Store("ci", bw->chan);
data.Store("word", bw->word);
data.Store("type", bw->type);
}
Serializable *Unserialize(Serializable *obj, Serialize::Data &) const override;
};
struct BadWordsImpl final
@@ -117,7 +127,7 @@ BadWordImpl::~BadWordImpl()
}
}
Serializable *BadWordImpl::Unserialize(Serializable *obj, Serialize::Data &data)
Serializable *BadWordTypeImpl::Unserialize(Serializable *obj, Serialize::Data &data) const
{
Anope::string sci, sword;
@@ -155,6 +165,7 @@ class BadwordsDelCallback final
BadWords *bw;
Command *c;
unsigned deleted = 0;
Anope::string lastdeleted;
bool override = false;
public:
BadwordsDelCallback(CommandSource &_source, ChannelInfo *_ci, Command *_c, const Anope::string &list) : NumberList(list, true), source(_source), ci(_ci), c(_c)
@@ -166,12 +177,20 @@ public:
~BadwordsDelCallback() override
{
if (!deleted)
source.Reply(_("No matching entries on %s bad words list."), ci->name.c_str());
else if (deleted == 1)
source.Reply(_("Deleted 1 entry from %s bad words list."), ci->name.c_str());
else
source.Reply(_("Deleted %d entries from %s bad words list."), deleted, ci->name.c_str());
switch (deleted)
{
case 0:
source.Reply(_("No matching entries on %s bad words list."), ci->name.c_str());
break;
case 1:
source.Reply(_("Deleted %s from %s bad words list."), lastdeleted.c_str(), ci->name.c_str());
break;
default:
source.Reply(deleted, N_("Deleted %d entry from %s bad words list.", "Deleted %d entries from %s bad words list."), deleted, ci->name.c_str());
break;
}
}
void HandleNumber(unsigned Number) override
@@ -179,7 +198,8 @@ public:
if (!bw || !Number || Number > bw->GetBadWordCount())
return;
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "DEL " << bw->GetBadWord(Number - 1)->word;
lastdeleted = bw->GetBadWord(Number - 1)->word;
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "DEL " << lastdeleted;
++deleted;
bw->EraseBadWord(Number - 1);
}
@@ -286,14 +306,14 @@ private:
realword = word.substr(0, pos);
}
unsigned badwordsmax = Config->GetModule(this->module)->Get<unsigned>("badwordsmax");
unsigned badwordsmax = Config->GetModule(this->module).Get<unsigned>("badwordsmax");
if (badwords->GetBadWordCount() >= badwordsmax)
{
source.Reply(_("Sorry, you can only have %d bad words entries on a channel."), badwordsmax);
return;
}
bool casesensitive = Config->GetModule(this->module)->Get<bool>("casesensitive");
bool casesensitive = Config->GetModule(this->module).Get<bool>("casesensitive");
for (unsigned i = 0, end = badwords->GetBadWordCount(); i < end; ++i)
{
@@ -427,34 +447,38 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Maintains the \002bad words list\002 for a channel. The bad\n"
"words list determines which words are to be kicked\n"
"when the bad words kicker is enabled. For more information,\n"
"type \002%s HELP KICK %s\002.\n"
" \n"
"The \002ADD\002 command adds the given word to the\n"
"bad words list. If SINGLE is specified, a kick will be\n"
"done only if a user says the entire word. If START is\n"
"specified, a kick will be done if a user says a word\n"
"that starts with \037word\037. If END is specified, a kick\n"
"will be done if a user says a word that ends with\n"
"\037word\037. If you don't specify anything, a kick will\n"
"be issued every time \037word\037 is said by a user.\n"
" \n"), source.service->GetQueryCommand().c_str(), source.command.c_str());
source.Reply(_("The \002DEL\002 command removes the given word from the\n"
"bad words list. If a list of entry numbers is given, those\n"
"entries are deleted. (See the example for LIST below.)\n"
" \n"
"The \002LIST\002 command displays the bad words list. If\n"
"a wildcard mask is given, only those entries matching the\n"
"mask are displayed. If a list of entry numbers is given,\n"
source.Reply(_(
"Maintains the \002bad words list\002 for a channel. The bad "
"words list determines which words are to be kicked "
"when the bad words kicker is enabled. For more information, "
"type \002%s\032KICK\032%s\002."
"\n\n"
"The \002ADD\002 command adds the given word to the "
"bad words list. If SINGLE is specified, a kick will be "
"done only if a user says the entire word. If START is "
"specified, a kick will be done if a user says a word "
"that starts with \037word\037. If END is specified, a kick "
"will be done if a user says a word that ends with "
"\037word\037. If you don't specify anything, a kick will "
"be issued every time \037word\037 is said by a user."
"\n\n"
"The \002DEL\002 command removes the given word from the "
"bad words list. If a list of entry numbers is given, those "
"entries are deleted. (See the example for LIST below.)"
"\n\n"
"The \002LIST\002 command displays the bad words list. If "
"a wildcard mask is given, only those entries matching the "
"mask are displayed. If a list of entry numbers is given, "
"only those entries are shown; for example:\n"
" \002#channel LIST 2-5,7-9\002\n"
" \002#channel\032LIST\0322-5,7-9\002\n"
" Lists bad words entries numbered 2 through 5 and\n"
" 7 through 9.\n"
" \n"
"The \002CLEAR\002 command clears all entries from the\n"
"bad words list."));
" 7 through 9."
"\n\n"
"The \002CLEAR\002 command clears all entries from the "
"bad words list."
),
source.service->GetQueryCommand("generic/help").c_str(),
source.command.nobreak().c_str());
return true;
}
};
@@ -464,11 +488,13 @@ class BSBadwords final
{
CommandBSBadwords commandbsbadwords;
ExtensibleItem<BadWordsImpl> badwords;
Serialize::Type badword_type;
BadWordTypeImpl badword_type;
public:
BSBadwords(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
commandbsbadwords(this), badwords(this, "badwords"), badword_type("BadWord", BadWordImpl::Unserialize)
BSBadwords(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandbsbadwords(this)
, badwords(this, "badwords")
{
}
};
+26 -21
View File
@@ -142,7 +142,10 @@ private:
* And we must finally check that the nick is not already
* taken by another bot.
*/
if (nick.equals_cs(bi->nick) && (!user.empty() ? user.equals_cs(bi->GetIdent()) : 1) && (!host.empty() ? host.equals_cs(bi->host) : 1) && (!real.empty() ? real.equals_cs(bi->realname) : 1))
if (nick.equals_cs(bi->nick)
&& (user.empty() || user.equals_cs(bi->GetIdent()))
&& (host.empty() || host.equals_cs(bi->host))
&& (real.empty() || real.equals_cs(bi->realname)))
{
source.Reply(_("The old information is the same as the new information specified."));
return;
@@ -179,10 +182,7 @@ private:
source.Reply(_("Nick \002%s\002 is currently in use."), nick.c_str());
return;
}
}
if (!nick.equals_ci(bi->nick))
{
/* We check whether the nick is registered, and inform the user
* if so. You need to drop the nick manually before you can use
* it as a bot nick from now on -GD
@@ -347,23 +347,28 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Allows Services Operators to create, modify, and delete\n"
"bots that users will be able to use on their own\n"
"channels.\n"
" \n"
"\002BOT ADD\002 adds a bot with the given nickname, username,\n"
"hostname and realname. Since no integrity checks are done\n"
"for these settings, be really careful.\n"
" \n"
"\002BOT CHANGE\002 allows you to change the nickname, username, hostname\n"
"or realname of a bot without deleting it (and\n"
"all the data associated with it).\n"
" \n"
"\002BOT DEL\002 removes the given bot from the bot list.\n"
" \n"
"\002Note\002: You cannot create a bot with a nick that is\n"
"currently registered. If an unregistered user is currently\n"
"using the nick, they will be killed."));
source.Reply(_(
"Allows Services Operators to create, modify, and delete "
"bots that users will be able to use on their own "
"channels."
"\n\n"
"\002%s\032ADD\002 adds a bot with the given nickname, username, "
"hostname and realname. Since no integrity checks are done "
"for these settings, be really careful."
"\n\n"
"\002%s\032CHANGE\002 allows you to change the nickname, username, hostname "
"or realname of a bot without deleting it (and "
"all the data associated with it)."
"\n\n"
"\002%s\032DEL\002 removes the given bot from the bot list."
"\n\n"
"\002Note\002: You cannot create a bot with a nick that is "
"currently registered. If an unregistered user is currently "
"using the nick, they will be killed."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
+17 -11
View File
@@ -70,8 +70,12 @@ public:
list.Process(replies);
if (!count)
source.Reply(_("There are no bots available at this time.\n"
"Ask a Services Operator to create one!"));
{
source.Reply(_(
"There are no bots available at this time. "
"Ask a Services Operator to create one!"
));
}
else
{
source.Reply(_("Bot list:"));
@@ -87,15 +91,17 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Lists all available bots on this network.\n"
"\n"
"If the OPERONLY, UNUSED or VANITY options are given only\n"
"bots which, respectively, are oper-only, unused or were\n"
"added at runtime will be displayed. If multiple options are\n"
"given, all nicks matching at least one option will be\n"
"displayed.\n"
"\n"
"Note that these options are limited to \037Services Operators\037."));
source.Reply(_(
"Lists all available bots on this network."
"\n\n"
"If the OPERONLY, UNUSED or VANITY options are given only "
"bots which, respectively, are oper-only, unused or were "
"added at runtime will be displayed. If multiple options are "
"given, all nicks matching at least one option will be "
"displayed."
"\n\n"
"Note that these options are limited to \037Services Operators\037."
));
return true;
}
};
+4 -2
View File
@@ -122,8 +122,10 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Makes the bot do the equivalent of a \"/me\" command\n"
"on the specified channel using the specified text."));
source.Reply(_(
"Makes the bot do the equivalent of a \"/me\" command "
"on the specified channel using the specified text."
));
return true;
}
};
+7 -5
View File
@@ -104,11 +104,13 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Allows you to see %s information about a channel or a bot.\n"
"If the parameter is a channel, then you'll get information\n"
"such as enabled kickers. If the parameter is a nick,\n"
"you'll get information about a bot, such as creation\n"
"time or number of channels it is on."), source.service->nick.c_str());
source.Reply(_(
"Allows you to see %s information about a channel or a bot. "
"If the parameter is a channel, then you'll get information "
"such as enabled kickers. If the parameter is a nick, "
"you'll get information about a bot, such as creation "
"time or number of channels it is on."
), source.service->nick.c_str());
return true;
}
+188 -117
View File
@@ -10,8 +10,8 @@
*/
#include "module.h"
#include "modules/bs_kick.h"
#include "modules/bs_badwords.h"
#include "modules/botserv/kick.h"
#include "modules/botserv/badwords.h"
static Module *me;
@@ -45,7 +45,7 @@ struct KickerDataImpl final
void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const override
{
if (s->GetSerializableType()->GetName() != "ChannelInfo")
if (s->GetSerializableType()->GetName() != CHANNELINFO_TYPE)
return;
const ChannelInfo *ci = anope_dynamic_static_cast<const ChannelInfo *>(e);
@@ -79,7 +79,7 @@ struct KickerDataImpl final
void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) override
{
if (s->GetSerializableType()->GetName() != "ChannelInfo")
if (s->GetSerializableType()->GetName() != CHANNELINFO_TYPE)
return;
ChannelInfo *ci = anope_dynamic_static_cast<ChannelInfo *>(e);
@@ -139,6 +139,7 @@ public:
source.Reply(" ");
source.Reply(_("Configures bot kickers. \037option\037 can be one of:"));
HelpWrapper help;
Anope::string this_name = source.command;
for (const auto &[c_name, info] : source.service->commands)
{
@@ -148,17 +149,20 @@ public:
if (command)
{
source.command = c_name;
command->OnServHelp(source);
command->OnServHelp(source, help);
}
}
}
help.SendTo(source);
source.Reply(_("Type \002%s HELP %s \037option\037\002 for more information\n"
"on a specific option.\n"
" \n"
"Note: access to this command is controlled by the\n"
"level SET."), source.service->GetQueryCommand().c_str(), this_name.c_str());
source.Reply(_(
"Type \002%s\032\037option\037\002 for more information "
"on a specific option."
"\n\n"
"Note: access to this command is controlled by the "
"level SET."
),
source.service->GetQueryCommand("generic/help", this_name).c_str());
return true;
}
};
@@ -220,8 +224,10 @@ protected:
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(), kd->ttb[ttb_idx]);
{
source.Reply(_("Bot will now kick for \002%s\002, and will place a ban 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());
@@ -267,13 +273,16 @@ public:
this->SendSyntax(source);
source.Reply(" ");
BotInfo *bi = Config->GetClient("BotServ");
source.Reply(_("Sets the AMSG kicker on or off. When enabled, the bot will\n"
"kick users who send the same message to multiple channels\n"
"where %s bots are.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before they get banned. Don't give ttb to disable\n"
"the ban system once activated."), bi ? bi->nick.c_str() : "BotServ");
source.Reply(_(
"Sets the AMSG kicker on or off. When enabled, the bot will "
"kick users who send the same message to multiple channels "
"where %s bots are."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before they get banned. Don't give ttb to disable "
"the ban system once activated."
),
bi ? bi->nick.c_str() : "BotServ");
return true;
}
};
@@ -304,16 +313,20 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the bad words kicker on or off. When enabled, this\n"
"option tells the bot to kick users who say certain words\n"
"on the channels.\n"
"You can define bad words for your channel using the\n"
"\002BADWORDS\002 command. Type \002%s HELP BADWORDS\002 for\n"
"more information.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."), source.service->GetQueryCommand().c_str());
source.Reply(_(
"Sets the bad words kicker on or off. When enabled, this "
"option tells the bot to kick users who say certain words "
"on the channels."
"\n\n"
"You can define bad words for your channel using the "
"\002BADWORDS\002 command. Type \002%s\032BADWORDS\002 for "
"more information."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
),
source.service->GetQueryCommand("generic/help").c_str());
return true;
}
};
@@ -343,12 +356,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the bolds kicker on or off. When enabled, this\n"
"option tells the bot to kick users who use bolds.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the bolds kicker on or off. When enabled, this "
"option tells the bot to kick users who use bolds."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -400,12 +415,23 @@ public:
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."), kd->capsmin, kd->capspercent, kd->ttb[TTB_CAPS]);
{
source.Reply(_(
"Bot will now kick for \002caps\002 (they must constitute at least "
"%d characters and %d%% of the entire message), and will "
"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)."), kd->capsmin, kd->capspercent);
source.Reply(_(
"Bot will now kick for \002caps\002 (they must constitute at least "
"%d characters and %d%% of the entire message)."
),
kd->capsmin,
kd->capspercent);
}
else
{
@@ -420,17 +446,20 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the caps kicker on or off. When enabled, this\n"
"option tells the bot to kick users who are talking in\n"
"CAPS.\n"
"The bot kicks only if there are at least \002min\002 caps\n"
"and they constitute at least \002percent\002%% of the total\n"
"text line (if not given, it defaults to 10 characters\n"
"and 25%%).\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the caps kicker on or off. When enabled, this "
"option tells the bot to kick users who are talking in "
"CAPS."
"\n\n"
"The bot kicks only if there are at least \002min\002 caps "
"and they constitute at least \002percent\002%% of the total "
"text line (if not given, it defaults to 10 characters "
"and 25%%)."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -460,12 +489,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the colors kicker on or off. When enabled, this\n"
"option tells the bot to kick users who use colors.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the colors kicker on or off. When enabled, this "
"option tells the bot to kick users who use colors."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -515,13 +546,20 @@ public:
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");
if (kd->floodsecs > Config->GetModule(me).Get<time_t>("keepdata"))
kd->floodsecs = Config->GetModule(me).Get<time_t>("keepdata");
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."), kd->floodlines, kd->floodsecs, kd->ttb[TTB_FLOOD]);
{
source.Reply(_(
"Bot will now kick for \002flood\002 (%d lines in %d seconds "
"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)."), kd->floodlines, kd->floodsecs);
}
@@ -540,14 +578,15 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the flood kicker on or off. When enabled, this\n"
"option tells the bot to kick users who are flooding\n"
"the channel using at least \002ln\002 lines in \002secs\002 seconds\n"
"(if not given, it defaults to 6 lines in 10 seconds).\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the flood kicker on or off. When enabled, this "
"option tells the bot to kick users who are flooding "
"the channel using at least \002ln\002 lines in \002secs\002 seconds "
"(if not given, it defaults to 6 lines in 10 seconds). "
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."));
return true;
}
};
@@ -577,12 +616,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the italics kicker on or off. When enabled, this\n"
"option tells the bot to kick users who use italics.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the italics kicker on or off. When enabled, this "
"option tells the bot to kick users who use italics. "
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -631,22 +672,42 @@ public:
if (kd->ttb[TTB_REPEAT])
{
if (kd->repeattimes != 1)
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d times), and will place a ban after %d\n"
"kicks for the same user."), kd->repeattimes, kd->ttb[TTB_REPEAT]);
{
source.Reply(_(
"Bot will now kick for \002repeats\002 (users that repeat the "
"same message %d times), and will place a ban after %d "
"kicks for the same user."
),
kd->repeattimes,
kd->ttb[TTB_REPEAT]);
}
else
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d time), and will place a ban after %d\n"
"kicks for the same user."), kd->repeattimes, kd->ttb[TTB_REPEAT]);
source.Reply(_(
"Bot will now kick for \002repeats\002 (users that repeat the "
"same message %d time), and will place a ban after %d "
"kicks for the same user."
),
kd->repeattimes,
kd->ttb[TTB_REPEAT]);
}
else
{
if (kd->repeattimes != 1)
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d times)."), kd->repeattimes);
{
source.Reply(_(
"Bot will now kick for \002repeats\002 (users that repeat the "
"same message %d times)."
),
kd->repeattimes);
}
else
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d time)."), kd->repeattimes);
{
source.Reply(_(
"Bot will now kick for \002repeats\002 (users that repeat the "
"same message %d time)."
),
kd->repeattimes);
}
}
}
else if (params[1].equals_ci("OFF"))
@@ -664,14 +725,16 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the repeat kicker on or off. When enabled, this\n"
"option tells the bot to kick users who are repeating\n"
"themselves \002num\002 times (if num is not given, it\n"
"defaults to 3).\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the repeat kicker on or off. When enabled, this "
"option tells the bot to kick users who are repeating "
"themselves \002num\002 times (if num is not given, it "
"defaults to 3)."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -701,12 +764,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the reverses kicker on or off. When enabled, this\n"
"option tells the bot to kick users who use reverses.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the reverses kicker on or off. When enabled, this "
"option tells the bot to kick users who use reverses. "
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -736,12 +801,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the underlines kicker on or off. When enabled, this\n"
"option tells the bot to kick users who use underlines.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the underlines kicker on or off. When enabled, this "
"option tells the bot to kick users who use underlines. "
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -804,10 +871,12 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) 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."));
source.Reply(" ");
source.Reply(_(
"Enables or disables \002ops protection\002 mode on a channel. "
"When it is enabled, ops won't be kicked by the bot "
"even if they don't match the NOKICK level."
));
return true;
}
};
@@ -870,10 +939,12 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) 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."));
source.Reply(" ");
source.Reply(_(
"Enables or disables \002voices protection\002 mode on a channel. "
"When it is enabled, voices won't be kicked by the bot "
"even if they don't match the NOKICK level."
));
return true;
}
};
@@ -913,7 +984,7 @@ public:
void purge()
{
time_t keepdata = Config->GetModule(me)->Get<time_t>("keepdata");
time_t keepdata = Config->GetModule(me).Get<time_t>("keepdata");
for (data_type::iterator it = data_map.begin(), it_end = data_map.end(); it != it_end;)
{
const Anope::string &user = it->first;
@@ -1299,7 +1370,7 @@ public:
/* Normalize the buffer */
Anope::string nbuf = Anope::NormalizeBuffer(realbuf);
bool casesensitive = Config->GetModule("botserv")->Get<bool>("casesensitive");
bool casesensitive = Config->GetModule("botserv").Get<bool>("casesensitive");
/* Normalize can return an empty string if this only contains control codes etc */
if (badwords && !nbuf.empty())
@@ -1368,7 +1439,7 @@ public:
if (mustkick)
{
check_ban(ci, u, kd, TTB_BADWORDS);
if (Config->GetModule(me)->Get<bool>("gentlebadwordreason"))
if (Config->GetModule(me).Get<bool>("gentlebadwordreason"))
bot_kick(ci, u, _("Watch your language!"));
else
bot_kick(ci, u, _("Don't use the word \"%s\" on this channel!"), bw->word.c_str());
+26 -16
View File
@@ -30,11 +30,15 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Configures bot options.\n"
" \n"
"Available options:"));
bool hide_privileged_commands = Config->GetBlock("options")->Get<bool>("hideprivilegedcommands"),
hide_registered_commands = Config->GetBlock("options")->Get<bool>("hideregisteredcommands");
source.Reply(_(
"Configures bot options."
"\n\n"
"Available options:"
));
bool hide_privileged_commands = Config->GetBlock("options").Get<bool>("hideprivilegedcommands"),
hide_registered_commands = Config->GetBlock("options").Get<bool>("hideregisteredcommands");
HelpWrapper help;
Anope::string this_name = source.command;
for (const auto &[c_name, info] : source.service->commands)
{
@@ -54,12 +58,14 @@ public:
continue;
source.command = c_name;
command->OnServHelp(source);
command->OnServHelp(source, help);
}
}
}
source.Reply(_("Type \002%s HELP %s \037option\037\002 for more information on a\n"
"particular option."), source.service->GetQueryCommand().c_str(), this_name.c_str());
help.SendTo(source);
source.Reply(_("Type \002%s\032\037option\037\002 for more information on a particular option."),
source.service->GetQueryCommand("generic/help", this_name).c_str());
return true;
}
@@ -150,11 +156,13 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(_(" \n"
"Sets the time bot bans expire in. If enabled, any bans placed by\n"
"bots, such as flood kicker, badwords kicker, etc. will automatically\n"
"be removed after the given time. Set to 0 to disable bans from\n"
"automatically expiring."));
source.Reply(" ");
source.Reply(_(
"Sets the time bot bans expire in. If enabled, any bans placed by "
"bots, such as flood kicker, badwords kicker, etc. will automatically "
"be removed after the given time. Set to 0 to disable bans from "
"automatically expiring."
));
return true;
}
};
@@ -203,9 +211,11 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(_(" \n"
"This option prevents a bot from being assigned to a\n"
"channel by users that aren't IRC Operators."));
source.Reply(" ");
source.Reply(_(
"This option prevents a bot from being assigned to a "
"channel by users that aren't IRC Operators."
));
return true;
}
};
+61 -43
View File
@@ -10,12 +10,12 @@
*/
#include "module.h"
#include "modules/cs_mode.h"
#include "modules/chanserv/mode.h"
inline static Anope::string BotModes()
{
return Config->GetModule("botserv")->Get<Anope::string>("botmodes",
Config->GetModule("chanserv")->Get<Anope::string>("botmodes", "o")
return Config->GetModule("botserv").Get<Anope::string>("botmodes",
Config->GetModule("chanserv").Get<Anope::string>("botmodes", "o")
);
}
@@ -52,7 +52,7 @@ public:
* @param chan The channel
*/
ChanServTimer(Reference<BotInfo> &cs, ExtensibleItem<bool> &i, Module *m, Channel *chan)
: Timer(m, Config->GetModule(m)->Get<time_t>("inhabit", "1m"))
: Timer(m, Config->GetModule(m).Get<time_t>("inhabit", "1m"))
, ChanServ(cs)
, inhabit(i)
, c(chan)
@@ -103,9 +103,9 @@ public:
new ChanServTimer(ChanServ, inhabit, this->owner, c);
}
void OnReload(Configuration::Conf *conf) override
void OnReload(Configuration::Conf &conf) override
{
const Anope::string &channick = conf->GetModule(this)->Get<const Anope::string>("client");
const Anope::string &channick = conf.GetModule(this).Get<const Anope::string>("client");
if (channick.empty())
throw ConfigException(Module::name + ": <client> must be defined");
@@ -116,18 +116,21 @@ public:
ChanServ = bi;
spacesepstream(conf->GetModule(this)->Get<const Anope::string>("defaults", "keeptopic peace securefounder signkick")).GetTokens(defaults);
spacesepstream(conf.GetModule(this).Get<const Anope::string>("defaults")).GetTokens(defaults);
if (defaults.empty())
{
defaults.emplace_back("KEEPTOPIC");
defaults.emplace_back("PEACE");
defaults.emplace_back("SECUREFOUNDER");
defaults.emplace_back("SIGNKICK");
defaults = {
"CS_KEEP_MODES",
"KEEPTOPIC",
"PEACE",
"SECUREFOUNDER",
"SIGNKICK",
};
}
else if (defaults[0].equals_ci("none"))
defaults.clear();
always_lower = conf->GetModule(this)->Get<bool>("always_lower_ts");
always_lower = conf.GetModule(this).Get<bool>("always_lower_ts");
}
void OnBotDelete(BotInfo *bi) override
@@ -138,7 +141,7 @@ public:
EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message, const Anope::map<Anope::string> &tags) override
{
if (bi == ChanServ && Config->GetModule(this)->Get<bool>("opersonly") && !u->HasMode("OPER"))
if (bi == ChanServ && Config->GetModule(this).Get<bool>("opersonly") && !u->HasMode("OPER"))
{
u->SendMessage(bi, ACCESS_DENIED);
return EVENT_STOP;
@@ -151,7 +154,7 @@ public:
{
std::deque<ChannelInfo *> chans;
nc->GetChannelReferences(chans);
int max_reg = Config->GetModule(this)->Get<int>("maxregistered");
int max_reg = Config->GetModule(this).Get<int>("maxregistered");
for (auto *ci : chans)
{
@@ -247,7 +250,7 @@ public:
{
ci->c->RemoveMode(ci->WhoSends(), "REGISTERED", "", false);
const Anope::string &require = Config->GetModule(this)->Get<const Anope::string>("require");
const Anope::string &require = Config->GetModule(this).Get<const Anope::string>("require");
if (!require.empty())
ci->c->SetModes(ci->WhoSends(), false, "-%s", require.c_str());
}
@@ -257,14 +260,19 @@ public:
{
if (!params.empty() || source.c || source.service != *ChanServ)
return EVENT_CONTINUE;
source.Reply(_("\002%s\002 allows you to register and control various\n"
"aspects of channels. %s can often prevent\n"
"malicious users from \"taking over\" channels by limiting\n"
"who is allowed channel operator privileges. Available\n"
"commands are listed below; to use them, type\n"
"\002%s \037command\037\002. For more information on a\n"
"specific command, type \002%s HELP \037command\037\002.\n"),
ChanServ->nick.c_str(), ChanServ->nick.c_str(), ChanServ->GetQueryCommand().c_str(), ChanServ->GetQueryCommand().c_str());
source.Reply(_(
"\002%s\002 allows you to register and control various "
"aspects of channels. %s can often prevent "
"malicious users from \"taking over\" channels by limiting "
"who is allowed channel operator privileges. Available "
"commands are listed below; to use them, type "
"\002%s\032\037command\037\002. For more information on a "
"specific command, type \002%s\032\037command\037\002."
),
ChanServ->nick.c_str(),
ChanServ->nick.c_str(),
ChanServ->GetQueryCommand().c_str(),
ChanServ->GetQueryCommand("generic/help").c_str());
return EVENT_CONTINUE;
}
@@ -272,17 +280,27 @@ public:
{
if (!params.empty() || source.c || source.service != *ChanServ)
return;
time_t chanserv_expire = Config->GetModule(this)->Get<time_t>("expire", "30d");
if (chanserv_expire >= 86400)
source.Reply(_(" \n"
"Note that any channel which is not used for %lu days\n"
"(i.e. which no user on the channel's access list enters\n"
"for that period of time) will be automatically dropped."), (unsigned long)chanserv_expire / 86400);
time_t chanserv_expire = Config->GetModule(this).Get<time_t>("expire", "30d");
if (chanserv_expire)
{
source.Reply(" ");
source.Reply(_(
"Note that any channel which is not used for %s "
"(i.e. which no user on the channel's access list enters "
"for that period of time) will be automatically dropped."
),
Anope::Duration(chanserv_expire, source.nc).c_str());
}
if (source.IsServicesOper())
source.Reply(_(" \n"
"Services Operators can also, depending on their access drop\n"
"any channel, view (and modify) the access, levels and akick\n"
"lists and settings for any channel."));
{
source.Reply(" ");
source.Reply(_(
"Services Operators can also, depending on their access drop "
"any channel, view (and modify) the access, levels and akick "
"lists and settings for any channel."
));
}
}
void OnCheckModes(Reference<Channel> &c) override
@@ -295,7 +313,7 @@ public:
else
c->RemoveMode(c->WhoSends(), "REGISTERED", "", false);
const Anope::string &require = Config->GetModule(this)->Get<const Anope::string>("require");
const Anope::string &require = Config->GetModule(this).Get<const Anope::string>("require");
if (!require.empty())
{
if (c->ci)
@@ -314,8 +332,8 @@ public:
EventReturn OnCanSet(User *u, const ChannelMode *cm) override
{
if (Config->GetModule(this)->Get<const Anope::string>("nomlock").find(cm->mchar) != Anope::string::npos
|| Config->GetModule(this)->Get<const Anope::string>("require").find(cm->mchar) != Anope::string::npos)
if (Config->GetModule(this).Get<const Anope::string>("nomlock").find(cm->mchar) != Anope::string::npos
|| Config->GetModule(this).Get<const Anope::string>("require").find(cm->mchar) != Anope::string::npos)
return EVENT_STOP;
return EVENT_CONTINUE;
}
@@ -337,7 +355,7 @@ public:
void OnExpireTick() override
{
time_t chanserv_expire = Config->GetModule(this)->Get<time_t>("expire", "30d");
time_t chanserv_expire = Config->GetModule(this).Get<time_t>("expire", "30d");
if (!chanserv_expire || Anope::NoExpire || Anope::ReadOnly)
return;
@@ -399,7 +417,7 @@ public:
continue;
bool c;
ci->c = Channel::FindOrCreate(ci->name, c, ci->time_registered);
ci->c = Channel::FindOrCreate(ci->name, c, ci->registered);
ci->c->syncing |= created;
if (perm)
@@ -434,10 +452,10 @@ public:
void OnJoinChannel(User *u, Channel *c) override
{
if (always_lower && c->ci && c->creation_time > c->ci->time_registered)
if (always_lower && c->ci && c->created > c->ci->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;
Log(LOG_DEBUG) << "Changing TS of " << c->name << " from " << c->created << " to " << c->ci->registered;
c->created = c->ci->registered;
IRCD->SendChannel(c);
c->Reset();
}
@@ -445,7 +463,7 @@ public:
EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) override
{
if (!always_lower && Anope::CurTime == c->creation_time && c->ci && setter.GetUser() && !setter.GetUser()->server->IsULined())
if (!always_lower && Anope::CurTime == c->created && c->ci && setter.GetUser() && !setter.GetUser()->server->IsULined())
{
ChanUserContainer *cu = c->FindUser(setter.GetUser());
ChannelMode *cm = ModeManager::FindChannelModeByName("OP");
@@ -467,7 +485,7 @@ public:
if (!show_all)
return;
time_t chanserv_expire = Config->GetModule(this)->Get<time_t>("expire", "30d");
time_t chanserv_expire = Config->GetModule(this).Get<time_t>("expire", "30d");
if (!ci->HasExt("CS_NO_EXPIRE") && chanserv_expire && !Anope::NoExpire && ci->last_used != Anope::CurTime)
info[_("Expires")] = Anope::strftime(ci->last_used + chanserv_expire, source.GetAccount());
}
+142 -126
View File
@@ -84,6 +84,38 @@ AccessAccessProvider *AccessAccessProvider::me;
class CommandCSAccess final
: public Command
{
private:
static void AddEntry(ListFormatter &list, const ChannelInfo *ci, const ChanAccess *access, unsigned number)
{
Anope::string timebuf;
if (ci->c)
{
for (const auto &[_, cuc] : ci->c->users)
{
ChannelInfo *p;
if (access->Matches(cuc->user, cuc->user->Account(), p))
timebuf = "Now";
}
}
if (timebuf.empty())
{
if (access->last_seen == 0)
timebuf = "Never";
else
timebuf = Anope::strftime(access->last_seen, NULL, true);
}
ListFormatter::ListEntry entry;
entry["Number"] = Anope::ToString(number);
entry["Level"] = access->AccessSerialize();
entry["Mask"] = access->Mask();
entry["By"] = access->creator;
entry["Last seen"] = timebuf;
entry["Description"] = access->description;
list.AddEntry(entry);
}
void DoAdd(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
{
Anope::string mask = params[2];
@@ -134,7 +166,7 @@ class CommandCSAccess final
if (IRCD->IsChannelValid(mask))
{
if (Config->GetModule("chanserv")->Get<bool>("disallow_channel_access"))
if (Config->GetModule("chanserv").Get<bool>("disallow_channel_access"))
{
source.Reply(_("Channels may not be on access lists."));
return;
@@ -158,7 +190,7 @@ class CommandCSAccess final
{
na = NickAlias::Find(mask);
if (!na && Config->GetModule("chanserv")->Get<bool>("disallow_hostmask_access"))
if (!na && Config->GetModule("chanserv").Get<bool>("disallow_hostmask_access"))
{
source.Reply(_("Masks and unregistered users may not be on access lists."));
return;
@@ -205,7 +237,7 @@ class CommandCSAccess final
}
}
unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1000");
unsigned access_max = Config->GetModule("chanserv").Get<unsigned>("accessmax", "1000");
if (access_max && ci->GetDeepAccessCount() >= access_max)
{
source.Reply(_("Sorry, you can only have %d access entries on a channel, including access entries from other channels."), access_max);
@@ -284,11 +316,11 @@ class CommandCSAccess final
else
{
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "to delete " << Nicks;
if (deleted == 1)
source.Reply(_("Deleted 1 entry from %s access list."), ci->name.c_str());
source.Reply(_("Deleted %s from %s access list."), Nicks.c_str(), ci->name.c_str());
else
source.Reply(_("Deleted %d entries from %s access list."), deleted, ci->name.c_str());
source.Reply(deleted, N_("Deleted %d entry from %s access list.", "Deleted %d entries from %s access list."), deleted, ci->name.c_str());
}
}
@@ -381,32 +413,7 @@ class CommandCSAccess final
const ChanAccess *access = ci->GetAccess(number - 1);
Anope::string timebuf;
if (ci->c)
{
for (const auto &[_, cuc] : ci->c->users)
{
ChannelInfo *p;
if (access->Matches(cuc->user, cuc->user->Account(), p))
timebuf = "Now";
}
}
if (timebuf.empty())
{
if (access->last_seen == 0)
timebuf = "Never";
else
timebuf = Anope::strftime(access->last_seen, NULL, true);
}
ListFormatter::ListEntry entry;
entry["Number"] = Anope::ToString(number);
entry["Level"] = access->AccessSerialize();
entry["Mask"] = access->Mask();
entry["By"] = access->creator;
entry["Last seen"] = timebuf;
entry["Description"] = access->description;
this->list.AddEntry(entry);
AddEntry(this->list, ci, access, number);
}
}
nl_list(list, ci, nick);
@@ -421,32 +428,7 @@ class CommandCSAccess final
if (!nick.empty() && !Anope::Match(access->Mask(), nick))
continue;
Anope::string timebuf;
if (ci->c)
{
for (auto &[_, cuc] : ci->c->users)
{
ChannelInfo *p;
if (access->Matches(cuc->user, cuc->user->Account(), p))
timebuf = "Now";
}
}
if (timebuf.empty())
{
if (access->last_seen == 0)
timebuf = "Never";
else
timebuf = Anope::strftime(access->last_seen, NULL, true);
}
ListFormatter::ListEntry entry;
entry["Number"] = Anope::ToString(i + 1);
entry["Level"] = access->AccessSerialize();
entry["Mask"] = access->Mask();
entry["By"] = access->creator;
entry["Last seen"] = timebuf;
entry["Description"] = access->description;
list.AddEntry(entry);
AddEntry(list, ci, access, i + 1);
}
}
@@ -586,52 +568,76 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Maintains the \002access list\002 for a channel. The access\n"
"list specifies which users are allowed chanop status or\n"
"access to %s commands on the channel. Different\n"
"user levels allow for access to different subsets of\n"
"privileges. Any registered user not on the access list has\n"
"a user level of 0, and any unregistered user has a user level\n"
"of -1."), source.service->nick.c_str());
source.Reply(_(
"Maintains the \002access list\002 for a channel. The access "
"list specifies which users are allowed chanop status or "
"access to %s commands on the channel. Different "
"user levels allow for access to different subsets of "
"privileges. Any registered user not on the access list has "
"a user level of 0, and any unregistered user has a user level "
"of -1."
"\n\n"
"The \002%s\032ADD\002 command adds the given mask to the "
"access list with the given user level; if the mask is "
"already present on the list, its access level is changed to "
"the level specified in the command. The \037level\037 specified "
"may be a numerical level or the name of a privilege (eg AUTOOP). "
"When a user joins the channel the access they receive is from the "
"highest level entry in the access list."
),
source.service->nick.c_str(),
source.command.nobreak().c_str());
if (!Config->GetModule("chanserv").Get<bool>("disallow_channel_access"))
{
source.Reply(_(
"The given mask may also be a channel, which will use the "
"access list from the other channel up to the given \037level\037."
));
}
source.Reply(" ");
source.Reply(_("The \002ACCESS ADD\002 command adds the given mask to the\n"
"access list with the given user level; if the mask is\n"
"already present on the list, its access level is changed to\n"
"the level specified in the command. The \037level\037 specified\n"
"may be a numerical level or the name of a privilege (eg AUTOOP).\n"
"When a user joins the channel the access they receive is from the\n"
"highest level entry in the access list."));
if (!Config->GetModule("chanserv")->Get<bool>("disallow_channel_access"))
source.Reply(_("The given mask may also be a channel, which will use the\n"
"access list from the other channel up to the given \037level\037."));
source.Reply(" ");
source.Reply(_("The \002ACCESS DEL\002 command removes the given nick from the\n"
"access list. If a list of entry numbers is given, those\n"
"entries are deleted. (See the example for LIST below.)\n"
"You may remove yourself from an access list, even if you\n"
"do not have access to modify that list otherwise."));
source.Reply(" ");
source.Reply(_("The \002ACCESS LIST\002 command displays the access list. If\n"
"a wildcard mask is given, only those entries matching the\n"
"mask are displayed. If a list of entry numbers is given,\n"
source.Reply(_(
"The \002%s\032DEL\002 command removes the given nick from the "
"access list. If a list of entry numbers is given, those "
"entries are deleted. (See the example for LIST below.) "
"You may remove yourself from an access list, even if you "
"do not have access to modify that list otherwise."
"\n\n"
"The \002%s\032LIST\002 command displays the access list. If "
"a wildcard mask is given, only those entries matching the "
"mask are displayed. If a list of entry numbers is given, "
"only those entries are shown; for example:\n"
" \002ACCESS #channel LIST 2-5,7-9\002\n"
" \002%s\032#channel\032LIST\0322-5,7-9\002\n"
" Lists access entries numbered 2 through 5 and\n"
" 7 through 9.\n"
" \n"
"The \002ACCESS VIEW\002 command displays the access list similar\n"
"to \002ACCESS LIST\002 but shows the creator and last used time.\n"
" \n"
"The \002ACCESS CLEAR\002 command clears all entries of the\n"
"access list."));
source.Reply(" ");
" 7 through 9."
"\n\n"
"The \002%s\032VIEW\002 command displays the access list similar "
"to \002%s\032LIST\002 but shows the creator and last used time."
"\n\n"
"The \002%s\032CLEAR\002 command clears all entries of the "
"access list."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
BotInfo *bi;
Anope::string cmd;
if (Command::FindCommandFromService("chanserv/levels", bi, cmd))
source.Reply(_("\002User access levels\002 can be seen by using the\n"
"\002%s\002 command; type \002%s HELP LEVELS\002 for\n"
"information."), cmd.c_str(), bi->GetQueryCommand().c_str());
{
source.Reply(" ");
source.Reply(_(
"\002User access levels\002 can be seen by using the "
"\002%s\002 command; type \002%s\032LEVELS\002 for "
"information."
),
cmd.c_str(),
bi->GetQueryCommand("generic/help").c_str());
}
return true;
}
};
@@ -666,8 +672,8 @@ class CommandCSLevels final
Privilege *p = PrivilegeManager::FindPrivilege(what);
if (p == NULL)
{
source.Reply(_("Setting \002%s\002 not known. Type \002%s HELP LEVELS\002 for a list of valid settings."),
what.c_str(), source.service->GetQueryCommand().c_str());
source.Reply(_("Setting \002%s\002 not known. Type \002%s\032LEVELS\002 for a list of valid settings."),
what.c_str(), source.service->GetQueryCommand("generic/help").c_str());
}
else
{
@@ -709,8 +715,8 @@ class CommandCSLevels final
return;
}
source.Reply(_("Setting \002%s\002 not known. Type \002%s HELP LEVELS\002 for a list of valid settings."),
what.c_str(), source.service->GetQueryCommand().c_str());
source.Reply(_("Setting \002%s\002 not known. Type \002%s\032LEVELS\002 for a list of valid settings."),
what.c_str(), source.service->GetQueryCommand("generic/help").c_str());
}
static void DoList(CommandSource &source, ChannelInfo *ci)
@@ -839,25 +845,35 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("The \002LEVELS\002 command allows fine control over the meaning of\n"
"the numeric access levels used for channels. With this\n"
"command, you can define the access level required for most\n"
"of %s's functions. (The \002SET FOUNDER\002 and this command\n"
"are always restricted to the channel founder.)\n"
" \n"
"\002LEVELS SET\002 allows the access level for a function or group of\n"
"functions to be changed. \002LEVELS DISABLE\002 (or \002DIS\002 for short)\n"
"disables an automatic feature or disallows access to a\n"
"function by anyone, INCLUDING the founder (although, the founder\n"
"can always re-enable it). Use \002LEVELS SET founder\002 to make a level\n"
"founder only.\n"
" \n"
"\002LEVELS LIST\002 shows the current levels for each function or\n"
"group of functions. \002LEVELS RESET\002 resets the levels to the\n"
"default levels of a newly-created channel.\n"
" \n"
"For a list of the features and functions whose levels can be\n"
"set, see \002HELP LEVELS DESC\002."), source.service->nick.c_str());
source.Reply(_(
"The \002%s\002 command allows fine control over the meaning of "
"the numeric access levels used for channels. With this "
"command, you can define the access level required for most "
"of %s's functions. (The \002SET\032FOUNDER\002 and this command "
"are always restricted to the channel founder)."
"\n\n"
"\002%s\032SET\002 allows the access level for a function or group of "
"functions to be changed. \002%s\032DISABLE\002 (or \002DIS\002 for short) "
"disables an automatic feature or disallows access to a "
"function by anyone, INCLUDING the founder (although, the founder "
"can always re-enable it). Use \002%s\032SET founder\002 to make a level "
"founder only."
"\n\n"
"\002%s\032LIST\002 shows the current levels for each function or "
"group of functions. \002%s\032RESET\002 resets the levels to the "
"default levels of a newly-created channel."
"\n\n"
"For a list of the features and functions whose levels can be "
"set, see \002HELP\032%s\032DESC\002."
),
source.service->nick.c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
}
return true;
}
@@ -878,21 +894,21 @@ public:
}
void OnReload(Configuration::Conf *conf) override
void OnReload(Configuration::Conf &conf) override
{
defaultLevels.clear();
for (int i = 0; i < conf->CountBlock("privilege"); ++i)
for (int i = 0; i < conf.CountBlock("privilege"); ++i)
{
Configuration::Block *priv = conf->GetBlock("privilege", i);
const auto &priv = conf.GetBlock("privilege", i);
const Anope::string &pname = priv->Get<const Anope::string>("name");
const Anope::string &pname = priv.Get<const Anope::string>("name");
Privilege *p = PrivilegeManager::FindPrivilege(pname);
if (p == NULL)
continue;
const Anope::string &value = priv->Get<const Anope::string>("level");
const Anope::string &value = priv.Get<const Anope::string>("level");
if (value.empty())
continue;
else if (value.equals_ci("founder"))
@@ -900,7 +916,7 @@ public:
else if (value.equals_ci("disabled"))
defaultLevels[p->name] = ACCESS_INVALID;
else
defaultLevels[p->name] = priv->Get<int16_t>("level");
defaultLevels[p->name] = priv.Get<int16_t>("level");
}
}
+69 -46
View File
@@ -46,7 +46,7 @@ class CommandCSAKick final
const NickAlias *na = NickAlias::Find(mask);
NickCore *nc = NULL;
const AutoKick *akick;
unsigned reasonmax = Config->GetModule("chanserv")->Get<unsigned>("reasonmax", "200");
unsigned reasonmax = Config->GetModule("chanserv").Get<unsigned>("reasonmax", "200");
if (reason.length() > reasonmax)
reason = reason.substr(0, reasonmax);
@@ -170,9 +170,9 @@ class CommandCSAKick final
}
}
if (ci->GetAkickCount() >= Config->GetModule(this->owner)->Get<unsigned>("autokickmax"))
if (ci->GetAkickCount() >= Config->GetModule(this->owner).Get<unsigned>("autokickmax"))
{
source.Reply(_("Sorry, you can only have %d autokick masks on a channel."), Config->GetModule(this->owner)->Get<unsigned>("autokickmax"));
source.Reply(_("Sorry, you can only have %d autokick masks on a channel."), Config->GetModule(this->owner).Get<unsigned>("autokickmax"));
return;
}
@@ -211,6 +211,7 @@ class CommandCSAKick final
ChannelInfo *ci;
Command *c;
unsigned deleted = 0;
Anope::string lastdeleted;
AccessGroup ag;
public:
AkickDelCallback(CommandSource &_source, ChannelInfo *_ci, Command *_c, const Anope::string &list) : NumberList(list, true), source(_source), ci(_ci), c(_c), ag(source.AccessFor(ci))
@@ -219,12 +220,20 @@ class CommandCSAKick final
~AkickDelCallback() override
{
if (!deleted)
source.Reply(_("No matching entries on %s autokick list."), ci->name.c_str());
else if (deleted == 1)
source.Reply(_("Deleted 1 entry from %s autokick list."), ci->name.c_str());
else
source.Reply(_("Deleted %d entries from %s autokick list."), deleted, ci->name.c_str());
switch (deleted)
{
case 0:
source.Reply(_("No matching entries on %s autokick list."), ci->name.c_str());
break;
case 1:
source.Reply(_("Deleted %s from %s autokick list."), lastdeleted.c_str(), ci->name.c_str());
break;
default:
source.Reply(deleted, N_("Deleted %d entry from %s autokick list.", "Deleted %d entries from %s autokick list."), deleted, ci->name.c_str());
break;
}
}
void HandleNumber(unsigned number) override
@@ -237,7 +246,8 @@ class CommandCSAKick final
FOREACH_MOD(OnAkickDel, (source, ci, akick));
bool override = !ag.HasPriv("AKICK");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "to delete " << (akick->nc ? akick->nc->display : akick->mask);
lastdeleted = (akick->nc ? akick->nc->display : akick->mask);
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "to delete " << lastdeleted;
++deleted;
ci->EraseAkick(number - 1);
@@ -490,40 +500,51 @@ public:
BotInfo *bi = Config->GetClient("NickServ");
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Maintains the \002AutoKick list\002 for a channel. If a user\n"
"on the AutoKick list attempts to join the channel,\n"
"%s will ban that user from the channel, then kick\n"
"the user.\n"
" \n"
"The \002AKICK ADD\002 command adds the given nick or usermask\n"
"to the AutoKick list. If a \037reason\037 is given with\n"
"the command, that reason will be used when the user is\n"
"kicked; if not, the default reason is \"User has been\n"
"banned from the channel\".\n"
"When akicking a \037registered nick\037 the %s account\n"
"will be added to the akick list instead of the mask.\n"
"All users within that nickgroup will then be akicked.\n"),
source.service->nick.c_str(), bi ? bi->nick.c_str() : "NickServ");
source.Reply(_(
" \n"
"The \002AKICK DEL\002 command removes the given nick or mask\n"
"from the AutoKick list. It does not, however, remove any\n"
"bans placed by an AutoKick; those must be removed\n"
"manually.\n"
" \n"
"The \002AKICK LIST\002 command displays the AutoKick list, or\n"
"optionally only those AutoKick entries which match the\n"
"given mask.\n"
" \n"
"The \002AKICK VIEW\002 command is a more verbose version of the\n"
"\002AKICK LIST\002 command.\n"
" \n"
"The \002AKICK ENFORCE\002 command causes %s to enforce the\n"
"current AKICK list by removing those users who match an\n"
"AKICK mask.\n"
" \n"
"The \002AKICK CLEAR\002 command clears all entries of the\n"
"akick list."), source.service->nick.c_str());
"Maintains the \002AutoKick list\002 for a channel. If a user "
"on the AutoKick list attempts to join the channel, "
"%s will ban that user from the channel, then kick "
"the user."
"\n\n"
"The \002%s\032ADD\002 command adds the given nick or usermask "
"to the AutoKick list. If a \037reason\037 is given with "
"the command, that reason will be used when the user is "
"kicked; if not, the default reason is \"User has been "
"banned from the channel\". "
"When akicking a \037registered nick\037 the %s account "
"will be added to the akick list instead of the mask. "
"All users within that nickgroup will then be akicked. "
"\n\n"
"The \002%s\032DEL\002 command removes the given nick or mask "
"from the AutoKick list. It does not, however, remove any "
"bans placed by an AutoKick; those must be removed "
"manually."
"\n\n"
"The \002%s\032LIST\002 command displays the AutoKick list, or "
"optionally only those AutoKick entries which match the "
"given mask."
"\n\n"
"The \002%s\032VIEW\002 command is a more verbose version of the "
"\002%s\032LIST\002 command."
"\n\n"
"The \002%s\032ENFORCE\002 command causes %s to enforce the "
"current akick list by removing those users who match an "
"akick mask."
"\n\n"
"The \002%s\032CLEAR\002 command clears all entries of the "
"akick list."
),
source.service->nick.c_str(),
source.command.nobreak().c_str(),
bi ? bi->nick.c_str() : "NickServ",
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
@@ -568,9 +589,11 @@ public:
reason = autokick->reason;
if (reason.empty())
{
reason = Language::Translate(u, Config->GetModule(this)->Get<const Anope::string>("autokickreason").c_str());
reason = reason.replace_all_cs("%n", u->nick)
.replace_all_cs("%c", c->name);
reason = Language::Translate(u, Config->GetModule(this).Get<const Anope::string>("autokickreason").c_str());
reason = Anope::Template(reason, {
{ "channel", c->name },
{ "nick", u->nick },
});
}
if (reason.empty())
reason = Language::Translate(u, _("User has been banned from the channel"));
+22 -15
View File
@@ -50,8 +50,8 @@ public:
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
Configuration::Block *block = Config->GetCommand(source);
const Anope::string &mode = block->Get<Anope::string>("mode", "BAN");
const auto &block = Config->GetCommand(source);
const Anope::string &mode = block.Get<Anope::string>("mode", "BAN");
ChannelMode *cm = ModeManager::FindChannelModeByName(mode);
if (cm == NULL)
return;
@@ -107,12 +107,11 @@ public:
reason += " " + params[3];
}
unsigned reasonmax = Config->GetModule("chanserv")->Get<unsigned>("reasonmax", "200");
unsigned reasonmax = Config->GetModule("chanserv").Get<unsigned>("reasonmax", "200");
if (reason.length() > reasonmax)
reason = reason.substr(0, reasonmax);
Anope::string signkickformat = Config->GetModule("chanserv")->Get<Anope::string>("signkickformat", "%m (%n)");
signkickformat = signkickformat.replace_all_cs("%n", source.GetNick());
auto signkickformat = Config->GetModule("chanserv").Get<Anope::string>("signkickformat", "{message} ({nick})");
User *u = source.GetUser();
User *u2 = User::Find(target, true);
@@ -156,11 +155,14 @@ public:
if (!c->FindUser(u2))
return;
if (block->Get<bool>("kick", "yes"))
if (block.Get<bool>("kick", "yes"))
{
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !source.AccessFor(ci).HasPriv("SIGNKICK")))
{
signkickformat = signkickformat.replace_all_cs("%m", reason);
signkickformat = Anope::Template(signkickformat, {
{ "message", reason },
{ "nick", source.GetNick() },
});
c->Kick(ci->WhoSends(), u2, signkickformat);
}
else
@@ -209,13 +211,16 @@ public:
else if (uc->user->IsProtected())
continue;
if (block->Get<bool>("kick", "yes"))
if (block.Get<bool>("kick", "yes"))
{
++kicked;
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
{
reason += " (Matches " + mask + ")";
signkickformat = signkickformat.replace_all_cs("%m", reason);
signkickformat = Anope::Template(signkickformat, {
{ "message", reason },
{ "nick", source.GetNick() },
});
c->Kick(ci->WhoSends(), uc->user, signkickformat);
}
else
@@ -235,12 +240,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Bans a given nick or mask on a channel. An optional expiry may\n"
"be given to cause services to remove the ban after a set amount\n"
"of time.\n"
" \n"
"By default, limited to AOPs or those with level 5 access\n"
"and above on the channel. Channel founders may ban masks."));
source.Reply(_(
"Bans a given nick or mask on a channel. An optional expiry may "
"be given to cause services to remove the ban after a set amount "
"of time."
"\n\n"
"By default, limited to AOPs or those with level 5 access "
"and above on the channel. Channel founders may ban masks."
));
return true;
}
};
+9 -7
View File
@@ -10,7 +10,7 @@
*/
#include "module.h"
#include "modules/bs_badwords.h"
#include "modules/botserv/badwords.h"
class CommandCSClone final
: public Command
@@ -24,7 +24,7 @@ class CommandCSClone final
static void CopyAccess(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci)
{
std::set<Anope::string> masks;
unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1000");
unsigned access_max = Config->GetModule("chanserv").Get<unsigned>("accessmax", "1000");
unsigned count = 0;
for (unsigned i = 0; i < target_ci->GetAccessCount(); ++i)
@@ -169,7 +169,7 @@ public:
delete target_ci;
target_ci = new ChannelInfo(*ci);
target_ci->name = target;
target_ci->time_registered = Anope::CurTime;
target_ci->registered = Anope::CurTime;
(*RegisteredChannelList)[target_ci->name] = target_ci;
target_ci->c = Channel::Find(target_ci->name);
@@ -239,10 +239,12 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Copies all settings, access, akicks, etc from \002channel\002 to the\n"
"\002target\002 channel. If \037what\037 is \002ACCESS\002, \002AKICK\002, \002BADWORDS\002,\n"
"or \002LEVELS\002 then only the respective settings are cloned.\n"
"You must be the founder of \037channel\037 and \037target\037."));
source.Reply(_(
"Copies all settings, access, akicks, etc from \002channel\002 to the "
"\002target\002 channel. If \037what\037 is \002ACCESS\002, \002AKICK\002, \002BADWORDS\002, "
"or \002LEVELS\002 then only the respective settings are cloned. "
"You must be the founder of \037channel\037 and \037target\037."
));
return true;
}
};
+20 -8
View File
@@ -55,10 +55,10 @@ public:
if (!code)
{
code = ci->Extend<Anope::string>("channel-dropcode");
*code = Anope::Random(15);
*code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", 15));
}
source.Reply(CONFIRM_DROP, ci->name.c_str(), source.service->GetQueryCommand().c_str(),
source.Reply(CONFIRM_DROP, ci->name.c_str(), source.service->GetQueryCommand("chanserv/drop").c_str(),
ci->name.c_str(), code->c_str());
return;
}
@@ -88,16 +88,28 @@ public:
this->SendSyntax(source);
source.Reply(" ");
if (source.IsServicesOper())
source.Reply(_("Unregisters the specified channel. Only \002Services Operators\002\n"
"can drop a channel of which they are not the founder of."));
{
source.Reply(_(
"Unregisters the specified channel. Only \002Services Operators\002 "
"can drop a channel of which they are not the founder of."
));
}
else
source.Reply(_("Unregisters the named channel. Can only be used by\n"
"the \002channel founder\002."));
{
source.Reply(_(
"Unregisters the named channel. Can only be used by "
"the \002channel founder\002."
));
}
source.Reply(" ");
if (source.HasPriv("chanserv/drop/override"))
source.Reply(_("Additionally, Services Operators with the \037chanserv/drop/override\037 permission can\n"
"replace \037code\037 with \002OVERRIDE\002 to drop without a confirmation code."));
{
source.Reply(_(
"Additionally, Services Operators with the \037chanserv/drop/override\037 permission can "
"replace \037code\037 with \002OVERRIDE\002 to drop without a confirmation code."
));
}
return true;
}
};
+15 -13
View File
@@ -240,19 +240,21 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enforce various channel modes and set options. The \037channel\037\n"
"option indicates what channel to enforce the modes and options\n"
"on. The \037what\037 option indicates what modes and options to\n"
"enforce, and can be any of \002SECUREOPS\002, \002RESTRICTED\002, \002REGONLY\002, \002SSLONLY\002,\n"
"\002BANS\002, or \002LIMIT\002.\n"
" \n"
"Use \002SECUREOPS\002 to enforce the SECUREOPS option, even if it is not\n"
"enabled. Use \002RESTRICTED\002 to enforce the RESTRICTED option, also\n"
"if it's not enabled. Use \002REGONLY\002 to kick all unregistered users\n"
"from the channel. Use \002SSLONLY\002 to kick all users not using a secure\n"
"connection from the channel. \002BANS\002 will enforce bans on the channel by\n"
"kicking users affected by them, and \002LIMIT\002 will kick users until the\n"
"user count drops below the channel limit, if one is set."));
source.Reply(_(
"Enforce various channel modes and set options. The \037channel\037 "
"option indicates what channel to enforce the modes and options "
"on. The \037what\037 option indicates what modes and options to "
"enforce, and can be any of \002SECUREOPS\002, \002RESTRICTED\002, \002REGONLY\002, \002SSLONLY\002, "
"\002BANS\002, or \002LIMIT\002."
"\n\n"
"Use \002SECUREOPS\002 to enforce the SECUREOPS option, even if it is not "
"enabled. Use \002RESTRICTED\002 to enforce the RESTRICTED option, also "
"if it's not enabled. Use \002REGONLY\002 to kick all unregistered users "
"from the channel. Use \002SSLONLY\002 to kick all users not using a secure "
"connection from the channel. \002BANS\002 will enforce bans on the channel by "
"kicking users affected by them, and \002LIMIT\002 will kick users until the "
"user count drops below the channel limit, if one is set."
));
return true;
}
};
+50 -33
View File
@@ -10,7 +10,7 @@
*/
#include "module.h"
#include "modules/cs_entrymsg.h"
#include "modules/chanserv/entrymsg.h"
struct EntryMsgImpl final
: EntryMsg
@@ -29,16 +29,26 @@ struct EntryMsgImpl final
}
~EntryMsgImpl() override;
};
void Serialize(Serialize::Data &data) const override
struct EntryMsgTypeImpl final
: Serialize::Type
{
EntryMsgTypeImpl()
: Serialize::Type("EntryMsg")
{
data.Store("ci", this->chan);
data.Store("creator", this->creator);
data.Store("message", this->message);
data.Store("when", this->when);
}
static Serializable *Unserialize(Serializable *obj, Serialize::Data &data);
void Serialize(const Serializable *obj, Serialize::Data &data) const override
{
const auto *msg = static_cast<const EntryMsgImpl *>(obj);
data.Store("ci", msg->chan);
data.Store("creator", msg->creator);
data.Store("message", msg->message);
data.Store("when", msg->when);
}
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
struct EntryMessageListImpl final
@@ -68,7 +78,7 @@ EntryMsgImpl::~EntryMsgImpl()
}
Serializable *EntryMsgImpl::Unserialize(Serializable *obj, Serialize::Data &data)
Serializable *EntryMsgTypeImpl::Unserialize(Serializable *obj, Serialize::Data &data) const
{
Anope::string sci, screator, smessage;
time_t swhen;
@@ -142,7 +152,7 @@ private:
{
EntryMessageList *messages = ci->Require<EntryMessageList>("entrymsg");
if ((*messages)->size() >= Config->GetModule(this->owner)->Get<unsigned>("maxentries"))
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());
else
{
@@ -235,26 +245,32 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Controls what messages will be sent to users when they join the channel."));
source.Reply(" ");
source.Reply(_("The \002ENTRYMSG ADD\002 command adds the given message to\n"
"the list of messages shown to users when they join\n"
"the channel."));
source.Reply(" ");
source.Reply(_("The \002ENTRYMSG DEL\002 command removes the specified message from\n"
"the list of messages shown to users when they join\n"
"the channel. You can remove a message by specifying its number\n"
"which you can get by listing the messages as explained below."));
source.Reply(" ");
source.Reply(_("The \002ENTRYMSG LIST\002 command displays a listing of messages\n"
"shown to users when they join the channel."));
source.Reply(" ");
source.Reply(_("The \002ENTRYMSG CLEAR\002 command clears all entries from\n"
"the list of messages shown to users when they join\n"
"the channel, effectively disabling entry messages."));
source.Reply(" ");
source.Reply(_("Adding, deleting, or clearing entry messages requires the\n"
"SET permission."));
source.Reply(_(
"Controls what messages will be sent to users when they join the channel."
"\n\n"
"The \002%s\032ADD\002 command adds the given message to "
"the list of messages shown to users when they join "
"the channel."
"\n\n"
"The \002%s\032DEL\002 command removes the specified message from "
"the list of messages shown to users when they join "
"the channel. You can remove a message by specifying its number "
"which you can get by listing the messages as explained below."
"\n\n"
"The \002%s\032LIST\002 command displays a listing of messages "
"shown to users when they join the channel."
"\n\n"
"The \002%s\032CLEAR\002 command clears all entries from "
"the list of messages shown to users when they join "
"the channel, effectively disabling entry messages."
"\n\n"
"Adding, deleting, or clearing entry messages requires the "
"SET permission."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
@@ -264,12 +280,13 @@ class CSEntryMessage final
{
CommandEntryMessage commandentrymsg;
ExtensibleItem<EntryMessageListImpl> eml;
Serialize::Type entrymsg_type;
EntryMsgTypeImpl entrymsg_type;
public:
CSEntryMessage(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
commandentrymsg(this),
eml(this, "entrymsg"), entrymsg_type("EntryMsg", EntryMsgImpl::Unserialize)
CSEntryMessage(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandentrymsg(this)
, eml(this, "entrymsg")
{
}
+3 -3
View File
@@ -77,10 +77,10 @@ public:
}
void OnReload(Configuration::Conf *conf) override
void OnReload(Configuration::Conf &conf) override
{
prefix = conf->GetModule("chanstats")->Get<const Anope::string>("prefix", "anope_");
this->sql = ServiceReference<SQL::Provider>("SQL::Provider", conf->GetModule("chanstats")->Get<const Anope::string>("engine"));
prefix = conf.GetModule("chanstats").Get<const Anope::string>("prefix", "anope_");
this->sql = ServiceReference<SQL::Provider>("SQL::Provider", conf.GetModule("chanstats").Get<const Anope::string>("engine"));
}
SQL::Result RunQuery(const SQL::Query &query)
+3 -3
View File
@@ -104,10 +104,10 @@ public:
}
void OnReload(Configuration::Conf *conf) override
void OnReload(Configuration::Conf &conf) override
{
prefix = conf->GetModule("chanstats")->Get<const Anope::string>("prefix", "anope_");
this->sql = ServiceReference<SQL::Provider>("SQL::Provider", conf->GetModule("chanstats")->Get<const Anope::string>("engine"));
prefix = conf.GetModule("chanstats").Get<const Anope::string>("prefix", "anope_");
this->sql = ServiceReference<SQL::Provider>("SQL::Provider", conf.GetModule("chanstats").Get<const Anope::string>("engine"));
}
SQL::Result RunQuery(const SQL::Query &query)
+29 -26
View File
@@ -93,7 +93,7 @@ class CommandCSFlags final
if (IRCD->IsChannelValid(mask))
{
if (Config->GetModule("chanserv")->Get<bool>("disallow_channel_access"))
if (Config->GetModule("chanserv").Get<bool>("disallow_channel_access"))
{
source.Reply(_("Channels may not be on access lists."));
return;
@@ -116,7 +116,7 @@ class CommandCSFlags final
else
{
na = NickAlias::Find(mask);
if (!na && Config->GetModule("chanserv")->Get<bool>("disallow_hostmask_access"))
if (!na && Config->GetModule("chanserv").Get<bool>("disallow_hostmask_access"))
{
source.Reply(_("Masks and unregistered users may not be on access lists."));
return;
@@ -179,7 +179,7 @@ class CommandCSFlags final
}
}
unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1000");
unsigned access_max = Config->GetModule("chanserv").Get<unsigned>("accessmax", "1000");
if (access_max && ci->GetDeepAccessCount() >= access_max)
{
source.Reply(_("Sorry, you can only have %d access entries on a channel, including access entries from other channels."), access_max);
@@ -444,24 +444,27 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("%s is another way to modify the channel access list, similar to\n"
"the XOP and ACCESS methods."), source.command.c_str());
source.Reply(" ");
source.Reply(_("The \002MODIFY\002 command allows you to modify the access list. If the mask is\n"
"not already on the access list it is added, then the changes are applied.\n"
"If the mask has no more flags, then the mask is removed from the access list.\n"
"Additionally, you may use +* or -* to add or remove all flags, respectively. You are\n"
"only able to modify the access list if you have the proper permission on the channel,\n"
"and even then you can only give other people access to the equivalent of what your access is."));
source.Reply(" ");
source.Reply(_("The \002LIST\002 command allows you to list existing entries on the channel access list.\n"
"If a mask is given, the mask is wildcard matched against all existing entries on the\n"
"access list, and only those entries are returned. If a set of flags is given, only those\n"
"on the access list with the specified flags are returned."));
source.Reply(" ");
source.Reply(_("The \002CLEAR\002 command clears the channel access list. This requires channel founder access."));
source.Reply(" ");
source.Reply(_("The available flags are:"));
source.Reply(_(
"%s is another way to modify the channel access list, similar to "
"the XOP and ACCESS methods."
"\n\n"
"The \002MODIFY\002 command allows you to modify the access list. If the mask is "
"not already on the access list it is added, then the changes are applied. "
"If the mask has no more flags, then the mask is removed from the access list. "
"Additionally, you may use +* or -* to add or remove all flags, respectively. You are "
"only able to modify the access list if you have the proper permission on the channel, "
"and even then you can only give other people access to the equivalent of what your access is."
"\n\n"
"The \002LIST\002 command allows you to list existing entries on the channel access list. "
"If a mask is given, the mask is wildcard matched against all existing entries on the "
"access list, and only those entries are returned. If a set of flags is given, only those "
"on the access list with the specified flags are returned."
"\n\n"
"The \002CLEAR\002 command clears the channel access list. This requires channel founder access."
"\n\n"
"The available flags are:"
),
source.command.nobreak().c_str());
typedef std::multimap<char, Anope::string, ci::less> reverse_map;
reverse_map reverse;
@@ -494,21 +497,21 @@ public:
}
void OnReload(Configuration::Conf *conf) override
void OnReload(Configuration::Conf &conf) override
{
defaultFlags.clear();
for (int i = 0; i < conf->CountBlock("privilege"); ++i)
for (int i = 0; i < conf.CountBlock("privilege"); ++i)
{
Configuration::Block *priv = conf->GetBlock("privilege", i);
const auto &priv = conf.GetBlock("privilege", i);
const Anope::string &pname = priv->Get<const Anope::string>("name");
const Anope::string &pname = priv.Get<const Anope::string>("name");
Privilege *p = PrivilegeManager::FindPrivilege(pname);
if (p == NULL)
continue;
const Anope::string &value = priv->Get<const Anope::string>("flag");
const Anope::string &value = priv.Get<const Anope::string>("flag");
if (value.empty())
continue;
+9 -7
View File
@@ -53,7 +53,7 @@ public:
if (!ci->desc.empty())
info[_("Description")] = ci->desc;
info[_("Registered")] = Anope::strftime(ci->time_registered, source.GetAccount());
info[_("Registered")] = Anope::strftime(ci->registered, source.GetAccount());
info[_("Last used")] = Anope::strftime(ci->last_used, source.GetAccount());
if (show_all)
@@ -74,12 +74,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Lists information about the specified registered channel,\n"
"including its founder, time of registration, last\n"
"time used, and description. If the user issuing the\n"
"command has the appropriate access for it, then the\n"
"successor, last topic set, settings and expiration\n"
"time will also be displayed when applicable."));
source.Reply(_(
"Lists information about the specified registered channel, "
"including its founder, time of registration, last "
"time used, and description. If the user issuing the "
"command has the appropriate access for it, then the "
"successor, last topic set, settings and expiration "
"time will also be displayed when applicable."
));
return true;
}
};
+8 -5
View File
@@ -89,11 +89,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Tells %s to invite you or an optionally specified\n"
"nick into the given channel.\n"
" \n"
"By default, limited to AOPs or those with level 5 access and above\n"
"on the channel."), source.service->nick.c_str());
source.Reply(_(
"Tells %s to invite you or an optionally specified "
"nick into the given channel."
"\n\n"
"By default, limited to AOPs or those with level 5 access and above "
"on the channel."
),
source.service->nick.c_str());
return true;
}
};
+16 -9
View File
@@ -44,12 +44,11 @@ public:
return;
}
unsigned reasonmax = Config->GetModule("chanserv")->Get<unsigned>("reasonmax", "200");
unsigned reasonmax = Config->GetModule("chanserv").Get<unsigned>("reasonmax", "200");
if (reason.length() > reasonmax)
reason = reason.substr(0, reasonmax);
Anope::string signkickformat = Config->GetModule("chanserv")->Get<Anope::string>("signkickformat", "%m (%n)");
signkickformat = signkickformat.replace_all_cs("%n", source.GetNick());
auto signkickformat = Config->GetModule("chanserv").Get<Anope::string>("signkickformat", "{message} ({nick})");
AccessGroup u_access = source.AccessFor(ci);
@@ -71,7 +70,10 @@ public:
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
{
signkickformat = signkickformat.replace_all_cs("%m", reason);
signkickformat = Anope::Template(signkickformat, {
{ "message", reason },
{ "nick", source.GetNick() },
});
c->Kick(ci->WhoSends(), u2, signkickformat);
}
else
@@ -105,7 +107,10 @@ public:
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
{
reason += " (Matches " + mask + ")";
signkickformat = signkickformat.replace_all_cs("%m", reason);
signkickformat = Anope::Template(signkickformat, {
{ "message", reason },
{ "nick", source.GetNick() },
});
c->Kick(ci->WhoSends(), uc->user, signkickformat);
}
else
@@ -126,10 +131,12 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Kicks a specified nick from a channel.\n"
" \n"
"By default, limited to AOPs or those with level 5 access\n"
"and above on the channel. Channel founders can also specify masks."));
source.Reply(_(
"Kicks a specified nick from a channel."
"\n\n"
"By default, limited to AOPs or those with level 5 access "
"and above on the channel. Channel founders can also specify masks."
));
return true;
}
};
+44 -35
View File
@@ -10,7 +10,7 @@
*/
#include "module.h"
#include "modules/cs_mode.h"
#include "modules/chanserv/mode.h"
class CommandCSList final
: public Command
@@ -42,8 +42,10 @@ public:
if (!num1.has_value() || !num2.has_value())
{
source.Reply(LIST_INCORRECT_RANGE);
source.Reply(_("To search for channels starting with #, search for the channel\n"
"name without the #-sign prepended (\002anope\002 instead of \002#anope\002)."));
source.Reply(_(
"To search for channels starting with #, search for the channel "
"name without the #-sign prepended (\002anope\002 instead of \002#anope\002)."
));
return;
}
@@ -68,7 +70,7 @@ public:
}
Anope::string spattern = "#" + pattern;
unsigned listmax = Config->GetModule(this->owner)->Get<unsigned>("listmax", "50");
unsigned listmax = Config->GetModule(this->owner).Get<unsigned>("listmax", "50");
source.Reply(_("List of entries matching \002%s\002:"), pattern.c_str());
@@ -133,38 +135,43 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Lists all registered channels matching the given pattern.\n"
"Channels with the \002PRIVATE\002 option set will only be\n"
"displayed to Services Operators with the proper access.\n"
"Channels with the \002NOEXPIRE\002 option set will have\n"
"a \002!\002 prefixed to the channel for Services Operators to see.\n"
" \n"
"Note that a preceding '#' specifies a range, channel names\n"
"are to be written without '#'.\n"
" \n"
"If the SUSPENDED or NOEXPIRE options are given, only channels\n"
"which, respectively, are SUSPENDED or have the NOEXPIRE\n"
"flag set will be displayed. If multiple options are given,\n"
"all channels matching at least one option will be displayed.\n"
"Note that these options are limited to \037Services Operators\037.\n"
" \n"
"Examples:\n"
" \n"
" \002LIST *anope*\002\n"
" Lists all registered channels with \002anope\002 in their\n"
" names (case insensitive).\n"
" \n"
" \002LIST * NOEXPIRE\002\n"
" Lists all registered channels which have been set to not expire.\n"
" \n"
" \002LIST #51-100\002\n"
" Lists all registered channels within the given range (51-100)."));
source.Reply(_(
"Lists all registered channels matching the given pattern. "
"Channels with the \002PRIVATE\002 option set will only be "
"displayed to Services Operators with the proper access. "
"Channels with the \002NOEXPIRE\002 option set will have "
"a \002!\002 prefixed to the channel for Services Operators to see."
"\n\n"
"Note that a preceding '#' specifies a range, channel names "
"are to be written without '#'."
"\n\n"
"If the SUSPENDED or NOEXPIRE options are given, only channels "
"which, respectively, are SUSPENDED or have the NOEXPIRE "
"flag set will be displayed. If multiple options are given, "
"all channels matching at least one option will be displayed. "
"Note that these options are limited to \037Services Operators\037."
"\n\n"
"Examples:"
"\n\n"
" \002LIST\032*anope*\002\n"
" Lists all registered channels with \002anope\002 in their\n"
" names (case insensitive)."
"\n\n"
" \002LIST\032*\032NOEXPIRE\002\n"
" Lists all registered channels which have been set to not expire."
"\n\n"
" \002LIST #51-100\002\n"
" Lists all registered channels within the given range (51-100)."
));
if (!Config->GetBlock("options")->Get<const Anope::string>("regexengine").empty())
if (!Config->GetBlock("options").Get<const Anope::string>("regexengine").empty())
{
source.Reply(" ");
source.Reply(_("Regex matches are also supported using the %s engine.\n"
"Enclose your pattern in // if this is desired."), Config->GetBlock("options")->Get<const Anope::string>("regexengine").c_str());
source.Reply(_(
"Regex matches are also supported using the %s engine. "
"Enclose your pattern in // if this is desired."
),
Config->GetBlock("options").Get<const Anope::string>("regexengine").c_str());
}
return true;
@@ -234,8 +241,10 @@ public:
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());
{
source.Reply(_("When \002private\002 is set, the channel will not appear in %s's %s command."),
bi->nick.c_str(), cmd.c_str());
}
return true;
}
};
+57 -42
View File
@@ -10,7 +10,7 @@
*/
#include "module.h"
#include "modules/cs_log.h"
#include "modules/chanserv/log.h"
struct LogSettingImpl final
: LogSetting
@@ -34,20 +34,30 @@ struct LogSettingImpl final
}
}
}
};
void Serialize(Serialize::Data &data) const override
struct LogSettingTypeImpl final
: Serialize::Type
{
LogSettingTypeImpl()
: Serialize::Type("LogSetting")
{
data.Store("ci", chan);
data.Store("service_name", service_name);
data.Store("command_service", command_service);
data.Store("command_name", command_name);
data.Store("method", method);
data.Store("extra", extra);
data.Store("creator", creator);
data.Store("created", created);
}
static Serializable *Unserialize(Serializable *obj, Serialize::Data &data)
void Serialize(const Serializable *obj, Serialize::Data &data) const override
{
const auto *ls = static_cast<const LogSettingImpl *>(obj);
data.Store("ci", ls->chan);
data.Store("service_name", ls->service_name);
data.Store("command_service", ls->command_service);
data.Store("command_name", ls->command_name);
data.Store("method", ls->method);
data.Store("extra", ls->extra);
data.Store("creator", ls->creator);
data.Store("created", ls->created);
}
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override
{
Anope::string sci;
data["ci"] >> sci;
@@ -261,26 +271,30 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("The %s command allows users to configure logging settings\n"
"for their channel. If no parameters are given this command\n"
"lists the current logging methods in place for this channel.\n"
" \n"
"Otherwise, \037command\037 must be a command name, and \037method\037\n"
"is one of the following logging methods:\n"
" \n"
" MESSAGE [status], NOTICE [status], MEMO\n"
" \n"
"Which are used to message, notice, and memo the channel respectively.\n"
"With MESSAGE or NOTICE you must have a service bot assigned to and joined\n"
"to your channel. Status may be a channel status such as @ or +.\n"
" \n"
"To remove a logging method use the same syntax as you would to add it.\n"
" \n"
source.Reply(_(
"The %s command allows users to configure logging settings "
"for their channel. If no parameters are given this command "
"lists the current logging methods in place for this channel."
"\n\n"
"Otherwise, \037command\037 must be a command name, and \037method\037 "
"is one of the following logging methods:"
"\n\n"
" MESSAGE\032[status], NOTICE\032[status], MEMO"
"\n\n"
"Which are used to message, notice, and memo the channel respectively. "
"With MESSAGE or NOTICE you must have a service bot assigned to and joined "
"to your channel. Status may be a channel status such as @ or +."
"\n\n"
"To remove a logging method use the same syntax as you would to add it."
"\n\n"
"Example:\n"
" %s #anope chanserv/access MESSAGE @\n"
" Would message any channel operators whenever someone used the\n"
" ACCESS command on ChanServ on the channel."),
source.command.upper().c_str(), source.command.upper().c_str());
" %s\032#anope\032chanserv/access\032MESSAGE\032@\n"
" Would message any channel operators whenever someone used the "
"ACCESS command on ChanServ on the channel."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
@@ -291,7 +305,7 @@ class CSLog final
ServiceReference<MemoServService> MSService;
CommandCSLog commandcslog;
ExtensibleItem<LogSettingsImpl> logsettings;
Serialize::Type logsetting_type;
LogSettingTypeImpl logsetting_type;
struct LogDefault final
{
@@ -301,27 +315,28 @@ class CSLog final
std::vector<LogDefault> defaults;
public:
CSLog(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
MSService("MemoServService", "MemoServ"), commandcslog(this),
logsettings(this, "logsettings"), logsetting_type("LogSetting", LogSettingImpl::Unserialize)
CSLog(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, MSService("MemoServService", "MemoServ")
, commandcslog(this)
, logsettings(this, "logsettings")
{
}
void OnReload(Configuration::Conf *conf) override
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block *block = conf->GetModule(this);
const auto &block = conf.GetModule(this);
defaults.clear();
for (int i = 0; i < block->CountBlock("default"); ++i)
for (int i = 0; i < block.CountBlock("default"); ++i)
{
Configuration::Block *def = block->GetBlock("default", i);
const auto &def = block.GetBlock("default", i);
LogDefault ld;
ld.service = def->Get<const Anope::string>("service");
ld.command = def->Get<const Anope::string>("command");
ld.method = def->Get<const Anope::string>("method");
ld.service = def.Get<const Anope::string>("service");
ld.command = def.Get<const Anope::string>("command");
ld.method = def.Get<const Anope::string>("method");
defaults.push_back(ld);
}
+76 -55
View File
@@ -10,7 +10,7 @@
*/
#include "module.h"
#include "modules/cs_mode.h"
#include "modules/chanserv/mode.h"
struct ModeLockImpl final
: ModeLock
@@ -30,9 +30,17 @@ struct ModeLockImpl final
ml->RemoveMLock(this);
}
}
};
void Serialize(Serialize::Data &data) const override;
static Serializable *Unserialize(Serializable *obj, Serialize::Data &data);
struct ModeLockTypeImpl final
: Serialize::Type
{
ModeLockTypeImpl()
: Serialize::Type("ModeLock")
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
struct ModeLocksImpl final
@@ -203,17 +211,18 @@ struct ModeLocksImpl final
}
};
void ModeLockImpl::Serialize(Serialize::Data &data) const
void ModeLockTypeImpl::Serialize(const Serializable *obj, Serialize::Data &data) const
{
data.Store("ci", this->ci);
data.Store("set", this->set);
data.Store("name", this->name);
data.Store("param", this->param);
data.Store("setter", this->setter);
data.Store("created", this->created);
const auto *ml = static_cast<const ModeLockImpl *>(obj);
data.Store("ci", ml->ci);
data.Store("set", ml->set);
data.Store("name", ml->name);
data.Store("param", ml->param);
data.Store("setter", ml->setter);
data.Store("created", ml->created);
}
Serializable *ModeLockImpl::Unserialize(Serializable *obj, Serialize::Data &data)
Serializable *ModeLockTypeImpl::Unserialize(Serializable *obj, Serialize::Data &data) const
{
Anope::string sci;
@@ -336,7 +345,7 @@ class CommandCSMode final
continue;
}
if (modelocks->GetMLock().size() >= Config->GetModule(this->owner)->Get<unsigned>("max", "50"))
if (modelocks->GetMLock().size() >= Config->GetModule(this->owner).Get<unsigned>("max", "50"))
{
source.Reply(_("The mode lock list of \002%s\002 is full."), ci->name.c_str());
continue;
@@ -765,29 +774,39 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Mainly controls mode locks and mode access (which is different from channel access)\n"
"on a channel.\n"
" \n"
"The \002%s LOCK\002 command allows you to add, delete, and view mode locks on a channel.\n"
"If a mode is locked on or off, services will not allow that mode to be changed. The \002SET\002\n"
"command will clear all existing mode locks and set the new one given, while \002ADD\002 and \002DEL\002\n"
"modify the existing mode lock.\n"
"Example:\n"
" \002MODE #channel LOCK ADD +bmnt *!*@*aol*\002\n"
" \n"
"The \002%s SET\002 command allows you to set modes through services. Wildcards * and ? may\n"
"be given as parameters for list and status modes.\n"
"Example:\n"
" \002MODE #channel SET +v *\002\n"
" Sets voice status to all users in the channel.\n"
" \n"
" \002MODE #channel SET -b ~c:*\n"
" Clears all extended bans that start with ~c:\n"
" \n"
"The \002%s CLEAR\002 command is an easy way to clear modes on a channel. \037what\037 may be\n"
"any mode name. Examples include bans, excepts, inviteoverrides, ops, halfops, and voices. If \037what\037\n"
"is not given then all basic modes are removed."),
source.command.upper().c_str(), source.command.upper().c_str(), source.command.upper().c_str());
source.Reply(_(
"Mainly controls mode locks and mode access (which is different from channel access) "
"on a channel."
"\n\n"
"The \002%s\032LOCK\002 command allows you to add, delete, and view mode locks on a channel. "
"If a mode is locked on or off, services will not allow that mode to be changed. The \002SET\002 "
"command will clear all existing mode locks and set the new one given, while \002ADD\002 and \002DEL\002 "
"modify the existing mode lock."
"\n\n"
"Example:\n"
" \002%s\032#channel\032%s\032ADD\032+bmnt\032*!*@*aol*\002\n"
"\n\n"
"The \002%s\032SET\002 command allows you to set modes through services. Wildcards * and ? may "
"be given as parameters for list and status modes."
"\n\n"
"Example:\n"
" \002%s\032#channel\032SET\032+v\032*\002\n"
" Sets voice status to all users in the channel."
"\n\n"
" \002%s\032#channel\032SET\032-b\032~c:*\n"
" Clears all extended bans that start with ~c:"
"\n\n"
"The \002%s\032CLEAR\002 command is an easy way to clear modes on a channel. \037what\037 may be "
"any mode name. Examples include bans, excepts, inviteoverrides, ops, halfops, and voices. If \037what\037 "
"is not given then all basic modes are removed."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
@@ -915,13 +934,15 @@ public:
this->SendSyntax(source);
source.Reply(" ");
if (m.first)
source.Reply(_("Gives %s status to the selected nicks on a channel. If \037nick\037 is\n"
"not given, it will %s you."),
m.second.upper().c_str(), m.second.lower().c_str());
{
source.Reply(_("Gives %s status to the selected nicks on a channel. If \037nick\037 is not given, it will %s you."),
m.second.upper().c_str(), m.second.lower().c_str());
}
else
source.Reply(_("Removes %s status from the selected nicks on a channel. If \037nick\037 is\n"
"not given, it will de%s you."),
m.second.upper().c_str(), m.second.lower().c_str());
{
source.Reply(_("Removes %s status from the selected nicks on a channel. If \037nick\037 is not given, it will de%s you."),
m.second.upper().c_str(), m.second.lower().c_str());
}
source.Reply(" ");
source.Reply(_("You must have the %s(ME) privilege on the channel to use this command."), m.second.upper().c_str());
@@ -935,33 +956,33 @@ class CSMode final
CommandCSMode commandcsmode;
CommandCSModes commandcsmodes;
ExtensibleItem<ModeLocksImpl> modelocks;
Serialize::Type modelocks_type;
ModeLockTypeImpl modelocks_type;
public:
CSMode(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
commandcsmode(this), commandcsmodes(this),
modelocks(this, "modelocks"),
modelocks_type("ModeLock", ModeLockImpl::Unserialize)
CSMode(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandcsmode(this)
, commandcsmodes(this)
, modelocks(this, "modelocks")
{
}
void OnReload(Configuration::Conf *conf) override
void OnReload(Configuration::Conf &conf) override
{
modes.clear();
for (int i = 0; i < conf->CountBlock("command"); ++i)
for (int i = 0; i < conf.CountBlock("command"); ++i)
{
Configuration::Block *block = conf->GetBlock("command", i);
const auto &block = conf.GetBlock("command", i);
const Anope::string &cname = block->Get<const Anope::string>("name"),
&cmd = block->Get<const Anope::string>("command");
const Anope::string &cname = block.Get<const Anope::string>("name"),
&cmd = block.Get<const Anope::string>("command");
if (cname.empty() || cmd != "chanserv/modes")
continue;
const Anope::string &set = block->Get<const Anope::string>("set"),
&unset = block->Get<const Anope::string>("unset");
const Anope::string &set = block.Get<const Anope::string>("set"),
&unset = block.Get<const Anope::string>("unset");
if (set.empty() && unset.empty())
continue;
@@ -1024,7 +1045,7 @@ public:
{
ModeLocks *ml = modelocks.Require(ci);
Anope::string mlock;
spacesepstream sep(Config->GetModule(this)->Get<const Anope::string>("mlock", "+nt"));
spacesepstream sep(Config->GetModule(this).Get<const Anope::string>("mlock", "+nt"));
if (sep.GetToken(mlock))
{
bool add = true;
+32 -19
View File
@@ -25,7 +25,7 @@ public:
{
const Anope::string &chan = params[0];
const Anope::string &chdesc = params.size() > 1 ? params[1] : "";
unsigned maxregistered = Config->GetModule("chanserv")->Get<unsigned>("maxregistered");
unsigned maxregistered = Config->GetModule("chanserv").Get<unsigned>("maxregistered");
User *u = source.GetUser();
NickCore *nc = source.nc;
@@ -84,28 +84,41 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Registers a channel in the %s database. In order\n"
"to use this command, you must first be a channel operator\n"
"on the channel you're trying to register.\n"
"The description, which is optional, is a\n"
"general description of the channel's purpose.\n"
" \n"
"When you register a channel, you are recorded as the\n"
"\"founder\" of the channel. The channel founder is allowed\n"
"to change all of the channel settings for the channel;\n"
"%s will also automatically give the founder\n"
"channel operator privileges when they enter the channel."),
source.service->nick.c_str(), source.service->nick.c_str());
source.Reply(_(
"Registers a channel in the %s database. In order "
"to use this command, you must first be a channel operator "
"on the channel you're trying to register. "
"The description, which is optional, is a "
"general description of the channel's purpose. "
"\n\n"
"When you register a channel, you are recorded as the "
"\"founder\" of the channel. The channel founder is allowed "
"to change all of the channel settings for the channel; "
"%s will also automatically give the founder "
"channel operator privileges when they enter the channel."
),
source.service->nick.c_str(),
source.service->nick.c_str());
BotInfo *bi;
Anope::string cmd;
if (Command::FindCommandFromService("chanserv/access", bi, cmd))
source.Reply(_(" \n"
"See the \002%s\002 command (\002%s HELP ACCESS\002) for\n"
"information on giving a subset of these privileges to\n"
"other channel users.\n"), cmd.c_str(), bi->GetQueryCommand().c_str());
source.Reply(_(" \n"
"NOTICE: In order to register a channel, you must have\n"
{
source.Reply(" ");
source.Reply(_(
"See the \002%s\002 command (\002%s\032ACCESS\002) for "
"information on giving a subset of these privileges to "
"other channel users."
),
cmd.c_str(),
bi->GetQueryCommand("generic/help").c_str());
}
source.Reply(" ");
source.Reply(_(
"NOTICE: In order to register a channel, you must have "
"first registered your nickname."));
return true;
}
};

Some files were not shown because too many files have changed in this diff Show More