1
0
mirror of https://github.com/anope/anope.git synced 2026-06-16 23:54:46 +02:00

Compare commits

...

229 Commits

Author SHA1 Message Date
Sadie Powell da799bd6f1 Release 2.1.18. 2025-10-01 11:07:16 +01:00
Sadie Powell 4dada51e08 Sort options in the information formatter output. 2025-09-29 13:00:17 +01:00
Sadie Powell 1275fd01a7 Fix a missing command description in hs_request. 2025-09-28 14:58:35 +01:00
Sadie Powell 5b8018eb80 Update the change logs. 2025-09-27 20:33:21 +01:00
Sadie Powell b2026fe739 Fix various stupid mistakes in nickserv/confirm/register. 2025-09-27 18:12:34 +01:00
Sadie Powell 3390d82ebe Log the fingerprint used to authenticate in ns_cert. 2025-09-26 11:22:20 +01:00
Sadie Powell 4762e306f9 Default to code registration confirmation. 2025-09-23 18:23:12 +01:00
Sadie Powell fd759f7bd3 Fix a minor comment typo in Anope::Template. 2025-09-23 18:18:52 +01:00
Sadie Powell 003ddde09d Improve the services.host define documentation. 2025-09-23 18:18:52 +01:00
Sadie Powell c021d7134e Tweak the badwords documentation to document ALL. 2025-09-23 18:18:52 +01:00
Sadie Powell a792088a62 Add the monospace layout.
This works best in clients like The Lounge which use a variable-width
font but support monospace formatting.
2025-09-20 14:56:51 +01:00
Sadie Powell 03e2ebe2d2 Make LineWrapper UTF-8 aware. 2025-09-20 00:01:26 +01:00
Sadie Powell 0238f0a9e3 Move setting the display nickname to ns_group. 2025-09-19 21:30:52 +01:00
Sadie Powell c2dfb9a447 Use rounded durations in more places. 2025-09-19 20:38:53 +01:00
Sadie Powell bd8435a061 Add the reason to the regular version of operserv/session. 2025-09-19 20:38:53 +01:00
Sadie Powell 2cd67c9f36 Add a registration date column to nickserv/glist. 2025-09-19 20:38:53 +01:00
Sadie Powell 45ab094d63 Fix the case of the new SET LAYOUT command. 2025-09-19 19:25:57 +01:00
Sadie Powell 54389f474b Implement support for flexible table layouts. 2025-09-19 18:50:27 +01:00
Sadie Powell ac2b38b1b6 Fix a minor layout issue in cs_log. 2025-09-19 16:06:39 +01:00
Sadie Powell df551bee03 Fix the documentation of the ns_set_protect module. 2025-09-19 12:55:58 +01:00
Sadie Powell 59bb9d3d06 Rework the InfoFormatter/ListFormatter APIs and move to textproc. 2025-09-19 12:31:15 +01:00
Sadie Powell 3b2d798e76 Allow unprivileged users to use !help by default. 2025-09-19 11:41:02 +01:00
Sadie Powell ff6d6bdb3c Remove some now unused code. 2025-09-14 13:43:18 +01:00
Sadie Powell 411b3ce65a Update the en_US translation. 2025-09-12 15:44:42 +01:00
Sadie Powell ad19603818 Show the account id as part of the account field. 2025-09-12 15:44:24 +01:00
Sadie Powell 535ff9b839 Stop showing the last real name in the nick information output.
This isn't really used anymore and a lot of clients just set it to
a static string so it doesn't make sense to show it.
2025-09-12 15:33:00 +01:00
Sadie Powell 51916a50d2 Remove extraneous whitespace from the example configs. 2025-09-12 15:07:37 +01:00
Sadie Powell 42e58952cc Alias the old GETPASS command to RESETPASS. 2025-09-12 15:05:09 +01:00
Sadie Powell ba9f4e93c2 Redo how information tables are built to be multibyte aware. 2025-09-12 14:34:39 +01:00
Sadie Powell 679a313ae2 Add the utf8length method to Anope::string. 2025-09-12 14:21:39 +01:00
Sadie Powell 390975e6c4 Remove some duplicate code from ns_set. 2025-09-11 16:01:58 +01:00
Sadie Powell d631885495 Split autoop and neverop out into their own module. 2025-09-11 16:01:58 +01:00
Sadie Powell 8e337c6592 Fix printing the MySQL version when building against MariaDB. 2025-09-11 16:01:58 +01:00
Sadie Powell 9d89d8233d Modernize the ns_sasl_plain module slightly. 2025-09-10 12:30:45 +01:00
Sadie Powell 6f27418381 Fail an EXTERNAL auth attempt if the user has no client cert. 2025-09-08 15:13:57 +01:00
Sadie Powell 1932081c27 Modularise the supported SASL mechanisms. 2025-09-07 15:10:19 +01:00
Sadie Powell f73159159f Fix the name of the DNS record config option for the previous commit. 2025-09-06 17:48:46 +01:00
Sadie Powell eccb338cdd Add support for self-service vhost validation via DNS. 2025-09-06 17:46:01 +01:00
Sadie Powell 4021c0bb68 Fix looking up TXT records using the dns module. 2025-09-06 17:02:02 +01:00
Sadie Powell 7dfb40cb58 Update yyjson (for real this time). 2025-09-03 11:18:02 +01:00
dependabot[bot] 0fbd3095c4 Bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-02 10:50:15 +01:00
Sadie Powell 6d426ec386 Update yyjson. 2025-08-26 18:06:48 +01:00
Sadie Powell 1b33a51695 Update the Turkish translation.
Co-Authored-By: CaPa CuL <capacul@gmail.com>
2025-08-26 13:04:16 +01:00
Sadie Powell 168a1173ed Error out when db_json can't find the backup directory. 2025-08-25 20:01:02 +01:00
Sadie Powell 59c777d4ff Fix the pid check on systems with reliable pid ordering (e.g. Docker). 2025-08-25 18:40:19 +01:00
Sadie Powell 43f88524e2 Vendor utfcpp, use to fix alignment for non-ascii syntax messages. 2025-08-24 23:18:06 +01:00
Sadie Powell 04de41ad7f Fix some code which was supposed to be part of the previous commit. 2025-08-21 10:45:39 +01:00
Sadie Powell dd13846cad Allow a different badpasslimit for partially connected users.
Closes #455.
2025-08-21 10:12:13 +01:00
Sadie Powell 6864bc6171 Fix building on Windows. 2025-08-08 16:15:51 +01:00
Sadie Powell 003cb55409 Skip deprecated modules when checking for a database/encryption backend. 2025-08-08 14:12:56 +01:00
Sadie Powell d15b8ee949 Remove some dead code from enc_sha256. 2025-08-08 13:14:14 +01:00
Sadie Powell 70de2b7de2 Move B64{Decode,Encode} to textproc and redesign their interface. 2025-08-08 12:27:28 +01:00
Sadie Powell e5c5689985 Move Anope::Distance to textproc. 2025-08-08 12:09:42 +01:00
Sadie Powell 928d4260dc Allow db_flatfile to be loadable first to import databases. 2025-08-07 10:03:34 +01:00
Sadie Powell 5e8561a7f1 Add support for TXT and SRV records in the dns module. 2025-08-06 15:38:13 +01:00
Sadie Powell 4dd3075ddf Merge branch '2.0' into 2.1. 2025-08-05 17:26:29 +01:00
Sadie Powell dbef7a7c64 Don't try to write to a buffered socket if there's no data.
This can cause the SSL modules to act weirdly because the TLS
library will return 0 bytes written (correctly) which is then
interpreted as an error.
2025-08-05 13:10:16 +01:00
Sadie Powell cd0f00a819 Improve the error diagnostics when the link fails. 2025-08-03 13:15:14 +01:00
Sadie Powell b2d40d4189 Improve how Anope formats C strings. 2025-08-02 18:17:01 +01:00
Sadie Powell e6e812c43c Move NormalizeBuffer to textproc and rename more descriptively. 2025-08-02 17:09:24 +01:00
Sadie Powell 2dbd41d244 Move some methods to textproc. 2025-08-02 17:00:31 +01:00
Sadie Powell 02aeb254ee Add an option to disable the encryption and database module checks. 2025-08-01 13:57:47 +01:00
Sadie Powell 1245b43ade Require that users have a non-deprecated database module loaded. 2025-08-01 13:28:29 +01:00
Sadie Powell 5a3f9f3f87 Warn when a user loads a deprecated module. 2025-08-01 13:08:22 +01:00
Sadie Powell 2c6f4d7c27 Make db_flatfile import-only. 2025-08-01 12:41:27 +01:00
Sadie Powell 64f8449bf4 Banish db_old and enc_old to the shadow realm. 2025-08-01 12:41:27 +01:00
Sadie Powell 0e1f6b403b Bump for 2.1.18-git. 2025-08-01 12:22:21 +01:00
Sadie Powell 206192abdc Release 2.1.17. 2025-08-01 12:21:00 +01:00
Sadie Powell 32d3ddc0e4 Fix the grammar of two messages. 2025-07-30 15:30:44 +01:00
Sadie Powell 4410e5ccce Update the change logs. 2025-07-27 19:23:02 +01:00
Sadie Powell d5f2232140 Fix importing some older databases. 2025-07-27 15:42:32 +01:00
Sadie Powell 6d754b7d73 Add the intended target of the mode to CanSet. 2025-07-25 21:07:26 +01:00
Sadie Powell 4d2870fa45 Make it more clear that db_flatfile is deprecated. 2025-07-25 13:38:13 +01:00
Sadie Powell 5948c2ea53 Simplify the Windows module copying logic.
As far as I can tell from reading the Windows documentation there
is no reason to overcomplicate this so much.
2025-07-25 13:21:15 +01:00
Sadie Powell ace7d99797 Tweak the default ns_set_misc examples slightly.
- Discord is proprietary software so we shouldn't be encouraging
  its use. ;-)

- Time zone is going to be replaced by a future feature that allows
  users to get timestamps in their local time so I'm removing it
  now to prevent future conflict.

- Location is a good example of how this should be used for extra
  fields.
2025-07-25 12:53:47 +01:00
Sadie Powell 52595b90fa Rewrite nickserv/resend with some functionality improvements.
- Allow server operators to resend a confirmation email. Closes #518.
- Allow use of the command whilst unauthenticated.
2025-07-25 12:28:14 +01:00
Sadie Powell b39f002d1b Remove some unused files. 2025-07-21 19:14:34 +01:00
Sadie Powell 5df95d9f86 Remove a variant message which is only used in one place. 2025-07-12 16:33:14 +01:00
Sadie Powell a56d9a4096 Only show the last quit message if the user is not online. 2025-07-12 15:28:57 +01:00
Sadie Powell ce7bb15c18 Use IsIdentValid for validating usernames in hs_request. 2025-07-12 14:41:09 +01:00
Sadie Powell 6873630f2e Improve the "please identify" messages. 2025-07-08 16:24:16 +01:00
Sadie Powell 44a4d62654 Show the last real mask to services operators with nickserv/list. 2025-07-07 11:51:10 +01:00
Sadie Powell 97389cd105 Rename some fields to be more accurately named. 2025-07-07 11:51:10 +01:00
Sadie Powell 80c0adf7c8 Make a message consistent with others. 2025-07-02 14:08:04 +01:00
Sadie Powell 6a539277b9 Bump for 2.1.17-git. 2025-07-01 10:58:05 +01:00
Sadie Powell 9930fa01ac Release 2.1.16. 2025-07-01 10:56:40 +01:00
Sadie Powell 40929a0490 Update the change logs. 2025-07-01 10:13:36 +01:00
Sadie Powell 783be31f64 Update author list. 2025-07-01 09:48:19 +01:00
Sadie Powell 0f5f2aef2e Bump the minimum OpenSSL version to 1.1.1.
Close #517.
2025-07-01 00:00:55 +01:00
Sadie Powell 6cc997c4e9 When unsetting a temporary ban delete the unset timer.
This prevents Anope from unsetting a later-added ban,

Resolves MantisBT bug 1709.
2025-06-25 19:16:15 +01:00
Sadie Powell eda6d8cc0f Fix storing the setter of a list mode. 2025-06-25 19:10:49 +01:00
Sadie Powell 3440b38a21 Merge branch '2.0' into 2.1. 2025-06-25 17:50:01 +01:00
Sadie Powell fca421aa2a Fix resetpass confirming accounts when not using email confirmation.
Fixes MantisBT bug 1734.
2025-06-25 17:36:16 +01:00
Sadie Powell 035905d321 Fix example messages using .site which is a real TLD now. 2025-06-25 15:39:35 +01:00
Sadie Powell d1cd57d98e Resynchronise the en_US language file. 2025-06-25 15:34:01 +01:00
Sadie Powell 48daeeac1d Merge branch '2.0' into 2.1. 2025-06-25 15:33:36 +01:00
Sadie Powell 9bcf46f8ea Fix using service's instead of services' where appropriate. 2025-06-25 15:29:16 +01:00
Sadie Powell 0b6c7ce5d6 Update some messages for the language used by modern BIND versions. 2025-06-25 15:28:54 +01:00
Sadie Powell a0d21b207b Fix reading the purge time in cs_seen. 2025-06-25 14:08:44 +01:00
Sadie Powell 3cc5b5143f Remove the old 1.8-style seen system. 2025-06-25 14:06:59 +01:00
Sadie Powell da738126a4 Merge branch '2.0' into 2.1. 2025-06-25 12:07:36 +01:00
Sadie Powell 0bb1bc5c67 Backport various minor config changes from 2.1. 2025-06-25 12:00:33 +01:00
Sadie Powell 72010cd1a9 Fix messages that say IRC Operator when they mean Services Operator. 2025-06-24 13:58:47 +01:00
Sadie Powell c48b3af3d4 Remove an obsolete workaround from Config. 2025-06-24 09:29:33 +01:00
Sadie Powell 85c129701b Clarify how to migrate db_flatfile databases to db_json. 2025-06-23 23:39:20 +01:00
Sadie Powell a9e5a79e91 Remove some unused strings in os_news. 2025-06-22 15:45:21 +01:00
Sadie Powell adc1343d6c Serialize item types as strings instead of integers.
Using the type cast to an integer here was undefined behaviour.
2025-06-22 15:45:21 +01:00
Sadie Powell 8aa1102c7a Default to db_json. 2025-06-22 15:45:21 +01:00
TehPeGaSuS 1a89d32926 Document NS_STATS and CS_STATS. 2025-06-21 17:09:26 +01:00
Sadie Powell ad06853edf Fix suggesting unloaded commands in the "did you mean" message. 2025-06-21 09:56:02 +01:00
Sadie Powell 66ae20e0f2 Tweak a message to make it easier for ESL speakers to understand. 2025-06-21 09:48:01 +01:00
Sadie Powell 2850e3c65c Implement serializer hashing in db_json. 2025-06-21 00:31:02 +01:00
Sadie Powell 80b8856254 Consistently use "account" instead of "nick group". 2025-06-20 20:30:21 +01:00
Sadie Powell 21c8164539 When assigning a new display nick use the oldest not the first. 2025-06-20 20:27:39 +01:00
Sadie Powell a4abd27ffd Fix the grammar of a message in ns_confirm. 2025-06-20 19:43:02 +01:00
Sadie Powell b912b403f0 Fix a comment in CommandInfo. 2025-06-20 19:43:02 +01:00
Sadie Powell 59e9d47667 Update another message to use pluralisation. 2025-06-18 20:53:11 +01:00
Sadie Powell 1108e54250 We don't need to reserialize aliases now we use account identifiers. 2025-06-17 14:50:36 +01:00
Sadie Powell 8b37cdb5d5 Make the access description more useful when importing from Atheme. 2025-06-17 14:50:36 +01:00
Sadie Powell c5bff3a099 Fix various issues with language strings. 2025-06-16 12:30:42 +01:00
Sadie Powell 61b0c82884 Rework how confirmation works and make it modular. 2025-06-16 10:00:41 +01:00
Sadie Powell c4c159d197 Fix showing the MORE_INFO message. 2025-06-15 11:49:26 +01:00
Sadie Powell 04a32be1e1 Add support for code authentication via IRC.
This breaks spambots which try to register but that can't handle
reading the response from services.
2025-06-15 11:22:03 +01:00
Sadie Powell fe4b8ee669 When a command is missing in GetQueryCommand just return (MISSING). 2025-06-15 11:20:34 +01:00
Sadie Powell 34b451f36c The require_privilege option should default to yes not no. 2025-06-11 09:28:46 +01:00
Sadie Powell 16aff210fd Allow configuring fantasy commands to not require the FANTASY priv. 2025-06-10 16:05:11 +01:00
Sadie Powell 5702fb9145 Add a PREPEND subcommand to chanserv/topic. 2025-06-10 12:06:02 +01:00
Sadie Powell 783ba3fd74 Undocument DISCOURAGED; we do not use this anymore. 2025-06-08 16:21:08 +01:00
Sadie Powell f1ddd7cd02 Promote NickServ from OPTIONAL to RECOMMENDED.
Not sure why this wasn't already.
2025-06-08 16:09:43 +01:00
Sadie Powell c424c4d24d Document cs_statusupdate in the same way as other modules. 2025-06-08 12:22:45 +01:00
Sadie Powell 2d88383d9e Group some more chanserv commands. 2025-06-08 12:18:10 +01:00
Sadie Powell c73a6c621f Make the set_misc help format consistent with other set commands. 2025-06-07 13:27:30 +01:00
Sadie Powell 96a503b4d9 Fix a memory leak in the db_json module.
This reworks the module to store Data instead of a yyjson document
which does not free until yyjson_doc_free even if an array is cleared
(which annoyingly was only documented using a single comment in the
yyjson docs).
2025-06-05 22:01:45 +01:00
Sadie Powell 0632abd111 Banish irc2sql to the shadow realm. 2025-06-05 18:22:13 +01:00
TehPeGaSuS 1043e2189c Remove a reference to a config option that doesn't exist.
There's no `memoreceipt` anywhere, as far as I could check.
2025-06-01 15:29:35 +01:00
Sadie Powell 85f0d56c39 Bump for 2.1.16-git. 2025-06-01 10:14:44 +01:00
Sadie Powell cebc3f757b Release 2.1.15. 2025-06-01 10:13:49 +01:00
Sadie Powell 447a59d6f5 Update author list. 2025-06-01 10:06:05 +01:00
Sadie Powell 75aa633d87 Update yyjson. 2025-06-01 10:05:49 +01:00
Sadie Powell 7833a96dde Update the change logs. 2025-06-01 10:04:36 +01:00
Sadie Powell d326f869a3 Add the rpc_user module. 2025-06-01 09:50:29 +01:00
Sadie Powell b724617a8d Revert "Optimise the maths for the jsonrpc oversize integer workaround".
This reverts commit 937404e311.
2025-05-30 18:09:37 +01:00
Sadie Powell 76f0c78ece Remove some unused Windows code. 2025-05-30 14:43:54 +01:00
Sadie Powell 13491bd960 Add {nickserv}:enforcerreal and cache enforcer config on reload. 2025-05-29 17:36:28 +01:00
Sadie Powell bade5ea109 Tweak some help messages for consistency. 2025-05-29 16:46:55 +01:00
Sadie Powell 682a6a6ad4 Fix unsetting vhosts when cloaking isn't available on InspIRCd. 2025-05-29 15:46:31 +01:00
Sadie Powell 50030e07fa Make CTCP support more modular. 2025-05-27 15:30:09 +01:00
Sadie Powell 7b2f0f5790 Fix some trivial wrong types when getting config values. 2025-05-27 13:21:55 +01:00
Sadie Powell 23e72fc934 Convert Anope::Debug to an unsigned value. 2025-05-24 16:54:49 +01:00
Sadie Powell e182519e4d Fix using the wrong command name in the help module. 2025-05-24 15:20:47 +01:00
Sadie Powell 4317b5557e Redocument sendmailpath. 2025-05-23 23:18:12 +01:00
Sadie Powell f97448f48a Modernize some bits of Command. 2025-05-22 10:49:38 +01:00
Sadie Powell cb334fbae1 Remove the pidfile before restarting.
Fixes being unable to restart now we only allow one instance.
2025-05-17 20:04:41 +01:00
Sadie Powell d3bb930a5e Fix some inconsistencies with account lookups. 2025-05-17 19:35:03 +01:00
Sadie Powell 0fc1eb3133 Rename one last use of time_registered. 2025-05-17 15:05:13 +01:00
Sadie Powell 0ac9d70d63 Update the change logs. 2025-05-16 17:07:03 +01:00
Sadie Powell a3d61e3d18 Rename id to uniqueid to avoid shadowing. 2025-05-16 15:23:09 +01:00
Sadie Powell cac10aaa41 Always store a unique identifier in the database. 2025-05-16 15:18:24 +01:00
Sadie Powell be5a0e8108 Serialize using mutable objects not immutable ones. 2025-05-16 15:18:00 +01:00
Sadie Powell 3da8244de5 Log any startup error to the terminal. 2025-05-16 15:15:42 +01:00
Sadie Powell 8722daa6e7 Only allow one instance of Anope at once. 2025-05-16 15:15:30 +01:00
Sadie Powell a0e98acea8 Fix the codelength default. 2025-05-15 01:42:13 +01:00
Sadie Powell c5a2f40666 Move the ssl extensible into the METADATA handler on InspIRCd. 2025-05-14 21:02:48 +01:00
Sadie Powell 1daafff79d Merge various email modules into one module.
In the future this will become the basis of the email contact
module and will encapsulate everything relating to email but for
now its mostly kept as-is.
2025-05-12 14:00:47 +01:00
Sadie Powell 3dd20975aa Also require services operators to confirm their email addresses.
Closes #468.
2025-05-11 22:59:20 +01:00
Sadie Powell 368d8e8b1c Remove first_commit which snuck into an earlier commit. 2025-05-11 18:24:57 +01:00
Sadie Powell 7c5d2c09fa Be more specific in the generator field in db_json. 2025-05-11 17:16:35 +01:00
Sadie Powell 41e702d853 Prefix the special db_json columns with an @. 2025-05-11 16:52:46 +01:00
Sadie Powell 19f83eaa34 Fix loading databases in db_json. 2025-05-11 16:45:44 +01:00
Sadie Powell b1212f9e89 Enable db_json by default. 2025-05-11 15:09:39 +01:00
Sadie Powell 3e9f516d55 Consistently use yes/no instead of true/false in the configs. 2025-05-11 12:49:25 +01:00
Sadie Powell 744b8bc4dc Redocument db_sql(_live) in the example configs. 2025-05-11 12:44:45 +01:00
Sadie Powell e9a0a214b0 Refactor Anope::strftime. 2025-05-10 14:40:12 +01:00
Sadie Powell 46c5570b1d Use UTC in timestamps shown to users. 2025-05-10 14:40:12 +01:00
Sadie Powell 151795a1df Remove an outdated comment in the memoserv example config. 2025-05-10 14:40:12 +01:00
Sadie Powell 50f17ea8e1 Consistently use realname instead of gecos. 2025-05-10 14:40:12 +01:00
Sadie Powell 2609ff44c6 Add defaults for service:{user,host,gecos}. 2025-05-10 14:40:12 +01:00
Sadie Powell ca30bb2370 Fix some remaining uses of vHost in the configs. 2025-05-10 13:32:45 +01:00
Sadie Powell f36b311f84 Add a note to irc2sql about using rpc_data instead. 2025-05-10 11:50:40 +01:00
Sadie Powell fec85376e7 Remove some duplicate chanstats settings. 2025-05-10 11:29:23 +01:00
Sadie Powell 0bf14650fa Always use the same stats object when deserialising stats.
Closes #509.
2025-05-10 10:23:11 +01:00
Sadie Powell 49f93b7670 Use more appropriate types for MaxUserCount and OperCount. 2025-05-10 00:59:20 +01:00
Sadie Powell ce0982cc4a There's no need to count the servers in os_stats. 2025-05-10 00:54:39 +01:00
Sadie Powell b4150841ec Try to ensure we only have use Stats instance.
This probably only happens when a user has a broken database but
its best to be more robust.
2025-05-10 00:54:39 +01:00
Sadie Powell eec428b0c7 Build buffers a bit smarter in cs_access/cs_xop/help. 2025-05-09 22:36:50 +01:00
Sadie Powell b706a6259e Add an accessor to Serialize::Reference and deduplicate code. 2025-05-09 22:25:10 +01:00
Sadie Powell 2cf8f003ce Allow using an account identifier in the anope.account RPC method. 2025-05-09 22:02:06 +01:00
Sadie Powell 07f57b1108 Be more explicit about what versions compatibility code is for. 2025-05-09 21:43:35 +01:00
Sadie Powell 5d648f9f1c Revert "Force the MySQL module to use UTC for connections".
This results in a deadlock. We have other ways for dealing with
this problem anyway.

Closes #506.
2025-05-09 15:35:02 +01:00
Sadie Powell 46e6b0adde Fix some forward declarations in the httpd header. 2025-05-09 15:35:02 +01:00
Sadie Powell 977780d8ef Store user away state and add it to the anope.user RPC event. 2025-05-09 14:47:31 +01:00
Sadie Powell 459f3d07c9 Add TLS usage to the anope.user RPC event. 2025-05-09 14:17:55 +01:00
Sadie Powell b76b407b33 Move HTTP types to the HTTP namespace. 2025-05-09 12:36:42 +01:00
Sadie Powell 8b089ab1a7 Stringify all parameters in the example RPC clients. 2025-05-09 11:33:20 +01:00
Sadie Powell fbec4d04a5 Merge branch '2.0' into 2.1. 2025-05-08 16:55:59 +01:00
Sadie Powell 34582a40ef Change Command::Run to return true on success. 2025-05-08 16:53:10 +01:00
Sadie Powell 4b15ca0232 Bump for 2.0.19-git. 2025-05-08 15:03:03 +01:00
Sadie Powell 997302f861 Release 2.0.18. 2025-05-08 15:01:58 +01:00
Sadie Powell b3b6e9f862 Update the change log. 2025-05-08 14:59:37 +01:00
Sadie Powell d23bfb0113 Fix being able to group guest nicknames.
This does not affect 2.1 because grouped nicknames work differently
on that branch.

Reported by @ValwareIRC.
2025-05-08 14:51:56 +01:00
Val Lorentz 0b7b4aa42d Fix French translation of "last used" 2025-05-06 10:18:58 +01:00
Sadie Powell fab8589e1e Remove rpc_main. 2025-05-05 21:18:27 +01:00
Sadie Powell 937404e311 Optimise the maths for the jsonrpc oversize integer workaround. 2025-05-05 21:11:51 +01:00
Sadie Powell c5ad774ce5 Add a workaround for JavaScript truncating integers in RPC. 2025-05-05 16:53:03 +01:00
Sadie Powell 1321f4f071 Add an example Ruby JSON-RPC client. 2025-05-05 13:25:40 +01:00
Sadie Powell 4319b6428f Fix various documentation errors in the JavaScript JSON-RPC client. 2025-05-05 13:24:23 +01:00
Sadie Powell e1f6d0ca16 Document the existence of the example JSON-RPC client. 2025-05-04 14:45:00 +01:00
Sadie Powell bb9074cbd5 Fix HTTP headers to be case insensitive as required by the spec. 2025-05-04 14:39:51 +01:00
Sadie Powell 72f5e3580f Also allow hashed RPC tokens in the config file. 2025-05-04 14:39:20 +01:00
Sadie Powell 4b854d3935 Add support for bearer tokens for authorising with RPC. 2025-05-04 14:14:19 +01:00
Sadie Powell 0b2b00b37d Send list mode changes with BMASK or EBMASK on Solanum. 2025-05-04 11:28:49 +01:00
Sadie Powell 196a3c32c2 Request EBMASK on Solanum.
TODO: also send this.
2025-05-04 03:18:23 +01:00
Sadie Powell 8955c53088 Zero-initialize a variable in BuildModeChange. 2025-05-04 02:56:59 +01:00
Sadie Powell 88c71fba64 Request SJSBY from UnrealIRCd.
We don't send this yet because its not ergonomic to do so with
the current API. Bleh.
2025-05-04 02:07:15 +01:00
Sadie Powell 21f61981ca Enable hidenetsplitquit by default. 2025-05-04 00:18:09 +01:00
Sadie Powell 5752c07a56 Fix a missing override keyword. 2025-05-03 21:40:21 +01:00
Sadie Powell 010beb52b1 Store the setter and ts for all modes and try to restore them.
This is mostly for preserving channel list mode info.
2025-05-03 21:28:56 +01:00
Sadie Powell c955941413 Remove the unused template overload of SendMode. 2025-05-03 19:01:35 +01:00
Sadie Powell 2e2515b9f0 Always use SVSLOGIN on UnrealIRCd. 2025-05-03 19:00:58 +01:00
Sadie Powell f0b26c9b44 Drop support for Bahamut as it has no non-DALnet users.
Closes #438.
2025-05-03 18:41:59 +01:00
Sadie Powell f953f7f006 Bump the minimum version of ircd-hybrid to 8.2.34.
This is 5 years old and allows us to remove the SVSACCOUNT hack.
2025-05-03 18:10:24 +01:00
Sadie Powell 84baf15620 Don't send join numerics to our own clients. 2025-05-03 17:16:05 +01:00
Sadie Powell 89f61ac91b Remove the inconsistently used [auto memo] prefix from some memos. 2025-05-02 12:25:15 +01:00
Sadie Powell b091184c60 Remove an obsolete comment about Windows. 2025-05-02 11:38:17 +01:00
Sadie Powell 6b1a491694 Add a note to LANGUAGE about control characters in messages. 2025-05-02 11:37:23 +01:00
Sadie Powell 66d3293ae6 Remove double spacing after a full stop in help messages.
This hasn't been considered a best practice since the age of the
typewriter.

