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

Compare commits

...

93 Commits

Author SHA1 Message Date
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
172 changed files with 6107 additions and 4212 deletions
+1 -1
View File
@@ -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
+64 -45
View File
@@ -259,7 +259,6 @@ serverinfo
* You MUST modify this to match the IRCd you run.
*
* Supported:
* - bahamut
* - hybrid
* - inspircd
* - ngircd
@@ -326,7 +325,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,17 +333,17 @@ 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.
*/
@@ -891,8 +890,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 +930,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"
@@ -1150,11 +1151,14 @@ module
/*
* 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.
*
* IMPORTANT: This will become the default database module in the future but 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 as your
* primary database module.
*/
#module
module
{
name = "db_json"
@@ -1203,17 +1207,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 +1229,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 +1240,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
}
/*
@@ -1404,10 +1416,17 @@ include
}
/*
* IRC2SQL Gateway
* [DEPRECATED] 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.
*
* This module is deprecated in favour of the RPC interface and the rpc_data
* module. This should provide almost all of the same information as irc2sql but
* without requiring MySQL and with much better performance. If you have a use
* case which is not covered by rpc_data then please open an issue so we can
* extend rpc_data before irc2sql is removed.
*
* Requires a MySQL Database and MySQL version 5.5 or higher
*/
#include
+5 -5
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.
@@ -387,15 +387,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; }
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 +403,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"; }
+7 -7
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.
@@ -171,19 +171,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
}
/*
@@ -1179,7 +1179,7 @@ module
name = "cs_seen"
/* If set, uses the older 1.8 style seen, which is less resource intensive */
simple = false
simple = no
/* Sets the time to keep seen entries in the seen database. */
purgetime = 90d
@@ -1228,7 +1228,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 +1269,7 @@ 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_suspend
+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"; }
+1 -1
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.
+13 -13
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"; }
@@ -170,20 +170,20 @@ command { service = "HostServ"; name = "ON"; command = "hostserv/on"; }
*
* Provides the commands hostserv/request, hostserv/activate, hostserv/reject, and hostserv/waiting.
*
* 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
}
@@ -197,7 +197,7 @@ command { service = "HostServ"; name = "WAITING"; command = "hostserv/waiting";
*
* 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"; }
+1 -1
View File
@@ -23,7 +23,7 @@ service
/*
* The realname of the StatServ client.
*/
gecos = "Statistical Service"
real = "Statistical Service"
/*
* The modes this client should use.
+3 -4
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.
*/
@@ -209,7 +208,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"; }
+99 -16
View File
@@ -457,7 +457,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"
@@ -795,8 +795,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 +810,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 +865,6 @@ module
{
name = "xmlrpc"
/* Web service to use. Requires httpd. */
server = "httpd/main"
/*
* Whether to enable the use of XML-RPC extensions.
*
@@ -836,6 +878,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 +946,6 @@ module
*/
#module { name = "rpc_data" }
/*
* rpc_main
*
* Adds the main RPC core functions.
* Requires xmlrpc.
*/
#module { name = "rpc_main" }
/*
* rpc_message
*
+40 -42
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.
@@ -164,7 +164,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 +202,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.
@@ -306,7 +308,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
@@ -344,14 +346,37 @@ 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/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 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 = "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
@@ -400,7 +425,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"; }
/*
@@ -473,8 +498,8 @@ 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
@@ -557,7 +582,6 @@ module
* 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.
@@ -574,9 +598,6 @@ command { service = "NickServ"; name = "SASET AUTOOP"; command = "nickserv/saset
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"; }
@@ -663,8 +684,8 @@ command { service = "NickServ"; name = "SET PROTECT"; command = "nickserv/set/pr
command { service = "NickServ"; name = "SASET PROTECT"; command = "nickserv/saset/protect"; permission = "nickserv/saset/kill"; }
# For compatibility with Anope 2.0.
command { service = "NickServ"; name = "SET KILL"; command = "nickserv/set/protect"; hide = true; }
command { service = "NickServ"; name = "SASET KILL"; command = "nickserv/saset/protect"; permission = "nickserv/saset/protect"; hide = true; }
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 +720,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
}
+1 -1
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.
+4 -5
View File
@@ -256,7 +256,6 @@ serverinfo
* You MUST modify this to match the IRCd you run.
*
* Supported:
* - bahamut
* - hybrid
* - inspircd
* - ngircd
@@ -316,7 +315,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.
@@ -324,17 +323,17 @@ 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.
*/
+1 -1
View File
@@ -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>
+22 -2
View File
@@ -1,5 +1,25 @@
Anope Version 2.1.14-git
------------------------
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.
+23 -6
View File
@@ -1,5 +1,22 @@
Anope Version 2.1.14-git
------------------------
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 +25,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 +151,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;
};
+6 -6
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;
};
@@ -113,7 +113,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 +129,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 +137,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 +151,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.
@@ -195,7 +195,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);
+1 -1
View File
@@ -379,7 +379,7 @@ namespace Anope
/** The debug level we are running at.
*/
extern CoreExport int Debug;
extern CoreExport unsigned Debug;
/** Other command line options.
*/
+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
+6 -6
View File
@@ -99,9 +99,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 +136,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 +173,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 -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;
};
+19 -4
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
@@ -311,6 +325,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 +393,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
*/
+2 -2
View File
@@ -871,10 +871,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
+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)
{
+53 -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,66 @@ 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.
Anope::string rawtoken;
Anope::B64Decode(header.substr(7), rawtoken);
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;
};
+3 -11
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? */
@@ -195,19 +195,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);
}
};
+20 -10
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.
@@ -252,6 +256,12 @@ public:
/** Update the last usermask 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;
};
+81 -80
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Anope\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-25 13:08+0100\n"
"PO-Revision-Date: 2025-04-25 13:08+0100\n"
"POT-Creation-Date: 2025-05-29 16:46+0100\n"
"PO-Revision-Date: 2025-05-29 16:46+0100\n"
"Last-Translator: Sadie Powell <sadie@witchery.services>\n"
"Language-Team: English\n"
"Language: en_US\n"
@@ -775,6 +775,14 @@ msgstr ""
msgid "%s (%d times)"
msgstr ""
#, c-format
msgid "%s (%s ago)"
msgstr ""
#, c-format
msgid "%s (%s from now)"
msgstr ""
#, c-format
msgid "%s (%s) was kicked from %s (\"%s\") %s ago%s"
msgstr ""
@@ -819,6 +827,10 @@ msgstr ""
msgid "%s (minimum %d/%d%%)"
msgstr ""
#, c-format
msgid "%s (now)"
msgstr ""
#, c-format
msgid "%s access list is empty."
msgstr ""
@@ -1088,14 +1100,6 @@ msgid_plural "%zu nicknames in the group."
msgstr[0] ""
msgstr[1] ""
#, c-format
msgid "(%s ago)"
msgstr ""
#, c-format
msgid "(%s from now)"
msgstr ""
msgid "(Split)"
msgstr ""
@@ -1109,9 +1113,6 @@ msgstr ""
msgid "(founder only)"
msgstr ""
msgid "(now)"
msgstr ""
msgid "* AKILL any new clients connecting"
msgstr ""
@@ -1528,15 +1529,15 @@ msgid ""
msgstr ""
msgid ""
"Allows Services Operators to manipulate the SNLINE list. If a user with a realname matching an SNLINE mask attempts to connect, services will not allow them to pursue their IRC session.\n"
"Allows Services Operators to manipulate the SNLINE list. If a user with a realname matching an SNLINE mask attempts to connect, services will not allow them to pursue their IRC session.\n"
"\n"
"SNLINEADD adds the given realname mask to the SNLINE list for the given reason (which must be given). expiry is specified as an integer followed by one of d (days), h (hours), or m (minutes). Combinations (such as 1h30m) are not permitted. If a unit specifier is not included, the default is days (so +30 by itself means 30 days). To add an SNLINE which does not expire, use +0. If the realname mask to be added starts with a +, an expiry time must be given, even if it is the same as the default. The current SNLINE default expiry time can be found with the STATSAKILL command. \n"
"SNLINEADD adds the given realname mask to the SNLINE list for the given reason (which must be given). expiry is specified as an integer followed by one of d (days), h (hours), or m (minutes). Combinations (such as 1h30m) are not permitted. If a unit specifier is not included, the default is days (so +30 by itself means 30 days). To add an SNLINE which does not expire, use +0. If the realname mask to be added starts with a +, an expiry time must be given, even if it is the same as the default. The current SNLINE default expiry time can be found with the STATSAKILL command. \n"
"\n"
"Note: because the realname mask may contain spaces, the separator between it and the reason is a colon."
msgstr ""
msgid ""
"Allows Services Operators to manipulate the SQLINE list. If a user with a nick matching an SQLINE mask attempts to connect, services will not allow them to pursue their IRC session. If the first character of the mask is #, services will prevent the use of matching channels. If the mask is a regular expression, the expression will be matched against channels too.\n"
"Allows Services Operators to manipulate the SQLINE list. If a user with a nick matching an SQLINE mask attempts to connect, services will not allow them to pursue their IRC session. If the first character of the mask is #, services will prevent the use of matching channels. If the mask is a regular expression, the expression will be matched against channels too.\n"
"\n"
"SQLINEADD adds the given (nick/channel) mask to the SQLINE list for the given reason (which must be given). expiry is specified as an integer followed by one of d (days), h (hours), or m (minutes). Combinations (such as 1h30m) are not permitted. If a unit specifier is not included, the default is days (so +30 by itself means 30 days). To add an SQLINE which does not expire, use +0. If the mask to be added starts with a +, an expiry time must be given, even if it is the same as the default. The current SQLINE default expiry time can be found with the STATSAKILL command."
msgstr ""
@@ -1635,11 +1636,11 @@ msgid "Allows you to kill a user from the network. Parameters are the same as fo
msgstr ""
#, c-format
msgid "Allows you to prevent certain pieces of information from being displayed when someone does a %sINFO on the nick. You can hide the email address (EMAIL), last seen user@host mask (USERMASK), the services access status (STATUS) and last quit message (QUIT). The second parameter specifies whether the information should be displayed (OFF) or hidden (ON)."
msgid "Allows you to prevent certain pieces of information from being displayed when someone does a %sINFO on the nick. You can hide the email address (EMAIL), last seen user@host mask (USERMASK), the services access status (STATUS) and last quit message (QUIT). The second parameter specifies whether the information should be displayed (OFF) or hidden (ON)."
msgstr ""
#, c-format
msgid "Allows you to prevent certain pieces of information from being displayed when someone does a %sINFO on your nick. You can hide your email address(EMAIL), last seen user@host mask (USERMASK), your services access status (STATUS) and last quit message (QUIT). The second parameter specifies whether the information should be displayed (OFF) or hidden (ON)."
msgid "Allows you to prevent certain pieces of information from being displayed when someone does a %sINFO on your nick. You can hide your email address(EMAIL), last seen user@host mask (USERMASK), your services access status (STATUS) and last quit message (QUIT). The second parameter specifies whether the information should be displayed (OFF) or hidden (ON)."
msgstr ""
#, c-format
@@ -1945,7 +1946,7 @@ msgstr ""
msgid "Caps kicker"
msgstr ""
msgid "Causes services to do an immediate shutdown; databases are not saved. This command should not be used unless damage to the in-memory copies of the databases is feared and they should not be saved."
msgid "Causes services to do an immediate shutdown; databases are not saved. This command should not be used unless damage to the in-memory copies of the databases is feared and they should not be saved."
msgstr ""
msgid "Causes services to reload the configuration file. Note that some directives still need the restart of the services to take effect (such as services' nicknames, activation of the session limitation, etc.)."
@@ -2272,7 +2273,7 @@ msgid "Current number of SQLINEs: %zu"
msgstr ""
#, c-format
msgid "Current users: %zu (%d ops)"
msgid "Current users: %zu (%zu ops)"
msgstr ""
msgid "DEL entry-num"
@@ -2621,14 +2622,14 @@ msgid "Drops the given nick from the database. Once your nickname is dropped you
msgstr ""
#, c-format
msgid "Edits or displays the list of logon news messages. When a user connects to the network, these messages will be sent to them. However, no more than %d messages will be sent in order to avoid flooding the user. If there are more news messages, only the most recent will be sent."
msgid "Edits or displays the list of logon news messages. When a user connects to the network, these messages will be sent to them. However, no more than %d messages will be sent in order to avoid flooding the user. If there are more news messages, only the most recent will be sent."
msgstr ""
#, c-format
msgid "Edits or displays the list of oper news messages. When a user opers up (with the /OPER command), these messages will be sent to them. However, no more than %d messages will be sent in order to avoid flooding the user. If there are more news messages, only the most recent will be sent."
msgid "Edits or displays the list of oper news messages. When a user opers up (with the /OPER command), these messages will be sent to them. However, no more than %d messages will be sent in order to avoid flooding the user. If there are more news messages, only the most recent will be sent."
msgstr ""
msgid "Edits or displays the list of random news messages. When a user connects to the network, one (and only one) of the random news will be randomly chosen and sent to them."
msgid "Edits or displays the list of random news messages. When a user connects to the network, one (and only one) of the random news will be randomly chosen and sent to them."
msgstr ""
msgid "Email address"
@@ -2692,7 +2693,7 @@ msgid "Enables or disables keepmodes for your nick. If keep modes is enabled, se
msgstr ""
msgid ""
"Enables or disables signed kicks for a channel. When SIGNKICK is set, kicks issued with the KICK command will have the nick that used the command in their reason.\n"
"Enables or disables signed kicks for a channel. When SIGNKICK is set, kicks issued with the KICK command will have the nick that used the command in their reason.\n"
"\n"
"If you use LEVEL, those who have a level that is superior or equal to the SIGNKICK level on the channel won't have their kicks signed."
msgstr ""
@@ -3259,7 +3260,7 @@ msgid ""
msgstr ""
msgid ""
"Lists all registered nicknames which match the given pattern, in nick!user@host format. Nicks with the PRIVATE option set will only be displayed to Services Operators with the proper access. Nicks with the NOEXPIRE option set will have a ! prefixed to the nickname for Services Operators to see.\n"
"Lists all registered nicknames which match the given pattern, in nick!user@host format. Nicks with the PRIVATE option set will only be displayed to Services Operators with the proper access. Nicks with the NOEXPIRE option set will have a ! prefixed to the nickname for Services Operators to see.\n"
"\n"
"Note that a preceding '#' specifies a range.\n"
"\n"
@@ -3291,7 +3292,7 @@ msgid ""
msgstr ""
msgid ""
"Lists any memos you currently have. With NEW, lists only new (unread) memos. Unread memos are marked with a \"*\" to the left of the memo number. You can also specify a list of numbers, as in the example below:\n"
"Lists any memos you currently have. With NEW, lists only new (unread) memos. Unread memos are marked with a \"*\" to the left of the memo number. You can also specify a list of numbers, as in the example below:\n"
" LIST 2-5,7-9\n"
" Lists memos numbered 2 through 5 and 7 through 9."
msgstr ""
@@ -3395,11 +3396,11 @@ msgstr ""
#, c-format
msgid ""
"Maintains the AutoKick list 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"
"Maintains the AutoKick list 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 %sADD command adds the given nick or usermask to the AutoKick list. If a reason is given with the command, that reason will be used when the user is kicked; if not, the default reason is \"User has been banned from the channel\". When akicking a registered nick the %s account will be added to the akick list instead of the mask. All users within that nickgroup will then be akicked. \n"
"The %sADD command adds the given nick or usermask to the AutoKick list. If a reason is given with the command, that reason will be used when the user is kicked; if not, the default reason is \"User has been banned from the channel\". When akicking a registered nick the %s account will be added to the akick list instead of the mask. All users within that nickgroup will then be akicked. \n"
"\n"
"The %sDEL command removes the given nick or mask from the AutoKick list. It does not, however, remove any bans placed by an AutoKick; those must be removed manually.\n"
"The %sDEL command removes the given nick or mask from the AutoKick list. It does not, however, remove any bans placed by an AutoKick; those must be removed manually.\n"
"\n"
"The %sLIST command displays the AutoKick list, or optionally only those AutoKick entries which match the given mask.\n"
"\n"
@@ -3412,9 +3413,9 @@ msgstr ""
#, c-format
msgid ""
"Maintains the access list for a channel. The access list specifies which users are allowed chanop status or access to %s commands on the channel. Different user levels allow for access to different subsets of privileges. Any registered user not on the access list has a user level of 0, and any unregistered user has a user level of -1.\n"
"Maintains the access list for a channel. The access list specifies which users are allowed chanop status or access to %s commands on the channel. Different user levels allow for access to different subsets of privileges. Any registered user not on the access list has a user level of 0, and any unregistered user has a user level of -1.\n"
"\n"
"The %sADD 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 level 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."
"The %sADD 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 level 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."
msgstr ""
#, c-format
@@ -3423,9 +3424,9 @@ msgid ""
"\n"
"The ADD command adds the given word to the bad words list. If SINGLE is specified, a kick will be done only if a user says the entire word. If START is specified, a kick will be done if a user says a word that starts with word. If END is specified, a kick will be done if a user says a word that ends with word. If you don't specify anything, a kick will be issued every time word is said by a user.\n"
"\n"
"The DEL command removes the given word from the bad words list. If a list of entry numbers is given, those entries are deleted. (See the example for LIST below.)\n"
"The DEL command removes the given word from the bad words list. If a list of entry numbers is given, those entries are deleted. (See the example for LIST below.)\n"
"\n"
"The LIST command displays the bad words list. If a wildcard mask is given, only those entries matching the mask are displayed. If a list of entry numbers is given, only those entries are shown; for example:\n"
"The LIST command displays the bad words list. If a wildcard mask is given, only those entries matching the mask are displayed. If a list of entry numbers is given, only those entries are shown; for example:\n"
" #channelLIST2-5,7-9\n"
" Lists bad words entries numbered 2 through 5 and\n"
" 7 through 9.\n"
@@ -3499,7 +3500,7 @@ msgid "Matches for %s:"
msgstr ""
#, c-format
msgid "Maximum users: %d (%s)"
msgid "Maximum users: %zu (%s)"
msgstr ""
#, c-format
@@ -4231,7 +4232,7 @@ msgstr ""
#, c-format
msgid ""
"Registers a channel in the %s database. In order to use this command, you must first be a channel operator on the channel you're trying to register. The description, which is optional, is a general description of the channel's purpose. \n"
"Registers a channel in the %s database. In order to use this command, you must first be a channel operator on the channel you're trying to register. The description, which is optional, is a general description of the channel's purpose. \n"
"\n"
"When you register a channel, you are recorded as the \"founder\" of the channel. The channel founder is allowed to change all of the channel settings for the channel; %s will also automatically give the founder channel operator privileges when they enter the channel."
msgstr ""
@@ -4450,7 +4451,7 @@ msgstr ""
msgid "Sends a memo and requests a read receipt"
msgstr ""
msgid "Sends a passcode to the nickname with instructions on how to reset their password. Email must be the email address associated to the nickname."
msgid "Sends a passcode to the nickname with instructions on how to reset their password. Email must be the email address associated to the nickname."
msgstr ""
msgid "Sends all registered users a memo containing memo-text."
@@ -4466,7 +4467,7 @@ msgid "Sends the named nick or channel a memo containing memo-text. When s
msgstr ""
msgid ""
"Sends you the text of the memos specified. If LAST is given, sends you the memo you most recently received. If NEW is given, sends you all of your new memos. If ALL is given, sends you all of your memos. Otherwise, sends you memo number num. You can also give a list of numbers, as in this example:\n"
"Sends you the text of the memos specified. If LAST is given, sends you the memo you most recently received. If NEW is given, sends you all of your new memos. If ALL is given, sends you all of your memos. Otherwise, sends you memo number num. You can also give a list of numbers, as in this example:\n"
"\n"
" READ 2-5,7-9\n"
" Displays memos numbered 2 through 5 and 7 through 9."
@@ -4527,7 +4528,7 @@ msgid "Servers"
msgstr ""
#, c-format
msgid "Servers found: %d"
msgid "Servers found: %zu"
msgstr ""
msgid "Service"
@@ -4554,7 +4555,7 @@ msgid "Services are now at DEFCON %d."
msgstr ""
#, c-format
msgid "Services are now in debug mode (level %d)."
msgid "Services are now in debug mode (level %u)."
msgstr ""
msgid "Services are now in debug mode."
@@ -4771,15 +4772,15 @@ msgid ""
msgstr ""
msgid ""
"Sets the vhost for all nicks in the same group as that of the given nick. If your IRCD supports vidents, then using SETALL <nick> <ident>@<hostmask> will set idents for users as well as vhosts.\n"
"Sets the vhost for all nicks in the same group as that of the given nick. If your IRCD supports vidents, then using SETALL <nick> <ident>@<hostmask> will set idents for users as well as vhosts.\n"
"\n"
"* NOTE, this will not update the vhost for any nicks added to the group after this command was used."
msgstr ""
msgid "Sets the vhost for the given nick to that of the given hostmask. If your IRCD supports vidents, then using SET <nick> <ident>@<hostmask> set idents for users as well as vhosts."
msgid "Sets the vhost for the given nick to that of the given hostmask. If your IRCD supports vidents, then using SET <nick> <ident>@<hostmask> set idents for users as well as vhosts."
msgstr ""
msgid "Sets various global services options. Option names currently defined are:"
msgid "Sets various global services options. Option names currently defined are:"
msgstr ""
msgid "Sets various memo options. option can be one of:"
@@ -4791,7 +4792,7 @@ msgstr ""
msgid "Sets whether services should set channel status modes on you automatically."
msgstr ""
msgid "Sets whether the given channel will expire. Setting this to ON prevents the channel from expiring."
msgid "Sets whether the given channel will expire. Setting this to ON prevents the channel from expiring."
msgstr ""
msgid "Sets whether the given nickname can be added to a channel access list."
@@ -4801,7 +4802,7 @@ msgstr ""
msgid "Sets whether the given nickname will be given its status modes in channels automatically. Set to ON to allow %s to set status modes on the given nickname automatically when it is entering channels. Note that depending on channel settings some modes may not get set automatically."
msgstr ""
msgid "Sets whether the given nickname will expire. Setting this to ON prevents the nickname from expiring."
msgid "Sets whether the given nickname will expire. Setting this to ON prevents the nickname from expiring."
msgstr ""
msgid "Sets whether you can be added to a channel access list."
@@ -4812,7 +4813,7 @@ msgid "Sets whether you will be given your channel status modes automatically. S
msgstr ""
#, c-format
msgid "Setting %s not known. Type %sLEVELS for a list of valid settings."
msgid "Setting %s not known. Type %sLEVELS for a list of valid settings."
msgstr ""
msgid "Setting for DEBUG must be ON, OFF, or a positive number."
@@ -4982,18 +4983,18 @@ msgstr ""
msgid ""
"Syntax: LIMIT [channel] limit\n"
"\n"
"Sets the maximum number of memos you (or the given channel) are allowed to have. If you set this to 0, no one will be able to send any memos to you. However, you cannot set this any higher than %d."
"Sets the maximum number of memos you (or the given channel) are allowed to have. If you set this to 0, no one will be able to send any memos to you. However, you cannot set this any higher than %d."
msgstr ""
#, c-format
msgid ""
"Syntax: LIMIT [user | channel] {limit | NONE} [HARD]\n"
"\n"
"Sets the maximum number of memos a user or channel is allowed to have. Setting the limit to 0 prevents the user from receiving any memos; setting it to NONE allows the user to receive and keep as many memos as they want. If you do not give a nickname or channel, your own limit is set.\n"
"Sets the maximum number of memos a user or channel is allowed to have. Setting the limit to 0 prevents the user from receiving any memos; setting it to NONE allows the user to receive and keep as many memos as they want. If you do not give a nickname or channel, your own limit is set.\n"
"\n"
"Adding HARD prevents the user from changing the limit. Not adding HARD has the opposite effect, allowing the user to change the limit (even if a previous limit was set with HARD).\n"
"Adding HARD prevents the user from changing the limit. Not adding HARD has the opposite effect, allowing the user to change the limit (even if a previous limit was set with HARD).\n"
"\n"
"This use of the SETLIMIT command is limited to Services Operators. Other users may only enter a limit for themselves or a channel on which they have such privileges, may not remove their limit, may not set a limit above %d, and may not set a hard limit."
"This use of the SETLIMIT command is limited to Services Operators. Other users may only enter a limit for themselves or a channel on which they have such privileges, may not remove their limit, may not set a limit above %d, and may not set a hard limit."
msgstr ""
#, c-format
@@ -5020,7 +5021,7 @@ msgstr ""
msgid ""
"Syntax: READONLY {ON | OFF}\n"
"\n"
"Sets read-only mode on or off. In read-only mode, normal users will not be allowed to modify any services data, including channel access lists, etc. Server operators with sufficient services privileges will be able to modify Services' AKILL, SQLINE, SNLINE and ignore lists, drop, suspend or forbid nicknames and channels, and manage news, oper info and DNS, but any such changes will not be saved unless read-only mode is deactivated before services are terminated or restarted.\n"
"Sets read-only mode on or off. In read-only mode, normal users will not be allowed to modify any services data, including channel access lists, etc. Server operators with sufficient services privileges will be able to modify Services' AKILL, SQLINE, SNLINE and ignore lists, drop, suspend or forbid nicknames and channels, and manage news, oper info and DNS, but any such changes will not be saved unless read-only mode is deactivated before services are terminated or restarted.\n"
"\n"
"This option is equivalent to the command-line option --readonly."
msgstr ""
@@ -5034,7 +5035,7 @@ msgid ""
msgstr ""
#, c-format
msgid "Tells %s that you are really the owner of this nick. Many commands require you to authenticate yourself with this command before you use them. The password should be the same one you sent with the REGISTER command."
msgid "Tells %s that you are really the owner of this nick. Many commands require you to authenticate yourself with this command before you use them. The password should be the same one you sent with the REGISTER command."
msgstr ""
#, c-format
@@ -5051,7 +5052,7 @@ msgid ""
"By default, limited to AOPs or those with level 5 access and above on the channel."
msgstr ""
msgid "Tells services to jupiter a server -- that is, to create a fake \"server\" connected to services which prevents the real server of that name from connecting. The jupe may be removed using a standard SQUIT. If a reason is given, it is placed in the server information field; otherwise, the server information field will contain the text \"Juped by <nick>\", showing the nickname of the person who jupitered the server."
msgid "Tells services to jupiter a server -- that is, to create a fake \"server\" connected to services which prevents the real server of that name from connecting. The jupe may be removed using a standard SQUIT. If a reason is given, it is placed in the server information field; otherwise, the server information field will contain the text \"Juped by <nick>\", showing the nickname of the person who jupitered the server."
msgstr ""
msgid "Tells you about the last time a user was seen"
@@ -5068,7 +5069,7 @@ msgstr ""
#, c-format
msgid ""
"The %s command allows fine control over the meaning of the numeric access levels used for channels. With this command, you can define the access level required for most of %s's functions. (The SETFOUNDER and this command are always restricted to the channel founder).\n"
"The %s command allows fine control over the meaning of the numeric access levels used for channels. With this command, you can define the access level required for most of %s's functions. (The SETFOUNDER and this command are always restricted to the channel founder).\n"
"\n"
"%sSET allows the access level for a function or group of functions to be changed. %sDISABLE (or DIS for short) disables an automatic feature or disallows access to a function by anyone, INCLUDING the founder (although, the founder can always re-enable it). Use %sSET founder to make a level founder only.\n"
"\n"
@@ -5093,9 +5094,9 @@ msgstr ""
#, c-format
msgid ""
"The %sDEL command removes the given mask from the AKILL list if it is present. If a list of entry numbers is given, those entries are deleted. (See the example for LIST below.)\n"
"The %sDEL command removes the given mask from the AKILL list if it is present. If a list of entry numbers is given, those entries are deleted. (See the example for LIST below.)\n"
"\n"
"The %sLIST command displays the AKILL list. If a wildcard mask is given, only those entries matching the mask are displayed. If a list of entry numbers is given, only those entries are shown; for example:\n"
"The %sLIST command displays the AKILL list. If a wildcard mask is given, only those entries matching the mask are displayed. If a list of entry numbers is given, only those entries are shown; for example:\n"
" %sLIST2-5,7-9\n"
" Lists AKILL entries numbered 2 through 5 and 7\n"
" through 9.\n"
@@ -5107,9 +5108,9 @@ msgstr ""
#, c-format
msgid ""
"The %sDEL command removes the given nick from the access list. If a list of entry numbers is given, those entries are deleted. (See the example for LIST below.) You may remove yourself from an access list, even if you do not have access to modify that list otherwise.\n"
"The %sDEL command removes the given nick from the access list. If a list of entry numbers is given, those entries are deleted. (See the example for LIST below.) You may remove yourself from an access list, even if you do not have access to modify that list otherwise.\n"
"\n"
"The %sLIST command displays the access list. If a wildcard mask is given, only those entries matching the mask are displayed. If a list of entry numbers is given, only those entries are shown; for example:\n"
"The %sLIST command displays the access list. If a wildcard mask is given, only those entries matching the mask are displayed. If a list of entry numbers is given, only those entries are shown; for example:\n"
" %s#channelLIST2-5,7-9\n"
" Lists access entries numbered 2 through 5 and\n"
" 7 through 9.\n"
@@ -5120,9 +5121,9 @@ msgid ""
msgstr ""
msgid ""
"The SNLINEDEL command removes the given mask from the SNLINE list if it is present. If a list of entry numbers is given, those entries are deleted. (See the example for LIST below.)\n"
"The SNLINEDEL command removes the given mask from the SNLINE list if it is present. If a list of entry numbers is given, those entries are deleted. (See the example for LIST below.)\n"
"\n"
"The SNLINELIST command displays the SNLINE list. If a wildcard mask is given, only those entries matching the mask are displayed. If a list of entry numbers is given, only those entries are shown; for example:\n"
"The SNLINELIST command displays the SNLINE list. If a wildcard mask is given, only those entries matching the mask are displayed. If a list of entry numbers is given, only those entries are shown; for example:\n"
" SNLINELIST2-5,7-9\n"
" Lists SNLINE entries numbered 2 through 5 and 7\n"
" through 9.\n"
@@ -5629,16 +5630,16 @@ msgstr ""
msgid "Unknown command %s."
msgstr ""
#, c-format
msgid "Unknown command %s. \"%s\" for help."
msgstr ""
#, c-format
msgid "Unknown command %s. Did you mean %s?"
msgstr ""
#, c-format
msgid "Unknown command %s. Did you mean %s? \"%s\" for help."
msgid "Unknown command %s. Did you mean %s? Type \"%s\" for help."
msgstr ""
#, c-format
msgid "Unknown command %s. Type \"%s\" for help."
msgstr ""
#, c-format
@@ -5656,10 +5657,10 @@ msgstr ""
msgid "Unpooled"
msgstr ""
msgid "Unregisters the named channel. Can only be used by the channel founder."
msgid "Unregisters the named channel. Can only be used by the channel founder."
msgstr ""
msgid "Unregisters the specified channel. Only Services Operators can drop a channel of which they are not the founder of."
msgid "Unregisters the specified channel. Only Services Operators can drop a channel of which they are not the founder of."
msgstr ""
msgid "Unsuspend a given nick"
@@ -5739,6 +5740,10 @@ msgstr ""
msgid "VHost"
msgstr ""
#, c-format
msgid "VHost %s has been requested by %s."
msgstr ""
#, c-format
msgid "VHost for %s removed."
msgstr ""
@@ -6260,6 +6265,16 @@ msgstr ""
msgid "Your password reset request has expired."
msgstr ""
msgid "Your requested vhost has been approved."
msgstr ""
msgid "Your requested vhost has been rejected."
msgstr ""
#, c-format
msgid "Your requested vhost has been rejected. Reason: %s"
msgstr ""
msgid "Your vhost has been requested."
msgstr ""
@@ -6375,20 +6390,6 @@ msgstr ""
msgid "[Unconfirmed]"
msgstr ""
#, c-format
msgid "[auto memo] VHost %s has been requested by %s."
msgstr ""
msgid "[auto memo] Your requested vhost has been approved."
msgstr ""
msgid "[auto memo] Your requested vhost has been rejected."
msgstr ""
#, c-format
msgid "[auto memo] Your requested vhost has been rejected. Reason: %s"
msgstr ""
msgid "[{pattern | channel} [INVISIBLE]]"
msgstr ""
+1 -1
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"
+3 -3
View File
@@ -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;
+4 -4
View File
@@ -28,7 +28,7 @@ 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);
@@ -463,12 +463,12 @@ public:
"be issued every time \037word\037 is said by a user."
"\n\n"
"The \002DEL\002 command removes the given word from the "
"bad words list. If a list of entry numbers is given, those "
"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"
+4 -4
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);
@@ -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.
*/
+15 -16
View File
@@ -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);
@@ -569,9 +568,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 +579,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 +598,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 +671,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 +714,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());
}
@@ -847,7 +846,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)."
+3 -3
View File
@@ -501,13 +501,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 "
"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 +516,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"
+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."
));
}
+1 -1
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);
+1 -1
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);
+3 -3
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);
@@ -1008,7 +1008,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 "
+1 -1
View File
@@ -53,7 +53,7 @@ struct SeenInfoType final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *s = static_cast<const SeenInfo *>(obj);
data.Store("nick", s->nick);
+39 -12
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)
{
+2 -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);
@@ -230,7 +230,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);
+7 -6
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));
@@ -556,16 +555,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)
+5 -20
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;
@@ -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);
+24 -23
View File
@@ -61,7 +61,7 @@ public:
continue;
Anope::string akey(yyjson_mut_get_str(key));
if (akey.equals_ci("id"))
if (akey.equals_ci("@id"))
{
this->id = yyjson_mut_get_uint(value);
continue;
@@ -201,6 +201,22 @@ private:
CreateBackup(backupdir, dbpath, monthly_backups, "%Y-%m", "\?\?\?\?-\?\?");
}
void LoadType(Serialize::Type *s_type, yyjson_mut_val *data)
{
auto *entries = yyjson_mut_obj_get(data, s_type->GetName().c_str());
if (!entries || !yyjson_mut_is_arr(entries))
return;
Log(LOG_DEBUG) << "Loading " << yyjson_mut_arr_size(entries) << " " << s_type->GetName() << " records";
size_t idx, max;
yyjson_mut_val *elem;
yyjson_mut_arr_foreach(entries, idx, max, elem)
{
Data ld(elem);
s_type->Unserialize(nullptr, ld);
}
}
DBPair ReadDatabase(const Anope::string &dbname)
{
yyjson_read_err errmsg;
@@ -246,7 +262,7 @@ private:
static void UpdateMetadata(yyjson_mut_doc *doc, yyjson_mut_val *obj)
{
const auto generator = "Anope " + Anope::Version();
const auto generator = "Anope " + Anope::Version() + " " + Anope::VersionBuildString();
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));
@@ -269,19 +285,11 @@ public:
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, data);
}
loaded = false;
loaded = true;
return EVENT_STOP;
}
@@ -346,7 +354,7 @@ public:
auto *elem = yyjson_mut_arr_add_obj(doc, type);
if (item->id)
yyjson_mut_obj_add_uint(doc, elem, "id", item->id);
yyjson_mut_obj_add_uint(doc, elem, "@id", item->id);
Data sd;
s_type->Serialize(item, sd);
@@ -413,15 +421,8 @@ public:
it = databases.emplace(s_type->GetOwner(), db).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);
}
auto &[_, data] = it->second;
LoadType(s_type, data);
}
};
-4
View File
@@ -631,10 +631,6 @@ void MySQLService::Connect()
if (!connect)
throw SQL::Exception("Unable to connect to MySQL service " + this->name + ": " + mysql_error(this->sql));
// We force UTC so that FromUnixtime works as expected.
SQL::Query tzquery("SET time_zone = '+00:00'");
RunQuery(tzquery);
if (this->socket.empty())
Log(LOG_DEBUG) << "Successfully connected to MySQL service " << this->name << " at " << this->server << ":" << this->port;
else
+33 -7
View File
@@ -20,10 +20,10 @@ template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
class XMLRPCServiceInterface final
: public RPC::ServiceInterface
, public HTTPPage
, public HTTP::Page
{
private:
static void SendError(HTTPReply &reply, xmlrpc_env &env)
static void SendError(HTTP::Reply &reply, xmlrpc_env &env)
{
Log(LOG_DEBUG) << "XML-RPC error " << env.fault_code << ": " << env.fault_string;
@@ -69,11 +69,11 @@ public:
XMLRPCServiceInterface(Module *creator)
: RPC::ServiceInterface(creator)
, HTTPPage("/xmlrpc", "text/xml")
, HTTP::Page("/xmlrpc", "text/xml")
{
}
bool OnRequest(HTTPProvider *provider, const Anope::string &page_name, HTTPClient *client, HTTPMessage &message, HTTPReply &reply) override
bool OnRequest(HTTP::Provider *provider, const Anope::string &page_name, HTTP::Client *client, HTTP::Message &message, HTTP::Reply &reply) override
{
xmlrpc_env env;
xmlrpc_env_init(&env);
@@ -93,6 +93,17 @@ public:
request.name = method;
delete method;
if (!tokens.empty())
{
auto it = message.headers.find("Authorization");
if (it == message.headers.end() || !CanExecute(it->second, request.name))
{
xmlrpc_env_set_fault(&env, RPC::ERR_METHOD_NOT_FOUND, "No authorization for method");
SendError(reply, env);
return true;
}
}
ServiceReference<RPC::Event> event(RPC_EVENT, request.name);
if (!event)
{
@@ -265,7 +276,7 @@ class ModuleXMLRPC final
: public Module
{
private:
ServiceReference<HTTPProvider> httpref;
ServiceReference<HTTP::Provider> httpref;
XMLRPCServiceInterface xmlrpcinterface;
public:
@@ -305,11 +316,26 @@ public:
XMLRPCServiceInterface::enable_i8 = modconf.Get<bool>("enable_i8", "yes");
XMLRPCServiceInterface::enable_nil = modconf.Get<bool>("enable_nil", "yes");
this->httpref = ServiceReference<HTTPProvider>("HTTPProvider", modconf.Get<const Anope::string>("server", "httpd/main"));
this->httpref = ServiceReference<HTTP::Provider>(HTTP_PROVIDER, modconf.Get<const Anope::string>("server", "httpd/main"));
if (!httpref)
throw ConfigException("Unable to find http reference, is httpd loaded?");
httpref->RegisterPage(&xmlrpcinterface);
xmlrpcinterface.tokens.clear();
for (int i = 0; i < modconf.CountBlock("token"); ++i)
{
const auto &block = modconf.GetBlock("token", i);
RPC::Token token;
token.token = block.Get<const Anope::string>("token");
if (!token.token.empty())
{
token.token_hash = block.Get<const Anope::string>("token_hash");
spacesepstream(block.Get<const Anope::string>("methods")).GetTokens(token.methods);
xmlrpcinterface.tokens.emplace_back(token);
}
}
httpref->RegisterPage(&xmlrpcinterface);
}
};
+7 -4
View File
@@ -102,24 +102,27 @@ public:
Anope::string buf;
for (const auto &c_name : cmds)
{
buf += ", " + c_name;
if (!buf.empty())
buf += ", ";
buf += c_name;
if (buf.length() > help_wrap_len)
{
source.Reply(" %s", buf.substr(2).c_str());
source.Reply(" %s", buf.c_str());
buf.clear();
}
}
if (buf.length() > 2)
{
source.Reply(" %s", buf.substr(2).c_str());
source.Reply(" %s", buf.c_str());
buf.clear();
}
}
if (!groups.empty())
{
source.Reply(" ");
source.Reply(_("Use the \002%s\032ALL\002 command to list all commands and their descriptions."), source.command.nobreak().c_str());
source.Reply(_("Use the \002%s\032ALL\002 command to list all commands and their descriptions."),
source_command.nobreak().c_str());
}
}
else
+2 -2
View File
@@ -16,11 +16,11 @@ public:
{
}
EventReturn OnChannelModeSet(Channel *c, MessageSource &, ChannelMode *mode, const Anope::string &param) override
EventReturn OnChannelModeSet(Channel *c, MessageSource &, ChannelMode *mode, const ModeData &data) override
{
if (mode->name == "OP" && c && c->ci && c->name.equals_ci(Config->GetModule(this).Get<const Anope::string>("helpchannel")))
{
User *u = User::Find(param);
User *u = User::Find(data.value);
if (u && c->ci->AccessFor(u).HasPriv("OPME"))
u->SetMode(Config->GetClient("OperServ"), "HELPOP");
+5 -5
View File
@@ -39,7 +39,7 @@ struct HostRequestTypeImpl final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *req = static_cast<const HostRequestImpl *>(obj);
data.Store("nick", req->nick);
@@ -226,7 +226,7 @@ public:
FOREACH_MOD(OnSetVHost, (na));
if (Config->GetModule(this->owner).Get<bool>("memouser") && memoserv)
memoserv->Send(source.service->nick, na->nick, _("[auto memo] Your requested vhost has been approved."), true);
memoserv->Send(source.service->nick, na->nick, _("Your requested vhost has been approved."), true);
source.Reply(_("VHost for %s has been activated."), na->nick.c_str());
Log(LOG_COMMAND, source, this) << "for " << na->nick << " for vhost " << (!req->ident.empty() ? req->ident + "@" : "") << req->host;
@@ -279,9 +279,9 @@ public:
{
Anope::string message;
if (!reason.empty())
message = Anope::printf(_("[auto memo] Your requested vhost has been rejected. Reason: %s"), reason.c_str());
message = Anope::printf(_("Your requested vhost has been rejected. Reason: %s"), reason.c_str());
else
message = _("[auto memo] Your requested vhost has been rejected.");
message = _("Your requested vhost has been rejected.");
memoserv->Send(source.service->nick, nick, Language::Translate(source.GetAccount(), message.c_str()), true);
}
@@ -404,7 +404,7 @@ static void req_send_memos(Module *me, CommandSource &source, const Anope::strin
if (!na)
continue;
Anope::string message = Anope::printf(_("[auto memo] VHost \002%s\002 has been requested by %s."), host.c_str(), source.GetNick().c_str());
Anope::string message = Anope::printf(_("VHost \002%s\002 has been requested by %s."), host.c_str(), source.GetNick().c_str());
memoserv->Send(source.service->nick, na->nick, message, true);
}
+2 -2
View File
@@ -96,7 +96,7 @@ public:
source.Reply(" ");
source.Reply(_(
"Sets the vhost for the given nick to that of the given "
"hostmask. If your IRCD supports vidents, then using "
"hostmask. If your IRCD supports vidents, then using "
"SET <nick> <ident>@<hostmask> set idents for users as "
"well as vhosts."
));
@@ -202,7 +202,7 @@ public:
source.Reply(" ");
source.Reply(_(
"Sets the vhost for all nicks in the same group as that "
"of the given nick. If your IRCD supports vidents, then "
"of the given nick. If your IRCD supports vidents, then "
"using SETALL <nick> <ident>@<hostmask> will set idents "
"for users as well as vhosts."
"\n\n"
+27 -27
View File
@@ -18,19 +18,19 @@ static Anope::string BuildDate()
return timebuf;
}
static Anope::string GetStatusFromCode(HTTPError err)
static Anope::string GetStatusFromCode(HTTP::Error err)
{
switch (err)
{
case HTTP_ERROR_OK:
case HTTP::OK:
return "200 OK";
case HTTP_FOUND:
case HTTP::FOUND:
return "302 Found";
case HTTP_BAD_REQUEST:
case HTTP::BAD_REQUEST:
return "400 Bad Request";
case HTTP_PAGE_NOT_FOUND:
case HTTP::PAGE_NOT_FOUND:
return "404 Not Found";
case HTTP_NOT_SUPPORTED:
case HTTP::NOT_SUPPORTED:
return "505 HTTP Version Not Supported";
}
@@ -38,13 +38,13 @@ static Anope::string GetStatusFromCode(HTTPError err)
}
class MyHTTPClient final
: public HTTPClient
: public HTTP::Client
{
HTTPProvider *provider;
HTTPMessage message;
HTTP::Provider *provider;
HTTP::Message message;
bool header_done = false, served = false;
Anope::string page_name;
Reference<HTTPPage> page;
Reference<HTTP::Page> page;
Anope::string ip;
unsigned content_length = 0;
@@ -64,7 +64,7 @@ class MyHTTPClient final
if (!this->page)
{
this->SendError(HTTP_PAGE_NOT_FOUND, "Page not found");
this->SendError(HTTP::PAGE_NOT_FOUND, "Page not found");
return;
}
@@ -83,7 +83,7 @@ class MyHTTPClient final
Log(LOG_DEBUG, "httpd") << "httpd: Serving page " << this->page_name << " to " << this->ip;
HTTPReply reply;
HTTP::Reply reply;
reply.content_type = this->page->GetContentType();
if (this->page->OnRequest(this->provider, this->page_name, this, this->message, reply))
@@ -93,7 +93,7 @@ class MyHTTPClient final
public:
time_t created;
MyHTTPClient(HTTPProvider *l, int f, const sockaddrs &a) : Socket(f, l->GetFamily()), HTTPClient(l, f, a), provider(l), ip(a.addr()), created(Anope::CurTime)
MyHTTPClient(HTTP::Provider *l, int f, const sockaddrs &a) : Socket(f, l->GetFamily()), HTTP::Client(l, f, a), provider(l), ip(a.addr()), created(Anope::CurTime)
{
Log(LOG_DEBUG, "httpd") << "Accepted connection " << f << " from " << a.addr();
}
@@ -142,7 +142,7 @@ public:
size_t sz = token.find('=');
if (sz == Anope::string::npos || !sz || sz + 1 >= token.length())
continue;
this->message.post_data[token.substr(0, sz)] = HTTPUtils::URLDecode(token.substr(sz + 1));
this->message.post_data[token.substr(0, sz)] = HTTP::URLDecode(token.substr(sz + 1));
Log(LOG_DEBUG_2) << "HTTP POST from " << this->clientaddr.addr() << ": " << token.substr(0, sz) << ": " << this->message.post_data[token.substr(0, sz)];
}
@@ -163,13 +163,13 @@ public:
if (params.empty() || (params[0] != "GET" && params[0] != "POST"))
{
this->SendError(HTTP_BAD_REQUEST, "Unknown operation");
this->SendError(HTTP::BAD_REQUEST, "Unknown operation");
return true;
}
if (params.size() != 3)
{
this->SendError(HTTP_BAD_REQUEST, "Invalid parameters");
this->SendError(HTTP::BAD_REQUEST, "Invalid parameters");
return true;
}
@@ -191,7 +191,7 @@ public:
size_t sz = token.find('=');
if (sz == Anope::string::npos || !sz || sz + 1 >= token.length())
continue;
this->message.get_data[token.substr(0, sz)] = HTTPUtils::URLDecode(token.substr(sz + 1));
this->message.get_data[token.substr(0, sz)] = HTTP::URLDecode(token.substr(sz + 1));
}
}
@@ -229,9 +229,9 @@ public:
return true;
}
void SendError(HTTPError err, const Anope::string &msg) override
void SendError(HTTP::Error err, const Anope::string &msg) override
{
HTTPReply h;
HTTP::Reply h;
h.error = err;
@@ -240,7 +240,7 @@ public:
this->SendReply(&h);
}
void SendReply(HTTPReply *msg) override
void SendReply(HTTP::Reply *msg) override
{
this->WriteClient("HTTP/1.1 " + GetStatusFromCode(msg->error));
this->WriteClient("Date: " + BuildDate());
@@ -281,17 +281,17 @@ public:
};
class MyHTTPProvider final
: public HTTPProvider
: public HTTP::Provider
, public Timer
{
int timeout;
std::map<Anope::string, HTTPPage *> pages;
std::map<Anope::string, HTTP::Page *> pages;
std::list<Reference<MyHTTPClient> > clients;
public:
MyHTTPProvider(Module *c, const Anope::string &n, const Anope::string &i, const unsigned short p, const int t, bool s)
: Socket(-1, i.find(':') == Anope::string::npos ? AF_INET : AF_INET6)
, HTTPProvider(c, n, i, p, s)
, HTTP::Provider(c, n, i, p, s)
, Timer(c, 10, true)
, timeout(t)
{
@@ -317,17 +317,17 @@ public:
return c;
}
bool RegisterPage(HTTPPage *page) override
bool RegisterPage(HTTP::Page *page) override
{
return this->pages.emplace(page->GetURL(), page).second;
}
void UnregisterPage(HTTPPage *page) override
void UnregisterPage(HTTP::Page *page) override
{
this->pages.erase(page->GetURL());
}
HTTPPage *FindPage(const Anope::string &pname) override
HTTP::Page *FindPage(const Anope::string &pname) override
{
if (this->pages.count(pname) == 0)
return NULL;
@@ -443,7 +443,7 @@ public:
for (std::map<Anope::string, MyHTTPProvider *>::iterator it = this->providers.begin(), it_end = this->providers.end(); it != it_end;)
{
HTTPProvider *p = it->second;
HTTP::Provider *p = it->second;
++it;
if (existing.count(p->name) == 0)
+2 -2
View File
@@ -232,11 +232,11 @@ void IRC2SQL::OnJoinChannel(User *u, Channel *c)
this->RunQuery(query);
}
EventReturn IRC2SQL::OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param)
EventReturn IRC2SQL::OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data)
{
if (mode->type == MODE_STATUS)
{
User *u = User::Find(param);
User *u = User::Find(data.value);
if (u == NULL)
return EVENT_CONTINUE;
+1 -1
View File
@@ -79,7 +79,7 @@ public:
void OnChannelDelete(Channel *c) override;
void OnLeaveChannel(User *u, Channel *c) override;
void OnJoinChannel(User *u, Channel *c) override;
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;
EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) override;
void OnTopicUpdated(User *source, Channel *c, const Anope::string &user, const Anope::string &topic) override;
+1 -1
View File
@@ -142,7 +142,7 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Lists any memos you currently have. With \002NEW\002, lists only "
"Lists any memos you currently have. With \002NEW\002, lists only "
"new (unread) memos. Unread memos are marked with a \"*\" "
"to the left of the memo number. You can also specify a list "
"of numbers, as in the example below:\n"
+1 -1
View File
@@ -201,7 +201,7 @@ public:
source.Reply(_(
"Sends you the text of the memos specified. If LAST is "
"given, sends you the memo you most recently received. If "
"NEW is given, sends you all of your new memos. If ALL is "
"NEW is given, sends you all of your new memos. If ALL is "
"given, sends you all of your memos. Otherwise, sends you "
"memo number \037num\037. You can also give a list of numbers, "
"as in this example:"
+5 -5
View File
@@ -269,19 +269,19 @@ public:
"Syntax: \002LIMIT [\037user\037 | \037channel\037] {\037limit\037 | NONE} [HARD]\002"
"\n\n"
"Sets the maximum number of memos a user or channel is "
"allowed to have. Setting the limit to 0 prevents the user "
"allowed to have. Setting the limit to 0 prevents the user "
"from receiving any memos; setting it to \002NONE\002 allows the "
"user to receive and keep as many memos as they want. If "
"user to receive and keep as many memos as they want. If "
"you do not give a nickname or channel, your own limit is "
"set."
"\n\n"
"Adding \002HARD\002 prevents the user from changing the limit. Not "
"Adding \002HARD\002 prevents the user from changing the limit. Not "
"adding \002HARD\002 has the opposite effect, allowing the user to "
"change the limit (even if a previous limit was set with "
"\002HARD\002)."
"\n\n"
"This use of the \002SET\032LIMIT\002 command is limited to \002Services "
"Operators\002. Other users may only enter a limit for themselves "
"Operators\002. Other users may only enter a limit for themselves "
"or a channel on which they have such privileges, may not "
"remove their limit, may not set a limit above %d, and may "
"not set a hard limit."
@@ -294,7 +294,7 @@ public:
"\n\n"
"Sets the maximum number of memos you (or the given channel) "
"are allowed to have. If you set this to 0, no one will be "
"able to send any memos to you. However, you cannot set "
"able to send any memos to you. However, you cannot set "
"this any higher than %d."
),
max_memos);
+13 -3
View File
@@ -11,6 +11,11 @@
#include "module.h"
namespace
{
Anope::string enforcer_user, enforcer_host, enforcer_real;
}
class NickServCollide;
static std::set<NickServCollide *> collides;
@@ -98,7 +103,7 @@ class NickServRelease final
public:
NickServRelease(Module *me, NickAlias *na, time_t delay)
: User(na->nick, Config->GetModule(me).Get<const Anope::string>("enforceruser", "user"), Config->GetModule(me).Get<const Anope::string>("enforcerhost", Me->GetName()), "", "", Me, "Services Enforcer", Anope::CurTime, "", {}, IRCD->UID_Retrieve(), NULL)
: User(na->nick, enforcer_user, enforcer_host, "", "", Me, enforcer_real, Anope::CurTime, "", {}, IRCD->UID_Retrieve(), nullptr)
, Timer(me, delay)
, nick(na->nick)
{
@@ -317,7 +322,8 @@ public:
void OnReload(Configuration::Conf &conf) override
{
const Anope::string &nsnick = conf.GetModule(this).Get<const Anope::string>("client");
const auto &modconf = conf.GetModule(this);
const Anope::string &nsnick = modconf.Get<const Anope::string>("client");
if (nsnick.empty())
throw ConfigException(Module::name + ": <client> must be defined");
@@ -328,7 +334,7 @@ public:
NickServ = bi;
spacesepstream(conf.GetModule(this).Get<const Anope::string>("defaults", "memo_signon memo_receive")).GetTokens(defaults);
spacesepstream(modconf.Get<const Anope::string>("defaults", "memo_signon memo_receive")).GetTokens(defaults);
if (defaults.empty())
{
defaults.emplace_back("MEMO_SIGNON");
@@ -336,6 +342,10 @@ public:
}
else if (defaults[0].equals_ci("none"))
defaults.clear();
enforcer_user = modconf.Get<const Anope::string>("enforceruser", "enforcer");
enforcer_host = modconf.Get<const Anope::string>("enforcerhost", Me->GetName());
enforcer_real = modconf.Get<const Anope::string>("enforcerreal", "Services Enforcer");
}
void OnDelNick(NickAlias *na) override
+1 -1
View File
@@ -49,7 +49,7 @@ struct AJoinEntryType final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *aj = static_cast<const AJoinEntry *>(obj);
if (!aj->owner)
+1 -1
View File
@@ -69,7 +69,7 @@ public:
if (!code)
{
code = na->Extend<Anope::string>("nickname-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, na->nick.c_str(), source.service->GetQueryCommand("nickserv/drop").c_str(),
+327
View File
@@ -0,0 +1,327 @@
/* NickServ core functions
*
* (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"
namespace
{
bool clean = false;
unsigned maxemails = 0;
/* strip dots from username, and remove anything after the first + */
Anope::string CleanMail(const Anope::string &email)
{
size_t host = email.find('@');
if (host == Anope::string::npos)
return email;
Anope::string username = email.substr(0, host);
username = username.replace_all_cs(".", "");
size_t sz = username.find('+');
if (sz != Anope::string::npos)
username = username.substr(0, sz);
Anope::string cleaned = username + email.substr(host);
Log(LOG_DEBUG) << "cleaned " << email << " to " << cleaned;
return cleaned;
}
unsigned CountEmail(const Anope::string &email, NickCore *unc)
{
unsigned count = 0;
if (email.empty())
return 0;
Anope::string cleanemail = clean ? CleanMail(email) : email;
for (const auto &[_, nc] : *NickCoreList)
{
Anope::string cleannc = clean ? CleanMail(nc->email) : nc->email;
if (unc != nc && cleanemail.equals_ci(cleannc))
++count;
}
return count;
}
bool CheckLimitReached(CommandSource &source, const Anope::string &email, bool ignoreself)
{
if (!maxemails || email.empty())
return false;
if (CountEmail(email, ignoreself ? source.GetAccount() : NULL) < maxemails)
return false;
source.Reply(maxemails, N_("The email address \002%s\002 has reached its usage limit of %u user.", "The email address \002%s\002 has reached its usage limit of %u users."), email.c_str(), maxemails);
return true;
}
}
class CommandNSGetEmail final
: public Command
{
public:
CommandNSGetEmail(Module *creator)
: Command(creator, "nickserv/getemail", 1, 1)
{
this->SetDesc(_("Matches and returns all users that registered using given email"));
this->SetSyntax(_("\037email\037"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
const Anope::string &email = params[0];
int j = 0;
Log(LOG_ADMIN, source, this) << "on " << email;
for (const auto &[_, nc] : *NickCoreList)
{
if (!nc->email.empty() && Anope::Match(nc->email, email))
{
++j;
source.Reply(_("Email matched: \002%s\002 (\002%s\002) to \002%s\002."), nc->display.c_str(), nc->email.c_str(), email.c_str());
}
}
if (j <= 0)
{
source.Reply(_("No registrations matching \002%s\002 were found."), email.c_str());
return;
}
return;
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Returns the matching accounts that used given email."));
return true;
}
};
class CommandNSSetEmail
: public Command
{
static bool SendConfirmMail(User *u, NickCore *nc, BotInfo *bi, const Anope::string &new_email)
{
Anope::string code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", "15"));
std::pair<Anope::string, Anope::string> *n = nc->Extend<std::pair<Anope::string, Anope::string> >("ns_set_email");
n->first = new_email;
n->second = code;
Anope::map<Anope::string> vars = {
{ "old_email", nc->email },
{ "new_email", new_email },
{ "account", nc->display },
{ "network", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname") },
{ "code", code },
};
auto subject = Anope::Template(Config->GetBlock("mail").Get<const Anope::string>("emailchange_subject"), vars);
auto message = Anope::Template(Config->GetBlock("mail").Get<const Anope::string>("emailchange_message"), vars);
Anope::string old = nc->email;
nc->email = new_email;
bool b = Mail::Send(u, nc, bi, subject, message);
nc->email = old;
return b;
}
public:
CommandNSSetEmail(Module *creator, const Anope::string &cname = "nickserv/set/email", size_t min = 0) : Command(creator, cname, min, min + 1)
{
this->SetDesc(_("Associate an email address with your nickname"));
this->SetSyntax(_("\037address\037"));
}
void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
{
if (Anope::ReadOnly)
{
source.Reply(READ_ONLY_MODE);
return;
}
const NickAlias *na = NickAlias::Find(user);
if (!na)
{
source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
return;
}
NickCore *nc = na->nc;
if (nc->HasExt("UNCONFIRMED"))
{
source.Reply(_("You may not change the email of an unconfirmed account."));
return;
}
if (param.empty() && Config->GetModule("nickserv").Get<bool>("forceemail", "yes"))
{
source.Reply(_("You cannot unset the email on this network."));
return;
}
else if (Config->GetModule("nickserv").Get<bool>("secureadmins", "yes") && source.nc != nc && nc->IsServicesOper())
{
source.Reply(_("You may not change the email of other Services Operators."));
return;
}
else if (!param.empty() && !Mail::Validate(param))
{
source.Reply(MAIL_X_INVALID, param.c_str());
return;
}
else if (CheckLimitReached(source, param, true))
return;
EventReturn MOD_RESULT;
FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
if (MOD_RESULT == EVENT_STOP)
return;
const auto nsmailreg = Config->GetModule("ns_register").Get<const Anope::string>("registration").equals_ci("mail");
if (!param.empty() && Config->GetModule("nickserv").Get<bool>("confirmemailchanges", nsmailreg ? "yes" : "no") && source.GetAccount() == nc)
{
if (SendConfirmMail(source.GetUser(), source.GetAccount(), source.service, param))
{
Log(LOG_COMMAND, source, this) << "to request changing the email of " << nc->display << " to " << param;
source.Reply(_("A confirmation email has been sent to \002%s\002. Follow the instructions in it to change your email address."), param.c_str());
}
}
else
{
if (!param.empty())
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change the email of " << nc->display << " to " << param;
nc->email = param;
source.Reply(_("Email address for \002%s\002 changed to \002%s\002."), nc->display.c_str(), param.c_str());
}
else
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to unset the email of " << nc->display;
nc->email.clear();
source.Reply(_("Email address for \002%s\002 unset."), nc->display.c_str());
}
}
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, source.nc->display, params.size() ? params[0] : "");
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Associates the given email address with your nickname. "
"This address will be displayed whenever someone requests "
"information on the nickname with the \002INFO\002 command."
));
return true;
}
};
class CommandNSSASetEmail final
: public CommandNSSetEmail
{
public:
CommandNSSASetEmail(Module *creator) : CommandNSSetEmail(creator, "nickserv/saset/email", 2)
{
this->ClearSyntax();
this->SetSyntax(_("\037nickname\037 \037address\037"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, params[0], params.size() > 1 ? params[1] : "");
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Associates the given email address with the nickname."));
return true;
}
};
class NSEmail final
: public Module
{
private:
CommandNSGetEmail commandnsgetemail;
CommandNSSetEmail commandnssetemail;
CommandNSSASetEmail commandnssasetemail;
/* email, passcode */
PrimitiveExtensibleItem<std::pair<Anope::string, Anope::string>> ns_set_email;
public:
NSEmail(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandnsgetemail(this)
, commandnssetemail(this)
, commandnssasetemail(this)
, ns_set_email(this, "ns_set_email")
{
}
void OnReload(Configuration::Conf &conf) override
{
const auto &modconf = conf.GetModule(this);
maxemails = modconf.Get<unsigned>("maxemails");
clean = modconf.Get<bool>("remove_aliases", "yes");
}
EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) override
{
NickCore *uac = source.nc;
if (command->name == "nickserv/confirm" && !params.empty() && uac)
{
std::pair<Anope::string, Anope::string> *n = ns_set_email.Get(uac);
if (n)
{
if (params[0] == n->second)
{
uac->email = n->first;
Log(LOG_COMMAND, source, command) << "to confirm their email address change to " << uac->email;
source.Reply(_("Your email address has been changed to \002%s\002."), uac->email.c_str());
ns_set_email.Unset(uac);
return EVENT_STOP;
}
}
}
if (!source.IsOper() && command->name == "nickserv/register")
{
if (CheckLimitReached(source, params.size() > 1 ? params[1] : "", false))
return EVENT_STOP;
}
else if (!source.IsOper() && command->name == "nickserv/ungroup" && source.GetAccount())
{
if (CheckLimitReached(source, source.GetAccount()->email, false))
return EVENT_STOP;
}
return EVENT_CONTINUE;
}
};
MODULE_INIT(NSEmail)
-78
View File
@@ -1,78 +0,0 @@
/* NickServ core functions
*
* (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.
*
* A simple call to check for all emails that a user may have registered
* with. It returns the nicks that match the email you provide. Wild
* Cards are not excepted. Must use user@email-host.
*/
#include "module.h"
class CommandNSGetEmail final
: public Command
{
public:
CommandNSGetEmail(Module *creator)
: Command(creator, "nickserv/getemail", 1, 1)
{
this->SetDesc(_("Matches and returns all users that registered using given email"));
this->SetSyntax(_("\037email\037"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
const Anope::string &email = params[0];
int j = 0;
Log(LOG_ADMIN, source, this) << "on " << email;
for (const auto &[_, nc] : *NickCoreList)
{
if (!nc->email.empty() && Anope::Match(nc->email, email))
{
++j;
source.Reply(_("Email matched: \002%s\002 (\002%s\002) to \002%s\002."), nc->display.c_str(), nc->email.c_str(), email.c_str());
}
}
if (j <= 0)
{
source.Reply(_("No registrations matching \002%s\002 were found."), email.c_str());
return;
}
return;
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Returns the matching accounts that used given email."));
return true;
}
};
class NSGetEmail final
: public Module
{
private:
CommandNSGetEmail commandnsgetemail;
public:
NSGetEmail(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandnsgetemail(this)
{
}
};
MODULE_INIT(NSGetEmail)
+2 -2
View File
@@ -113,8 +113,8 @@ public:
source.Reply(" ");
source.Reply(_(
"Tells %s that you are really the owner of this "
"nick. Many commands require you to authenticate yourself "
"with this command before you use them. The password "
"nick. Many commands require you to authenticate yourself "
"with this command before you use them. The password "
"should be the same one you sent with the \002REGISTER\002 "
"command."
),
+2 -2
View File
@@ -251,7 +251,7 @@ public:
source.Reply(_(
"Allows you to prevent certain pieces of information from "
"being displayed when someone does a %s\032\002INFO\002 on your "
"nick. You can hide your email address\032(\002EMAIL\002), last seen "
"nick. You can hide your email address\032(\002EMAIL\002), last seen "
"user@host mask (\002USERMASK\002), your services access status "
"(\002STATUS\002) and last quit message (\002QUIT\002). "
"The second parameter specifies whether the information should "
@@ -284,7 +284,7 @@ public:
source.Reply(_(
"Allows you to prevent certain pieces of information from "
"being displayed when someone does a %s\032\002INFO\002 on the "
"nick. You can hide the email address (\002EMAIL\002), last seen "
"nick. You can hide the email address (\002EMAIL\002), last seen "
"user@host mask (\002USERMASK\002), the services access status "
"(\002STATUS\002) and last quit message (\002QUIT\002). "
"The second parameter specifies whether the information should "
+2 -2
View File
@@ -137,9 +137,9 @@ public:
source.Reply(" ");
source.Reply(_(
"Lists all registered nicknames which match the given "
"pattern, in \037nick!user@host\037 format. Nicks with the \002PRIVATE\002 "
"pattern, in \037nick!user@host\037 format. Nicks with the \002PRIVATE\002 "
"option set will only be displayed to Services Operators with the "
"proper access. Nicks with the \002NOEXPIRE\002 option set will have "
"proper access. Nicks with the \002NOEXPIRE\002 option set will have "
"a \002!\002 prefixed to the nickname for Services Operators to see."
"\n\n"
"Note that a preceding '#' specifies a range."
-107
View File
@@ -1,107 +0,0 @@
/* ns_maxemail.cpp - Limit the amount of times an email address
* can be used for a NickServ account.
*
* (C) 2003-2025 Anope Team
* Contact us at team@anope.org
*
* Included in the Anope module pack since Anope 1.7.9
* Anope Coder: GeniusDex <geniusdex@anope.org>
*
* Please read COPYING and README for further details.
*/
#include "module.h"
class NSMaxEmail final
: public Module
{
bool clean = false;
/* strip dots from username, and remove anything after the first + */
static Anope::string CleanMail(const Anope::string &email)
{
size_t host = email.find('@');
if (host == Anope::string::npos)
return email;
Anope::string username = email.substr(0, host);
username = username.replace_all_cs(".", "");
size_t sz = username.find('+');
if (sz != Anope::string::npos)
username = username.substr(0, sz);
Anope::string cleaned = username + email.substr(host);
Log(LOG_DEBUG) << "cleaned " << email << " to " << cleaned;
return cleaned;
}
bool CheckLimitReached(CommandSource &source, const Anope::string &email, bool ignoreself)
{
const auto NSEmailMax = Config->GetModule(this).Get<unsigned>("maxemails");
if (NSEmailMax < 1 || email.empty())
return false;
if (this->CountEmail(email, ignoreself ? source.GetAccount() : NULL) < NSEmailMax)
return false;
source.Reply(NSEmailMax, N_("The email address \002%s\002 has reached its usage limit of %u user.", "The email address \002%s\002 has reached its usage limit of %u users."), email.c_str(), NSEmailMax);
return true;
}
unsigned CountEmail(const Anope::string &email, NickCore *unc)
{
unsigned count = 0;
if (email.empty())
return 0;
Anope::string cleanemail = clean ? CleanMail(email) : email;
for (const auto &[_, nc] : *NickCoreList)
{
Anope::string cleannc = clean ? CleanMail(nc->email) : nc->email;
if (unc != nc && cleanemail.equals_ci(cleannc))
++count;
}
return count;
}
public:
NSMaxEmail(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
{
}
void OnReload(Configuration::Conf &conf) override
{
clean = conf.GetModule(this).Get<bool>("remove_aliases", "true");
}
EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) override
{
if (source.IsOper())
return EVENT_CONTINUE;
if (command->name == "nickserv/register")
{
if (this->CheckLimitReached(source, params.size() > 1 ? params[1] : "", false))
return EVENT_STOP;
}
else if (command->name == "nickserv/set/email")
{
if (this->CheckLimitReached(source, params.size() > 0 ? params[0] : "", true))
return EVENT_STOP;
}
else if (command->name == "nickserv/ungroup" && source.GetAccount())
{
if (this->CheckLimitReached(source, source.GetAccount()->email, false))
return EVENT_STOP;
}
return EVENT_CONTINUE;
}
};
MODULE_INIT(NSMaxEmail)
+1 -1
View File
@@ -439,7 +439,7 @@ static bool SendRegmail(User *u, const NickAlias *na, BotInfo *bi)
if (code == NULL)
{
code = na->nc->Extend<Anope::string>("passcode");
*code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", 15));
*code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", "15"));
}
Anope::map<Anope::string> vars = {
+2 -2
View File
@@ -52,7 +52,7 @@ public:
source.Reply(" ");
source.Reply(_(
"Sends a passcode to the nickname with instructions on how to "
"reset their password. Email must be the email address associated "
"reset their password. Email must be the email address associated "
"to the nickname."
));
return true;
@@ -135,7 +135,7 @@ public:
static bool SendResetEmail(User *u, const NickAlias *na, BotInfo *bi)
{
auto *ri = na->nc->Extend<ResetInfo>("reset");
ri->code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", 15));
ri->code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", "15"));
ri->time = Anope::CurTime;
Anope::map<Anope::string> vars = {
+1 -1
View File
@@ -405,7 +405,7 @@ public:
return;
}
const auto badpasslimit = Config->GetBlock("options").Get<int>("badpasslimit");
const auto badpasslimit = Config->GetBlock("options").Get<unsigned>("badpasslimit");
if (!badpasslimit)
return;
+2 -180
View File
@@ -532,153 +532,6 @@ public:
}
};
class CommandNSSetEmail
: public Command
{
static bool SendConfirmMail(User *u, NickCore *nc, BotInfo *bi, const Anope::string &new_email)
{
Anope::string code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", 15));
std::pair<Anope::string, Anope::string> *n = nc->Extend<std::pair<Anope::string, Anope::string> >("ns_set_email");
n->first = new_email;
n->second = code;
Anope::map<Anope::string> vars = {
{ "old_email", nc->email },
{ "new_email", new_email },
{ "account", nc->display },
{ "network", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname") },
{ "code", code },
};
auto subject = Anope::Template(Config->GetBlock("mail").Get<const Anope::string>("emailchange_subject"), vars);
auto message = Anope::Template(Config->GetBlock("mail").Get<const Anope::string>("emailchange_message"), vars);
Anope::string old = nc->email;
nc->email = new_email;
bool b = Mail::Send(u, nc, bi, subject, message);
nc->email = old;
return b;
}
public:
CommandNSSetEmail(Module *creator, const Anope::string &cname = "nickserv/set/email", size_t min = 0) : Command(creator, cname, min, min + 1)
{
this->SetDesc(_("Associate an email address with your nickname"));
this->SetSyntax(_("\037address\037"));
}
void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
{
if (Anope::ReadOnly)
{
source.Reply(READ_ONLY_MODE);
return;
}
const NickAlias *na = NickAlias::Find(user);
if (!na)
{
source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
return;
}
NickCore *nc = na->nc;
if (nc->HasExt("UNCONFIRMED"))
{
source.Reply(_("You may not change the email of an unconfirmed account."));
return;
}
if (param.empty() && Config->GetModule("nickserv").Get<bool>("forceemail", "yes"))
{
source.Reply(_("You cannot unset the email on this network."));
return;
}
else if (Config->GetModule("nickserv").Get<bool>("secureadmins", "yes") && source.nc != nc && nc->IsServicesOper())
{
source.Reply(_("You may not change the email of other Services Operators."));
return;
}
else if (!param.empty() && !Mail::Validate(param))
{
source.Reply(MAIL_X_INVALID, param.c_str());
return;
}
EventReturn MOD_RESULT;
FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
if (MOD_RESULT == EVENT_STOP)
return;
const auto nsmailreg = Config->GetModule("ns_register").Get<const Anope::string>("registration").equals_ci("mail");
if (!param.empty() && Config->GetModule("nickserv").Get<bool>("confirmemailchanges", nsmailreg ? "yes" : "no") && !source.IsServicesOper())
{
if (SendConfirmMail(source.GetUser(), source.GetAccount(), source.service, param))
{
Log(LOG_COMMAND, source, this) << "to request changing the email of " << nc->display << " to " << param;
source.Reply(_("A confirmation email has been sent to \002%s\002. Follow the instructions in it to change your email address."), param.c_str());
}
}
else
{
if (!param.empty())
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change the email of " << nc->display << " to " << param;
nc->email = param;
source.Reply(_("Email address for \002%s\002 changed to \002%s\002."), nc->display.c_str(), param.c_str());
}
else
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to unset the email of " << nc->display;
nc->email.clear();
source.Reply(_("Email address for \002%s\002 unset."), nc->display.c_str());
}
}
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, source.nc->display, params.size() ? params[0] : "");
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Associates the given email address with your nickname. "
"This address will be displayed whenever someone requests "
"information on the nickname with the \002INFO\002 command."
));
return true;
}
};
class CommandNSSASetEmail final
: public CommandNSSetEmail
{
public:
CommandNSSASetEmail(Module *creator) : CommandNSSetEmail(creator, "nickserv/saset/email", 2)
{
this->ClearSyntax();
this->SetSyntax(_("\037nickname\037 \037address\037"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, params[0], params.size() > 1 ? params[1] : "");
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Associates the given email address with the nickname."));
return true;
}
};
class CommandNSSASetNoexpire final
: public Command
{
@@ -727,7 +580,7 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Sets whether the given nickname will expire. Setting this "
"Sets whether the given nickname will expire. Setting this "
"to \002ON\002 prevents the nickname from expiring."
));
return true;
@@ -749,9 +602,6 @@ class NSSet final
CommandNSSetDisplay commandnssetdisplay;
CommandNSSASetDisplay commandnssasetdisplay;
CommandNSSetEmail commandnssetemail;
CommandNSSASetEmail commandnssasetemail;
CommandNSSetPassword commandnssetpassword;
CommandNSSASetPassword commandnssasetpassword;
@@ -759,48 +609,20 @@ class NSSet final
SerializableExtensibleItem<bool> autoop, neverop, noexpire;
/* email, passcode */
PrimitiveExtensibleItem<std::pair<Anope::string, Anope::string > > ns_set_email;
public:
NSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
commandnsset(this), commandnssaset(this),
commandnssetautoop(this), commandnssasetautoop(this),
commandnssetneverop(this), commandnssasetneverop(this),
commandnssetdisplay(this), commandnssasetdisplay(this),
commandnssetemail(this), commandnssasetemail(this),
commandnssetpassword(this), commandnssasetpassword(this),
commandnssasetnoexpire(this),
autoop(this, "AUTOOP"), neverop(this, "NEVEROP"),
noexpire(this, "NS_NO_EXPIRE"),
ns_set_email(this, "ns_set_email")
noexpire(this, "NS_NO_EXPIRE")
{
}
EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) override
{
NickCore *uac = source.nc;
if (command->name == "nickserv/confirm" && !params.empty() && uac)
{
std::pair<Anope::string, Anope::string> *n = ns_set_email.Get(uac);
if (n)
{
if (params[0] == n->second)
{
uac->email = n->first;
Log(LOG_COMMAND, source, command) << "to confirm their email address change to " << uac->email;
source.Reply(_("Your email address has been changed to \002%s\002."), uac->email.c_str());
ns_set_email.Unset(uac);
return EVENT_STOP;
}
}
}
return EVENT_CONTINUE;
}
void OnSetCorrectModes(User *user, Channel *chan, AccessGroup &access, bool &give_modes, bool &take_modes) override
{
if (chan->ci)
+36 -9
View File
@@ -128,13 +128,19 @@ private:
const NickCore *nc = anope_dynamic_static_cast<const NickCore *>(s);
Anope::string modes;
for (const auto &[last_mode, last_value] : nc->last_modes)
for (const auto &[last_mode, last_data] : nc->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);
}
@@ -152,11 +158,32 @@ private:
nc->last_modes.clear();
for (spacesepstream sep(modes); sep.GetToken(modes);)
{
size_t c = modes.find(',');
if (c == Anope::string::npos)
nc->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();
nc->last_modes.emplace(modes, info);
continue;
}
else
nc->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)
nc->last_modes.emplace(modes, ModeData());
else
nc->last_modes.emplace(modes.substr(0, c), ModeData(modes.substr(c + 1)));
// End 2.0 compatibility.
}
}
}
} keep_modes;
@@ -197,11 +224,11 @@ public:
{
const auto norestore = Config->GetModule(this).Get<const Anope::string>("norestore");
User::ModeList modes = u->Account()->last_modes;
for (const auto &[last_mode, last_value] : modes)
for (const auto &[last_mode, last_data] : modes)
{
auto *um = ModeManager::FindUserModeByName(last_mode);
if (um && um->CanSet(nullptr) && norestore.find(um->mchar) == Anope::string::npos)
u->SetMode(nullptr, last_mode, last_value);
u->SetMode(nullptr, last_mode, last_data);
}
}
}
+1 -1
View File
@@ -53,7 +53,7 @@ struct NSMiscDataType final
{
}
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 NSMiscData *>(obj);
sdata.Store("nc", d->object);
+1 -1
View File
@@ -29,7 +29,7 @@ struct NSSuspendInfoType 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 NSSuspendInfo *>(obj);
data.Store("nick", si->what);
+2 -2
View File
@@ -471,13 +471,13 @@ public:
source.Reply(" ");
source.Reply(_(
"The \002%s\032DEL\002 command removes the given mask from the "
"AKILL list if it is present. If a list of entry numbers is "
"AKILL list if it is present. If a list of entry numbers is "
"given, those entries are deleted. (See the example for LIST "
"below.)"
"\n\n"
"The \002%s\032LIST\002 command displays the AKILL 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\032LIST\0322-5,7-9\002\n"
" Lists AKILL entries numbered 2 through 5 and 7\n"
+3 -3
View File
@@ -356,7 +356,7 @@ public:
{
const auto &block = conf.GetModule("os_session");
dconfig.max_session_kill = block.Get<int>("maxsessionkill");
dconfig.max_session_kill = block.Get<unsigned>("maxsessionkill");
dconfig.session_autokill_expiry = block.Get<time_t>("sessionautokillexpiry");
dconfig.sle_reason = block.Get<const Anope::string>("sessionlimitexceeded");
dconfig.sle_detailsloc = block.Get<const Anope::string>("sessionlimitdetailsloc");
@@ -407,11 +407,11 @@ public:
this->ParseModeString();
}
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 (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && DConfig.DefConModesOff.count(mode->name) && source.GetUser() && !source.GetBot())
{
c->RemoveMode(Config->GetClient("OperServ"), mode, param);
c->RemoveMode(Config->GetClient("OperServ"), mode, data.value);
return EVENT_STOP;
}
+2 -2
View File
@@ -59,7 +59,7 @@ struct DNSZoneType final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *zone = static_cast<const DNSZone *>(obj);
data.Store("name", zone->name);
@@ -174,7 +174,7 @@ struct DNSServerType final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *req = static_cast<const DNSServer *>(obj);
data.Store("server_name", req->server_name);
+2 -2
View File
@@ -29,11 +29,11 @@ struct ForbidDataTypeImpl final
{
}
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;
};
void ForbidDataTypeImpl::Serialize(const Serializable *obj, Serialize::Data &data) const
void ForbidDataTypeImpl::Serialize(Serializable *obj, Serialize::Data &data) const
{
const auto *fb = static_cast<const ForbidDataImpl *>(obj);
data.Store("mask", fb->mask);
+2 -2
View File
@@ -33,11 +33,11 @@ struct IgnoreDataTypeImpl final
: Serialize::Type("IgnoreData")
{
}
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;
};
void IgnoreDataTypeImpl::Serialize(const Serializable *obj, Serialize::Data &data) const
void IgnoreDataTypeImpl::Serialize(Serializable *obj, Serialize::Data &data) const
{
const auto *ign = static_cast<const IgnoreDataImpl *>(obj);
data.Store("mask", ign->mask);
+1 -1
View File
@@ -35,7 +35,7 @@ struct OperInfoTypeImpl
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *oi = static_cast<const OperInfoImpl *>(obj);
data.Store("target", oi->target);
+1 -1
View File
@@ -57,7 +57,7 @@ public:
source.Reply(_(
"Tells services to jupiter a server -- that is, to create "
"a fake \"server\" connected to services which prevents "
"the real server of that name from connecting. The jupe "
"the real server of that name from connecting. The jupe "
"may be removed using a standard \002SQUIT\002. If a reason is "
"given, it is placed in the server information field; "
"otherwise, the server information field will contain the "
+2 -2
View File
@@ -36,8 +36,8 @@ public:
{
bool all = params.size() > 2 && params[2].equals_ci("ALL");
for (const auto &[mode, value] : c->GetModes())
c->RemoveMode(c->WhoSends(), mode, value, false);
for (const auto &[mode, data] : c->GetModes())
c->RemoveMode(c->WhoSends(), mode, data.value, false);
if (!c)
{
+8 -8
View File
@@ -80,7 +80,7 @@ struct NewsItemType final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *ni = static_cast<const NewsItem *>(obj);
data.Store("type", ni->type);
@@ -328,10 +328,10 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Edits or displays the list of logon news messages. When a "
"Edits or displays the list of logon news messages. When a "
"user connects to the network, these messages will be sent "
"to them. However, no more than \002%d\002 messages will be "
"sent in order to avoid flooding the user. If there are "
"to them. However, no more than \002%d\002 messages will be "
"sent in order to avoid flooding the user. If there are "
"more news messages, only the most recent will be sent."
),
Config->GetModule(this->owner).Get<unsigned>("newscount", "3"));
@@ -358,10 +358,10 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Edits or displays the list of oper news messages. When a "
"Edits or displays the list of oper news messages. When a "
"user opers up (with the /OPER command), these messages will "
"be sent to them. However, no more than \002%d\002 messages will "
"be sent in order to avoid flooding the user. If there are "
"be sent to them. However, no more than \002%d\002 messages will "
"be sent in order to avoid flooding the user. If there are "
"more news messages, only the most recent will be sent."
),
Config->GetModule(this->owner).Get<unsigned>("newscount", "3"));
@@ -388,7 +388,7 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Edits or displays the list of random news messages. When a "
"Edits or displays the list of random news messages. When a "
"user connects to the network, one (and only one) of the "
"random news will be randomly chosen and sent to them."
));
+1 -1
View File
@@ -20,7 +20,7 @@ struct OSOperType
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *myo = static_cast<const MyOper *>(obj);
data.Store("name", myo->name);
+4 -4
View File
@@ -43,7 +43,7 @@ struct ExceptionType final
{
}
void Serialize(const Serializable *obj, Serialize::Data &data) const override
void Serialize(Serializable *obj, Serialize::Data &data) const override
{
const auto *ex = static_cast<const Exception *>(obj);
data.Store("mask", ex->mask);
@@ -661,13 +661,13 @@ public:
{
const auto &block = Config->GetModule(this);
session_limit = block.Get<int>("defaultsessionlimit");
max_session_kill = block.Get<int>("maxsessionkill");
session_limit = block.Get<unsigned>("defaultsessionlimit");
max_session_kill = block.Get<unsigned>("maxsessionkill");
session_autokill_expiry = block.Get<time_t>("sessionautokillexpiry");
sle_reason = block.Get<const Anope::string>("sessionlimitexceeded");
sle_detailsloc = block.Get<const Anope::string>("sessionlimitdetailsloc");
max_exception_limit = block.Get<int>("maxsessionlimit");
max_exception_limit = block.Get<unsigned>("maxsessionlimit");
exception_expiry = block.Get<time_t>("exceptionexpiry");
ipv4_cidr = block.Get<unsigned>("session_ipv4_cidr", "32");

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