mirror of
https://github.com/anope/anope.git
synced 2026-06-17 02:44:46 +02:00
Compare commits
144 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9930fa01ac | |||
| 40929a0490 | |||
| 783be31f64 | |||
| 0f5f2aef2e | |||
| 6cc997c4e9 | |||
| eda6d8cc0f | |||
| 3440b38a21 | |||
| fca421aa2a | |||
| 035905d321 | |||
| d1cd57d98e | |||
| 48daeeac1d | |||
| 9bcf46f8ea | |||
| 0b6c7ce5d6 | |||
| a0d21b207b | |||
| 3cc5b5143f | |||
| da738126a4 | |||
| 0bb1bc5c67 | |||
| 72010cd1a9 | |||
| c48b3af3d4 | |||
| 85c129701b | |||
| a9e5a79e91 | |||
| adc1343d6c | |||
| 8aa1102c7a | |||
| 1a89d32926 | |||
| ad06853edf | |||
| 66ae20e0f2 | |||
| 2850e3c65c | |||
| 80b8856254 | |||
| 21c8164539 | |||
| a4abd27ffd | |||
| b912b403f0 | |||
| 59e9d47667 | |||
| 1108e54250 | |||
| 8b37cdb5d5 | |||
| c5bff3a099 | |||
| 61b0c82884 | |||
| c4c159d197 | |||
| 04a32be1e1 | |||
| fe4b8ee669 | |||
| 34b451f36c | |||
| 16aff210fd | |||
| 5702fb9145 | |||
| 783ba3fd74 | |||
| f1ddd7cd02 | |||
| c424c4d24d | |||
| 2d88383d9e | |||
| c73a6c621f | |||
| 96a503b4d9 | |||
| 0632abd111 | |||
| 1043e2189c | |||
| 85f0d56c39 | |||
| cebc3f757b | |||
| 447a59d6f5 | |||
| 75aa633d87 | |||
| 7833a96dde | |||
| d326f869a3 | |||
| b724617a8d | |||
| 76f0c78ece | |||
| 13491bd960 | |||
| bade5ea109 | |||
| 682a6a6ad4 | |||
| 50030e07fa | |||
| 7b2f0f5790 | |||
| 23e72fc934 | |||
| e182519e4d | |||
| 4317b5557e | |||
| f97448f48a | |||
| cb334fbae1 | |||
| d3bb930a5e | |||
| 0fc1eb3133 | |||
| 0ac9d70d63 | |||
| a3d61e3d18 | |||
| cac10aaa41 | |||
| be5a0e8108 | |||
| 3da8244de5 | |||
| 8722daa6e7 | |||
| a0e98acea8 | |||
| c5a2f40666 | |||
| 1daafff79d | |||
| 3dd20975aa | |||
| 368d8e8b1c | |||
| 7c5d2c09fa | |||
| 41e702d853 | |||
| 19f83eaa34 | |||
| b1212f9e89 | |||
| 3e9f516d55 | |||
| 744b8bc4dc | |||
| e9a0a214b0 | |||
| 46c5570b1d | |||
| 151795a1df | |||
| 50f17ea8e1 | |||
| 2609ff44c6 | |||
| ca30bb2370 | |||
| f36b311f84 | |||
| fec85376e7 | |||
| 0bf14650fa | |||
| 49f93b7670 | |||
| ce0982cc4a | |||
| b4150841ec | |||
| eec428b0c7 | |||
| b706a6259e | |||
| 2cf8f003ce | |||
| 07f57b1108 | |||
| 5d648f9f1c | |||
| 46e6b0adde | |||
| 977780d8ef | |||
| 459f3d07c9 | |||
| b76b407b33 | |||
| 8b089ab1a7 | |||
| fbec4d04a5 | |||
| 34582a40ef | |||
| 4b15ca0232 | |||
| 997302f861 | |||
| b3b6e9f862 | |||
| d23bfb0113 | |||
| 0b7b4aa42d | |||
| fab8589e1e | |||
| 937404e311 | |||
| c5ad774ce5 | |||
| 1321f4f071 | |||
| 4319b6428f | |||
| e1f6d0ca16 | |||
| bb9074cbd5 | |||
| 72f5e3580f | |||
| 4b854d3935 | |||
| 0b2b00b37d | |||
| 196a3c32c2 | |||
| 8955c53088 | |||
| 88c71fba64 | |||
| 21f61981ca | |||
| 5752c07a56 | |||
| 010beb52b1 | |||
| c955941413 | |||
| 2e2515b9f0 | |||
| f0b26c9b44 | |||
| f953f7f006 | |||
| 84baf15620 | |||
| 89f61ac91b | |||
| b091184c60 | |||
| 6b1a491694 | |||
| 66d3293ae6 | |||
| a4691f9d4d | |||
| 51c7a15c45 | |||
| 151f9c2bcc |
@@ -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
|
||||
|
||||
@@ -13,14 +13,6 @@
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
exists () { # because some shells don't have test -e
|
||||
if [ -f $1 -o -d $1 -o -p $1 -o -c $1 -o -b $1 ] ; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
Load_Cache () {
|
||||
if [ -f $SOURCE_DIR/config.cache -a -r $SOURCE_DIR/config.cache -a ! "$IGNORE_CACHE" ] ; then
|
||||
echo "Using defaults from config.cache. To ignore, $SOURCE_DIR/Config -nocache"
|
||||
@@ -208,7 +200,7 @@ while [ $ok -eq 0 ] ; do
|
||||
INPUT=$INSTDIR
|
||||
fi
|
||||
if [ ! -d "$INPUT" ] ; then
|
||||
if exists "$INPUT" ; then
|
||||
if [ -e "$INPUT" ]; then
|
||||
echo "$INPUT exists, but is not a directory!"
|
||||
else
|
||||
echo "$INPUT does not exist. Create it?"
|
||||
@@ -220,7 +212,7 @@ while [ $ok -eq 0 ] ; do
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
elif exists "$INPUT/include/services.h" ; then
|
||||
elif [ -e "$INPUT/include/services.h" ]; then
|
||||
echo "You cannot use the Anope source directory as a target directory."
|
||||
else
|
||||
ok=1
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Only install cron.example.sh and anope.example.conf from this directory
|
||||
# NOTE: I would've had this just find all files in the directory, but that would include files not needed (like this file)
|
||||
set(DATA cron.example.sh anope.example.conf botserv.example.conf hostserv.example.conf modules.example.conf operserv.example.conf chanserv.example.conf global.example.conf memoserv.example.conf nickserv.example.conf chanstats.example.conf irc2sql.example.conf stats.standalone.example.conf)
|
||||
set(DATA cron.example.sh anope.example.conf botserv.example.conf hostserv.example.conf modules.example.conf operserv.example.conf chanserv.example.conf global.example.conf memoserv.example.conf nickserv.example.conf chanstats.example.conf)
|
||||
install(FILES ${DATA}
|
||||
DESTINATION ${CONF_DIR}
|
||||
)
|
||||
|
||||
+68
-72
@@ -65,10 +65,6 @@
|
||||
* will typically be disabled. If this is not the case, more
|
||||
* information will be given in the documentation.
|
||||
*
|
||||
* [DISCOURAGED]
|
||||
* Indicates a directive which may cause undesirable side effects if
|
||||
* specified.
|
||||
*
|
||||
* [DEPRECATED]
|
||||
* Indicates a directive which will disappear in a future version of
|
||||
* Anope, usually because its functionality has been either
|
||||
@@ -259,7 +255,6 @@ serverinfo
|
||||
* You MUST modify this to match the IRCd you run.
|
||||
*
|
||||
* Supported:
|
||||
* - bahamut
|
||||
* - hybrid
|
||||
* - inspircd
|
||||
* - ngircd
|
||||
@@ -326,7 +321,7 @@ networkinfo
|
||||
* The characters allowed in hostnames. This is used for validating hostnames given
|
||||
* to services, such as BotServ bot hostnames and user vhosts. Changing this is not
|
||||
* recommended unless you know for sure your IRCd supports whatever characters you are
|
||||
* wanting to use. Telling services to set a vHost containing characters your IRCd
|
||||
* wanting to use. Telling services to set a vhost containing characters your IRCd
|
||||
* disallows could potentially break the IRCd and/or Anope.
|
||||
*
|
||||
* It is recommended you DON'T change this.
|
||||
@@ -334,21 +329,21 @@ networkinfo
|
||||
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-/"
|
||||
|
||||
/*
|
||||
* If set to true, allows vHosts to not contain dots (.).
|
||||
* If enabled, allows vhosts to not contain dots (.).
|
||||
* Newer IRCds generally do not have a problem with this, but the same warning as
|
||||
* vhost_chars applies.
|
||||
*
|
||||
* It is recommended you DON'T change this.
|
||||
*/
|
||||
allow_undotted_vhosts = false
|
||||
allow_undotted_vhosts = no
|
||||
|
||||
/*
|
||||
* The characters that are not allowed to be at the very beginning or very ending
|
||||
* of a vHost. The same warning as vhost_chars applies.
|
||||
* of a vhost. The same warning as vhost_chars applies.
|
||||
*
|
||||
* It is recommended you DON'T change this.
|
||||
*/
|
||||
disallow_start_or_end = ".-"
|
||||
disallow_start_or_end = ".-/"
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -588,7 +583,7 @@ include
|
||||
}
|
||||
|
||||
/*
|
||||
* [OPTIONAL] NickServ
|
||||
* [RECOMMENDED] NickServ
|
||||
*
|
||||
* Includes nickserv.example.conf, which is necessary for NickServ functionality.
|
||||
*
|
||||
@@ -746,7 +741,8 @@ log
|
||||
* nickserv/alist - Can see the channel access list of other users
|
||||
* nickserv/auspex - Can see any information with /NICKSERV INFO
|
||||
* nickserv/cert - Can modify other users certificate lists
|
||||
* nickserv/confirm - Can confirm other users nicknames
|
||||
* nickserv/confirm/email - Can confirm other users email address change
|
||||
* nickserv/confirm/register - Can confirm other users account registration
|
||||
* nickserv/drop - Can drop other users nicks
|
||||
* nickserv/drop/display - Allows dropping display nicks when preservedisplay is enabled
|
||||
* nickserv/drop/override - Allows dropping nicks without using a confirmation code
|
||||
@@ -818,7 +814,7 @@ opertype
|
||||
commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline"
|
||||
|
||||
/* What privs (see above) this opertype has */
|
||||
privs = "chanserv/auspex chanserv/no-register-limit memoserv/* nickserv/auspex nickserv/confirm"
|
||||
privs = "chanserv/auspex chanserv/no-register-limit memoserv/* nickserv/auspex nickserv/confirm/*"
|
||||
|
||||
/*
|
||||
* Modes to be set on users when they identify to accounts linked to this opertype.
|
||||
@@ -891,8 +887,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 +927,20 @@ mail
|
||||
usemail = yes
|
||||
|
||||
/*
|
||||
* This is the command-line that will be used to call the mailer to send an
|
||||
* email. It must be called with all the parameters needed to make it
|
||||
* scan the mail input to find the mail recipient; consult your mailer
|
||||
* documentation.
|
||||
* The command used for sending emails. It is assumed that this behaves like
|
||||
* sendmail (i.e. it reads the email from the standard input stream) but you
|
||||
* should probably use Postfix or some other sendmail-compatible emailer
|
||||
* instead of sendmail as sendmail is very hard to configure correctly. If
|
||||
* you are using Windows then https://www.glob.com.au/sendmail/ is probably
|
||||
* the best option currently.
|
||||
*
|
||||
* Postfix users must use the compatible sendmail utility provided with
|
||||
* it. This one usually needs no parameters on the command-line. Most
|
||||
* sendmail applications (or replacements of it) require the -t option
|
||||
* to be used.
|
||||
*
|
||||
* If you are running on Windows you should use a Windows sendmail port
|
||||
* like https://www.glob.com.au/sendmail/ for sending emails.
|
||||
* If your emailer sends emails directly from the services host you will
|
||||
* need to configure DKIM, DMARC, and SPF to avoid email hosts from marking
|
||||
* your services emails as spam. It is important that you do this *BEFORE*
|
||||
* sending emails for the first time as some email providers will add your
|
||||
* host to a DNSBL like Spamhaus if they consider your emails to be spam. If
|
||||
* this is too difficult then you may want to consider sending emails via an
|
||||
* external email provider using a forwarder like msmtp.
|
||||
*/
|
||||
#sendmailpath = "/usr/sbin/sendmail -it"
|
||||
|
||||
@@ -993,7 +991,7 @@ mail
|
||||
registration_message = "Hi,
|
||||
|
||||
You have requested to register the nickname {nick} on {network}.
|
||||
Please type \" /msg NickServ CONFIRM {code} \" to complete registration.
|
||||
Please type \" /msg NickServ CONFIRM REGISTER {code} \" to complete registration.
|
||||
|
||||
If you don't know why this mail was sent to you, please ignore it silently.
|
||||
|
||||
@@ -1011,7 +1009,7 @@ mail
|
||||
reset_message = "Hi,
|
||||
|
||||
You have requested to have the password for {nick} reset.
|
||||
To reset your password, type \" /msg NickServ CONFIRM {nick} {code} \"
|
||||
To reset your password, type \" /msg NickServ CONFIRM RESETPASS {nick} {code} \"
|
||||
|
||||
If you don't know why this mail was sent to you, please ignore it silently.
|
||||
|
||||
@@ -1031,7 +1029,7 @@ mail
|
||||
emailchange_message = "Hi,
|
||||
|
||||
You have requested to change your email address from {old_email} to {new_email}.
|
||||
Please type \" /msg NickServ CONFIRM {code} \" to confirm this change.
|
||||
Please type \" /msg NickServ CONFIRM EMAIL {code} \" to confirm this change.
|
||||
|
||||
If you don't know why this mail was sent to you, please ignore it silently.
|
||||
|
||||
@@ -1103,11 +1101,16 @@ mail
|
||||
}
|
||||
|
||||
/*
|
||||
* [RECOMMENDED] db_flatfile
|
||||
* db_flatfile
|
||||
*
|
||||
* This is the default flatfile database format.
|
||||
* Stores your database in a custom flatfile format.
|
||||
*
|
||||
* This was the recommended database module in 2.0 but it is now recommended
|
||||
* that you use db_json instead. You can migrate your db_flatfile database to
|
||||
* db_json by loading db_flatfile BEFORE db_json, sending SIGUSR1 to force a
|
||||
* database write, and then unloading db_flatfile.
|
||||
*/
|
||||
module
|
||||
#module
|
||||
{
|
||||
name = "db_flatfile"
|
||||
|
||||
@@ -1148,13 +1151,11 @@ module
|
||||
}
|
||||
|
||||
/*
|
||||
* db_json
|
||||
* [RECOMMENDED] db_json
|
||||
*
|
||||
* Stores your data in a JSON file. This is currently experimental and has not
|
||||
* been fully tested so make sure you have db_flatfile loaded as a secondary
|
||||
* database module if you use this.
|
||||
* Stores your database in a JSON file.
|
||||
*/
|
||||
#module
|
||||
module
|
||||
{
|
||||
name = "db_json"
|
||||
|
||||
@@ -1203,17 +1204,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 +1226,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 +1237,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
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1402,16 +1411,3 @@ include
|
||||
type = "file"
|
||||
name = "chanstats.example.conf"
|
||||
}
|
||||
|
||||
/*
|
||||
* IRC2SQL Gateway
|
||||
* This module collects data about users, channels and servers. It doesn't build stats
|
||||
* itself, however, it gives you the database, it's up to you how you use it.
|
||||
*
|
||||
* Requires a MySQL Database and MySQL version 5.5 or higher
|
||||
*/
|
||||
#include
|
||||
{
|
||||
type = "file"
|
||||
name = "irc2sql.example.conf"
|
||||
}
|
||||
|
||||
@@ -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"; }
|
||||
|
||||
+18
-25
@@ -26,7 +26,7 @@ service
|
||||
/*
|
||||
* The realname of the ChanServ client.
|
||||
*/
|
||||
gecos = "Channel Registration Service"
|
||||
real = "Channel Registration Service"
|
||||
|
||||
/*
|
||||
* The modes this client should use.
|
||||
@@ -100,6 +100,7 @@ module
|
||||
* not in use.
|
||||
* - cs_no_expire: Enables no expire. Needs founder, successor (if set) or anyone in the access list
|
||||
* to be a registered nick, otherwise the channel will be dropped.
|
||||
* - cs_stats: Enable Chanstats for newly registered channels
|
||||
* - none: No defaults
|
||||
*
|
||||
* This directive is optional, if left blank, the options will default to cs_keep_modes, keeptopic, peace,
|
||||
@@ -171,19 +172,19 @@ module
|
||||
/*
|
||||
* If set, prevents channel access entries from containing hostmasks.
|
||||
*/
|
||||
disallow_hostmask_access = false
|
||||
disallow_hostmask_access = no
|
||||
|
||||
/*
|
||||
* If set, prevents channels from being on access lists.
|
||||
*/
|
||||
disallow_channel_access = false
|
||||
disallow_channel_access = no
|
||||
|
||||
/*
|
||||
* If set, ChanServ will always lower the timestamp of registered channels to their registration date.
|
||||
* This prevents several race conditions where unauthorized users can join empty registered channels and set
|
||||
* modes etc. prior to services deopping them.
|
||||
*/
|
||||
always_lower_ts = false
|
||||
always_lower_ts = no
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -946,7 +947,7 @@ command { service = "ChanServ"; name = "AKICK"; command = "chanserv/akick"; grou
|
||||
* Used for banning users from channels.
|
||||
*/
|
||||
module { name = "cs_ban" }
|
||||
command { service = "ChanServ"; name = "BAN"; command = "chanserv/ban"; }
|
||||
command { service = "ChanServ"; name = "BAN"; command = "chanserv/ban"; group = "chanserv/management"; }
|
||||
|
||||
/*
|
||||
* cs_clone
|
||||
@@ -1047,7 +1048,7 @@ command { service = "ChanServ"; name = "INVITE"; command = "chanserv/invite"; }
|
||||
* Used for kicking users from channels.
|
||||
*/
|
||||
module { name = "cs_kick" }
|
||||
command { service = "ChanServ"; name = "KICK"; command = "chanserv/kick"; }
|
||||
command { service = "ChanServ"; name = "KICK"; command = "chanserv/kick"; group = "chanserv/management"; }
|
||||
|
||||
/*
|
||||
* cs_list
|
||||
@@ -1178,9 +1179,6 @@ module
|
||||
{
|
||||
name = "cs_seen"
|
||||
|
||||
/* If set, uses the older 1.8 style seen, which is less resource intensive */
|
||||
simple = false
|
||||
|
||||
/* Sets the time to keep seen entries in the seen database. */
|
||||
purgetime = 90d
|
||||
}
|
||||
@@ -1228,7 +1226,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 +1267,15 @@ command { service = "ChanServ"; name = "SET EMAIL"; command = "chanserv/set/misc
|
||||
*/
|
||||
module { name = "cs_status" }
|
||||
command { service = "ChanServ"; name = "STATUS"; command = "chanserv/status"; }
|
||||
command { service = "ChanServ"; name = "WHY"; command = "chanserv/status"; hide = true; }
|
||||
command { service = "ChanServ"; name = "WHY"; command = "chanserv/status"; hide = yes; }
|
||||
|
||||
/*
|
||||
* cs_statusupdate
|
||||
*
|
||||
* This module automatically updates users' status on channels when the
|
||||
* channel's access list is modified.
|
||||
*/
|
||||
module { name = "cs_statusupdate" }
|
||||
|
||||
/*
|
||||
* cs_suspend
|
||||
@@ -1330,7 +1336,7 @@ command { service = "ChanServ"; name = "SET KEEPTOPIC"; command = "chanserv/set/
|
||||
* Used for unbanning users from channels.
|
||||
*/
|
||||
module { name = "cs_unban" }
|
||||
command { service = "ChanServ"; name = "UNBAN"; command = "chanserv/unban"; }
|
||||
command { service = "ChanServ"; name = "UNBAN"; command = "chanserv/unban"; group = "chanserv/management"; }
|
||||
|
||||
/*
|
||||
* cs_updown
|
||||
@@ -1363,16 +1369,3 @@ command { service = "ChanServ"; name = "SOP"; command = "chanserv/xop"; group =
|
||||
command { service = "ChanServ"; name = "AOP"; command = "chanserv/xop"; group = "chanserv/access"; }
|
||||
command { service = "ChanServ"; name = "HOP"; command = "chanserv/xop"; group = "chanserv/access"; }
|
||||
command { service = "ChanServ"; name = "VOP"; command = "chanserv/xop"; group = "chanserv/access"; }
|
||||
|
||||
|
||||
/*
|
||||
* Extra ChanServ related modules.
|
||||
*/
|
||||
|
||||
/*
|
||||
* cs_statusupdate
|
||||
*
|
||||
* This module automatically updates users' status on channels when the
|
||||
* channel's access list is modified.
|
||||
*/
|
||||
module { name = "cs_statusupdate" }
|
||||
|
||||
@@ -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"; }
|
||||
|
||||
@@ -26,7 +26,7 @@ service
|
||||
/*
|
||||
* The realname of the Global client.
|
||||
*/
|
||||
gecos = "Global Noticer"
|
||||
real = "Global Noticer"
|
||||
|
||||
/*
|
||||
* The modes this client should use.
|
||||
@@ -93,7 +93,7 @@ module
|
||||
#globaloncycleup = "Services are now back online - have a nice day"
|
||||
|
||||
/*
|
||||
* If set, Anope will hide the IRC Operator's nick in a global
|
||||
* If set, Anope will hide the Services Operator's nick in a global
|
||||
* message/notice.
|
||||
*
|
||||
* This directive is optional.
|
||||
|
||||
+13
-13
@@ -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,97 +0,0 @@
|
||||
/*
|
||||
* Example configuration file for the irc2sql gateway
|
||||
*
|
||||
*/
|
||||
|
||||
service
|
||||
{
|
||||
/*
|
||||
* The name of the StatServ client.
|
||||
*/
|
||||
nick = "StatServ"
|
||||
|
||||
/*
|
||||
* The username of the StatServ client.
|
||||
*/
|
||||
user = "StatServ"
|
||||
|
||||
/*
|
||||
* The hostname of the StatServ client.
|
||||
*/
|
||||
host = "${services.host}"
|
||||
|
||||
/*
|
||||
* The realname of the StatServ client.
|
||||
*/
|
||||
gecos = "Statistical Service"
|
||||
|
||||
/*
|
||||
* The modes this client should use.
|
||||
* Do not modify this unless you know what you are doing.
|
||||
*
|
||||
* These modes are very IRCd specific. If left commented, sane defaults
|
||||
* are used based on what protocol module you have loaded.
|
||||
*
|
||||
* Note that setting this option incorrectly could potentially BREAK some, if
|
||||
* not all, usefulness of the client. We will not support you if this client is
|
||||
* unable to do certain things if this option is enabled.
|
||||
*/
|
||||
#modes = "+o"
|
||||
|
||||
/*
|
||||
* An optional comma separated list of channels this service should join. Outside
|
||||
* of log channels this is not very useful, as the service will just idle in the
|
||||
* specified channels, and will not accept any types of commands.
|
||||
*
|
||||
* Prefixes may be given to the channels in the form of mode characters or prefix symbols.
|
||||
*/
|
||||
#channels = "@#stats,#mychan"
|
||||
}
|
||||
|
||||
module
|
||||
{
|
||||
name = "irc2sql"
|
||||
|
||||
/*
|
||||
* The name of the client that should send the CTCP VERSION requests.
|
||||
* It must already exist or must be defined in the following service block.
|
||||
*/
|
||||
client = "StatServ"
|
||||
|
||||
/*
|
||||
* The name of the SQL engine to use.
|
||||
* This must be MySQL and must match the name in the mysql{} block
|
||||
*/
|
||||
engine = "mysql/main"
|
||||
|
||||
/*
|
||||
* An optional prefix to prepended to the name of each created table.
|
||||
* Do not use the same prefix for other programs.
|
||||
*/
|
||||
prefix = "anope_"
|
||||
|
||||
/*
|
||||
* GeoIP - Automatically adds users geoip location to the user table.
|
||||
* Tables are created by irc2sql, you have to run the
|
||||
* geoipupdate script after you started Anope to download
|
||||
* and import the GeoIP database.
|
||||
*
|
||||
* The geoip database can be the smaller "country" database or the
|
||||
* larger "city" database. Comment to disable geoip lookup.
|
||||
*/
|
||||
geoip_database = "country"
|
||||
|
||||
/*
|
||||
* Get the CTCP version from users
|
||||
* The users connecting to the network will receive a CTCP VERSION
|
||||
* request from the above configured stats client
|
||||
*/
|
||||
ctcpuser = "yes"
|
||||
|
||||
/*
|
||||
* Send out CTCP VERSION requests to users during burst.
|
||||
* Disable this if you restart Anope often and don't want to
|
||||
* annoy your users.
|
||||
*/
|
||||
ctcpeob = "yes"
|
||||
}
|
||||
@@ -26,7 +26,7 @@ service
|
||||
/*
|
||||
* The realname of the MemoServ client.
|
||||
*/
|
||||
gecos = "Memo Service"
|
||||
real = "Memo Service"
|
||||
|
||||
/*
|
||||
* The modes this client should use.
|
||||
@@ -89,8 +89,7 @@ module
|
||||
/*
|
||||
* The delay between consecutive uses of the MemoServ SEND command. This can help prevent spam
|
||||
* as well as denial-of-service attacks from sending large numbers of memos and filling up disk
|
||||
* space (and memory). The default 3-second wait means a maximum average of 150 bytes of memo
|
||||
* per second per user under the current IRC protocol.
|
||||
* space (and memory).
|
||||
*
|
||||
* This directive is optional, but recommended.
|
||||
*/
|
||||
@@ -197,8 +196,6 @@ command { service = "MemoServ"; name = "READ"; command = "memoserv/read"; }
|
||||
* Provides the command memoserv/rsend.
|
||||
*
|
||||
* Used to send a memo requiring a receipt be sent back once it is read.
|
||||
*
|
||||
* Requires configuring memoserv:memoreceipt.
|
||||
*/
|
||||
#module
|
||||
{
|
||||
@@ -209,7 +206,7 @@ command { service = "MemoServ"; name = "READ"; command = "memoserv/read"; }
|
||||
*
|
||||
* This directive is optional.
|
||||
*/
|
||||
operonly = false
|
||||
operonly = no
|
||||
}
|
||||
#command { service = "MemoServ"; name = "RSEND"; command = "memoserv/rsend"; }
|
||||
|
||||
|
||||
+115
-32
@@ -65,7 +65,7 @@ module { name = "help" }
|
||||
/* This should be the names of the public facing nameservers serving the records. */
|
||||
nameservers = "ns1.example.com ns2.example.com"
|
||||
|
||||
/* The time slave servers are allowed to cache. This should be reasonably low
|
||||
/* The time secondary servers are allowed to cache for. This should be reasonably low
|
||||
* if you want your records to be updated without much delay.
|
||||
*/
|
||||
refresh = 3600
|
||||
@@ -233,7 +233,7 @@ module { name = "help" }
|
||||
}
|
||||
|
||||
/*
|
||||
* ldap [EXTRA]
|
||||
* [EXTRA] ldap
|
||||
*
|
||||
* This module allows other modules to use LDAP. By itself, this module does nothing useful.
|
||||
*/
|
||||
@@ -304,13 +304,13 @@ module { name = "help" }
|
||||
*
|
||||
* If not set, then registration is not blocked.
|
||||
*/
|
||||
#disable_register_reason = "To register on this network visit https://some.misconfigured.site/register"
|
||||
#disable_register_reason = "To register on this network visit https://some.misconfigured.site.example/register"
|
||||
|
||||
/*
|
||||
* If set, the reason to give the users who try to "/msg NickServ SET EMAIL".
|
||||
* If not set, then email changing is not blocked.
|
||||
*/
|
||||
#disable_email_reason = "To change your email address visit https://some.misconfigured.site"
|
||||
#disable_email_reason = "To change your email address visit https://some.misconfigured.site.example"
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -355,7 +355,7 @@ module { name = "help" }
|
||||
}
|
||||
|
||||
/*
|
||||
* mysql [EXTRA]
|
||||
* [EXTRA] mysql
|
||||
*
|
||||
* This module allows other modules to use MySQL.
|
||||
*/
|
||||
@@ -402,7 +402,7 @@ module { name = "help" }
|
||||
}
|
||||
|
||||
/*
|
||||
* regex_pcre2 [EXTRA]
|
||||
* [EXTRA] regex_pcre2
|
||||
*
|
||||
* Provides the regex engine regex/pcre, which uses version 2 of the Perl Compatible Regular
|
||||
* Expressions library.
|
||||
@@ -410,7 +410,7 @@ module { name = "help" }
|
||||
#module { name = "regex_pcre2" }
|
||||
|
||||
/*
|
||||
* regex_posix [EXTRA]
|
||||
* [EXTRA] regex_posix
|
||||
*
|
||||
* Provides the regex engine regex/posix, which uses the POSIX compliant regular expressions.
|
||||
*/
|
||||
@@ -440,7 +440,7 @@ module
|
||||
}
|
||||
|
||||
/*
|
||||
* regex_tre [EXTRA]
|
||||
* [EXTRA] regex_tre
|
||||
*
|
||||
* Provides the regex engine regex/tre, which uses the TRE regex library.
|
||||
*/
|
||||
@@ -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"
|
||||
@@ -559,7 +559,7 @@ module
|
||||
}
|
||||
|
||||
/*
|
||||
* ssl_gnutls [EXTRA]
|
||||
* [EXTRA] ssl_gnutls
|
||||
*
|
||||
* This module provides SSL services to Anope using GnuTLS, for example to
|
||||
* connect to the uplink server(s) via SSL.
|
||||
@@ -598,7 +598,7 @@ module
|
||||
}
|
||||
|
||||
/*
|
||||
* ssl_openssl [EXTRA]
|
||||
* [EXTRA] ssl_openssl
|
||||
*
|
||||
* This module provides SSL services to Anope using OpenSSL, for example to
|
||||
* connect to the uplink server(s) via SSL.
|
||||
@@ -691,20 +691,20 @@ module
|
||||
* If set, the reason to give the users who try to "/msg NickServ REGISTER".
|
||||
* If not set, then registration is not blocked.
|
||||
*/
|
||||
#disable_reason = "To register on this network visit https://some.misconfigured.site/register"
|
||||
#disable_reason = "To register on this network visit https://some.misconfigured.site.example/register"
|
||||
|
||||
/*
|
||||
* If set, the reason to give the users who try to "/msg NickServ SET EMAIL".
|
||||
* If not set, then email changing is not blocked.
|
||||
*/
|
||||
#disable_email_reason = "To change your email address visit https://some.misconfigured.site"
|
||||
#disable_email_reason = "To change your email address visit https://some.misconfigured.site.example"
|
||||
}
|
||||
|
||||
/*
|
||||
* sql_log
|
||||
*
|
||||
* This module adds an additional target option to log{} blocks
|
||||
* that allows logging Service's logs to SQL. To log to SQL, add
|
||||
* that allows logging Services' logs to SQL. To log to SQL, add
|
||||
* the SQL service name to log:targets prefixed by sql_log:. For
|
||||
* example:
|
||||
*
|
||||
@@ -723,8 +723,8 @@ module
|
||||
/*
|
||||
* sql_oper
|
||||
*
|
||||
* This module allows granting users services operator privileges and possibly IRC Operator
|
||||
* privileges based on an external SQL database using a custom query.
|
||||
* This module allows granting users Services Operator privileges based on an
|
||||
* external SQL database using a custom query.
|
||||
*/
|
||||
#module
|
||||
{
|
||||
@@ -747,7 +747,7 @@ module
|
||||
}
|
||||
|
||||
/*
|
||||
* sqlite [EXTRA]
|
||||
* [EXTRA] sqlite
|
||||
*
|
||||
* This module allows other modules to use SQLite.
|
||||
*/
|
||||
@@ -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
|
||||
*
|
||||
|
||||
+82
-52
@@ -26,7 +26,7 @@ service
|
||||
/*
|
||||
* The realname of the NickServ client.
|
||||
*/
|
||||
gecos = "Nickname Registration Service"
|
||||
real = "Nickname Registration Service"
|
||||
|
||||
/*
|
||||
* The modes this client should use.
|
||||
@@ -118,6 +118,7 @@ module
|
||||
* - msg: Messages will be sent as PRIVMSGs instead of NOTICEs
|
||||
* - ns_keep_modes: Enables keepmodes, which retains user modes across sessions
|
||||
* - protect: Protects the registered nickname from use by unidentified users.
|
||||
* - ns_stats: Enable Chanstats for newly registered nicks
|
||||
*
|
||||
* This directive is optional, if left blank, the options will default to memo_signon, and
|
||||
* memo_receive. If you really want no defaults, use "none" by itself as the option.
|
||||
@@ -164,7 +165,7 @@ module
|
||||
* If set, Anope will not show netsplits in the last quit message field
|
||||
* of NickServ's INFO command.
|
||||
*/
|
||||
hidenetsplitquit = no
|
||||
hidenetsplitquit = yes
|
||||
|
||||
/*
|
||||
* The default period to force users to stop using a protected nickname after.
|
||||
@@ -202,11 +203,13 @@ module
|
||||
#restrictopernicks = yes
|
||||
|
||||
/*
|
||||
* The username, and possibly hostname, used for fake users created when Anope needs to
|
||||
* hold a nickname.
|
||||
* The username, hostname, and real name used for pseudoclients created when
|
||||
* Anope needs to hold a nickname. This is only used if your IRCd does not
|
||||
* support SVSHOLDs.
|
||||
*/
|
||||
enforceruser = "enforcer"
|
||||
enforcerhost = "${services.host}"
|
||||
enforcerreal = "Services Enforcer"
|
||||
|
||||
/*
|
||||
* The length of time Anope should hold nicknames for.
|
||||
@@ -248,8 +251,8 @@ module
|
||||
maxpasslen = 50
|
||||
|
||||
/*
|
||||
* Whether all of the secondary nicks of a nick group have to expire or be
|
||||
dropped before the display nick can expire or be dropped.
|
||||
* Whether all of the secondary nicks of an account have to expire or be
|
||||
* dropped before the display nick can expire or be dropped.
|
||||
*/
|
||||
preservedisplay = no
|
||||
}
|
||||
@@ -306,7 +309,7 @@ command { service = "NickServ"; name = "AJOIN"; command = "nickserv/ajoin"; }
|
||||
*/
|
||||
module { name = "ns_alist" }
|
||||
command { service = "NickServ"; name = "ALIST"; command = "nickserv/alist"; }
|
||||
command { service = "NickServ"; name = "ACCESS"; command = "nickserv/alist"; hide = true; }
|
||||
command { service = "NickServ"; name = "ACCESS"; command = "nickserv/alist"; hide = yes; }
|
||||
|
||||
/*
|
||||
* ns_cert
|
||||
@@ -333,6 +336,16 @@ module
|
||||
}
|
||||
command { service = "NickServ"; name = "CERT"; command = "nickserv/cert"; }
|
||||
|
||||
/*
|
||||
* ns_confirm
|
||||
*
|
||||
* Provides the command nickserv/confirm.
|
||||
*
|
||||
* Used for confirming previous account actions.
|
||||
*/
|
||||
module { name = "ns_confirm" }
|
||||
command { service = "NickServ"; name = "CONFIRM"; command = "nickserv/confirm"; }
|
||||
|
||||
/*
|
||||
* ns_drop
|
||||
*
|
||||
@@ -344,21 +357,51 @@ module { name = "ns_drop" }
|
||||
command { service = "NickServ"; name = "DROP"; command = "nickserv/drop"; }
|
||||
|
||||
/*
|
||||
* ns_getemail
|
||||
* ns_email
|
||||
*
|
||||
* Provides the command nickserv/getemail.
|
||||
* Provides various functionality relating to email addresses. This includes the
|
||||
* following commands:
|
||||
*
|
||||
* Used for getting registered accounts by searching for emails.
|
||||
* - nickserv/confirm/email: Used for confirming email changes.
|
||||
* - nickserv/getemail: Used for getting accounts by searching for emails.
|
||||
* - nickserv/set/email, nickserv/saset/email: Used for setting an account's
|
||||
* emailvaddress.
|
||||
*/
|
||||
module { name = "ns_getemail" }
|
||||
module
|
||||
{
|
||||
name = "ns_email"
|
||||
|
||||
/*
|
||||
* The amount of time a user has after requesting a change of email address
|
||||
* before it expires. Defaults to 1 day.
|
||||
*/
|
||||
#changeexpire = 1d
|
||||
|
||||
/*
|
||||
* The limit to how many registered accounts can use the same email address.
|
||||
* If set to 0 or left commented there will be no limit enforced when
|
||||
* registering new accounts or using /msg NickServ SET EMAIL.
|
||||
*/
|
||||
#maxemails = 1
|
||||
|
||||
/*
|
||||
* Whether to attempt to remove aliases when counting email addresses. This
|
||||
* means removing dots (.) and anything after a plus (+) in the user part of
|
||||
* the address, e.g. foo.bar+baz@example.com -> foobar@example.com.
|
||||
*/
|
||||
#remove_aliases = yes
|
||||
}
|
||||
command { service = "NickServ"; name = "CONFIRM EMAIL"; command = "nickserv/confirm/email"; }
|
||||
command { service = "NickServ"; name = "GETEMAIL"; command = "nickserv/getemail"; permission = "nickserv/getemail"; group = "nickserv/admin"; }
|
||||
command { service = "NickServ"; name = "SET EMAIL"; command = "nickserv/set/email"; }
|
||||
command { service = "NickServ"; name = "SASET EMAIL"; command = "nickserv/saset/email"; permission = "nickserv/saset/email"; }
|
||||
|
||||
/*
|
||||
* ns_group
|
||||
*
|
||||
* Provides the commands nickserv/group, nickserv/glist, and nickserv/ungroup.
|
||||
*
|
||||
* Used for controlling nick groups.
|
||||
* Used for controlling grouped nicknames.
|
||||
*/
|
||||
module
|
||||
{
|
||||
@@ -400,7 +443,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,13 +516,13 @@ module
|
||||
command { service = "NickServ"; name = "RECOVER"; command = "nickserv/recover"; }
|
||||
|
||||
# For compatibility with Anope 1.8 and Atheme.
|
||||
command { service = "NickServ"; name = "GHOST"; command = "nickserv/recover"; hide = true; }
|
||||
command { service = "NickServ"; name = "RELEASE"; command = "nickserv/recover"; hide = true; }
|
||||
command { service = "NickServ"; name = "GHOST"; command = "nickserv/recover"; hide = yes; }
|
||||
command { service = "NickServ"; name = "RELEASE"; command = "nickserv/recover"; hide = yes; }
|
||||
|
||||
/*
|
||||
* ns_register
|
||||
*
|
||||
* Provides the commands nickserv/confirm, nickserv/register, and nickserv/resend.
|
||||
* Provides the commands nickserv/confirm/register, nickserv/register, and nickserv/resend.
|
||||
*
|
||||
* Used for registering accounts.
|
||||
*/
|
||||
@@ -488,9 +531,13 @@ module
|
||||
name = "ns_register"
|
||||
|
||||
/*
|
||||
* Registration confirmation setting. Set to "none" for no registration confirmation,
|
||||
* "mail" for email confirmation, and "admin" to have services operators manually confirm
|
||||
* every registration. Set to "disable" to completely disable all registrations.
|
||||
* The method for confirming account registrations. Possible values are:
|
||||
*
|
||||
* "admin" to require confirmation by a Services Operator.
|
||||
* "code" to require confirmation with a code provided via IRC.
|
||||
* "disable" to disable account registration.
|
||||
* "mail" to require confirmation with a code provided via email.
|
||||
* "none" to automatically confirm (this is the default).
|
||||
*/
|
||||
registration = "none"
|
||||
|
||||
@@ -515,18 +562,28 @@ module
|
||||
*/
|
||||
#unconfirmedexpire = 1d
|
||||
}
|
||||
command { service = "NickServ"; name = "CONFIRM"; command = "nickserv/confirm"; }
|
||||
command { service = "NickServ"; name = "CONFIRM REGISTER"; command = "nickserv/confirm/register"; }
|
||||
command { service = "NickServ"; name = "REGISTER"; command = "nickserv/register"; }
|
||||
command { service = "NickServ"; name = "RESEND"; command = "nickserv/resend"; }
|
||||
|
||||
/*
|
||||
* ns_resetpass
|
||||
*
|
||||
* Provides the command nickserv/resetpass.
|
||||
* Provides the command nickserv/confirm/resetpass and nickserv/resetpass.
|
||||
*
|
||||
* Used for resetting passwords by emailing users a temporary one.
|
||||
*/
|
||||
module { name = "ns_resetpass" }
|
||||
module
|
||||
{
|
||||
name = "ns_resetpass"
|
||||
|
||||
/*
|
||||
* The amount of time a user has after requesting a password reset before it
|
||||
* expires. Defaults to 1 day.
|
||||
*/
|
||||
#resetexpire = 1d
|
||||
}
|
||||
command { service = "NickServ"; name = "CONFIRM RESETPASS"; command = "nickserv/confirm/resetpass"; }
|
||||
command { service = "NickServ"; name = "RESETPASS"; command = "nickserv/resetpass"; }
|
||||
|
||||
/*
|
||||
@@ -557,7 +614,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 +630,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 +716,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 +752,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
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ service
|
||||
/*
|
||||
* The realname of the OperServ client.
|
||||
*/
|
||||
gecos = "Operator Service"
|
||||
real = "Operator Service"
|
||||
|
||||
/*
|
||||
* The modes this client should use.
|
||||
@@ -111,7 +111,7 @@ module
|
||||
killonsqline = yes
|
||||
|
||||
/*
|
||||
* Adds the nickname of the IRC Operator issuing an AKILL to the kill reason.
|
||||
* Adds the nickname of the Services Operator issuing an AKILL to the kill reason.
|
||||
*
|
||||
* This directive is optional.
|
||||
*/
|
||||
@@ -287,15 +287,15 @@ command { service = "OperServ"; name = "CHANKILL"; command = "operserv/chankill"
|
||||
* To use this module you must set a nameserver record for services
|
||||
* so that DNS queries go to services.
|
||||
*
|
||||
* Alternatively, you may use a slave DNS server to hide service's IP,
|
||||
* Alternatively, you may use a secondary DNS server to hide services' IP,
|
||||
* provide query caching, and provide better fault tolerance.
|
||||
*
|
||||
* To do this using BIND, configure similar to:
|
||||
*
|
||||
* options { max-refresh-time 60; };
|
||||
* zone "irc.example.com" IN {
|
||||
* type slave;
|
||||
* masters { 127.0.0.1 port 5353; };
|
||||
* type secondary;
|
||||
* primaries { 127.0.0.1 port 5353; };
|
||||
* };
|
||||
*
|
||||
* Where 127.0.0.1:5353 is the IP and port services are listening on.
|
||||
|
||||
@@ -1,515 +0,0 @@
|
||||
/*
|
||||
* Example configuration file for Anope. After making the appropriate
|
||||
* changes to this file, place it in the Anope conf directory (as
|
||||
* specified in the "Config" script, default /home/username/anope/conf)
|
||||
* under the name "anope.conf".
|
||||
*
|
||||
* The format of this file is fairly simple: three types of comments are supported:
|
||||
* - All text after a '#' on a line is ignored, as in shell scripting
|
||||
* - All text after '//' on a line is ignored, as in C++
|
||||
* - A block of text like this one is ignored, as in C
|
||||
*
|
||||
* Outside of comments, there are three structures: blocks, keys, and values.
|
||||
*
|
||||
* A block is a named container, which contains a number of key to value pairs
|
||||
* - you may think of this as an array.
|
||||
*
|
||||
* A block is created like so:
|
||||
* foobar
|
||||
* {
|
||||
* moo = "cow"
|
||||
* foo = bar
|
||||
* }
|
||||
*
|
||||
* Note that nameless blocks are allowed and are often used with comments to allow
|
||||
* easily commenting an entire block, for example:
|
||||
* #foobar
|
||||
* {
|
||||
* moo = "cow"
|
||||
* foo = bar
|
||||
* }
|
||||
* is an entirely commented block.
|
||||
*
|
||||
* Keys are case insensitive. Values depend on what key - generally, information is
|
||||
* given in the key comment. The quoting of values (and most other syntax) is quite
|
||||
* flexible, however, please do not forget to quote your strings:
|
||||
*
|
||||
* "This is a parameter string with spaces in it"
|
||||
*
|
||||
* If you need to include a double quote inside a quoted string, precede it
|
||||
* by a backslash:
|
||||
*
|
||||
* "This string has \"double quotes\" in it"
|
||||
*
|
||||
* Time parameters can be specified either as an integer representing a
|
||||
* number of seconds (e.g. "3600" = 1 hour), or as an integer with a unit
|
||||
* specifier: "s" = seconds, "m" = minutes, "h" = hours, "d" = days.
|
||||
* Combinations (such as "1h30m") are not permitted. Examples (all of which
|
||||
* represent the same length of time, one day):
|
||||
*
|
||||
* "86400", "86400s", "1440m", "24h", "1d"
|
||||
*
|
||||
* In the documentation for each directive, one of the following will be
|
||||
* included to indicate whether an option is required:
|
||||
*
|
||||
* [REQUIRED]
|
||||
* Indicates a directive which must be given. Without it, Anope will
|
||||
* not start.
|
||||
*
|
||||
* [RECOMMENDED]
|
||||
* Indicates a directive which may be omitted, but omitting it may cause
|
||||
* undesirable side effects.
|
||||
*
|
||||
* [OPTIONAL]
|
||||
* Indicates a directive which is optional. If not given, the feature
|
||||
* will typically be disabled. If this is not the case, more
|
||||
* information will be given in the documentation.
|
||||
*
|
||||
* [DISCOURAGED]
|
||||
* Indicates a directive which may cause undesirable side effects if
|
||||
* specified.
|
||||
*
|
||||
* [DEPRECATED]
|
||||
* Indicates a directive which will disappear in a future version of
|
||||
* Anope, usually because its functionality has been either
|
||||
* superseded by that of other directives or incorporated into the main
|
||||
* program.
|
||||
*/
|
||||
|
||||
/*
|
||||
* [OPTIONAL] Defines
|
||||
*
|
||||
* You can use defines for repeated information, which can be used to easily change many
|
||||
* values in the configuration at once.
|
||||
*
|
||||
* To use a define called foo.bar you use ${foo.bar} in your config file. You can also use
|
||||
* environment variables by prefixing their name with "env." like ${env.USER}.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The services.host define is used in multiple different locations throughout the
|
||||
* configuration for the server name and pseudoclient hostnames.
|
||||
*/
|
||||
define
|
||||
{
|
||||
name = "services.host"
|
||||
value = "stats.example.com"
|
||||
}
|
||||
|
||||
/*
|
||||
* [OPTIONAL] Additional Includes
|
||||
*
|
||||
* You can include additional configuration files here.
|
||||
* You may also include executable files, which will be executed and
|
||||
* the output from it will be included into your configuration.
|
||||
*/
|
||||
|
||||
#include
|
||||
{
|
||||
type = "file"
|
||||
name = "some.conf"
|
||||
}
|
||||
|
||||
#include
|
||||
{
|
||||
type = "executable"
|
||||
name = "/usr/bin/wget -q -O - https://some.misconfigured.network.com/stats.conf"
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] IRCd Config
|
||||
*
|
||||
* This section is used to set up Anope to connect to your IRC network.
|
||||
* This section can be included multiple times, and Anope will attempt to
|
||||
* connect to each server until it finally connects.
|
||||
*
|
||||
* Each uplink IRCd should have a corresponding configuration to allow Anope
|
||||
* to link to it.
|
||||
*
|
||||
* An example configuration for InspIRCd that is compatible with the below uplink
|
||||
* and serverinfo configuration would look like:
|
||||
*
|
||||
* # This goes in inspircd.conf, *NOT* your Anope config!
|
||||
* <link name="stats.example.com"
|
||||
* ipaddr="127.0.0.1"
|
||||
* port="7000"
|
||||
* sendpass="mypassword"
|
||||
* recvpass="mypassword">
|
||||
* <uline server="stats.example.com" silent="yes">
|
||||
* <bind address="127.0.0.1" port="7000" type="servers">
|
||||
*
|
||||
* An example configuration for UnrealIRCd that is compatible with the below uplink
|
||||
* and serverinfo configuration would look like:
|
||||
*
|
||||
* // This goes in unrealircd.conf, *NOT* your Anope config!
|
||||
* listen {
|
||||
* ip 127.0.0.1;
|
||||
* port 7000;
|
||||
* options {
|
||||
* serversonly;
|
||||
* };
|
||||
* };
|
||||
* link stats.example.com {
|
||||
* incoming {
|
||||
* mask *@127.0.0.1;
|
||||
* };
|
||||
* password "mypassword";
|
||||
* class servers;
|
||||
* };
|
||||
* ulines { stats.example.com; };
|
||||
*/
|
||||
uplink
|
||||
{
|
||||
/*
|
||||
* The IP address, hostname, or UNIX socket path of the IRC server you wish
|
||||
* to connect Anope to.
|
||||
* Usually, you will want to connect over 127.0.0.1 (aka localhost).
|
||||
*
|
||||
* NOTE: On some shell providers, this will not be an option.
|
||||
*/
|
||||
host = "127.0.0.1"
|
||||
|
||||
/*
|
||||
* The protocol that Anope should use when connecting to the uplink. Can
|
||||
* be set to "ipv4" (the default), "ipv6", or "unix".
|
||||
*/
|
||||
protocol = "ipv4"
|
||||
|
||||
/*
|
||||
* Enable if Anope should connect using SSL.
|
||||
* You must have an SSL module loaded for this to work.
|
||||
*/
|
||||
ssl = no
|
||||
|
||||
/*
|
||||
* The port to connect to.
|
||||
* The IRCd *MUST* be configured to listen on this port, and to accept
|
||||
* server connections.
|
||||
*
|
||||
* Refer to your IRCd documentation for how this is to be done.
|
||||
*/
|
||||
port = 7000
|
||||
|
||||
/*
|
||||
* The password to send to the IRC server for authentication.
|
||||
* This must match the link block on your IRCd.
|
||||
*
|
||||
* Refer to your IRCd documentation for more information on link blocks.
|
||||
*/
|
||||
password = "mypassword"
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] Server Information
|
||||
*
|
||||
* This section contains information about the services server.
|
||||
*/
|
||||
serverinfo
|
||||
{
|
||||
/*
|
||||
* The hostname that Anope will be seen as, it must have no conflicts with any
|
||||
* other server names on the rest of your IRC network. Note that it does not have
|
||||
* to be an existing hostname, just one that isn't on your network already.
|
||||
*/
|
||||
name = "${services.host}"
|
||||
|
||||
/*
|
||||
* The text which should appear as the server's information in /WHOIS and similar
|
||||
* queries.
|
||||
*/
|
||||
description = "Anope IRC Statistics"
|
||||
|
||||
/*
|
||||
* The local address that Anope will bind to before connecting to the remote
|
||||
* server. This may be useful for multihomed hosts. If omitted, Anope will let
|
||||
* the Operating System choose the local address. This directive is optional.
|
||||
*
|
||||
* If you don't know what this means or don't need to use it, just leave this
|
||||
* directive commented out.
|
||||
*/
|
||||
#localhost = "nowhere."
|
||||
|
||||
/*
|
||||
* What Server ID to use for this connection?
|
||||
* Note: This should *ONLY* be used for TS6/P10 IRCds. Refer to your IRCd documentation
|
||||
* to see if this is needed.
|
||||
*/
|
||||
#id = "00A"
|
||||
|
||||
/*
|
||||
* The filename containing the Anope process ID. The path is relative to the
|
||||
* data directory.
|
||||
*/
|
||||
pid = "anope.pid"
|
||||
|
||||
/*
|
||||
* The filename containing the Message of the Day. The path is relative to the
|
||||
* config directory.
|
||||
*/
|
||||
motd = "motd.txt"
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] Protocol module
|
||||
*
|
||||
* This directive tells Anope which IRCd Protocol to speak when connecting.
|
||||
* You MUST modify this to match the IRCd you run.
|
||||
*
|
||||
* Supported:
|
||||
* - bahamut
|
||||
* - hybrid
|
||||
* - inspircd
|
||||
* - ngircd
|
||||
* - plexus
|
||||
* - ratbox
|
||||
* - solanum
|
||||
* - unrealircd
|
||||
*/
|
||||
module
|
||||
{
|
||||
name = "inspircd"
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] Network Information
|
||||
*
|
||||
* This section contains information about the IRC network that Anope will be
|
||||
* connecting to.
|
||||
*/
|
||||
networkinfo
|
||||
{
|
||||
/*
|
||||
* This is the name of the network that Anope will be running on.
|
||||
*/
|
||||
networkname = "LocalNet"
|
||||
|
||||
/*
|
||||
* Set this to the maximum allowed nick length on your network.
|
||||
* Be sure to set this correctly, as setting this wrong can result in
|
||||
* Anope being disconnected from the network. Defaults to 31.
|
||||
*/
|
||||
#nicklen = 31
|
||||
|
||||
/* Set this to the maximum allowed ident length on your network.
|
||||
* Be sure to set this correctly, as setting this wrong can result in
|
||||
* Anope being disconnected from the network. Defaults to 10.
|
||||
*/
|
||||
#userlen = 10
|
||||
|
||||
/* Set this to the maximum allowed hostname length on your network.
|
||||
* Be sure to set this correctly, as setting this wrong can result in
|
||||
* Anope being disconnected from the network. Defaults to 64.
|
||||
*/
|
||||
#hostlen = 64
|
||||
|
||||
/* Set this to the maximum allowed channel length on your network.
|
||||
* Defaults to 64.
|
||||
*/
|
||||
#chanlen = 32
|
||||
|
||||
/* The maximum number of list modes settable on a channel (such as b, e, I).
|
||||
* Comment out or set to 0 to disable.
|
||||
*/
|
||||
modelistsize = 100
|
||||
|
||||
/*
|
||||
* The characters allowed in hostnames. This is used for validating hostnames given
|
||||
* to services, such as BotServ bot hostnames and user vhosts. Changing this is not
|
||||
* recommended unless you know for sure your IRCd supports whatever characters you are
|
||||
* wanting to use. Telling services to set a vHost containing characters your IRCd
|
||||
* disallows could potentially break the IRCd and/or Anope.
|
||||
*
|
||||
* It is recommended you DON'T change this.
|
||||
*/
|
||||
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"
|
||||
|
||||
/*
|
||||
* If set to true, allows vHosts to not contain dots (.).
|
||||
* Newer IRCds generally do not have a problem with this, but the same warning as
|
||||
* vhost_chars applies.
|
||||
*
|
||||
* It is recommended you DON'T change this.
|
||||
*/
|
||||
allow_undotted_vhosts = false
|
||||
|
||||
/*
|
||||
* The characters that are not allowed to be at the very beginning or very ending
|
||||
* of a vHost. The same warning as vhost_chars applies.
|
||||
*
|
||||
* It is recommended you DON'T change this.
|
||||
*/
|
||||
disallow_start_or_end = ".-"
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] Anope Options
|
||||
*
|
||||
* This section contains various options which determine how Anope will operate.
|
||||
*/
|
||||
options
|
||||
{
|
||||
/*
|
||||
* On Linux/UNIX systems Anope can setuid and setgid to this user and group
|
||||
* after starting up. This is useful if Anope has to bind to privileged ports.
|
||||
*/
|
||||
#user = "anope"
|
||||
#group = "anope"
|
||||
|
||||
/*
|
||||
* The case mapping used by services. This must be set to a valid locale name
|
||||
* installed on your machine. Anope uses this case map to compare, with
|
||||
* case insensitivity, things such as nick names, channel names, etc.
|
||||
*
|
||||
* We provide two special casemaps shipped with Anope, ascii and rfc1459.
|
||||
*
|
||||
* This value should be set to what your IRCd uses, which is probably rfc1459,
|
||||
* however Anope has always used ascii for comparison, so the default is ascii.
|
||||
*
|
||||
* Changing this value once set is not recommended.
|
||||
*/
|
||||
casemap = "ascii"
|
||||
|
||||
/*
|
||||
* Sets the timeout period for reading from the uplink.
|
||||
*/
|
||||
readtimeout = 5s
|
||||
|
||||
/*
|
||||
* If set, Anope will only show /stats o to IRC Operators. This directive
|
||||
* is optional.
|
||||
*/
|
||||
#hidestatso = yes
|
||||
|
||||
/*
|
||||
* A space-separated list of U-lined servers on your network, it is assumed that
|
||||
* the servers in this list are allowed to set channel modes and Anope will
|
||||
* not attempt to reverse their mode changes.
|
||||
*
|
||||
* WARNING: Do NOT put your normal IRC user servers in this directive.
|
||||
*
|
||||
* This directive is optional.
|
||||
*/
|
||||
#ulineservers = "services.your.network"
|
||||
|
||||
/*
|
||||
* How long to wait between connection retries with the uplink(s).
|
||||
*/
|
||||
retrywait = 60s
|
||||
}
|
||||
|
||||
/*
|
||||
* [RECOMMENDED] Logging Configuration
|
||||
*
|
||||
* This section is used for configuring what is logged and where it is logged to.
|
||||
* You may have multiple log blocks if you wish. Remember to properly secure any
|
||||
* channels you choose to have Anope log to!
|
||||
*/
|
||||
log
|
||||
{
|
||||
/*
|
||||
* Target(s) to log to, which may be one of the following:
|
||||
* - a channel name
|
||||
* - a filename
|
||||
* - globops
|
||||
*/
|
||||
target = "stats.log"
|
||||
|
||||
/* Log to both stats.log and the channel #stats
|
||||
*
|
||||
* Note that some older IRCds, such as Ratbox, require services to be in the
|
||||
* log channel to be able to message it. To do this, configure service:channels to
|
||||
* join your logging channel.
|
||||
*/
|
||||
#target = "stats.log #stats"
|
||||
|
||||
/*
|
||||
* The source(s) to only accept log messages from. Leave commented to allow all sources.
|
||||
* This can be a users name, a channel name, one of our clients (e.g. OperServ), or a server name.
|
||||
*/
|
||||
#source = ""
|
||||
|
||||
/*
|
||||
* The bot used to log generic messages which have no predefined sender if there
|
||||
* is a channel in the target directive.
|
||||
*/
|
||||
bot = "Global"
|
||||
|
||||
/*
|
||||
* The number of days to keep log files, only useful if you are logging to a file.
|
||||
* Set to 0 to never delete old log files.
|
||||
*
|
||||
* Note that Anope must run 24 hours a day for this feature to work correctly.
|
||||
*/
|
||||
logage = 7
|
||||
|
||||
/*
|
||||
* What types of log messages should be logged by this block. There are nine general categories:
|
||||
*
|
||||
* servers - Server actions, linking, squitting, etc.
|
||||
* channels - Actions in channels such as joins, parts, kicks, etc.
|
||||
* users - User actions such as connecting, disconnecting, changing name, etc.
|
||||
* other - All other messages without a category.
|
||||
* rawio - Logs raw input and output from services
|
||||
* debug - Debug messages (log files can become VERY large from this).
|
||||
*
|
||||
* These options determine what messages from the categories should be logged. Wildcards are accepted, and
|
||||
* you can also negate values with a ~. For example, "~operserv/akill operserv/*" would log all operserv
|
||||
* messages except for operserv/akill. Note that processing stops at the first matching option, which
|
||||
* means "* ~operserv/*" would log everything because * matches everything.
|
||||
*
|
||||
* Valid server options are:
|
||||
* connect, quit, sync, squit
|
||||
*
|
||||
* Valid channel options are:
|
||||
* create, destroy, join, part, kick, leave, mode
|
||||
*
|
||||
* Valid user options are:
|
||||
* connect, disconnect, quit, nick, ident, host, mode, maxusers, oper, away
|
||||
*
|
||||
* Rawio and debug are simple yes/no answers, there are no types for them.
|
||||
*
|
||||
* Note that modules may add their own values to these options.
|
||||
*/
|
||||
servers = "*"
|
||||
#channels = "~mode *"
|
||||
users = "connect disconnect nick"
|
||||
other = "*"
|
||||
rawio = no
|
||||
debug = no
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] MySQL Database configuration.
|
||||
*
|
||||
* mysql
|
||||
*
|
||||
* This module allows other modules to use MySQL.
|
||||
*/
|
||||
module
|
||||
{
|
||||
name = "mysql"
|
||||
|
||||
mysql
|
||||
{
|
||||
/* The name of this service. */
|
||||
name = "mysql/main"
|
||||
database = "anope"
|
||||
server = "127.0.0.1"
|
||||
username = "anope"
|
||||
password = "mypassword"
|
||||
port = 3306
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* IRC2SQL Gateway
|
||||
* This module collects data about users, channels and servers. It doesn't build stats
|
||||
* itself, however, it gives you the database, it's up to you how you use it.
|
||||
*
|
||||
* Requires a MySQL Database and MySQL version 5.5 or higher
|
||||
*/
|
||||
include
|
||||
{
|
||||
type = "file"
|
||||
name = "irc2sql.example.conf"
|
||||
}
|
||||
+2
-2
@@ -22,9 +22,9 @@ contributions they have made, are:
|
||||
* Michael Wobst <wobst.michael@web.de>
|
||||
* Mark Summers <mark@goopler.net>
|
||||
* Matt Schatz <genius3000@g3k.solutions>
|
||||
* PeGaSuS <droider.pc@gmail.com>
|
||||
* Daniel Vassdal <shutter@canternet.org>
|
||||
* MatthewM <mcm@they-got.us>
|
||||
* PeGaSuS <droider.pc@gmail.com>
|
||||
* Sebastian V. <hal9000@denorastats.org>
|
||||
* Alvaro Toledo <atoledo@keldon.org>
|
||||
* Dragone2 <dragone2@risposteinformatiche.it>
|
||||
@@ -33,9 +33,9 @@ contributions they have made, are:
|
||||
* Hendrik Jäger <gitcommit@henk.geekmail.org>
|
||||
* k4be <k4be@pirc.pl>
|
||||
* Thomas Fargeix <t.fargeix@gmail.com>
|
||||
* Val Lorentz <progval+git@progval.net>
|
||||
* Bram Matthys <syzop@vulnscan.org>
|
||||
* Federico G. Schwindt <fgsch@lodoss.net>
|
||||
* Val Lorentz <progval+git@progval.net>
|
||||
* Alexander Barton <alex@barton.de>
|
||||
* CaPa CuL <capacul@gmail.com>
|
||||
* Cronus <cronus@nite-serv.com>
|
||||
|
||||
+41
-2
@@ -1,5 +1,44 @@
|
||||
Anope Version 2.1.14-git
|
||||
------------------------
|
||||
Anope Version 2.1.16
|
||||
--------------------
|
||||
Added support for on-IRC code confirmation.
|
||||
Added the ability for fantasy commands to be executable without the FANTASY privilege.
|
||||
Added the ability to prepend to topics as well as appending to them.
|
||||
Changed various fields to serialize to the database as a string not an integer.
|
||||
Disabled db_flatfile by default in preparation for becoming import-only.
|
||||
Fixed a memory leak in the db_json module.
|
||||
Fixed building on OpenSSL 1.1.1 (for now).
|
||||
Fixed removed and later re-added temporary bans being removed automatically.
|
||||
Fixed sometimes sending malformed LMODE messages on InspIRCd.
|
||||
Fixed the "did you mean" message suggesting unloaded commands.
|
||||
Fixed various issues with the example config files.
|
||||
Marked db_json as the recommended database module.
|
||||
Moved the BAN, UNBAN, and KICK commands to the chanserv/management group.
|
||||
Removed support for the 1.8-style seen command.
|
||||
Reworked confirmation to allow confirmation of multiple account actions.
|
||||
When dropping a display nickname the new display will now be the oldest in the group.
|
||||
|
||||
Anope Version 2.1.15
|
||||
--------------------
|
||||
Added a workaround to the jsonrpc module for JavaScript truncating big integers.
|
||||
Added an example Ruby library for accessing the RPC interface.
|
||||
Added away state and tls usage to the anope.user RPC event.
|
||||
Added support for looking up accounts by identifier in the anope.account RPC event.
|
||||
Added support for storing the setter and set time and setter of list modes and restoring them on InspIRCd and Solanum.
|
||||
Added support for token authentication to the RPC modules.
|
||||
Added the anope.checkCredentials, anope.identify, anope.listCommands, and anope.command RPC events to the new rpc_user module.
|
||||
Bumped the minimum supported version of ircd-hybrid to 8.2.34.
|
||||
Deprecated irc2sql in favour of rpc_data.
|
||||
Dropped support for Bahamut as it has no known users.
|
||||
Fixed creating duplicate Stats rows on some servers.
|
||||
Fixed loading databases in db_json.
|
||||
Fixed restoring cloaked hosts on InspIRCd when the cloak module is not loaded.
|
||||
Fixed some variable shadowing that potentially caused issues with the SQL database backends.
|
||||
Fixed sometimes writing accounts to the database without a unique identifier.
|
||||
Fixed various documentation issues with the example JavaScript JSON-RPC client.
|
||||
Improved CTCP handling and added support for more CTCP types.
|
||||
|
||||
Anope Version 2.1.14
|
||||
--------------------
|
||||
Added a detail specifier to the anope.list{Channels,Opers,Servers,Users} RPC methods.
|
||||
Added a matcher for the InspIRCd oper extban.
|
||||
Added support for hashed operator passwords.
|
||||
|
||||
+36
-6
@@ -1,5 +1,35 @@
|
||||
Anope Version 2.1.14-git
|
||||
------------------------
|
||||
Anope Version 2.1.16
|
||||
--------------------
|
||||
Added fantasy:require_privilege (defaults to yes).
|
||||
Added the nickserv/confirm/email command.
|
||||
Added the nickserv/confirm/email oper privilege.
|
||||
Added the nickserv/confirm/register command.
|
||||
Added the ns_confirm module.
|
||||
Added {ns_email}:changeexpire (defaults to 1 day).
|
||||
Added {ns_resetpass}:resetexpire (defaults to 1 day).
|
||||
Removed the irc2sql module (migrate to JSON-RPC instead).
|
||||
Removed {ns_seen}:simple (1.8-style seen has been removed).
|
||||
Renamed the nickserv/confirm oper privilege to nickserv/confirm/register.
|
||||
|
||||
Anope Version 2.1.15
|
||||
--------------------
|
||||
Added the ns_email module.
|
||||
Added the rpc_user module.
|
||||
Added {jsonrpc}:integer_bits (defaults to 64).
|
||||
Added {jsonrpc}:token.
|
||||
Added {nickserv}:enforcerreal (defaults to "Services Enforcer").
|
||||
Added {xmlrpc}:token.
|
||||
Moved nickserv/set/email and nickserv/saset/email to the ns_email module.
|
||||
Removed the bahamut module.
|
||||
Removed the ns_getemail module (load ns_email instead).
|
||||
Removed the ns_maxemail module (load ns_email instead).
|
||||
Removed the rpc_main module (migrate to the other RPC modules).
|
||||
Removed {chanstats}:cs_def_chanstats (add CS_STATS to {chanserv}:defaults instead).
|
||||
Removed {chanstats}:ns_def_chanstats (add NS_STATS to {nickserv}:defaults instead).
|
||||
Renamed service:gecos to service:real.
|
||||
|
||||
Anope Version 2.1.14
|
||||
--------------------
|
||||
Added oper:password_hash.
|
||||
Added options:codelength (defaults to 15).
|
||||
Added {os_news}:showdate (defaults to yes).
|
||||
@@ -8,7 +38,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 +164,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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
@@ -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
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
+7
-7
@@ -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.
|
||||
@@ -164,7 +164,7 @@ public:
|
||||
/* Unsaved data */
|
||||
|
||||
/** The display nick for this account. */
|
||||
NickAlias *na = nullptr;
|
||||
Serialize::Reference<NickAlias> na;
|
||||
/* Number of channels registered by this account */
|
||||
uint16_t channelcount = 0;
|
||||
/* Users online now logged into this account */
|
||||
@@ -195,7 +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
@@ -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
@@ -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
@@ -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 ¶m = "", 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 ¶m = "", 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 ¶m = "", bool enforce_mlock = true);
|
||||
void SetMode(BotInfo *bi, const Anope::string &name, const ModeData &data = {}, bool enforce_mlock = true);
|
||||
|
||||
/** Remove a mode from a channel
|
||||
* @param bi The client setting the modes
|
||||
|
||||
+10
-8
@@ -32,10 +32,12 @@ struct CommandInfo final
|
||||
Anope::string permission;
|
||||
/* Group this command is in */
|
||||
Anope::string group;
|
||||
/* whether or not to hide this command in help output */
|
||||
/* Whether to hide this command in help and suggestions */
|
||||
bool hide = false;
|
||||
/* Only used with fantasy */
|
||||
/* Whether to prepend the channel name (only used with fantasy) */
|
||||
bool prepend_channel = false;
|
||||
/* Whether to require the FANTASY privilege (only used with fantasy) */
|
||||
bool require_privilege = true;
|
||||
};
|
||||
|
||||
/* Where the replies from commands go to. User inherits from this and is the normal
|
||||
@@ -99,9 +101,9 @@ class CoreExport Command
|
||||
Anope::string desc;
|
||||
std::vector<std::pair<Anope::string, std::function<bool(CommandSource&)>>> syntax;
|
||||
/* Allow unregistered users to use this command */
|
||||
bool allow_unregistered;
|
||||
bool allow_unregistered = false;
|
||||
/* Command requires that a user is executing it */
|
||||
bool require_user;
|
||||
bool require_user = false;
|
||||
|
||||
public:
|
||||
/* Maximum parameters accepted by this command */
|
||||
@@ -136,8 +138,8 @@ protected:
|
||||
void RequireUser(bool b);
|
||||
|
||||
public:
|
||||
bool AllowUnregistered() const;
|
||||
bool RequireUser() const;
|
||||
inline bool AllowUnregistered() const { return this->allow_unregistered; }
|
||||
inline bool RequireUser() const { return this->require_user; }
|
||||
|
||||
/** Get the command description
|
||||
* @param source The source wanting the command description
|
||||
@@ -173,9 +175,9 @@ public:
|
||||
* @param source The source of the command
|
||||
* @param message The full message to run, the command is at the beginning of the message
|
||||
*/
|
||||
static void Run(CommandSource &source, const Anope::string &message);
|
||||
static bool Run(CommandSource &source, const Anope::string &message);
|
||||
|
||||
void Run(CommandSource &source, const Anope::string &, const CommandInfo &, std::vector<Anope::string> ¶ms);
|
||||
bool Run(CommandSource &source, const Anope::string &, const CommandInfo &, std::vector<Anope::string> ¶ms);
|
||||
|
||||
/** 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
|
||||
|
||||
@@ -19,6 +19,7 @@ class ChanAccess;
|
||||
class Channel;
|
||||
class ChannelInfo;
|
||||
class ChannelStatus;
|
||||
struct ModeData;
|
||||
struct ChanUserContainer;
|
||||
class ClientSocket;
|
||||
class Command;
|
||||
|
||||
+1
-2
@@ -102,7 +102,7 @@ namespace Language
|
||||
/* Commonly used language strings */
|
||||
#define CONFIRM_DROP _("Please confirm that you want to drop \002%s\002 with \002%s\032%s\032%s\002")
|
||||
#define SERVICE_UNAVAILABLE _("Sorry, %s is temporarily unavailable.")
|
||||
#define MORE_INFO _("\002%s\002 for more information.")
|
||||
#define MORE_INFO _("Type \002%s\002 for more information.")
|
||||
#define BAD_USERHOST_MASK _("Mask must be in the form \037user\037@\037host\037.")
|
||||
#define BAD_EXPIRY_TIME _("Invalid expiry time.")
|
||||
#define USERHOST_MASK_TOO_WIDE _("%s coverage is too wide; Please use a more specific mask.")
|
||||
@@ -134,7 +134,6 @@ namespace Language
|
||||
#define NICK_CANNOT_BE_REGISTERED _("Nickname \002%s\002 may not be registered.")
|
||||
#define NICK_ALREADY_REGISTERED _("Nickname \002%s\002 is already registered!")
|
||||
#define NICK_SET_DISPLAY_CHANGED _("The new display is now \002%s\002.")
|
||||
#define NICK_CONFIRM_INVALID _("Invalid passcode has been entered, please check the email again, and retry.")
|
||||
#define CHAN_NOT_ALLOWED_TO_JOIN _("You are not permitted to be on this channel.")
|
||||
#define CHAN_X_INVALID _("Channel %s is not a valid channel.")
|
||||
#define CHAN_REACHED_CHANNEL_LIMIT _("Sorry, you have already reached your limit of \002%d\002 channels.")
|
||||
|
||||
+1
-1
@@ -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
@@ -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 ¶m = "");
|
||||
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 ¶m = "");
|
||||
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
@@ -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 ¶m) 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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -15,13 +15,6 @@ enum NewsType
|
||||
NEWS_OPER
|
||||
};
|
||||
|
||||
struct NewsMessages final
|
||||
{
|
||||
NewsType type;
|
||||
Anope::string name;
|
||||
const char *msgs[10];
|
||||
};
|
||||
|
||||
struct NewsItem
|
||||
: Serializable
|
||||
{
|
||||
|
||||
+53
-3
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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 ¶m = "");
|
||||
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 ¶m = "");
|
||||
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 ¶m = "");
|
||||
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
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -6607,7 +6607,7 @@ msgid "Service"
|
||||
msgstr "Server gefunden: %d"
|
||||
|
||||
#, fuzzy, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Die Services haben den Nicknamen wieder verfügbar gemacht."
|
||||
|
||||
#, fuzzy
|
||||
|
||||
@@ -6832,7 +6832,7 @@ msgid "Service"
|
||||
msgstr "Τα services είναι ενεργά για %s"
|
||||
|
||||
#, fuzzy, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Οι υπηρεσίες απελευθέρωααν το ψευδώνυμό σου."
|
||||
|
||||
#, fuzzy
|
||||
|
||||
+252
-252
File diff suppressed because it is too large
Load Diff
@@ -6273,7 +6273,7 @@ msgid "Service"
|
||||
msgstr "Servicio"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "El nick %s retenido por los servicios ha sido liberado."
|
||||
|
||||
#, fuzzy
|
||||
|
||||
@@ -4412,7 +4412,7 @@ msgid "Last topic"
|
||||
msgstr "Dernier topic"
|
||||
|
||||
msgid "Last used"
|
||||
msgstr "Utilisé dernièrement"
|
||||
msgstr "Dernière utilisation"
|
||||
|
||||
msgid "Last usermask"
|
||||
msgstr "Dernier usermask"
|
||||
@@ -6155,7 +6155,7 @@ msgid "Service"
|
||||
msgstr "Service"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "La tutelle des Services sur %s a été enlevée."
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
@@ -6146,7 +6146,7 @@ msgid "Service"
|
||||
msgstr "Servizio"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Il blocco dei servizi sul nick %s è stato rilasciato."
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
@@ -6182,7 +6182,7 @@ msgid "Service"
|
||||
msgstr "Service"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Nick %s werd vrijgegeven."
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
@@ -6123,7 +6123,7 @@ msgid "Service"
|
||||
msgstr "Usługa"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Serwisy właśnie zwolniły nicka %s."
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
@@ -5675,7 +5675,7 @@ msgid "Service"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr ""
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
@@ -6067,7 +6067,7 @@ msgid "Service"
|
||||
msgstr "Servis"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Servisin %s üzerindeki bekletmesi kaldırıldı."
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
@@ -196,15 +196,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const Anope::string ¶m) 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;
|
||||
|
||||
@@ -12,6 +12,39 @@
|
||||
#include "module.h"
|
||||
#include "modules/botserv/badwords.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
Anope::string TypeToString(BadWordType bw)
|
||||
{
|
||||
switch (bw)
|
||||
{
|
||||
case BW_ANY:
|
||||
return "ANY";
|
||||
case BW_SINGLE:
|
||||
return "SINGLE";
|
||||
case BW_START:
|
||||
return "START";
|
||||
case BW_END:
|
||||
return "END";
|
||||
}
|
||||
return ""; // Should never happen.
|
||||
}
|
||||
|
||||
BadWordType StringToType(const Anope::string &bw)
|
||||
{
|
||||
if (bw.equals_ci("ANY") || bw.equals_ci("0"))
|
||||
return BW_ANY;
|
||||
if (bw.equals_ci("SINGLE") || bw.equals_ci("1"))
|
||||
return BW_SINGLE;
|
||||
if (bw.equals_ci("START") || bw.equals_ci("2"))
|
||||
return BW_START;
|
||||
if (bw.equals_ci("END") || bw.equals_ci("3"))
|
||||
return BW_END;
|
||||
|
||||
return BW_ANY; // Should never happen.
|
||||
}
|
||||
}
|
||||
|
||||
struct BadWordImpl final
|
||||
: BadWord
|
||||
, Serializable
|
||||
@@ -28,12 +61,12 @@ struct BadWordTypeImpl final
|
||||
{
|
||||
}
|
||||
|
||||
void Serialize(const Serializable *obj, Serialize::Data &data) const override
|
||||
void Serialize(Serializable *obj, Serialize::Data &data) const override
|
||||
{
|
||||
const auto *bw = static_cast<const BadWordImpl *>(obj);
|
||||
data.Store("ci", bw->chan);
|
||||
data.Store("word", bw->word);
|
||||
data.Store("type", bw->type);
|
||||
data.Store("type", TypeToString(bw->type));
|
||||
}
|
||||
|
||||
Serializable *Unserialize(Serializable *obj, Serialize::Data &) const override;
|
||||
@@ -138,7 +171,7 @@ Serializable *BadWordTypeImpl::Unserialize(Serializable *obj, Serialize::Data &d
|
||||
if (!ci)
|
||||
return NULL;
|
||||
|
||||
unsigned int n;
|
||||
Anope::string n;
|
||||
data["type"] >> n;
|
||||
|
||||
BadWordImpl *bw;
|
||||
@@ -148,7 +181,7 @@ Serializable *BadWordTypeImpl::Unserialize(Serializable *obj, Serialize::Data &d
|
||||
bw = new BadWordImpl();
|
||||
bw->chan = sci;
|
||||
bw->word = sword;
|
||||
bw->type = static_cast<BadWordType>(n);
|
||||
bw->type = StringToType(n);
|
||||
|
||||
BadWordsImpl *bws = ci->Require<BadWordsImpl>("badwords");
|
||||
if (!obj)
|
||||
@@ -244,7 +277,7 @@ private:
|
||||
ListFormatter::ListEntry entry;
|
||||
entry["Number"] = Anope::ToString(Number);
|
||||
entry["Word"] = b->word;
|
||||
entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : ""));
|
||||
entry["Type"] = TypeToString(b->type);
|
||||
this->list.AddEntry(entry);
|
||||
}
|
||||
}
|
||||
@@ -263,7 +296,7 @@ private:
|
||||
ListFormatter::ListEntry entry;
|
||||
entry["Number"] = Anope::ToString(i + 1);
|
||||
entry["Word"] = b->word;
|
||||
entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : ""));
|
||||
entry["Type"] = TypeToString(b->type);
|
||||
list.AddEntry(entry);
|
||||
}
|
||||
}
|
||||
@@ -295,14 +328,7 @@ private:
|
||||
{
|
||||
Anope::string opt = word.substr(pos + 1);
|
||||
if (!opt.empty())
|
||||
{
|
||||
if (opt.equals_ci("SINGLE"))
|
||||
bwtype = BW_SINGLE;
|
||||
else if (opt.equals_ci("START"))
|
||||
bwtype = BW_START;
|
||||
else if (opt.equals_ci("END"))
|
||||
bwtype = BW_END;
|
||||
}
|
||||
bwtype = StringToType(opt);
|
||||
realword = word.substr(0, pos);
|
||||
}
|
||||
|
||||
@@ -463,12 +489,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"
|
||||
|
||||
@@ -173,7 +173,7 @@ class CommandBSSetPrivate final
|
||||
public:
|
||||
CommandBSSetPrivate(Module *creator, const Anope::string &sname = "botserv/set/private") : Command(creator, sname, 2, 2)
|
||||
{
|
||||
this->SetDesc(_("Prevent a bot from being assigned by non IRC operators"));
|
||||
this->SetDesc(_("Prevent a bot from being assigned by non Services Operators"));
|
||||
this->SetSyntax(_("\037botname\037 {\037ON|OFF\037}"));
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ public:
|
||||
source.Reply(" ");
|
||||
source.Reply(_(
|
||||
"This option prevents a bot from being assigned to a "
|
||||
"channel by users that aren't IRC Operators."
|
||||
"channel by users that aren't Services Operators."
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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 ¶m) 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.
|
||||
*/
|
||||
|
||||
@@ -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)."
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
|
||||
static Module *me;
|
||||
|
||||
class TempBan;
|
||||
static std::vector<TempBan *> tempbans;
|
||||
|
||||
class TempBan final
|
||||
: public Timer
|
||||
{
|
||||
@@ -28,6 +31,21 @@ public:
|
||||
, mask(banmask)
|
||||
, mode(mod)
|
||||
{
|
||||
tempbans.push_back(this);
|
||||
}
|
||||
|
||||
~TempBan()
|
||||
{
|
||||
auto it = std::find(tempbans.begin(), tempbans.end(), this);
|
||||
if (it != tempbans.end())
|
||||
tempbans.erase(it);
|
||||
}
|
||||
|
||||
bool Matches(Channel *chan, ChannelMode *cmode, const Anope::string &bmask) const
|
||||
{
|
||||
return chan->name.equals_ci(this->channel)
|
||||
&& cmode->name == this->mode
|
||||
&& bmask == this->mask;
|
||||
}
|
||||
|
||||
void Tick() override
|
||||
@@ -258,10 +276,25 @@ class CSBan final
|
||||
CommandCSBan commandcsban;
|
||||
|
||||
public:
|
||||
CSBan(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandcsban(this)
|
||||
CSBan(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, VENDOR)
|
||||
, commandcsban(this)
|
||||
{
|
||||
me = this;
|
||||
}
|
||||
|
||||
EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *cmode, const Anope::string ¶m) override
|
||||
{
|
||||
for (const auto *tempban : tempbans)
|
||||
{
|
||||
if (tempban->Matches(c, cmode, param))
|
||||
{
|
||||
delete tempban;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return EVENT_CONTINUE;
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_INIT(CSBan)
|
||||
|
||||
@@ -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."
|
||||
));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -16,7 +16,6 @@ enum TypeInfo
|
||||
NEW, NICK_TO, NICK_FROM, JOIN, PART, QUIT, KICK
|
||||
};
|
||||
|
||||
static bool simple;
|
||||
struct SeenInfo;
|
||||
static SeenInfo *FindInfo(const Anope::string &nick);
|
||||
typedef Anope::unordered_map<SeenInfo *> database_map;
|
||||
@@ -53,12 +52,54 @@ struct SeenInfoType final
|
||||
{
|
||||
}
|
||||
|
||||
void Serialize(const Serializable *obj, Serialize::Data &data) const override
|
||||
static Anope::string TypeToString(TypeInfo ti)
|
||||
{
|
||||
switch (ti)
|
||||
{
|
||||
case NEW:
|
||||
return "NEW";
|
||||
case NICK_TO:
|
||||
return "NICK_TO";
|
||||
case NICK_FROM:
|
||||
return "NICK_FROM";
|
||||
case JOIN:
|
||||
return "JOIN";
|
||||
case PART:
|
||||
return "PART";
|
||||
case QUIT:
|
||||
return "QUIT";
|
||||
case KICK:
|
||||
return "KICK";
|
||||
}
|
||||
return ""; // Should never happen.
|
||||
}
|
||||
|
||||
static TypeInfo StringToType(const Anope::string &ti)
|
||||
{
|
||||
if (ti.equals_ci("NEW") || ti.equals_ci("0"))
|
||||
return NEW;
|
||||
if (ti.equals_ci("NICK_TO") || ti.equals_ci("1"))
|
||||
return NICK_TO;
|
||||
if (ti.equals_ci("NICK_FROM") || ti.equals_ci("2"))
|
||||
return NICK_FROM;
|
||||
if (ti.equals_ci("JOIN") || ti.equals_ci("3"))
|
||||
return JOIN;
|
||||
if (ti.equals_ci("PART") || ti.equals_ci("4"))
|
||||
return PART;
|
||||
if (ti.equals_ci("QUIT") || ti.equals_ci("5"))
|
||||
return QUIT;
|
||||
if (ti.equals_ci("KICK") || ti.equals_ci("6"))
|
||||
return KICK;
|
||||
|
||||
return NEW; // Should never happen.
|
||||
}
|
||||
|
||||
void Serialize(Serializable *obj, Serialize::Data &data) const override
|
||||
{
|
||||
const auto *s = static_cast<const SeenInfo *>(obj);
|
||||
data.Store("nick", s->nick);
|
||||
data.Store("vhost", s->vhost);
|
||||
data.Store("type", s->type);
|
||||
data.Store("type", TypeToString(s->type));
|
||||
data.Store("nick2", s->nick2);
|
||||
data.Store("channel", s->channel);
|
||||
data.Store("message", s->message);
|
||||
@@ -84,9 +125,9 @@ struct SeenInfoType final
|
||||
|
||||
s->nick = snick;
|
||||
data["vhost"] >> s->vhost;
|
||||
unsigned int n;
|
||||
Anope::string n;
|
||||
data["type"] >> n;
|
||||
s->type = static_cast<TypeInfo>(n);
|
||||
s->type = StringToType(n);
|
||||
data["nick2"] >> s->nick2;
|
||||
data["channel"] >> s->channel;
|
||||
data["message"] >> s->message;
|
||||
@@ -199,76 +240,6 @@ public:
|
||||
class CommandSeen final
|
||||
: public Command
|
||||
{
|
||||
static void SimpleSeen(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
{
|
||||
if (!source.c || !source.c->ci)
|
||||
{
|
||||
if (source.IsOper())
|
||||
source.Reply("Seen in simple mode is designed as a fantasy command only!");
|
||||
return;
|
||||
}
|
||||
|
||||
BotInfo *bi = BotInfo::Find(params[0], true);
|
||||
if (bi)
|
||||
{
|
||||
if (bi == source.c->ci->bi)
|
||||
source.Reply(_("You found me, %s!"), source.GetNick().c_str());
|
||||
else
|
||||
source.Reply(_("%s is a network service."), bi->nick.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
NickAlias *na = NickAlias::Find(params[0]);
|
||||
if (!na)
|
||||
{
|
||||
source.Reply(_("I don't know who %s is."), params[0].c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (source.GetAccount() == na->nc)
|
||||
{
|
||||
source.Reply(_("Looking for yourself, eh %s?"), source.GetNick().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
User *target = User::Find(params[0], true);
|
||||
|
||||
if (target && source.c->FindUser(target))
|
||||
{
|
||||
source.Reply(_("%s is on the channel right now!"), target->nick.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &[_, uc] : source.c->users)
|
||||
{
|
||||
User *u = uc->user;
|
||||
|
||||
if (u->Account() == na->nc)
|
||||
{
|
||||
source.Reply(_("%s is on the channel right now (as %s)!"), params[0].c_str(), u->nick.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AccessGroup ag = source.c->ci->AccessFor(na->nc);
|
||||
time_t last = 0;
|
||||
for (const auto &p : ag.paths)
|
||||
{
|
||||
if (p.empty())
|
||||
continue;
|
||||
|
||||
ChanAccess *a = p[p.size() - 1];
|
||||
|
||||
if (a->GetAccount() == na->nc && a->last_seen > last)
|
||||
last = a->last_seen;
|
||||
}
|
||||
|
||||
if (last > Anope::CurTime || !last)
|
||||
source.Reply(_("I've never seen %s on this channel."), na->nick.c_str());
|
||||
else
|
||||
source.Reply(_("%s was last seen here %s ago."), na->nick.c_str(), Anope::Duration(Anope::CurTime - last, source.GetAccount()).c_str());
|
||||
}
|
||||
|
||||
public:
|
||||
CommandSeen(Module *creator) : Command(creator, "chanserv/seen", 1, 2)
|
||||
{
|
||||
@@ -281,9 +252,6 @@ public:
|
||||
{
|
||||
const Anope::string &target = params[0];
|
||||
|
||||
if (simple)
|
||||
return this->SimpleSeen(source, params);
|
||||
|
||||
if (target.length() > IRCD->MaxNick)
|
||||
{
|
||||
source.Reply(_("Nick too long, max length is %zu characters."), IRCD->MaxNick);
|
||||
@@ -401,17 +369,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void OnReload(Configuration::Conf &conf) override
|
||||
{
|
||||
simple = conf.GetModule(this).Get<bool>("simple");
|
||||
}
|
||||
|
||||
void OnExpireTick() override
|
||||
{
|
||||
size_t previous_size = database.size();
|
||||
time_t purgetime = Config->GetModule(this).Get<time_t>("purgetime");
|
||||
auto purgetime = Config->GetModule(this).Get<time_t>("purgetime", "90d");
|
||||
if (!purgetime)
|
||||
purgetime = Anope::DoTime("30d");
|
||||
return;
|
||||
|
||||
auto previous_size = database.size();
|
||||
for (database_map::iterator it = database.begin(), it_end = database.end(); it != it_end;)
|
||||
{
|
||||
database_map::iterator cur = it;
|
||||
@@ -461,7 +425,7 @@ public:
|
||||
private:
|
||||
static void UpdateUser(const User *u, const TypeInfo Type, const Anope::string &nick, const Anope::string &nick2, const Anope::string &channel, const Anope::string &message)
|
||||
{
|
||||
if (simple || !u->server->IsSynced())
|
||||
if (!u->server->IsSynced())
|
||||
return;
|
||||
|
||||
SeenInfo *&info = database[nick];
|
||||
|
||||
+39
-12
@@ -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 ¶m) override
|
||||
EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const ModeData &data) override
|
||||
{
|
||||
if (c->ci)
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ struct CSMiscDataType
|
||||
{
|
||||
}
|
||||
|
||||
void Serialize(const Serializable *obj, Serialize::Data &sdata) const override
|
||||
void Serialize(Serializable *obj, Serialize::Data &sdata) const override
|
||||
{
|
||||
const auto *d = static_cast<const CSMiscData *>(obj);
|
||||
sdata.Store("ci", d->object);
|
||||
@@ -171,6 +171,7 @@ public:
|
||||
if (descriptions.count(source.command))
|
||||
{
|
||||
this->SendSyntax(source);
|
||||
source.Reply(" ");
|
||||
source.Reply("%s", Language::Translate(source.nc, descriptions[source.command].c_str()));
|
||||
return true;
|
||||
}
|
||||
@@ -230,7 +231,7 @@ public:
|
||||
|
||||
void OnJoinChannel(User *user, Channel *c) override
|
||||
{
|
||||
if (!c->ci || !user->server->IsSynced() || numerics.empty())
|
||||
if (!c->ci || !user->server->IsSynced() || user->server == Me || numerics.empty())
|
||||
return;
|
||||
|
||||
for (const auto &[name, ext] : items)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -132,14 +132,18 @@ class CommandCSTopic final
|
||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << (!topic.empty() ? "to change the topic to: " : "to unset the topic") << (!topic.empty() ? topic : "");
|
||||
}
|
||||
|
||||
void Append(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms)
|
||||
void Combine(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms, bool append)
|
||||
{
|
||||
const Anope::string &topic = params[2];
|
||||
|
||||
Anope::string new_topic;
|
||||
if (!ci->c->topic.empty())
|
||||
{
|
||||
new_topic = ci->c->topic + " " + topic;
|
||||
if (append)
|
||||
new_topic = ci->c->topic + " " + topic;
|
||||
else
|
||||
new_topic = topic + " " + ci->c->topic;
|
||||
|
||||
ci->last_topic.clear();
|
||||
}
|
||||
else
|
||||
@@ -155,6 +159,7 @@ public:
|
||||
this->SetDesc(_("Manipulate the topic of the specified channel"));
|
||||
this->SetSyntax(_("\037channel\037 [SET] [\037topic\037]"));
|
||||
this->SetSyntax(_("\037channel\037 APPEND \037topic\037"));
|
||||
this->SetSyntax(_("\037channel\037 PREPEND \037topic\037"));
|
||||
this->SetSyntax(_("\037channel\037 [UNLOCK|LOCK]"));
|
||||
}
|
||||
|
||||
@@ -174,7 +179,9 @@ public:
|
||||
else if (!ci->c)
|
||||
source.Reply(CHAN_X_NOT_IN_USE, ci->name.c_str());
|
||||
else if (subcmd.equals_ci("APPEND") && params.size() > 2)
|
||||
this->Append(source, ci, params);
|
||||
this->Combine(source, ci, params, true);
|
||||
else if (subcmd.equals_ci("PREPEND") && params.size() > 2)
|
||||
this->Combine(source, ci, params, false);
|
||||
else
|
||||
{
|
||||
Anope::string topic;
|
||||
|
||||
@@ -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
@@ -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 ¶m) 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)
|
||||
|
||||
@@ -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);
|
||||
@@ -527,7 +512,7 @@ private:
|
||||
|
||||
if (!forbid_service)
|
||||
{
|
||||
Log(this) << "Unable to convert forbidden email " << email << " as os_forbid is not loaded";
|
||||
Log(this) << "Unable to convert forbidden email address " << email << " as os_forbid is not loaded";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -640,6 +625,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
auto originalflags = flags;
|
||||
Anope::string accessflags;
|
||||
ApplyAccess(flags, 'A', accessflags, { "ACCESS_LIST" });
|
||||
ApplyAccess(flags, 'a', accessflags, { "AUTOPROTECT", "PROTECT", "PROTECTME" });
|
||||
@@ -662,7 +648,7 @@ private:
|
||||
auto *access = accessprov->Create();
|
||||
access->SetMask(mask, ci);
|
||||
access->creator = setter;
|
||||
access->description = "Imported from Atheme";
|
||||
access->description = "Imported from Atheme: " + flags;
|
||||
access->last_seen = modifiedtime;
|
||||
access->created = modifiedtime;
|
||||
access->AccessUnserialize(accessflags);
|
||||
|
||||
+188
-158
@@ -20,23 +20,13 @@ namespace fs = std::filesystem;
|
||||
|
||||
// TODO:
|
||||
// * forking into background
|
||||
// * stable key order
|
||||
|
||||
inline Anope::string yyjson_mut_get_astr(yyjson_mut_val *val)
|
||||
inline Anope::string yyjson_get_astr(yyjson_val *val)
|
||||
{
|
||||
const auto *str = yyjson_mut_get_str(val);
|
||||
const auto *str = yyjson_get_str(val);
|
||||
return str ? str : "";
|
||||
}
|
||||
|
||||
inline void yyjson_mut_obj_upsert(yyjson_mut_doc *doc, yyjson_mut_val *obj, const char *key, yyjson_mut_val *val)
|
||||
{
|
||||
auto *oldval = yyjson_mut_obj_get(obj, key);
|
||||
if (oldval)
|
||||
yyjson_mut_obj_replace(obj, yyjson_mut_str(doc, key), val);
|
||||
else
|
||||
yyjson_mut_obj_add_val(doc, obj, key, val);
|
||||
}
|
||||
|
||||
class Data final
|
||||
: public Serialize::Data
|
||||
{
|
||||
@@ -48,37 +38,42 @@ public:
|
||||
Anope::map<std::stringstream> data;
|
||||
|
||||
// Used when writing data.
|
||||
Data() = default;
|
||||
Data(Serialize::Type *s_type, Serializable *obj)
|
||||
{
|
||||
if (obj->id)
|
||||
this->id = obj->id;
|
||||
s_type->Serialize(obj, *this);
|
||||
}
|
||||
|
||||
// Used when reading data.
|
||||
Data(yyjson_mut_val *elem)
|
||||
Data(yyjson_val *elem)
|
||||
{
|
||||
size_t idx, max;
|
||||
yyjson_mut_val *key, *value;
|
||||
yyjson_mut_obj_foreach(elem, idx, max, key, value)
|
||||
yyjson_val *key, *value;
|
||||
yyjson_obj_foreach(elem, idx, max, key, value)
|
||||
{
|
||||
if (yyjson_mut_get_type(key) != YYJSON_TYPE_STR)
|
||||
if (yyjson_get_type(key) != YYJSON_TYPE_STR)
|
||||
continue;
|
||||
|
||||
Anope::string akey(yyjson_mut_get_str(key));
|
||||
if (akey.equals_ci("id"))
|
||||
auto akey = yyjson_get_astr(key);
|
||||
if (akey.equals_ci("@id"))
|
||||
{
|
||||
this->id = yyjson_mut_get_uint(value);
|
||||
this->id = yyjson_get_uint(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (yyjson_mut_is_bool(value))
|
||||
data[akey] << yyjson_mut_get_bool(value);
|
||||
else if (yyjson_mut_is_int(value))
|
||||
data[akey] << yyjson_mut_get_int(value);
|
||||
else if (yyjson_mut_is_null(value))
|
||||
if (yyjson_is_bool(value))
|
||||
data[akey] << yyjson_get_bool(value);
|
||||
else if (yyjson_is_int(value))
|
||||
data[akey] << yyjson_get_int(value);
|
||||
else if (yyjson_is_null(value))
|
||||
data[akey];
|
||||
else if (yyjson_mut_is_real(value))
|
||||
data[akey] << yyjson_mut_get_real(value);
|
||||
else if (yyjson_mut_is_str(value))
|
||||
data[akey] << yyjson_mut_get_str(value);
|
||||
else if (yyjson_mut_is_uint(value))
|
||||
data[akey] << yyjson_mut_get_uint(value);
|
||||
else if (yyjson_is_real(value))
|
||||
data[akey] << yyjson_get_real(value);
|
||||
else if (yyjson_is_str(value))
|
||||
data[akey] << yyjson_get_astr(value);
|
||||
else if (yyjson_is_uint(value))
|
||||
data[akey] << yyjson_get_uint(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,16 +81,29 @@ public:
|
||||
{
|
||||
return data[key];
|
||||
}
|
||||
|
||||
size_t Hash() const override
|
||||
{
|
||||
size_t hash = 0;
|
||||
for (const auto &[_, value] : this->data)
|
||||
{
|
||||
auto valuestr = value.str();
|
||||
if (!valuestr.empty())
|
||||
hash ^= Anope::hash_cs()(valuestr);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
class DBJSON final
|
||||
: public Module
|
||||
{
|
||||
private:
|
||||
using DBPair = std::pair<yyjson_mut_doc *, yyjson_mut_val *>;
|
||||
// Multimap from serializable type to serializable data.
|
||||
using DBData = Anope::multimap<Data>;
|
||||
|
||||
// The databases which have already been loaded from disk.
|
||||
std::unordered_map<Module *, DBPair> databases;
|
||||
std::unordered_map<Module *, DBData> databases;
|
||||
|
||||
// Whether OnLoadDatabase has been called yet.
|
||||
bool loaded = false;
|
||||
@@ -201,55 +209,131 @@ private:
|
||||
CreateBackup(backupdir, dbpath, monthly_backups, "%Y-%m", "\?\?\?\?-\?\?");
|
||||
}
|
||||
|
||||
DBPair ReadDatabase(const Anope::string &dbname)
|
||||
void LoadType(Serialize::Type *s_type, DBData &data)
|
||||
{
|
||||
auto entries = data.equal_range(s_type->GetName());
|
||||
if (entries.first == entries.second)
|
||||
return;
|
||||
|
||||
for (auto it = entries.first; it != entries.second; ++it)
|
||||
s_type->Unserialize(nullptr, it->second);
|
||||
}
|
||||
|
||||
std::optional<DBData> ReadDatabase(const Anope::string &dbname)
|
||||
{
|
||||
yyjson_read_err errmsg;
|
||||
const auto flags = YYJSON_READ_ALLOW_TRAILING_COMMAS | YYJSON_READ_ALLOW_INVALID_UNICODE;
|
||||
auto *idoc = yyjson_read_file(dbname.c_str(), flags, nullptr, &errmsg);
|
||||
if (!idoc)
|
||||
auto *doc = yyjson_read_file(dbname.c_str(), flags, nullptr, &errmsg);
|
||||
if (!doc)
|
||||
{
|
||||
Log(this) << "Unable to read " << dbname << ": error #" << errmsg.code << ": " << errmsg.msg;
|
||||
return { nullptr, nullptr };
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// We operate on a mutable document because we need to write to it later.
|
||||
auto *doc = yyjson_doc_mut_copy(idoc, nullptr);
|
||||
yyjson_doc_free(idoc);
|
||||
|
||||
auto *root = yyjson_mut_doc_get_root(doc);
|
||||
if (!yyjson_mut_is_obj(root))
|
||||
auto *root = yyjson_doc_get_root(doc);
|
||||
if (!yyjson_is_obj(root))
|
||||
{
|
||||
Log(this) << "Unable to read " << dbname << ": root element is not an object";
|
||||
return { nullptr, nullptr };
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto version = yyjson_mut_get_uint(yyjson_mut_obj_get(root, "version"));
|
||||
auto version = yyjson_get_uint(yyjson_obj_get(root, "version"));
|
||||
if (version && version != ANOPE_DATABASE_VERSION)
|
||||
{
|
||||
Log(this) << "Refusing to load an unsupported database version: " << version;
|
||||
return { nullptr, nullptr };
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto generator = yyjson_mut_get_astr(yyjson_mut_obj_get(root, "generator"));
|
||||
auto updated = yyjson_mut_get_uint(yyjson_mut_obj_get(root, "updated"));
|
||||
auto generator = yyjson_get_astr(yyjson_obj_get(root, "generator"));
|
||||
auto updated = yyjson_get_uint(yyjson_obj_get(root, "updated"));
|
||||
Log(LOG_DEBUG) << "Database " << dbname << " was generated on " << Anope::strftime(updated) << " by " << generator;
|
||||
|
||||
auto *data = yyjson_mut_obj_get(root, "data");
|
||||
if (!data || !yyjson_mut_is_obj(data))
|
||||
auto *data = yyjson_obj_get(root, "data");
|
||||
if (!data || !yyjson_is_obj(data))
|
||||
{
|
||||
Log(this) << "Unable to read " << dbname << ": data element is missing or not an object";
|
||||
return { nullptr, nullptr };
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return { doc, data };
|
||||
DBData ret;
|
||||
|
||||
size_t idx, max;
|
||||
yyjson_val *key, *val;
|
||||
yyjson_obj_foreach(data, idx, max, key, val)
|
||||
{
|
||||
if (!yyjson_is_str(key))
|
||||
{
|
||||
Log(this) << "Unable to read part of " << dbname << ": key of data element #" << idx << " is not a string";
|
||||
continue;
|
||||
}
|
||||
|
||||
auto keystr = yyjson_get_astr(key);
|
||||
if (!yyjson_is_arr(val))
|
||||
{
|
||||
Log(this) << "Unable to read part of " << dbname << ": " << keystr << " value of data element #" << idx << " is not an array";
|
||||
continue;
|
||||
}
|
||||
|
||||
Log(LOG_DEBUG) << "Loading " << yyjson_arr_size(val) << " " << keystr << " records";
|
||||
|
||||
size_t idx, max;
|
||||
yyjson_val *elem;
|
||||
yyjson_arr_foreach(val, idx, max, elem)
|
||||
{
|
||||
Data ld(elem);
|
||||
ret.emplace(keystr, std::move(ld));
|
||||
}
|
||||
}
|
||||
|
||||
yyjson_doc_free(doc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void UpdateMetadata(yyjson_mut_doc *doc, yyjson_mut_val *obj)
|
||||
void SaveType(yyjson_mut_doc *doc, yyjson_mut_val *obj, const Anope::string &typestr, const Data &data)
|
||||
{
|
||||
const auto generator = "Anope " + Anope::Version();
|
||||
yyjson_mut_obj_upsert(doc, obj, "generator", yyjson_mut_strncpy(doc, generator.c_str(), generator.length()));
|
||||
yyjson_mut_obj_upsert(doc, obj, "version", yyjson_mut_uint(doc, ANOPE_DATABASE_VERSION));
|
||||
yyjson_mut_obj_upsert(doc, obj, "updated", yyjson_mut_int(doc, Anope::CurTime));
|
||||
auto *type = yyjson_mut_obj_getn(obj, typestr.c_str(), typestr.length());
|
||||
if (!type || !yyjson_mut_is_arr(type))
|
||||
{
|
||||
// We haven't seen this element before.
|
||||
type = yyjson_mut_arr(doc);
|
||||
yyjson_mut_obj_add_val(doc, obj, typestr.c_str(), type);
|
||||
}
|
||||
|
||||
auto *elem = yyjson_mut_obj(doc);
|
||||
if (data.id)
|
||||
yyjson_mut_obj_add_uint(doc, elem, "@id", data.id);
|
||||
|
||||
for (const auto &[key, value] : data.data)
|
||||
{
|
||||
yyjson_mut_val *v;
|
||||
switch (data.GetType(key))
|
||||
{
|
||||
case Serialize::DataType::BOOL:
|
||||
v = yyjson_mut_bool(doc, Anope::Convert<bool>(value.str(), false));
|
||||
break;
|
||||
case Serialize::DataType::FLOAT:
|
||||
v = yyjson_mut_real(doc, Anope::Convert<double>(value.str(), 0.0));
|
||||
break;
|
||||
case Serialize::DataType::INT:
|
||||
v = yyjson_mut_int(doc, Anope::Convert<int64_t>(value.str(), 0));
|
||||
break;
|
||||
case Serialize::DataType::TEXT:
|
||||
{
|
||||
auto str = value.str();
|
||||
v = str.empty() ? yyjson_mut_null(doc) : yyjson_mut_strncpy(doc, str.c_str(), str.length());
|
||||
break;
|
||||
}
|
||||
case Serialize::DataType::UINT:
|
||||
v = yyjson_mut_uint(doc, Anope::Convert<uint64_t>(value.str(), 0));
|
||||
break;
|
||||
}
|
||||
|
||||
auto *k = yyjson_mut_strncpy(doc, key.c_str(), key.length());
|
||||
yyjson_mut_obj_add(elem, k, v);
|
||||
}
|
||||
|
||||
yyjson_mut_arr_add_val(type, elem);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -262,136 +346,90 @@ public:
|
||||
{
|
||||
auto dbname = GetDatabaseFile(nullptr);
|
||||
|
||||
auto [doc, data] = ReadDatabase(dbname);
|
||||
if (!data)
|
||||
auto db = ReadDatabase(dbname);
|
||||
if (!db)
|
||||
return EVENT_STOP;
|
||||
|
||||
for (const auto &type : Serialize::Type::GetTypeOrder())
|
||||
{
|
||||
auto *s_type = Serialize::Type::Find(type);
|
||||
if (!s_type || !s_type->GetOwner())
|
||||
continue;
|
||||
|
||||
size_t idx, max;
|
||||
yyjson_mut_val *elem;
|
||||
yyjson_mut_arr_foreach(data, idx, max, elem)
|
||||
{
|
||||
Data ld(elem);
|
||||
s_type->Unserialize(nullptr, ld);
|
||||
}
|
||||
if (s_type && !s_type->GetOwner())
|
||||
LoadType(s_type, db.value());
|
||||
}
|
||||
|
||||
loaded = false;
|
||||
loaded = true;
|
||||
return EVENT_STOP;
|
||||
}
|
||||
|
||||
void OnSaveDatabase() override
|
||||
{
|
||||
std::set<Module *> updated;
|
||||
for (const auto &[_, s_type] : Serialize::Type::GetTypes())
|
||||
// Step 1: clear the old data.
|
||||
for (const auto &type : Serialize::Type::GetTypeOrder())
|
||||
{
|
||||
auto *s_type = Serialize::Type::Find(type);
|
||||
if (!s_type)
|
||||
continue; // Provider has been unloaded.
|
||||
|
||||
auto it = databases.find(s_type->GetOwner());
|
||||
if (it == databases.end())
|
||||
{
|
||||
auto *doc = yyjson_mut_doc_new(nullptr);
|
||||
|
||||
auto *root = yyjson_mut_obj(doc);
|
||||
yyjson_mut_doc_set_root(doc, root);
|
||||
|
||||
UpdateMetadata(doc, root);
|
||||
|
||||
auto *data = yyjson_mut_obj(doc);
|
||||
yyjson_mut_obj_add_val(doc, root, "data", data);
|
||||
|
||||
databases[s_type->GetOwner()] = { doc, data };
|
||||
databases.emplace(s_type->GetOwner(), DBData());
|
||||
continue; // We just need to create for this type.
|
||||
}
|
||||
else if (updated.find(s_type->GetOwner()) == updated.end())
|
||||
{
|
||||
auto *doc = it->second.first;
|
||||
auto *root = yyjson_mut_doc_get_root(doc);
|
||||
|
||||
UpdateMetadata(doc, root);
|
||||
updated.insert(s_type->GetOwner());
|
||||
}
|
||||
// As this type has been written before we need to clear the entries
|
||||
// from the previous writes so we can update it in the next loop. We
|
||||
// have to do it this way so we don't purge any entries for unloaded
|
||||
// modules.
|
||||
it->second.erase(s_type->GetName());
|
||||
}
|
||||
|
||||
std::set<Serialize::Type *> seen;
|
||||
// Step 2: store the new data.
|
||||
for (auto *item : Serializable::GetItems())
|
||||
{
|
||||
auto *s_type = item->GetSerializableType();
|
||||
if (!s_type)
|
||||
continue; // Provider has been unloaded.
|
||||
|
||||
// This should always be found because we create it in the previous step.
|
||||
auto it = databases.find(s_type->GetOwner());
|
||||
if (it == databases.end())
|
||||
continue; // Type has not been registered?
|
||||
|
||||
auto &[doc, data] = it->second;
|
||||
|
||||
// If the type object doesn't exist then create it. Otherwise, clear.
|
||||
// all of the previous objects stored in it.
|
||||
auto *type = yyjson_mut_obj_getn(data, s_type->GetName().c_str(), s_type->GetName().length());
|
||||
if (!type || yyjson_mut_get_type(type) != YYJSON_TYPE_ARR)
|
||||
{
|
||||
// We haven't seen this element before.
|
||||
type = yyjson_mut_arr(doc);
|
||||
yyjson_mut_obj_add_val(doc, data, s_type->GetName().c_str(), type);
|
||||
}
|
||||
else if (seen.find(s_type) == seen.end())
|
||||
{
|
||||
// We are reusing an existing element, clear it.
|
||||
yyjson_mut_arr_clear(type);
|
||||
seen.insert(s_type);
|
||||
}
|
||||
|
||||
auto *elem = yyjson_mut_arr_add_obj(doc, type);
|
||||
if (item->id)
|
||||
yyjson_mut_obj_add_uint(doc, elem, "id", item->id);
|
||||
|
||||
Data sd;
|
||||
s_type->Serialize(item, sd);
|
||||
for (const auto &[key, value] : sd.data)
|
||||
{
|
||||
yyjson_mut_val *v;
|
||||
switch (sd.GetType(key))
|
||||
{
|
||||
case Serialize::DataType::BOOL:
|
||||
v = yyjson_mut_bool(doc, Anope::Convert<bool>(value.str(), false));
|
||||
break;
|
||||
case Serialize::DataType::FLOAT:
|
||||
v = yyjson_mut_real(doc, Anope::Convert<double>(value.str(), 0.0));
|
||||
break;
|
||||
case Serialize::DataType::INT:
|
||||
v = yyjson_mut_int(doc, Anope::Convert<int64_t>(value.str(), 0));
|
||||
break;
|
||||
case Serialize::DataType::TEXT:
|
||||
{
|
||||
auto str = value.str();
|
||||
v = str.empty() ? yyjson_mut_null(doc) : yyjson_mut_strncpy(doc, str.c_str(), str.length());
|
||||
break;
|
||||
}
|
||||
case Serialize::DataType::UINT:
|
||||
v = yyjson_mut_uint(doc, Anope::Convert<uint64_t>(value.str(), 0));
|
||||
break;
|
||||
}
|
||||
|
||||
auto *k = yyjson_mut_strncpy(doc, key.c_str(), key.length());
|
||||
yyjson_mut_obj_add(elem, k, v);
|
||||
}
|
||||
if (it != databases.end())
|
||||
it->second.emplace(s_type->GetName(), Data(s_type, item));
|
||||
}
|
||||
|
||||
// Step 3: serialize to JSON.
|
||||
for (auto &[mod, database] : databases)
|
||||
{
|
||||
auto dbname = GetDatabaseFile(mod);
|
||||
BackupDatabase(dbname);
|
||||
|
||||
auto *doc = yyjson_mut_doc_new(nullptr);
|
||||
|
||||
auto *root = yyjson_mut_obj(doc);
|
||||
yyjson_mut_doc_set_root(doc, root);
|
||||
|
||||
const auto generator = "Anope " + Anope::Version() + " " + Anope::VersionBuildString();
|
||||
yyjson_mut_obj_add_strncpy(doc, root, "generator", generator.c_str(), generator.length());
|
||||
yyjson_mut_obj_add_uint(doc, root, "version", ANOPE_DATABASE_VERSION);
|
||||
yyjson_mut_obj_add_int(doc, root, "updated", Anope::CurTime);
|
||||
|
||||
auto *data = yyjson_mut_obj(doc);
|
||||
yyjson_mut_obj_add_val(doc, root, "data", data);
|
||||
|
||||
for (const auto &[name, items] : database)
|
||||
SaveType(doc, data, name, items);
|
||||
|
||||
Log(LOG_DEBUG) << "Writing " << dbname;
|
||||
|
||||
yyjson_write_err errmsg;
|
||||
const auto flags = YYJSON_WRITE_ALLOW_INVALID_UNICODE | YYJSON_WRITE_NEWLINE_AT_END | YYJSON_WRITE_PRETTY;
|
||||
if (!yyjson_mut_write_file(dbname.c_str(), database.first, flags, nullptr, &errmsg))
|
||||
if (!yyjson_mut_write_file(dbname.c_str(), doc, flags, nullptr, &errmsg))
|
||||
{
|
||||
Log(this) << "Unable to write " << dbname << ": error #" << errmsg.code << ": " << errmsg.msg;
|
||||
// TODO: exit??? retry???
|
||||
}
|
||||
|
||||
yyjson_mut_doc_free(doc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,21 +445,13 @@ public:
|
||||
const auto dbname = GetDatabaseFile(s_type->GetOwner());
|
||||
|
||||
auto db = ReadDatabase(dbname);
|
||||
if (!db.second)
|
||||
if (!db)
|
||||
return; // Not much we can do here.
|
||||
|
||||
it = databases.emplace(s_type->GetOwner(), db).first;
|
||||
it = databases.emplace(s_type->GetOwner(), std::move(db.value())).first;
|
||||
}
|
||||
|
||||
auto &[doc, data] = it->second;
|
||||
|
||||
size_t idx, max;
|
||||
yyjson_mut_val *elem;
|
||||
yyjson_mut_arr_foreach(data, idx, max, elem)
|
||||
{
|
||||
Data ld(elem);
|
||||
s_type->Unserialize(nullptr, ld);
|
||||
}
|
||||
LoadType(s_type, it->second);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+2
-2
@@ -638,7 +638,7 @@ public:
|
||||
if (!packet)
|
||||
return false;
|
||||
|
||||
Log(LOG_DEBUG_2) << "Resolver: Notifying slave " << packet->addr.addr();
|
||||
Log(LOG_DEBUG_2) << "Resolver: Notifying secondary " << packet->addr.addr();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -939,7 +939,7 @@ public:
|
||||
|
||||
void Notify(const Anope::string &zone) override
|
||||
{
|
||||
/* notify slaves of the update */
|
||||
/* notify secondaries of the update */
|
||||
for (const auto &[ip, port] : notify)
|
||||
{
|
||||
sockaddrs addr;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "module.h"
|
||||
#include "modules/ssl.h"
|
||||
|
||||
#define OPENSSL_API_COMPAT 0x10100000L
|
||||
#define OPENSSL_API_COMPAT 0x10101000L
|
||||
#define OPENSSL_NO_DEPRECATED
|
||||
|
||||
#include <openssl/bio.h>
|
||||
@@ -126,7 +126,9 @@ public:
|
||||
SSL_CTX_set_session_id_context(client_ctx, reinterpret_cast<const unsigned char *>(context_name.c_str()), context_name.length());
|
||||
SSL_CTX_set_session_id_context(server_ctx, reinterpret_cast<const unsigned char *>(context_name.c_str()), context_name.length());
|
||||
|
||||
#ifdef OPENSSL_VERSION_STR
|
||||
Log(this) << "Module was compiled against OpenSSL version " << OPENSSL_VERSION_STR << " and is running against version " << OpenSSL_version(OPENSSL_VERSION_STRING);
|
||||
#endif
|
||||
}
|
||||
|
||||
~SSLModule()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -188,7 +188,7 @@ public:
|
||||
source.permission = info.permission;
|
||||
|
||||
AccessGroup ag = c->ci->AccessFor(u);
|
||||
bool has_fantasy = ag.HasPriv("FANTASY") || source.HasPriv("botserv/fantasy");
|
||||
bool has_fantasy = !info.require_privilege || ag.HasPriv("FANTASY") || source.HasPriv("botserv/fantasy");
|
||||
|
||||
EventReturn MOD_RESULT;
|
||||
if (has_fantasy)
|
||||
|
||||
+7
-4
@@ -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
|
||||
|
||||
@@ -16,11 +16,11 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
EventReturn OnChannelModeSet(Channel *c, MessageSource &, ChannelMode *mode, const Anope::string ¶m) 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");
|
||||
|
||||
@@ -57,7 +57,7 @@ class CommandHSDelAll final
|
||||
public:
|
||||
CommandHSDelAll(Module *creator) : Command(creator, "hostserv/delall", 1, 1)
|
||||
{
|
||||
this->SetDesc(_("Deletes the vhost for all nicks in a group"));
|
||||
this->SetDesc(_("Deletes the vhost for all nicks in an account"));
|
||||
this->SetSyntax(_("\037nick\037"));
|
||||
}
|
||||
|
||||
@@ -80,8 +80,8 @@ public:
|
||||
na = alias;
|
||||
na->RemoveVHost();
|
||||
}
|
||||
Log(LOG_ADMIN, source, this) << "for all nicks in group " << nc->display;
|
||||
source.Reply(_("VHosts for group \002%s\002 have been removed."), nc->display.c_str());
|
||||
Log(LOG_ADMIN, source, this) << "for all nicks in account " << nc->display;
|
||||
source.Reply(_("VHosts for account \002%s\002 have been removed."), nc->display.c_str());
|
||||
}
|
||||
else
|
||||
source.Reply(NICK_X_NOT_REGISTERED, nick.c_str());
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
{
|
||||
this->SendSyntax(source);
|
||||
source.Reply(" ");
|
||||
source.Reply(_("Deletes the vhost for all nicks in the same group as that of the given nick."));
|
||||
source.Reply(_("Deletes the vhost for all nicks in the same account as that of the given nick."));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
|
||||
CommandHSGroup(Module *creator) : Command(creator, "hostserv/group", 0, 0)
|
||||
{
|
||||
this->SetDesc(_("Syncs the vhost for all nicks in a group"));
|
||||
this->SetDesc(_("Syncs the vhost for all nicks in an account"));
|
||||
}
|
||||
|
||||
void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) override
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
if (na && source.GetAccount() == na->nc && na->HasVHost())
|
||||
{
|
||||
this->Sync(na);
|
||||
source.Reply(_("All vhosts in the group \002%s\002 have been set to \002%s\002."),
|
||||
source.Reply(_("All vhosts for the account \002%s\002 have been set to \002%s\002."),
|
||||
source.nc->display.c_str(), na->GetVHostMask().c_str());
|
||||
}
|
||||
else
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
));
|
||||
@@ -122,7 +122,7 @@ class CommandHSSetAll final
|
||||
public:
|
||||
CommandHSSetAll(Module *creator) : Command(creator, "hostserv/setall", 2, 2)
|
||||
{
|
||||
this->SetDesc(_("Set the vhost for all nicks in a group"));
|
||||
this->SetDesc(_("Set the vhost for all nicks in an account"));
|
||||
this->SetSyntax(_("\037nick\037 \037hostmask\037"));
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ public:
|
||||
na->SetVHost(user, host, source.GetNick());
|
||||
this->Sync(na);
|
||||
FOREACH_MOD(OnSetVHost, (na));
|
||||
source.Reply(_("VHost for group \002%s\002 set to \002%s\002."), nick.c_str(), na->GetVHostMask().c_str());
|
||||
source.Reply(_("VHost for account \002%s\002 set to \002%s\002."), nick.c_str(), na->GetVHostMask().c_str());
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
|
||||
@@ -201,13 +201,13 @@ public:
|
||||
this->SendSyntax(source);
|
||||
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 "
|
||||
"Sets the vhost for all nicks in the same account 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."
|
||||
"added to the account after this command was used."
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
+27
-27
@@ -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)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
build_subdir(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@@ -1,325 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (C) 2013-2025 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
#include "irc2sql.h"
|
||||
|
||||
void IRC2SQL::OnShutdown()
|
||||
{
|
||||
// TODO: test if we really have to use blocking query here
|
||||
// (sometimes mysql get unloaded before the other thread executed all queries)
|
||||
if (this->sql)
|
||||
SQL::Result r = this->sql->RunQuery(SQL::Query("CALL " + prefix + "OnShutdown()"));
|
||||
quitting = true;
|
||||
}
|
||||
|
||||
void IRC2SQL::OnReload(Configuration::Conf &conf)
|
||||
{
|
||||
const auto &block = Config->GetModule(this);
|
||||
prefix = block.Get<const Anope::string>("prefix", "anope_");
|
||||
GeoIPDB = block.Get<const Anope::string>("geoip_database");
|
||||
ctcpuser = block.Get<bool>("ctcpuser", "no");
|
||||
ctcpeob = block.Get<bool>("ctcpeob", "yes");
|
||||
Anope::string engine = block.Get<const Anope::string>("engine");
|
||||
this->sql = ServiceReference<SQL::Provider>("SQL::Provider", engine);
|
||||
if (sql)
|
||||
this->CheckTables();
|
||||
else
|
||||
Log() << "IRC2SQL: no database connection to " << engine;
|
||||
|
||||
const Anope::string &snick = block.Get<const Anope::string>("client");
|
||||
if (snick.empty())
|
||||
throw ConfigException(Module::name + ": <client> must be defined");
|
||||
StatServ = BotInfo::Find(snick, true);
|
||||
if (!StatServ)
|
||||
throw ConfigException(Module::name + ": no bot named " + snick);
|
||||
|
||||
if (firstrun)
|
||||
{
|
||||
firstrun = false;
|
||||
|
||||
for (Anope::map<Server *>::const_iterator it = Servers::ByName.begin(); it != Servers::ByName.end(); ++it)
|
||||
{
|
||||
this->OnNewServer(it->second);
|
||||
}
|
||||
|
||||
for (const auto &[_, c] : ChannelList)
|
||||
{
|
||||
this->OnChannelCreate(c);
|
||||
}
|
||||
|
||||
for (const auto &[_, u] : UserListByNick)
|
||||
{
|
||||
bool exempt = false;
|
||||
this->OnUserConnect(u, exempt);
|
||||
for (const auto &[_, uc] : u->chans)
|
||||
{
|
||||
this->OnJoinChannel(u, uc->chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void IRC2SQL::OnNewServer(Server *server)
|
||||
{
|
||||
query = "INSERT DELAYED INTO `" + prefix + "server` (name, hops, comment, link_time, online, ulined) "
|
||||
"VALUES (@name@, @hops@, @comment@, now(), 'Y', @ulined@) "
|
||||
"ON DUPLICATE KEY UPDATE name=VALUES(name), hops=VALUES(hops), comment=VALUES(comment), "
|
||||
"link_time=VALUES(link_time), online=VALUES(online), ulined=VALUES(ulined)";
|
||||
query.SetValue("name", server->GetName());
|
||||
query.SetValue("hops", server->GetHops());
|
||||
query.SetValue("comment", server->GetDescription());
|
||||
query.SetValue("ulined", server->IsULined() ? "Y" : "N");
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnServerQuit(Server *server)
|
||||
{
|
||||
if (quitting)
|
||||
return;
|
||||
|
||||
query = "CALL " + prefix + "ServerQuit(@name@)";
|
||||
query.SetValue("name", server->GetName());
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnUserConnect(User *u, bool &exempt)
|
||||
{
|
||||
if (!introduced_myself)
|
||||
{
|
||||
this->OnNewServer(Me);
|
||||
introduced_myself = true;
|
||||
}
|
||||
|
||||
query = "CALL " + prefix + "UserConnect(@nick@,@host@,@vhost@,@chost@,@realname@,@ip@,@ident@,@vident@,"
|
||||
"@account@,@secure@,@fingerprint@,@signon@,@server@,@uuid@,@modes@,@oper@)";
|
||||
query.SetValue("nick", u->nick);
|
||||
query.SetValue("host", u->host);
|
||||
query.SetValue("vhost", u->vhost);
|
||||
query.SetValue("chost", u->chost);
|
||||
query.SetValue("realname", u->realname);
|
||||
query.SetValue("ip", u->ip.addr());
|
||||
query.SetValue("ident", u->GetIdent());
|
||||
query.SetValue("vident", u->GetVIdent());
|
||||
query.SetValue("secure", u->IsSecurelyConnected() ? "Y" : "N");
|
||||
query.SetValue("account", u->IsIdentified() ? u->Account()->display : "");
|
||||
query.SetValue("fingerprint", u->fingerprint);
|
||||
query.SetValue("signon", u->signon);
|
||||
query.SetValue("server", u->server->GetName());
|
||||
query.SetValue("uuid", u->GetUID());
|
||||
query.SetValue("modes", u->GetModes());
|
||||
query.SetValue("oper", u->HasMode("OPER") ? "Y" : "N");
|
||||
this->RunQuery(query);
|
||||
|
||||
if (ctcpuser && (Me->IsSynced() || ctcpeob) && u->server != Me)
|
||||
IRCD->SendPrivmsg(StatServ, u->GetUID(), Anope::FormatCTCP("VERSION"));
|
||||
|
||||
}
|
||||
|
||||
void IRC2SQL::OnUserQuit(User *u, const Anope::string &msg)
|
||||
{
|
||||
if (quitting || u->server->IsQuitting())
|
||||
return;
|
||||
|
||||
query = "CALL " + prefix + "UserQuit(@nick@)";
|
||||
query.SetValue("nick", u->nick);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnUserNickChange(User *u, const Anope::string &oldnick)
|
||||
{
|
||||
query = "UPDATE `" + prefix + "user` SET nick=@newnick@ WHERE nick=@oldnick@";
|
||||
query.SetValue("newnick", u->nick);
|
||||
query.SetValue("oldnick", oldnick);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnUserAway(User *u, const Anope::string &message)
|
||||
{
|
||||
query = "UPDATE `" + prefix + "user` SET away=@away@, awaymsg=@awaymsg@ WHERE nick=@nick@";
|
||||
query.SetValue("away", (!message.empty()) ? "Y" : "N");
|
||||
query.SetValue("awaymsg", message);
|
||||
query.SetValue("nick", u->nick);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnFingerprint(User *u)
|
||||
{
|
||||
query = "UPDATE `" + prefix + "user` SET secure=@secure@, fingerprint=@fingerprint@ WHERE nick=@nick@";
|
||||
query.SetValue("secure", u->IsSecurelyConnected() ? "Y" : "N");
|
||||
query.SetValue("fingerprint", u->fingerprint);
|
||||
query.SetValue("nick", u->nick);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnUserModeSet(const MessageSource &setter, User *u, const Anope::string &mname)
|
||||
{
|
||||
query = "UPDATE `" + prefix + "user` SET modes=@modes@, oper=@oper@ WHERE nick=@nick@";
|
||||
query.SetValue("nick", u->nick);
|
||||
query.SetValue("modes", u->GetModes());
|
||||
query.SetValue("oper", u->HasMode("OPER") ? "Y" : "N");
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnUserModeUnset(const MessageSource &setter, User *u, const Anope::string &mname)
|
||||
{
|
||||
this->OnUserModeSet(setter, u, mname);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnUserLogin(User *u)
|
||||
{
|
||||
query = "UPDATE `" + prefix + "user` SET account=@account@ WHERE nick=@nick@";
|
||||
query.SetValue("nick", u->nick);
|
||||
query.SetValue("account", u->IsIdentified() ? u->Account()->display : "");
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnNickLogout(User *u)
|
||||
{
|
||||
this->OnUserLogin(u);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnSetDisplayedHost(User *u)
|
||||
{
|
||||
query = "UPDATE `" + prefix + "user` "
|
||||
"SET vhost=@vhost@ "
|
||||
"WHERE nick=@nick@";
|
||||
query.SetValue("vhost", u->GetDisplayedHost());
|
||||
query.SetValue("nick", u->nick);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnChannelCreate(Channel *c)
|
||||
{
|
||||
query = "INSERT INTO `" + prefix + "chan` (channel, topic, topicauthor, topictime, modes) "
|
||||
"VALUES (@channel@,@topic@,@topicauthor@,@topictime@,@modes@) "
|
||||
"ON DUPLICATE KEY UPDATE channel=VALUES(channel), topic=VALUES(topic),"
|
||||
"topicauthor=VALUES(topicauthor), topictime=VALUES(topictime), modes=VALUES(modes)";
|
||||
query.SetValue("channel", c->name);
|
||||
query.SetValue("topic", c->topic);
|
||||
query.SetValue("topicauthor", c->topic_setter);
|
||||
if (c->topic_ts > 0)
|
||||
query.SetValue("topictime", c->topic_ts);
|
||||
else
|
||||
query.SetValue("topictime", "NULL", false);
|
||||
query.SetValue("modes", c->GetModes(true,true));
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnChannelDelete(Channel *c)
|
||||
{
|
||||
query = "DELETE FROM `" + prefix + "chan` WHERE channel=@channel@";
|
||||
query.SetValue("channel", c->name);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnJoinChannel(User *u, Channel *c)
|
||||
{
|
||||
Anope::string modes;
|
||||
ChanUserContainer *cu = u->FindChannel(c);
|
||||
if (cu)
|
||||
modes = cu->status.Modes();
|
||||
|
||||
query = "CALL " + prefix + "JoinUser(@nick@,@channel@,@modes@)";
|
||||
query.SetValue("nick", u->nick);
|
||||
query.SetValue("channel", c->name);
|
||||
query.SetValue("modes", modes);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
EventReturn IRC2SQL::OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m)
|
||||
{
|
||||
if (mode->type == MODE_STATUS)
|
||||
{
|
||||
User *u = User::Find(param);
|
||||
if (u == NULL)
|
||||
return EVENT_CONTINUE;
|
||||
|
||||
ChanUserContainer *cc = u->FindChannel(c);
|
||||
if (cc == NULL)
|
||||
return EVENT_CONTINUE;
|
||||
|
||||
query = "UPDATE `" + prefix + "user` AS u, `" + prefix + "ison` AS i, `" + prefix + "chan` AS c"
|
||||
" SET i.modes=@modes@"
|
||||
" WHERE u.nick=@nick@ AND c.channel=@channel@"
|
||||
" AND u.nickid = i.nickid AND c.chanid = i.chanid";
|
||||
query.SetValue("nick", u->nick);
|
||||
query.SetValue("modes", cc->status.Modes());
|
||||
query.SetValue("channel", c->name);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = "UPDATE `" + prefix + "chan` SET modes=@modes@ WHERE channel=@channel@";
|
||||
query.SetValue("channel", c->name);
|
||||
query.SetValue("modes", c->GetModes(true,true));
|
||||
this->RunQuery(query);
|
||||
}
|
||||
return EVENT_CONTINUE;
|
||||
}
|
||||
|
||||
EventReturn IRC2SQL::OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m)
|
||||
{
|
||||
this->OnChannelModeSet(c, setter, mode, param);
|
||||
return EVENT_CONTINUE;
|
||||
}
|
||||
|
||||
void IRC2SQL::OnLeaveChannel(User *u, Channel *c)
|
||||
{
|
||||
if (quitting)
|
||||
return;
|
||||
/*
|
||||
* user is quitting, we already received a OnUserQuit()
|
||||
* at this point the user is already removed from SQL and all channels
|
||||
*/
|
||||
if (u->Quitting())
|
||||
return;
|
||||
query = "CALL " + prefix + "PartUser(@nick@,@channel@)";
|
||||
query.SetValue("nick", u->nick);
|
||||
query.SetValue("channel", c->name);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnTopicUpdated(User *source, Channel *c, const Anope::string &user, const Anope::string &topic)
|
||||
{
|
||||
query = "UPDATE `" + prefix + "chan` "
|
||||
"SET topic=@topic@, topicauthor=@author@, topictime=FROM_UNIXTIME(@time@) "
|
||||
"WHERE channel=@channel@";
|
||||
query.SetValue("topic", c->topic);
|
||||
query.SetValue("author", c->topic_setter);
|
||||
query.SetValue("time", c->topic_ts);
|
||||
query.SetValue("channel", c->name);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
void IRC2SQL::OnBotNotice(User *u, BotInfo *bi, Anope::string &message, const Anope::map<Anope::string> &tags)
|
||||
{
|
||||
if (bi != StatServ)
|
||||
return;
|
||||
|
||||
Anope::string ctcpname, ctcpbody;
|
||||
if (!Anope::ParseCTCP(message, ctcpname, ctcpbody) || ctcpname != "VERSION")
|
||||
return;
|
||||
|
||||
if (u->HasExt("CTCPVERSION"))
|
||||
return;
|
||||
|
||||
u->Extend<bool>("CTCPVERSION");
|
||||
auto versionstr = Anope::NormalizeBuffer(ctcpbody);
|
||||
if (versionstr.empty())
|
||||
return;
|
||||
|
||||
query = "UPDATE `" + prefix + "user` "
|
||||
"SET version=@version@ "
|
||||
"WHERE nick=@nick@";
|
||||
query.SetValue("version", versionstr);
|
||||
query.SetValue("nick", u->nick);
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
MODULE_INIT(IRC2SQL)
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (C) 2013-2025 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/sql.h"
|
||||
|
||||
class MySQLInterface final
|
||||
: public SQL::Interface
|
||||
{
|
||||
public:
|
||||
MySQLInterface(Module *o) : SQL::Interface(o) { }
|
||||
|
||||
void OnResult(const SQL::Result &r) override
|
||||
{
|
||||
}
|
||||
|
||||
void OnError(const SQL::Result &r) override
|
||||
{
|
||||
if (!r.GetQuery().query.empty())
|
||||
Log(LOG_DEBUG) << "irc2sql: Error executing query " << r.finished_query << ": " << r.GetError();
|
||||
else
|
||||
Log(LOG_DEBUG) << "irc2sql: Error executing query: " << r.GetError();
|
||||
}
|
||||
};
|
||||
|
||||
class IRC2SQL final
|
||||
: public Module
|
||||
{
|
||||
ServiceReference<SQL::Provider> sql;
|
||||
MySQLInterface sqlinterface;
|
||||
SQL::Query query;
|
||||
std::vector<Anope::string> TableList, ProcedureList, EventList;
|
||||
Anope::string prefix, GeoIPDB;
|
||||
bool quitting, introduced_myself, ctcpuser, ctcpeob, firstrun;
|
||||
BotInfo *StatServ;
|
||||
PrimitiveExtensibleItem<bool> versionreply;
|
||||
|
||||
void RunQuery(const SQL::Query &q);
|
||||
void GetTables();
|
||||
|
||||
bool HasTable(const Anope::string &table);
|
||||
bool HasProcedure(const Anope::string &table);
|
||||
bool HasEvent(const Anope::string &table);
|
||||
|
||||
void CheckTables();
|
||||
|
||||
public:
|
||||
IRC2SQL(const Anope::string &modname, const Anope::string &creator) :
|
||||
Module(modname, creator, EXTRA | VENDOR), sql("", ""), sqlinterface(this), versionreply(this, "CTCPVERSION")
|
||||
{
|
||||
firstrun = true;
|
||||
quitting = false;
|
||||
introduced_myself = false;
|
||||
}
|
||||
|
||||
void OnShutdown() override;
|
||||
void OnReload(Configuration::Conf &config) override;
|
||||
void OnNewServer(Server *server) override;
|
||||
void OnServerQuit(Server *server) override;
|
||||
void OnUserConnect(User *u, bool &exempt) override;
|
||||
void OnUserQuit(User *u, const Anope::string &msg) override;
|
||||
void OnUserNickChange(User *u, const Anope::string &oldnick) override;
|
||||
void OnUserAway(User *u, const Anope::string &message) override;
|
||||
void OnFingerprint(User *u) override;
|
||||
void OnUserModeSet(const MessageSource &setter, User *u, const Anope::string &mname) override;
|
||||
void OnUserModeUnset(const MessageSource &setter, User *u, const Anope::string &mname) override;
|
||||
void OnUserLogin(User *u) override;
|
||||
void OnNickLogout(User *u) override;
|
||||
void OnSetDisplayedHost(User *u) override;
|
||||
|
||||
void OnChannelCreate(Channel *c) override;
|
||||
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 ¶m) override;
|
||||
EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) override;
|
||||
|
||||
void OnTopicUpdated(User *source, Channel *c, const Anope::string &user, const Anope::string &topic) override;
|
||||
|
||||
void OnBotNotice(User *u, BotInfo *bi, Anope::string &message, const Anope::map<Anope::string> &tags) override;
|
||||
};
|
||||
@@ -1,343 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (C) 2013-2025 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
#include "irc2sql.h"
|
||||
|
||||
void IRC2SQL::CheckTables()
|
||||
{
|
||||
Anope::string geoquery("");
|
||||
|
||||
if (firstrun)
|
||||
{
|
||||
/*
|
||||
* reset some tables to make sure they are really empty
|
||||
*/
|
||||
this->sql->RunQuery("TRUNCATE TABLE " + prefix + "user");
|
||||
this->sql->RunQuery("TRUNCATE TABLE " + prefix + "chan");
|
||||
this->sql->RunQuery("TRUNCATE TABLE " + prefix + "ison");
|
||||
this->sql->RunQuery("UPDATE `" + prefix + "server` SET currentusers=0, online='N'");
|
||||
}
|
||||
|
||||
this->GetTables();
|
||||
|
||||
if (GeoIPDB.equals_ci("country"))
|
||||
{
|
||||
if (!this->HasTable(prefix + "geoip_country"))
|
||||
{
|
||||
query = "CREATE TABLE `" + prefix + "geoip_country` ("
|
||||
"`start` INT UNSIGNED NOT NULL,"
|
||||
"`end` INT UNSIGNED NOT NULL,"
|
||||
"`countrycode` varchar(2),"
|
||||
"`countryname` varchar(50),"
|
||||
"PRIMARY KEY `end` (`end`),"
|
||||
"KEY `start` (`start`)"
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
}
|
||||
else if (GeoIPDB.equals_ci("city"))
|
||||
{
|
||||
if (!this->HasTable(prefix + "geoip_city_blocks"))
|
||||
{
|
||||
query = "CREATE TABLE `" + prefix + "geoip_city_blocks` ("
|
||||
"`start` INT UNSIGNED NOT NULL,"
|
||||
"`end` INT UNSIGNED NOT NULL,"
|
||||
"`locId` INT UNSIGNED NOT NULL,"
|
||||
"PRIMARY KEY `end` (`end`),"
|
||||
"KEY `start` (`start`)"
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
if (!this->HasTable(prefix + "geoip_city_location"))
|
||||
{
|
||||
query = "CREATE TABLE `" + prefix + "geoip_city_location` ("
|
||||
"`locId` INT UNSIGNED NOT NULL,"
|
||||
"`country` CHAR(2) NOT NULL,"
|
||||
"`region` CHAR(2) NOT NULL,"
|
||||
"`city` VARCHAR(50),"
|
||||
"`latitude` FLOAT,"
|
||||
"`longitude` FLOAT,"
|
||||
"`areaCode` INT,"
|
||||
"PRIMARY KEY (`locId`)"
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
if (!this->HasTable(prefix + "geoip_city_region"))
|
||||
{ query = "CREATE TABLE `" + prefix + "geoip_city_region` ("
|
||||
"`country` CHAR(2) NOT NULL,"
|
||||
"`region` CHAR(2) NOT NULL,"
|
||||
"`regionname` VARCHAR(100) NOT NULL,"
|
||||
"PRIMARY KEY (`country`,`region`)"
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
}
|
||||
if (!this->HasTable(prefix + "server"))
|
||||
{
|
||||
query = "CREATE TABLE `" + prefix + "server` ("
|
||||
"`id` int UNSIGNED NOT NULL AUTO_INCREMENT,"
|
||||
"`name` varchar(64) NOT NULL,"
|
||||
"`hops` tinyint NOT NULL,"
|
||||
"`comment` varchar(255) NOT NULL,"
|
||||
"`link_time` datetime DEFAULT NULL,"
|
||||
"`split_time` datetime DEFAULT NULL,"
|
||||
"`version` varchar(127) DEFAULT NULL,"
|
||||
"`currentusers` int DEFAULT 0,"
|
||||
"`online` enum('Y','N') NOT NULL DEFAULT 'Y',"
|
||||
"`ulined` enum('Y','N') NOT NULL DEFAULT 'N',"
|
||||
"PRIMARY KEY (`id`),"
|
||||
"UNIQUE KEY `name` (`name`)"
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
if (!this->HasTable(prefix + "chan"))
|
||||
{
|
||||
query = "CREATE TABLE `" + prefix + "chan` ("
|
||||
"`chanid` int UNSIGNED NOT NULL AUTO_INCREMENT,"
|
||||
"`channel` varchar(255) NOT NULL,"
|
||||
"`topic` varchar(512) DEFAULT NULL,"
|
||||
"`topicauthor` varchar(255) DEFAULT NULL,"
|
||||
"`topictime` datetime DEFAULT NULL,"
|
||||
"`modes` varchar(512) DEFAULT NULL,"
|
||||
"PRIMARY KEY (`chanid`),"
|
||||
"UNIQUE KEY `channel`(`channel`)"
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
if (!this->HasTable(prefix + "user"))
|
||||
{
|
||||
query = "CREATE TABLE `" + prefix + "user` ("
|
||||
"`nickid` int UNSIGNED NOT NULL AUTO_INCREMENT,"
|
||||
"`nick` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`host` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`vhost` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`chost` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`realname` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`ip` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`ident` varchar(32) NOT NULL DEFAULT '',"
|
||||
"`vident` varchar(32) NOT NULL DEFAULT '',"
|
||||
"`modes` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`account` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`secure` enum('Y','N') NOT NULL DEFAULT 'N',"
|
||||
"`fingerprint` varchar(128) NOT NULL DEFAULT '',"
|
||||
"`signon` datetime DEFAULT NULL,"
|
||||
"`server` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`servid` int UNSIGNED NOT NULL DEFAULT '0',"
|
||||
"`uuid` varchar(32) NOT NULL DEFAULT '',"
|
||||
"`oper` enum('Y','N') NOT NULL DEFAULT 'N',"
|
||||
"`away` enum('Y','N') NOT NULL DEFAULT 'N',"
|
||||
"`awaymsg` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`version` varchar(255) NOT NULL DEFAULT '',"
|
||||
"`geocode` varchar(16) NOT NULL DEFAULT '',"
|
||||
"`geocountry` varchar(64) NOT NULL DEFAULT '',"
|
||||
"`georegion` varchar(100) NOT NULL DEFAULT '',"
|
||||
"`geocity` varchar(128) NOT NULL DEFAULT '',"
|
||||
"`locId` INT UNSIGNED,"
|
||||
"PRIMARY KEY (`nickid`),"
|
||||
"UNIQUE KEY `nick` (`nick`),"
|
||||
"KEY `servid` (`servid`)"
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
if (!this->HasTable(prefix + "ison"))
|
||||
{
|
||||
query = "CREATE TABLE `" + prefix + "ison` ("
|
||||
"`nickid` int unsigned NOT NULL default '0',"
|
||||
"`chanid` int unsigned NOT NULL default '0',"
|
||||
"`modes` varchar(255) NOT NULL default '',"
|
||||
"PRIMARY KEY (`nickid`,`chanid`),"
|
||||
"KEY `modes` (`modes`)"
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
if (!this->HasTable(prefix + "maxusers"))
|
||||
{
|
||||
query = "CREATE TABLE `" + prefix + "maxusers` ("
|
||||
"`name` VARCHAR(255) NOT NULL,"
|
||||
"`maxusers` int NOT NULL,"
|
||||
"`maxtime` DATETIME NOT NULL,"
|
||||
"`lastused` DATETIME NOT NULL,"
|
||||
"UNIQUE KEY `name` (`name`)"
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
if (this->HasProcedure(prefix + "UserConnect"))
|
||||
this->RunQuery(SQL::Query("DROP PROCEDURE " + prefix + "UserConnect"));
|
||||
|
||||
if (GeoIPDB.equals_ci("country"))
|
||||
geoquery = "UPDATE `" + prefix + "user` AS u "
|
||||
"JOIN ( SELECT `countrycode`, `countryname` "
|
||||
"FROM `" + prefix + "geoip_country` "
|
||||
"WHERE INET_ATON(ip_) <= `end` "
|
||||
"AND `start` <= INET_ATON(ip_) "
|
||||
"ORDER BY `end` ASC LIMIT 1 ) as c "
|
||||
"SET u.geocode = c.countrycode, u.geocountry = c.countryname "
|
||||
"WHERE u.nick = nick_; ";
|
||||
else if (GeoIPDB.equals_ci("city"))
|
||||
geoquery = "UPDATE `" + prefix + "user` as u "
|
||||
"JOIN ( SELECT * FROM `" + prefix + "geoip_city_location` "
|
||||
"WHERE `locID` = ( SELECT `locID` "
|
||||
"FROM `" + prefix + "geoip_city_blocks` "
|
||||
"WHERE INET_ATON(ip_) <= `end` "
|
||||
"AND `start` <= INET_ATON(ip_) "
|
||||
"ORDER BY `end` ASC LIMIT 1 ) "
|
||||
") as l "
|
||||
"SET u.geocode = l.country, "
|
||||
"u.geocity = l.city, "
|
||||
"u.locID = l.locID, "
|
||||
"u.georegion = ( SELECT `regionname` "
|
||||
"FROM `" + prefix + "geoip_city_region` "
|
||||
"WHERE `country` = l.country "
|
||||
"AND `region` = l.region )"
|
||||
"WHERE u.nick = nick_;";
|
||||
|
||||
query = "CREATE PROCEDURE `" + prefix + "UserConnect`"
|
||||
"(nick_ varchar(255), host_ varchar(255), vhost_ varchar(255), "
|
||||
"chost_ varchar(255), realname_ varchar(255), ip_ varchar(255), "
|
||||
"ident_ varchar(255), vident_ varchar(255), account_ varchar(255), "
|
||||
"secure_ enum('Y','N'), fingerprint_ varchar(255), signon_ int, "
|
||||
"server_ varchar(255), uuid_ varchar(32), modes_ varchar(255), "
|
||||
"oper_ enum('Y','N')) "
|
||||
"BEGIN "
|
||||
"DECLARE cur int;"
|
||||
"DECLARE max int;"
|
||||
"INSERT INTO `" + prefix + "user` "
|
||||
"(nick, host, vhost, chost, realname, ip, ident, vident, account, "
|
||||
"secure, fingerprint, signon, server, uuid, modes, oper) "
|
||||
"VALUES (nick_, host_, vhost_, chost_, realname_, ip_, ident_, vident_, "
|
||||
"account_, secure_, fingerprint_, FROM_UNIXTIME(signon_), server_, "
|
||||
"uuid_, modes_, oper_) "
|
||||
"ON DUPLICATE KEY UPDATE host=VALUES(host), vhost=VALUES(vhost), "
|
||||
"chost=VALUES(chost), realname=VALUES(realname), ip=VALUES(ip), "
|
||||
"ident=VALUES(ident), vident=VALUES(vident), account=VALUES(account), "
|
||||
"secure=VALUES(secure), fingerprint=VALUES(fingerprint), signon=VALUES(signon), "
|
||||
"server=VALUES(server), uuid=VALUES(uuid), modes=VALUES(modes), "
|
||||
"oper=VALUES(oper);"
|
||||
"UPDATE `" + prefix + "user` as `u`, `" + prefix + "server` as `s`"
|
||||
"SET u.servid = s.id, "
|
||||
"s.currentusers = s.currentusers + 1 "
|
||||
"WHERE s.name = server_ AND u.nick = nick_;"
|
||||
"SELECT `currentusers` INTO cur FROM `" + prefix + "server` WHERE name=server_;"
|
||||
"SELECT `maxusers` INTO max FROM `" + prefix + "maxusers` WHERE name=server_;"
|
||||
"IF found_rows() AND cur <= max THEN "
|
||||
"UPDATE `" + prefix + "maxusers` SET lastused=now() WHERE name=server_;"
|
||||
"ELSE "
|
||||
"INSERT INTO `" + prefix + "maxusers` (name, maxusers, maxtime, lastused) "
|
||||
"VALUES ( server_, cur, now(), now() ) "
|
||||
"ON DUPLICATE KEY UPDATE "
|
||||
"name=VALUES(name), maxusers=VALUES(maxusers),"
|
||||
"maxtime=VALUES(maxtime), lastused=VALUES(lastused);"
|
||||
"END IF;"
|
||||
+ geoquery +
|
||||
"END";
|
||||
this->RunQuery(query);
|
||||
|
||||
if (this->HasProcedure(prefix + "ServerQuit"))
|
||||
this->RunQuery(SQL::Query("DROP PROCEDURE " + prefix + "ServerQuit"));
|
||||
query = "CREATE PROCEDURE " + prefix + "ServerQuit(sname_ varchar(255)) "
|
||||
"BEGIN "
|
||||
/* 1.
|
||||
* remove all users on the splitting server from the ison table
|
||||
*/
|
||||
"DELETE i FROM `" + prefix + "ison` AS i "
|
||||
"INNER JOIN `" + prefix + "server` AS s "
|
||||
"INNER JOIN `" + prefix + "user` AS u "
|
||||
"WHERE i.nickid = u.nickid "
|
||||
"AND u.servid = s.id "
|
||||
"AND s.name = sname_;"
|
||||
|
||||
/* 2.
|
||||
* remove all users on the splitting server from the user table
|
||||
*/
|
||||
"DELETE u FROM `" + prefix + "user` AS u "
|
||||
"INNER JOIN `" + prefix + "server` AS s "
|
||||
"WHERE s.id = u.servid "
|
||||
"AND s.name = sname_;"
|
||||
|
||||
/* 3.
|
||||
* on the splitting server, set usercount = 0, split_time = now(), online = 'N'
|
||||
*/
|
||||
"UPDATE `" + prefix + "server` SET currentusers = 0, split_time = now(), online = 'N' "
|
||||
"WHERE name = sname_;"
|
||||
"END;"; // end of the procedure
|
||||
this->RunQuery(query);
|
||||
|
||||
|
||||
if (this->HasProcedure(prefix + "UserQuit"))
|
||||
this->RunQuery(SQL::Query("DROP PROCEDURE " + prefix + "UserQuit"));
|
||||
query = "CREATE PROCEDURE `" + prefix + "UserQuit`"
|
||||
"(nick_ varchar(255)) "
|
||||
"BEGIN "
|
||||
/* decrease usercount on the server where the user was on */
|
||||
"UPDATE `" + prefix + "user` AS `u`, `" + prefix + "server` AS `s` "
|
||||
"SET s.currentusers = s.currentusers - 1 "
|
||||
"WHERE u.nick=nick_ AND u.servid = s.id; "
|
||||
/* remove from all channels where the user was on */
|
||||
"DELETE i FROM `" + prefix + "ison` AS i "
|
||||
"INNER JOIN `" + prefix + "user` as u "
|
||||
"WHERE u.nick = nick_ "
|
||||
"AND i.nickid = u.nickid;"
|
||||
/* remove the user from the user table */
|
||||
"DELETE FROM `" + prefix + "user` WHERE nick = nick_; "
|
||||
"END";
|
||||
this->RunQuery(query);
|
||||
|
||||
if (this->HasProcedure(prefix + "ShutDown"))
|
||||
this->RunQuery(SQL::Query("DROP PROCEDURE " + prefix + "ShutDown"));
|
||||
query = "CREATE PROCEDURE `" + prefix + "ShutDown`()"
|
||||
"BEGIN "
|
||||
"UPDATE `" + prefix + "server` "
|
||||
"SET currentusers=0, online='N', split_time=now();"
|
||||
"TRUNCATE TABLE `" + prefix + "user`;"
|
||||
"TRUNCATE TABLE `" + prefix + "chan`;"
|
||||
"TRUNCATE TABLE `" + prefix + "ison`;"
|
||||
"END";
|
||||
this->RunQuery(query);
|
||||
|
||||
if (this->HasProcedure(prefix + "JoinUser"))
|
||||
this->RunQuery(SQL::Query("DROP PROCEDURE " + prefix + "JoinUser"));
|
||||
query = "CREATE PROCEDURE `"+ prefix + "JoinUser`"
|
||||
"(nick_ varchar(255), channel_ varchar(255), modes_ varchar(255)) "
|
||||
"BEGIN "
|
||||
"DECLARE cur int;"
|
||||
"DECLARE max int;"
|
||||
"INSERT INTO `" + prefix + "ison` (nickid, chanid, modes) "
|
||||
"SELECT u.nickid, c.chanid, modes_ "
|
||||
"FROM " + prefix + "user AS u, " + prefix + "chan AS c "
|
||||
"WHERE u.nick=nick_ AND c.channel=channel_;"
|
||||
"SELECT count(i.chanid) INTO cur "
|
||||
"FROM `" + prefix + "chan` AS c, " + prefix + "ison AS i "
|
||||
"WHERE i.chanid = c.chanid AND c.channel=channel_;"
|
||||
"SELECT `maxusers` INTO max FROM `" + prefix + "maxusers` WHERE name=channel_;"
|
||||
"IF found_rows() AND cur <= max THEN "
|
||||
"UPDATE `" + prefix + "maxusers` SET lastused=now() WHERE name=channel_;"
|
||||
"ELSE "
|
||||
"INSERT INTO `" + prefix + "maxusers` (name, maxusers, maxtime, lastused) "
|
||||
"VALUES ( channel_, cur, now(), now() ) "
|
||||
"ON DUPLICATE KEY UPDATE "
|
||||
"name=VALUES(name), maxusers=VALUES(maxusers),"
|
||||
"maxtime=VALUES(maxtime), lastused=VALUES(lastused);"
|
||||
"END IF;"
|
||||
"END";
|
||||
this->RunQuery(query);
|
||||
|
||||
if (this->HasProcedure(prefix + "PartUser"))
|
||||
this->RunQuery(SQL::Query("DROP PROCEDURE " + prefix + "PartUser"));
|
||||
query = "CREATE PROCEDURE `" + prefix + "PartUser`"
|
||||
"(nick_ varchar(255), channel_ varchar(255)) "
|
||||
"BEGIN "
|
||||
"DELETE i FROM `" + prefix + "ison` AS i "
|
||||
"INNER JOIN `" + prefix + "user` AS u "
|
||||
"INNER JOIN `" + prefix + "chan` AS c "
|
||||
"WHERE i.nickid = u.nickid "
|
||||
"AND u.nick = nick_ "
|
||||
"AND i.chanid = c.chanid "
|
||||
"AND c.channel = channel_;"
|
||||
"END";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* (C) 2013-2025 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
#include "irc2sql.h"
|
||||
|
||||
void IRC2SQL::RunQuery(const SQL::Query &q)
|
||||
{
|
||||
if (sql)
|
||||
sql->Run(&sqlinterface, q);
|
||||
}
|
||||
|
||||
void IRC2SQL::GetTables()
|
||||
{
|
||||
TableList.clear();
|
||||
ProcedureList.clear();
|
||||
EventList.clear();
|
||||
if (!sql)
|
||||
return;
|
||||
|
||||
SQL::Result r = this->sql->RunQuery(this->sql->GetTables(prefix));
|
||||
for (int i = 0; i < r.Rows(); ++i)
|
||||
{
|
||||
const std::map<Anope::string, Anope::string> &map = r.Row(i);
|
||||
for (std::map<Anope::string, Anope::string>::const_iterator it = map.begin(); it != map.end(); ++it)
|
||||
TableList.push_back(it->second);
|
||||
}
|
||||
query = "SHOW PROCEDURE STATUS WHERE `Db` = Database();";
|
||||
r = this->sql->RunQuery(query);
|
||||
for (int i = 0; i < r.Rows(); ++i)
|
||||
{
|
||||
ProcedureList.push_back(r.Get(i, "Name"));
|
||||
}
|
||||
query = "SHOW EVENTS WHERE `Db` = Database();";
|
||||
r = this->sql->RunQuery(query);
|
||||
for (int i = 0; i < r.Rows(); ++i)
|
||||
{
|
||||
EventList.push_back(r.Get(i, "Name"));
|
||||
}
|
||||
}
|
||||
|
||||
bool IRC2SQL::HasTable(const Anope::string &table)
|
||||
{
|
||||
for (std::vector<Anope::string>::const_iterator it = TableList.begin(); it != TableList.end(); ++it)
|
||||
if (*it == table)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRC2SQL::HasProcedure(const Anope::string &table)
|
||||
{
|
||||
for (std::vector<Anope::string>::const_iterator it = ProcedureList.begin(); it != ProcedureList.end(); ++it)
|
||||
if (*it == table)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRC2SQL::HasEvent(const Anope::string &table)
|
||||
{
|
||||
for (std::vector<Anope::string>::const_iterator it = EventList.begin(); it != EventList.end(); ++it)
|
||||
if (*it == table)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -161,7 +161,7 @@ public:
|
||||
u->Account()->email = email;
|
||||
BotInfo *NickServ = Config->GetClient("NickServ");
|
||||
if (NickServ)
|
||||
u->SendMessage(NickServ, _("Your email has been updated to \002%s\002"), email.c_str());
|
||||
u->SendMessage(NickServ, _("Your email address has been updated to \002%s\002"), email.c_str());
|
||||
Log(this->owner) << "Updated email address for " << u->nick << " (" << u->Account()->display << ") to " << email;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,10 +187,9 @@ public:
|
||||
{
|
||||
if (c->ci && !c->ci->memos.memos->empty() && c->ci->AccessFor(u).HasPriv("MEMO"))
|
||||
{
|
||||
if (c->ci->memos.memos->size() == 1)
|
||||
u->SendMessage(MemoServ, _("There is \002%zu\002 memo on channel %s."), c->ci->memos.memos->size(), c->ci->name.c_str());
|
||||
else
|
||||
u->SendMessage(MemoServ, _("There are \002%zu\002 memos on channel %s."), c->ci->memos.memos->size(), c->ci->name.c_str());
|
||||
auto memocount = c->ci->memos.memos->size();
|
||||
u->SendMessage(MemoServ, memocount, N_("There is \002%zu\002 memo on channel %s.", "There are \002%zu\002 memos on channel %s."),
|
||||
memocount, c->ci->name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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:"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -351,7 +361,7 @@ public:
|
||||
|
||||
void OnDelCore(NickCore *nc) override
|
||||
{
|
||||
Log(NickServ, "nick") << "Deleting nickname group " << nc->display;
|
||||
Log(NickServ, "nick") << "Deleting account " << nc->display;
|
||||
|
||||
/* Clean up this nick core from any users online */
|
||||
for (std::list<User *>::iterator it = nc->users.begin(); it != nc->users.end();)
|
||||
@@ -367,7 +377,7 @@ public:
|
||||
|
||||
void OnChangeCoreDisplay(NickCore *nc, const Anope::string &newdisplay) override
|
||||
{
|
||||
Log(LOG_NORMAL, "nick", NickServ) << "Changing " << nc->display << " nickname group display to " << newdisplay;
|
||||
Log(LOG_NORMAL, "nick", NickServ) << "Changing " << nc->display << " account display nickname to " << newdisplay;
|
||||
}
|
||||
|
||||
void OnNickIdentify(User *u) override
|
||||
@@ -391,10 +401,9 @@ public:
|
||||
if (block.Get<bool>("forceemail", "yes") && u->Account()->email.empty())
|
||||
{
|
||||
u->SendMessage(NickServ, _(
|
||||
"You must now supply an email for your nick. "
|
||||
"This email will allow you to retrieve your password in "
|
||||
"case you forget it. "
|
||||
"Type \002%s\032\037email\037\002 in order to set your email."
|
||||
"You must now supply an email address for your nick. This email address will "
|
||||
"allow you to recover your account in case you forget your password. Type "
|
||||
"\002%s\032\037email\037\002 in order to set your email address."
|
||||
),
|
||||
NickServ->GetQueryCommand("nickserv/set/email").c_str());
|
||||
}
|
||||
@@ -482,7 +491,7 @@ public:
|
||||
IRCD->SendLogin(u, na);
|
||||
if (!Config->GetModule("nickserv").Get<bool>("nonicknameownership") && na->nc == u->Account() && !na->nc->HasExt("UNCONFIRMED"))
|
||||
u->SetMode(NickServ, "REGISTERED");
|
||||
Log(u, "", NickServ) << u->GetMask() << " automatically identified for group " << u->Account()->display;
|
||||
Log(u, "", NickServ) << u->GetMask() << " automatically identified for account " << u->Account()->display;
|
||||
}
|
||||
|
||||
if (!u->nick.equals_ci(oldnick) && old_na)
|
||||
@@ -607,7 +616,7 @@ public:
|
||||
|
||||
if (expire)
|
||||
{
|
||||
Log(LOG_NORMAL, "nickserv/expire", NickServ) << "Expiring nickname " << na->nick << " (group: " << na->nc->display << ") (email: " << (na->nc->email.empty() ? "none" : na->nc->email) << ")";
|
||||
Log(LOG_NORMAL, "nickserv/expire", NickServ) << "Expiring nickname " << na->nick << " (account: " << na->nc->display << ") (email: " << (na->nc->email.empty() ? "none" : na->nc->email) << ")";
|
||||
FOREACH_MOD(OnNickExpire, (na));
|
||||
delete na;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user