https://english.stackexchange.com/questions/2544/how-many-spaces-should-come-after-a-period-full-stop
2025-05-02 11:10:35 +01:00
Sadie Powell a4691f9d4d Fix some typos in the change log. 2025-05-02 11:01:38 +01:00
Sadie Powell 51c7a15c45 Bump for 2.1.15-git. 2025-05-02 09:52:40 +01:00
Sadie Powell 151f9c2bcc Backport the Windows CI runner to 2.0.
[skip ubuntu ci]
2025-04-18 18:24:29 +01:00
254 changed files with 15616 additions and 16974 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
CXX: ${{ matrix.compiler }}
CXXFLAGS: -Werror
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Install dependencies
run: |
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
CXX: ${{ matrix.compiler }}
CXXFLAGS: -Werror
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Install dependencies
run: |
+2 -2
View File
@@ -16,7 +16,7 @@ jobs:
CONAN_USER_HOME: ${{ github.workspace }}/win/build
CONAN_USER_HOME_SHORT: None
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup NSIS
run: |-
@@ -28,7 +28,7 @@ jobs:
- name: Setup Conan
uses: turtlebrowser/get-conan@v1.2
with:
version: 1.64.0
version: 1.66.0
- name: Try to restore libraries from the cache
uses: actions/cache/restore@v4
+2 -10
View File
@@ -13,14 +13,6 @@
#
###########################################################################
exists () { # because some shells don't have test -e
if [ -f $1 -o -d $1 -o -p $1 -o -c $1 -o -b $1 ] ; then
return 0
else
return 1
fi
}
Load_Cache () {
if [ -f $SOURCE_DIR/config.cache -a -r $SOURCE_DIR/config.cache -a ! "$IGNORE_CACHE" ] ; then
echo "Using defaults from config.cache. To ignore, $SOURCE_DIR/Config -nocache"
@@ -208,7 +200,7 @@ while [ $ok -eq 0 ] ; do
INPUT=$INSTDIR
fi
if [ ! -d "$INPUT" ] ; then
if exists "$INPUT" ; then
if [ -e "$INPUT" ]; then
echo "$INPUT exists, but is not a directory!"
else
echo "$INPUT does not exist. Create it?"
@@ -220,7 +212,7 @@ while [ $ok -eq 0 ] ; do
fi
fi
fi
elif exists "$INPUT/include/services.h" ; then
elif [ -e "$INPUT/include/services.h" ]; then
echo "You cannot use the Anope source directory as a target directory."
else
ok=1
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
# Only install cron.example.sh and anope.example.conf from this directory
# NOTE: I would've had this just find all files in the directory, but that would include files not needed (like this file)
set(DATA cron.example.sh anope.example.conf botserv.example.conf hostserv.example.conf modules.example.conf operserv.example.conf chanserv.example.conf global.example.conf memoserv.example.conf nickserv.example.conf chanstats.example.conf irc2sql.example.conf stats.standalone.example.conf)
set(DATA cron.example.sh anope.example.conf botserv.example.conf hostserv.example.conf modules.example.conf operserv.example.conf chanserv.example.conf global.example.conf memoserv.example.conf nickserv.example.conf chanstats.example.conf)
install(FILES ${DATA}
DESTINATION ${CONF_DIR}
)
+76 -134
View File
@@ -65,10 +65,6 @@
* will typically be disabled. If this is not the case, more
* information will be given in the documentation.
*
* [DISCOURAGED]
* Indicates a directive which may cause undesirable side effects if
* specified.
*
* [DEPRECATED]
* Indicates a directive which will disappear in a future version of
* Anope, usually because its functionality has been either
@@ -87,8 +83,9 @@
*/
/*
* The services.host define is used in multiple different locations throughout the
* configuration for the server name and pseudoclient hostnames.
* The "services.host" define is used in multiple different locations throughout
* the configuration for the server name and pseudoclient hostnames. You should
* change the value to the hostname you wish to use for your services server.
*/
define
{
@@ -259,7 +256,6 @@ serverinfo
* You MUST modify this to match the IRCd you run.
*
* Supported:
* - bahamut
* - hybrid
* - inspircd
* - ngircd
@@ -326,7 +322,7 @@ networkinfo
* The characters allowed in hostnames. This is used for validating hostnames given
* to services, such as BotServ bot hostnames and user vhosts. Changing this is not
* recommended unless you know for sure your IRCd supports whatever characters you are
* wanting to use. Telling services to set a vHost containing characters your IRCd
* wanting to use. Telling services to set a vhost containing characters your IRCd
* disallows could potentially break the IRCd and/or Anope.
*
* It is recommended you DON'T change this.
@@ -334,21 +330,21 @@ networkinfo
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-/"
/*
* If set to true, allows vHosts to not contain dots (.).
* If enabled, allows vhosts to not contain dots (.).
* Newer IRCds generally do not have a problem with this, but the same warning as
* vhost_chars applies.
*
* It is recommended you DON'T change this.
*/
allow_undotted_vhosts = false
allow_undotted_vhosts = no
/*
* The characters that are not allowed to be at the very beginning or very ending
* of a vHost. The same warning as vhost_chars applies.
* of a vhost. The same warning as vhost_chars applies.
*
* It is recommended you DON'T change this.
*/
disallow_start_or_end = ".-"
disallow_start_or_end = ".-/"
}
/*
@@ -588,7 +584,7 @@ include
}
/*
* [OPTIONAL] NickServ
* [RECOMMENDED] NickServ
*
* Includes nickserv.example.conf, which is necessary for NickServ functionality.
*
@@ -746,11 +742,13 @@ log
* nickserv/alist - Can see the channel access list of other users
* nickserv/auspex - Can see any information with /NICKSERV INFO
* nickserv/cert - Can modify other users certificate lists
* nickserv/confirm - Can confirm other users nicknames
* nickserv/confirm/email - Can confirm other users email address change
* nickserv/confirm/register - Can confirm other users account registration
* nickserv/drop - Can drop other users nicks
* nickserv/drop/display - Allows dropping display nicks when preservedisplay is enabled
* nickserv/drop/override - Allows dropping nicks without using a confirmation code
* nickserv/recover - Can recover other users nicks
* nickserv/resend - Can resend confirmation codes via email
* operserv/config - Can modify services's configuration
* operserv/oper/modify - Can add and remove operators with at most the same privileges
* protected - Can not be kicked from channels by services
@@ -815,10 +813,10 @@ opertype
inherits = "Helper, Another Helper"
/* What commands (see above) this opertype may use */
commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline"
commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/resend nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline"
/* What privs (see above) this opertype has */
privs = "chanserv/auspex chanserv/no-register-limit memoserv/* nickserv/auspex nickserv/confirm"
privs = "chanserv/auspex chanserv/no-register-limit memoserv/* nickserv/auspex nickserv/confirm/*"
/*
* Modes to be set on users when they identify to accounts linked to this opertype.
@@ -891,8 +889,8 @@ opertype
/* An optional list of user@host masks. If defined the user must be connected from one of them */
#host = "*@*.anope.org ident@*"
/* An optional vHost to set on users who identify for this oper block.
* This will override HostServ vHosts, and may not be available on all IRCds
/* An optional vhost to set on users who identify for this oper block.
* This will override HostServ vhosts, and may not be available on all IRCds
*/
#vhost = "oper.mynet"
}
@@ -931,18 +929,20 @@ mail
usemail = yes
/*
* This is the command-line that will be used to call the mailer to send an
* email. It must be called with all the parameters needed to make it
* scan the mail input to find the mail recipient; consult your mailer
* documentation.
* The command used for sending emails. It is assumed that this behaves like
* sendmail (i.e. it reads the email from the standard input stream) but you
* should probably use Postfix or some other sendmail-compatible emailer
* instead of sendmail as sendmail is very hard to configure correctly. If
* you are using Windows then https://www.glob.com.au/sendmail/ is probably
* the best option currently.
*
* Postfix users must use the compatible sendmail utility provided with
* it. This one usually needs no parameters on the command-line. Most
* sendmail applications (or replacements of it) require the -t option
* to be used.
*
* If you are running on Windows you should use a Windows sendmail port
* like https://www.glob.com.au/sendmail/ for sending emails.
* If your emailer sends emails directly from the services host you will
* need to configure DKIM, DMARC, and SPF to avoid email hosts from marking
* your services emails as spam. It is important that you do this *BEFORE*
* sending emails for the first time as some email providers will add your
* host to a DNSBL like Spamhaus if they consider your emails to be spam. If
* this is too difficult then you may want to consider sending emails via an
* external email provider using a forwarder like msmtp.
*/
#sendmailpath = "/usr/sbin/sendmail -it"
@@ -993,7 +993,7 @@ mail
registration_message = "Hi,
You have requested to register the nickname {nick} on {network}.
Please type \" /msg NickServ CONFIRM {code} \" to complete registration.
Please type \" /msg NickServ CONFIRM REGISTER {code} \" to complete registration.
If you don't know why this mail was sent to you, please ignore it silently.
@@ -1011,7 +1011,7 @@ mail
reset_message = "Hi,
You have requested to have the password for {nick} reset.
To reset your password, type \" /msg NickServ CONFIRM {nick} {code} \"
To reset your password, type \" /msg NickServ CONFIRM RESETPASS {nick} {code} \"
If you don't know why this mail was sent to you, please ignore it silently.
@@ -1031,7 +1031,7 @@ mail
emailchange_message = "Hi,
You have requested to change your email address from {old_email} to {new_email}.
Please type \" /msg NickServ CONFIRM {code} \" to confirm this change.
Please type \" /msg NickServ CONFIRM EMAIL {code} \" to confirm this change.
If you don't know why this mail was sent to you, please ignore it silently.
@@ -1065,96 +1065,46 @@ mail
* have will not be stored!
*/
/*
* [DEPRECATED] db_old
*
* This is the old binary database format from late Anope 1.7.x, Anope 1.8.x, and
* early Anope 1.9.x. This module only loads these databases, and will NOT save them.
* You should only use this to upgrade old databases to a newer database format by loading
* other database modules in addition to this one, which will be used when saving databases.
*/
#module
{
name = "db_old"
/*
* This is the encryption type used by the databases. This must be set correctly or
* your passwords will not work. Valid options are: md5, oldmd5, sha1, and plain.
* You must also be sure to load the correct encryption module below in the Encryption
* Modules section so that your passwords work.
*/
#hash = "md5"
}
/*
* db_atheme
*
* This allows importing databases from Atheme. You should load another database module as
* well as this as it can only read Atheme databases not write them.
* This allows importing databases from Atheme. You should load another database
* module like db_json as well as this as it can only read Atheme databases not
* write them.
*/
#module
{
name = "db_atheme"
/*
* The database name db_atheme should use.
* The file that db_atheme will import your main database from.
*/
database = "atheme.db"
}
/*
* [RECOMMENDED] db_flatfile
* [DEPRECATED] db_flatfile
*
* This is the default flatfile database format.
* This allows importing databases from the custom flat file format used between
* Anope 1.9.6 and 2.1.17. You should load another database module like db_json
* as well as this as it can only read db_flatfile databases not write them.
*/
module
#module
{
name = "db_flatfile"
/*
* The database name db_flatfile should use
* The file that db_flatfile will import your main database from.
*/
database = "anope.db"
/*
* 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.
*
* This directive is optional, but recommended.
*/
keepbackups = 7
/*
* Allows Anope to continue file write operations (i.e. database saving)
* even if the original file cannot be backed up. Enabling this option may
* allow Anope to continue operation under conditions where it might
* otherwise fail, such as a nearly-full disk.
*
* NOTE: Enabling this option can cause irrecoverable data loss under some
* conditions, so make CERTAIN you know what you're doing when you enable it!
*
* This directive is optional, and you are discouraged against enabling it.
*/
#nobackupokay = yes
/*
* If enabled, services will fork a child process to save databases.
*
* This is only useful with very large databases, with hundreds
* of thousands of objects, that have a noticeable delay from
* writing databases.
*/
fork = no
}
/*
* db_json
* [RECOMMENDED] 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.
* Stores your database in a JSON file.
*/
#module
module
{
name = "db_json"
@@ -1203,17 +1153,21 @@ module
/*
* db_sql and db_sql_live
*
* db_sql module allows saving and loading databases using one of the SQL engines.
* This module loads the databases once on startup, then incrementally updates
* objects in the database as they are changed within Anope in real time. Changes
* to the SQL tables not done by Anope will have no effect and will be overwritten.
* Allows saving and loading databases to a SQL database.
*
* db_sql_live module allows saving and loading databases using one of the SQL engines.
* This module reads and writes to SQL in real time. Changes to the SQL tables
* will be immediately reflected into Anope. This module should not be loaded
* in conjunction with db_sql. It should also not be used on large networks as it
* executes quite a lot of queries which can cause performance issues.
* db_sql loads the databases once on startup and then incrementally updates in
* in the database as they are changed within Anope. Changes to the SQL tables
* not done by Anope will have no effect and will be overwritten.
*
* db_sql_live module reads and writes to SQL in real time. Changes to the SQL
* tables will be immediately reflected in Anope. This module can not be loaded
* at the same time as db_sql. It should also not be used on large networks as
* it executes quite a lot of queries which can cause performance issues.
*
* IMPORTANT: The SQL schema has changed in the 2.1 branch. Whilst Anope will
* try to update your schema it is recommended that before upgrading you export
* to a file and re-import your database on 2.1. This will remove any obsolete
* columns and change the types of existing columns to match the new schema.
*/
#module
{
@@ -1221,10 +1175,10 @@ module
#name = "db_sql_live"
/*
* The SQL service db_sql(_live) should use, these are configured in modules.conf.
* For MySQL, this should probably be mysql/main.
* The SQL service that db_sql(_live) should use. These are configured in
* modules.example.conf. For MySQL, this should probably be mysql/main.
*/
engine = "sqlite/main"
engine = "mysql/main"
/*
* An optional prefix to prepended to the name of each created table.
@@ -1232,18 +1186,22 @@ module
*/
#prefix = "anope_db_"
/* Whether or not to import data from another database module in to SQL on startup.
* If you enable this, be sure that the database services is configured to use is
* empty and that another database module to import from is loaded BEFORE db_sql.
* After you enable this and do a database import you MUST disable it for
* subsequent restarts. If you want to keep writing a flatfile database after the
* SQL import is done you should load db_flatfile AFTER this module.
/*
* Whether or not to import data from another database module in to SQL on
* startup.
*
* Note that you can not import databases using db_sql_live. If you want to import
* databases and use db_sql_live you should import them using db_sql, then shut down
* and start services with db_sql_live.
* If you enable this, be sure that the database Anope is configured to use
* is empty and that another database module to import from is loaded BEFORE
* db_sql. After you enable this and do a database import you MUST disable
* it for subsequent restarts. If you want to keep writing a file database
* after the SQL import is done you should load db_flatfile or db_json AFTER
* this module.
*
* Note that you can not import databases using db_sql_live. If you want to
* import databases and use db_sql_live you should import them using db_sql,
* then shut down and start Anope with db_sql_live.
*/
import = false
import = no
}
/*
@@ -1362,7 +1320,7 @@ module
#module { name = "enc_posix" }
/*
* [DEPRECATED] enc_md5, enc_none, enc_old, enc_sha1, enc_sha256
* [DEPRECATED] enc_md5, enc_none, enc_sha1, enc_sha256
*
* Provides verify-only support for passwords encrypted using encryption methods
* from older versions of Anope. These methods are no longer considered secure
@@ -1372,8 +1330,6 @@ module
* enc_md5: Verifies passwords encrypted with the MD5 algorithm
* enc_none: Verifies passwords that are not encrypted
* enc_sha1: Verifies passwords encrypted with the SHA1 algorithm
* enc_old: Verifies passwords encrypted with the broken MD5 algorithm used
* before 1.7.17.
* enc_sha256: Verifies passwords encrypted with the SHA256 algorithm using a
* custom initialisation vector as a salt.
*
@@ -1382,7 +1338,6 @@ module
*/
#module { name = "enc_md5" }
#module { name = "enc_none" }
#module { name = "enc_old" }
#module { name = "enc_sha1" }
#module { name = "enc_sha256" }
@@ -1402,16 +1357,3 @@ include
type = "file"
name = "chanstats.example.conf"
}
/*
* IRC2SQL Gateway
* This module collects data about users, channels and servers. It doesn't build stats
* itself, however, it gives you the database, it's up to you how you use it.
*
* Requires a MySQL Database and MySQL version 5.5 or higher
*/
#include
{
type = "file"
name = "irc2sql.example.conf"
}
+5 -8
View File
@@ -36,7 +36,7 @@ service
/*
* The realname of the BotServ client.
*/
gecos = "Bot Service"
real = "Bot Service"
/*
* The modes this client should use.
@@ -296,11 +296,9 @@ command { service = "BotServ"; name = "KICK ITALICS"; command = "botserv/kick/it
command { service = "BotServ"; name = "KICK REPEAT"; command = "botserv/kick/repeat"; }
command { service = "BotServ"; name = "KICK REVERSES"; command = "botserv/kick/reverses"; }
command { service = "BotServ"; name = "KICK UNDERLINES"; command = "botserv/kick/underlines"; }
command { service = "BotServ"; name = "SET DONTKICKOPS"; command = "botserv/set/dontkickops"; }
command { service = "BotServ"; name = "SET DONTKICKVOICES"; command = "botserv/set/dontkickvoices"; }
/*
* bs_set
*
@@ -341,7 +339,6 @@ privilege
xop = "AOP"
}
/*
* fantasy
*
@@ -387,15 +384,15 @@ fantasy { name = "ENFORCE"; command = "chanserv/enforce"; }
fantasy { name = "ENTRYMSG"; command = "chanserv/entrymsg"; }
fantasy { name = "FLAGS"; command = "chanserv/flags"; }
fantasy { name = "HALFOP"; command = "chanserv/modes"; }
fantasy { name = "HELP"; command = "generic/help"; prepend_channel = false; }
fantasy { name = "HELP"; command = "generic/help"; prepend_channel = no; require_privilege = no; }
fantasy { name = "HOP"; command = "chanserv/xop"; }
fantasy { name = "INFO"; command = "chanserv/info"; prepend_channel = false; }
fantasy { name = "INFO"; command = "chanserv/info"; prepend_channel = no; }
fantasy { name = "INVITE"; command = "chanserv/invite"; }
fantasy { name = "K"; command = "chanserv/kick"; }
fantasy { name = "KB"; command = "chanserv/ban"; }
fantasy { name = "KICK"; command = "chanserv/kick"; }
fantasy { name = "LEVELS"; command = "chanserv/levels"; }
fantasy { name = "LIST"; command = "chanserv/list"; prepend_channel = false; }
fantasy { name = "LIST"; command = "chanserv/list"; prepend_channel = no; }
fantasy { name = "LOG"; command = "chanserv/log"; }
fantasy { name = "MODE"; command = "chanserv/mode"; }
fantasy { name = "MUTE"; command = "chanserv/ban"; kick = no; mode = "QUIET"; }
@@ -403,7 +400,7 @@ fantasy { name = "OP"; command = "chanserv/modes"; }
fantasy { name = "OWNER"; command = "chanserv/modes"; }
fantasy { name = "PROTECT"; command = "chanserv/modes"; }
fantasy { name = "QOP"; command = "chanserv/xop"; }
fantasy { name = "SEEN"; command = "chanserv/seen"; prepend_channel = false; }
fantasy { name = "SEEN"; command = "chanserv/seen"; prepend_channel = no; }
fantasy { name = "SOP"; command = "chanserv/xop"; }
fantasy { name = "STATUS"; command = "chanserv/status"; }
fantasy { name = "SUSPEND"; command = "chanserv/suspend"; permission = "chanserv/suspend"; }
+18 -28
View File
@@ -26,7 +26,7 @@ service
/*
* The realname of the ChanServ client.
*/
gecos = "Channel Registration Service"
real = "Channel Registration Service"
/*
* The modes this client should use.
@@ -100,6 +100,7 @@ module
* not in use.
* - cs_no_expire: Enables no expire. Needs founder, successor (if set) or anyone in the access list
* to be a registered nick, otherwise the channel will be dropped.
* - cs_stats: Enable Chanstats for newly registered channels
* - none: No defaults
*
* This directive is optional, if left blank, the options will default to cs_keep_modes, keeptopic, peace,
@@ -171,19 +172,19 @@ module
/*
* If set, prevents channel access entries from containing hostmasks.
*/
disallow_hostmask_access = false
disallow_hostmask_access = no
/*
* If set, prevents channels from being on access lists.
*/
disallow_channel_access = false
disallow_channel_access = no
/*
* If set, ChanServ will always lower the timestamp of registered channels to their registration date.
* This prevents several race conditions where unauthorized users can join empty registered channels and set
* modes etc. prior to services deopping them.
*/
always_lower_ts = false
always_lower_ts = no
}
/*
@@ -946,7 +947,7 @@ command { service = "ChanServ"; name = "AKICK"; command = "chanserv/akick"; grou
* Used for banning users from channels.
*/
module { name = "cs_ban" }
command { service = "ChanServ"; name = "BAN"; command = "chanserv/ban"; }
command { service = "ChanServ"; name = "BAN"; command = "chanserv/ban"; group = "chanserv/management"; }
/*
* cs_clone
@@ -1047,7 +1048,7 @@ command { service = "ChanServ"; name = "INVITE"; command = "chanserv/invite"; }
* Used for kicking users from channels.
*/
module { name = "cs_kick" }
command { service = "ChanServ"; name = "KICK"; command = "chanserv/kick"; }
command { service = "ChanServ"; name = "KICK"; command = "chanserv/kick"; group = "chanserv/management"; }
/*
* cs_list
@@ -1066,10 +1067,8 @@ module
listmax = 50
}
command { service = "ChanServ"; name = "LIST"; command = "chanserv/list"; }
command { service = "ChanServ"; name = "SET PRIVATE"; command = "chanserv/set/private"; }
/*
* cs_log
*
@@ -1155,7 +1154,6 @@ command { service = "ChanServ"; name = "DEHALFOP"; command = "chanserv/modes"; g
command { service = "ChanServ"; name = "VOICE"; command = "chanserv/modes"; group = "chanserv/status"; set = "VOICE" }
command { service = "ChanServ"; name = "DEVOICE"; command = "chanserv/modes"; group = "chanserv/status"; unset = "VOICE" }
/*
* cs_register
*
@@ -1178,9 +1176,6 @@ module
{
name = "cs_seen"
/* If set, uses the older 1.8 style seen, which is less resource intensive */
simple = false
/* Sets the time to keep seen entries in the seen database. */
purgetime = 90d
}
@@ -1228,7 +1223,7 @@ module
* If set, persistent channels have their creation times lowered to their
* original registration dates.
*/
persist_lower_ts = true
persist_lower_ts = yes
}
command { service = "ChanServ"; name = "SET"; command = "chanserv/set"; group = "chanserv/management"; }
command { service = "ChanServ"; name = "SET AUTOOP"; command = "chanserv/set/autoop"; }
@@ -1269,7 +1264,15 @@ command { service = "ChanServ"; name = "SET EMAIL"; command = "chanserv/set/misc
*/
module { name = "cs_status" }
command { service = "ChanServ"; name = "STATUS"; command = "chanserv/status"; }
command { service = "ChanServ"; name = "WHY"; command = "chanserv/status"; hide = true; }
command { service = "ChanServ"; name = "WHY"; command = "chanserv/status"; hide = yes; }
/*
* cs_statusupdate
*
* This module automatically updates users' status on channels when the
* channel's access list is modified.
*/
module { name = "cs_statusupdate" }
/*
* cs_suspend
@@ -1330,7 +1333,7 @@ command { service = "ChanServ"; name = "SET KEEPTOPIC"; command = "chanserv/set/
* Used for unbanning users from channels.
*/
module { name = "cs_unban" }
command { service = "ChanServ"; name = "UNBAN"; command = "chanserv/unban"; }
command { service = "ChanServ"; name = "UNBAN"; command = "chanserv/unban"; group = "chanserv/management"; }
/*
* cs_updown
@@ -1363,16 +1366,3 @@ command { service = "ChanServ"; name = "SOP"; command = "chanserv/xop"; group =
command { service = "ChanServ"; name = "AOP"; command = "chanserv/xop"; group = "chanserv/access"; }
command { service = "ChanServ"; name = "HOP"; command = "chanserv/xop"; group = "chanserv/access"; }
command { service = "ChanServ"; name = "VOP"; command = "chanserv/xop"; group = "chanserv/access"; }
/*
* Extra ChanServ related modules.
*/
/*
* cs_statusupdate
*
* This module automatically updates users' status on channels when the
* channel's access list is modified.
*/
module { name = "cs_statusupdate" }
+4 -6
View File
@@ -1,5 +1,9 @@
/*
* Example configuration file for Chanstats.
*
* You can enable Chanstats by default by adding CS_STATS to {chanserv}:defaults
* and NS_STATS to {nickserv}:defaults.
*
* Make sure BotServ, ChanServ and NickServ are running.
*/
@@ -23,12 +27,6 @@ module
smileyshappy = ":) :-) ;) ;-) :D :-D :P :-P"
smileyssad = ":( :-( ;( ;-("
smileysother = ":/ :-/"
/*
* Enable Chanstats for newly registered nicks / channels.
*/
ns_def_chanstats = yes
cs_def_chanstats = yes
}
command { service = "ChanServ"; name = "SET CHANSTATS"; command = "chanserv/set/chanstats"; }
command { service = "NickServ"; name = "SET CHANSTATS"; command = "nickserv/set/chanstats"; }
+2 -2
View File
@@ -26,7 +26,7 @@ service
/*
* The realname of the Global client.
*/
gecos = "Global Noticer"
real = "Global Noticer"
/*
* The modes this client should use.
@@ -93,7 +93,7 @@ module
#globaloncycleup = "Services are now back online - have a nice day"
/*
* If set, Anope will hide the IRC Operator's nick in a global
* If set, Anope will hide the Services Operator's nick in a global
* message/notice.
*
* This directive is optional.
+33 -14
View File
@@ -26,7 +26,7 @@ service
/*
* The realname of the HostServ client.
*/
gecos = "vHost Service"
real = "Hostname Service"
/*
* The modes this client should use.
@@ -106,7 +106,7 @@ command { service = "HostServ"; name = "HELP"; command = "generic/help"; }
*
* Provides the commands hostserv/del and hostserv/delall.
*
* Used for removing users' vHosts.
* Used for removing users' vhosts.
*/
module { name = "hs_del" }
command { service = "HostServ"; name = "DEL"; command = "hostserv/del"; permission = "hostserv/del"; }
@@ -117,21 +117,21 @@ command { service = "HostServ"; name = "DELALL"; command = "hostserv/delall"; pe
*
* Provides the command hostserv/group.
*
* Used for grouping one vHost to many nicks.
* Used for syncing one vhost to many nicks.
*/
module
{
name = "hs_group"
/*
* Upon nickserv/group, this option syncs the nick's main vHost to the grouped nick.
* Upon nickserv/group, this option syncs the nick's main vhost to the grouped nick.
*/
syncongroup = true
syncongroup = yes
/*
* This makes vhosts act as if they are per account.
*/
synconset = true
synconset = yes
}
command { service = "HostServ"; name = "GROUP"; command = "hostserv/group"; }
@@ -140,7 +140,7 @@ command { service = "HostServ"; name = "GROUP"; command = "hostserv/group"; }
*
* Provides the command hostserv/list.
*
* Used for listing actively set vHosts.
* Used for listing actively set vhosts.
*/
module { name = "hs_list" }
command { service = "HostServ"; name = "LIST"; command = "hostserv/list"; permission = "hostserv/list"; }
@@ -150,7 +150,7 @@ command { service = "HostServ"; name = "LIST"; command = "hostserv/list"; permis
*
* Provides the command hostserv/off.
*
* Used for turning off your vHost.
* Used for turning off your vhost.
*/
module { name = "hs_off" }
command { service = "HostServ"; name = "OFF"; command = "hostserv/off"; }
@@ -160,7 +160,7 @@ command { service = "HostServ"; name = "OFF"; command = "hostserv/off"; }
*
* Provides the command hostserv/on.
*
* Used for turning on your vHost.
* Used for turning on your vhost.
*/
module { name = "hs_on" }
command { service = "HostServ"; name = "ON"; command = "hostserv/on"; }
@@ -168,36 +168,55 @@ command { service = "HostServ"; name = "ON"; command = "hostserv/on"; }
/*
* hs_request
*
* Provides the commands hostserv/request, hostserv/activate, hostserv/reject, and hostserv/waiting.
* Provides the commands:
* hostserv/request - Requests a vhost.
* hostserv/activate - Approves a requested vhost.
* hostserv/reject - Rejects a requested vhost.
* hostserv/waiting - Lists pending vhost requests.
* hostserv/validate - Allows self-service approval of vhosts using DNS
* validation (requires the dns module).
*
* Used to manage vHosts requested by users.
* Used to manage vhosts requested by users.
*/
module
{
name = "hs_request"
/*
* If set, Anope will send a memo to the user requesting a vHost when it's been
* If set, Anope will send a memo to the user requesting a vhost when it's been
* approved or rejected.
*/
#memouser = yes
/*
* If set, Anope will send a memo to all services staff when a new vHost is requested.
* If set, Anope will send a memo to all services staff when a new vhost is requested.
*/
#memooper = yes
/*
* If DNS validation is enabled, how long should users have to wait between
* attempts at DNS validation. Defaults to 5 minutes.
*/
#validationcooldown = 5m
/*
* If DNS validation is enabled, the TXT record to look for when determining
* if the requester controls the domain. Defaults to anope-dns-validation.
*/
#validationrecord = "anope-dns-validation"
}
command { service = "HostServ"; name = "REQUEST"; command = "hostserv/request"; }
command { service = "HostServ"; name = "ACTIVATE"; command = "hostserv/activate"; permission = "hostserv/set"; }
command { service = "HostServ"; name = "REJECT"; command = "hostserv/reject"; permission = "hostserv/set"; }
command { service = "HostServ"; name = "WAITING"; command = "hostserv/waiting"; permission = "hostserv/set"; }
#command { service = "HostServ"; name = "VALIDATE"; command = "hostserv/validate"; }
/*
* hs_set
*
* Provides the commands hostserv/set and hostserv/setall.
*
* Used for setting users' vHosts.
* Used for setting users' vhosts.
*/
module { name = "hs_set" }
command { service = "HostServ"; name = "SET"; command = "hostserv/set"; permission = "hostserv/set"; }
-97
View File
@@ -1,97 +0,0 @@
/*
* Example configuration file for the irc2sql gateway
*
*/
service
{
/*
* The name of the StatServ client.
*/
nick = "StatServ"
/*
* The username of the StatServ client.
*/
user = "StatServ"
/*
* The hostname of the StatServ client.
*/
host = "${services.host}"
/*
* The realname of the StatServ client.
*/
gecos = "Statistical Service"
/*
* The modes this client should use.
* Do not modify this unless you know what you are doing.
*
* These modes are very IRCd specific. If left commented, sane defaults
* are used based on what protocol module you have loaded.
*
* Note that setting this option incorrectly could potentially BREAK some, if
* not all, usefulness of the client. We will not support you if this client is
* unable to do certain things if this option is enabled.
*/
#modes = "+o"
/*
* An optional comma separated list of channels this service should join. Outside
* of log channels this is not very useful, as the service will just idle in the
* specified channels, and will not accept any types of commands.
*
* Prefixes may be given to the channels in the form of mode characters or prefix symbols.
*/
#channels = "@#stats,#mychan"
}
module
{
name = "irc2sql"
/*
* The name of the client that should send the CTCP VERSION requests.
* It must already exist or must be defined in the following service block.
*/
client = "StatServ"
/*
* The name of the SQL engine to use.
* This must be MySQL and must match the name in the mysql{} block
*/
engine = "mysql/main"
/*
* An optional prefix to prepended to the name of each created table.
* Do not use the same prefix for other programs.
*/
prefix = "anope_"
/*
* GeoIP - Automatically adds users geoip location to the user table.
* Tables are created by irc2sql, you have to run the
* geoipupdate script after you started Anope to download
* and import the GeoIP database.
*
* The geoip database can be the smaller "country" database or the
* larger "city" database. Comment to disable geoip lookup.
*/
geoip_database = "country"
/*
* Get the CTCP version from users
* The users connecting to the network will receive a CTCP VERSION
* request from the above configured stats client
*/
ctcpuser = "yes"
/*
* Send out CTCP VERSION requests to users during burst.
* Disable this if you restart Anope often and don't want to
* annoy your users.
*/
ctcpeob = "yes"
}
+3 -6
View File
@@ -26,7 +26,7 @@ service
/*
* The realname of the MemoServ client.
*/
gecos = "Memo Service"
real = "Memo Service"
/*
* The modes this client should use.
@@ -89,8 +89,7 @@ module
/*
* The delay between consecutive uses of the MemoServ SEND command. This can help prevent spam
* as well as denial-of-service attacks from sending large numbers of memos and filling up disk
* space (and memory). The default 3-second wait means a maximum average of 150 bytes of memo
* per second per user under the current IRC protocol.
* space (and memory).
*
* This directive is optional, but recommended.
*/
@@ -197,8 +196,6 @@ command { service = "MemoServ"; name = "READ"; command = "memoserv/read"; }
* Provides the command memoserv/rsend.
*
* Used to send a memo requiring a receipt be sent back once it is read.
*
* Requires configuring memoserv:memoreceipt.
*/
#module
{
@@ -209,7 +206,7 @@ command { service = "MemoServ"; name = "READ"; command = "memoserv/read"; }
*
* This directive is optional.
*/
operonly = false
operonly = no
}
#command { service = "MemoServ"; name = "RSEND"; command = "memoserv/rsend"; }
+115 -34
View File
@@ -41,7 +41,6 @@ module { name = "help" }
*/
timeout = 5
/* Only edit below if you are expecting to use os_dns or otherwise answer DNS queries. */
/*
@@ -54,7 +53,6 @@ module { name = "help" }
ip = "0.0.0.0"
port = 53
/*
* SOA record information.
*/
@@ -65,7 +63,7 @@ module { name = "help" }
/* This should be the names of the public facing nameservers serving the records. */
nameservers = "ns1.example.com ns2.example.com"
/* The time slave servers are allowed to cache. This should be reasonably low
/* The time secondary servers are allowed to cache for. This should be reasonably low
* if you want your records to be updated without much delay.
*/
refresh = 3600
@@ -233,7 +231,7 @@ module { name = "help" }
}
/*
* ldap [EXTRA]
* [EXTRA] ldap
*
* This module allows other modules to use LDAP. By itself, this module does nothing useful.
*/
@@ -304,13 +302,13 @@ module { name = "help" }
*
* If not set, then registration is not blocked.
*/
#disable_register_reason = "To register on this network visit https://some.misconfigured.site/register"
#disable_register_reason = "To register on this network visit https://some.misconfigured.site.example/register"
/*
* If set, the reason to give the users who try to "/msg NickServ SET EMAIL".
* If not set, then email changing is not blocked.
*/
#disable_email_reason = "To change your email address visit https://some.misconfigured.site"
#disable_email_reason = "To change your email address visit https://some.misconfigured.site.example"
}
/*
@@ -355,7 +353,7 @@ module { name = "help" }
}
/*
* mysql [EXTRA]
* [EXTRA] mysql
*
* This module allows other modules to use MySQL.
*/
@@ -402,7 +400,7 @@ module { name = "help" }
}
/*
* regex_pcre2 [EXTRA]
* [EXTRA] regex_pcre2
*
* Provides the regex engine regex/pcre, which uses version 2 of the Perl Compatible Regular
* Expressions library.
@@ -410,7 +408,7 @@ module { name = "help" }
#module { name = "regex_pcre2" }
/*
* regex_posix [EXTRA]
* [EXTRA] regex_posix
*
* Provides the regex engine regex/posix, which uses the POSIX compliant regular expressions.
*/
@@ -440,7 +438,7 @@ module
}
/*
* regex_tre [EXTRA]
* [EXTRA] regex_tre
*
* Provides the regex engine regex/tre, which uses the TRE regex library.
*/
@@ -457,7 +455,7 @@ module
service = "ChanServ"; name = "CLEAR"; command = "rewrite"
/* Enable rewrite. */
rewrite = true
rewrite = yes
/* Source message to match. A $ can be used to match anything. */
rewrite_source = "CLEAR $ USERS"
@@ -559,7 +557,7 @@ module
}
/*
* ssl_gnutls [EXTRA]
* [EXTRA] ssl_gnutls
*
* This module provides SSL services to Anope using GnuTLS, for example to
* connect to the uplink server(s) via SSL.
@@ -598,7 +596,7 @@ module
}
/*
* ssl_openssl [EXTRA]
* [EXTRA] ssl_openssl
*
* This module provides SSL services to Anope using OpenSSL, for example to
* connect to the uplink server(s) via SSL.
@@ -691,20 +689,20 @@ module
* If set, the reason to give the users who try to "/msg NickServ REGISTER".
* If not set, then registration is not blocked.
*/
#disable_reason = "To register on this network visit https://some.misconfigured.site/register"
#disable_reason = "To register on this network visit https://some.misconfigured.site.example/register"
/*
* If set, the reason to give the users who try to "/msg NickServ SET EMAIL".
* If not set, then email changing is not blocked.
*/
#disable_email_reason = "To change your email address visit https://some.misconfigured.site"
#disable_email_reason = "To change your email address visit https://some.misconfigured.site.example"
}
/*
* sql_log
*
* This module adds an additional target option to log{} blocks
* that allows logging Service's logs to SQL. To log to SQL, add
* that allows logging Services' logs to SQL. To log to SQL, add
* the SQL service name to log:targets prefixed by sql_log:. For
* example:
*
@@ -723,8 +721,8 @@ module
/*
* sql_oper
*
* This module allows granting users services operator privileges and possibly IRC Operator
* privileges based on an external SQL database using a custom query.
* This module allows granting users Services Operator privileges based on an
* external SQL database using a custom query.
*/
#module
{
@@ -747,7 +745,7 @@ module
}
/*
* sqlite [EXTRA]
* [EXTRA] sqlite
*
* This module allows other modules to use SQLite.
*/
@@ -795,8 +793,14 @@ module
/*
* jsonrpc
*
* Allows remote applications (websites) to execute queries in real time to retrieve data from Anope.
* By itself this module does nothing, but allows other modules (rpc_main) to receive and send JSON-RPC queries.
* Allows remote applications to execute methods within Anope using the JSON-RPC
* protocol. See https://www.jsonrpc.org/specification for more information.
*
* By itself this module does nothing. You should load a RPC method module like
* rpc_data which actually provides RPC methods.
*
* See docs/RPC/jsonrpc.js for an example JavaScript JSON-RPC client.
* See docs/RPC/jsonrpc.rb for an example Ruby JSON-RPC client.
*
* IMPORTANT: this can not be loaded at the same time as the xmlrpc module.
*/
@@ -804,15 +808,54 @@ module
{
name = "jsonrpc"
/*
* The maximum number of bits an integer can be have in its native type.
*
* By default Anope will emit integers as their native JSON type. If you are
* using JavaScript (which has 53 bit integers) or another language with
* native integer types smaller than 64 bits you may need to limit the size
* of integers emitted by Anope.
*
* If this is enabled a string will be used for values outside of the range
* supported by the native data type.
*/
#integer_bits = 53
/* Web service to use. Requires httpd. */
server = "httpd/main"
/*
* You can also specify one or more authorization tokens to protect access
* to the JSON-RPC interface. These tokens should be sent using the Bearer
* authorization header as defined in RFC 6750.
*/
#token
{
/* The token used for authentication. */
token = "BmcxTaiYjoBtayfnxCFq"
/*
* The algorithm which the above token 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.
*/
#token_hash = "bcrypt"
/** A list of glob patterns for methods the token can execute. */
methods = "~anope.message* anope.*"
}
}
/*
* [EXTRA] xmlrpc
*
* Allows remote applications (websites) to execute queries in real time to retrieve data from Anope.
* By itself this module does nothing, but allows other modules (rpc_main) to receive and send XMLRPC queries.
* Allows remote applications to execute methods within Anope using the XML-RPC
* protocol. See https://xmlrpc.com/spec.md for more information.
*
* By itself this module does nothing. You should load a RPC method module like
* rpc_data which actually provides RPC methods.
*
* IMPORTANT: this can not be loaded at the same time as the jsonrpc module.
*/
@@ -820,9 +863,6 @@ module
{
name = "xmlrpc"
/* Web service to use. Requires httpd. */
server = "httpd/main"
/*
* Whether to enable the use of XML-RPC extensions.
*
@@ -836,6 +876,55 @@ module
*/
#enable_i8 = no
#enable_nil = no
/* Web service to use. Requires httpd. */
server = "httpd/main"
/*
* You can also specify one or more authorization tokens to protect access
* to the XML-RPC interface. These tokens should be sent using the Bearer
* authorization header as defined in RFC 6750.
*/
#token
{
/* The token used for authentication. */
token = "BmcxTaiYjoBtayfnxCFq"
/*
* The algorithm which the above token 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.
*/
#token_hash = "bcrypt"
/** A list of glob patterns for methods the token can execute. */
methods = "~anope.message* anope.*"
}
}
/*
* rpc_user
*
* Adds support for the following RPC methods:
*
* anope.checkCredentials anope.identify
* anope.listCommands anope.command
*
* Requires either the jsonrpc or xmlrpc module.
*
* See docs/RPC/rpc_user.md for API documentation.
*/
#module
{
name = "rpc_user"
/*
* Some commands can only be executed by a real IRC user. You can work around
* this executing them as an IRC user logged into the account if one exists.
*/
pretenduser = no
}
/*
@@ -855,14 +944,6 @@ module
*/
#module { name = "rpc_data" }
/*
* rpc_main
*
* Adds the main RPC core functions.
* Requires xmlrpc.
*/
#module { name = "rpc_main" }
/*
* rpc_message
*
+166 -78
View File
@@ -26,7 +26,7 @@ service
/*
* The realname of the NickServ client.
*/
gecos = "Nickname Registration Service"
real = "Nickname Registration Service"
/*
* The modes this client should use.
@@ -118,6 +118,7 @@ module
* - 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.
* - ns_stats: Enable Chanstats for newly registered nicks
*
* 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.
@@ -164,7 +165,7 @@ module
* If set, Anope will not show netsplits in the last quit message field
* of NickServ's INFO command.
*/
hidenetsplitquit = no
hidenetsplitquit = yes
/*
* The default period to force users to stop using a protected nickname after.
@@ -202,11 +203,13 @@ module
#restrictopernicks = yes
/*
* The username, and possibly hostname, used for fake users created when Anope needs to
* hold a nickname.
* The username, hostname, and real name used for pseudoclients created when
* Anope needs to hold a nickname. This is only used if your IRCd does not
* support SVSHOLDs.
*/
enforceruser = "enforcer"
enforcerhost = "${services.host}"
enforcerreal = "Services Enforcer"
/*
* The length of time Anope should hold nicknames for.
@@ -248,8 +251,8 @@ module
maxpasslen = 50
/*
* Whether all of the secondary nicks of a nick group have to expire or be
dropped before the display nick can expire or be dropped.
* Whether all of the secondary nicks of an account have to expire or be
* dropped before the display nick can expire or be dropped.
*/
preservedisplay = no
}
@@ -306,7 +309,7 @@ command { service = "NickServ"; name = "AJOIN"; command = "nickserv/ajoin"; }
*/
module { name = "ns_alist" }
command { service = "NickServ"; name = "ALIST"; command = "nickserv/alist"; }
command { service = "NickServ"; name = "ACCESS"; command = "nickserv/alist"; hide = true; }
command { service = "NickServ"; name = "ACCESS"; command = "nickserv/alist"; hide = yes; }
/*
* ns_cert
@@ -333,6 +336,16 @@ module
}
command { service = "NickServ"; name = "CERT"; command = "nickserv/cert"; }
/*
* ns_confirm
*
* Provides the command nickserv/confirm.
*
* Used for confirming previous account actions.
*/
module { name = "ns_confirm" }
command { service = "NickServ"; name = "CONFIRM"; command = "nickserv/confirm"; }
/*
* ns_drop
*
@@ -344,21 +357,56 @@ module { name = "ns_drop" }
command { service = "NickServ"; name = "DROP"; command = "nickserv/drop"; }
/*
* ns_getemail
* ns_email
*
* Provides the command nickserv/getemail.
* Provides various functionality relating to email addresses. This includes the
* following commands:
*
* Used for getting registered accounts by searching for emails.
* - nickserv/confirm/email: Used for confirming email changes.
* - nickserv/getemail: Used for getting accounts by searching for emails.
* - nickserv/set/email, nickserv/saset/email: Used for setting an account's
* emailvaddress.
*/
module { name = "ns_getemail" }
module
{
name = "ns_email"
/*
* The amount of time a user has after requesting a change of email address
* before it expires. Defaults to 1 day.
*/
#changeexpire = 1d
/*
* The limit to how many registered accounts can use the same email address.
* If set to 0 or left commented there will be no limit enforced when
* registering new accounts or using /msg NickServ SET EMAIL.
*/
#maxemails = 1
/*
* Whether to attempt to remove aliases when counting email addresses. This
* means removing dots (.) and anything after a plus (+) in the user part of
* the address, e.g. foo.bar+baz@example.com -> foobar@example.com.
*/
#remove_aliases = yes
}
command { service = "NickServ"; name = "CONFIRM EMAIL"; command = "nickserv/confirm/email"; }
command { service = "NickServ"; name = "GETEMAIL"; command = "nickserv/getemail"; permission = "nickserv/getemail"; group = "nickserv/admin"; }
command { service = "NickServ"; name = "SET EMAIL"; command = "nickserv/set/email"; }
command { service = "NickServ"; name = "SASET EMAIL"; command = "nickserv/saset/email"; permission = "nickserv/saset/email"; }
/*
* ns_group
*
* Provides the commands nickserv/group, nickserv/glist, and nickserv/ungroup.
* Provides the commands:
* nickserv/group
* nickserv/ungroup
* nickserv/glist
* nickserv/saset/display
* nickserv/set/display
*
* Used for controlling nick groups.
* Used for controlling grouped nicknames.
*/
module
{
@@ -383,6 +431,12 @@ module
command { service = "NickServ"; name = "GLIST"; command = "nickserv/glist"; }
command { service = "NickServ"; name = "GROUP"; command = "nickserv/group"; }
command { service = "NickServ"; name = "UNGROUP"; command = "nickserv/ungroup"; }
command { service = "NickServ"; name = "SET DISPLAY"; command = "nickserv/set/display"; }
command { service = "NickServ"; name = "SASET DISPLAY"; command = "nickserv/saset/display"; permission = "nickserv/saset/display"; }
# For compatibility with Atheme.
command { service = "NickServ"; name = "SET ACCOUNTNAME"; command = "nickserv/set/display"; hide = yes; }
command { service = "NickServ"; name = "SASET ACCOUNTNAME"; command = "nickserv/saset/display"; permission = "nickserv/saset/display"; hide = yes; }
/*
* ns_identify
@@ -400,7 +454,7 @@ module
*/
maxlogins = 10
}
command { service = "NickServ"; name = "ID"; command = "nickserv/identify"; hide = true; }
command { service = "NickServ"; name = "ID"; command = "nickserv/identify"; hide = yes; }
command { service = "NickServ"; name = "IDENTIFY"; command = "nickserv/identify"; }
/*
@@ -417,7 +471,6 @@ command { service = "NickServ"; name = "INFO"; command = "nickserv/info"; }
command { service = "NickServ"; name = "SET HIDE"; command = "nickserv/set/hide"; }
command { service = "NickServ"; name = "SASET HIDE"; command = "nickserv/saset/hide"; permission = "nickserv/saset/hide"; }
/*
* ns_list
*
@@ -436,11 +489,9 @@ module
listmax = 50
}
command { service = "NickServ"; name = "LIST"; command = "nickserv/list"; }
command { service = "NickServ"; name = "SET PRIVATE"; command = "nickserv/set/private"; }
command { service = "NickServ"; name = "SASET PRIVATE"; command = "nickserv/saset/private"; permission = "nickserv/saset/private"; }
/*
* ns_logout
*
@@ -473,13 +524,13 @@ module
command { service = "NickServ"; name = "RECOVER"; command = "nickserv/recover"; }
# For compatibility with Anope 1.8 and Atheme.
command { service = "NickServ"; name = "GHOST"; command = "nickserv/recover"; hide = true; }
command { service = "NickServ"; name = "RELEASE"; command = "nickserv/recover"; hide = true; }
command { service = "NickServ"; name = "GHOST"; command = "nickserv/recover"; hide = yes; }
command { service = "NickServ"; name = "RELEASE"; command = "nickserv/recover"; hide = yes; }
/*
* ns_register
*
* Provides the commands nickserv/confirm, nickserv/register, and nickserv/resend.
* Provides the commands nickserv/confirm/register, nickserv/register, and nickserv/resend.
*
* Used for registering accounts.
*/
@@ -488,11 +539,15 @@ module
name = "ns_register"
/*
* Registration confirmation setting. Set to "none" for no registration confirmation,
* "mail" for email confirmation, and "admin" to have services operators manually confirm
* every registration. Set to "disable" to completely disable all registrations.
* The method for confirming account registrations. Possible values are:
*
* "admin" to require confirmation by a Services Operator.
* "code" to require confirmation with a code provided via IRC.
* "disable" to disable account registration.
* "mail" to require confirmation with a code provided via email.
* "none" to automatically confirm (this is the default).
*/
registration = "none"
registration = "code"
/*
* The minimum length of time between consecutive uses of NickServ's RESEND command.
@@ -507,7 +562,7 @@ module
*
* This directive is optional.
*/
nickregdelay = 15s
#nickregdelay = 1m
/*
* The length of time a user using an unconfirmed account has
@@ -515,20 +570,33 @@ module
*/
#unconfirmedexpire = 1d
}
command { service = "NickServ"; name = "CONFIRM"; command = "nickserv/confirm"; }
command { service = "NickServ"; name = "CONFIRM REGISTER"; command = "nickserv/confirm/register"; }
command { service = "NickServ"; name = "REGISTER"; command = "nickserv/register"; }
command { service = "NickServ"; name = "RESEND"; command = "nickserv/resend"; }
/*
* ns_resetpass
*
* Provides the command nickserv/resetpass.
* Provides the command nickserv/confirm/resetpass and nickserv/resetpass.
*
* Used for resetting passwords by emailing users a temporary one.
*/
module { name = "ns_resetpass" }
module
{
name = "ns_resetpass"
/*
* The amount of time a user has after requesting a password reset before it
* expires. Defaults to 1 day.
*/
#resetexpire = 1d
}
command { service = "NickServ"; name = "CONFIRM RESETPASS"; command = "nickserv/confirm/resetpass"; }
command { service = "NickServ"; name = "RESETPASS"; command = "nickserv/resetpass"; }
# For compatibility with Anope 2.0.
command { service = "NickServ"; name = "GETPASS"; command = "nickserv/resetpass"; hide = yes; }
/*
* ns_sasl
*
@@ -548,18 +616,46 @@ module
* The nick of the client which operates as the SASL agent.
*/
#agent = "NickServ"
/*
* Sets the number of invalid SASL authentication attempts before services
* removes a partially-connected user from the network. If not defined then
* the value specified in options:badpasslimit will be used instead.
*/
#badpasslimit = 1
/*
* Sets the time after which invalid SASL authentication attempts are
* forgotten about. If a user does not fail to authenticate in this amount
* of time, the incorrect password count will reset to zero. If not defined
* then the value specified in options:badpasstimeout will be used instead.
*/
#badpasstimeout = 15m
}
/*
* ns_sasl_anonymous, ns_sasl_external, ns_sasl_plain
*
* Provides support for the following SASL mechanisms:
*
* ns_sasl_anonymous: Adds the ANONYMOUS mechanism which allows logging out of
* an account. See RFC 4505 for more details.
* ns_sasl_external: Adds the EXTERNAL mechanism which allows logging into an
account using a TLS client certificate. See RFC 4422 for
for more details.
* ns_sasl_plain: Adds the PLAIN mechanism which allows logging in to an
account using a plain text username and password. See RFC
4422 for more details.
*/
module { name = "ns_sasl_anonymous" }
module { name = "ns_sasl_external" }
module { name = "ns_sasl_plain" }
/*
* ns_set
*
* Provides the commands:
* nickserv/set, nickserv/saset - Dummy help wrappers for the SET and SASET commands.
* nickserv/set/autoop, nickserv/saset/autoop - Determines whether or not modes are automatically set users when joining a channel.
* nickserv/set/display, nickserv/saset/display - Used for setting a users display name.
* nickserv/set/email, nickserv/saset/email - Used for setting a users email address.
* nickserv/set/keepmodes, nickserv/saset/keepmodes - Configure whether or not services should retain a user's modes across sessions.
* nickserv/set/neverop, nickserv/saset/neverop - Used to configure whether a user can be added to access lists
* nickserv/saset/noexpire - Used for configuring noexpire, which prevents nicks from expiring.
* nickserv/set/password, nickserv/saset/password - Used for changing a users password.
*/
@@ -568,21 +664,9 @@ module { name = "ns_set" }
command { service = "NickServ"; name = "SET"; command = "nickserv/set"; }
command { service = "NickServ"; name = "SASET"; command = "nickserv/saset"; permission = "nickserv/saset/"; group = "nickserv/admin"; }
command { service = "NickServ"; name = "SET AUTOOP"; command = "nickserv/set/autoop"; }
command { service = "NickServ"; name = "SASET AUTOOP"; command = "nickserv/saset/autoop"; permission = "nickserv/saset/autoop"; }
command { service = "NickServ"; name = "SET DISPLAY"; command = "nickserv/set/display"; }
command { service = "NickServ"; name = "SASET DISPLAY"; command = "nickserv/saset/display"; permission = "nickserv/saset/display"; }
command { service = "NickServ"; name = "SET EMAIL"; command = "nickserv/set/email"; }
command { service = "NickServ"; name = "SASET EMAIL"; command = "nickserv/saset/email"; permission = "nickserv/saset/email"; }
command { service = "NickServ"; name = "SET PASSWORD"; command = "nickserv/set/password"; }
command { service = "NickServ"; name = "SASET PASSWORD"; command = "nickserv/saset/password"; permission = "nickserv/saset/password"; }
command { service = "NickServ"; name = "SET NEVEROP"; command = "nickserv/set/neverop"; }
command { service = "NickServ"; name = "SASET NEVEROP"; command = "nickserv/saset/neverop"; permission = "nickserv/saset/neverop"; }
command { service = "NickServ"; name = "SASET NOEXPIRE"; command = "nickserv/saset/noexpire"; permission = "nickserv/saset/noexpire"; }
/*
@@ -617,6 +701,17 @@ module { name = "ns_set_language" }
command { service = "NickServ"; name = "SET LANGUAGE"; command = "nickserv/set/language"; }
command { service = "NickServ"; name = "SASET LANGUAGE"; command = "nickserv/saset/language"; permission = "nickserv/saset/language"; }
/*
* ns_set_layout
*
* Provides the command nickserv/set/layout and nickserv/saset/layout.
*
* Allows configuring the layout that services uses.
*/
module { name = "ns_set_layout" }
command { service = "NickServ"; name = "SET LAYOUT"; command = "nickserv/set/layout"; }
command { service = "NickServ"; name = "SASET LAYOUT"; command = "nickserv/saset/layout"; permission = "nickserv/saset/layout"; }
/*
* ns_set_message
*
@@ -643,28 +738,44 @@ command { service = "NickServ"; name = "SASET LANGUAGE"; command = "nickserv/sas
module { name = "ns_set_misc" }
command { service = "NickServ"; name = "SET URL"; command = "nickserv/set/misc"; misc_description = _("Associate a URL with your account"); }
command { service = "NickServ"; name = "SASET URL"; command = "nickserv/saset/misc"; misc_description = _("Associate a URL with this account"); permission = "nickserv/saset/url"; group = "nickserv/admin"; }
#command { service = "NickServ"; name = "SET DISCORD"; command = "nickserv/set/misc"; misc_description = _("Associate a Discord account with your account"); }
#command { service = "NickServ"; name = "SASET DISCORD"; command = "nickserv/saset/misc"; misc_description = _("Associate a Discord account with this account"); permission = "nickserv/saset/discord"; group = "nickserv/admin"; }
#command { service = "NickServ"; name = "SET MASTODON"; command = "nickserv/set/misc"; misc_description = _("Associate a Mastodon account with your account"); }
#command { service = "NickServ"; name = "SASET MASTODON"; command = "nickserv/saset/misc"; misc_description = _("Associate a Mastodon account with this account"); permission = "nickserv/saset/mastodon"; group = "nickserv/admin"; }
#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"; }
#command { service = "NickServ"; name = "SET LOCATION"; command = "nickserv/set/misc"; misc_description = _("Associate a location with your account"); }
#command { service = "NickServ"; name = "SASET LOCATION"; command = "nickserv/saset/misc"; misc_description = _("Associate a location with this account"); permission = "nickserv/saset/location"; group = "nickserv/admin"; }
/*
* ns_set_op
*
* Provides the commands:
* nickserv/set/autoop, nickserv/saset/autoop - Allows configuring whether status modes are automatically granted when joining a channel.
* nickserv/set/neverop, nickserv/saset/neverop - Allows configuring whether a user can be added to access lists.
*/
module { name = "ns_set_op" }
command { service = "NickServ"; name = "SET AUTOOP"; command = "nickserv/set/autoop"; }
command { service = "NickServ"; name = "SASET AUTOOP"; command = "nickserv/saset/autoop"; permission = "nickserv/saset/autoop"; }
command { service = "NickServ"; name = "SET NEVEROP"; command = "nickserv/set/neverop"; }
command { service = "NickServ"; name = "SASET NEVEROP"; command = "nickserv/saset/neverop"; permission = "nickserv/saset/neverop"; }
# For compatibility with DALnet Services.
command { service = "NickServ"; name = "SET NOOP"; command = "nickserv/set/neverop"; hide = yes; }
command { service = "NickServ"; name = "SASET NOOP"; command = "nickserv/saset/neverop"; permission = "nickserv/saset/neverop"; hide = yes; }
/*
* ns_set_protect
*
* Provides the commands nickserv/set/protect and kickserv/saset/protect.
* Provides the commands nickserv/set/protect and nickserv/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"; }
command { service = "NickServ"; name = "SASET PROTECT"; command = "nickserv/saset/protect"; permission = "nickserv/saset/protect"; }
# 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; }
command { service = "NickServ"; name = "SET KILL"; command = "nickserv/set/protect"; hide = yes; }
command { service = "NickServ"; name = "SASET KILL"; command = "nickserv/saset/protect"; permission = "nickserv/saset/protect"; hide = yes; }
/*
* ns_suspend
@@ -699,30 +810,7 @@ command { service = "NickServ"; name = "UNSUSPEND"; command = "nickserv/unsuspen
*
* Provides the command nickserv/update.
*
* Used to update your status on all channels, turn on your vHost, etc.
* Used to update your status on all channels, turn on your vhost, etc.
*/
module { name = "ns_update" }
command { service = "NickServ"; name = "UPDATE"; command = "nickserv/update"; }
/*
* Extra NickServ related modules.
*/
/*
* ns_maxemail
*
* Limits how many times the same email address may be used in Anope
* to register accounts.
*/
#module
{
name = "ns_maxemail"
/*
* The limit to how many registered nicks can use the same email address. If set to 0 or left
* commented, there will be no limit enforced when registering new accounts or using
* /msg NickServ SET EMAIL.
*/
maxemails = 1
}
+5 -5
View File
@@ -26,7 +26,7 @@ service
/*
* The realname of the OperServ client.
*/
gecos = "Operator Service"
real = "Operator Service"
/*
* The modes this client should use.
@@ -111,7 +111,7 @@ module
killonsqline = yes
/*
* Adds the nickname of the IRC Operator issuing an AKILL to the kill reason.
* Adds the nickname of the Services Operator issuing an AKILL to the kill reason.
*
* This directive is optional.
*/
@@ -287,15 +287,15 @@ command { service = "OperServ"; name = "CHANKILL"; command = "operserv/chankill"
* To use this module you must set a nameserver record for services
* so that DNS queries go to services.
*
* Alternatively, you may use a slave DNS server to hide service's IP,
* Alternatively, you may use a secondary DNS server to hide services' IP,
* provide query caching, and provide better fault tolerance.
*
* To do this using BIND, configure similar to:
*
* options { max-refresh-time 60; };
* zone "irc.example.com" IN {
* type slave;
* masters { 127.0.0.1 port 5353; };
* type secondary;
* primaries { 127.0.0.1 port 5353; };
* };
*
* Where 127.0.0.1:5353 is the IP and port services are listening on.
-515
View File
@@ -1,515 +0,0 @@
/*
* Example configuration file for Anope. After making the appropriate
* changes to this file, place it in the Anope conf directory (as
* specified in the "Config" script, default /home/username/anope/conf)
* under the name "anope.conf".
*
* The format of this file is fairly simple: three types of comments are supported:
* - All text after a '#' on a line is ignored, as in shell scripting
* - All text after '//' on a line is ignored, as in C++
* - A block of text like this one is ignored, as in C
*
* Outside of comments, there are three structures: blocks, keys, and values.
*
* A block is a named container, which contains a number of key to value pairs
* - you may think of this as an array.
*
* A block is created like so:
* foobar
* {
* moo = "cow"
* foo = bar
* }
*
* Note that nameless blocks are allowed and are often used with comments to allow
* easily commenting an entire block, for example:
* #foobar
* {
* moo = "cow"
* foo = bar
* }
* is an entirely commented block.
*
* Keys are case insensitive. Values depend on what key - generally, information is
* given in the key comment. The quoting of values (and most other syntax) is quite
* flexible, however, please do not forget to quote your strings:
*
* "This is a parameter string with spaces in it"
*
* If you need to include a double quote inside a quoted string, precede it
* by a backslash:
*
* "This string has \"double quotes\" in it"
*
* Time parameters can be specified either as an integer representing a
* number of seconds (e.g. "3600" = 1 hour), or as an integer with a unit
* specifier: "s" = seconds, "m" = minutes, "h" = hours, "d" = days.
* Combinations (such as "1h30m") are not permitted. Examples (all of which
* represent the same length of time, one day):
*
* "86400", "86400s", "1440m", "24h", "1d"
*
* In the documentation for each directive, one of the following will be
* included to indicate whether an option is required:
*
* [REQUIRED]
* Indicates a directive which must be given. Without it, Anope will
* not start.
*
* [RECOMMENDED]
* Indicates a directive which may be omitted, but omitting it may cause
* undesirable side effects.
*
* [OPTIONAL]
* Indicates a directive which is optional. If not given, the feature
* will typically be disabled. If this is not the case, more
* information will be given in the documentation.
*
* [DISCOURAGED]
* Indicates a directive which may cause undesirable side effects if
* specified.
*
* [DEPRECATED]
* Indicates a directive which will disappear in a future version of
* Anope, usually because its functionality has been either
* superseded by that of other directives or incorporated into the main
* program.
*/
/*
* [OPTIONAL] Defines
*
* 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 the server name and pseudoclient hostnames.
*/
define
{
name = "services.host"
value = "stats.example.com"
}
/*
* [OPTIONAL] Additional Includes
*
* You can include additional configuration files here.
* You may also include executable files, which will be executed and
* the output from it will be included into your configuration.
*/
#include
{
type = "file"
name = "some.conf"
}
#include
{
type = "executable"
name = "/usr/bin/wget -q -O - https://some.misconfigured.network.com/stats.conf"
}
/*
* [REQUIRED] IRCd Config
*
* This section is used to set up Anope to connect to your IRC network.
* This section can be included multiple times, and Anope will attempt to
* connect to each server until it finally connects.
*
* Each uplink IRCd should have a corresponding configuration to allow Anope
* to link to it.
*
* An example configuration for InspIRCd that is compatible with the below uplink
* and serverinfo configuration would look like:
*
* # This goes in inspircd.conf, *NOT* your Anope config!
* <link name="stats.example.com"
* ipaddr="127.0.0.1"
* port="7000"
* sendpass="mypassword"
* recvpass="mypassword">
* <uline server="stats.example.com" silent="yes">
* <bind address="127.0.0.1" port="7000" type="servers">
*
* An example configuration for UnrealIRCd that is compatible with the below uplink
* and serverinfo configuration would look like:
*
* // This goes in unrealircd.conf, *NOT* your Anope config!
* listen {
* ip 127.0.0.1;
* port 7000;
* options {
* serversonly;
* };
* };
* link stats.example.com {
* incoming {
* mask *@127.0.0.1;
* };
* password "mypassword";
* class servers;
* };
* ulines { stats.example.com; };
*/
uplink
{
/*
* The IP address, hostname, or UNIX socket path of the IRC server you wish
* to connect Anope to.
* Usually, you will want to connect over 127.0.0.1 (aka localhost).
*
* NOTE: On some shell providers, this will not be an option.
*/
host = "127.0.0.1"
/*
* The protocol that Anope should use when connecting to the uplink. Can
* be set to "ipv4" (the default), "ipv6", or "unix".
*/
protocol = "ipv4"
/*
* Enable if Anope should connect using SSL.
* You must have an SSL module loaded for this to work.
*/
ssl = no
/*
* The port to connect to.
* The IRCd *MUST* be configured to listen on this port, and to accept
* server connections.
*
* Refer to your IRCd documentation for how this is to be done.
*/
port = 7000
/*
* The password to send to the IRC server for authentication.
* This must match the link block on your IRCd.
*
* Refer to your IRCd documentation for more information on link blocks.
*/
password = "mypassword"
}
/*
* [REQUIRED] Server Information
*
* This section contains information about the services server.
*/
serverinfo
{
/*
* The hostname that Anope will be seen as, it must have no conflicts with any
* 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.host}"
/*
* The text which should appear as the server's information in /WHOIS and similar
* queries.
*/
description = "Anope IRC Statistics"
/*
* The local address that Anope will bind to before connecting to the remote
* server. This may be useful for multihomed hosts. If omitted, Anope will let
* the Operating System choose the local address. This directive is optional.
*
* If you don't know what this means or don't need to use it, just leave this
* directive commented out.
*/
#localhost = "nowhere."
/*
* What Server ID to use for this connection?
* Note: This should *ONLY* be used for TS6/P10 IRCds. Refer to your IRCd documentation
* to see if this is needed.
*/
#id = "00A"
/*
* The filename containing the Anope process ID. The path is relative to the
* data directory.
*/
pid = "anope.pid"
/*
* The filename containing the Message of the Day. The path is relative to the
* config directory.
*/
motd = "motd.txt"
}
/*
* [REQUIRED] Protocol module
*
* This directive tells Anope which IRCd Protocol to speak when connecting.
* You MUST modify this to match the IRCd you run.
*
* Supported:
* - bahamut
* - hybrid
* - inspircd
* - ngircd
* - plexus
* - ratbox
* - solanum
* - unrealircd
*/
module
{
name = "inspircd"
}
/*
* [REQUIRED] Network Information
*
* This section contains information about the IRC network that Anope will be
* connecting to.
*/
networkinfo
{
/*
* This is the name of the network that Anope will be running on.
*/
networkname = "LocalNet"
/*
* Set this to the maximum allowed nick length on your network.
* Be sure to set this correctly, as setting this wrong can result in
* Anope being disconnected from the network. Defaults to 31.
*/
#nicklen = 31
/* Set this to the maximum allowed ident length on your network.
* Be sure to set this correctly, as setting this wrong can result in
* Anope being disconnected from the network. Defaults to 10.
*/
#userlen = 10
/* Set this to the maximum allowed hostname length on your network.
* Be sure to set this correctly, as setting this wrong can result in
* Anope being disconnected from the network. Defaults to 64.
*/
#hostlen = 64
/* Set this to the maximum allowed channel length on your network.
* Defaults to 64.
*/
#chanlen = 32
/* The maximum number of list modes settable on a channel (such as b, e, I).
* Comment out or set to 0 to disable.
*/
modelistsize = 100
/*
* The characters allowed in hostnames. This is used for validating hostnames given
* to services, such as BotServ bot hostnames and user vhosts. Changing this is not
* recommended unless you know for sure your IRCd supports whatever characters you are
* wanting to use. Telling services to set a vHost containing characters your IRCd
* disallows could potentially break the IRCd and/or Anope.
*
* It is recommended you DON'T change this.
*/
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"
/*
* If set to true, allows vHosts to not contain dots (.).
* Newer IRCds generally do not have a problem with this, but the same warning as
* vhost_chars applies.
*
* It is recommended you DON'T change this.
*/
allow_undotted_vhosts = false
/*
* The characters that are not allowed to be at the very beginning or very ending
* of a vHost. The same warning as vhost_chars applies.
*
* It is recommended you DON'T change this.
*/
disallow_start_or_end = ".-"
}
/*
* [REQUIRED] Anope Options
*
* This section contains various options which determine how Anope will operate.
*/
options
{
/*
* On Linux/UNIX systems Anope can setuid and setgid to this user and group
* after starting up. This is useful if Anope has to bind to privileged ports.
*/
#user = "anope"
#group = "anope"
/*
* The case mapping used by services. This must be set to a valid locale name
* installed on your machine. Anope uses this case map to compare, with
* case insensitivity, things such as nick names, channel names, etc.
*
* We provide two special casemaps shipped with Anope, ascii and rfc1459.
*
* This value should be set to what your IRCd uses, which is probably rfc1459,
* however Anope has always used ascii for comparison, so the default is ascii.
*
* Changing this value once set is not recommended.
*/
casemap = "ascii"
/*
* Sets the timeout period for reading from the uplink.
*/
readtimeout = 5s
/*
* If set, Anope will only show /stats o to IRC Operators. This directive
* is optional.
*/
#hidestatso = yes
/*
* A space-separated list of U-lined servers on your network, it is assumed that
* the servers in this list are allowed to set channel modes and Anope will
* not attempt to reverse their mode changes.
*
* WARNING: Do NOT put your normal IRC user servers in this directive.
*
* This directive is optional.
*/
#ulineservers = "services.your.network"
/*
* How long to wait between connection retries with the uplink(s).
*/
retrywait = 60s
}
/*
* [RECOMMENDED] Logging Configuration
*
* This section is used for configuring what is logged and where it is logged to.
* You may have multiple log blocks if you wish. Remember to properly secure any
* channels you choose to have Anope log to!
*/
log
{
/*
* Target(s) to log to, which may be one of the following:
* - a channel name
* - a filename
* - globops
*/
target = "stats.log"
/* Log to both stats.log and the channel #stats
*
* Note that some older IRCds, such as Ratbox, require services to be in the
* log channel to be able to message it. To do this, configure service:channels to
* join your logging channel.
*/
#target = "stats.log #stats"
/*
* The source(s) to only accept log messages from. Leave commented to allow all sources.
* This can be a users name, a channel name, one of our clients (e.g. OperServ), or a server name.
*/
#source = ""
/*
* The bot used to log generic messages which have no predefined sender if there
* is a channel in the target directive.
*/
bot = "Global"
/*
* The number of days to keep log files, only useful if you are logging to a file.
* Set to 0 to never delete old log files.
*
* Note that Anope must run 24 hours a day for this feature to work correctly.
*/
logage = 7
/*
* What types of log messages should be logged by this block. There are nine general categories:
*
* servers - Server actions, linking, squitting, etc.
* channels - Actions in channels such as joins, parts, kicks, etc.
* users - User actions such as connecting, disconnecting, changing name, etc.
* other - All other messages without a category.
* rawio - Logs raw input and output from services
* debug - Debug messages (log files can become VERY large from this).
*
* These options determine what messages from the categories should be logged. Wildcards are accepted, and
* you can also negate values with a ~. For example, "~operserv/akill operserv/*" would log all operserv
* messages except for operserv/akill. Note that processing stops at the first matching option, which
* means "* ~operserv/*" would log everything because * matches everything.
*
* Valid server options are:
* connect, quit, sync, squit
*
* Valid channel options are:
* create, destroy, join, part, kick, leave, mode
*
* Valid user options are:
* connect, disconnect, quit, nick, ident, host, mode, maxusers, oper, away
*
* Rawio and debug are simple yes/no answers, there are no types for them.
*
* Note that modules may add their own values to these options.
*/
servers = "*"
#channels = "~mode *"
users = "connect disconnect nick"
other = "*"
rawio = no
debug = no
}
/*
* [REQUIRED] MySQL Database configuration.
*
* mysql
*
* This module allows other modules to use MySQL.
*/
module
{
name = "mysql"
mysql
{
/* The name of this service. */
name = "mysql/main"
database = "anope"
server = "127.0.0.1"
username = "anope"
password = "mypassword"
port = 3306
}
}
/*
* IRC2SQL Gateway
* This module collects data about users, channels and servers. It doesn't build stats
* itself, however, it gives you the database, it's up to you how you use it.
*
* Requires a MySQL Database and MySQL version 5.5 or higher
*/
include
{
type = "file"
name = "irc2sql.example.conf"
}
+2 -2
View File
@@ -22,9 +22,9 @@ contributions they have made, are:
* Michael Wobst <wobst.michael@web.de>
* Mark Summers <mark@goopler.net>
* Matt Schatz <genius3000@g3k.solutions>
* PeGaSuS <droider.pc@gmail.com>
* 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>
@@ -33,9 +33,9 @@ contributions they have made, are:
* Hendrik Jäger <gitcommit@henk.geekmail.org>
* k4be <k4be@pirc.pl>
* Thomas Fargeix <t.fargeix@gmail.com>
* Val Lorentz <progval+git@progval.net>
* 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>
+73 -2
View File
@@ -1,5 +1,76 @@
Anope Version 2.1.14-git
------------------------
Anope Version 2.1.18
--------------------
Added a check that a non-deprecated database module is loaded.
Added support for flexible and monospace layouts to make text easier to read on clients that use a variable-width font.
Added support for logging about deprecated modules on boot.
Added support for per-IRCd hints when a link fails.
Added support for self-service validation of vhosts using DNS TXT records.
Added support for separate bad password limits for pre-connection SASL authentication.
Added support for SRV and TXT records to the dns module.
Added the --nodb option to disable database and encrytption module checks.
Added the nickname registration date to the nickserv/glist output.
Changed db_flatfile to be import-only (migrate to db_json).
Changed the default registration confirmation type to code validation.
Changed the fantasy !help command to not require the FANTASY privilege by default.
Changed various length measurement code to be UTF-8 aware.
Disabled the nickname registration delay by default.
Fixed reporting the MySQL version that the mysql module was built against.
Improved the layout of the nickserv/info command.
Modularised the ns_sasl module to make it easier to pick SASL mechanisms.
Moved duration rounding logic from Anope::Expires to Anope::Duration.
Removed support for importing old databases from 1.8.
Removed support for verifying "old MD5" passwords from 1.7.
Reworked how memory is allocated when formatting messages.
Anope Version 2.1.17
--------------------
Allowed opers to resend passwords for users in nickserv/resend.
Fixed HostServ using a different valid username character set to the protocol module.
Fixed losing the channel and nickname registration time when upgrading from an earlier 2.1 release.
Improved the messages sent when a user is forced off a protected nickname.
Simplified copying modules to the runtime directory on Windows.
Anope Version 2.1.16
--------------------
Added support for on-IRC code confirmation.
Added the ability for fantasy commands to be executable without the FANTASY privilege.
Added the ability to prepend to topics as well as appending to them.
Changed various fields to serialize to the database as a string not an integer.
Disabled db_flatfile by default in preparation for becoming import-only.
Fixed a memory leak in the db_json module.
Fixed building on OpenSSL 1.1.1 (for now).
Fixed removed and later re-added temporary bans being removed automatically.
Fixed sometimes sending malformed LMODE messages on InspIRCd.
Fixed the "did you mean" message suggesting unloaded commands.
Fixed various issues with the example config files.
Marked db_json as the recommended database module.
Moved the BAN, UNBAN, and KICK commands to the chanserv/management group.
Removed support for the 1.8-style seen command.
Reworked confirmation to allow confirmation of multiple account actions.
When dropping a display nickname the new display will now be the oldest in the group.
Anope Version 2.1.15
--------------------
Added a workaround to the jsonrpc module for JavaScript truncating big integers.
Added an example Ruby library for accessing the RPC interface.
Added away state and tls usage to the anope.user RPC event.
Added support for looking up accounts by identifier in the anope.account RPC event.
Added support for storing the setter and set time and setter of list modes and restoring them on InspIRCd and Solanum.
Added support for token authentication to the RPC modules.
Added the anope.checkCredentials, anope.identify, anope.listCommands, and anope.command RPC events to the new rpc_user module.
Bumped the minimum supported version of ircd-hybrid to 8.2.34.
Deprecated irc2sql in favour of rpc_data.
Dropped support for Bahamut as it has no known users.
Fixed creating duplicate Stats rows on some servers.
Fixed loading databases in db_json.
Fixed restoring cloaked hosts on InspIRCd when the cloak module is not loaded.
Fixed some variable shadowing that potentially caused issues with the SQL database backends.
Fixed sometimes writing accounts to the database without a unique identifier.
Fixed various documentation issues with the example JavaScript JSON-RPC client.
Improved CTCP handling and added support for more CTCP types.
Anope Version 2.1.14
--------------------
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.
+63 -6
View File
@@ -1,5 +1,62 @@
Anope Version 2.1.14-git
------------------------
Anope Version 2.1.18
--------------------
Added the hostserv/validate command.
Added the nickserv/saset/layout command.
Added the nickserv/set/layout command.
Added the ns_sasl_anonymous module.
Added the ns_sasl_external module.
Added the ns_sasl_plain module.
Added the ns_set_layout module.
Added the ns_set_op module.
Added {hs_request}:validationcooldown (defaults to 5 minutes).
Added {hs_request}:validationrecord (defaults to "anope-dns-validation").
Added {ns_sasl}:badpasslimit (defaults to options:badpasslimit).
Added {ns_sasl}:badpasstimeout (defaults to options:badpasstimeout).
Moved nickserv/set/autoop and nickserv/saset/autoop to the ns_set_op module.
Moved nickserv/set/display and nickserv/saset/display to the ns_set_group module.
Moved nickserv/set/neverop and nickserv/saset/neverop to the ns_set_op module.
Removed the db_old module.
Removed the enc_old module.
Removed {db_flatfile}:fork (module is now import-only).
Removed {db_flatfile}:keepbackups (module is now import-only).
Removed {db_flatfile}:nobackupokay (module is now import-only).
Anope Version 2.1.17
--------------------
Added the nickserv/resend oper privilege.
Anope Version 2.1.16
--------------------
Added fantasy:require_privilege (defaults to yes).
Added the nickserv/confirm/email command.
Added the nickserv/confirm/email oper privilege.
Added the nickserv/confirm/register command.
Added the ns_confirm module.
Added {ns_email}:changeexpire (defaults to 1 day).
Added {ns_resetpass}:resetexpire (defaults to 1 day).
Removed the irc2sql module (migrate to JSON-RPC instead).
Removed {ns_seen}:simple (1.8-style seen has been removed).
Renamed the nickserv/confirm oper privilege to nickserv/confirm/register.
Anope Version 2.1.15
--------------------
Added the ns_email module.
Added the rpc_user module.
Added {jsonrpc}:integer_bits (defaults to 64).
Added {jsonrpc}:token.
Added {nickserv}:enforcerreal (defaults to "Services Enforcer").
Added {xmlrpc}:token.
Moved nickserv/set/email and nickserv/saset/email to the ns_email module.
Removed the bahamut module.
Removed the ns_getemail module (load ns_email instead).
Removed the ns_maxemail module (load ns_email instead).
Removed the rpc_main module (migrate to the other RPC modules).
Removed {chanstats}:cs_def_chanstats (add CS_STATS to {chanserv}:defaults instead).
Removed {chanstats}:ns_def_chanstats (add NS_STATS to {nickserv}:defaults instead).
Renamed service:gecos to service:real.
Anope Version 2.1.14
--------------------
Added oper:password_hash.
Added options:codelength (defaults to 15).
Added {os_news}:showdate (defaults to yes).
@@ -8,7 +65,7 @@ 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.
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}:filter, {nickserv}:unregistered_notice, {os_session}:sessionlimitexceeded, {proxyscan}:proxyscan:reason.
Anope Version 2.1.13
--------------------
@@ -134,13 +191,13 @@ 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 (obsolete now nickserv:minpasslen exists).
Added {nickserv}:minpasslen for configuring the minimum password length (defaults to 8).
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).
Removed the unreal module (use unrealircd instead).
Renamed nickserv:passlen to nickserv:maxpasslen.
Renamed {nickserv}:passlen to {nickserv}:maxpasslen.
Renamed the charybdis module to solanum.
Renamed the inspircd3 module to inspircd.
Renamed the unreal4 module to unrealircd.
+4 -1
View File
@@ -29,11 +29,14 @@ Anope Multi Language Support
install gettext and run `msginit -l language -o anope.language.po -i anope.pot`. For example if I was translating to
Spanish I could run `msginit -l es_ES -o anope.es_ES.po -i anope.pot`. Open the newly generating .po file and start
translating. Once you are done simply rerun ./Config; make && make install and add the language to your anope.conf.
Note that on Windows it is not quite this simple, windows.cpp must be edited and Anope recompiled and restarted.
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).
There are several control characters within the messages. These are mostly IRC formatting codes (https://modern.ircdocs.horse/formatting)
but 0x1A is special to Anope and is used to prevent the automatic linewrapper from breaking messages in the middle of
text that should not be split (e.g. commands). Your editor may not show these so be careful you don't delete them!
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.
+2 -3
View File
@@ -160,15 +160,14 @@ Table of Contents
they log on, to set modes and to kick users from any channel, to
send notices quickly to the entire network, and much more!
* HostServ, a neat service that allows users to show custom vHosts
* HostServ, a neat service that allows users to show custom vhosts
(virtual hosts) instead of their real IP address; this only works
on daemons supporting ip cloaking, such as UnrealIRCd.
Anope currently works with:
* Bahamut 2.0 or later
* InspIRCd 3 or later
* ircd-hybrid 8.2.23 or later
* ircd-hybrid 8.2.34 or later
* ircd-ratbox 3 or later
* ngIRCd 19.2 or later
* Plexus 3 or later
-21
View File
@@ -1,21 +0,0 @@
RPC using JSON-RPC and XML-RPC (using PECL's xmlrpc_encode_request and xmlrpc_decode functions) is supported.
This allows external applications, such as websites, to execute remote procedure calls to Anope in real time.
Currently there are 5 supported RPC calls, provided by rpc_main:
checkAuthentication - Takes two parameters, an account name and a password. Checks if the account name is valid and the password
is correct for the account name, useful for making login pages on websites.
command - Takes three parameters, a service name (BotServ, ChanServ, NickServ), a user name (whether online or not), and the command
to execute. This will execute the given command to Anope using the given service name. If the user given is online, the
command reply will go to them, if not it is returned by RPC.
stats - Takes no parameters, returns miscellaneous stats that can be found in the /operserv stats command.
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.
Also note that when using XMLRPC the parameter named "id" is reserved for query ID. If you pass a query to Anope containing a value for id. it will
be stored by Anope and the same id will be passed back in the result.
+75 -16
View File
@@ -7,10 +7,12 @@ class AnopeRPC {
/**
* Initializes a new AnopeRPC instance with the specified RPC host.
*
* @param {string} The RPC host base URL.
* @param {string} host The RPC host base URL.
* @param {string} token The bearer token for authorizing with the RPC interface.
*/
constructor(host) {
constructor(host, token = "") {
this.host = host;
this.token = token;
}
/**
@@ -21,15 +23,20 @@ class AnopeRPC {
* @returns {*} The result of the RPC query.
*/
async run(method, ...params) {
const request = JSON.stringify({
const body = JSON.stringify({
"jsonrpc": "2.0",
"method": method,
"params": params,
"params": params.map((p) => p.toString()),
"id": Math.random().toString(36).slice(2)
});
const headers = new Headers();
if (this.token) {
headers.append("Authorization", `Bearer ${btoa(this.token)}`);
}
const response = await fetch(this.host, {
method: 'POST',
body: request
headers: headers,
body: body
});
if (!response.ok) {
throw new Error(`HTTP returned ${response.status}`)
@@ -49,8 +56,8 @@ class AnopeRPC {
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of account names.
* @param {string} detail The level of detail to request.
* @returns {(array|object)} A list of accounts.
*/
listAccounts(detail = "name") {
return this.run("anope.listAccounts", detail);
@@ -73,8 +80,8 @@ class AnopeRPC {
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of channel names.
* @param {string} detail The level of detail to request.
* @returns {(array|object)} A list of channels.
*/
listChannels(detail = "name") {
return this.run("anope.listChannels", detail);
@@ -97,8 +104,8 @@ class AnopeRPC {
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of channel names.
* @param {string} detail The level of detail to request.
* @returns {(array|object)} A list of services operators.
*/
listOpers(detail = "name") {
return this.run("anope.listOpers", detail);
@@ -121,8 +128,8 @@ class AnopeRPC {
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of servers names.
* @param {string} detail The level of detail to request.
* @returns {(array|object)} A list of servers.
*/
listServers(detail = "name") {
return this.run("anope.listServers", detail);
@@ -145,8 +152,8 @@ class AnopeRPC {
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of channel names.
* @param {string} detail The level of detail to request.
* @returns {(array|object)} A list of users.
*/
listUsers(detail = "name") {
return this.run("anope.listUsers", detail);
@@ -199,11 +206,63 @@ class AnopeRPC {
messageUser(source, target, ...messages) {
return this.run("anope.messageUser", source, target, ...messages);
}
/**
* Checks whether the specified credentials are valid.
*
* Requires the rpc_user module to be loaded.
*
* @param {string} account A nickname belonging to the account to check.
* @param {string} password The password for the specified account.
* @returns {object} An object containing basic information about the account.
*/
checkCredentials(account, password) {
return this.run("anope.checkCredentials", account, password);
}
/**
* Identifies an IRC user to the specified account.
*
* Requires the rpc_user module to be loaded.
*
* @param {string} account Either an account identifier or nickname belonging to the account to
* identify to.
* @param {string} password The nickname of the IRC user to identify to the account.
*/
identify(account, user) {
return this.run("anope.identify", account, user);
}
/**
* Lists all commands that exist on the network.
*
* Requires the rpc_user module to be loaded.
*
* @param {...*} services The nicknames of the services to list commands for.
* @returns {object} An object containing information about the available commands.
*/
listCommands(...services) {
return this.run("anope.listCommands", ...services);
}
/**
* Lists all commands that exist on the network.
*
* Requires the rpc_user module to be loaded.
*
* @param {string} account If non-empty then the account to execute the command as.
* @param {string} service The service which the command exists on.
* @param {...*} command The the command to execute and any parameters to pass to it.
* @returns {object} An object containing information about the available commands.
*/
command(account, service, ...command) {
return this.run("anope.command", account, service, ...command);
}
}
/*
const arpc = new AnopeRPC("http://127.0.0.1:8080/jsonrpc");
arpc.listServers().then(servers => {
arpc.listServers("full").then(servers => {
console.log(servers);
}).catch (error => {
console.log(error);
-150
View File
@@ -1,150 +0,0 @@
<?php
/**
* JSON-RPC functions
*
* (C) 2003-2025 Anope Team
* Contact us at team@anope.org
*/
class AnopeRPC
{
/**
* The RPC host
*
* @var string
*/
private $host;
/**
* Initiate a new AnopeRPC instance
*
* @param $host
*/
public function __construct($host)
{
$this->host = $host;
}
/**
* Run an RPC command. Name should be a query name and params an array of parameters, eg:
* $this->raw("checkAuthentication", ["adam", "qwerty"]);
* If successful returns back an array of useful information.
*
* Note that $params["id"] is reserved for query ID, you may set it to something if you wish.
* If you do, the same ID will be passed back with the reply from Anope.
*
* @param $name
* @param $params
* @return array|null
*/
public function run($name, $params)
{
$request = json_encode([
"jsonrpc" => "2.0",
"id" => uniqid(),
"method" => $name,
"params" => $params,
]);
$context = stream_context_create(["http" => [
"method" => "POST",
"header" => "Content-Type: application/json",
"content" => $request]]);
$inbuf = file_get_contents($this->host, false, $context);
$response = json_decode($inbuf, true);
if ($response) {
return $response;
}
return null;
}
/**
* Do Command on Service as User, eg:
* $anope->command("ChanServ", "Adam", "REGISTER #adam");
* Returns an array of information regarding the command execution, if
* If 'online' is set to yes, then the reply to the command was sent to the user on IRC.
* If 'online' is set to no, then the reply to the command is in the array member 'return'
*
* @param $service
* @param $user
* @param $command
* @return array|null
*/
public function command($service, $user, $command)
{
return $this->run("command", [$service, $user, $command]);
}
/**
* Check an account/nick name and password to see if they are valid
* Returns the account display name if valid
*
* @param $account
* @param $pass
* @return string|null
*/
public function auth($account, $pass)
{
$ret = $this->run("checkAuthentication", [$account, $pass]);
if ($ret && array_key_exists("result", $ret) && array_key_exists("account", $ret["result"])) {
return $ret["result"]["account"];
}
return null;
}
/**
* Returns an array of misc stats regarding Anope
*
* @return array|null
*/
public function stats()
{
return $this->run("stats", null);
}
/**
* Look up data for a channel
* Returns an array containing channel information, or an array of size one
* (just containing the name) if the channel does not exist
*
* @param $channel
* @return array|null
*/
public function channel($channel)
{
return $this->run("anope.channel", [$channel]);
}
/**
* Sent a notice to a user.
* Returns an array containing channel information, or an array of size one
* (just containing the name) if the channel does not exist
*
* @param $source
* @param $target
* @param $message
* @return array|null
*/
public function notice($source, $target, $message)
{
return $this->run("anope.messageUser", [$source, $target, $message]);
}
/**
* Like channel(), but different.
*
* @param $user
* @return array|null
*/
public function user($user)
{
return $this->run("anope.user", [$user]);
}
}
$anope = new AnopeRPC("http://127.0.0.1:8080/jsonrpc");
+242
View File
@@ -0,0 +1,242 @@
# SPDX-License-Identifier: CC0-1.0
require "base64"
require "json"
require "net/http"
# Implements methods for accessing an Anope JSON-RPC server.
class AnopeRPC
# The RPC host base URL.
attr_accessor :host
# The bearer token for authorizing with the RPC interface.
attr_accessor :token
# Initializes a new AnopeRPC instance with the specified RPC host.
#
# @param host [String] The RPC host base URL.
# @param token [String] The bearer token for authorizing with the RPC interface.
def initialize(host, token = nil)
@host = URI(host)
@token = token
end
# Executes an arbitrary RPC query.
#
# @param method [String] The name of the method to execute.
# @param params [Object] The parameters pass to the method.
# @return [Object] The result of the RPC query.
private def run(method, *params)
body = {
jsonrpc: "2.0",
method: method,
params: params.map(&:to_s),
id: rand(36**16).to_s(36)
}.to_json
headers = {}
headers["Authorization"] = "Bearer #{Base64.strict_encode64(@token)}" if @token
response = Net::HTTP.post(@host, body, headers)
raise "HTTP returned #{response.status}" unless response.is_a?(Net::HTTPSuccess)
json = JSON.parse(response.body, symbolize_names: true)
raise "JSON-RPC returned #{json[:error][:code]}: #{json[:error][:message]}" if json.key?(:error)
json.dig(:result)
end
# Retrieves a list of accounts.
#
# Requires the rpc_data module to be loaded.
#
# @param detail [Symbol] detail The level of detail to request.
# @return [Array] If the detail level is set to :name then an array of account names.
# @return [Hash] If the detail level is set to :full then a hash of information about the
# accounts.
def list_accounts(detail = :name)
self.run("anope.listAccounts", detail)
end
# Retrieves information about the specified account.
#
# Requires the rpc_data module to be loaded.
#
# @param name [String] The name of the account.
# @return [Hash] A hash containing information about the account.
def account(name)
self.run("anope.account", name)
end
# Retrieves a list of channels.
#
# Requires the rpc_data module to be loaded.
#
# @param detail [Symbol] detail The level of detail to request.
# @return [Array] If the detail level is set to :name then an array of channel names.
# @return [Hash] If the detail level is set to :full then a hash of information about the
# channels.
def list_channels(detail = :name)
self.run("anope.listChannels", detail)
end
# Retrieves information about the specified channel.
#
# Requires the rpc_data module to be loaded.
#
# @param name [String] The name of the channel.
# @return [Hash] A hash containing information about the channel.
def channel(name)
self.run("anope.channel", name)
end
# Retrieves a list of services operators.
#
# Requires the rpc_data module to be loaded.
#
# @param detail [Symbol] detail The level of detail to request.
# @return [Array] If the detail level is set to :name then an array of services operator names.
# @return [Hash] If the detail level is set to :full then a hash of information about the
# services operators.
def list_opers(detail = :name)
self.run("anope.listOpers", detail)
end
# Retrieves information about the specified services operator.
#
# Requires the rpc_data module to be loaded.
#
# @param name [String] The name of the services operator.
# @return [Hash] A hash containing information about the services operator.
def oper(name)
self.run("anope.oper", name)
end
# Retrieves a list of servers.
#
# Requires the rpc_data module to be loaded.
#
# @param detail [Symbol] detail The level of detail to request.
# @return [Array] If the detail level is set to :name then an array of server names.
# @return [Hash] If the detail level is set to :full then a hash of information about the
# servers.
def list_servers(detail = :name)
self.run("anope.listServers", detail)
end
# Retrieves information about the specified server.
#
# Requires the rpc_data module to be loaded.
#
# @param name [String] The name of the server.
# @return [Hash] A hash containing information about the server.
def server(name)
self.run("anope.server", name)
end
# Retrieves a list of users.
#
# Requires the rpc_data module to be loaded.
#
# @param detail [Symbol] detail The level of detail to request.
# @return [Array] If the detail level is set to :name then an array of user nicknames.
# @return [Hash] If the detail level is set to :full then a hash of information about the
# users.
def list_users(detail = :name)
self.run("anope.listUsers", detail)
end
# Retrieves information about the specified user.
#
# Requires the rpc_data module to be loaded.
#
# @param name [String] The name of the user.
# @return [Hash] A hash containing information about the user.
def user(name)
self.run("anope.user", name)
end
# Sends a message to every user on the network.
#
# Requires the rpc_message module to be loaded.
#
# @param messages [Array<String>] One or more messages to send.
def message_network(*messages)
self.run("anope.messageNetwork", *messages)
end
# Sends a message to every user on the specified server.
#
# Requires the rpc_message module to be loaded.
#
# @param name [String] The name of the server.
# @param messages [Array<String>] One or more messages to send.
def message_server(server, *messages)
self.run("anope.messageServer", server, *messages)
end
# Sends a message to the specified user.
#
# Requires the rpc_message module to be loaded.
#
# @param source [String] The source pseudoclient to send the message from.
# @param target [String] The target user to send the message to.
# @param messages [Array<String>] One or more messages to send.
def message_user(source, target, *messages)
self.run("anope.messageUser", source, target, *messages)
end
# Checks whether the specified credentials are valid.
#
# Requires the rpc_user module to be loaded.
#
# @param account [String] A nickname belonging to the account to check.
# @param password [String] The password for the specified account.
# @return [Hash] A hash containing basic information about the account.
def check_credentials(account, password)
self.run("anope.checkCredentials", account, password)
end
# Identifies an IRC user to the specified account.
#
# Requires the rpc_user module to be loaded.
#
# @param account [String] Either an account identifier or nickname belonging to the account to
# identify to.
# @param password [String] The nickname of the IRC user to identify to the account.
def identify(account, user)
self.run("anope.identify", account, user)
end
# Lists all commands that exist on the network.
#
# Requires the rpc_user module to be loaded.
#
# @param services [Array<String>] The nicknames of the services to list commands for.
# @return [Hash] A hash containing information about the available commands.
def list_commands(*services)
self.run("anope.listCommands", *services)
end
# Lists all commands that exist on the network.
#
# Requires the rpc_user module to be loaded.
#
# @param account [String] If non-empty then the account to execute the command as.
# @param service [String] The service which the command exists on.
# @param command [Array<String>] The the command to execute and any parameters to pass to it.
# @return [Hash] A hash containing information about the available commands.
def command(account, service, *command)
self.run("anope.command", account, service, *command)
end
end
=begin
arpc = AnopeRPC.new("http://127.0.0.1:8080/jsonrpc")
begin
pp arpc.list_servers(:full)
rescue StandardError => err
STDERR.puts err
end
=end
+8 -2
View File
@@ -36,7 +36,7 @@ Retrieves information about the specified account.
Index | Description
----- | -----------
0 | A nickname belonging to the account.
0 | Either a nickname belonging to the account or an account identifier.
### Errors
@@ -414,6 +414,9 @@ account.display | string | The display nickname of the account.
account.opertype | string or null | The account's oper type or null if the account is not a services operator.
account.uniqueid | uint | The unique immutable identifier of the account.
address | string | The IP address the user is connecting from.
away | map or null | The user's away state or null if they are not away.
away.message | string | The away message specified by the user.
away.time | int | The UNIX time at which the user went away.
channels | array[string] | The channels that the user is in prefixed by their status mode prefixes.
chost | string or null | The cloaked hostname of the user or null if they have no cloak.
fingerprint | string or null | The fingerprint of the user's client certificate or null if they are not using one.
@@ -425,6 +428,7 @@ nickchanged | int | The time at which the user last changed thei
real | string | The real name of the user.
server | string | The server that the user is connected to.
signon | int | The time at which the user connected to the network.
tls | bool | Whether the user is connected using TLS (SSL).
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.
@@ -438,7 +442,8 @@ vident | string or null | The virtual ident (username) of the user or
"opertype": "Services Root",
"uniqueid": "17183514657819486040"
},
"address": "127.0.0.1",
"address": "127.0.0.1",
"away": null,
"channels": ["@#chan1", "#chan2"],
"chost": "localhost",
"fingerprint": null,
@@ -451,6 +456,7 @@ vident | string or null | The virtual ident (username) of the user or
"real": "An IRC User",
"server": "irc.example.com",
"signon": 1740408296,
"tls": true,
"vhost": "staff.example.com",
"vident": null,
}
+175
View File
@@ -0,0 +1,175 @@
# Anope `rpc_user` RPC interface
## `anope.checkCredentials`
Checks whether the specified credentials are valid.
### Parameters
Index | Description
----- | -----------
0 | A nickname belonging to the account to check.
1 | The password for the specified account.
### Errors
Code | Description
------ | -----------
-32099 | The specified account does not exist.
-32098 | The specified password is not correct.
-32097 | The specified account is suspended.
### Result
Returns a map containing basic information about the account. More information about the account can be found by calling [the `anope.account` event using the value from the `uniqueid` field (requires the rpc_data module)](./rpc_user.md).
Key | Type | Description
--- | ---- | -----------
account | string | The display nickname of the account.
confirmed | boolean | Whether the account has been confirmed.
uniqueid | uint | The unique immutable identifier of the account.
#### Example
```json
{
"account": "foo",
"confirmed": true,
"uniqueid": 11085415958920757000,
}
```
## `anope.identify`
Identifies an IRC user to the specified account.
### Parameters
Index | Description
----- | -----------
0 | Either an account identifier or nickname belonging to the account to identify to.
1 | The nickname of the IRC user to identify to the account.
### Errors
Code | Description
------ | -----------
-32099 | The specified account does not exist.
-32098 | The specified IRC user does not exist.
### Result
This procedure returns no result.
## `anope.listCommands`
Lists all commands that exist on the network.
### Parameters
Index | Description
----- | -----------
0...n | The nicknames of the services to list commands for. If none are specified then all commands are returned.
### Errors
Code | Description
------ | -----------
-32098 | The specified service does not exist.
### Result
Returns a map containing information about the available commands.
Key | Type | Description
--- | ---- | -----------
\* | map | A key-value map of services to the commands that exist on them.
\*.\* | string | A key-value map of commands to information about the commands.
\*.\*.group | string or null | The group that the command belongs to or null if the command is not grouped.
\*.\*.hidden | boolean | Whether the command is visible in the help output.
\*.\*.maxparams | uint or null | The maximum number of parameters that the command accepts or null if there is no limit.
\*.\*.minparams | uint | The minimum number of parameters that the command accepts.
\*.\*.permission | string or null | The services operator permission required to execute the command or null if no permissions are required.
\*.\*.requiresaccount | boolean | Whether a caller must be logged into an account to execute the command.
\*.\*.requiresuser | boolean | Whether an IRC user is required to execute the command.
#### Example
```json
{
"Global": {
"GLOBAL": {
"group": null,
"hidden": false,
"maxparams": 1,
"minparams": 0,
"permission": "global/global",
"requiresaccount": true,
"requiresuser": false
},
"HELP": {
"group": null,
"hidden": false,
"maxparams": null,
"minparams": 0,
"permission": null,
"requireaccount": false,
"requireuser": false
},
"QUEUE": {
"group": null,
"hidden": false,
"maxparams": 2,
"minparams": 1,
"permission": "global/queue",
"requireaccount": true,
"requireuser": false
},
"SERVER": {
"group": null,
"hidden": false,
"maxparams": 2,
"minparams": 1,
"permission": "global/server",
"requireaccount": true,
"requireuser": false
}
}
}
```
## `anope.commands`
Executes the specified command.
### Parameters
Index | Description
----- | -----------
0 | If non-empty then the account to execute the command as.
1 | The service which the command exists on.
2...n | The the command to execute and any parameters to pass to it.
### Errors
Code | Description
------ | -----------
-32099 | The specified account does not exist.
-32098 | The specified service does not exist.
-32097 | The specified command does not exist.
### Result
Returns an array of messages returned by the command.
#### Example
```json
[
"Global commands:",
" GLOBAL Send a message to all users",
" HELP Displays this list and give information about commands",
" QUEUE Manages your pending message queue.",
" SERVER Send a message to all users on a server"
]
```
+1 -1
View File
@@ -79,7 +79,7 @@ public:
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
void Serialize(Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
+11 -12
View File
@@ -37,7 +37,7 @@ public:
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
void Serialize(Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
@@ -48,11 +48,10 @@ private:
public:
Anope::string nick;
Anope::string last_quit;
Anope::string last_realname;
/* Last usermask this nick was seen on, eg user@host */
Anope::string last_usermask;
/* Last uncloaked usermask, requires nickserv/auspex to see */
Anope::string last_realhost;
/* Last cloaked user@host this nick was seen using. */
Anope::string last_userhost;
/* Last real user@host this nick was seen using. */
Anope::string last_userhost_real;
time_t registered = Anope::CurTime;
time_t last_seen = Anope::CurTime;
@@ -113,7 +112,7 @@ public:
* @return the nick, if found
*/
static NickAlias *Find(const Anope::string &nick);
static NickAlias *FindId(uint64_t id);
static NickAlias *FindId(uint64_t uid);
};
/* A registered account. Each account must have a NickAlias with the same nick as the
@@ -129,7 +128,7 @@ public:
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
void Serialize(Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
@@ -137,7 +136,7 @@ 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. */
uint64_t id;
uint64_t uniqueid;
public:
/* Name of the account. Find(display)->nc == this. */
Anope::string display;
@@ -151,7 +150,7 @@ public:
/* The time this account was registered */
time_t registered = Anope::CurTime;
MemoInfo memos;
std::map<Anope::string, Anope::string> last_modes;
std::map<Anope::string, ModeData> last_modes;
/* Nicknames registered that are grouped to this account.
* for n in aliases, n->nc == this.
@@ -164,7 +163,7 @@ public:
/* Unsaved data */
/** The display nick for this account. */
NickAlias *na = nullptr;
Serialize::Reference<NickAlias> na;
/* Number of channels registered by this account */
uint16_t channelcount = 0;
/* Users online now logged into this account */
@@ -195,7 +194,7 @@ public:
* @return The account, if it exists
*/
static NickCore *Find(const Anope::string &nick);
static NickCore *FindId(uint64_t id);
static NickCore *FindId(uint64_t uid);
void AddChannelReference(ChannelInfo *ci);
void RemoveChannelReference(ChannelInfo *ci);
+6 -79
View File
@@ -14,6 +14,7 @@
#include <signal.h>
#include "hashcomp.h"
#include "utfcpp/unchecked.h"
namespace Anope
{
@@ -129,6 +130,7 @@ namespace Anope
* Returns the string's length.
*/
inline size_type length() const { return this->_string.length(); }
inline size_type utf8length() const { return utf8::unchecked::distance(str().begin(), str().end()); }
/**
* Returns the size of the currently allocated storage space in the string object.
@@ -379,11 +381,11 @@ namespace Anope
/** The debug level we are running at.
*/
extern CoreExport int Debug;
extern CoreExport unsigned Debug;
/** Other command line options.
*/
extern CoreExport bool ReadOnly, NoFork, NoThird, NoPID, NoExpire, ProtocolDebug;
extern CoreExport bool ReadOnly, NoFork, NoThird, NoDB, NoPID, NoExpire, ProtocolDebug;
/** The root of the Anope installation. Usually ~/anope
*/
@@ -463,33 +465,12 @@ namespace Anope
extern CoreExport void Unhex(const string &src, string &dest);
extern CoreExport void Unhex(const string &src, char *dest, size_t sz);
/** Base 64 encode a string
* @param src The string to encode
* @param target Where the encoded string is placed
*/
extern CoreExport void B64Encode(const string &src, string &target);
/** Base 64 decode a string
* @param src The base64 encoded string
* @param target The plain text result
*/
extern CoreExport void B64Decode(const string &src, string &target);
/** Encrypts what is in 'src' to 'dest'
* @param src The source string to encrypt
* @param dest The destination where the encrypted string is placed
*/
extern CoreExport bool Encrypt(const Anope::string &src, Anope::string &dest);
/** Returns a sequence of data formatted as the format argument specifies.
** After the format parameter, the function expects at least as many
** additional arguments as specified in format.
* @param fmt Format of the Message
* @param ... any number of parameters
* @return a Anope::string
*/
extern CoreExport string printf(const char *fmt, ...) ATTR_FORMAT(1, 2);
/** Return the last error code
* @return The error code
*/
@@ -513,9 +494,10 @@ namespace Anope
/** Retrieves a human readable string representing the time in seconds
* @param seconds The time on seconds, eg 60
* @param nc The account to use language settings for to translate this string, if applicable
* @param round Whether to round the duration to produce a shorter output.
* @return A human readable string, eg "1 minute"
*/
extern CoreExport Anope::string Duration(time_t seconds, const NickCore *nc = NULL);
extern CoreExport Anope::string Duration(time_t seconds, const NickCore *nc = nullptr, bool round = false);
/** Generates a human readable string of type "expires in ..."
* @param expires time in seconds
@@ -531,12 +513,6 @@ namespace Anope
*/
extern CoreExport Anope::string strftime(time_t t, const NickCore *nc = NULL, bool short_output = false);
/** Normalize buffer, stripping control characters and colors
* @param A string to be parsed for control and color codes
* @return A string stripped of control and color codes
*/
extern CoreExport Anope::string NormalizeBuffer(const Anope::string &);
/** Parses a raw message from the uplink and calls its command handler.
* @param message Raw message from the uplink
*/
@@ -572,57 +548,8 @@ namespace Anope
/** Generate a random number. */
extern CoreExport int RandomNumber();
/** Calculates the levenshtein distance between two strings.
* @param s1 The first string.
* @param s2 The second string.
*/
extern CoreExport size_t Distance(const Anope::string &s1, const Anope::string &s2);
/** Update the current time. */
extern CoreExport void UpdateTime();
/** Expands a path fragment that is relative to the base directory.
* @param base The base directory that it is relative to.
* @param fragment The fragment to expand.
*/
extern CoreExport Anope::string Expand(const Anope::string &base, const Anope::string &fragment);
/** Expands a config path. */
inline auto ExpandConfig(const Anope::string &path) { return Expand(ConfigDir, path); }
/** Expands a data path. */
inline auto ExpandData(const Anope::string &path) { return Expand(DataDir, path); }
/** Expands a locale path. */
inline auto ExpandLocale(const Anope::string &path) { return Expand(LocaleDir, path); }
/** Expands a log path. */
inline auto ExpandLog(const Anope::string &path) { return Expand(LogDir, path); }
/** Expands a module path. */
inline auto ExpandModule(const Anope::string &path) { return Expand(ModuleDir, path); }
/** Formats a CTCP message for sending to a client.
* @param name The name of the CTCP.
* @param body If present then the body of the CTCP.
* @return A formatted CTCP ready to send to a client.
*/
extern CoreExport Anope::string FormatCTCP(const Anope::string &name, const Anope::string &body = "");
/** Parses a CTCP message received from a client.
* @param text The raw message to parse.
* @param name The location to store the name of the CTCP.
* @param body The location to store body of the CTCP if one is present.
* @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.
+3 -1
View File
@@ -28,7 +28,7 @@ public:
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
void Serialize(Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
@@ -41,6 +41,8 @@ public:
time_t lastmsg;
/* Map of actual command names -> service name/permission required */
CommandInfo::map commands;
/** CTCP responses this bot can send. */
Anope::map<std::function<void(BotInfo *, User *, const Anope::string &)>> ctcps;
/* The server-side alias used to message this bot. */
Anope::string alias;
/* Modes the bot should have as configured in service:modes */
+7 -7
View File
@@ -36,7 +36,7 @@ class CoreExport Channel final
static std::vector<Channel *> deleting;
public:
typedef std::multimap<Anope::string, Anope::string> ModeList;
typedef std::multimap<Anope::string, ModeData> ModeList;
private:
/** A map of channel modes with their parameters set on this channel
*/
@@ -148,10 +148,10 @@ public:
/** Set a mode internally on a channel, this is not sent out to the IRCd
* @param setter The setter
* @param cm The mode
* @param param The param
* @param data Data about the mode.
* @param enforce_mlock true if mlocks should be enforced, false to override mlock
*/
void SetModeInternal(MessageSource &source, ChannelMode *cm, const Anope::string &param = "", bool enforce_mlock = true);
void SetModeInternal(MessageSource &source, ChannelMode *cm, const ModeData &data = {}, bool enforce_mlock = true);
/** Remove a mode internally on a channel, this is not sent out to the IRCd
* @param setter The Setter
@@ -164,19 +164,19 @@ public:
/** Set a mode on a channel
* @param bi The client setting the modes
* @param cm The mode
* @param param Optional param arg for the mode
* @param data Data about the mode
* @param enforce_mlock true if mlocks should be enforced, false to override mlock
*/
void SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string &param = "", bool enforce_mlock = true);
void SetMode(BotInfo *bi, ChannelMode *cm, const ModeData &data = {}, bool enforce_mlock = true);
/**
* Set a mode on a channel
* @param bi The client setting the modes
* @param name The mode name
* @param param Optional param arg for the mode
* @param data Data about the mode
* @param enforce_mlock true if mlocks should be enforced, false to override mlock
*/
void SetMode(BotInfo *bi, const Anope::string &name, const Anope::string &param = "", bool enforce_mlock = true);
void SetMode(BotInfo *bi, const Anope::string &name, const ModeData &data = {}, bool enforce_mlock = true);
/** Remove a mode from a channel
* @param bi The client setting the modes
+10 -8
View File
@@ -32,10 +32,12 @@ struct CommandInfo final
Anope::string permission;
/* Group this command is in */
Anope::string group;
/* whether or not to hide this command in help output */
/* Whether to hide this command in help and suggestions */
bool hide = false;
/* Only used with fantasy */
/* Whether to prepend the channel name (only used with fantasy) */
bool prepend_channel = false;
/* Whether to require the FANTASY privilege (only used with fantasy) */
bool require_privilege = true;
};
/* Where the replies from commands go to. User inherits from this and is the normal
@@ -99,9 +101,9 @@ class CoreExport Command
Anope::string desc;
std::vector<std::pair<Anope::string, std::function<bool(CommandSource&)>>> syntax;
/* Allow unregistered users to use this command */
bool allow_unregistered;
bool allow_unregistered = false;
/* Command requires that a user is executing it */
bool require_user;
bool require_user = false;
public:
/* Maximum parameters accepted by this command */
@@ -136,8 +138,8 @@ protected:
void RequireUser(bool b);
public:
bool AllowUnregistered() const;
bool RequireUser() const;
inline bool AllowUnregistered() const { return this->allow_unregistered; }
inline bool RequireUser() const { return this->require_user; }
/** Get the command description
* @param source The source wanting the command description
@@ -173,9 +175,9 @@ public:
* @param source The source of the command
* @param message The full message to run, the command is at the beginning of the message
*/
static void Run(CommandSource &source, const Anope::string &message);
static bool Run(CommandSource &source, const Anope::string &message);
void Run(CommandSource &source, const Anope::string &, const CommandInfo &, std::vector<Anope::string> &params);
bool Run(CommandSource &source, const Anope::string &, const CommandInfo &, std::vector<Anope::string> &params);
/** Looks up a command name from the service name.
* Note that if the same command exists multiple places this will return the first one encountered
+1
View File
@@ -19,6 +19,7 @@ class ChanAccess;
class Channel;
class ChannelInfo;
class ChannelStatus;
struct ModeData;
struct ChanUserContainer;
class ClientSocket;
class Command;
+1 -7
View File
@@ -102,7 +102,7 @@ namespace Language
/* Commonly used language strings */
#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\002 for more information.")
#define MORE_INFO _("Type \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.")
@@ -114,7 +114,6 @@ namespace Language
"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.")
#define NICK_X_NOT_REGISTERED _("Nick \002%s\002 isn't registered.")
#define NICK_X_NOT_IN_USE _("Nick \002%s\002 isn't currently in use.")
#define NICK_X_NOT_ON_CHAN _("\002%s\002 is not currently on channel %s.")
@@ -127,14 +126,9 @@ 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 " \
"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.")
#define NICK_ALREADY_REGISTERED _("Nickname \002%s\002 is already registered!")
#define NICK_SET_DISPLAY_CHANGED _("The new display is now \002%s\002.")
#define NICK_CONFIRM_INVALID _("Invalid passcode has been entered, please check the email again, and retry.")
#define CHAN_NOT_ALLOWED_TO_JOIN _("You are not permitted to be on this channel.")
#define CHAN_X_INVALID _("Channel %s is not a valid channel.")
#define CHAN_REACHED_CHANNEL_LIMIT _("Sorry, you have already reached your limit of \002%d\002 channels.")
-32
View File
@@ -57,35 +57,3 @@ public:
*/
virtual bool InvalidRange(const Anope::string &list);
};
/** This class handles formatting LIST/VIEW replies.
*/
class CoreExport ListFormatter final
{
public:
typedef std::map<Anope::string, Anope::string> ListEntry;
private:
NickCore *nc;
std::vector<Anope::string> columns;
std::vector<ListEntry> entries;
public:
ListFormatter(NickCore *nc);
ListFormatter &AddColumn(const Anope::string &name);
void AddEntry(const ListEntry &entry);
bool IsEmpty() const;
void Process(std::vector<Anope::string> &);
};
/** This class handles formatting INFO replies
*/
class CoreExport InfoFormatter final
{
NickCore *nc;
std::vector<std::pair<Anope::string, Anope::string> > replies;
unsigned longest = 0;
public:
InfoFormatter(NickCore *nc);
void Process(std::vector<Anope::string> &);
Anope::string &operator[](const Anope::string &key);
void AddOption(const Anope::string &opt);
};
+1 -1
View File
@@ -22,7 +22,7 @@ public:
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
void Serialize(Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
+34 -14
View File
@@ -33,6 +33,20 @@ enum ModeClass
MC_USER
};
struct ModeData final
{
Anope::string value;
Anope::string set_by;
time_t set_at;
ModeData(const Anope::string &v = "", const Anope::string &s = "", time_t t = 0)
: value(v)
, set_by(s)
, set_at(t)
{
}
};
/** This class is the basis of all modes in Anope
*/
class CoreExport Mode
@@ -56,11 +70,6 @@ public:
*/
Mode(const Anope::string &mname, ModeClass mclass, char mc, ModeType type);
virtual ~Mode() = default;
/** Can a user set this mode, used for mlock
* @param u The user
*/
virtual bool CanSet(User *u) const;
};
/** This class is a user mode, all user modes use this/inherit from this
@@ -74,6 +83,12 @@ public:
* @param mc The mode char
*/
UserMode(const Anope::string &name, char mc);
/** Can a user set this mode, used for mlock
* @param source The user who is setting the mode.
* @param target The user the mode is being set on.
*/
virtual bool CanSet(User *source, User *target) const { return true; }
};
class CoreExport UserModeParam
@@ -108,7 +123,11 @@ public:
*/
ChannelMode(const Anope::string &name, char mc);
bool CanSet(User *u) const override;
/** Can a user set this mode, used for mlock
* @param u The user who is setting the mode.
* @param c The channel the mode is being set on.
*/
virtual bool CanSet(User *u, Channel *c) const;
virtual void Check() { }
@@ -256,7 +275,7 @@ class CoreExport UserModeOperOnly
public:
UserModeOperOnly(const Anope::string &mname, char um) : UserMode(mname, um) { }
bool CanSet(User *u) const override;
bool CanSet(User *source, User *target) const override;
};
class CoreExport UserModeNoone
@@ -265,7 +284,7 @@ class CoreExport UserModeNoone
public:
UserModeNoone(const Anope::string &mname, char um) : UserMode(mname, um) { }
bool CanSet(User *u) const override;
bool CanSet(User *source, User *target) const override;
};
/** Channel mode +k (key)
@@ -288,7 +307,7 @@ public:
ChannelModeOperOnly(const Anope::string &mname, char mc) : ChannelMode(mname, mc) { }
/* Opers only */
bool CanSet(User *u) const override;
bool CanSet(User *u, Channel *c) const override;
};
/** This class is used for channel modes only servers may set
@@ -299,7 +318,7 @@ class CoreExport ChannelModeNoone
public:
ChannelModeNoone(const Anope::string &mname, char mc) : ChannelMode(mname, mc) { }
bool CanSet(User *u) const override;
bool CanSet(User *u, Channel *c) const override;
};
/** This is the mode manager
@@ -311,6 +330,7 @@ public:
class CoreExport ModeManager final
{
public:
using Change = std::multimap<Mode *, std::pair<bool, ModeData>>;
/* Number of generic channel and user modes we are tracking */
static unsigned GenericChannelModes;
@@ -378,18 +398,18 @@ public:
* @param c The channel
* @param cm The channel mode
* @param set true for setting, false for removing
* @param param The param, if there is one
* @param data Data about the mode.
*/
static void StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool set, const Anope::string &param = "");
static void StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool set, const ModeData &data = {});
/** Add a mode to the stacker to be set on a user
* @param bi The client to set the modes from
* @param u The user
* @param um The user mode
* @param set true for setting, false for removing
* @param param The param, if there is one
* @param data Data about the mode.
*/
static void StackerAdd(BotInfo *bi, User *u, UserMode *um, bool set, const Anope::string &param = "");
static void StackerAdd(BotInfo *bi, User *u, UserMode *um, bool set, const ModeData &data = {});
/** Process all of the modes in the stacker and send them to the IRCd to be set on channels/users
*/
+1
View File
@@ -39,6 +39,7 @@
#include "services.h"
#include "socketengine.h"
#include "sockets.h"
#include "textproc.h"
#include "threadengine.h"
#include "timers.h"
#include "uplink.h"
+9 -5
View File
@@ -158,7 +158,9 @@ enum
PSEUDOCLIENT = 1 << 5,
/* Module provides IRCd protocol support */
PROTOCOL = 1 << 6,
MT_END = 1 << 7
/* Module is deprecated */
DEPRECATED = 1 << 7,
MT_END = DEPRECATED,
};
typedef unsigned short ModType;
@@ -871,10 +873,10 @@ public:
* @param c The channel
* @param setter The user or server that is setting the mode
* @param mode The mode
* @param param The mode param, if there is one
* @param data Data about the mode.
* @return EVENT_STOP to make mlock/secureops etc checks not happen
*/
virtual EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) ATTR_NOT_NULL(2, 4) { throw NotImplementedException(); }
virtual EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) ATTR_NOT_NULL(2, 4) { throw NotImplementedException(); }
/** Called when a mode is unset on a channel
* @param c The channel
@@ -1046,9 +1048,10 @@ public:
/** Called to determine if a channel mode can be set by a user
* @param u The user
* @param c The channel
* @param cm The mode
*/
virtual EventReturn OnCanSet(User *u, const ChannelMode *cm) ATTR_NOT_NULL(2, 3) { throw NotImplementedException(); }
virtual EventReturn OnCanSet(User *u, Channel *c, const ChannelMode *cm) ATTR_NOT_NULL(2, 3) { throw NotImplementedException(); }
virtual EventReturn OnCheckDelete(Channel *c) ATTR_NOT_NULL(2) { throw NotImplementedException(); }
@@ -1245,9 +1248,10 @@ public:
/** Find the first module of a certain type
* @param type The module type
* @param ignoredeprecated Whether to ignore deprecated modules.
* @return The module
*/
static Module *FindFirstOf(ModType type);
static Module *FindFirstOf(ModType type, bool ignoredeprecated = false);
/** Checks whether this version of Anope is at least major.minor.patch.build
* Throws a ModuleException if not
+18
View File
@@ -11,6 +11,8 @@
#pragma once
#include <memory>
namespace DNS
{
/** Valid query types
@@ -29,8 +31,12 @@ namespace DNS
QUERY_SOA = 6,
/* Reverse DNS lookup */
QUERY_PTR = 12,
/* TXT lookup */
QUERY_TXT = 16,
/* IPv6 AAAA lookup */
QUERY_AAAA = 28,
/** SRV lookup */
QUERY_SRV = 33,
/* Zone transfer */
QUERY_AXFR = 252,
/* A lookup for any record */
@@ -88,11 +94,23 @@ namespace DNS
};
};
namespace Record
{
struct SRV final
{
uint16_t priority = UINT16_MAX;
uint16_t weight = 0;
uint16_t port = 0;
Anope::string host;
};
}
struct ResourceRecord final
: Question
{
unsigned int ttl = 0;
Anope::string rdata;
std::shared_ptr<void> rdataobj;
time_t created;
ResourceRecord(const Anope::string &n, QueryType t, unsigned short c = 1) : Question(n, t, c), created(Anope::CurTime) { }
+2
View File
@@ -18,6 +18,8 @@ public:
Anope::string ident;
Anope::string host;
time_t time = 0;
Anope::string validation_token;
time_t last_validation = 0;
virtual ~HostRequest() = default;
};
+59 -34
View File
@@ -8,28 +8,39 @@
#pragma once
enum HTTPError
namespace HTTP
{
HTTP_ERROR_OK = 200,
HTTP_FOUND = 302,
HTTP_BAD_REQUEST = 400,
HTTP_PAGE_NOT_FOUND = 404,
HTTP_NOT_SUPPORTED = 505
};
struct Reply;
struct Message;
class Page;
class Client;
class Provider;
enum Error
{
OK = 200,
FOUND = 302,
BAD_REQUEST = 400,
PAGE_NOT_FOUND = 404,
NOT_SUPPORTED = 505,
};
}
/* A message to someone */
struct HTTPReply final
struct HTTP::Reply final
{
HTTPError error = HTTP_ERROR_OK;
HTTP::Error error = HTTP::OK;
Anope::string content_type;
std::map<Anope::string, Anope::string, ci::less> headers;
typedef std::list<std::pair<Anope::string, Anope::string> > cookie;
std::vector<cookie> cookies;
HTTPReply() = default;
HTTPReply &operator=(const HTTPReply &) = default;
Reply() = default;
Reply &operator=(const HTTP::Reply &) = default;
HTTPReply(const HTTPReply &other) : error(other.error), length(other.length)
Reply(const HTTP::Reply &other)
: error(other.error)
, length(other.length)
{
content_type = other.content_type;
headers = other.headers;
@@ -39,7 +50,7 @@ struct HTTPReply final
out.push_back(new Data(datum->buf, datum->len));
}
~HTTPReply()
~Reply()
{
for (const auto *datum : out)
delete datum;
@@ -81,26 +92,27 @@ struct HTTPReply final
};
/* A message from someone */
struct HTTPMessage final
struct HTTP::Message final
{
std::map<Anope::string, Anope::string> headers;
std::map<Anope::string, Anope::string> cookies;
std::map<Anope::string, Anope::string> get_data;
std::map<Anope::string, Anope::string> post_data;
std::map<Anope::string, Anope::string, ci::less> headers;
std::map<Anope::string, Anope::string, ci::less> cookies;
std::map<Anope::string, Anope::string, ci::less> get_data;
std::map<Anope::string, Anope::string, ci::less> post_data;
Anope::string content;
};
class HTTPClient;
class HTTPProvider;
class HTTPPage
class HTTP::Page
: public virtual Base
{
Anope::string url;
Anope::string content_type;
public:
HTTPPage(const Anope::string &u, const Anope::string &ct = "text/html") : url(u), content_type(ct) { }
Page(const Anope::string &u, const Anope::string &ct = "text/html")
: url(u)
, content_type(ct)
{
}
const Anope::string &GetURL() const { return this->url; }
@@ -113,10 +125,10 @@ public:
* @param The HTTP header sent from the client to request the page
* @param The HTTP header that will be sent back to the client
*/
virtual bool OnRequest(HTTPProvider *, const Anope::string &, HTTPClient *, HTTPMessage &, HTTPReply &) = 0;
virtual bool OnRequest(HTTP::Provider *, const Anope::string &, HTTP::Client *, HTTP::Message &, HTTP::Reply &) = 0;
};
class HTTPClient
class HTTP::Client
: public ClientSocket
, public BinarySocket
, public Base
@@ -128,18 +140,24 @@ protected:
}
public:
HTTPClient(ListenSocket *l, int f, const sockaddrs &a) : ClientSocket(l, a), BinarySocket() { }
Client(ListenSocket *l, int f, const sockaddrs &a)
: ClientSocket(l, a)
, BinarySocket()
{
}
virtual const Anope::string GetIP()
{
return this->clientaddr.addr();
}
virtual void SendError(HTTPError err, const Anope::string &msg) = 0;
virtual void SendReply(HTTPReply *) = 0;
virtual void SendError(HTTP::Error err, const Anope::string &msg) = 0;
virtual void SendReply(HTTP::Reply *) = 0;
};
class HTTPProvider
#define HTTP_PROVIDER "HTTP::Provider"
class HTTP::Provider
: public ListenSocket
, public Service
{
@@ -150,7 +168,14 @@ public:
std::vector<Anope::string> ext_ips;
std::vector<Anope::string> ext_headers;
HTTPProvider(Module *c, const Anope::string &n, const Anope::string &i, const unsigned short p, bool s) : ListenSocket(i, p, i.find(':') != Anope::string::npos), Service(c, "HTTPProvider", n), ip(i), port(p), ssl(s) { }
Provider(Module *c, const Anope::string &n, const Anope::string &i, const unsigned short p, bool s)
: ListenSocket(i, p, i.find(':') != Anope::string::npos)
, Service(c, HTTP_PROVIDER, n)
, ip(i)
, port(p)
, ssl(s)
{
}
const Anope::string &GetIP() const
{
@@ -167,12 +192,12 @@ public:
return this->ssl;
}
virtual bool RegisterPage(HTTPPage *page) = 0;
virtual void UnregisterPage(HTTPPage *page) = 0;
virtual HTTPPage *FindPage(const Anope::string &name) = 0;
virtual bool RegisterPage(HTTP::Page *page) = 0;
virtual void UnregisterPage(HTTP::Page *page) = 0;
virtual HTTP::Page *FindPage(const Anope::string &name) = 0;
};
namespace HTTPUtils
namespace HTTP
{
inline Anope::string URLDecode(const Anope::string &url)
{
+1 -1
View File
@@ -151,7 +151,7 @@ struct SASL::Session
if (u)
return u->GetMask();
if (!hostname.empty() && !ip.empty())
return Anope::printf("%s (%s)", hostname.c_str(), ip.c_str());
return Anope::Format("%s (%s)", hostname.c_str(), ip.c_str());
return "A user";
};
};
-7
View File
@@ -15,13 +15,6 @@ enum NewsType
NEWS_OPER
};
struct NewsMessages final
{
NewsType type;
Anope::string name;
const char *msgs[10];
};
struct NewsItem
: Serializable
{
+51 -3
View File
@@ -8,6 +8,7 @@
#pragma once
#include "encryption.h"
#include "httpd.h"
#include <variant>
@@ -19,6 +20,7 @@ namespace RPC
class Map;
class Request;
class ServiceInterface;
struct Token;
class Value;
/** Represents possible types of RPC value. */
@@ -146,9 +148,9 @@ public:
Anope::string name;
Anope::string id;
std::deque<Anope::string> data;
HTTPReply &reply;
HTTP::Reply &reply;
Request(HTTPReply &r)
Request(HTTP::Reply &r)
: reply(r)
{
}
@@ -186,18 +188,64 @@ public:
const auto &GetMinParams() const { return minparams; }
virtual bool Run(ServiceInterface *iface, HTTPClient *client, Request &request) = 0;
virtual bool Run(ServiceInterface *iface, HTTP::Client *client, Request &request) = 0;
};
struct RPC::Token final
{
std::vector<Anope::string> methods;
Anope::string token;
Anope::string token_hash;
};
class RPC::ServiceInterface
: public Service
{
private:
bool CompareToken(const RPC::Token &token, const Anope::string &rawtoken) const
{
if (token.token_hash.empty())
return token.token.equals_cs(rawtoken); // Plaintext token.
auto *service = Service::FindService("Encryption::Provider", token.token_hash);
if (!service)
return false; // Malformed hash.
auto *hashprov = static_cast<Encryption::Provider *>(service);
return hashprov->Compare(token.token, rawtoken);
}
public:
std::vector<Token> tokens;
ServiceInterface(Module *creator)
: Service(creator, "RPC::ServiceInterface", "rpc")
{
}
bool CanExecute(const Anope::string &header, const Anope::string &method) const
{
if (header.compare(0, 7, "Bearer ", 7) != 0)
return false; // No token provided.
auto rawtoken = Anope::B64Decode(header.substr(7));
for (const auto &token : tokens)
{
if (!CompareToken(token, rawtoken))
continue; // No valid token.
for (const auto &glob : token.methods)
{
if (glob[0] == '~' && Anope::Match(method, glob.substr(1)))
return false; // Negative match.
if (Anope::Match(method, glob))
return true; // Positive match.
}
}
return false; // No match.
}
virtual void Reply(Request &request) = 0;
};
+8 -12
View File
@@ -83,7 +83,7 @@ public:
/* Can we set vidents on users? */
bool CanSetVIdent = false;
/* Can we ban specific gecos from being used? */
/* Can we ban specific realname from being used? */
bool CanSNLine = false;
/* Can we ban specific nicknames from being used? */
@@ -131,11 +131,15 @@ public:
/* The maximum length of a username. */
size_t MaxUser = 0;
/* Retrieves the next free UID or SID */
virtual Anope::string UID_Retrieve();
virtual Anope::string SID_Retrieve();
/** Retrieves advice on what might be the problem when a link fails.
* @param advice The location to store the advice.
*/
virtual void GetLinkAdvice(std::vector<Anope::string> &advice) { }
/** Extracts a timestamp from a string. */
virtual time_t ExtractTimestamp(const Anope::string &str);
@@ -195,19 +199,11 @@ public:
*/
virtual void SendSVSKill(const MessageSource &source, User *user, const Anope::string &msg);
virtual void SendMode(const MessageSource &source, Channel *chan, const ModeManager::Change &change);
virtual void SendModeInternal(const MessageSource &source, Channel *chan, const Anope::string &modes, const std::vector<Anope::string> &values);
template <typename... Args>
void SendMode(const MessageSource &source, Channel *chan, const Anope::string &modes, Args &&...args)
{
SendModeInternal(source, chan, modes, { Anope::ToString(args)... });
}
virtual void SendMode(const MessageSource &source, User *u, const ModeManager::Change &change);
virtual void SendModeInternal(const MessageSource &source, User *u, const Anope::string &modes, const std::vector<Anope::string> &values);
template <typename... Args>
void SendMode(const MessageSource &source, User *u, const Anope::string &modes, Args &&...args)
{
SendModeInternal(source, u, modes, { Anope::ToString(args)... });
}
/** Introduces a client to the rest of the network
* @param u The client to introduce
+2 -2
View File
@@ -29,7 +29,7 @@ public:
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
void Serialize(Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
@@ -59,7 +59,7 @@ public:
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
void Serialize(Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
+17 -29
View File
@@ -216,7 +216,7 @@ public:
* 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;
virtual void Serialize(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
@@ -326,6 +326,18 @@ public:
this->ref->DelReference(this);
}
inline T *Get(bool update = true) const
{
if (!this->invalid)
{
if (this->ref && update)
this->ref->QueueUpdate(); // This can invalidate me
if (!this->invalid)
return this->ref;
}
return nullptr;
}
inline Reference<T>& operator=(const Reference<T> &other)
{
if (this != &other)
@@ -349,42 +361,18 @@ public:
return false;
}
inline operator T*() const
inline operator T *() const
{
if (!this->invalid)
{
if (this->ref)
// This can invalidate me
this->ref->QueueUpdate();
if (!this->invalid)
return this->ref;
}
return NULL;
return Get(true);
}
inline T *operator*() const
{
if (!this->invalid)
{
if (this->ref)
// This can invalidate me
this->ref->QueueUpdate();
if (!this->invalid)
return this->ref;
}
return NULL;
return Get(true);
}
inline T *operator->() const
{
if (!this->invalid)
{
if (this->ref)
// This can invalidate me
this->ref->QueueUpdate();
if (!this->invalid)
return this->ref;
}
return NULL;
return Get(true);
}
};
+125
View File
@@ -11,6 +11,93 @@
#pragma once
#define ANOPE_FORMAT(LAST, FORMAT, BUFFER) \
do { \
va_list _valist; \
va_start(_valist, LAST); \
(BUFFER) = Anope::Format(_valist, (FORMAT)); \
va_end(_valist); \
} while (false);
namespace Anope
{
/** Encode a string as base-64.
* @param str The string to encode as base-64 .
*/
extern CoreExport Anope::string B64Encode(const Anope::string &str);
/** Decode a string from base-64.
* @param str The string to decode from base-64.
*/
extern CoreExport Anope::string B64Decode(const Anope::string &str);
/** Calculates the levenshtein distance between two strings.
* @param s1 The first string.
* @param s2 The second string.
*/
extern CoreExport size_t Distance(const Anope::string &s1, const Anope::string &s2);
/** Expands a path fragment that is relative to the base directory.
* @param base The base directory that it is relative to.
* @param fragment The fragment to expand.
*/
extern CoreExport Anope::string Expand(const Anope::string &base, const Anope::string &fragment);
/** Expands a config path. */
inline auto ExpandConfig(const Anope::string &path) { return Expand(ConfigDir, path); }
/** Expands a data path. */
inline auto ExpandData(const Anope::string &path) { return Expand(DataDir, path); }
/** Expands a locale path. */
inline auto ExpandLocale(const Anope::string &path) { return Expand(LocaleDir, path); }
/** Expands a log path. */
inline auto ExpandLog(const Anope::string &path) { return Expand(LogDir, path); }
/** Expands a module path. */
inline auto ExpandModule(const Anope::string &path) { return Expand(ModuleDir, path); }
/** Formats a string using one or more values. This uses snprintf internally but with a flexible buffer.
* @param fmt The message to format.
*/
extern CoreExport Anope::string Format(const char *fmt, ...) ATTR_FORMAT(1, 2);
/** Formats a string using a list of values. This uses snprintf internally but with a flexible buffer.
* @param valist A list of values to format the message with.
* @param fmt The message to format.
*/
extern CoreExport Anope::string Format(va_list &valist, const char *fmt) ATTR_FORMAT(2, 0);
/** Formats a CTCP message for sending to a client.
* @param name The name of the CTCP.
* @param body If present then the body of the CTCP.
* @return A formatted CTCP ready to send to a client.
*/
extern CoreExport Anope::string FormatCTCP(const Anope::string &name, const Anope::string &body = "");
/** Parses a CTCP message received from a client.
* @param text The raw message to parse.
* @param name The location to store the name of the CTCP.
* @param body The location to store body of the CTCP if one is present.
* @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);
/** Remove all formatting characters from a string.
* @param text A string containing formatting characters.
* @return A copy of \p text with all formatting characters removed.
*/
extern CoreExport Anope::string RemoveFormatting(const Anope::string &text);
/** 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);
}
class CoreExport HelpWrapper final
{
private:
@@ -22,6 +109,21 @@ public:
void SendTo(CommandSource &source);
};
class CoreExport InfoFormatter final
{
private:
size_t longest = 0;
NickCore *nc;
std::vector<Anope::string> options;
std::vector<std::pair<Anope::string, Anope::string>> replies;
public:
InfoFormatter(NickCore *nc);
Anope::string &operator[](const Anope::string &key);
void AddOption(const Anope::string &opt);
void SendTo(CommandSource &source);
};
class CoreExport LineWrapper final
{
private:
@@ -34,3 +136,26 @@ public:
bool GetLine(Anope::string &out);
};
class CoreExport ListFormatter final
{
public:
using ListEntry = std::map<Anope::string, Anope::string>;
using FlexibleFormatFn = std::function<Anope::string(ListEntry &)>;
private:
std::vector<Anope::string> columns;
std::vector<ListEntry> entries;
FlexibleFormatFn flexiblerow;
NickCore *nc;
void SendFixed(CommandSource &source);
void SendFlexible(CommandSource &source);
public:
ListFormatter(NickCore *nc);
ListFormatter &AddColumn(const Anope::string &name);
void AddEntry(const ListEntry &entry);
bool IsEmpty() const;
void SendTo(CommandSource &source);
void SetFlexible(const Anope::string &format);
void SetFlexible(const FlexibleFormatFn &formatter);
};
+21 -11
View File
@@ -23,8 +23,8 @@ typedef Anope::unordered_map<User *> user_map;
extern CoreExport user_map UserListByNick, UserListByUID;
extern CoreExport int OperCount;
extern CoreExport unsigned MaxUserCount;
extern CoreExport size_t OperCount;
extern CoreExport size_t MaxUserCount;
extern CoreExport time_t MaxUserTime;
/* Online user and channel data. */
@@ -39,7 +39,7 @@ class CoreExport User
static std::list<User *> quitting_users;
public:
typedef std::map<Anope::string, Anope::string> ModeList;
typedef std::map<Anope::string, ModeData> ModeList;
protected:
Anope::string vident;
Anope::string ident;
@@ -79,6 +79,10 @@ public: // XXX: exposing a tiny bit too much
time_t timestamp;
/* Is the user as super admin? */
bool super_admin;
/* The away message of the user */
Anope::string awaymsg;
/* The time the user went away */
time_t awaytime = 0;
/* Channels the user is in */
typedef std::map<Channel *, ChanUserContainer *> ChanUserList;
@@ -101,7 +105,7 @@ protected:
* @param svhost The vhost of the user
* @param sip The ip of the user
* @param sserver The server of the user
* @param srealname The realname/gecos of the user
* @param srealname The realname of the user
* @param ts User's timestamp
* @param smodes User's modes
* @param suid The unique identifier of the user.
@@ -249,9 +253,15 @@ public:
*/
bool HasPriv(const Anope::string &privstr);
/** Update the last usermask stored for a user. */
/** Update the last mask stored for a user. */
void UpdateHost();
/** Update the away state for a user. */
void SetAway(const Anope::string &msg = "", time_t ts = 0);
/** Determines whether this user is away. */
auto IsAway() const { return awaymsg.empty(); }
/** Check if the user has a mode
* @param name Mode name
* @return true or false
@@ -261,9 +271,9 @@ public:
/** Set a mode internally on the user, the IRCd is not informed
* @param setter who/what is setting the mode
* @param um The user mode
* @param Param The param, if there is one
* @param data Data about the mode.
*/
void SetModeInternal(const MessageSource &setter, UserMode *um, const Anope::string &param = "");
void SetModeInternal(const MessageSource &setter, UserMode *um, const ModeData &data = {});
/** Remove a mode internally on the user, the IRCd is not informed
* @param setter who/what is setting the mode
@@ -274,16 +284,16 @@ public:
/** Set a mode on the user
* @param bi The client setting the mode
* @param um The user mode
* @param Param Optional param for the mode
* @param data Data about the mode
*/
void SetMode(BotInfo *bi, UserMode *um, const Anope::string &param = "");
void SetMode(BotInfo *bi, UserMode *um, const ModeData &data = {});
/** Set a mode on the user
* @param bi The client setting the mode
* @param name The mode name
* @param Param Optional param for the mode
* @param data Data about the mode
*/
void SetMode(BotInfo *bi, const Anope::string &name, const Anope::string &param = "");
void SetMode(BotInfo *bi, const Anope::string &name, const ModeData &data = {});
/** Remove a mode on the user
* @param bi The client setting the mode
+1 -1
View File
@@ -21,7 +21,7 @@ public:
: public Serialize::Type
{
Type();
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
void Serialize(Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
+1 -1
View File
@@ -6607,7 +6607,7 @@ msgid "Service"
msgstr "Server gefunden: %d"
#, fuzzy, c-format
msgid "Service's hold on %s has been released."
msgid "Services' hold on %s has been released."
msgstr "Die Services haben den Nicknamen wieder verfügbar gemacht."
#, fuzzy
+1 -1
View File
@@ -6832,7 +6832,7 @@ msgid "Service"
msgstr "Τα services είναι ενεργά για %s"
#, fuzzy, c-format
msgid "Service's hold on %s has been released."
msgid "Services' hold on %s has been released."
msgstr "Οι υπηρεσίες απελευθέρωααν το ψευδώνυμό σου."
#, fuzzy
+497 -279
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6273,7 +6273,7 @@ msgid "Service"
msgstr "Servicio"
#, c-format
msgid "Service's hold on %s has been released."
msgid "Services' hold on %s has been released."
msgstr "El nick %s retenido por los servicios ha sido liberado."
#, fuzzy
+2 -2
View File
@@ -4412,7 +4412,7 @@ msgid "Last topic"
msgstr "Dernier topic"
msgid "Last used"
msgstr "Utilisé dernièrement"
msgstr "Dernière utilisation"
msgid "Last usermask"
msgstr "Dernier usermask"
@@ -6155,7 +6155,7 @@ msgid "Service"
msgstr "Service"
#, c-format
msgid "Service's hold on %s has been released."
msgid "Services' hold on %s has been released."
msgstr "La tutelle des Services sur %s a été enlevée."
msgid "Services Operator commands"
+1 -1
View File
@@ -6146,7 +6146,7 @@ msgid "Service"
msgstr "Servizio"
#, c-format
msgid "Service's hold on %s has been released."
msgid "Services' hold on %s has been released."
msgstr "Il blocco dei servizi sul nick %s è stato rilasciato."
msgid "Services Operator commands"
+1 -1
View File
@@ -6182,7 +6182,7 @@ msgid "Service"
msgstr "Service"
#, c-format
msgid "Service's hold on %s has been released."
msgid "Services' hold on %s has been released."
msgstr "Nick %s werd vrijgegeven."
msgid "Services Operator commands"
+1 -1
View File
@@ -6123,7 +6123,7 @@ msgid "Service"
msgstr "Usługa"
#, c-format
msgid "Service's hold on %s has been released."
msgid "Services' hold on %s has been released."
msgstr "Serwisy właśnie zwolniły nicka %s."
msgid "Services Operator commands"
+1 -1
View File
@@ -5675,7 +5675,7 @@ msgid "Service"
msgstr ""
#, c-format
msgid "Service's hold on %s has been released."
msgid "Services' hold on %s has been released."
msgstr ""
msgid "Services Operator commands"
+1627 -3622
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -83,7 +83,7 @@ public:
{
ChannelMode *cm = ModeManager::FindChannelModeByName("OP");
char symbol = cm ? anope_dynamic_static_cast<ChannelModeStatus *>(cm)->symbol : 0;
const auto message = Anope::printf("%s invited %s into the channel.", user->nick.c_str(), user->nick.c_str());
const auto message = Anope::Format("%s invited %s into the channel.", user->nick.c_str(), user->nick.c_str());
IRCD->SendNotice(bi, (symbol ? Anope::string(symbol) : "") + c->name, message);
}
@@ -196,15 +196,15 @@ public:
}
}
EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const Anope::string &param) override
EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const ModeData &data) 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))
{
BotInfo *bi = c->ci->bi;
Entry ban("BAN", param);
Entry ban("BAN", data.value);
if (ban.Matches(bi))
c->RemoveMode(bi, "BAN", param);
c->RemoveMode(bi, "BAN", data.value);
}
return EVENT_CONTINUE;
+49 -27
View File
@@ -12,6 +12,39 @@
#include "module.h"
#include "modules/botserv/badwords.h"
namespace
{
Anope::string TypeToString(BadWordType bw)
{
switch (bw)
{
case BW_ANY:
return "ANY";
case BW_SINGLE:
return "SINGLE";
case BW_START:
return "START";
case BW_END:
return "END";
}
return ""; // Should never happen.
}
BadWordType StringToType(const Anope::string &bw)
{
if (bw.equals_ci("ANY") || bw.equals_ci("0"))
return BW_ANY;
if (bw.equals_ci("SINGLE") || bw.equals_ci("1"))
return BW_SINGLE;
if (bw.equals_ci("START") || bw.equals_ci("2"))
return BW_START;
if (bw.equals_ci("END") || bw.equals_ci("3"))
return BW_END;
return BW_ANY; // Should never happen.
}
}
struct BadWordImpl final
: BadWord
, Serializable
@@ -28,12 +61,12 @@ struct BadWordTypeImpl final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(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);
data.Store("type", TypeToString(bw->type));
}
Serializable *Unserialize(Serializable *obj, Serialize::Data &) const override;
@@ -138,7 +171,7 @@ Serializable *BadWordTypeImpl::Unserialize(Serializable *obj, Serialize::Data &d
if (!ci)
return NULL;
unsigned int n;
Anope::string n;
data["type"] >> n;
BadWordImpl *bw;
@@ -148,7 +181,7 @@ Serializable *BadWordTypeImpl::Unserialize(Serializable *obj, Serialize::Data &d
bw = new BadWordImpl();
bw->chan = sci;
bw->word = sword;
bw->type = static_cast<BadWordType>(n);
bw->type = StringToType(n);
BadWordsImpl *bws = ci->Require<BadWordsImpl>("badwords");
if (!obj)
@@ -213,11 +246,12 @@ private:
{
bool override = !source.AccessFor(ci).HasPriv("BADWORDS");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "LIST";
ListFormatter list(source.GetAccount());
BadWords *bw = ci->GetExt<BadWords>("badwords");
list.AddColumn(_("Number")).AddColumn(_("Word")).AddColumn(_("Type"));
list.SetFlexible(_("{number}: \002{word}\002 -- type: {type}"));
BadWords *bw = ci->GetExt<BadWords>("badwords");
if (!bw || !bw->GetBadWordCount())
{
source.Reply(_("%s bad words list is empty."), ci->name.c_str());
@@ -244,7 +278,7 @@ private:
ListFormatter::ListEntry entry;
entry["Number"] = Anope::ToString(Number);
entry["Word"] = b->word;
entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : ""));
entry["Type"] = TypeToString(b->type);
this->list.AddEntry(entry);
}
}
@@ -263,7 +297,7 @@ private:
ListFormatter::ListEntry entry;
entry["Number"] = Anope::ToString(i + 1);
entry["Word"] = b->word;
entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : ""));
entry["Type"] = TypeToString(b->type);
list.AddEntry(entry);
}
}
@@ -272,14 +306,8 @@ private:
source.Reply(_("No matching entries on %s bad words list."), ci->name.c_str());
else
{
std::vector<Anope::string> replies;
list.Process(replies);
source.Reply(_("Bad words list for %s:"), ci->name.c_str());
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
source.Reply(_("End of bad words list."));
}
}
@@ -295,14 +323,7 @@ private:
{
Anope::string opt = word.substr(pos + 1);
if (!opt.empty())
{
if (opt.equals_ci("SINGLE"))
bwtype = BW_SINGLE;
else if (opt.equals_ci("START"))
bwtype = BW_START;
else if (opt.equals_ci("END"))
bwtype = BW_END;
}
bwtype = StringToType(opt);
realword = word.substr(0, pos);
}
@@ -460,15 +481,16 @@ public:
"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."
"be issued every time \037word\037 is said by a user. This "
"will be shown in the \002LIST\002 output as ANY."
"\n\n"
"The \002DEL\002 command removes the given word from the "
"bad words list. If a list of entry numbers is given, those "
"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 "
"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, "
"mask are displayed. If a list of entry numbers is given, "
"only those entries are shown; for example:\n"
" \002#channel\032LIST\0322-5,7-9\002\n"
" Lists bad words entries numbered 2 through 5 and\n"
+3 -9
View File
@@ -41,11 +41,11 @@ public:
}
}
unsigned count = 0;
ListFormatter list(source.GetAccount());
list.AddColumn(_("Nick")).AddColumn(_("Mask")).AddColumn(_("Real name"));
list.SetFlexible(_("\002{nick}\002 ({mask}) [{real_name}]"));
unsigned count = 0;
for (const auto &[_, bi] : *BotListByNick)
{
if (is_admin || !bi->oper_only)
@@ -66,9 +66,6 @@ public:
}
}
std::vector<Anope::string> replies;
list.Process(replies);
if (!count)
{
source.Reply(_(
@@ -79,10 +76,7 @@ public:
else
{
source.Reply(_("Bot list:"));
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
source.Reply(_("%d bots available."), count);
}
}
+4 -14
View File
@@ -55,15 +55,10 @@ public:
info[_("Real name")] = bi->realname;
info[_("Created")] = Anope::strftime(bi->created, source.GetAccount());
info[_("Options")] = bi->oper_only ? _("Private") : _("None");
info[_("Used on")] = Anope::printf(Language::Translate(source.nc, bi->GetChannelCount(), N_("%u channel", "%u channels")), bi->GetChannelCount());
info[_("Used on")] = Anope::Format(Language::Translate(source.nc, bi->GetChannelCount(), N_("%u channel", "%u channels")), bi->GetChannelCount());
FOREACH_MOD(OnBotInfo, (source, bi, ci, info));
std::vector<Anope::string> replies;
info.Process(replies);
for (const auto &reply : replies)
source.Reply(reply);
info.SendTo(source);
if (source.HasPriv("botserv/administration"))
{
@@ -89,12 +84,7 @@ public:
Anope::string disabled = Language::Translate(source.nc, _("Disabled"));
FOREACH_MOD(OnBotInfo, (source, bi, ci, info));
std::vector<Anope::string> replies;
info.Process(replies);
for (const auto &reply : replies)
source.Reply(reply);
info.SendTo(source);
}
else
source.Reply(_("\002%s\002 is not a valid bot or registered channel."), query.c_str());
@@ -116,7 +106,7 @@ public:
const Anope::string GetDesc(CommandSource &source) const override
{
return Anope::printf(Language::Translate(source.GetAccount(), _("Allows you to see %s information about a channel or a bot")), source.service->nick.c_str());
return Anope::Format(Language::Translate(source.GetAccount(), _("Allows you to see %s information about a channel or a bot")), source.service->nick.c_str());
}
};
+18 -22
View File
@@ -1112,18 +1112,14 @@ class BSKick final
static void bot_kick(ChannelInfo *ci, User *u, const char *message, ...) ATTR_FORMAT(3, 4)
{
va_list args;
char buf[1024];
if (!ci || !ci->bi || !ci->c || !u || u->IsProtected() || !ci->c->FindUser(u))
return;
Anope::string fmt = Language::Translate(u, message);
va_start(args, message);
vsnprintf(buf, sizeof(buf), fmt.c_str(), args);
va_end(args);
const auto *fmt = Language::Translate(u, message);
ci->c->Kick(ci->bi, u, Anope::string(buf));
Anope::string buf;
ANOPE_FORMAT(message, fmt, buf);
ci->c->Kick(ci->bi, u, buf);
}
public:
@@ -1157,7 +1153,7 @@ public:
if (kd && kd->badwords)
{
if (kd->ttb[TTB_BADWORDS])
info[_("Bad words kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BADWORDS]);
info[_("Bad words kicker")] = Anope::Format("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BADWORDS]);
else
info[_("Bad words kicker")] = enabled;
}
@@ -1167,7 +1163,7 @@ public:
if (kd && kd->bolds)
{
if (kd->ttb[TTB_BOLDS])
info[_("Bolds kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BOLDS]);
info[_("Bolds kicker")] = Anope::Format("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BOLDS]);
else
info[_("Bolds kicker")] = enabled;
}
@@ -1177,9 +1173,9 @@ public:
if (kd && kd->caps)
{
if (kd->ttb[TTB_CAPS])
info[_("Caps kicker")] = Anope::printf(_("%s (%d kick(s) to ban; minimum %d/%d%%)"), enabled.c_str(), kd->ttb[TTB_CAPS], kd->capsmin, kd->capspercent);
info[_("Caps kicker")] = Anope::Format(_("%s (%d kick(s) to ban; minimum %d/%d%%)"), enabled.c_str(), kd->ttb[TTB_CAPS], kd->capsmin, kd->capspercent);
else
info[_("Caps kicker")] = Anope::printf(_("%s (minimum %d/%d%%)"), enabled.c_str(), kd->capsmin, kd->capspercent);
info[_("Caps kicker")] = Anope::Format(_("%s (minimum %d/%d%%)"), enabled.c_str(), kd->capsmin, kd->capspercent);
}
else
info[_("Caps kicker")] = disabled;
@@ -1187,7 +1183,7 @@ public:
if (kd && kd->colors)
{
if (kd->ttb[TTB_COLORS])
info[_("Colors kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_COLORS]);
info[_("Colors kicker")] = Anope::Format(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_COLORS]);
else
info[_("Colors kicker")] = enabled;
}
@@ -1197,9 +1193,9 @@ public:
if (kd && kd->flood)
{
if (kd->ttb[TTB_FLOOD])
info[_("Flood kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d lines in %ds)"), enabled.c_str(), kd->ttb[TTB_FLOOD], kd->floodlines, kd->floodsecs);
info[_("Flood kicker")] = Anope::Format(_("%s (%d kick(s) to ban; %d lines in %ds)"), enabled.c_str(), kd->ttb[TTB_FLOOD], kd->floodlines, kd->floodsecs);
else
info[_("Flood kicker")] = Anope::printf(_("%s (%d lines in %ds)"), enabled.c_str(), kd->floodlines, kd->floodsecs);
info[_("Flood kicker")] = Anope::Format(_("%s (%d lines in %ds)"), enabled.c_str(), kd->floodlines, kd->floodsecs);
}
else
info[_("Flood kicker")] = disabled;
@@ -1207,9 +1203,9 @@ public:
if (kd && kd->repeat)
{
if (kd->ttb[TTB_REPEAT])
info[_("Repeat kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d times)"), enabled.c_str(), kd->ttb[TTB_REPEAT], kd->repeattimes);
info[_("Repeat kicker")] = Anope::Format(_("%s (%d kick(s) to ban; %d times)"), enabled.c_str(), kd->ttb[TTB_REPEAT], kd->repeattimes);
else
info[_("Repeat kicker")] = Anope::printf(_("%s (%d times)"), enabled.c_str(), kd->repeattimes);
info[_("Repeat kicker")] = Anope::Format(_("%s (%d times)"), enabled.c_str(), kd->repeattimes);
}
else
info[_("Repeat kicker")] = disabled;
@@ -1217,7 +1213,7 @@ public:
if (kd && kd->reverses)
{
if (kd->ttb[TTB_REVERSES])
info[_("Reverses kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_REVERSES]);
info[_("Reverses kicker")] = Anope::Format(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_REVERSES]);
else
info[_("Reverses kicker")] = enabled;
}
@@ -1227,7 +1223,7 @@ public:
if (kd && kd->underlines)
{
if (kd->ttb[TTB_UNDERLINES])
info[_("Underlines kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_UNDERLINES]);
info[_("Underlines kicker")] = Anope::Format(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_UNDERLINES]);
else
info[_("Underlines kicker")] = enabled;
}
@@ -1237,7 +1233,7 @@ public:
if (kd && kd->italics)
{
if (kd->ttb[TTB_ITALICS])
info[_("Italics kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_ITALICS]);
info[_("Italics kicker")] = Anope::Format(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_ITALICS]);
else
info[_("Italics kicker")] = enabled;
}
@@ -1247,7 +1243,7 @@ public:
if (kd && kd->amsgs)
{
if (kd->ttb[TTB_AMSGS])
info[_("AMSG kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_AMSGS]);
info[_("AMSG kicker")] = Anope::Format(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_AMSGS]);
else
info[_("AMSG kicker")] = enabled;
}
@@ -1369,7 +1365,7 @@ public:
BadWords *badwords = ci->GetExt<BadWords>("badwords");
/* Normalize the buffer */
Anope::string nbuf = Anope::NormalizeBuffer(realbuf);
Anope::string nbuf = Anope::RemoveFormatting(realbuf);
bool casesensitive = Config->GetModule("botserv").Get<bool>("casesensitive");
/* Normalize can return an empty string if this only contains control codes etc */
+2 -2
View File
@@ -173,7 +173,7 @@ class CommandBSSetPrivate final
public:
CommandBSSetPrivate(Module *creator, const Anope::string &sname = "botserv/set/private") : Command(creator, sname, 2, 2)
{
this->SetDesc(_("Prevent a bot from being assigned by non IRC operators"));
this->SetDesc(_("Prevent a bot from being assigned by non Services Operators"));
this->SetSyntax(_("\037botname\037 {\037ON|OFF\037}"));
}
@@ -214,7 +214,7 @@ public:
source.Reply(" ");
source.Reply(_(
"This option prevents a bot from being assigned to a "
"channel by users that aren't IRC Operators."
"channel by users that aren't Services Operators."
));
return true;
}
+5 -5
View File
@@ -154,7 +154,7 @@ public:
{
std::deque<ChannelInfo *> chans;
nc->GetChannelReferences(chans);
int max_reg = Config->GetModule(this).Get<int>("maxregistered");
auto max_reg = Config->GetModule(this).Get<uint16_t>("maxregistered");
for (auto *ci : chans)
{
@@ -309,7 +309,7 @@ public:
return;
if (c->ci)
c->SetMode(c->ci->WhoSends(), "REGISTERED", "", false);
c->SetMode(c->ci->WhoSends(), "REGISTERED", {}, false);
else
c->RemoveMode(c->WhoSends(), "REGISTERED", "", false);
@@ -330,7 +330,7 @@ public:
ci->Extend<bool>(def.upper());
}
EventReturn OnCanSet(User *u, const ChannelMode *cm) override
EventReturn OnCanSet(User *u, Channel *c, 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)
@@ -461,7 +461,7 @@ public:
}
}
EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) override
EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) override
{
if (!always_lower && Anope::CurTime == c->created && c->ci && setter.GetUser() && !setter.GetUser()->server->IsULined())
{
@@ -470,7 +470,7 @@ public:
if (cu && cm && !cu->status.HasMode(cm->mchar))
{
/* Our -o and their mode change crossing, bounce their mode */
c->RemoveMode(c->ci->WhoSends(), mode, param);
c->RemoveMode(c->ci->WhoSends(), mode, data.value);
/* We don't set mlocks until after the join has finished processing, it will stack with this change,
* so there isn't much for the user to remove except -nt etc which is likely locked anyway.
*/
+36 -35
View File
@@ -109,7 +109,7 @@ private:
entry["Number"] = Anope::ToString(number);
entry["Level"] = access->AccessSerialize();
entry["Mask"] = access->Mask();
entry["By"] = access->creator;
entry["Creator"] = access->creator;
entry["Last seen"] = timebuf;
entry["Description"] = access->description;
list.AddEntry(entry);
@@ -297,7 +297,7 @@ private:
ChannelInfo *ci;
Command *c;
unsigned deleted = 0;
Anope::string Nicks;
Anope::string nicks;
bool denied = false;
bool override = false;
public:
@@ -315,9 +315,9 @@ private:
source.Reply(_("No matching entries on %s access list."), ci->name.c_str());
else
{
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "to delete " << Nicks;
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "to delete " << nicks;
if (deleted == 1)
source.Reply(_("Deleted %s from %s access list."), Nicks.c_str(), ci->name.c_str());
source.Reply(_("Deleted %s from %s access list."), nicks.c_str(), ci->name.c_str());
else
source.Reply(deleted, N_("Deleted %d entry from %s access list.", "Deleted %d entries from %s access list."), deleted, ci->name.c_str());
@@ -341,10 +341,9 @@ private:
}
++deleted;
if (!Nicks.empty())
Nicks += ", " + access->Mask();
else
Nicks = access->Mask();
if (!nicks.empty())
nicks += ", ";
nicks += access->Mask();
ci->EraseAccess(Number - 1);
@@ -436,14 +435,8 @@ private:
source.Reply(_("No matching entries on %s access list."), ci->name.c_str());
else
{
std::vector<Anope::string> replies;
list.Process(replies);
source.Reply(_("Access list for %s:"), ci->name.c_str());
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
source.Reply(_("End of access list"));
}
@@ -460,6 +453,13 @@ private:
ListFormatter list(source.GetAccount());
list.AddColumn(_("Number")).AddColumn(_("Level")).AddColumn(_("Mask")).AddColumn(_("Description"));
list.SetFlexible([](ListFormatter::ListEntry &row)
{
return row["Description"].empty()
? _("{number}: \002{mask}\002 = {level}")
: _("{number}: \002{mask}\002 = {level} ({description})");
});
this->ProcessList(source, ci, params, list);
}
@@ -472,7 +472,14 @@ private:
}
ListFormatter list(source.GetAccount());
list.AddColumn(_("Number")).AddColumn(_("Level")).AddColumn(_("Mask")).AddColumn(_("By")).AddColumn(_("Last seen")).AddColumn(_("Description"));
list.AddColumn(_("Number")).AddColumn(_("Level")).AddColumn(_("Mask")).AddColumn(_("Creator")).AddColumn(_("Last seen")).AddColumn(_("Description"));
list.SetFlexible([](ListFormatter::ListEntry &row)
{
return row["Description"].empty()
? _("{number}: \002{mask}\002 = {level} -- created by {creator}; last seen {last_seen}")
: _("{number}: \002{mask}\002 = {level} -- created by {creator}; last seen {last_seen} ({description})");
});
this->ProcessList(source, ci, params, list);
}
@@ -569,9 +576,9 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Maintains the \002access list\002 for a channel. The access "
"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 "
"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 "
@@ -580,7 +587,7 @@ public:
"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 "
"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."
@@ -599,14 +606,14 @@ public:
source.Reply(" ");
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 "
"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 "
"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, "
"mask are displayed. If a list of entry numbers is given, "
"only those entries are shown; for example:\n"
" \002%s\032#channel\032LIST\0322-5,7-9\002\n"
" Lists access entries numbered 2 through 5 and\n"
@@ -672,7 +679,7 @@ class CommandCSLevels final
Privilege *p = PrivilegeManager::FindPrivilege(what);
if (p == NULL)
{
source.Reply(_("Setting \002%s\002 not known. Type \002%s\032LEVELS\002 for a list of valid settings."),
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
@@ -715,7 +722,7 @@ class CommandCSLevels final
return;
}
source.Reply(_("Setting \002%s\002 not known. Type \002%s\032LEVELS\002 for a list of valid settings."),
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());
}
@@ -725,6 +732,7 @@ class CommandCSLevels final
ListFormatter list(source.GetAccount());
list.AddColumn(_("Name")).AddColumn(_("Level"));
list.SetFlexible(_("\002{name}\002 = {level}"));
const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges();
@@ -745,11 +753,7 @@ class CommandCSLevels final
list.AddEntry(entry);
}
std::vector<Anope::string> replies;
list.Process(replies);
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
}
void DoReset(CommandSource &source, ChannelInfo *ci)
@@ -826,6 +830,7 @@ public:
ListFormatter list(source.GetAccount());
list.AddColumn(_("Name")).AddColumn(_("Description"));
list.SetFlexible(_("\002{name}\002: {description}"));
for (const auto &p : PrivilegeManager::GetPrivileges())
{
@@ -835,11 +840,7 @@ public:
list.AddEntry(entry);
}
std::vector<Anope::string> replies;
list.Process(replies);
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
}
else
{
@@ -847,7 +848,7 @@ public:
source.Reply(" ");
source.Reply(_(
"The \002%s\002 command allows fine control over the meaning of "
"the numeric access levels used for channels. With this "
"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)."
+21 -13
View File
@@ -141,7 +141,7 @@ class CommandCSAKick final
}
}
/* Match against the lastusermask of all nickalias's with equal
/* Match against the last mask of all nickalias's with equal
* or higher access. - Viper */
for (const auto &[_, na2] : *NickAliasList)
{
@@ -150,7 +150,7 @@ class CommandCSAKick final
AccessGroup nc_access = ci->AccessFor(na->nc), u_access = source.AccessFor(ci);
if (na->nc && (na->nc == ci->GetFounder() || nc_access >= u_access))
{
Anope::string buf = na->nick + "!" + na->last_usermask;
Anope::string buf = na->nick + "!" + na->last_userhost;
if (Anope::Match(buf, mask))
{
source.Reply(ACCESS_DENIED);
@@ -378,14 +378,8 @@ class CommandCSAKick final
source.Reply(_("No matching entries on %s autokick list."), ci->name.c_str());
else
{
std::vector<Anope::string> replies;
list.Process(replies);
source.Reply(_("Autokick list for %s:"), ci->name.c_str());
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
source.Reply(_("End of autokick list"));
}
}
@@ -400,6 +394,13 @@ class CommandCSAKick final
ListFormatter list(source.GetAccount());
list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("Reason"));
list.SetFlexible([](ListFormatter::ListEntry &row)
{
return row["Reason"].empty()
? _("{number}: \002{mask}\002")
: _("{number}: \002{mask}\002 ({reason})");
});
this->ProcessList(source, ci, params, list);
}
@@ -413,6 +414,13 @@ class CommandCSAKick final
ListFormatter list(source.GetAccount());
list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("Creator")).AddColumn(_("Created")).AddColumn(_("Last used")).AddColumn(_("Reason"));
list.SetFlexible([](ListFormatter::ListEntry &row)
{
return row["Reason"].empty()
? _("{number}: \002{mask}\002 -- added by {creator} on {created}; last used: {last_used}")
: _("{number}: \002{mask}\002 -- added by {creator} on {created}; last used: {last_used} ({reason})");
});
this->ProcessList(source, ci, params, list);
}
@@ -501,13 +509,13 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Maintains the \002AutoKick list\002 for a channel. If a user "
"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 \002%s\032ADD\002 command adds the given nick or mask "
"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\". "
@@ -516,7 +524,7 @@ public:
"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 "
"from the AutoKick list. It does not, however, remove any "
"bans placed by an AutoKick; those must be removed "
"manually."
"\n\n"
+34 -1
View File
@@ -13,6 +13,9 @@
static Module *me;
class TempBan;
static std::vector<TempBan *> tempbans;
class TempBan final
: public Timer
{
@@ -28,6 +31,21 @@ public:
, mask(banmask)
, mode(mod)
{
tempbans.push_back(this);
}
~TempBan()
{
auto it = std::find(tempbans.begin(), tempbans.end(), this);
if (it != tempbans.end())
tempbans.erase(it);
}
bool Matches(Channel *chan, ChannelMode *cmode, const Anope::string &bmask) const
{
return chan->name.equals_ci(this->channel)
&& cmode->name == this->mode
&& bmask == this->mask;
}
void Tick() override
@@ -258,10 +276,25 @@ class CSBan final
CommandCSBan commandcsban;
public:
CSBan(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandcsban(this)
CSBan(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandcsban(this)
{
me = this;
}
EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *cmode, const Anope::string &param) override
{
for (const auto *tempban : tempbans)
{
if (tempban->Matches(c, cmode, param))
{
delete tempban;
break;
}
}
return EVENT_CONTINUE;
}
};
MODULE_INIT(CSBan)
+3 -3
View File
@@ -55,7 +55,7 @@ public:
if (!code)
{
code = ci->Extend<Anope::string>("channel-dropcode");
*code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", 15));
*code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", "15"));
}
source.Reply(CONFIRM_DROP, ci->name.c_str(), source.service->GetQueryCommand("chanserv/drop").c_str(),
@@ -90,14 +90,14 @@ public:
if (source.IsServicesOper())
{
source.Reply(_(
"Unregisters the specified channel. Only \002Services Operators\002 "
"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 "
"Unregisters the named channel. Can only be used by "
"the \002channel founder\002."
));
}
+4 -6
View File
@@ -39,7 +39,7 @@ struct EntryMsgTypeImpl final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *msg = static_cast<const EntryMsgImpl *>(obj);
data.Store("ci", msg->chan);
@@ -128,6 +128,8 @@ private:
ListFormatter list(source.GetAccount());
list.AddColumn(_("Number")).AddColumn(_("Creator")).AddColumn(_("Created")).AddColumn(_("Message"));
list.SetFlexible(_("{number}: {message} -- created by {creator} at {created}"));
for (unsigned i = 0; i < (*messages)->size(); ++i)
{
EntryMsg *msg = (*messages)->at(i);
@@ -140,11 +142,7 @@ private:
list.AddEntry(entry);
}
std::vector<Anope::string> replies;
list.Process(replies);
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
source.Reply(_("End of entry message list."));
}
+7 -6
View File
@@ -309,8 +309,13 @@ class CommandCSFlags final
}
ListFormatter list(source.GetAccount());
list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("Flags")).AddColumn(_("Creator")).AddColumn(_("Created")).AddColumn(_("Description"));
list.SetFlexible([](ListFormatter::ListEntry &row)
{
return row["Description"].empty()
? _("{number}: \002{mask}\002 = {flags} -- added by {creator} at {created}")
: _("{number}: \002{mask}\002 = {flags} -- added by {creator} at {created} ({description})");
});
unsigned count = 0;
for (unsigned i = 0, end = ci->GetAccessCount(); i < end; ++i)
@@ -348,12 +353,8 @@ class CommandCSFlags final
source.Reply(_("No matching entries on %s access list."), ci->name.c_str());
else
{
std::vector<Anope::string> replies;
list.Process(replies);
source.Reply(_("Flags list for %s"), ci->name.c_str());
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
if (count == ci->GetAccessCount())
source.Reply(_("End of access list."));
else
+1 -6
View File
@@ -62,12 +62,7 @@ public:
}
FOREACH_MOD(OnChanInfo, (source, ci, info, show_all));
std::vector<Anope::string> replies;
info.Process(replies);
for (const auto &reply : replies)
source.Reply(reply);
info.SendTo(source);
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
+7 -6
View File
@@ -76,6 +76,12 @@ public:
ListFormatter list(source.GetAccount());
list.AddColumn(_("Name")).AddColumn(_("Description"));
list.SetFlexible([](ListFormatter::ListEntry &row)
{
return row["Description"].empty()
? _("\002{name}\002")
: _("\002{name}\002 ({description})");
});
Anope::map<ChannelInfo *> ordered_map;
for (const auto &[cname, ci] : *RegisteredChannelList)
@@ -122,12 +128,7 @@ public:
}
}
std::vector<Anope::string> replies;
list.Process(replies);
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
source.Reply(_("End of list - %d/%d matches shown."), nchans > listmax ? listmax : nchans, nchans);
}
+6 -11
View File
@@ -44,7 +44,7 @@ struct LogSettingTypeImpl final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *ls = static_cast<const LogSettingImpl *>(obj);
data.Store("ci", ls->chan);
@@ -138,7 +138,8 @@ public:
else
{
ListFormatter list(source.GetAccount());
list.AddColumn(_("Number")).AddColumn(_("Service")).AddColumn(_("Command")).AddColumn(_("Method")).AddColumn("");
list.AddColumn(_("Number")).AddColumn(_("Service")).AddColumn(_("Command")).AddColumn(_("Method"));
list.SetFlexible(_("{number}: {command} on {service}: {method}"));
for (unsigned i = 0; i < (*ls)->size(); ++i)
{
@@ -147,19 +148,13 @@ public:
ListFormatter::ListEntry entry;
entry["Number"] = Anope::ToString(i + 1);
entry["Service"] = log->command_service;
entry["Command"] = !log->command_name.empty() ? log->command_name : log->service_name;
entry["Method"] = log->method;
entry[""] = log->extra;
entry["Command"] = !log->command_name.empty() ? log->command_name.upper() : log->service_name;
entry["Method"] = log->method + (log->extra.empty() ? "" : " ") + log->extra;
list.AddEntry(entry);
}
source.Reply(_("Log list for %s:"), ci->name.c_str());
std::vector<Anope::string> replies;
list.Process(replies);
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
}
}
else if (params.size() > 2)
+18 -17
View File
@@ -39,7 +39,7 @@ struct ModeLockTypeImpl final
: Serialize::Type("ModeLock")
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override;
void Serialize(Serializable *obj, Serialize::Data &data) const override;
Serializable *Unserialize(Serializable *obj, Serialize::Data &data) const override;
};
@@ -211,7 +211,7 @@ struct ModeLocksImpl final
}
};
void ModeLockTypeImpl::Serialize(const Serializable *obj, Serialize::Data &data) const
void ModeLockTypeImpl::Serialize(Serializable *obj, Serialize::Data &data) const
{
const auto *ml = static_cast<const ModeLockImpl *>(obj);
data.Store("ci", ml->ci);
@@ -288,7 +288,7 @@ class CommandCSMode final
for (auto *ml : mlocks)
{
ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name);
if (cm && cm->CanSet(source.GetUser()))
if (cm && cm->CanSet(source.GetUser(), ci->c))
modelocks->RemoveMLock(cm, ml->set, ml->param);
}
}
@@ -320,7 +320,7 @@ class CommandCSMode final
source.Reply(_("Unknown mode character %c ignored."), mode);
break;
}
else if (u && !cm->CanSet(u))
else if (u && !cm->CanSet(u, ci->c))
{
source.Reply(_("You may not (un)lock mode %c."), mode);
break;
@@ -412,7 +412,7 @@ class CommandCSMode final
source.Reply(_("Unknown mode character %c ignored."), mode);
break;
}
else if (u && !cm->CanSet(u))
else if (u && !cm->CanSet(u, ci->c))
{
source.Reply(_("You may not (un)lock mode %c."), mode);
break;
@@ -450,6 +450,12 @@ class CommandCSMode final
{
ListFormatter list(source.GetAccount());
list.AddColumn(_("Mode")).AddColumn(_("Param")).AddColumn(_("Creator")).AddColumn(_("Created"));
list.SetFlexible([](ListFormatter::ListEntry &row)
{
return row["Param"].empty()
? _("{mode} -- created by {creator} on {created}")
: _("{mode} {param} -- created by {creator} on {created}");
});
for (auto *ml : mlocks)
{
@@ -458,7 +464,7 @@ class CommandCSMode final
continue;
ListFormatter::ListEntry entry;
entry["Mode"] = Anope::printf("%c%c", ml->set ? '+' : '-', cm->mchar);
entry["Mode"] = Anope::Format("%c%c", ml->set ? '+' : '-', cm->mchar);
entry["Param"] = ml->param;
entry["Creator"] = ml->setter;
entry["Created"] = Anope::strftime(ml->created, NULL, true);
@@ -466,12 +472,7 @@ class CommandCSMode final
}
source.Reply(_("Mode locks for %s:"), ci->name.c_str());
std::vector<Anope::string> replies;
list.Process(replies);
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
}
}
else
@@ -508,7 +509,7 @@ class CommandCSMode final
{
ChannelMode *cm = ModeManager::GetChannelModes()[j];
if (!u || cm->CanSet(u) || can_override)
if (!u || cm->CanSet(u, ci->c) || can_override)
{
if (cm->type == MODE_REGULAR || (!adding && cm->type == MODE_PARAM))
{
@@ -524,7 +525,7 @@ class CommandCSMode final
if (adding == -1)
break;
ChannelMode *cm = ModeManager::FindChannelModeByChar(mode);
if (!cm || (u && !cm->CanSet(u) && !can_override))
if (!cm || (u && !cm->CanSet(u, ci->c) && !can_override))
continue;
switch (cm->type)
{
@@ -917,9 +918,9 @@ public:
if (!m.second.empty())
{
if (m.first)
return Anope::printf(Language::Translate(source.GetAccount(), _("Gives you or the specified nick %s status on a channel")), m.second.c_str());
return Anope::Format(Language::Translate(source.GetAccount(), _("Gives you or the specified nick %s status on a channel")), m.second.c_str());
else
return Anope::printf(Language::Translate(source.GetAccount(), _("Removes %s status from you or the specified nick on a channel")), m.second.c_str());
return Anope::Format(Language::Translate(source.GetAccount(), _("Removes %s status from you or the specified nick on a channel")), m.second.c_str());
}
else
return "";
@@ -1008,7 +1009,7 @@ public:
if (cm->type == MODE_REGULAR)
{
if (!c->HasMode(cm->name) && ml->set)
c->SetMode(NULL, cm, "", false);
c->SetMode(NULL, cm, {}, false);
else if (c->HasMode(cm->name) && !ml->set)
c->RemoveMode(NULL, cm, "", false);
}
+1 -1
View File
@@ -85,7 +85,7 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Registers a channel in the %s database. In order "
"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 "
+54 -90
View File
@@ -16,7 +16,6 @@ enum TypeInfo
NEW, NICK_TO, NICK_FROM, JOIN, PART, QUIT, KICK
};
static bool simple;
struct SeenInfo;
static SeenInfo *FindInfo(const Anope::string &nick);
typedef Anope::unordered_map<SeenInfo *> database_map;
@@ -53,12 +52,54 @@ struct SeenInfoType final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
static Anope::string TypeToString(TypeInfo ti)
{
switch (ti)
{
case NEW:
return "NEW";
case NICK_TO:
return "NICK_TO";
case NICK_FROM:
return "NICK_FROM";
case JOIN:
return "JOIN";
case PART:
return "PART";
case QUIT:
return "QUIT";
case KICK:
return "KICK";
}
return ""; // Should never happen.
}
static TypeInfo StringToType(const Anope::string &ti)
{
if (ti.equals_ci("NEW") || ti.equals_ci("0"))
return NEW;
if (ti.equals_ci("NICK_TO") || ti.equals_ci("1"))
return NICK_TO;
if (ti.equals_ci("NICK_FROM") || ti.equals_ci("2"))
return NICK_FROM;
if (ti.equals_ci("JOIN") || ti.equals_ci("3"))
return JOIN;
if (ti.equals_ci("PART") || ti.equals_ci("4"))
return PART;
if (ti.equals_ci("QUIT") || ti.equals_ci("5"))
return QUIT;
if (ti.equals_ci("KICK") || ti.equals_ci("6"))
return KICK;
return NEW; // Should never happen.
}
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *s = static_cast<const SeenInfo *>(obj);
data.Store("nick", s->nick);
data.Store("vhost", s->vhost);
data.Store("type", s->type);
data.Store("type", TypeToString(s->type));
data.Store("nick2", s->nick2);
data.Store("channel", s->channel);
data.Store("message", s->message);
@@ -84,9 +125,9 @@ struct SeenInfoType final
s->nick = snick;
data["vhost"] >> s->vhost;
unsigned int n;
Anope::string n;
data["type"] >> n;
s->type = static_cast<TypeInfo>(n);
s->type = StringToType(n);
data["nick2"] >> s->nick2;
data["channel"] >> s->channel;
data["message"] >> s->message;
@@ -199,76 +240,6 @@ public:
class CommandSeen final
: public Command
{
static void SimpleSeen(CommandSource &source, const std::vector<Anope::string> &params)
{
if (!source.c || !source.c->ci)
{
if (source.IsOper())
source.Reply("Seen in simple mode is designed as a fantasy command only!");
return;
}
BotInfo *bi = BotInfo::Find(params[0], true);
if (bi)
{
if (bi == source.c->ci->bi)
source.Reply(_("You found me, %s!"), source.GetNick().c_str());
else
source.Reply(_("%s is a network service."), bi->nick.c_str());
return;
}
NickAlias *na = NickAlias::Find(params[0]);
if (!na)
{
source.Reply(_("I don't know who %s is."), params[0].c_str());
return;
}
if (source.GetAccount() == na->nc)
{
source.Reply(_("Looking for yourself, eh %s?"), source.GetNick().c_str());
return;
}
User *target = User::Find(params[0], true);
if (target && source.c->FindUser(target))
{
source.Reply(_("%s is on the channel right now!"), target->nick.c_str());
return;
}
for (const auto &[_, uc] : source.c->users)
{
User *u = uc->user;
if (u->Account() == na->nc)
{
source.Reply(_("%s is on the channel right now (as %s)!"), params[0].c_str(), u->nick.c_str());
return;
}
}
AccessGroup ag = source.c->ci->AccessFor(na->nc);
time_t last = 0;
for (const auto &p : ag.paths)
{
if (p.empty())
continue;
ChanAccess *a = p[p.size() - 1];
if (a->GetAccount() == na->nc && a->last_seen > last)
last = a->last_seen;
}
if (last > Anope::CurTime || !last)
source.Reply(_("I've never seen %s on this channel."), na->nick.c_str());
else
source.Reply(_("%s was last seen here %s ago."), na->nick.c_str(), Anope::Duration(Anope::CurTime - last, source.GetAccount()).c_str());
}
public:
CommandSeen(Module *creator) : Command(creator, "chanserv/seen", 1, 2)
{
@@ -281,9 +252,6 @@ public:
{
const Anope::string &target = params[0];
if (simple)
return this->SimpleSeen(source, params);
if (target.length() > IRCD->MaxNick)
{
source.Reply(_("Nick too long, max length is %zu characters."), IRCD->MaxNick);
@@ -314,7 +282,7 @@ public:
if (u2)
onlinestatus = ".";
else
onlinestatus = Anope::printf(Language::Translate(source.nc, _(" but %s mysteriously dematerialized.")), target.c_str());
onlinestatus = Anope::Format(Language::Translate(source.nc, _(" but %s mysteriously dematerialized.")), target.c_str());
Anope::string timebuf = Anope::Duration(Anope::CurTime - info->last, source.nc);
Anope::string timebuf2 = Anope::strftime(info->last, source.nc, true);
@@ -328,9 +296,9 @@ public:
{
u2 = User::Find(info->nick2, true);
if (u2)
onlinestatus = Anope::printf(Language::Translate(source.nc, _(". %s is still online.")), u2->nick.c_str());
onlinestatus = Anope::Format(Language::Translate(source.nc, _(". %s is still online.")), u2->nick.c_str());
else
onlinestatus = Anope::printf(Language::Translate(source.nc, _(", but %s mysteriously dematerialized.")), info->nick2.c_str());
onlinestatus = Anope::Format(Language::Translate(source.nc, _(", but %s mysteriously dematerialized.")), info->nick2.c_str());
source.Reply(_("%s (%s) was last seen changing nick to %s %s ago%s"),
target.c_str(), info->vhost.c_str(), info->nick2.c_str(), timebuf.c_str(), onlinestatus.c_str());
@@ -401,17 +369,13 @@ public:
{
}
void OnReload(Configuration::Conf &conf) override
{
simple = conf.GetModule(this).Get<bool>("simple");
}
void OnExpireTick() override
{
size_t previous_size = database.size();
time_t purgetime = Config->GetModule(this).Get<time_t>("purgetime");
auto purgetime = Config->GetModule(this).Get<time_t>("purgetime", "90d");
if (!purgetime)
purgetime = Anope::DoTime("30d");
return;
auto previous_size = database.size();
for (database_map::iterator it = database.begin(), it_end = database.end(); it != it_end;)
{
database_map::iterator cur = it;
@@ -461,7 +425,7 @@ public:
private:
static void UpdateUser(const User *u, const TypeInfo Type, const Anope::string &nick, const Anope::string &nick2, const Anope::string &channel, const Anope::string &message)
{
if (simple || !u->server->IsSynced())
if (!u->server->IsSynced())
return;
SeenInfo *&info = database[nick];
+40 -13
View File
@@ -912,7 +912,7 @@ public:
source.Reply(" ");
source.Reply(_(
"Enables or disables signed kicks for a "
"channel. When \002SIGNKICK\002 is set, kicks issued with "
"channel. When \002SIGNKICK\002 is set, kicks issued with "
"the \002KICK\002 command will have the nick that used the "
"command in their reason."
"\n\n"
@@ -1093,7 +1093,7 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Sets whether the given channel will expire. Setting this "
"Sets whether the given channel will expire. Setting this "
"to ON prevents the channel from expiring."
));
return true;
@@ -1121,13 +1121,19 @@ class CSSet final
const ChannelInfo *ci = anope_dynamic_static_cast<const ChannelInfo *>(s);
Anope::string modes;
for (const auto &[last_mode, last_value] : ci->last_modes)
for (const auto &[last_mode, last_data] : ci->last_modes)
{
if (!modes.empty())
modes += " ";
modes += '+';
modes += last_mode;
if (!last_value.empty())
modes += "," + last_value;
if (!last_data.value.empty())
{
modes += "," + Anope::ToString(last_data.set_at);
modes += "," + last_data.set_by;
modes += "," + last_data.value;
}
}
data.Store("last_modes", modes);
}
@@ -1145,11 +1151,32 @@ class CSSet final
ci->last_modes.clear();
for (spacesepstream sep(modes); sep.GetToken(modes);)
{
size_t c = modes.find(',');
if (c == Anope::string::npos)
ci->last_modes.emplace(modes, "");
if (modes[0] == '+')
{
commasepstream mode(modes, true);
mode.GetToken(modes);
modes.erase(0, 1);
ModeData info;
Anope::string set_at;
mode.GetToken(set_at);
info.set_at = Anope::Convert(set_at, 0);
mode.GetToken(info.set_by);
info.value = mode.GetRemaining();
ci->last_modes.emplace(modes, info);
continue;
}
else
ci->last_modes.emplace(modes.substr(0, c), modes.substr(c + 1));
{
// Begin 2.0 compatibility.
size_t c = modes.find(',');
if (c == Anope::string::npos)
ci->last_modes.emplace(modes, ModeData());
else
ci->last_modes.emplace(modes.substr(0, c), ModeData(modes.substr(c + 1)));
// End 2.0 compatibility.
}
}
}
} keep_modes;
@@ -1207,8 +1234,8 @@ public:
if (c->ci && keep_modes.HasExt(c->ci))
{
Channel::ModeList ml = c->ci->last_modes;
for (const auto &[last_mode, last_value] : ml)
c->SetMode(c->ci->WhoSends(), last_mode, last_value);
for (const auto &[last_mode, last_data] : ml)
c->SetMode(c->ci->WhoSends(), last_mode, last_data);
}
}
@@ -1230,7 +1257,7 @@ public:
persist.Unset(ci);
}
EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) override
EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) override
{
if (c->ci)
{
@@ -1306,7 +1333,7 @@ public:
if (persist.HasExt(ci))
info.AddOption(_("Persistent"));
if (noexpire.HasExt(ci))
info.AddOption(_("No expire"));
info.AddOption(_("No expiry"));
if (keep_modes.HasExt(ci))
info.AddOption(_("Keep modes"));
if (noautoop.HasExt(ci))
+3 -2
View File
@@ -54,7 +54,7 @@ struct CSMiscDataType
{
}
void Serialize(const Serializable *obj, Serialize::Data &sdata) const override
void Serialize(Serializable *obj, Serialize::Data &sdata) const override
{
const auto *d = static_cast<const CSMiscData *>(obj);
sdata.Store("ci", d->object);
@@ -171,6 +171,7 @@ public:
if (descriptions.count(source.command))
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply("%s", Language::Translate(source.nc, descriptions[source.command].c_str()));
return true;
}
@@ -230,7 +231,7 @@ public:
void OnJoinChannel(User *user, Channel *c) override
{
if (!c->ci || !user->server->IsSynced() || numerics.empty())
if (!c->ci || !user->server->IsSynced() || user->server == Me || numerics.empty())
return;
for (const auto &[name, ext] : items)
+1 -1
View File
@@ -27,7 +27,7 @@ struct CSSuspendInfoType final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *si = static_cast<const CSSuspendInfo *>(obj);
data.Store("chan", si->what);
+10 -3
View File
@@ -132,14 +132,18 @@ class CommandCSTopic final
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << (!topic.empty() ? "to change the topic to: " : "to unset the topic") << (!topic.empty() ? topic : "");
}
void Append(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
void Combine(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params, bool append)
{
const Anope::string &topic = params[2];
Anope::string new_topic;
if (!ci->c->topic.empty())
{
new_topic = ci->c->topic + " " + topic;
if (append)
new_topic = ci->c->topic + " " + topic;
else
new_topic = topic + " " + ci->c->topic;
ci->last_topic.clear();
}
else
@@ -155,6 +159,7 @@ public:
this->SetDesc(_("Manipulate the topic of the specified channel"));
this->SetSyntax(_("\037channel\037 [SET] [\037topic\037]"));
this->SetSyntax(_("\037channel\037 APPEND \037topic\037"));
this->SetSyntax(_("\037channel\037 PREPEND \037topic\037"));
this->SetSyntax(_("\037channel\037 [UNLOCK|LOCK]"));
}
@@ -174,7 +179,9 @@ public:
else if (!ci->c)
source.Reply(CHAN_X_NOT_IN_USE, ci->name.c_str());
else if (subcmd.equals_ci("APPEND") && params.size() > 2)
this->Append(source, ci, params);
this->Combine(source, ci, params, true);
else if (subcmd.equals_ci("PREPEND") && params.size() > 2)
this->Combine(source, ci, params, false);
else
{
Anope::string topic;
+15 -12
View File
@@ -338,9 +338,8 @@ private:
++deleted;
if (!nicks.empty())
nicks += ", " + caccess->Mask();
else
nicks = caccess->Mask();
nicks += ", ";
nicks += caccess->Mask();
ci->EraseAccess(number - 1);
FOREACH_MOD(OnAccessDel, (ci, source, caccess));
@@ -398,6 +397,12 @@ private:
ListFormatter list(source.GetAccount());
list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("Description"));
list.SetFlexible([](ListFormatter::ListEntry &row)
{
return row["Description"].empty()
? _("{number}: \002{mask}\002")
: _("{number}: \002{mask}\002 ({description})");
});
if (!nick.empty() && nick.find_first_not_of("1234567890,-") == Anope::string::npos)
{
@@ -454,12 +459,8 @@ private:
source.Reply(_("No matching entries on %s access list."), ci->name.c_str());
else
{
std::vector<Anope::string> replies;
list.Process(replies);
source.Reply(_("%s list for %s"), source.command.nobreak().c_str(), ci->name.c_str());
for (const auto &reply : replies)
source.Reply(reply);
list.SendTo(source);
}
}
@@ -512,7 +513,7 @@ public:
const Anope::string GetDesc(CommandSource &source) const override
{
return Anope::printf(Language::Translate(source.GetAccount(), _("Modify the list of %s users")), source.command.nobreak().c_str());
return Anope::Format(Language::Translate(source.GetAccount(), _("Modify the list of %s users")), source.command.nobreak().c_str());
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
@@ -556,16 +557,18 @@ public:
Anope::string buf;
for (const auto &permission : permissions[cmd])
{
buf += ", " + permission;
if (!buf.empty())
buf += ", ";
buf += permission;
if (buf.length() > 75)
{
source.Reply(" %s", buf.substr(2).c_str());
source.Reply(" %s", buf.c_str());
buf.clear();
}
}
if (!buf.empty())
{
source.Reply(" %s", buf.substr(2).c_str());
source.Reply(" %s", buf.c_str());
buf.clear();
}
+1 -16
View File
@@ -181,7 +181,6 @@ class MChanstats final
SQL::Query query;
Anope::string SmileysHappy, SmileysSad, SmileysOther, prefix;
std::vector<Anope::string> TableList, ProcedureList, EventList;
bool NSDefChanstats, CSDefChanstats;
void RunQuery(const SQL::Query &q)
{
@@ -504,8 +503,6 @@ public:
SmileysHappy = block.Get<const Anope::string>("SmileysHappy");
SmileysSad = block.Get<const Anope::string>("SmileysSad");
SmileysOther = block.Get<const Anope::string>("SmileysOther");
NSDefChanstats = block.Get<bool>("ns_def_chanstats");
CSDefChanstats = block.Get<bool>("cs_def_chanstats");
Anope::string engine = block.Get<const Anope::string>("engine");
this->sql = ServiceReference<SQL::Provider>("SQL::Provider", engine);
if (sql)
@@ -540,7 +537,7 @@ public:
this->RunQuery(query);
}
EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) override
EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) override
{
this->OnModeChange(c, setter.GetUser());
return EVENT_CONTINUE;
@@ -643,18 +640,6 @@ public:
query.SetValue("channel", ci->name);
this->RunQuery(query);
}
void OnChanRegistered(ChannelInfo *ci) override
{
if (CSDefChanstats)
ci->Extend<bool>("CS_STATS");
}
void OnNickRegister(User *user, NickAlias *na, const Anope::string &) override
{
if (NSDefChanstats)
na->nc->Extend<bool>("NS_STATS");
}
};
MODULE_INIT(MChanstats)
+23 -42
View File
@@ -84,14 +84,14 @@ public:
}
};
struct ModeData final
struct ModeLockData final
{
char letter;
Anope::string name;
Anope::string value;
bool set;
ModeData(const Anope::string &n, bool s, const Anope::string &v = "")
ModeLockData(const Anope::string &n, bool s, const Anope::string &v = "")
: letter(0)
, name(n)
, value(v)
@@ -99,7 +99,7 @@ struct ModeData final
{
}
ModeData(char l, const Anope::string &v = "")
ModeLockData(char l, const Anope::string &v = "")
: letter(l)
, value(v)
, set(true)
@@ -123,7 +123,7 @@ struct ChannelData final
Anope::string info_adder;
Anope::string info_message;
time_t info_ts = 0;
std::vector<ModeData> mlocks;
std::vector<ModeLockData> mlocks;
Anope::string suspend_by;
Anope::string suspend_reason;
time_t suspend_ts = 0;
@@ -134,9 +134,9 @@ struct UserData final
Anope::string info_adder;
Anope::string info_message;
time_t info_ts = 0;
Anope::string last_mask;
Anope::string last_quit;
Anope::string last_real_mask;
Anope::string last_userhost;
Anope::string last_userhost_real;
bool noexpire = false;
bool protect = false;
std::optional<time_t> protectafter;
@@ -286,22 +286,7 @@ private:
data->mlocks.emplace_back("REGISTERED", set);
// Atheme also supports per-ircd values here (ew).
if (IRCD->owner->name == "bahamut")
{
if (locks & 0x1000u)
data->mlocks.emplace_back("BLOCKCOLOR", set);
if (locks & 0x2000u)
data->mlocks.emplace_back("REGMODERATED", set);
if (locks & 0x4000u)
data->mlocks.emplace_back("REGISTEREDONLY", set);
if (locks & 0x8000u)
data->mlocks.emplace_back("OPERONLY", set);
// Anope doesn't recognise the following Bahamut modes currently:
// - 0x10000u ('A')
// - 0x20000u ('P')
}
else if (IRCD->owner->name == "inspircd")
if (IRCD->owner->name == "inspircd")
{
if (locks & 0x1000u)
data->mlocks.emplace_back("BLOCKCOLOR", set);
@@ -447,7 +432,7 @@ private:
// crypt3-md5 Converted to enc_posix
// crypt3-sha2-256 Converted to enc_posix
// crypt3-sha2-512 Converted to enc_posix
// ircservices Converted to enc_old
// ircservices NO
// pbkdf2 NO
// pbkdf2v2 NO
// rawmd5 Converted to enc_md5
@@ -458,10 +443,9 @@ private:
if (pass.compare(0, 18, "$anope$enc_sha256$", 18) == 0)
{
auto sep = pass.find('$', 18);
Anope::string iv, pass;
Anope::B64Decode(pass.substr(18, sep - 18), iv);
Anope::B64Decode(pass.substr(sep + 1), pass);
nc->pass = "sha256:" + Anope::Hex(pass) + ":" + Anope::Hex(iv);
auto iv = Anope::B64Decode(pass.substr(18, sep - 18));
auto pw = Anope::B64Decode(pass.substr(sep + 1));
nc->pass = "sha256:" + Anope::Hex(pw) + ":" + Anope::Hex(iv);
}
else if (pass.compare(0, 9, "$argon2d$", 9) == 0)
@@ -475,14 +459,10 @@ private:
else if (pass.compare(0, 8, "$base64$", 8) == 0)
{
Anope::string rawpass;
Anope::B64Decode(pass.substr(8), rawpass);
auto rawpass = Anope::B64Decode(pass.substr(8));
Anope::Encrypt(rawpass, nc->pass);
}
else if (pass.compare(0, 13, "$ircservices$", 13) == 0)
nc->pass = "oldmd5:" + pass.substr(13);
else if (pass.compare(0, 8, "$rawmd5$", 8) == 0)
nc->pass = "md5:" + pass.substr(8);
@@ -527,7 +507,7 @@ private:
if (!forbid_service)
{
Log(this) << "Unable to convert forbidden email " << email << " as os_forbid is not loaded";
Log(this) << "Unable to convert forbidden email address " << email << " as os_forbid is not loaded";
return true;
}
@@ -640,6 +620,7 @@ private:
return true;
}
auto originalflags = flags;
Anope::string accessflags;
ApplyAccess(flags, 'A', accessflags, { "ACCESS_LIST" });
ApplyAccess(flags, 'a', accessflags, { "AUTOPROTECT", "PROTECT", "PROTECTME" });
@@ -662,7 +643,7 @@ private:
auto *access = accessprov->Create();
access->SetMask(mask, ci);
access->creator = setter;
access->description = "Imported from Atheme";
access->description = "Imported from Atheme: " + flags;
access->last_seen = modifiedtime;
access->created = modifiedtime;
access->AccessUnserialize(accessflags);
@@ -820,7 +801,7 @@ private:
auto *ni = news_service->CreateNewsItem();
ni->type = NEWS_LOGON;
ni->text = Anope::printf("[%s] %s", subject.c_str(), body.c_str());
ni->text = Anope::Format("[%s] %s", subject.c_str(), body.c_str());
ni->who = setter;
ni->time = ts;
news_service->AddNewsItem(ni);
@@ -846,7 +827,7 @@ private:
auto *ni = news_service->CreateNewsItem();
ni->type = NEWS_OPER;
ni->text = Anope::printf("[%s] %s", subject.c_str(), body.c_str());
ni->text = Anope::Format("[%s] %s", subject.c_str(), body.c_str());
ni->who = setter;
ni->time = ts;
news_service->AddNewsItem(ni);
@@ -1160,9 +1141,9 @@ private:
else if (key == "private:freeze:timestamp")
data->suspend_ts = Anope::Convert<time_t>(value, 0);
else if (key == "private:host:actual")
data->last_real_mask = value;
data->last_userhost_real = value;
else if (key == "private:host:vhost")
data->last_mask = value;
data->last_userhost = value;
else if (key == "private:lastquit:message")
data->last_quit = value;
else if (key == "private:loginfail:failnum")
@@ -1328,14 +1309,14 @@ private:
auto *data = userdata.Get(nc);
if (data)
{
if (!data->last_mask.empty())
na->last_usermask = data->last_mask;
if (!data->last_userhost.empty())
na->last_userhost = data->last_userhost;
if (!data->last_quit.empty())
na->last_quit = data->last_quit;
if (!data->last_real_mask.empty())
na->last_realhost = data->last_real_mask;
if (!data->last_userhost_real.empty())
na->last_userhost_real = data->last_userhost_real;
if (data->noexpire)
na->Extend<bool>("NS_NO_EXPIRE");
+3 -251
View File
@@ -11,31 +11,6 @@
#include "module.h"
#ifndef _WIN32
#include <sys/wait.h>
#endif
#include <filesystem>
class SaveData final
: public Serialize::Data
{
public:
Anope::string last;
std::fstream *fs = nullptr;
std::iostream &operator[](const Anope::string &key) override
{
if (key != last)
{
*fs << "\nDATA " << key << " ";
last = key;
}
return *fs;
}
};
class LoadData final
: public Serialize::Data
{
@@ -97,133 +72,14 @@ public:
class DBFlatFile final
: public Module
, public Pipe
{
/* Day the last backup was on */
int last_day = 0;
private:
bool loaded = false;
int child_pid = -1;
void BackupDatabase()
{
tm *tm = localtime(&Anope::CurTime);
if (tm->tm_mday != last_day)
{
last_day = tm->tm_mday;
std::set<Anope::string> dbs;
dbs.insert(Config->GetModule(this).Get<const Anope::string>("database", "anope.db"));
for (const auto &type_order : Serialize::Type::GetTypeOrder())
{
Serialize::Type *stype = Serialize::Type::Find(type_order);
if (stype && stype->GetOwner())
dbs.insert("module_" + stype->GetOwner()->name + ".db");
}
const auto backupdir = Anope::ExpandData("backups");
for (const auto &db : dbs)
{
const auto oldname = Anope::ExpandData(db);
const auto basename = Anope::Expand(backupdir, db + "-");
const auto newname = Anope::printf("%s%04i-%02i-%02i", basename.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
/* Backup already exists or no database to backup */
if (Anope::IsFile(newname) || !Anope::IsFile(oldname))
continue;
Log(LOG_DEBUG) << "db_flatfile: Attempting to rename " << db << " to " << newname;
if (rename(oldname.c_str(), newname.c_str()))
{
Anope::string err = Anope::LastError();
Log(this) << "Unable to back up database " << db << " (" << err << ")!";
if (!Config->GetModule(this).Get<bool>("nobackupokay"))
{
Anope::Quitting = true;
Anope::QuitReason = "Unable to back up database " + db + " (" + err + ")";
}
continue;
}
const auto keepbackups = Config->GetModule(this).Get<unsigned>("keepbackups", "7");
if (!keepbackups)
continue;
std::error_code ec;
std::set<Anope::string> old_backups;
for (const auto &entry : std::filesystem::directory_iterator(backupdir.str(), ec))
{
Anope::string entryname = entry.path().string();
if (entryname.compare(0, basename.length(), basename) != 0)
continue;
old_backups.insert(entryname);
if (old_backups.size() <= keepbackups)
continue;
Log(LOG_DEBUG) << "Deleting expired backup " << *old_backups.begin();
if (!std::filesystem::remove(old_backups.begin()->str(), ec))
{
Log(this) << "Failed to delete expired backup " << *old_backups.begin() << ": " << ec.message();
continue;
}
old_backups.erase(old_backups.begin());
}
}
}
}
public:
DBFlatFile(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR)
DBFlatFile(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, DATABASE | DEPRECATED | VENDOR)
{
}
#ifndef _WIN32
void OnRestart() override
{
OnShutdown();
}
void OnShutdown() override
{
if (child_pid > -1)
{
Log(this) << "Waiting for child to exit...";
int status;
waitpid(child_pid, &status, 0);
Log(this) << "Done";
}
}
#endif
void OnNotify() override
{
char buf[512];
int i = this->Read(buf, sizeof(buf) - 1);
if (i <= 0)
return;
buf[i] = 0;
child_pid = -1;
if (!*buf)
{
Log(this) << "Finished saving databases";
return;
}
Log(this) << "Error saving databases: " << buf;
if (!Config->GetModule(this).Get<bool>("nobackupokay"))
Anope::Quitting = true;
}
EventReturn OnLoadDatabase() override
@@ -270,110 +126,6 @@ public:
return EVENT_STOP;
}
void OnSaveDatabase() override
{
if (child_pid > -1)
{
Log(this) << "Database save is already in progress!";
return;
}
BackupDatabase();
int i = -1;
#ifndef _WIN32
if (!Anope::Quitting && Config->GetModule(this).Get<bool>("fork"))
{
i = fork();
if (i > 0)
{
child_pid = i;
return;
}
else if (i < 0)
Log(this) << "Unable to fork for database save";
}
#endif
try
{
std::map<Module *, std::fstream *> databases;
/* First open the databases of all of the registered types. This way, if we have a type with 0 objects, that database will be properly cleared */
for (const auto &[_, s_type] : Serialize::Type::GetTypes())
{
if (databases[s_type->GetOwner()])
continue;
Anope::string db_name;
if (s_type->GetOwner())
db_name = Anope::ExpandData("module_" + s_type->GetOwner()->name + ".db");
else
db_name = Anope::ExpandData(Config->GetModule(this).Get<const Anope::string>("database", "anope.db"));
std::fstream *fs = databases[s_type->GetOwner()] = new std::fstream((db_name + ".tmp").c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
if (!fs->is_open())
Log(this) << "Unable to open " << db_name << " for writing";
}
SaveData data;
const std::list<Serializable *> &items = Serializable::GetItems();
for (auto *base : items)
{
Serialize::Type *s_type = base->GetSerializableType();
if (!s_type)
continue;
data.fs = databases[s_type->GetOwner()];
if (!data.fs || !data.fs->is_open())
continue;
*data.fs << "OBJECT " << s_type->GetName();
if (base->id)
*data.fs << "\nID " << base->id;
s_type->Serialize(base, data);
*data.fs << "\nEND\n";
}
for (auto &[mod, f] : databases)
{
const auto db_name = Anope::ExpandData((mod ? (mod->name + ".db") : Config->GetModule(this).Get<const Anope::string>("database", "anope.db")));
if (!f->is_open() || !f->good())
{
this->Write("Unable to write database " + db_name);
f->close();
}
else
{
f->close();
#ifdef _WIN32
/* Windows rename() fails if the file already exists. */
remove(db_name.c_str());
#endif
rename((db_name + ".tmp").c_str(), db_name.c_str());
}
delete f;
}
}
catch (...)
{
if (i)
throw;
}
if (!i)
{
this->Notify();
exit(0);
}
}
/* Load just one type. Done if a module is reloaded during runtime */
void OnSerializeTypeCreate(Serialize::Type *stype) override
{
if (!loaded)
+189 -159
View File
@@ -20,23 +20,13 @@ namespace fs = std::filesystem;
// TODO:
// * forking into background
// * stable key order
inline Anope::string yyjson_mut_get_astr(yyjson_mut_val *val)
inline Anope::string yyjson_get_astr(yyjson_val *val)
{
const auto *str = yyjson_mut_get_str(val);
const auto *str = yyjson_get_str(val);
return str ? str : "";
}
inline void yyjson_mut_obj_upsert(yyjson_mut_doc *doc, yyjson_mut_val *obj, const char *key, yyjson_mut_val *val)
{
auto *oldval = yyjson_mut_obj_get(obj, key);
if (oldval)
yyjson_mut_obj_replace(obj, yyjson_mut_str(doc, key), val);
else
yyjson_mut_obj_add_val(doc, obj, key, val);
}
class Data final
: public Serialize::Data
{
@@ -48,37 +38,42 @@ public:
Anope::map<std::stringstream> data;
// Used when writing data.
Data() = default;
Data(Serialize::Type *s_type, Serializable *obj)
{
if (obj->id)
this->id = obj->id;
s_type->Serialize(obj, *this);
}
// Used when reading data.
Data(yyjson_mut_val *elem)
Data(yyjson_val *elem)
{
size_t idx, max;
yyjson_mut_val *key, *value;
yyjson_mut_obj_foreach(elem, idx, max, key, value)
yyjson_val *key, *value;
yyjson_obj_foreach(elem, idx, max, key, value)
{
if (yyjson_mut_get_type(key) != YYJSON_TYPE_STR)
if (yyjson_get_type(key) != YYJSON_TYPE_STR)
continue;
Anope::string akey(yyjson_mut_get_str(key));
if (akey.equals_ci("id"))
auto akey = yyjson_get_astr(key);
if (akey.equals_ci("@id"))
{
this->id = yyjson_mut_get_uint(value);
this->id = yyjson_get_uint(value);
continue;
}
if (yyjson_mut_is_bool(value))
data[akey] << yyjson_mut_get_bool(value);
else if (yyjson_mut_is_int(value))
data[akey] << yyjson_mut_get_int(value);
else if (yyjson_mut_is_null(value))
if (yyjson_is_bool(value))
data[akey] << yyjson_get_bool(value);
else if (yyjson_is_int(value))
data[akey] << yyjson_get_int(value);
else if (yyjson_is_null(value))
data[akey];
else if (yyjson_mut_is_real(value))
data[akey] << yyjson_mut_get_real(value);
else if (yyjson_mut_is_str(value))
data[akey] << yyjson_mut_get_str(value);
else if (yyjson_mut_is_uint(value))
data[akey] << yyjson_mut_get_uint(value);
else if (yyjson_is_real(value))
data[akey] << yyjson_get_real(value);
else if (yyjson_is_str(value))
data[akey] << yyjson_get_astr(value);
else if (yyjson_is_uint(value))
data[akey] << yyjson_get_uint(value);
}
}
@@ -86,16 +81,29 @@ public:
{
return data[key];
}
size_t Hash() const override
{
size_t hash = 0;
for (const auto &[_, value] : this->data)
{
auto valuestr = value.str();
if (!valuestr.empty())
hash ^= Anope::hash_cs()(valuestr);
}
return hash;
}
};
class DBJSON final
: public Module
{
private:
using DBPair = std::pair<yyjson_mut_doc *, yyjson_mut_val *>;
// Multimap from serializable type to serializable data.
using DBData = Anope::multimap<Data>;
// The databases which have already been loaded from disk.
std::unordered_map<Module *, DBPair> databases;
std::unordered_map<Module *, DBData> databases;
// Whether OnLoadDatabase has been called yet.
bool loaded = false;
@@ -182,7 +190,7 @@ private:
return; // No backups.
auto backupdir = Anope::ExpandData(modconf.Get<Anope::string>("backup_directory", "backups"));
if (!fs::is_directory(backupdir.str(), ec) && !ec)
if (!fs::is_directory(backupdir.str(), ec))
{
fs::create_directories(backupdir.str(), ec);
if (ec)
@@ -201,55 +209,131 @@ private:
CreateBackup(backupdir, dbpath, monthly_backups, "%Y-%m", "\?\?\?\?-\?\?");
}
DBPair ReadDatabase(const Anope::string &dbname)
void LoadType(Serialize::Type *s_type, DBData &data)
{
auto entries = data.equal_range(s_type->GetName());
if (entries.first == entries.second)
return;
for (auto it = entries.first; it != entries.second; ++it)
s_type->Unserialize(nullptr, it->second);
}
std::optional<DBData> ReadDatabase(const Anope::string &dbname)
{
yyjson_read_err errmsg;
const auto flags = YYJSON_READ_ALLOW_TRAILING_COMMAS | YYJSON_READ_ALLOW_INVALID_UNICODE;
auto *idoc = yyjson_read_file(dbname.c_str(), flags, nullptr, &errmsg);
if (!idoc)
auto *doc = yyjson_read_file(dbname.c_str(), flags, nullptr, &errmsg);
if (!doc)
{
Log(this) << "Unable to read " << dbname << ": error #" << errmsg.code << ": " << errmsg.msg;
return { nullptr, nullptr };
return std::nullopt;
}
// We operate on a mutable document because we need to write to it later.
auto *doc = yyjson_doc_mut_copy(idoc, nullptr);
yyjson_doc_free(idoc);
auto *root = yyjson_mut_doc_get_root(doc);
if (!yyjson_mut_is_obj(root))
auto *root = yyjson_doc_get_root(doc);
if (!yyjson_is_obj(root))
{
Log(this) << "Unable to read " << dbname << ": root element is not an object";
return { nullptr, nullptr };
return std::nullopt;
}
auto version = yyjson_mut_get_uint(yyjson_mut_obj_get(root, "version"));
auto version = yyjson_get_uint(yyjson_obj_get(root, "version"));
if (version && version != ANOPE_DATABASE_VERSION)
{
Log(this) << "Refusing to load an unsupported database version: " << version;
return { nullptr, nullptr };
return std::nullopt;
}
auto generator = yyjson_mut_get_astr(yyjson_mut_obj_get(root, "generator"));
auto updated = yyjson_mut_get_uint(yyjson_mut_obj_get(root, "updated"));
auto generator = yyjson_get_astr(yyjson_obj_get(root, "generator"));
auto updated = yyjson_get_uint(yyjson_obj_get(root, "updated"));
Log(LOG_DEBUG) << "Database " << dbname << " was generated on " << Anope::strftime(updated) << " by " << generator;
auto *data = yyjson_mut_obj_get(root, "data");
if (!data || !yyjson_mut_is_obj(data))
auto *data = yyjson_obj_get(root, "data");
if (!data || !yyjson_is_obj(data))
{
Log(this) << "Unable to read " << dbname << ": data element is missing or not an object";
return { nullptr, nullptr };
return std::nullopt;
}
return { doc, data };
DBData ret;
size_t idx, max;
yyjson_val *key, *val;
yyjson_obj_foreach(data, idx, max, key, val)
{
if (!yyjson_is_str(key))
{
Log(this) << "Unable to read part of " << dbname << ": key of data element #" << idx << " is not a string";
continue;
}
auto keystr = yyjson_get_astr(key);
if (!yyjson_is_arr(val))
{
Log(this) << "Unable to read part of " << dbname << ": " << keystr << " value of data element #" << idx << " is not an array";
continue;
}
Log(LOG_DEBUG) << "Loading " << yyjson_arr_size(val) << " " << keystr << " records";
size_t idx, max;
yyjson_val *elem;
yyjson_arr_foreach(val, idx, max, elem)
{
Data ld(elem);
ret.emplace(keystr, std::move(ld));
}
}
yyjson_doc_free(doc);
return ret;
}
static void UpdateMetadata(yyjson_mut_doc *doc, yyjson_mut_val *obj)
void SaveType(yyjson_mut_doc *doc, yyjson_mut_val *obj, const Anope::string &typestr, const Data &data)
{
const auto generator = "Anope " + Anope::Version();
yyjson_mut_obj_upsert(doc, obj, "generator", yyjson_mut_strncpy(doc, generator.c_str(), generator.length()));
yyjson_mut_obj_upsert(doc, obj, "version", yyjson_mut_uint(doc, ANOPE_DATABASE_VERSION));
yyjson_mut_obj_upsert(doc, obj, "updated", yyjson_mut_int(doc, Anope::CurTime));
auto *type = yyjson_mut_obj_getn(obj, typestr.c_str(), typestr.length());
if (!type || !yyjson_mut_is_arr(type))
{
// We haven't seen this element before.
type = yyjson_mut_arr(doc);
yyjson_mut_obj_add_val(doc, obj, typestr.c_str(), type);
}
auto *elem = yyjson_mut_obj(doc);
if (data.id)
yyjson_mut_obj_add_uint(doc, elem, "@id", data.id);
for (const auto &[key, value] : data.data)
{
yyjson_mut_val *v;
switch (data.GetType(key))
{
case Serialize::DataType::BOOL:
v = yyjson_mut_bool(doc, Anope::Convert<bool>(value.str(), false));
break;
case Serialize::DataType::FLOAT:
v = yyjson_mut_real(doc, Anope::Convert<double>(value.str(), 0.0));
break;
case Serialize::DataType::INT:
v = yyjson_mut_int(doc, Anope::Convert<int64_t>(value.str(), 0));
break;
case Serialize::DataType::TEXT:
{
auto str = value.str();
v = str.empty() ? yyjson_mut_null(doc) : yyjson_mut_strncpy(doc, str.c_str(), str.length());
break;
}
case Serialize::DataType::UINT:
v = yyjson_mut_uint(doc, Anope::Convert<uint64_t>(value.str(), 0));
break;
}
auto *k = yyjson_mut_strncpy(doc, key.c_str(), key.length());
yyjson_mut_obj_add(elem, k, v);
}
yyjson_mut_arr_add_val(type, elem);
}
public:
@@ -262,136 +346,90 @@ public:
{
auto dbname = GetDatabaseFile(nullptr);
auto [doc, data] = ReadDatabase(dbname);
if (!data)
auto db = ReadDatabase(dbname);
if (!db)
return EVENT_STOP;
for (const auto &type : Serialize::Type::GetTypeOrder())
{
auto *s_type = Serialize::Type::Find(type);
if (!s_type || !s_type->GetOwner())
continue;
size_t idx, max;
yyjson_mut_val *elem;
yyjson_mut_arr_foreach(data, idx, max, elem)
{
Data ld(elem);
s_type->Unserialize(nullptr, ld);
}
if (s_type && !s_type->GetOwner())
LoadType(s_type, db.value());
}
loaded = false;
loaded = true;
return EVENT_STOP;
}
void OnSaveDatabase() override
{
std::set<Module *> updated;
for (const auto &[_, s_type] : Serialize::Type::GetTypes())
// Step 1: clear the old data.
for (const auto &type : Serialize::Type::GetTypeOrder())
{
auto *s_type = Serialize::Type::Find(type);
if (!s_type)
continue; // Provider has been unloaded.
auto it = databases.find(s_type->GetOwner());
if (it == databases.end())
{
auto *doc = yyjson_mut_doc_new(nullptr);
auto *root = yyjson_mut_obj(doc);
yyjson_mut_doc_set_root(doc, root);
UpdateMetadata(doc, root);
auto *data = yyjson_mut_obj(doc);
yyjson_mut_obj_add_val(doc, root, "data", data);
databases[s_type->GetOwner()] = { doc, data };
databases.emplace(s_type->GetOwner(), DBData());
continue; // We just need to create for this type.
}
else if (updated.find(s_type->GetOwner()) == updated.end())
{
auto *doc = it->second.first;
auto *root = yyjson_mut_doc_get_root(doc);
UpdateMetadata(doc, root);
updated.insert(s_type->GetOwner());
}
// As this type has been written before we need to clear the entries
// from the previous writes so we can update it in the next loop. We
// have to do it this way so we don't purge any entries for unloaded
// modules.
it->second.erase(s_type->GetName());
}
std::set<Serialize::Type *> seen;
// Step 2: store the new data.
for (auto *item : Serializable::GetItems())
{
auto *s_type = item->GetSerializableType();
if (!s_type)
continue; // Provider has been unloaded.
// This should always be found because we create it in the previous step.
auto it = databases.find(s_type->GetOwner());
if (it == databases.end())
continue; // Type has not been registered?
auto &[doc, data] = it->second;
// If the type object doesn't exist then create it. Otherwise, clear.
// all of the previous objects stored in it.
auto *type = yyjson_mut_obj_getn(data, s_type->GetName().c_str(), s_type->GetName().length());
if (!type || yyjson_mut_get_type(type) != YYJSON_TYPE_ARR)
{
// We haven't seen this element before.
type = yyjson_mut_arr(doc);
yyjson_mut_obj_add_val(doc, data, s_type->GetName().c_str(), type);
}
else if (seen.find(s_type) == seen.end())
{
// We are reusing an existing element, clear it.
yyjson_mut_arr_clear(type);
seen.insert(s_type);
}
auto *elem = yyjson_mut_arr_add_obj(doc, type);
if (item->id)
yyjson_mut_obj_add_uint(doc, elem, "id", item->id);
Data sd;
s_type->Serialize(item, sd);
for (const auto &[key, value] : sd.data)
{
yyjson_mut_val *v;
switch (sd.GetType(key))
{
case Serialize::DataType::BOOL:
v = yyjson_mut_bool(doc, Anope::Convert<bool>(value.str(), false));
break;
case Serialize::DataType::FLOAT:
v = yyjson_mut_real(doc, Anope::Convert<double>(value.str(), 0.0));
break;
case Serialize::DataType::INT:
v = yyjson_mut_int(doc, Anope::Convert<int64_t>(value.str(), 0));
break;
case Serialize::DataType::TEXT:
{
auto str = value.str();
v = str.empty() ? yyjson_mut_null(doc) : yyjson_mut_strncpy(doc, str.c_str(), str.length());
break;
}
case Serialize::DataType::UINT:
v = yyjson_mut_uint(doc, Anope::Convert<uint64_t>(value.str(), 0));
break;
}
auto *k = yyjson_mut_strncpy(doc, key.c_str(), key.length());
yyjson_mut_obj_add(elem, k, v);
}
if (it != databases.end())
it->second.emplace(s_type->GetName(), Data(s_type, item));
}
// Step 3: serialize to JSON.
for (auto &[mod, database] : databases)
{
auto dbname = GetDatabaseFile(mod);
BackupDatabase(dbname);
auto *doc = yyjson_mut_doc_new(nullptr);
auto *root = yyjson_mut_obj(doc);
yyjson_mut_doc_set_root(doc, root);
const auto generator = "Anope " + Anope::Version() + " " + Anope::VersionBuildString();
yyjson_mut_obj_add_strncpy(doc, root, "generator", generator.c_str(), generator.length());
yyjson_mut_obj_add_uint(doc, root, "version", ANOPE_DATABASE_VERSION);
yyjson_mut_obj_add_int(doc, root, "updated", Anope::CurTime);
auto *data = yyjson_mut_obj(doc);
yyjson_mut_obj_add_val(doc, root, "data", data);
for (const auto &[name, items] : database)
SaveType(doc, data, name, items);
Log(LOG_DEBUG) << "Writing " << dbname;
yyjson_write_err errmsg;
const auto flags = YYJSON_WRITE_ALLOW_INVALID_UNICODE | YYJSON_WRITE_NEWLINE_AT_END | YYJSON_WRITE_PRETTY;
if (!yyjson_mut_write_file(dbname.c_str(), database.first, flags, nullptr, &errmsg))
if (!yyjson_mut_write_file(dbname.c_str(), doc, flags, nullptr, &errmsg))
{
Log(this) << "Unable to write " << dbname << ": error #" << errmsg.code << ": " << errmsg.msg;
// TODO: exit??? retry???
}
yyjson_mut_doc_free(doc);
}
}
@@ -407,21 +445,13 @@ public:
const auto dbname = GetDatabaseFile(s_type->GetOwner());
auto db = ReadDatabase(dbname);
if (!db.second)
if (!db)
return; // Not much we can do here.
it = databases.emplace(s_type->GetOwner(), db).first;
it = databases.emplace(s_type->GetOwner(), std::move(db.value())).first;
}
auto &[doc, data] = it->second;
size_t idx, max;
yyjson_mut_val *elem;
yyjson_mut_arr_foreach(data, idx, max, elem)
{
Data ld(elem);
s_type->Unserialize(nullptr, ld);
}
LoadType(s_type, it->second);
}
};
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -174,9 +174,9 @@ public:
if (!this->CheckInit() || obj->GetTimestamp() == Anope::CurTime)
return;
Anope::string sql = Anope::printf("SELECT * from `%s`", GetTableName(obj).c_str());
Anope::string sql = Anope::Format("SELECT * from `%s`", GetTableName(obj).c_str());
if (obj->GetTimestamp())
sql += Anope::printf(" WHERE (`timestamp` >= %s OR `timestamp` IS NULL)", this->SQL->FromUnixtime(obj->GetTimestamp()).c_str());
sql += Anope::Format(" WHERE (`timestamp` >= %s OR `timestamp` IS NULL)", this->SQL->FromUnixtime(obj->GetTimestamp()).c_str());
Query query(sql);
+41 -3
View File
@@ -142,7 +142,7 @@ class Packet final
record.ttl = (input[pos] << 24) | (input[pos + 1] << 16) | (input[pos + 2] << 8) | input[pos + 3];
pos += 4;
//record.rdlength = input[pos] << 8 | input[pos + 1];
auto rdlength = input[pos] << 8 | input[pos + 1];
pos += 2;
switch (record.type)
@@ -192,6 +192,44 @@ class Packet final
break;
}
case DNS::QUERY_TXT:
{
if (pos + rdlength > input_size)
throw SocketException("Unable to unpack TXT resource record");
auto txtlength = input[pos++];
if (pos + txtlength > input_size)
throw SocketException("Unable to unpack TXT resource record");
record.rdata = Anope::string(reinterpret_cast<const char* >(input + pos), txtlength);
pos += rdlength - 1;
break;
}
case DNS::QUERY_SRV:
{
if (rdlength < 6 || pos + rdlength > input_size)
throw SocketException("Unable to unpack SRV resource record");
auto srv = std::make_shared<DNS::Record::SRV>();
srv->priority = input[pos] << 8 | input[pos + 1];
pos += 2;
srv->weight = input[pos] << 8 | input[pos + 1];
pos += 2;
srv->port = input[pos] << 8 | input[pos + 1];
pos += 2;
srv->host = this->UnpackName(input, input_size, pos);
if (!IsValidName(srv->host))
throw SocketException("Invalid name in SRV resource record");
record.rdata = Anope::Format("%hu %hu %hu %s", srv->priority,
srv->weight, srv->port, srv->host.c_str());
record.rdataobj = srv;
break;
}
default:
break;
}
@@ -638,7 +676,7 @@ public:
if (!packet)
return false;
Log(LOG_DEBUG_2) << "Resolver: Notifying slave " << packet->addr.addr();
Log(LOG_DEBUG_2) << "Resolver: Notifying secondary " << packet->addr.addr();
try
{
@@ -939,7 +977,7 @@ public:
void Notify(const Anope::string &zone) override
{
/* notify slaves of the update */
/* notify secondaries of the update */
for (const auto &[ip, port] : notify)
{
sockaddrs addr;
+1 -1
View File
@@ -49,7 +49,7 @@ private:
public:
EMD5(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, ENCRYPTION | VENDOR)
: Module(modname, creator, DEPRECATED | ENCRYPTION | VENDOR)
, md5provider(this, "md5", 16, 64)
{
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
+2 -4
View File
@@ -14,7 +14,7 @@ class ENone final
{
public:
ENone(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, ENCRYPTION | VENDOR)
: Module(modname, creator, DEPRECATED | ENCRYPTION | VENDOR)
{
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
throw ModuleException("enc_none is deprecated and can not be used as a primary encryption method");
@@ -35,9 +35,7 @@ public:
if (!hash_method.equals_cs("plain"))
return;
Anope::string b64pass;
Anope::B64Encode(req->GetPassword(), b64pass);
auto enc = "plain:" + b64pass;
auto enc = "plain:" + Anope::B64Encode(req->GetPassword());
if (nc->pass.equals_cs(enc))
{
// If we are NOT the first encryption module we want to re-encrypt
-86
View File
@@ -1,86 +0,0 @@
/* Include file for high-level encryption routines.
*
* (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.
*/
#include "module.h"
#include "modules/encryption.h"
class EOld final
: public Module
{
private:
ServiceReference<Encryption::Provider> md5;
Anope::string EncryptInternal(const Anope::string &src)
{
if (!md5)
return {};
char digest[32];
memset(digest, 0, sizeof(digest));
auto hash = md5->Encrypt(src);
if (hash.length() != sizeof(digest))
return {}; // Probably a bug?
memcpy(digest, hash.data(), hash.length());
char digest2[16];
for (size_t i = 0; i < sizeof(digest); i += 2)
digest2[i / 2] = XTOI(digest[i]) << 4 | XTOI(digest[i + 1]);
return Anope::Hex(digest2, sizeof(digest2));
}
inline static char XTOI(char c)
{
return c > 9 ? c - 'A' + 10 : c - '0';
}
public:
EOld(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, ENCRYPTION | VENDOR)
, md5("Encryption::Provider", "md5")
{
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
throw ModuleException("enc_old is deprecated and can not be used as a primary encryption method");
ModuleManager::LoadModule("enc_md5", User::Find(creator, true));
if (!md5)
throw ModuleException("Unable to find md5 reference");
}
void OnCheckAuthentication(User *, IdentifyRequest *req) override
{
const auto *na = NickAlias::Find(req->GetAccount());
if (!na)
return;
NickCore *nc = na->nc;
size_t pos = nc->pass.find(':');
if (pos == Anope::string::npos)
return;
Anope::string hash_method(nc->pass.begin(), nc->pass.begin() + pos);
if (!hash_method.equals_cs("oldmd5"))
return;
auto enc = EncryptInternal(req->GetPassword());
if (!enc.empty() && nc->pass.equals_cs(enc))
{
// If we are NOT the first encryption module we want to re-encrypt
// the password with the primary encryption method.
if (ModuleManager::FindFirstOf(ENCRYPTION) != this)
Anope::Encrypt(req->GetPassword(), nc->pass);
req->Success(this);
}
}
};
MODULE_INIT(EOld)
+1 -1
View File
@@ -173,7 +173,7 @@ private:
public:
ESHA1(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, ENCRYPTION | VENDOR)
: Module(modname, creator, DEPRECATED | ENCRYPTION | VENDOR)
, sha1provider(this, "sha1", 20, 64)
{
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
+1 -16
View File
@@ -17,14 +17,6 @@ class ESHA256 final
{
private:
unsigned iv[8];
bool use_iv;
/* initializes the IV with a new random value */
void NewRandomIV()
{
for (auto &ivsegment : iv)
ivsegment = static_cast<uint32_t>(Anope::RandomNumber());
}
/* returns the IV as base64-encrypted string */
Anope::string GetIVString()
@@ -50,11 +42,6 @@ private:
Anope::string EncryptInternal(const Anope::string &src)
{
if (!use_iv)
NewRandomIV();
else
use_iv = false;
sha256_ctx ctx;
sha256_init(&ctx);
for (size_t i = 0; i < 8; ++i)
@@ -69,9 +56,8 @@ private:
public:
ESHA256(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, ENCRYPTION | VENDOR)
: Module(modname, creator, DEPRECATED | ENCRYPTION | VENDOR)
{
use_iv = false;
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
throw ModuleException("enc_sha256 is deprecated and can not be used as a primary encryption method");
}
@@ -92,7 +78,6 @@ public:
return;
GetIVFromPass(nc->pass);
use_iv = true;
auto enc = EncryptInternal(req->GetPassword());
if (nc->pass.equals_cs(enc))
{

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