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

Compare commits

...

74 Commits

Author SHA1 Message Date
Sadie Powell b51c6453ae Release 2.1.14. 2025-05-02 09:52:40 +01:00
Sadie Powell 8a44b9c0ea Update the change logs. 2025-05-02 09:52:40 +01:00
Sadie Powell 0dd5430c94 Deduplicate code in cs_access. 2025-04-27 20:58:35 +01:00
Sadie Powell 046fa5c848 Show the reason why a config file failed to open. 2025-04-27 14:16:10 +01:00
Sadie Powell 551f3504c8 Fix broken handling of colour codes in LineWrapper.
Closes #504.
2025-04-27 13:01:29 +01:00
Sadie Powell c11638db98 Allow disabling the timestamp in os_news messages. 2025-04-25 13:08:26 +01:00
Sadie Powell 9ca69a7b49 Fix a typo in ns_alist. 2025-04-24 15:01:54 +01:00
Sadie Powell 459c7947ce Fix skipping lone $ values within config values. 2025-04-24 12:48:48 +01:00
Sadie Powell fad0a4a0e8 Add support for hashing operator passwords in the config.
Closes #327.
2025-04-24 12:46:58 +01:00
Sadie Powell 1630ccedb1 Remove some double lookups in User::BadPassword. 2025-04-24 11:59:21 +01:00
Sadie Powell 36d69b1e5c Update the change logs. 2025-04-23 17:34:33 +01:00
Sadie Powell 627b89ec7b Fix a minor regression in serialising channel data. 2025-04-23 17:33:01 +01:00
Sadie Powell 9373677610 Respect NEVEROP in chanserv/set/{founder,successor}. 2025-04-23 03:21:08 +01:00
Sadie Powell bbb65ddc33 When deleting a single list item show the deleted item not a count.
Closes #487.
2025-04-23 01:57:02 +01:00
Sadie Powell 508bbe11e6 Show all privileges in nickserv/alist.
Closes #502.
2025-04-23 00:33:48 +01:00
Sadie Powell 095ed3c8c8 Allow users to unmark themselves as a channel successor.
Closes #501.
2025-04-22 22:53:40 +01:00
Sadie Powell f3743cd37d Remove hardcoded command names from most messages. 2025-04-22 18:56:26 +01:00
Sadie Powell 0c155e0c05 Replace hard linebreaks in RPC and webcpanel messages. 2025-04-22 18:16:31 +01:00
Sadie Powell f362959834 Fix splitting in the middle of some command names. 2025-04-22 18:16:31 +01:00
Sadie Powell f5a85c69d2 Remove time from the name of some variables where its obvious. 2025-04-19 22:53:49 +01:00
Sadie Powell c8b3819767 Add the anope.account and anope.listAccounts RPC events. 2025-04-19 22:31:49 +01:00
Sadie Powell e6a1982922 Fix various typos in the rpc_data docs. 2025-04-19 21:49:33 +01:00
Sadie Powell 40a1dc9536 Document the rpc_data result better. 2025-04-19 17:22:06 +01:00
Sadie Powell 70bf013ef0 Allow syntax messages to take a predicate. 2025-04-19 16:54:26 +01:00
Sadie Powell 18dfa62626 Add expanded data to the rpc_data list events. 2025-04-19 15:16:07 +01:00
Sadie Powell d815906393 Get rid of the internal block wrapper.
This only existed for compatibility with old 2.0 modules and 2.1
has already broken compatibility with them.
2025-04-19 12:49:06 +01:00
Sadie Powell 452e62c050 Add support for local password comparison in sql_authentication. 2025-04-19 12:38:32 +01:00
Sadie Powell 4916e1dbfc Use windows-2025 for the Windows CI.
[skip alpine ci]
[skip ubuntu ci]
2025-04-18 12:53:47 +01:00
Sadie Powell fa7ed12aad Use a duration string when telling people to wait before emailing. 2025-04-16 03:00:52 +01:00
Sadie Powell 94c20f3084 Use duration strings when reporting the expiry period. 2025-04-16 02:52:31 +01:00
Sadie Powell 597d4a1aee Update the change logs. 2025-04-16 02:45:53 +01:00
Sadie Powell 1e95d0f536 Fix some text strings that should be marked as translatable. 2025-04-16 02:19:17 +01:00
Sadie Powell ad0b4d1aa0 Rename TextSplitter to LineWrapper. 2025-04-16 01:53:50 +01:00
Sadie Powell 74e9a9d2fe Automatically wrap the help output. 2025-04-16 01:50:59 +01:00
Sadie Powell d2aee394ea Fix a compiler warning on Clang. 2025-04-16 00:14:46 +01:00
Sadie Powell 3e696fae0f Reduce the maximum line length from 120 to 100.
This should fit on user screens a bit better.
2025-04-16 00:07:33 +01:00
Sadie Powell ce362854a3 Update as many messages as possible for automatic line wrapping. 2025-04-16 00:04:30 +01:00
Sadie Powell a883b616a1 Automatically line wrap messages sent by services. 2025-04-15 19:30:59 +01:00
Sadie Powell b421ba258e Show the protection time in the INFO output. 2025-04-15 19:26:32 +01:00
Sadie Powell 3691887297 Add / to the default vhost chars. 2025-04-15 18:18:15 +01:00
Sadie Powell 75e2501500 Allow unbanning virtual modes, add the !unmute fantasy command. 2025-04-15 15:59:51 +01:00
Sadie Powell 1c6db37681 Fix a typo in cs_unban. 2025-04-15 15:29:59 +01:00
Sadie Powell 5c2fc1cedd Allow clearing other list modes using ClearBans. 2025-04-15 15:00:25 +01:00
Sadie Powell d891f2bcbd Sync the GitHub templates with the ones InspIRCd uses. 2025-04-15 13:51:51 +01:00
Sadie Powell 5eb13f4420 Use Anope::Template in db_json. 2025-04-15 13:04:09 +01:00
Sadie Powell bd9d3b0f7d Add support for monthly backups to db_json. 2025-04-15 13:00:34 +01:00
Sadie Powell cbb41241d4 Merge branch '2.0' into 2.1. 2025-04-15 11:42:49 +01:00
Sadie Powell b9acaa6d51 Ask people to file PRs on GitHub as well as emailing team@. 2025-04-15 10:05:51 +01:00
Sadie Powell 9d18fdf0f6 Update the change logs. 2025-04-14 11:56:40 +01:00
Sadie Powell d04a312d0d Add Anope::Templace and switch all template strings to use it. 2025-04-14 11:31:19 +01:00
Sadie Powell 099f0ce43a Purge the seen database after 90 days. 2025-04-14 01:51:40 +01:00
Sadie Powell 07bd1bbec9 Switch enc_sha2 default from sha256 to sha512. 2025-04-14 01:01:24 +01:00
Sadie Powell aa0a687a58 Fix a typo in the example config. 2025-04-14 01:00:17 +01:00
Sadie Powell b89cc47642 Resort the Implementation list. 2025-04-13 16:05:06 +01:00
Sadie Powell d87fa4d781 Add a matcher for the InspIRCd oper name extban. 2025-04-13 13:15:05 +01:00
Sadie Powell 9351debd73 Expand GetQueryCommand to take a command name. 2025-04-10 13:34:25 +01:00
Sadie Powell 40d558ef21 Make the length of confirmation codes configurable. 2025-04-07 12:27:45 +01:00
Sadie Powell e1224ac486 Ignore the SLOG message on UnrealIRCd. 2025-04-05 07:13:08 +01:00
Sadie Powell ddd33e65b4 Add a log message for when we receive a weirdly targeted message. 2025-04-05 07:11:54 +01:00
Sadie Powell e4f88d44cd Deduplicate checks in ns_cert. 2025-04-05 06:53:40 +01:00
Sadie Powell 063b4a9918 Merge branch '2.0' into 2.1. 2025-04-02 23:01:04 +01:00
Sadie Powell c6065ff0f3 Update the change log. 2025-04-02 23:00:12 +01:00
Sadie Powell a5aae4f41d Fix building in a post-CMP0082 world. 2025-04-02 23:00:12 +01:00
Sadie Powell d019da673d Replace NormalizeBuffer implementation with the one from InspIRCd.
This is more robust and will handle more formatting code types.
2025-04-02 17:04:47 +01:00
Sadie Powell 4d7adbf2b7 Fix an unnecessary substr in irc2sql. 2025-04-02 16:37:49 +01:00
Sadie Powell 404bf77ef5 Add a message handler for messages that can be safely ignored. 2025-04-02 13:17:38 +01:00
Sadie Powell 69393a5f14 Fix building in a post-CMP0082 world. 2025-04-02 13:12:19 +01:00
Sadie Powell 97c63822fc Bump the minimum CMake version to 3.20.
This should hopefully prevent us from being burned by CMake
dropping old version compatibility for a long time.
2025-04-02 10:11:21 +01:00
Sadie Powell 698dd78ef8 Merge branch '2.0' into 2.1. 2025-04-02 10:09:58 +01:00
Sadie Powell 0b36ddfaf3 Fix building on old versions of RHEL. 2025-04-02 09:58:49 +01:00
Sadie Powell 947ddc9e1b Fix building on CMake 4.
This is a partial backport from 2.1.
2025-04-02 09:53:10 +01:00
Sadie Powell 59d516d5b0 Refactor and document the rest of the SASL header. 2025-04-01 16:57:28 +01:00
Sadie Powell 2ecb667d1c Bump the minimum CMake version in the docs. 2025-04-01 16:29:11 +01:00
Sadie Powell c21f6ac597 Bump for 2.1.14-git. 2025-04-01 11:06:38 +01:00
193 changed files with 5221 additions and 4213 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Thanks for taking the time to fill out this bug report! Please make sure to answer the questions properly and don't just enter the same text into every field as this will make it harder for us to fix your bug.
If you're looking for help with setting up your services please post on [our support forum](https://github.com/orgs/anope/discussions/categories/support) instead.
+13
View File
@@ -24,3 +24,16 @@ I have tested this pull request on:
**Operating system name and version:** <!-- e.g. Linux 3.11 -->
**Compiler name and version:** <!-- e.g. GCC 4.2.0 -->
## Checks
<!--
Tick the boxes for the checks you have made.
-->
I have ensured that:
- [ ] The code I am submitting is my own work and/or I have permission from the author to share it.
- [ ] Generative AI (Copilot, ChatGPT, etc) was not used to create any part of this pull request.
- [ ] I have documented any features added by this pull request.
- [ ] This pull request does not introduce any incompatible API changes (stable branches only, delete if not applicable).
+25 -3
View File
@@ -10,10 +10,18 @@ on:
jobs:
build:
if: "!contains(github.event.head_commit.message, '[skip windows ci]')"
runs-on: windows-2019
runs-on: windows-2025
env:
BUILD_TYPE: ${{ github.event_name == 'release' && 'Release' || 'Debug' }}
CONAN_USER_HOME: ${{ github.workspace }}/win/build
CONAN_USER_HOME_SHORT: None
steps:
- uses: actions/checkout@v4
- name: Setup NSIS
run: |-
choco install nsis
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2
@@ -22,20 +30,34 @@ jobs:
with:
version: 1.64.0
- name: Try to restore libraries from the cache
uses: actions/cache/restore@v4
id: library-cache
with:
key: conan-${{ hashFiles('src/win32/conanfile.txt') }}
path: ${{ env.CONAN_USER_HOME }}/.conan
- name: Install libraries
run: |
conan install ${{ github.workspace }}\src\win32 --build=missing
- name: Save libraries to the cache
if: ${{ steps.library-cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v4
with:
key: ${{ steps.library-cache.outputs.cache-primary-key }}
path: ${{ env.CONAN_USER_HOME }}/.conan
- name: Run CMake
run: |
mkdir ${{ github.workspace }}\build
cd ${{ github.workspace }}\build
cmake -A "x64" -D "CMAKE_BUILD_TYPE=${{ github.event_name == 'release' && 'Release' || 'Debug' }}" -G "Visual Studio 16 2019" ..
cmake -A x64 -D "CMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }}" -G "Visual Studio 17 2022" ..
- name: Build Anope
working-directory: ${{ github.workspace }}\build
run: |
msbuild PACKAGE.vcxproj /M:3 /P:Configuration=${{ github.event_name == 'release' && 'Release' || 'Debug' }} /P:Platform=x64 /VERBOSITY:MINIMAL
msbuild PACKAGE.vcxproj /M:5 /P:Configuration=${{ env.BUILD_TYPE }} /P:Platform=x64 /VERBOSITY:MINIMAL
- name: Upload installer
if: "${{ github.event_name == 'release' }}"
+10 -10
View File
@@ -1,5 +1,5 @@
# This usage of CMake requires at least version 3.8
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
# This usage of CMake requires at least version 3.20
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
# Set the project as C++ primarily, but have C enabled for the checks required later
project(Anope CXX)
@@ -316,14 +316,6 @@ if(${Anope_SOURCE_DIR} STREQUAL ${Anope_BINARY_DIR})
endif()
endif()
# Go into the following directories and run their CMakeLists.txt as well
add_subdirectory(data)
add_subdirectory(docs)
add_subdirectory(language)
add_subdirectory(src)
add_subdirectory(modules)
add_subdirectory(include)
# Get the filename of the Anope binary, to use later
set(SERVICES_BINARY "$<TARGET_FILE:${PROGRAM_NAME}>")
get_filename_component(SERVICES_BINARY ${SERVICES_BINARY} NAME)
@@ -396,3 +388,11 @@ if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
set(CPACK_MONOLITHIC_INSTALL TRUE)
include(CPack)
endif()
# Go into the following directories and run their CMakeLists.txt as well
add_subdirectory(data)
add_subdirectory(docs)
add_subdirectory(language)
add_subdirectory(src)
add_subdirectory(modules)
add_subdirectory(include)
+1 -1
View File
@@ -139,7 +139,7 @@ done
cmake --version 2>&1 > /dev/null
if [ $? -ne 0 ] ; then
clear
echo "Anope requires CMake 3.8 or newer, which can be downloaded at https://cmake.org/ or through your system's package manager."
echo "Anope requires CMake 3.20 or newer, which can be downloaded at https://cmake.org/ or through your system's package manager."
echo "If you have installed CMake already, ensure it is in your PATH environment variable."
exit 0
fi
+57 -38
View File
@@ -331,7 +331,7 @@ networkinfo
*
* It is recommended you DON'T change this.
*/
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-/"
/*
* If set to true, allows vHosts to not contain dots (.).
@@ -479,6 +479,14 @@ options
*/
didyoumeandifference = 4
/*
* The length of codes used for confirming actions like dropping a channel or a
* nickname.
*
* Defaults to 15 if not set.
*/
codelength = 15
/*
* If set, the maximum number of bytes after which to wrap services messages. This
* can be set a bit higher than the default but should be well under the maximum
@@ -487,9 +495,9 @@ options
* NOTE: this currently only applies to tables but will be expanded to all messages
* in a later release.
*
* Defaults to 120 if not set.
* Defaults to 100 if not set.
*/
linelength = 120
linelength = 100
/* The regex engine to use, as provided by the regex modules.
* Leave commented to disable regex matching.
@@ -867,6 +875,16 @@ opertype
/* An optional password. If defined, the user must login using "/OPERSERV LOGIN" first */
#password = "secret"
/*
* The algorithm which the above password is hashed with. If this is not set then services will
* assume the above password is not hashed.
*
* You will need to have the appropriate encryption module (e.g. enc_bcrypt) loaded in order
* for this to work.
*
*/
#password_hash = "bcrypt"
/* An optional SSL fingerprint. If defined, it's required to be able to use this opertype. */
#certfp = "ed3383b3f7d74e89433ddaa4a6e5b2d7"
@@ -967,76 +985,76 @@ mail
* The subject and message of emails sent to users when they register accounts.
*
* Available tokens for this template are:
* %n - Gets replaced with the nickname
* %N - Gets replaced with the network name
* %c - Gets replaced with the confirmation code
* {nick} - Gets replaced with the nickname
* {network} - Gets replaced with the network name
* {code} - Gets replaced with the confirmation code
*/
registration_subject = "Nickname registration for %n"
registration_subject = "Nickname registration for {nick}"
registration_message = "Hi,
You have requested to register the nickname %n on %N.
Please type \" /msg NickServ CONFIRM %c \" to complete registration.
You have requested to register the nickname {nick} on {network}.
Please type \" /msg NickServ CONFIRM {code} \" to complete registration.
If you don't know why this mail was sent to you, please ignore it silently.
%N administrators."
{network} administrators."
/*
* The subject and message of emails sent to users when they request a new password.
*
* Available tokens for this template are:
* %n - Gets replaced with the nickname
* %N - Gets replaced with the network name
* %c - Gets replaced with the confirmation code
* {nick} - Gets replaced with the nickname
* {network} - Gets replaced with the network name
* {code} - Gets replaced with the confirmation code
*/
reset_subject = "Reset password request for %n"
reset_subject = "Reset password request for {nick}"
reset_message = "Hi,
You have requested to have the password for %n reset.
To reset your password, type \" /msg NickServ CONFIRM %n %c \"
You have requested to have the password for {nick} reset.
To reset your password, type \" /msg NickServ CONFIRM {nick} {code} \"
If you don't know why this mail was sent to you, please ignore it silently.
%N administrators."
{network} administrators."
/*
* The subject and message of emails sent to users when they request a new email address.
*
* Available tokens for this template are:
* %e - Gets replaced with the old email address
* %E - Gets replaced with the new email address
* %n - Gets replaced with the nickname
* %N - Gets replaced with the network name
* %c - Gets replaced with the confirmation code
* {old_email} - Gets replaced with the old email address
* {new_email} - Gets replaced with the new email address
* {account} - Gets replaced with the nickname
* {network} - Gets replaced with the network name
* {code} - Gets replaced with the confirmation code
*/
emailchange_subject = "Email confirmation"
emailchange_message = "Hi,
You have requested to change your email address from %e to %E.
Please type \" /msg NickServ CONFIRM %c \" to confirm this change.
You have requested to change your email address from {old_email} to {new_email}.
Please type \" /msg NickServ CONFIRM {code} \" to confirm this change.
If you don't know why this mail was sent to you, please ignore it silently.
%N administrators."
{network} administrators."
/*
* The subject and message of emails sent to users when they receive a new memo.
*
* Available tokens for this template are:
* %n - Gets replaced with the nickname
* %s - Gets replaced with the sender's nickname
* %d - Gets replaced with the memo number
* %t - Gets replaced with the memo text
* %N - Gets replaced with the network name
* {receiver} - Gets replaced with the receiver's nickname
* {sender} - Gets replaced with the sender's nickname
* {number} - Gets replaced with the memo number
* {text} - Gets replaced with the memo text
* {network} - Gets replaced with the network name
*/
memo_subject = "New memo"
memo_message = "Hi %n,
memo_message = "Hi {receiver},
You've just received a new memo from %s. This is memo number %d.
You've just received a new memo from {sender}. This is memo number {number}.
Memo text:
%t"
{text}"
}
/*
@@ -1157,14 +1175,15 @@ module
module_database = "{name}.module.json"
/*
* Sets how many days worth of backups should be kept.
* Sets how many days and months worth of backups should be kept.
*
* It is recommended that at the very least you keep one backup. Failure to
* do so may result in total data loss if you ever run out of disk space or
* have a power failure during a database write. However, if you're *REALLY*
* sure this won't happen you can disable backups by setting this to 0.
* sure this won't happen you can disable backups by setting these to 0.
*/
backups = 14
daily_backups = 7
monthly_backups = 3
/*
* The directory in which backups are kept.
@@ -1272,9 +1291,9 @@ module
name = "enc_sha2"
/** The sub-algorithm to use. Can be set to sha224 for SHA-224, sha256 for
* SHA-256, sha284 for SHA-384, or sha512 for SHA-512. Defaults to sha256.
* SHA-256, sha384 for SHA-384, or sha512 for SHA-512. Defaults to sha512.
*/
#algorithm = "sha256"
#algorithm = "sha512"
}
/*
+1
View File
@@ -410,6 +410,7 @@ fantasy { name = "SUSPEND"; command = "chanserv/suspend"; permission = "chanserv
fantasy { name = "SYNC"; command = "chanserv/sync"; }
fantasy { name = "TOPIC"; command = "chanserv/topic"; }
fantasy { name = "UNBAN"; command = "chanserv/unban"; }
fantasy { name = "UNMUTE"; command = "chanserv/unban"; mode = "QUIET"; }
fantasy { name = "UNSUSPEND"; command = "chanserv/unsuspend"; permission = "chanserv/suspend"; }
fantasy { name = "UP"; command = "chanserv/up"; }
fantasy { name = "VOICE"; command = "chanserv/modes"; }
+4 -4
View File
@@ -163,10 +163,10 @@ module
/*
* The message formatting to use for signed kick messages.
* %n is the nick of the kicker
* %m is the message specified
* {nick} is the nick of the kicker
* {message} is the message specified
*/
signkickformat = "%m (%n)"
signkickformat = "{message} ({nick})"
/*
* If set, prevents channel access entries from containing hostmasks.
@@ -1182,7 +1182,7 @@ module
simple = false
/* Sets the time to keep seen entries in the seen database. */
purgetime = "30d"
purgetime = 90d
}
command { service = "OperServ"; name = "SEEN"; command = "operserv/seen"; permission = "operserv/seen"; }
+37 -19
View File
@@ -119,15 +119,15 @@ module { name = "help" }
time = 4h
/* Reason for akill.
* %n is the nick of the user
* %u is the ident/username of the user
* %g is the realname of the user
* %h is the hostname of the user
* %i is the IP of the user
* %r is the reply reason (configured below). Will be nothing if not configured.
* %N is the network name set in networkinfo:networkname
* {nick} is the nick of the user
* {user} is the ident/username of the user
* {real} is the realname of the user
* {host} is the hostname of the user
* {ip} is the IP of the user
* {reply} is the reply reason (configured below). Will be nothing if not configured.
* {network} is the network name set in networkinfo:networkname
*/
reason = "You are listed in the EFnet RBL, visit https://rbl.efnetrbl.org/?i=%i for info"
reason = "You are listed in the EFnet RBL, visit https://rbl.efnetrbl.org/?i={ip} for info"
/* Replies to ban and their reason. If no replies are configured, all replies get banned. */
reply
@@ -171,7 +171,7 @@ module { name = "help" }
{
name = "dnsbl.dronebl.org"
time = 4h
reason = "You have a host listed in the DroneBL. For more information, visit https://dronebl.org/lookup_branded?ip=%i&network=%N"
reason = "You have a host listed in the DroneBL. For more information, visit https://dronebl.org/lookup?ip={ip}&network={network}"
}
/* Exempt localhost from DNSBL checks */
@@ -270,10 +270,10 @@ module { name = "help" }
/*
* The search filter used to look up users's accounts.
* %account is replaced with the user's account.
* %object_class is replaced with the object_class configured below.
* {account} is replaced with the user's account.
* {object_class} is replaced with the object_class configured below.
*/
search_filter = "(&(uid=%account)(objectClass=%object_class))"
search_filter = "(&(uid={account})(objectClass={object_class}))"
/*
* The object class used by LDAP to store user account information.
@@ -327,7 +327,7 @@ module { name = "help" }
/*
* An optional binddn to use when searching for groups.
* %a is replaced with the account name of the user.
* {account} is replaced with the account name of the user.
*/
#binddn = "cn=Manager,dc=anope,dc=org"
@@ -343,9 +343,9 @@ module { name = "help" }
/*
* The filter to use when searching for users.
* %a is replaced with the account name of the user.
* {account} is replaced with the account name of the user.
*/
filter = "(member=uid=%a,ou=users,dc=anope,dc=org)"
filter = "(member=uid={account},ou=users,dc=anope,dc=org)"
/*
* The attribute of the group that is the name of the opertype.
@@ -550,11 +550,11 @@ module
/*
* The reason to ban the user for.
* %h is replaced with the type of proxy found.
* %i is replaced with the IP of proxy found.
* %p is replaced with the port.
* {type} is replaced with the type of proxy found.
* {ip} is replaced with the IP of proxy found.
* {port} is replaced with the port.
*/
reason = "You have an open proxy running on your host (%t:%i:%p)"
reason = "You have an open proxy running on your host ({type}:{ip}:{port})"
}
}
@@ -670,6 +670,23 @@ module
*/
query = "SELECT `email_addr` AS `email` FROM `my_users` WHERE `username` = @a@ AND `password` = MD5(CONCAT('salt', @p@))"
/*
* If your database uses a password hashing algorithm that can not be compared using a simple
* comparison function then you can specify it here to compare locally.
*
* You will need to have the appropriate encryption module (e.g. enc_bcrypt) loaded in order
* for this to work.
*/
#password_hash = "bcrypt"
/*
* If using the password_hash field (above) you will need to specify the name of the field to
* fetch the password from.
*
* Defaults to "password" if not set.
*/
#password_field = "password"
/*
* If set, the reason to give the users who try to "/msg NickServ REGISTER".
* If not set, then registration is not blocked.
@@ -826,6 +843,7 @@ module
*
* Adds support for the following RPC methods:
*
* anope.listAccounts anope.account
* anope.listChannels anope.channel
* anope.listOpers anope.oper
* anope.listServers anope.server
+1 -1
View File
@@ -93,7 +93,7 @@ module
#confirmemailchanges = yes
/*
* A message sent to users on connect if they use an unregistered nick. %n will be replaced with the user's nickname.
* A message sent to users on connect if they use an unregistered nick. {nick} will be replaced with the user's nickname.
*
* This directive is optional.
*/
+8 -1
View File
@@ -502,6 +502,13 @@ module
* This directive is optional, if not set it will default to 3.
*/
#newscount = 3
/*
* Whether to show the datetime at which the news entry was added.
*
* This directive is optional, if not set it will default to yes.
*/
#showdate = yes
}
command { service = "OperServ"; name = "LOGONNEWS"; command = "operserv/logonnews"; permission = "operserv/news"; }
command { service = "OperServ"; name = "OPERNEWS"; command = "operserv/opernews"; permission = "operserv/news"; }
@@ -580,7 +587,7 @@ module
*
* This directive is optional, if not set, nothing will be sent.
*/
sessionlimitexceeded = "The session limit for your IP %IP% has been exceeded."
sessionlimitexceeded = "The session limit for your IP {ip} has been exceeded."
/*
* Same as above, but should be used to provide a website address where users can find out more
+23
View File
@@ -1,3 +1,26 @@
Anope Version 2.1.14-git
------------------------
Added a detail specifier to the anope.list{Channels,Opers,Servers,Users} RPC methods.
Added a matcher for the InspIRCd oper extban.
Added support for hashed operator passwords.
Added support for hiding the date news was added in os_news.
Added support for local password comparison to the sql_authentication module.
Added support for monthly backups to db_json.
Added support for unbanning virtual modes using cs_unban.
Added the !unmute fantasy command.
Added the anope.account and anope.listAccounts RPC methods to the rpc_data module.
Added the protection time to the INFO output.
Allowed unprivileged channel successors to remove themselves from succession.
Bumped the minimum required CMake version to 3.20.
Changed deletion callbacks to specify the mask that was deleted if only one was.
Changed nickserv/alist to show all permissions not just the highest ranked one.
Fixed NEVEROP not being respected in chanserv/set/founder and chanserv/set/successor.
Fixed stripping IRC formatting codes from messages.
Messages are now automatically line wrapped to options:linelength.
Redocumented the ns_sasl module.
Removed hardcoded command names from several messages.
Updated the Windows CI to Windows Server 2025 and Visual Studio 2022.
Anope Version 2.1.13
--------------------
Added a Config check to ensure users actually want to use the development branch.
+12
View File
@@ -1,3 +1,15 @@
Anope Version 2.1.14-git
------------------------
Added oper:password_hash.
Added options:codelength (defaults to 15).
Added {os_news}:showdate (defaults to yes).
Added {sql_authentication}:password_field (defaults to "password").
Added {sql_authentication}:password_hash.
Changed the default value for options:linelength to "100".
Changed the default value for {enc_sha2}:algorithm to "sha512".
Changed the default value for {ns_seen}:purgetime to "90d".
Changed the syntax for template variables in mail:emailchange_message, mail:emailchange_subject, mail:memo_message, mail:memo_subject, mail:registration_message, mail:registration_subject,, mail:reset_message, mail:reset_subject, {chanserv}:signkickformat, {dnsbl}:blacklist:reason, {ldap_authentication}:search_filter, {ldap_oper}:binddn, {ldap_oper}:search_filter, {nickserv}:unregistered_notice, {os_session}:sessionlimitexceeded, {proxyscan}:proxyscan:reason.
Anope Version 2.1.13
--------------------
Added options:linelength (defaults to 120).
+1 -1
View File
@@ -27,7 +27,7 @@ Note: You should also read the README and FAQ files!
cmake --version
If it's installed, you will get a line that says something similar to
"cmake version 2.8.12.2". If the version is less than 2.4 or you get
"cmake version 3.28.3". If the version is less than 3.20.0 or you get
an error saying the command was not found, you will not be able to use
CMake unless you install it yourself into your home directory. CMake
can be downloaded from:
+1 -1
View File
@@ -27,7 +27,7 @@ Note : Vous devrez également lire les fichiers README et FAQ !
cmake --version
Si CMake est installé, vous aurez une ligne qui dit quelque chose comme
"cmake version 2.8.12.2". Si la version est inférieure à 2.4 ou si vous
"cmake version 3.28.3". Si la version est inférieure à 3.20.0 ou si vous
obtenez une erreur disant que la commande n'a pas été trouvée, vous ne
pourrez pas utiliser CMake Ă  moins de l'installer vous-mĂŞme dans votre
répertoire home. CMake peut être téléchargé ici :
+3 -4
View File
@@ -34,10 +34,9 @@ Anope Multi Language Support
Poedit (https://poedit.net/) is a popular po file editor, and we recommend using it or another editor designed to edit
po files (especially on Windows).
If you have finished a language file translation and you want others to use it, please send it to team@anope.org
(don't forget to mention clearly your (nick)name, your email and the language name). You'll of course get full credit for it.
NOTE: There is no guarantee we will use your work so please do not be offended if we say no thanks.
If you have finished a language file translation and you want others to use it, please file a pull request on GitHub
or send it to team@anope.org (don't forget to mention clearly your (nick)name, your email and the language name).
You'll of course get full credit for it.
3) Using languages with modules
+36 -8
View File
@@ -44,15 +44,40 @@ class AnopeRPC {
return null;
}
/**
* Retrieves a list of accounts.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of account names.
*/
listAccounts(detail = "name") {
return this.run("anope.listAccounts", detail);
}
/**
* Retrieves information about the specified account.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} name The name of the account.
* @returns {object} An object containing information about the account.
*/
account(name) {
return this.run("anope.account", name);
}
/**
* Retrieves a list of channels.
*
* Requires the rpc_data module to be loaded.
*
* @param {string} The level of detail to request.
* @returns {array} An array of channel names.
*/
listChannels() {
return this.run("anope.listChannels");
listChannels(detail = "name") {
return this.run("anope.listChannels", detail);
}
/**
@@ -72,10 +97,11 @@ 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.
*/
listOpers() {
return this.run("anope.listOpers");
listOpers(detail = "name") {
return this.run("anope.listOpers", detail);
}
/**
@@ -95,10 +121,11 @@ 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.
*/
listServers() {
return this.run("anope.listServers");
listServers(detail = "name") {
return this.run("anope.listServers", detail);
}
/**
@@ -118,10 +145,11 @@ 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.
*/
listUsers() {
return this.run("anope.listUsers");
listUsers(detail = "name") {
return this.run("anope.listUsers", detail);
}
/**
+165 -17
View File
@@ -1,20 +1,151 @@
# Anope `rpc_data` RPC interface
## `anope.listAccounts`
Lists all accounts that exist on the network.
### Parameters
Index | Description
----- | -----------
0 | If specified then the level of detail to retrieve. Can be set to "full" to retrieve all information or "name" to just retrieve the account names. Defaults to "name".
### Errors
Code | Description
------ | -----------
-32099 | The specified detail level does not exist.
### Result
If the detail level is not specified or is "name" then an array of account names.
If the detail level is "full" then a mapping of account names to information about the account. See `anope.account` for more information on the data structure.
#### Example
```json
["account1", "account2", "account3"]
```
## `anope.account`
Retrieves information about the specified account.
### Parameters
Index | Description
----- | -----------
0 | A nickname belonging to the account.
### Errors
Code | Description
------ | -----------
-32099 | The specified account does not exist.
### Result
Returns a map containing information about the account.
Key | Type | Description
--- | ---- | -----------
display | string | The display nickname of the account.
email | string or null | The email address associated with the account or null if one has not been specified.
extensions | map | A key-value map of the extensions set on this account by modules.
language | string or null | The language associated with the account or null if the account uses the default language.
lastmail | int | The time at which an email was last sent for this account.
nicks | map | Information about nicknames that belong to the account keyed by the nickname.
nicks.\*.extensions | map | A key-value map of the extensions set on this nickname by modules.
nicks.\*.lastseen | int | The time at which this nickname was last used.
nicks.\*.registered | int | The time at which this nickname was registered.
nicks.\*.vhost | map or null | The vhost associated with the account or null if the user has no vhost.
nicks.\*.vhost.created | int | The time at which the vhost was created.
nicks.\*.vhost.creator | string | The nickname of the creator of the vhost.
nicks.\*.vhost.host | string | The host segment of the vhost.
nicks.\*.vhost.ident | string or null | The ident segment of the vhost or null if there is not one.
nicks.\*.vhost.mask | string | The user@host or host mask of the vhost.
opertype | map or null | The oper type associated with the account or null if they are not a services operator.
opertype.commands | array[string] | The commands that the services operator type can use.
opertype.name | string | The name of the services operator type.
opertype.privileges | array[string] | The privileges that the services operator type has.
registered | int | The time at which the account was registered.
uniqueid | uint | The unique immutable identifier of the account.
users | array[string] | The IRC users who are currently logged in to this account.
#### Example
```json
{
"display": "foo",
"email": "example@example.com",
"extensions": {
"AUTOOP": true,
"HIDE_EMAIL": true,
"HIDE_MASK": true,
"MEMO_RECEIVE": true,
"MEMO_SIGNON": true,
"NS_PRIVATE": true,
"PROTECT": true,
"PROTECT_AFTER": 69
},
"language": null,
"lastmail": 1745071858,
"nicks": {
"foo": {
"extensions": {
"NS_NO_EXPIRE": true
},
"lastseen": 1745074153,
"registered": 1745071857,
"vhost": null
},
"bar": {
"extensions": {},
"lastseen": 1745072602,
"registered": 1745071857,
"vhost": {
"created": 1745072653,
"creator": "foo",
"host": "bar.baz",
"ident": "foo",
"mask": "foo@bar.baz"
}
}
},
"opertype": {
"commands": ["hostserv/*", "operserv/session"],
"name": "Helper",
"privileges": ["chanserv/no-register-limit"]
},
"registered": 1745071857,
"uniqueid": 11085415958920757000,
"users": [
"foo"
]
}
```
## `anope.listChannels`
Lists all channels that exist on the network.
### Parameters
*None*
Index | Description
----- | -----------
0 | If specified then the level of detail to retrieve. Can be set to "full" to retrieve all information or "name" to just retrieve the channel names. Defaults to "name".
### Errors
*Only standard RPC errors*
Code | Description
------ | -----------
-32099 | The specified detail level does not exist.
### Result
Returns an array of channel names.
If the detail level is not specified or is "name" then an array of channel names.
If the detail level is "full" then a mapping of channel names to information about the channel. See `anope.channel` for more information on the data structure.
#### Example
@@ -44,13 +175,13 @@ Returns a map containing information about the channel.
Key | Type | Description
--- | ---- | -----------
created | uint | The UNIX time at which the channel was originally created.
created | int | The UNIX time at which the channel was originally created.
listmodes | map | List modes which are set on the channel keyed by the mode character.
modes | array[string] | Flag and parameter modes which are set on the channel.
name | string | The name of the channel.
registered | boolean | Whether the channel is registered.
topic | map or null | The channel topic or null if no topic is set.
topic.setat | uint | The time at which the topic was set.
topic.setat | int | The time at which the topic was set.
topic.setby | string | The nick or nuh of the user who set the topic.
topic.value | string | The text of the topic.
users | array[string] | The users that are current in the channel prefixed by their status mode prefixes.
@@ -81,15 +212,21 @@ Lists all services operators that exist on the network.
### Parameters
*None*
Index | Description
----- | -----------
0 | If specified then the level of detail to retrieve. Can be set to "full" to retrieve all information or "name" to just retrieve the services operator nicknames. Defaults to "name".
### Errors
*Only standard RPC errors*
Code | Description
------ | -----------
-32099 | The specified detail level does not exist.
### Result
Returns an array of services operator names.
If the detail level is not specified or is "name" then an array of services operator names.
If the detail level is "full" then a mapping of services operator names to information about the services operator. See `anope.oper` for more information on the data structure.
#### Example
@@ -123,7 +260,7 @@ fingerprints | array[string] or null | The client certificate fingerprint
hosts | array[string] or null | The user@ip and user@ip masks that a user must be connecting from to log in as this services operator or null if there are no host restrictions.
name | string | The name of the services operator.
operonly | boolean | Whether a user has to be a server operator to log in as this services operator.
opertype | map | The oper type associated with the services operator opertype.
opertype | map | The oper type associated with the services operator.
opertype.commands | array[string] | The commands that the services operator type can use.
opertype.name | string | The name of the services operator type.
opertype.privileges | array[string] | The privileges that the services operator type has.
@@ -154,15 +291,21 @@ Lists all servers that exist on the network.
### Parameters
*None*
Index | Description
----- | -----------
0 | If specified then the level of detail to retrieve. Can be set to "full" to retrieve all information or "name" to just retrieve the server names. Defaults to "name".
### Errors
*Only standard RPC errors*
Code | Description
------ | -----------
-32099 | The specified detail level does not exist.
### Result
Returns an array of server names.
If the detail level is not specified or is "name" then an array of server names.
If the detail level is "full" then a mapping of server names to information about the server. See `anope.server` for more information on the data structure.
#### Example
@@ -222,16 +365,21 @@ Lists all users that exist on the network.
### Parameters
*None*
Index | Description
----- | -----------
0 | If specified then the level of detail to retrieve. Can be set to "full" to retrieve all information or "name" to just retrieve the user nicknames. Defaults to "name".
### Errors
*Only standard RPC errors*
Code | Description
------ | -----------
-32099 | The specified detail level does not exist.
### Result
Returns an array of user nicknames.
If the detail level is not specified or is "name" then an array of user nicknames.
If the detail level is "full" then a mapping of user nicknames to information about the user. See `anope.user` for more information on the data structure.
#### Example
@@ -273,10 +421,10 @@ host | string | The real hostname of the user.
ident | string | The username (ident) of the user.
modes | array[string] | Flag and parameter modes which are set on the user.
nick | string | The nickname of the user.
nickchanged | uint | The time at which the user last changed their nickname.
nickchanged | int | The time at which the user last changed their nickname.
real | string | The real name of the user.
server | string | The server that the user is connected to.
signon | uint | The time at which the user connected to the network.
signon | int | The time at which the user connected to the network.
uid | string or null | The unique immutable identifier of the user or null if the IRCd does not use UIDs.
vhost | string or null | The virtual host of the user or null if they have no vhost.
vident | string or null | The virtual ident (username) of the user or null if they have no vident.
+2 -2
View File
@@ -53,7 +53,7 @@ public:
Anope::string last_usermask;
/* Last uncloaked usermask, requires nickserv/auspex to see */
Anope::string last_realhost;
time_t time_registered = Anope::CurTime;
time_t registered = Anope::CurTime;
time_t last_seen = Anope::CurTime;
/* Account this nick is tied to. Multiple nicks can be tied to a single account. */
@@ -149,7 +149,7 @@ public:
/* Last time an email was sent to this user */
time_t lastmail = 0;
/* The time this account was registered */
time_t time_registered = Anope::CurTime;
time_t registered = Anope::CurTime;
MemoInfo memos;
std::map<Anope::string, Anope::string> last_modes;
+15
View File
@@ -221,6 +221,14 @@ namespace Anope
inline bool is_number_only() const { return this->find_first_not_of("0123456789.-") == npos; }
inline bool is_pos_number_only() const { return this->find_first_not_of("0123456789.") == npos; }
/**
* In IRC messages we use a substitute (ASCII 0x1A) instead of a space
* (ASCII 0x20) so it doesn't get line wrapped when put into a message.
* The line wrapper will convert this to a space before it is sent to
* clients.
*/
inline Anope::string nobreak() const { return this->replace_all_cs("\x20", "\x1A"); }
/**
* Replace parts of the string.
*/
@@ -608,6 +616,13 @@ namespace Anope
* @return True if the message was a well formed CTCP; otherwise, false.
*/
extern CoreExport bool ParseCTCP(const Anope::string &text, Anope::string &name, Anope::string &body);
/** Replaces template variables within a string with values from a map.
* @param str The string to template from.
* @param vars The variables to replace within the string.
* @return The specified string with all variables replaced within it.
*/
extern CoreExport Anope::string Template(const Anope::string &str, const Anope::map<Anope::string> &vars);
}
/** sepstream allows for splitting token separated lists.
+1 -1
View File
@@ -139,7 +139,7 @@ public:
CommandInfo *GetCommand(const Anope::string &cname);
/** Get the command that users can use to send a message to this bot. */
Anope::string GetQueryCommand() const;
Anope::string GetQueryCommand(const Anope::string &command = "", const Anope::string &extra = "") const;
/** Find a bot by nick
* @param nick The nick
+1 -1
View File
@@ -48,7 +48,7 @@ public:
/* Set if this channel is registered. ci->c == this. Contains information relevant to the registered channel */
Serialize::Reference<ChannelInfo> ci;
/* When the channel was created */
time_t creation_time;
time_t created;
/* If the channel has just been created in a netjoin */
bool syncing = false;
/* Is configured in the conf as a channel bots should be in */
+5 -4
View File
@@ -14,6 +14,7 @@
#include "service.h"
#include "anope.h"
#include "channels.h"
#include "textproc.h"
struct CommandGroup final
{
@@ -96,7 +97,7 @@ class CoreExport Command
: public Service
{
Anope::string desc;
std::vector<Anope::string> syntax;
std::vector<std::pair<Anope::string, std::function<bool(CommandSource&)>>> syntax;
/* Allow unregistered users to use this command */
bool allow_unregistered;
/* Command requires that a user is executing it */
@@ -128,7 +129,7 @@ protected:
void SetDesc(const Anope::string &d);
void ClearSyntax();
void SetSyntax(const Anope::string &s);
void SetSyntax(const Anope::string &s, const std::function<bool(CommandSource&)> &p = nullptr);
void SendSyntax(CommandSource &);
void AllowUnregistered(bool b);
@@ -150,10 +151,10 @@ public:
*/
virtual void Execute(CommandSource &source, const std::vector<Anope::string> &params) = 0;
/** Called when HELP is requested for the client this command is on.
/** Called when help is requested for the client this command is on.
* @param source The source
*/
virtual void OnServHelp(CommandSource &source);
virtual void OnServHelp(CommandSource &source, HelpWrapper &help);
/** Requested when the user is requesting help on this command. Help on this command should be sent to the user.
* @param source The source
-6
View File
@@ -18,8 +18,6 @@
namespace Configuration
{
namespace Internal
{
class CoreExport Block
{
friend class Configuration::Conf;
@@ -56,10 +54,6 @@ namespace Configuration
template<> CoreExport const Anope::string Block::Get(const Anope::string &tag, const Anope::string &def) const;
template<> CoreExport time_t Block::Get(const Anope::string &tag, const Anope::string &def) const;
template<> CoreExport bool Block::Get(const Anope::string &tag, const Anope::string &def) const;
} // namespace Internal
typedef const Internal::Block Block;
typedef Internal::Block MutableBlock;
/** Represents a configuration file
*/
+11 -11
View File
@@ -100,18 +100,18 @@ namespace Language
} // namespace Language
/* Commonly used language strings */
#define CONFIRM_DROP _("Please confirm that you want to drop \002%s\002 with \002%s DROP %s %s\002")
#define CONFIRM_DROP _("Please confirm that you want to drop \002%s\002 with \002%s\032%s\032%s\002")
#define SERVICE_UNAVAILABLE _("Sorry, %s is temporarily unavailable.")
#define MORE_INFO _("\002%s HELP %s\002 for more information.")
#define MORE_INFO _("\002%s\002 for more information.")
#define BAD_USERHOST_MASK _("Mask must be in the form \037user\037@\037host\037.")
#define BAD_EXPIRY_TIME _("Invalid expiry time.")
#define USERHOST_MASK_TOO_WIDE _("%s coverage is too wide; Please use a more specific mask.")
#define READ_ONLY_MODE _("Services are temporarily in read-only mode.")
#define PASSWORD_INCORRECT _("Password incorrect.")
#define ACCESS_DENIED _("Access denied.")
#define MORE_OBSCURE_PASSWORD _("Please try again with a more obscure password. Passwords should not be\n" \
"something that could be easily guessed (e.g. your real name or your nick) and\n" \
"cannot contain the space or tab characters.\n")
#define MORE_OBSCURE_PASSWORD _("Please try again with a more obscure password. Passwords should not be " \
"something that could be easily guessed (e.g. your real name or your nick) and " \
"cannot contain the space or tab characters.")
#define PASSWORD_TOO_SHORT _("Your password is too short. It must be longer than %u characters.")
#define PASSWORD_TOO_LONG _("Your password is too long. It must be shorter than %u characters.")
#define NICK_NOT_REGISTERED _("Your nick isn't registered.")
@@ -127,8 +127,8 @@ namespace Language
#define UNKNOWN _("<unknown>")
#define NO_EXPIRE _("does not expire")
#define LIST_INCORRECT_RANGE _("Incorrect range specified. The correct syntax is \002#\037from\037-\037to\037\002.")
#define NICK_IS_SECURE _("This nickname is registered and protected. If it is your\n" \
"nick, type \002%s IDENTIFY \037password\037\002. Otherwise,\n" \
#define NICK_IS_SECURE _("This nickname is registered and protected. If it is your " \
"nick, type \002%s\032\037password\037\002. Otherwise, " \
"please choose a different nick.")
#define FORCENICKCHANGE_NOW _("This nickname has been registered; you may not use it.")
#define NICK_CANNOT_BE_REGISTERED _("Nickname \002%s\002 may not be registered.")
@@ -145,10 +145,10 @@ namespace Language
#define CHAN_ACCESS_LEVEL_RANGE _("Access level must be between %d and %d inclusive.")
#define CHAN_INFO_HEADER _("Information about channel \002%s\002:")
#define CHAN_EXCEPTED _("\002%s\002 matches an except on %s and cannot be banned until the except has been removed.")
#define MEMO_NEW_X_MEMO_ARRIVED _("There is a new memo on channel %s.\n" \
"Type \002%s READ %s %zu\002 to read it.")
#define MEMO_NEW_MEMO_ARRIVED _("You have a new memo from %s.\n" \
"Type \002%s READ %zu\002 to read it.")
#define MEMO_NEW_X_MEMO_ARRIVED _("There is a new memo on channel %s. " \
"Type \002%s\032%s\032%zu\002 to read it.")
#define MEMO_NEW_MEMO_ARRIVED _("You have a new memo from %s. " \
"Type \002%s\032%zu\002 to read it.")
#define MEMO_HAVE_NO_MEMOS _("You have no memos.")
#define MEMO_X_HAS_NO_MEMOS _("%s has no memos.")
#define MEMO_HAVE_NO_NEW_MEMOS _("You have no new memos.")
+7
View File
@@ -45,6 +45,13 @@ namespace Message
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override;
};
struct CoreExport Ignore final
: IRCDMessage
{
Ignore(Module *creator, const Anope::string &mname);
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override;
};
struct CoreExport Invite
: IRCDMessage
{
+132 -21
View File
@@ -1068,28 +1068,139 @@ public:
enum Implementation
{
I_IsServicesOper,
I_OnAccessAdd,
I_OnAccessClear,
I_OnAccessDel,
I_OnAddXLine,
I_OnAkickAdd,
I_OnAkickDel,
I_OnBadWordAdd,
I_OnBadWordDel,
I_OnBotAssign,
I_OnBotBan,
I_OnBotChange,
I_OnBotCreate,
I_OnBotDelete,
I_OnBotFantasy,
I_OnBotInfo,
I_OnBotKick,
I_OnBotNoFantasyAccess,
I_OnBotNotice,
I_OnBotPrivmsg,
I_OnBotUnAssign,
I_OnCanSet,
I_OnChanDrop,
I_OnChanExpire,
I_OnChangeCoreDisplay,
I_OnChanInfo,
I_OnChannelCreate,
I_OnChannelDelete,
I_OnChannelModeAdd,
I_OnChannelModeSet,
I_OnChannelModeUnset,
I_OnChannelSync,
I_OnChanRegistered,
I_OnChanSuspend,
I_OnChanUnsuspend,
I_OnCheckAuthentication,
I_OnCheckDelete,
I_OnCheckKick,
I_OnCheckModes,
I_OnCheckPriv,
I_OnCreateBot,
I_OnCreateChan,
I_OnDecrypt,
I_OnDefconLevel,
I_OnDelBot,
I_OnDelChan,
I_OnDelCore,
I_OnDeleteVHost,
I_OnDelNick,
I_OnDelXLine,
I_OnDnsRequest,
I_OnEncrypt,
I_OnExceptionAdd,
I_OnExceptionDel,
I_OnExpireTick,
I_OnFingerprint,
I_OnGroupCheckPriv,
I_OnInvite,
I_OnJoinChannel,
I_OnLeaveChannel,
I_OnLevelChange,
I_OnLoadDatabase,
I_OnLog,
I_OnLogMessage,
I_OnMemoDel,
I_OnMemoSend,
I_OnMessage,
I_OnMLock,
I_OnModuleLoad,
I_OnModuleUnload,
I_OnNewServer,
I_OnNickAddCert,
I_OnNickClearCert,
I_OnNickConfirm,
I_OnNickCoreCreate,
I_OnNickDrop,
I_OnNickEraseCert,
I_OnNickExpire,
I_OnNickGroup,
I_OnNickIdentify,
I_OnNickInfo,
I_OnNickLogout,
I_OnNickRegister,
I_OnNickSuspend,
I_OnNickUnsuspended,
I_OnNickUpdate,
I_OnNickValidate,
I_OnPartChannel,
I_OnPostCommand,
I_OnPostHelp,
I_OnPostInit,
I_OnPreUserKicked, I_OnUserKicked, I_OnReload, I_OnPreBotAssign, I_OnBotAssign, I_OnBotUnAssign, I_OnUserConnect,
I_OnNewServer, I_OnUserNickChange, I_OnPreHelp, I_OnPostHelp, I_OnPreCommand, I_OnPostCommand, I_OnSaveDatabase,
I_OnLoadDatabase, I_OnEncrypt, I_OnDecrypt, I_OnBotFantasy, I_OnBotNoFantasyAccess, I_OnBotBan, I_OnBadWordAdd,
I_OnBadWordDel, I_OnCreateBot, I_OnDelBot, I_OnBotKick, I_OnPrePartChannel, I_OnPartChannel, I_OnLeaveChannel,
I_OnJoinChannel, I_OnTopicUpdated, I_OnPreChanExpire, I_OnChanExpire, I_OnPreServerConnect, I_OnServerConnect,
I_OnPreUplinkSync, I_OnServerDisconnect, I_OnRestart, I_OnShutdown, I_OnPreNickExpire, I_OnNickExpire, I_OnDefconLevel,
I_OnExceptionAdd, I_OnExceptionDel, I_OnAddXLine, I_OnDelXLine, I_IsServicesOper, I_OnServerQuit, I_OnUserQuit,
I_OnPreUserLogoff, I_OnPostUserLogoff, I_OnBotCreate, I_OnBotChange, I_OnBotDelete, I_OnAccessDel, I_OnAccessAdd,
I_OnAccessClear, I_OnLevelChange, I_OnChanDrop, I_OnChanRegistered, I_OnChanSuspend, I_OnChanUnsuspend,
I_OnCreateChan, I_OnDelChan, I_OnChannelCreate, I_OnChannelDelete, I_OnAkickAdd, I_OnAkickDel, I_OnCheckKick,
I_OnChanInfo, I_OnCheckPriv, I_OnGroupCheckPriv, I_OnNickDrop, I_OnNickGroup, I_OnNickIdentify,
I_OnUserLogin, I_OnNickLogout, I_OnNickRegister, I_OnNickConfirm, I_OnNickSuspend, I_OnNickUnsuspended, I_OnDelNick, I_OnNickCoreCreate,
I_OnDelCore, I_OnChangeCoreDisplay, I_OnNickClearCert,
I_OnNickAddCert, I_OnNickEraseCert, I_OnNickInfo, I_OnBotInfo, I_OnCheckAuthentication, I_OnNickUpdate,
I_OnFingerprint, I_OnUserAway, I_OnInvite, I_OnDeleteVHost, I_OnSetVHost, I_OnSetDisplayedHost, I_OnMemoSend, I_OnMemoDel,
I_OnChannelModeSet, I_OnChannelModeUnset, I_OnUserModeSet, I_OnUserModeUnset, I_OnChannelModeAdd, I_OnUserModeAdd,
I_OnMLock, I_OnUnMLock, I_OnModuleLoad, I_OnModuleUnload, I_OnServerSync, I_OnUplinkSync, I_OnBotPrivmsg, I_OnBotNotice,
I_OnPrivmsg, I_OnLog, I_OnLogMessage, I_OnDnsRequest, I_OnCheckModes, I_OnChannelSync, I_OnSetCorrectModes,
I_OnSerializeCheck, I_OnSerializableConstruct, I_OnSerializableDestruct, I_OnSerializableUpdate,
I_OnSerializeTypeCreate, I_OnSetChannelOption, I_OnSetNickOption, I_OnMessage, I_OnCanSet, I_OnCheckDelete,
I_OnExpireTick, I_OnNickValidate,
I_OnPostUserLogoff,
I_OnPreBotAssign,
I_OnPreChanExpire,
I_OnPreCommand,
I_OnPreHelp,
I_OnPreNickExpire,
I_OnPrePartChannel,
I_OnPreServerConnect,
I_OnPreUplinkSync,
I_OnPreUserKicked,
I_OnPreUserLogoff,
I_OnPrivmsg,
I_OnReload,
I_OnRestart,
I_OnSaveDatabase,
I_OnSerializableConstruct,
I_OnSerializableDestruct,
I_OnSerializableUpdate,
I_OnSerializeCheck,
I_OnSerializeTypeCreate,
I_OnServerConnect,
I_OnServerDisconnect,
I_OnServerQuit,
I_OnServerSync,
I_OnSetChannelOption,
I_OnSetCorrectModes,
I_OnSetDisplayedHost,
I_OnSetNickOption,
I_OnSetVHost,
I_OnShutdown,
I_OnTopicUpdated,
I_OnUnMLock,
I_OnUplinkSync,
I_OnUserAway,
I_OnUserConnect,
I_OnUserKicked,
I_OnUserLogin,
I_OnUserModeAdd,
I_OnUserModeSet,
I_OnUserModeUnset,
I_OnUserNickChange,
I_OnUserQuit,
I_SIZE
};
+178 -100
View File
@@ -10,108 +10,186 @@
namespace SASL
{
struct Message final
{
Anope::string source;
Anope::string target;
Anope::string type;
std::vector<Anope::string> data;
};
class Mechanism;
struct Message;
class ProtocolInterface;
struct Service;
struct Session;
class Service
: public ::Service
{
public:
Service(Module *o) : ::Service(o, "SASL::Service", "sasl") { }
virtual void ProcessMessage(const Message &) = 0;
virtual Session *GetSession(const Anope::string &uid) = 0;
virtual void SendMessage(SASL::Session *session, const Anope::string &type, const Anope::string &data) = 0;
virtual void Succeed(Session *, NickCore *) = 0;
virtual void Fail(Session *) = 0;
virtual void DeleteSessions(Mechanism *, bool = false) = 0;
virtual void RemoveSession(Session *) = 0;
};
static ServiceReference<SASL::Service> service("SASL::Service", "sasl");
struct Session
{
time_t created;
Anope::string uid;
Anope::string hostname, ip;
Reference<Mechanism> mech;
Session(Mechanism *m, const Anope::string &u) : created(Anope::CurTime), uid(u), mech(m) { }
inline Anope::string GetUserInfo()
{
auto *u = User::Find(uid);
if (u)
return u->GetMask();
if (!hostname.empty() && !ip.empty())
return Anope::printf("%s (%s)", hostname.c_str(), ip.c_str());
return "A user";
};
virtual ~Session()
{
if (service)
service->RemoveSession(this);
}
};
/* PLAIN, EXTERNAL, etc */
class Mechanism
: public ::Service
{
public:
Mechanism(Module *o, const Anope::string &sname) : Service(o, "SASL::Mechanism", sname) { }
virtual Session *CreateSession(const Anope::string &uid) { return new Session(this, uid); }
virtual bool ProcessMessage(Session *session, const Message &) = 0;
virtual ~Mechanism()
{
if (service)
service->DeleteSessions(this, true);
}
};
/** Sends IRCd messages used by the SASL module. */
class ProtocolInterface
: public ::Service
{
protected:
ProtocolInterface(Module *o)
: ::Service(o, "SASL::ProtocolInterface", "sasl")
{
}
public:
/** Sends the list of SASL mechanisms to the IRCd
* @param mechs The list of SASL mechanisms.
*/
virtual void SendSASLMechanisms(std::vector<Anope::string> &mechs) { };
/** Sends a SASL message to the IRCd.
* @param message The SASL message to send.
*/
virtual void SendSASLMessage(const SASL::Message &message) = 0;
/** Sends a login or logout for \p uid to \p na.
* @param uid The uid of the user to log in.
* @param na The nick alias to log the user in as or logout if nullptr.
*/
virtual void SendSVSLogin(const Anope::string &uid, NickAlias *na) = 0;
};
/** The SASL interface implemented by the protocol modules. */
static ServiceReference<SASL::ProtocolInterface> protocol_interface("SASL::ProtocolInterface", "sasl");
/** The SASL interface implemented by ns_sasl. */
static ServiceReference<SASL::Service> service("SASL::Service", "sasl");
}
/** Represents a single SASL message. */
struct SASL::Message final
{
/** The source UID or name. */
Anope::string source;
/** The target UID or name. */
Anope::string target;
/** The type of message. */
Anope::string type;
/** One or more data parameters. */
std::vector<Anope::string> data;
};
/** Sends IRCd messages used by the SASL module. */
class SASL::ProtocolInterface
: public ::Service
{
protected:
ProtocolInterface(Module *o)
: ::Service(o, "SASL::ProtocolInterface", "sasl")
{
}
public:
/** Sends the list of SASL mechanisms to the IRCd
* @param mechs The list of SASL mechanisms.
*/
virtual void SendSASLMechanisms(std::vector<Anope::string> &mechs) { };
/** Sends a SASL message to the IRCd.
* @param message The SASL message to send.
*/
virtual void SendSASLMessage(const SASL::Message &message) = 0;
/** Sends a login or logout for \p uid to \p na.
* @param uid The uid of the user to log in.
* @param na The nick alias to log the user in as or logout if nullptr.
*/
virtual void SendSVSLogin(const Anope::string &uid, NickAlias *na) = 0;
};
/** SASL service interface. */
struct SASL::Service
: ::Service
{
Service(Module *o)
: ::Service(o, "SASL::Service", "sasl")
{
}
virtual void DeleteSessions(Mechanism *mech, bool da = false) = 0;
/** Fails a SASL session. This notifies the client and increments the
* failed attempt counter which may kill the client if the bad password
* limit has been reached.
*
* @param sess The session to fail.
*/
virtual void Fail(Session *sess) = 0;
/** Retrieves the session for the specified user identifier. */
virtual Session *GetSession(const Anope::string &uid) = 0;
/** Processes a SASL authentication message from the uplink.
* @param m The message to process.
*/
virtual void ProcessMessage(const Message &m) = 0;
/** Removes the specified SASL session from the service.
* @param sess The session to remove.
*/
virtual void RemoveSession(Session *sess) = 0;
/** Sends a SASL message for the specified session.
* @param type The type of message to send.
* @param data The contents of the SASL message.
*/
virtual void SendMessage(SASL::Session *sess, const Anope::string &type, const Anope::string &data) = 0;
/** Completes a successful authentication.
* @param sess The session which finished authentication.
* @param nc The account which has been logged into.
*/
virtual void Succeed(Session *sess, NickCore *nc) = 0;
};
/** Represents a single SASL session. */
struct SASL::Session
{
/** The time at which the session was created. */
const time_t created;
/** The hostname and IP address of the authenticating user. */
Anope::string hostname, ip;
/** A reference to the mechanism that the session is authenticating using. */
Reference<Mechanism> mech;
/** The unique identifier of the authenticating user. */
const Anope::string uid;
/** Creates a new authentication session.
* @param m The mechanism that the session is authenticating with.
* @param u The unique identifier of the authenticating user.
*/
Session(Mechanism *m, const Anope::string &u)
: created(Anope::CurTime)
, mech(m)
, uid(u)
{
}
virtual ~Session()
{
if (service)
service->RemoveSession(this);
}
/** Retrieves a description of the user this session is associated with. */
inline Anope::string GetUserInfo()
{
auto *u = User::Find(uid);
if (u)
return u->GetMask();
if (!hostname.empty() && !ip.empty())
return Anope::printf("%s (%s)", hostname.c_str(), ip.c_str());
return "A user";
};
};
/* Represents an authentication mechanism. */
class SASL::Mechanism
: public ::Service
{
protected:
/** Creates a new authentication mechanism.
* @param o The module that owns this instance.
* @param sname The name of the authentication mechanism (e.g. PLAIN).
*/
Mechanism(Module *o, const Anope::string &sname)
: Service(o, "SASL::Mechanism", sname)
{
}
public:
virtual ~Mechanism()
{
if (service)
service->DeleteSessions(this, true);
}
/** Creates a new SASL session.
* @param uid The unique identifier of the authenticating user.
*/
virtual Session *CreateSession(const Anope::string &uid)
{
return new Session(this, uid);
}
/** Processes an authentication message from the authenticating user.
* @param session The session for which the message applies.
* @param m The message sent by the user.
* @return True if the message was processed successfully or false if
* the session should be aborted.
*/
virtual bool ProcessMessage(Session *sess, const Message &m) = 0;
};
+1
View File
@@ -23,6 +23,7 @@ struct CoreExport Oper
/* Whether the user must be an IRC operator (umode +o) to be considered a services operator */
bool require_oper = true;
Anope::string password;
Anope::string password_hash;
std::vector<Anope::string> certfp;
/* Hosts allowed to use this operator block */
std::vector<Anope::string> hosts;
+4 -4
View File
@@ -107,8 +107,8 @@ public:
/* If this IRCd has unique ids, whether the IDs and nicknames are ambiguous */
bool AmbiguousID = false;
/** Can we ask the server to unban a user? */
bool CanClearBans = false;
/** Can we ask the server to remove list modes matching a user? */
std::set<Anope::string> CanClearModes;
/** Can we send tag messages? */
bool CanTagMessage = false;
@@ -304,7 +304,7 @@ public:
*/
virtual void SendOper(User *u);
virtual void SendClearBans(const MessageSource &user, Channel *c, User* u) { }
virtual void SendClearModes(const MessageSource &user, Channel *c, User* u, const Anope::string &mode) { }
virtual bool IsNickValid(const Anope::string &);
virtual bool IsChannelValid(const Anope::string &);
@@ -362,7 +362,7 @@ public:
FLAG_MAX,
};
private:
protected:
/** The name of the message (e.g. PRIVMSG). */
const Anope::string name;
+1 -1
View File
@@ -79,7 +79,7 @@ public:
Anope::string name; /* Channel name */
Anope::string desc;
time_t time_registered;
time_t registered;
time_t last_used;
Anope::string last_topic; /* The last topic that was set on this channel */
+1
View File
@@ -23,6 +23,7 @@
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iostream>
#include <list>
#include <map>
+36
View File
@@ -0,0 +1,36 @@
/*
*
* (C) 2003-2025 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*/
#pragma once
class CoreExport HelpWrapper final
{
private:
std::vector<std::pair<Anope::string, Anope::string>> entries;
size_t longest = 0;
public:
void AddEntry(const Anope::string &name, const Anope::string &desc);
void SendTo(CommandSource &source);
};
class CoreExport LineWrapper final
{
private:
std::vector<Anope::string> formatting;
const size_t max_length;
Anope::string text;
public:
LineWrapper(const Anope::string &t, size_t ml = 0);
bool GetLine(Anope::string &out);
};
+1 -1
View File
@@ -50,7 +50,7 @@ protected:
Serialize::Reference<NickCore> nc;
/* # of invalid password attempts */
unsigned short invalid_pw_count;
unsigned invalid_pw_count;
/* Time of last invalid password */
time_t invalid_pw_time;
+763 -1720
View File
File diff suppressed because it is too large Load Diff
+44 -26
View File
@@ -57,10 +57,10 @@ public:
BotInfo *bi = user->server == Me ? dynamic_cast<BotInfo *>(user) : NULL;
if (bi && Config->GetModule(this).Get<bool>("smartjoin"))
{
if (IRCD->CanClearBans)
if (IRCD->CanClearModes.count("BAN"))
{
// We can ask the IRCd to clear bans.
IRCD->SendClearBans(bi, c, bi);
IRCD->SendClearModes(bi, c, bi, "BAN");
}
else
{
@@ -135,29 +135,41 @@ public:
if (source.c)
{
source.Reply(_("\002%s\002 allows you to execute \"fantasy\" commands in the channel.\n"
"Fantasy commands are commands that can be executed from messaging a\n"
"channel, and provide a more convenient way to execute commands. Commands that\n"
"require a channel as a parameter will automatically have that parameter\n"
"given.\n"), source.service->nick.c_str());
source.Reply(_(
"\002%s\002 allows you to execute \"fantasy\" commands in the channel. "
"Fantasy commands are commands that can be executed from messaging a "
"channel, and provide a more convenient way to execute commands. Commands that "
"require a channel as a parameter will automatically have that parameter "
"given."
),
source.service->nick.c_str());
const Anope::string &fantasycharacters = Config->GetModule("fantasy").Get<const Anope::string>("fantasycharacter", "!");
if (!fantasycharacters.empty())
source.Reply(_(" \n"
"Fantasy commands may be prefixed with one of the following characters: %s\n"), fantasycharacters.c_str());
source.Reply(_(" \n"
"Available commands are:"));
{
source.Reply(" ");
source.Reply(_("Fantasy commands may be prefixed with one of the following characters: %s"),
fantasycharacters.c_str());
}
source.Reply(" ");
source.Reply(_("Available commands are:"));
}
else if (*source.service == BotServ)
{
source.Reply(_("\002%s\002 allows you to have a bot on your own channel.\n"
"It has been created for users that can't host or\n"
"configure a bot, or for use on networks that don't\n"
"allow user bots. Available commands are listed\n"
"below; to use them, type \002%s \037command\037\002. For\n"
"more information on a specific command, type\n"
"\002%s %s \037command\037\002.\n"),
BotServ->nick.c_str(), BotServ->GetQueryCommand().c_str(),
BotServ->GetQueryCommand().c_str(), source.command.c_str());
source.Reply(_(
"\002%s\002 allows you to have a bot on your own channel. "
"It has been created for users that can't host or "
"configure a bot, or for use on networks that don't "
"allow user bots. Available commands are listed "
"below; to use them, type \002%s\032\037command\037\002. For "
"more information on a specific command, type "
"\002%s\032\037command\037\002."
),
BotServ->nick.c_str(),
BotServ->GetQueryCommand().c_str(),
BotServ->GetQueryCommand({}, source.command).c_str());
source.Reply(" ");
}
return EVENT_CONTINUE;
@@ -168,14 +180,20 @@ public:
if (!params.empty() || source.c || source.service != *BotServ)
return;
source.Reply(_(" \n"
"Bot will join a channel whenever there is at least\n"
"\002%d\002 user(s) on it."), Config->GetModule(this).Get<unsigned>("minusers"));
source.Reply(" ");
source.Reply(_("Bot will join a channel whenever there is at least \002%d\002 user(s) on it."),
Config->GetModule(this).Get<unsigned>("minusers"));
const Anope::string &fantasycharacters = Config->GetModule("fantasy").Get<const Anope::string>("fantasycharacter", "!");
if (!fantasycharacters.empty())
source.Reply(_("Additionally, if fantasy is enabled fantasy commands\n"
"can be executed by prefixing the command name with\n"
"one of the following characters: %s"), fantasycharacters.c_str());
{
source.Reply(_(
"Additionally, if fantasy is enabled fantasy commands "
"can be executed by prefixing the command name with "
"one of the following characters: %s"
),
fantasycharacters.c_str());
}
}
EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const Anope::string &param) override
+18 -12
View File
@@ -76,9 +76,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Assigns the specified bot to a channel. You\n"
"can then configure the bot for the channel so it fits\n"
"your needs."));
source.Reply(_(
"Assigns the specified bot to a channel. You "
"can then configure the bot for the channel so it fits "
"your needs."
));
return true;
}
};
@@ -138,11 +140,13 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Unassigns a bot from a channel. When you use this command,\n"
"the bot won't join the channel anymore. However, bot\n"
"configuration for the channel is kept, so you will always\n"
"be able to reassign a bot later without having to reconfigure\n"
"it entirely."));
source.Reply(_(
"Unassigns a bot from a channel. When you use this command, "
"the bot won't join the channel anymore. However, bot "
"configuration for the channel is kept, so you will always "
"be able to reassign a bot later without having to reconfigure "
"it entirely."
));
return true;
}
};
@@ -197,10 +201,12 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(_(" \n"
"This option makes a channel unassignable. If a bot\n"
"is already assigned to the channel, it is unassigned\n"
"automatically when you enable it."));
source.Reply(" ");
source.Reply(_(
"This option makes a channel unassignable. If a bot "
"is already assigned to the channel, it is unassigned "
"automatically when you enable it."
));
return true;
}
};
+47 -31
View File
@@ -165,6 +165,7 @@ class BadwordsDelCallback final
BadWords *bw;
Command *c;
unsigned deleted = 0;
Anope::string lastdeleted;
bool override = false;
public:
BadwordsDelCallback(CommandSource &_source, ChannelInfo *_ci, Command *_c, const Anope::string &list) : NumberList(list, true), source(_source), ci(_ci), c(_c)
@@ -176,10 +177,20 @@ public:
~BadwordsDelCallback() override
{
if (deleted)
source.Reply(deleted, N_("Deleted %d entry from %s bad words list.", "Deleted %d entries from %s bad words list."), deleted, ci->name.c_str());
else
source.Reply(_("No matching entries on %s bad words list."), ci->name.c_str());
switch (deleted)
{
case 0:
source.Reply(_("No matching entries on %s bad words list."), ci->name.c_str());
break;
case 1:
source.Reply(_("Deleted %s from %s bad words list."), lastdeleted.c_str(), ci->name.c_str());
break;
default:
source.Reply(deleted, N_("Deleted %d entry from %s bad words list.", "Deleted %d entries from %s bad words list."), deleted, ci->name.c_str());
break;
}
}
void HandleNumber(unsigned Number) override
@@ -187,7 +198,8 @@ public:
if (!bw || !Number || Number > bw->GetBadWordCount())
return;
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "DEL " << bw->GetBadWord(Number - 1)->word;
lastdeleted = bw->GetBadWord(Number - 1)->word;
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "DEL " << lastdeleted;
++deleted;
bw->EraseBadWord(Number - 1);
}
@@ -435,34 +447,38 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Maintains the \002bad words list\002 for a channel. The bad\n"
"words list determines which words are to be kicked\n"
"when the bad words kicker is enabled. For more information,\n"
"type \002%s HELP KICK %s\002.\n"
" \n"
"The \002ADD\002 command adds the given word to the\n"
"bad words list. If SINGLE is specified, a kick will be\n"
"done only if a user says the entire word. If START is\n"
"specified, a kick will be done if a user says a word\n"
"that starts with \037word\037. If END is specified, a kick\n"
"will be done if a user says a word that ends with\n"
"\037word\037. If you don't specify anything, a kick will\n"
"be issued every time \037word\037 is said by a user.\n"
" \n"), source.service->GetQueryCommand().c_str(), source.command.c_str());
source.Reply(_("The \002DEL\002 command removes the given word from the\n"
"bad words list. If a list of entry numbers is given, those\n"
"entries are deleted. (See the example for LIST below.)\n"
" \n"
"The \002LIST\002 command displays the bad words list. If\n"
"a wildcard mask is given, only those entries matching the\n"
"mask are displayed. If a list of entry numbers is given,\n"
source.Reply(_(
"Maintains the \002bad words list\002 for a channel. The bad "
"words list determines which words are to be kicked "
"when the bad words kicker is enabled. For more information, "
"type \002%s\032KICK\032%s\002."
"\n\n"
"The \002ADD\002 command adds the given word to the "
"bad words list. If SINGLE is specified, a kick will be "
"done only if a user says the entire word. If START is "
"specified, a kick will be done if a user says a word "
"that starts with \037word\037. If END is specified, a kick "
"will be done if a user says a word that ends with "
"\037word\037. If you don't specify anything, a kick will "
"be issued every time \037word\037 is said by a user."
"\n\n"
"The \002DEL\002 command removes the given word from the "
"bad words list. If a list of entry numbers is given, those "
"entries are deleted. (See the example for LIST below.)"
"\n\n"
"The \002LIST\002 command displays the bad words list. If "
"a wildcard mask is given, only those entries matching the "
"mask are displayed. If a list of entry numbers is given, "
"only those entries are shown; for example:\n"
" \002#channel LIST 2-5,7-9\002\n"
" \002#channel\032LIST\0322-5,7-9\002\n"
" Lists bad words entries numbered 2 through 5 and\n"
" 7 through 9.\n"
" \n"
"The \002CLEAR\002 command clears all entries from the\n"
"bad words list."));
" 7 through 9."
"\n\n"
"The \002CLEAR\002 command clears all entries from the "
"bad words list."
),
source.service->GetQueryCommand("generic/help").c_str(),
source.command.nobreak().c_str());
return true;
}
};
+22 -17
View File
@@ -347,23 +347,28 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Allows Services Operators to create, modify, and delete\n"
"bots that users will be able to use on their own\n"
"channels.\n"
" \n"
"\002BOT ADD\002 adds a bot with the given nickname, username,\n"
"hostname and realname. Since no integrity checks are done\n"
"for these settings, be really careful.\n"
" \n"
"\002BOT CHANGE\002 allows you to change the nickname, username, hostname\n"
"or realname of a bot without deleting it (and\n"
"all the data associated with it).\n"
" \n"
"\002BOT DEL\002 removes the given bot from the bot list.\n"
" \n"
"\002Note\002: You cannot create a bot with a nick that is\n"
"currently registered. If an unregistered user is currently\n"
"using the nick, they will be killed."));
source.Reply(_(
"Allows Services Operators to create, modify, and delete "
"bots that users will be able to use on their own "
"channels."
"\n\n"
"\002%s\032ADD\002 adds a bot with the given nickname, username, "
"hostname and realname. Since no integrity checks are done "
"for these settings, be really careful."
"\n\n"
"\002%s\032CHANGE\002 allows you to change the nickname, username, hostname "
"or realname of a bot without deleting it (and "
"all the data associated with it)."
"\n\n"
"\002%s\032DEL\002 removes the given bot from the bot list."
"\n\n"
"\002Note\002: You cannot create a bot with a nick that is "
"currently registered. If an unregistered user is currently "
"using the nick, they will be killed."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
+17 -11
View File
@@ -70,8 +70,12 @@ public:
list.Process(replies);
if (!count)
source.Reply(_("There are no bots available at this time.\n"
"Ask a Services Operator to create one!"));
{
source.Reply(_(
"There are no bots available at this time. "
"Ask a Services Operator to create one!"
));
}
else
{
source.Reply(_("Bot list:"));
@@ -87,15 +91,17 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Lists all available bots on this network.\n"
"\n"
"If the OPERONLY, UNUSED or VANITY options are given only\n"
"bots which, respectively, are oper-only, unused or were\n"
"added at runtime will be displayed. If multiple options are\n"
"given, all nicks matching at least one option will be\n"
"displayed.\n"
"\n"
"Note that these options are limited to \037Services Operators\037."));
source.Reply(_(
"Lists all available bots on this network."
"\n\n"
"If the OPERONLY, UNUSED or VANITY options are given only "
"bots which, respectively, are oper-only, unused or were "
"added at runtime will be displayed. If multiple options are "
"given, all nicks matching at least one option will be "
"displayed."
"\n\n"
"Note that these options are limited to \037Services Operators\037."
));
return true;
}
};
+4 -2
View File
@@ -122,8 +122,10 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Makes the bot do the equivalent of a \"/me\" command\n"
"on the specified channel using the specified text."));
source.Reply(_(
"Makes the bot do the equivalent of a \"/me\" command "
"on the specified channel using the specified text."
));
return true;
}
};
+7 -5
View File
@@ -104,11 +104,13 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Allows you to see %s information about a channel or a bot.\n"
"If the parameter is a channel, then you'll get information\n"
"such as enabled kickers. If the parameter is a nick,\n"
"you'll get information about a bot, such as creation\n"
"time or number of channels it is on."), source.service->nick.c_str());
source.Reply(_(
"Allows you to see %s information about a channel or a bot. "
"If the parameter is a channel, then you'll get information "
"such as enabled kickers. If the parameter is a nick, "
"you'll get information about a bot, such as creation "
"time or number of channels it is on."
), source.service->nick.c_str());
return true;
}
+179 -108
View File
@@ -139,6 +139,7 @@ public:
source.Reply(" ");
source.Reply(_("Configures bot kickers. \037option\037 can be one of:"));
HelpWrapper help;
Anope::string this_name = source.command;
for (const auto &[c_name, info] : source.service->commands)
{
@@ -148,17 +149,20 @@ public:
if (command)
{
source.command = c_name;
command->OnServHelp(source);
command->OnServHelp(source, help);
}
}
}
help.SendTo(source);
source.Reply(_("Type \002%s HELP %s \037option\037\002 for more information\n"
"on a specific option.\n"
" \n"
"Note: access to this command is controlled by the\n"
"level SET."), source.service->GetQueryCommand().c_str(), this_name.c_str());
source.Reply(_(
"Type \002%s\032\037option\037\002 for more information "
"on a specific option."
"\n\n"
"Note: access to this command is controlled by the "
"level SET."
),
source.service->GetQueryCommand("generic/help", this_name).c_str());
return true;
}
};
@@ -220,8 +224,10 @@ protected:
val = true;
if (kd->ttb[ttb_idx])
source.Reply(_("Bot will now kick for \002%s\002, and will place a ban\n"
"after %d kicks for the same user."), optname.c_str(), kd->ttb[ttb_idx]);
{
source.Reply(_("Bot will now kick for \002%s\002, and will place a ban after %d kicks for the same user."),
optname.c_str(), kd->ttb[ttb_idx]);
}
else
source.Reply(_("Bot will now kick for \002%s\002."), optname.c_str());
@@ -267,13 +273,16 @@ public:
this->SendSyntax(source);
source.Reply(" ");
BotInfo *bi = Config->GetClient("BotServ");
source.Reply(_("Sets the AMSG kicker on or off. When enabled, the bot will\n"
"kick users who send the same message to multiple channels\n"
"where %s bots are.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before they get banned. Don't give ttb to disable\n"
"the ban system once activated."), bi ? bi->nick.c_str() : "BotServ");
source.Reply(_(
"Sets the AMSG kicker on or off. When enabled, the bot will "
"kick users who send the same message to multiple channels "
"where %s bots are."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before they get banned. Don't give ttb to disable "
"the ban system once activated."
),
bi ? bi->nick.c_str() : "BotServ");
return true;
}
};
@@ -304,16 +313,20 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the bad words kicker on or off. When enabled, this\n"
"option tells the bot to kick users who say certain words\n"
"on the channels.\n"
"You can define bad words for your channel using the\n"
"\002BADWORDS\002 command. Type \002%s HELP BADWORDS\002 for\n"
"more information.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."), source.service->GetQueryCommand().c_str());
source.Reply(_(
"Sets the bad words kicker on or off. When enabled, this "
"option tells the bot to kick users who say certain words "
"on the channels."
"\n\n"
"You can define bad words for your channel using the "
"\002BADWORDS\002 command. Type \002%s\032BADWORDS\002 for "
"more information."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
),
source.service->GetQueryCommand("generic/help").c_str());
return true;
}
};
@@ -343,12 +356,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the bolds kicker on or off. When enabled, this\n"
"option tells the bot to kick users who use bolds.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the bolds kicker on or off. When enabled, this "
"option tells the bot to kick users who use bolds."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -400,12 +415,23 @@ public:
kd->caps = true;
if (kd->ttb[TTB_CAPS])
source.Reply(_("Bot will now kick for \002caps\002 (they must constitute at least\n"
"%d characters and %d%% of the entire message), and will\n"
"place a ban after %d kicks for the same user."), kd->capsmin, kd->capspercent, kd->ttb[TTB_CAPS]);
{
source.Reply(_(
"Bot will now kick for \002caps\002 (they must constitute at least "
"%d characters and %d%% of the entire message), and will "
"place a ban after %d kicks for the same user."
),
kd->capsmin,
kd->capspercent,
kd->ttb[TTB_CAPS]);
}
else
source.Reply(_("Bot will now kick for \002caps\002 (they must constitute at least\n"
"%d characters and %d%% of the entire message)."), kd->capsmin, kd->capspercent);
source.Reply(_(
"Bot will now kick for \002caps\002 (they must constitute at least "
"%d characters and %d%% of the entire message)."
),
kd->capsmin,
kd->capspercent);
}
else
{
@@ -420,17 +446,20 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the caps kicker on or off. When enabled, this\n"
"option tells the bot to kick users who are talking in\n"
"CAPS.\n"
"The bot kicks only if there are at least \002min\002 caps\n"
"and they constitute at least \002percent\002%% of the total\n"
"text line (if not given, it defaults to 10 characters\n"
"and 25%%).\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the caps kicker on or off. When enabled, this "
"option tells the bot to kick users who are talking in "
"CAPS."
"\n\n"
"The bot kicks only if there are at least \002min\002 caps "
"and they constitute at least \002percent\002%% of the total "
"text line (if not given, it defaults to 10 characters "
"and 25%%)."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -460,12 +489,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the colors kicker on or off. When enabled, this\n"
"option tells the bot to kick users who use colors.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the colors kicker on or off. When enabled, this "
"option tells the bot to kick users who use colors."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -520,8 +551,15 @@ public:
kd->flood = true;
if (kd->ttb[TTB_FLOOD])
source.Reply(_("Bot will now kick for \002flood\002 (%d lines in %d seconds\n"
"and will place a ban after %d kicks for the same user."), kd->floodlines, kd->floodsecs, kd->ttb[TTB_FLOOD]);
{
source.Reply(_(
"Bot will now kick for \002flood\002 (%d lines in %d seconds "
"and will place a ban after %d kicks for the same user."
),
kd->floodlines,
kd->floodsecs,
kd->ttb[TTB_FLOOD]);
}
else
source.Reply(_("Bot will now kick for \002flood\002 (%d lines in %d seconds)."), kd->floodlines, kd->floodsecs);
}
@@ -540,14 +578,15 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the flood kicker on or off. When enabled, this\n"
"option tells the bot to kick users who are flooding\n"
"the channel using at least \002ln\002 lines in \002secs\002 seconds\n"
"(if not given, it defaults to 6 lines in 10 seconds).\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the flood kicker on or off. When enabled, this "
"option tells the bot to kick users who are flooding "
"the channel using at least \002ln\002 lines in \002secs\002 seconds "
"(if not given, it defaults to 6 lines in 10 seconds). "
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."));
return true;
}
};
@@ -577,12 +616,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the italics kicker on or off. When enabled, this\n"
"option tells the bot to kick users who use italics.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the italics kicker on or off. When enabled, this "
"option tells the bot to kick users who use italics. "
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -631,22 +672,42 @@ public:
if (kd->ttb[TTB_REPEAT])
{
if (kd->repeattimes != 1)
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d times), and will place a ban after %d\n"
"kicks for the same user."), kd->repeattimes, kd->ttb[TTB_REPEAT]);
{
source.Reply(_(
"Bot will now kick for \002repeats\002 (users that repeat the "
"same message %d times), and will place a ban after %d "
"kicks for the same user."
),
kd->repeattimes,
kd->ttb[TTB_REPEAT]);
}
else
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d time), and will place a ban after %d\n"
"kicks for the same user."), kd->repeattimes, kd->ttb[TTB_REPEAT]);
source.Reply(_(
"Bot will now kick for \002repeats\002 (users that repeat the "
"same message %d time), and will place a ban after %d "
"kicks for the same user."
),
kd->repeattimes,
kd->ttb[TTB_REPEAT]);
}
else
{
if (kd->repeattimes != 1)
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d times)."), kd->repeattimes);
{
source.Reply(_(
"Bot will now kick for \002repeats\002 (users that repeat the "
"same message %d times)."
),
kd->repeattimes);
}
else
source.Reply(_("Bot will now kick for \002repeats\002 (users that repeat the\n"
"same message %d time)."), kd->repeattimes);
{
source.Reply(_(
"Bot will now kick for \002repeats\002 (users that repeat the "
"same message %d time)."
),
kd->repeattimes);
}
}
}
else if (params[1].equals_ci("OFF"))
@@ -664,14 +725,16 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the repeat kicker on or off. When enabled, this\n"
"option tells the bot to kick users who are repeating\n"
"themselves \002num\002 times (if num is not given, it\n"
"defaults to 3).\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the repeat kicker on or off. When enabled, this "
"option tells the bot to kick users who are repeating "
"themselves \002num\002 times (if num is not given, it "
"defaults to 3)."
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -701,12 +764,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the reverses kicker on or off. When enabled, this\n"
"option tells the bot to kick users who use reverses.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the reverses kicker on or off. When enabled, this "
"option tells the bot to kick users who use reverses. "
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -736,12 +801,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the underlines kicker on or off. When enabled, this\n"
"option tells the bot to kick users who use underlines.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."));
source.Reply(_(
"Sets the underlines kicker on or off. When enabled, this "
"option tells the bot to kick users who use underlines. "
"\n\n"
"\037ttb\037 is the number of times a user can be kicked "
"before it gets banned. Don't give ttb to disable "
"the ban system once activated."
));
return true;
}
};
@@ -804,10 +871,12 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(_(" \n"
"Enables or disables \002ops protection\002 mode on a channel.\n"
"When it is enabled, ops won't be kicked by the bot\n"
"even if they don't match the NOKICK level."));
source.Reply(" ");
source.Reply(_(
"Enables or disables \002ops protection\002 mode on a channel. "
"When it is enabled, ops won't be kicked by the bot "
"even if they don't match the NOKICK level."
));
return true;
}
};
@@ -870,10 +939,12 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(_(" \n"
"Enables or disables \002voices protection\002 mode on a channel.\n"
"When it is enabled, voices won't be kicked by the bot\n"
"even if they don't match the NOKICK level."));
source.Reply(" ");
source.Reply(_(
"Enables or disables \002voices protection\002 mode on a channel. "
"When it is enabled, voices won't be kicked by the bot "
"even if they don't match the NOKICK level."
));
return true;
}
};
+24 -14
View File
@@ -30,11 +30,15 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Configures bot options.\n"
" \n"
"Available options:"));
source.Reply(_(
"Configures bot options."
"\n\n"
"Available options:"
));
bool hide_privileged_commands = Config->GetBlock("options").Get<bool>("hideprivilegedcommands"),
hide_registered_commands = Config->GetBlock("options").Get<bool>("hideregisteredcommands");
HelpWrapper help;
Anope::string this_name = source.command;
for (const auto &[c_name, info] : source.service->commands)
{
@@ -54,12 +58,14 @@ public:
continue;
source.command = c_name;
command->OnServHelp(source);
command->OnServHelp(source, help);
}
}
}
source.Reply(_("Type \002%s HELP %s \037option\037\002 for more information on a\n"
"particular option."), source.service->GetQueryCommand().c_str(), this_name.c_str());
help.SendTo(source);
source.Reply(_("Type \002%s\032\037option\037\002 for more information on a particular option."),
source.service->GetQueryCommand("generic/help", this_name).c_str());
return true;
}
@@ -150,11 +156,13 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(_(" \n"
"Sets the time bot bans expire in. If enabled, any bans placed by\n"
"bots, such as flood kicker, badwords kicker, etc. will automatically\n"
"be removed after the given time. Set to 0 to disable bans from\n"
"automatically expiring."));
source.Reply(" ");
source.Reply(_(
"Sets the time bot bans expire in. If enabled, any bans placed by "
"bots, such as flood kicker, badwords kicker, etc. will automatically "
"be removed after the given time. Set to 0 to disable bans from "
"automatically expiring."
));
return true;
}
};
@@ -203,9 +211,11 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(_(" \n"
"This option prevents a bot from being assigned to a\n"
"channel by users that aren't IRC Operators."));
source.Reply(" ");
source.Reply(_(
"This option prevents a bot from being assigned to a "
"channel by users that aren't IRC Operators."
));
return true;
}
};
+37 -22
View File
@@ -260,14 +260,19 @@ public:
{
if (!params.empty() || source.c || source.service != *ChanServ)
return EVENT_CONTINUE;
source.Reply(_("\002%s\002 allows you to register and control various\n"
"aspects of channels. %s can often prevent\n"
"malicious users from \"taking over\" channels by limiting\n"
"who is allowed channel operator privileges. Available\n"
"commands are listed below; to use them, type\n"
"\002%s \037command\037\002. For more information on a\n"
"specific command, type \002%s HELP \037command\037\002.\n"),
ChanServ->nick.c_str(), ChanServ->nick.c_str(), ChanServ->GetQueryCommand().c_str(), ChanServ->GetQueryCommand().c_str());
source.Reply(_(
"\002%s\002 allows you to register and control various "
"aspects of channels. %s can often prevent "
"malicious users from \"taking over\" channels by limiting "
"who is allowed channel operator privileges. Available "
"commands are listed below; to use them, type "
"\002%s\032\037command\037\002. For more information on a "
"specific command, type \002%s\032\037command\037\002."
),
ChanServ->nick.c_str(),
ChanServ->nick.c_str(),
ChanServ->GetQueryCommand().c_str(),
ChanServ->GetQueryCommand("generic/help").c_str());
return EVENT_CONTINUE;
}
@@ -275,17 +280,27 @@ public:
{
if (!params.empty() || source.c || source.service != *ChanServ)
return;
time_t chanserv_expire = Config->GetModule(this).Get<time_t>("expire", "30d");
if (chanserv_expire >= 86400)
source.Reply(_(" \n"
"Note that any channel which is not used for %lu days\n"
"(i.e. which no user on the channel's access list enters\n"
"for that period of time) will be automatically dropped."), (unsigned long)chanserv_expire / 86400);
if (chanserv_expire)
{
source.Reply(" ");
source.Reply(_(
"Note that any channel which is not used for %s "
"(i.e. which no user on the channel's access list enters "
"for that period of time) will be automatically dropped."
),
Anope::Duration(chanserv_expire, source.nc).c_str());
}
if (source.IsServicesOper())
source.Reply(_(" \n"
"Services Operators can also, depending on their access drop\n"
"any channel, view (and modify) the access, levels and akick\n"
"lists and settings for any channel."));
{
source.Reply(" ");
source.Reply(_(
"Services Operators can also, depending on their access drop "
"any channel, view (and modify) the access, levels and akick "
"lists and settings for any channel."
));
}
}
void OnCheckModes(Reference<Channel> &c) override
@@ -402,7 +417,7 @@ public:
continue;
bool c;
ci->c = Channel::FindOrCreate(ci->name, c, ci->time_registered);
ci->c = Channel::FindOrCreate(ci->name, c, ci->registered);
ci->c->syncing |= created;
if (perm)
@@ -437,10 +452,10 @@ public:
void OnJoinChannel(User *u, Channel *c) override
{
if (always_lower && c->ci && c->creation_time > c->ci->time_registered)
if (always_lower && c->ci && c->created > c->ci->registered)
{
Log(LOG_DEBUG) << "Changing TS of " << c->name << " from " << c->creation_time << " to " << c->ci->time_registered;
c->creation_time = c->ci->time_registered;
Log(LOG_DEBUG) << "Changing TS of " << c->name << " from " << c->created << " to " << c->ci->registered;
c->created = c->ci->registered;
IRCD->SendChannel(c);
c->Reset();
}
@@ -448,7 +463,7 @@ public:
EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) override
{
if (!always_lower && Anope::CurTime == c->creation_time && c->ci && setter.GetUser() && !setter.GetUser()->server->IsULined())
if (!always_lower && Anope::CurTime == c->created && c->ci && setter.GetUser() && !setter.GetUser()->server->IsULined())
{
ChanUserContainer *cu = c->FindUser(setter.GetUser());
ChannelMode *cm = ModeManager::FindChannelModeByName("OP");
+135 -115
View File
@@ -84,6 +84,38 @@ AccessAccessProvider *AccessAccessProvider::me;
class CommandCSAccess final
: public Command
{
private:
static void AddEntry(ListFormatter &list, const ChannelInfo *ci, const ChanAccess *access, unsigned number)
{
Anope::string timebuf;
if (ci->c)
{
for (const auto &[_, cuc] : ci->c->users)
{
ChannelInfo *p;
if (access->Matches(cuc->user, cuc->user->Account(), p))
timebuf = "Now";
}
}
if (timebuf.empty())
{
if (access->last_seen == 0)
timebuf = "Never";
else
timebuf = Anope::strftime(access->last_seen, NULL, true);
}
ListFormatter::ListEntry entry;
entry["Number"] = Anope::ToString(number);
entry["Level"] = access->AccessSerialize();
entry["Mask"] = access->Mask();
entry["By"] = access->creator;
entry["Last seen"] = timebuf;
entry["Description"] = access->description;
list.AddEntry(entry);
}
void DoAdd(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
{
Anope::string mask = params[2];
@@ -284,7 +316,11 @@ class CommandCSAccess final
else
{
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "to delete " << Nicks;
source.Reply(deleted, N_("Deleted %d entry from %s access list.", "Deleted %d entries from %s access list."), deleted, ci->name.c_str());
if (deleted == 1)
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());
}
}
@@ -377,32 +413,7 @@ class CommandCSAccess final
const ChanAccess *access = ci->GetAccess(number - 1);
Anope::string timebuf;
if (ci->c)
{
for (const auto &[_, cuc] : ci->c->users)
{
ChannelInfo *p;
if (access->Matches(cuc->user, cuc->user->Account(), p))
timebuf = "Now";
}
}
if (timebuf.empty())
{
if (access->last_seen == 0)
timebuf = "Never";
else
timebuf = Anope::strftime(access->last_seen, NULL, true);
}
ListFormatter::ListEntry entry;
entry["Number"] = Anope::ToString(number);
entry["Level"] = access->AccessSerialize();
entry["Mask"] = access->Mask();
entry["By"] = access->creator;
entry["Last seen"] = timebuf;
entry["Description"] = access->description;
this->list.AddEntry(entry);
AddEntry(this->list, ci, access, number);
}
}
nl_list(list, ci, nick);
@@ -417,32 +428,7 @@ class CommandCSAccess final
if (!nick.empty() && !Anope::Match(access->Mask(), nick))
continue;
Anope::string timebuf;
if (ci->c)
{
for (auto &[_, cuc] : ci->c->users)
{
ChannelInfo *p;
if (access->Matches(cuc->user, cuc->user->Account(), p))
timebuf = "Now";
}
}
if (timebuf.empty())
{
if (access->last_seen == 0)
timebuf = "Never";
else
timebuf = Anope::strftime(access->last_seen, NULL, true);
}
ListFormatter::ListEntry entry;
entry["Number"] = Anope::ToString(i + 1);
entry["Level"] = access->AccessSerialize();
entry["Mask"] = access->Mask();
entry["By"] = access->creator;
entry["Last seen"] = timebuf;
entry["Description"] = access->description;
list.AddEntry(entry);
AddEntry(list, ci, access, i + 1);
}
}
@@ -582,52 +568,76 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Maintains the \002access list\002 for a channel. The access\n"
"list specifies which users are allowed chanop status or\n"
"access to %s commands on the channel. Different\n"
"user levels allow for access to different subsets of\n"
"privileges. Any registered user not on the access list has\n"
"a user level of 0, and any unregistered user has a user level\n"
"of -1."), source.service->nick.c_str());
source.Reply(" ");
source.Reply(_("The \002ACCESS ADD\002 command adds the given mask to the\n"
"access list with the given user level; if the mask is\n"
"already present on the list, its access level is changed to\n"
"the level specified in the command. The \037level\037 specified\n"
"may be a numerical level or the name of a privilege (eg AUTOOP).\n"
"When a user joins the channel the access they receive is from the\n"
"highest level entry in the access list."));
source.Reply(_(
"Maintains the \002access list\002 for a channel. The access "
"list specifies which users are allowed chanop status or "
"access to %s commands on the channel. Different "
"user levels allow for access to different subsets of "
"privileges. Any registered user not on the access list has "
"a user level of 0, and any unregistered user has a user level "
"of -1."
"\n\n"
"The \002%s\032ADD\002 command adds the given mask to the "
"access list with the given user level; if the mask is "
"already present on the list, its access level is changed to "
"the level specified in the command. The \037level\037 specified "
"may be a numerical level or the name of a privilege (eg AUTOOP). "
"When a user joins the channel the access they receive is from the "
"highest level entry in the access list."
),
source.service->nick.c_str(),
source.command.nobreak().c_str());
if (!Config->GetModule("chanserv").Get<bool>("disallow_channel_access"))
source.Reply(_("The given mask may also be a channel, which will use the\n"
"access list from the other channel up to the given \037level\037."));
{
source.Reply(_(
"The given mask may also be a channel, which will use the "
"access list from the other channel up to the given \037level\037."
));
}
source.Reply(" ");
source.Reply(_("The \002ACCESS DEL\002 command removes the given nick from the\n"
"access list. If a list of entry numbers is given, those\n"
"entries are deleted. (See the example for LIST below.)\n"
"You may remove yourself from an access list, even if you\n"
"do not have access to modify that list otherwise."));
source.Reply(" ");
source.Reply(_("The \002ACCESS LIST\002 command displays the access list. If\n"
"a wildcard mask is given, only those entries matching the\n"
"mask are displayed. If a list of entry numbers is given,\n"
source.Reply(_(
"The \002%s\032DEL\002 command removes the given nick from the "
"access list. If a list of entry numbers is given, those "
"entries are deleted. (See the example for LIST below.) "
"You may remove yourself from an access list, even if you "
"do not have access to modify that list otherwise."
"\n\n"
"The \002%s\032LIST\002 command displays the access list. If "
"a wildcard mask is given, only those entries matching the "
"mask are displayed. If a list of entry numbers is given, "
"only those entries are shown; for example:\n"
" \002ACCESS #channel LIST 2-5,7-9\002\n"
" \002%s\032#channel\032LIST\0322-5,7-9\002\n"
" Lists access entries numbered 2 through 5 and\n"
" 7 through 9.\n"
" \n"
"The \002ACCESS VIEW\002 command displays the access list similar\n"
"to \002ACCESS LIST\002 but shows the creator and last used time.\n"
" \n"
"The \002ACCESS CLEAR\002 command clears all entries of the\n"
"access list."));
source.Reply(" ");
" 7 through 9."
"\n\n"
"The \002%s\032VIEW\002 command displays the access list similar "
"to \002%s\032LIST\002 but shows the creator and last used time."
"\n\n"
"The \002%s\032CLEAR\002 command clears all entries of the "
"access list."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
BotInfo *bi;
Anope::string cmd;
if (Command::FindCommandFromService("chanserv/levels", bi, cmd))
source.Reply(_("\002User access levels\002 can be seen by using the\n"
"\002%s\002 command; type \002%s HELP LEVELS\002 for\n"
"information."), cmd.c_str(), bi->GetQueryCommand().c_str());
{
source.Reply(" ");
source.Reply(_(
"\002User access levels\002 can be seen by using the "
"\002%s\002 command; type \002%s\032LEVELS\002 for "
"information."
),
cmd.c_str(),
bi->GetQueryCommand("generic/help").c_str());
}
return true;
}
};
@@ -662,8 +672,8 @@ class CommandCSLevels final
Privilege *p = PrivilegeManager::FindPrivilege(what);
if (p == NULL)
{
source.Reply(_("Setting \002%s\002 not known. Type \002%s HELP LEVELS\002 for a list of valid settings."),
what.c_str(), source.service->GetQueryCommand().c_str());
source.Reply(_("Setting \002%s\002 not known. Type \002%s\032LEVELS\002 for a list of valid settings."),
what.c_str(), source.service->GetQueryCommand("generic/help").c_str());
}
else
{
@@ -705,8 +715,8 @@ class CommandCSLevels final
return;
}
source.Reply(_("Setting \002%s\002 not known. Type \002%s HELP LEVELS\002 for a list of valid settings."),
what.c_str(), source.service->GetQueryCommand().c_str());
source.Reply(_("Setting \002%s\002 not known. Type \002%s\032LEVELS\002 for a list of valid settings."),
what.c_str(), source.service->GetQueryCommand("generic/help").c_str());
}
static void DoList(CommandSource &source, ChannelInfo *ci)
@@ -835,25 +845,35 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("The \002LEVELS\002 command allows fine control over the meaning of\n"
"the numeric access levels used for channels. With this\n"
"command, you can define the access level required for most\n"
"of %s's functions. (The \002SET FOUNDER\002 and this command\n"
"are always restricted to the channel founder.)\n"
" \n"
"\002LEVELS SET\002 allows the access level for a function or group of\n"
"functions to be changed. \002LEVELS DISABLE\002 (or \002DIS\002 for short)\n"
"disables an automatic feature or disallows access to a\n"
"function by anyone, INCLUDING the founder (although, the founder\n"
"can always re-enable it). Use \002LEVELS SET founder\002 to make a level\n"
"founder only.\n"
" \n"
"\002LEVELS LIST\002 shows the current levels for each function or\n"
"group of functions. \002LEVELS RESET\002 resets the levels to the\n"
"default levels of a newly-created channel.\n"
" \n"
"For a list of the features and functions whose levels can be\n"
"set, see \002HELP LEVELS DESC\002."), source.service->nick.c_str());
source.Reply(_(
"The \002%s\002 command allows fine control over the meaning of "
"the numeric access levels used for channels. With this "
"command, you can define the access level required for most "
"of %s's functions. (The \002SET\032FOUNDER\002 and this command "
"are always restricted to the channel founder)."
"\n\n"
"\002%s\032SET\002 allows the access level for a function or group of "
"functions to be changed. \002%s\032DISABLE\002 (or \002DIS\002 for short) "
"disables an automatic feature or disallows access to a "
"function by anyone, INCLUDING the founder (although, the founder "
"can always re-enable it). Use \002%s\032SET founder\002 to make a level "
"founder only."
"\n\n"
"\002%s\032LIST\002 shows the current levels for each function or "
"group of functions. \002%s\032RESET\002 resets the levels to the "
"default levels of a newly-created channel."
"\n\n"
"For a list of the features and functions whose levels can be "
"set, see \002HELP\032%s\032DESC\002."
),
source.service->nick.c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
}
return true;
}
@@ -880,7 +900,7 @@ public:
for (int i = 0; i < conf.CountBlock("privilege"); ++i)
{
Configuration::Block &priv = conf.GetBlock("privilege", i);
const auto &priv = conf.GetBlock("privilege", i);
const Anope::string &pname = priv.Get<const Anope::string>("name");
+65 -40
View File
@@ -211,6 +211,7 @@ class CommandCSAKick final
ChannelInfo *ci;
Command *c;
unsigned deleted = 0;
Anope::string lastdeleted;
AccessGroup ag;
public:
AkickDelCallback(CommandSource &_source, ChannelInfo *_ci, Command *_c, const Anope::string &list) : NumberList(list, true), source(_source), ci(_ci), c(_c), ag(source.AccessFor(ci))
@@ -219,10 +220,20 @@ class CommandCSAKick final
~AkickDelCallback() override
{
if (deleted)
source.Reply(deleted, N_("Deleted %d entry from %s autokick list.", "Deleted %d entries from %s autokick list."), deleted, ci->name.c_str());
else
source.Reply(_("No matching entries on %s autokick list."), ci->name.c_str());
switch (deleted)
{
case 0:
source.Reply(_("No matching entries on %s autokick list."), ci->name.c_str());
break;
case 1:
source.Reply(_("Deleted %s from %s autokick list."), lastdeleted.c_str(), ci->name.c_str());
break;
default:
source.Reply(deleted, N_("Deleted %d entry from %s autokick list.", "Deleted %d entries from %s autokick list."), deleted, ci->name.c_str());
break;
}
}
void HandleNumber(unsigned number) override
@@ -235,7 +246,8 @@ class CommandCSAKick final
FOREACH_MOD(OnAkickDel, (source, ci, akick));
bool override = !ag.HasPriv("AKICK");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "to delete " << (akick->nc ? akick->nc->display : akick->mask);
lastdeleted = (akick->nc ? akick->nc->display : akick->mask);
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "to delete " << lastdeleted;
++deleted;
ci->EraseAkick(number - 1);
@@ -488,40 +500,51 @@ public:
BotInfo *bi = Config->GetClient("NickServ");
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Maintains the \002AutoKick list\002 for a channel. If a user\n"
"on the AutoKick list attempts to join the channel,\n"
"%s will ban that user from the channel, then kick\n"
"the user.\n"
" \n"
"The \002AKICK ADD\002 command adds the given nick or usermask\n"
"to the AutoKick list. If a \037reason\037 is given with\n"
"the command, that reason will be used when the user is\n"
"kicked; if not, the default reason is \"User has been\n"
"banned from the channel\".\n"
"When akicking a \037registered nick\037 the %s account\n"
"will be added to the akick list instead of the mask.\n"
"All users within that nickgroup will then be akicked.\n"),
source.service->nick.c_str(), bi ? bi->nick.c_str() : "NickServ");
source.Reply(_(
" \n"
"The \002AKICK DEL\002 command removes the given nick or mask\n"
"from the AutoKick list. It does not, however, remove any\n"
"bans placed by an AutoKick; those must be removed\n"
"manually.\n"
" \n"
"The \002AKICK LIST\002 command displays the AutoKick list, or\n"
"optionally only those AutoKick entries which match the\n"
"given mask.\n"
" \n"
"The \002AKICK VIEW\002 command is a more verbose version of the\n"
"\002AKICK LIST\002 command.\n"
" \n"
"The \002AKICK ENFORCE\002 command causes %s to enforce the\n"
"current AKICK list by removing those users who match an\n"
"AKICK mask.\n"
" \n"
"The \002AKICK CLEAR\002 command clears all entries of the\n"
"akick list."), source.service->nick.c_str());
"Maintains the \002AutoKick list\002 for a channel. If a user "
"on the AutoKick list attempts to join the channel, "
"%s will ban that user from the channel, then kick "
"the user."
"\n\n"
"The \002%s\032ADD\002 command adds the given nick or usermask "
"to the AutoKick list. If a \037reason\037 is given with "
"the command, that reason will be used when the user is "
"kicked; if not, the default reason is \"User has been "
"banned from the channel\". "
"When akicking a \037registered nick\037 the %s account "
"will be added to the akick list instead of the mask. "
"All users within that nickgroup will then be akicked. "
"\n\n"
"The \002%s\032DEL\002 command removes the given nick or mask "
"from the AutoKick list. It does not, however, remove any "
"bans placed by an AutoKick; those must be removed "
"manually."
"\n\n"
"The \002%s\032LIST\002 command displays the AutoKick list, or "
"optionally only those AutoKick entries which match the "
"given mask."
"\n\n"
"The \002%s\032VIEW\002 command is a more verbose version of the "
"\002%s\032LIST\002 command."
"\n\n"
"The \002%s\032ENFORCE\002 command causes %s to enforce the "
"current akick list by removing those users who match an "
"akick mask."
"\n\n"
"The \002%s\032CLEAR\002 command clears all entries of the "
"akick list."
),
source.service->nick.c_str(),
source.command.nobreak().c_str(),
bi ? bi->nick.c_str() : "NickServ",
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
@@ -567,8 +590,10 @@ public:
if (reason.empty())
{
reason = Language::Translate(u, Config->GetModule(this).Get<const Anope::string>("autokickreason").c_str());
reason = reason.replace_all_cs("%n", u->nick)
.replace_all_cs("%c", c->name);
reason = Anope::Template(reason, {
{ "channel", c->name },
{ "nick", u->nick },
});
}
if (reason.empty())
reason = Language::Translate(u, _("User has been banned from the channel"));
+18 -11
View File
@@ -50,7 +50,7 @@ public:
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
Configuration::Block &block = Config->GetCommand(source);
const auto &block = Config->GetCommand(source);
const Anope::string &mode = block.Get<Anope::string>("mode", "BAN");
ChannelMode *cm = ModeManager::FindChannelModeByName(mode);
if (cm == NULL)
@@ -111,8 +111,7 @@ public:
if (reason.length() > reasonmax)
reason = reason.substr(0, reasonmax);
Anope::string signkickformat = Config->GetModule("chanserv").Get<Anope::string>("signkickformat", "%m (%n)");
signkickformat = signkickformat.replace_all_cs("%n", source.GetNick());
auto signkickformat = Config->GetModule("chanserv").Get<Anope::string>("signkickformat", "{message} ({nick})");
User *u = source.GetUser();
User *u2 = User::Find(target, true);
@@ -160,7 +159,10 @@ public:
{
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !source.AccessFor(ci).HasPriv("SIGNKICK")))
{
signkickformat = signkickformat.replace_all_cs("%m", reason);
signkickformat = Anope::Template(signkickformat, {
{ "message", reason },
{ "nick", source.GetNick() },
});
c->Kick(ci->WhoSends(), u2, signkickformat);
}
else
@@ -215,7 +217,10 @@ public:
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
{
reason += " (Matches " + mask + ")";
signkickformat = signkickformat.replace_all_cs("%m", reason);
signkickformat = Anope::Template(signkickformat, {
{ "message", reason },
{ "nick", source.GetNick() },
});
c->Kick(ci->WhoSends(), uc->user, signkickformat);
}
else
@@ -235,12 +240,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Bans a given nick or mask on a channel. An optional expiry may\n"
"be given to cause services to remove the ban after a set amount\n"
"of time.\n"
" \n"
"By default, limited to AOPs or those with level 5 access\n"
"and above on the channel. Channel founders may ban masks."));
source.Reply(_(
"Bans a given nick or mask on a channel. An optional expiry may "
"be given to cause services to remove the ban after a set amount "
"of time."
"\n\n"
"By default, limited to AOPs or those with level 5 access "
"and above on the channel. Channel founders may ban masks."
));
return true;
}
};
+7 -5
View File
@@ -169,7 +169,7 @@ public:
delete target_ci;
target_ci = new ChannelInfo(*ci);
target_ci->name = target;
target_ci->time_registered = Anope::CurTime;
target_ci->registered = Anope::CurTime;
(*RegisteredChannelList)[target_ci->name] = target_ci;
target_ci->c = Channel::Find(target_ci->name);
@@ -239,10 +239,12 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Copies all settings, access, akicks, etc from \002channel\002 to the\n"
"\002target\002 channel. If \037what\037 is \002ACCESS\002, \002AKICK\002, \002BADWORDS\002,\n"
"or \002LEVELS\002 then only the respective settings are cloned.\n"
"You must be the founder of \037channel\037 and \037target\037."));
source.Reply(_(
"Copies all settings, access, akicks, etc from \002channel\002 to the "
"\002target\002 channel. If \037what\037 is \002ACCESS\002, \002AKICK\002, \002BADWORDS\002, "
"or \002LEVELS\002 then only the respective settings are cloned. "
"You must be the founder of \037channel\037 and \037target\037."
));
return true;
}
};
+20 -8
View File
@@ -55,10 +55,10 @@ public:
if (!code)
{
code = ci->Extend<Anope::string>("channel-dropcode");
*code = Anope::Random(15);
*code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", 15));
}
source.Reply(CONFIRM_DROP, ci->name.c_str(), source.service->GetQueryCommand().c_str(),
source.Reply(CONFIRM_DROP, ci->name.c_str(), source.service->GetQueryCommand("chanserv/drop").c_str(),
ci->name.c_str(), code->c_str());
return;
}
@@ -88,16 +88,28 @@ public:
this->SendSyntax(source);
source.Reply(" ");
if (source.IsServicesOper())
source.Reply(_("Unregisters the specified channel. Only \002Services Operators\002\n"
"can drop a channel of which they are not the founder of."));
{
source.Reply(_(
"Unregisters the specified channel. Only \002Services Operators\002 "
"can drop a channel of which they are not the founder of."
));
}
else
source.Reply(_("Unregisters the named channel. Can only be used by\n"
"the \002channel founder\002."));
{
source.Reply(_(
"Unregisters the named channel. Can only be used by "
"the \002channel founder\002."
));
}
source.Reply(" ");
if (source.HasPriv("chanserv/drop/override"))
source.Reply(_("Additionally, Services Operators with the \037chanserv/drop/override\037 permission can\n"
"replace \037code\037 with \002OVERRIDE\002 to drop without a confirmation code."));
{
source.Reply(_(
"Additionally, Services Operators with the \037chanserv/drop/override\037 permission can "
"replace \037code\037 with \002OVERRIDE\002 to drop without a confirmation code."
));
}
return true;
}
};
+15 -13
View File
@@ -240,19 +240,21 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enforce various channel modes and set options. The \037channel\037\n"
"option indicates what channel to enforce the modes and options\n"
"on. The \037what\037 option indicates what modes and options to\n"
"enforce, and can be any of \002SECUREOPS\002, \002RESTRICTED\002, \002REGONLY\002, \002SSLONLY\002,\n"
"\002BANS\002, or \002LIMIT\002.\n"
" \n"
"Use \002SECUREOPS\002 to enforce the SECUREOPS option, even if it is not\n"
"enabled. Use \002RESTRICTED\002 to enforce the RESTRICTED option, also\n"
"if it's not enabled. Use \002REGONLY\002 to kick all unregistered users\n"
"from the channel. Use \002SSLONLY\002 to kick all users not using a secure\n"
"connection from the channel. \002BANS\002 will enforce bans on the channel by\n"
"kicking users affected by them, and \002LIMIT\002 will kick users until the\n"
"user count drops below the channel limit, if one is set."));
source.Reply(_(
"Enforce various channel modes and set options. The \037channel\037 "
"option indicates what channel to enforce the modes and options "
"on. The \037what\037 option indicates what modes and options to "
"enforce, and can be any of \002SECUREOPS\002, \002RESTRICTED\002, \002REGONLY\002, \002SSLONLY\002, "
"\002BANS\002, or \002LIMIT\002."
"\n\n"
"Use \002SECUREOPS\002 to enforce the SECUREOPS option, even if it is not "
"enabled. Use \002RESTRICTED\002 to enforce the RESTRICTED option, also "
"if it's not enabled. Use \002REGONLY\002 to kick all unregistered users "
"from the channel. Use \002SSLONLY\002 to kick all users not using a secure "
"connection from the channel. \002BANS\002 will enforce bans on the channel by "
"kicking users affected by them, and \002LIMIT\002 will kick users until the "
"user count drops below the channel limit, if one is set."
));
return true;
}
};
+26 -20
View File
@@ -245,26 +245,32 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Controls what messages will be sent to users when they join the channel."));
source.Reply(" ");
source.Reply(_("The \002ENTRYMSG ADD\002 command adds the given message to\n"
"the list of messages shown to users when they join\n"
"the channel."));
source.Reply(" ");
source.Reply(_("The \002ENTRYMSG DEL\002 command removes the specified message from\n"
"the list of messages shown to users when they join\n"
"the channel. You can remove a message by specifying its number\n"
"which you can get by listing the messages as explained below."));
source.Reply(" ");
source.Reply(_("The \002ENTRYMSG LIST\002 command displays a listing of messages\n"
"shown to users when they join the channel."));
source.Reply(" ");
source.Reply(_("The \002ENTRYMSG CLEAR\002 command clears all entries from\n"
"the list of messages shown to users when they join\n"
"the channel, effectively disabling entry messages."));
source.Reply(" ");
source.Reply(_("Adding, deleting, or clearing entry messages requires the\n"
"SET permission."));
source.Reply(_(
"Controls what messages will be sent to users when they join the channel."
"\n\n"
"The \002%s\032ADD\002 command adds the given message to "
"the list of messages shown to users when they join "
"the channel."
"\n\n"
"The \002%s\032DEL\002 command removes the specified message from "
"the list of messages shown to users when they join "
"the channel. You can remove a message by specifying its number "
"which you can get by listing the messages as explained below."
"\n\n"
"The \002%s\032LIST\002 command displays a listing of messages "
"shown to users when they join the channel."
"\n\n"
"The \002%s\032CLEAR\002 command clears all entries from "
"the list of messages shown to users when they join "
"the channel, effectively disabling entry messages."
"\n\n"
"Adding, deleting, or clearing entry messages requires the "
"SET permission."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
+22 -19
View File
@@ -444,24 +444,27 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("%s is another way to modify the channel access list, similar to\n"
"the XOP and ACCESS methods."), source.command.c_str());
source.Reply(" ");
source.Reply(_("The \002MODIFY\002 command allows you to modify the access list. If the mask is\n"
"not already on the access list it is added, then the changes are applied.\n"
"If the mask has no more flags, then the mask is removed from the access list.\n"
"Additionally, you may use +* or -* to add or remove all flags, respectively. You are\n"
"only able to modify the access list if you have the proper permission on the channel,\n"
"and even then you can only give other people access to the equivalent of what your access is."));
source.Reply(" ");
source.Reply(_("The \002LIST\002 command allows you to list existing entries on the channel access list.\n"
"If a mask is given, the mask is wildcard matched against all existing entries on the\n"
"access list, and only those entries are returned. If a set of flags is given, only those\n"
"on the access list with the specified flags are returned."));
source.Reply(" ");
source.Reply(_("The \002CLEAR\002 command clears the channel access list. This requires channel founder access."));
source.Reply(" ");
source.Reply(_("The available flags are:"));
source.Reply(_(
"%s is another way to modify the channel access list, similar to "
"the XOP and ACCESS methods."
"\n\n"
"The \002MODIFY\002 command allows you to modify the access list. If the mask is "
"not already on the access list it is added, then the changes are applied. "
"If the mask has no more flags, then the mask is removed from the access list. "
"Additionally, you may use +* or -* to add or remove all flags, respectively. You are "
"only able to modify the access list if you have the proper permission on the channel, "
"and even then you can only give other people access to the equivalent of what your access is."
"\n\n"
"The \002LIST\002 command allows you to list existing entries on the channel access list. "
"If a mask is given, the mask is wildcard matched against all existing entries on the "
"access list, and only those entries are returned. If a set of flags is given, only those "
"on the access list with the specified flags are returned."
"\n\n"
"The \002CLEAR\002 command clears the channel access list. This requires channel founder access."
"\n\n"
"The available flags are:"
),
source.command.nobreak().c_str());
typedef std::multimap<char, Anope::string, ci::less> reverse_map;
reverse_map reverse;
@@ -500,7 +503,7 @@ public:
for (int i = 0; i < conf.CountBlock("privilege"); ++i)
{
Configuration::Block &priv = conf.GetBlock("privilege", i);
const auto &priv = conf.GetBlock("privilege", i);
const Anope::string &pname = priv.Get<const Anope::string>("name");
+9 -7
View File
@@ -53,7 +53,7 @@ public:
if (!ci->desc.empty())
info[_("Description")] = ci->desc;
info[_("Registered")] = Anope::strftime(ci->time_registered, source.GetAccount());
info[_("Registered")] = Anope::strftime(ci->registered, source.GetAccount());
info[_("Last used")] = Anope::strftime(ci->last_used, source.GetAccount());
if (show_all)
@@ -74,12 +74,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Lists information about the specified registered channel,\n"
"including its founder, time of registration, last\n"
"time used, and description. If the user issuing the\n"
"command has the appropriate access for it, then the\n"
"successor, last topic set, settings and expiration\n"
"time will also be displayed when applicable."));
source.Reply(_(
"Lists information about the specified registered channel, "
"including its founder, time of registration, last "
"time used, and description. If the user issuing the "
"command has the appropriate access for it, then the "
"successor, last topic set, settings and expiration "
"time will also be displayed when applicable."
));
return true;
}
};
+8 -5
View File
@@ -89,11 +89,14 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Tells %s to invite you or an optionally specified\n"
"nick into the given channel.\n"
" \n"
"By default, limited to AOPs or those with level 5 access and above\n"
"on the channel."), source.service->nick.c_str());
source.Reply(_(
"Tells %s to invite you or an optionally specified "
"nick into the given channel."
"\n\n"
"By default, limited to AOPs or those with level 5 access and above "
"on the channel."
),
source.service->nick.c_str());
return true;
}
};
+15 -8
View File
@@ -48,8 +48,7 @@ public:
if (reason.length() > reasonmax)
reason = reason.substr(0, reasonmax);
Anope::string signkickformat = Config->GetModule("chanserv").Get<Anope::string>("signkickformat", "%m (%n)");
signkickformat = signkickformat.replace_all_cs("%n", source.GetNick());
auto signkickformat = Config->GetModule("chanserv").Get<Anope::string>("signkickformat", "{message} ({nick})");
AccessGroup u_access = source.AccessFor(ci);
@@ -71,7 +70,10 @@ public:
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
{
signkickformat = signkickformat.replace_all_cs("%m", reason);
signkickformat = Anope::Template(signkickformat, {
{ "message", reason },
{ "nick", source.GetNick() },
});
c->Kick(ci->WhoSends(), u2, signkickformat);
}
else
@@ -105,7 +107,10 @@ public:
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
{
reason += " (Matches " + mask + ")";
signkickformat = signkickformat.replace_all_cs("%m", reason);
signkickformat = Anope::Template(signkickformat, {
{ "message", reason },
{ "nick", source.GetNick() },
});
c->Kick(ci->WhoSends(), uc->user, signkickformat);
}
else
@@ -126,10 +131,12 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Kicks a specified nick from a channel.\n"
" \n"
"By default, limited to AOPs or those with level 5 access\n"
"and above on the channel. Channel founders can also specify masks."));
source.Reply(_(
"Kicks a specified nick from a channel."
"\n\n"
"By default, limited to AOPs or those with level 5 access "
"and above on the channel. Channel founders can also specify masks."
));
return true;
}
};
+41 -32
View File
@@ -42,8 +42,10 @@ public:
if (!num1.has_value() || !num2.has_value())
{
source.Reply(LIST_INCORRECT_RANGE);
source.Reply(_("To search for channels starting with #, search for the channel\n"
"name without the #-sign prepended (\002anope\002 instead of \002#anope\002)."));
source.Reply(_(
"To search for channels starting with #, search for the channel "
"name without the #-sign prepended (\002anope\002 instead of \002#anope\002)."
));
return;
}
@@ -133,38 +135,43 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Lists all registered channels matching the given pattern.\n"
"Channels with the \002PRIVATE\002 option set will only be\n"
"displayed to Services Operators with the proper access.\n"
"Channels with the \002NOEXPIRE\002 option set will have\n"
"a \002!\002 prefixed to the channel for Services Operators to see.\n"
" \n"
"Note that a preceding '#' specifies a range, channel names\n"
"are to be written without '#'.\n"
" \n"
"If the SUSPENDED or NOEXPIRE options are given, only channels\n"
"which, respectively, are SUSPENDED or have the NOEXPIRE\n"
"flag set will be displayed. If multiple options are given,\n"
"all channels matching at least one option will be displayed.\n"
"Note that these options are limited to \037Services Operators\037.\n"
" \n"
"Examples:\n"
" \n"
" \002LIST *anope*\002\n"
" Lists all registered channels with \002anope\002 in their\n"
" names (case insensitive).\n"
" \n"
" \002LIST * NOEXPIRE\002\n"
" Lists all registered channels which have been set to not expire.\n"
" \n"
" \002LIST #51-100\002\n"
" Lists all registered channels within the given range (51-100)."));
source.Reply(_(
"Lists all registered channels matching the given pattern. "
"Channels with the \002PRIVATE\002 option set will only be "
"displayed to Services Operators with the proper access. "
"Channels with the \002NOEXPIRE\002 option set will have "
"a \002!\002 prefixed to the channel for Services Operators to see."
"\n\n"
"Note that a preceding '#' specifies a range, channel names "
"are to be written without '#'."
"\n\n"
"If the SUSPENDED or NOEXPIRE options are given, only channels "
"which, respectively, are SUSPENDED or have the NOEXPIRE "
"flag set will be displayed. If multiple options are given, "
"all channels matching at least one option will be displayed. "
"Note that these options are limited to \037Services Operators\037."
"\n\n"
"Examples:"
"\n\n"
" \002LIST\032*anope*\002\n"
" Lists all registered channels with \002anope\002 in their\n"
" names (case insensitive)."
"\n\n"
" \002LIST\032*\032NOEXPIRE\002\n"
" Lists all registered channels which have been set to not expire."
"\n\n"
" \002LIST #51-100\002\n"
" Lists all registered channels within the given range (51-100)."
));
if (!Config->GetBlock("options").Get<const Anope::string>("regexengine").empty())
{
source.Reply(" ");
source.Reply(_("Regex matches are also supported using the %s engine.\n"
"Enclose your pattern in // if this is desired."), Config->GetBlock("options").Get<const Anope::string>("regexengine").c_str());
source.Reply(_(
"Regex matches are also supported using the %s engine. "
"Enclose your pattern in // if this is desired."
),
Config->GetBlock("options").Get<const Anope::string>("regexengine").c_str());
}
return true;
@@ -234,8 +241,10 @@ public:
BotInfo *bi;
Anope::string cmd;
if (Command::FindCommandFromService("chanserv/list", bi, cmd))
source.Reply(_("When \002private\002 is set, the channel will not appear in\n"
"%s's %s command."), bi->nick.c_str(), cmd.c_str());
{
source.Reply(_("When \002private\002 is set, the channel will not appear in %s's %s command."),
bi->nick.c_str(), cmd.c_str());
}
return true;
}
};
+25 -21
View File
@@ -271,26 +271,30 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("The %s command allows users to configure logging settings\n"
"for their channel. If no parameters are given this command\n"
"lists the current logging methods in place for this channel.\n"
" \n"
"Otherwise, \037command\037 must be a command name, and \037method\037\n"
"is one of the following logging methods:\n"
" \n"
" MESSAGE [status], NOTICE [status], MEMO\n"
" \n"
"Which are used to message, notice, and memo the channel respectively.\n"
"With MESSAGE or NOTICE you must have a service bot assigned to and joined\n"
"to your channel. Status may be a channel status such as @ or +.\n"
" \n"
"To remove a logging method use the same syntax as you would to add it.\n"
" \n"
source.Reply(_(
"The %s command allows users to configure logging settings "
"for their channel. If no parameters are given this command "
"lists the current logging methods in place for this channel."
"\n\n"
"Otherwise, \037command\037 must be a command name, and \037method\037 "
"is one of the following logging methods:"
"\n\n"
" MESSAGE\032[status], NOTICE\032[status], MEMO"
"\n\n"
"Which are used to message, notice, and memo the channel respectively. "
"With MESSAGE or NOTICE you must have a service bot assigned to and joined "
"to your channel. Status may be a channel status such as @ or +."
"\n\n"
"To remove a logging method use the same syntax as you would to add it."
"\n\n"
"Example:\n"
" %s #anope chanserv/access MESSAGE @\n"
" Would message any channel operators whenever someone used the\n"
" ACCESS command on ChanServ on the channel."),
source.command.upper().c_str(), source.command.upper().c_str());
" %s\032#anope\032chanserv/access\032MESSAGE\032@\n"
" Would message any channel operators whenever someone used the "
"ACCESS command on ChanServ on the channel."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
@@ -321,12 +325,12 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &block = conf.GetModule(this);
const auto &block = conf.GetModule(this);
defaults.clear();
for (int i = 0; i < block.CountBlock("default"); ++i)
{
Configuration::Block &def = block.GetBlock("default", i);
const auto &def = block.GetBlock("default", i);
LogDefault ld;
+42 -30
View File
@@ -774,29 +774,39 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Mainly controls mode locks and mode access (which is different from channel access)\n"
"on a channel.\n"
" \n"
"The \002%s LOCK\002 command allows you to add, delete, and view mode locks on a channel.\n"
"If a mode is locked on or off, services will not allow that mode to be changed. The \002SET\002\n"
"command will clear all existing mode locks and set the new one given, while \002ADD\002 and \002DEL\002\n"
"modify the existing mode lock.\n"
"Example:\n"
" \002MODE #channel LOCK ADD +bmnt *!*@*aol*\002\n"
" \n"
"The \002%s SET\002 command allows you to set modes through services. Wildcards * and ? may\n"
"be given as parameters for list and status modes.\n"
"Example:\n"
" \002MODE #channel SET +v *\002\n"
" Sets voice status to all users in the channel.\n"
" \n"
" \002MODE #channel SET -b ~c:*\n"
" Clears all extended bans that start with ~c:\n"
" \n"
"The \002%s CLEAR\002 command is an easy way to clear modes on a channel. \037what\037 may be\n"
"any mode name. Examples include bans, excepts, inviteoverrides, ops, halfops, and voices. If \037what\037\n"
"is not given then all basic modes are removed."),
source.command.upper().c_str(), source.command.upper().c_str(), source.command.upper().c_str());
source.Reply(_(
"Mainly controls mode locks and mode access (which is different from channel access) "
"on a channel."
"\n\n"
"The \002%s\032LOCK\002 command allows you to add, delete, and view mode locks on a channel. "
"If a mode is locked on or off, services will not allow that mode to be changed. The \002SET\002 "
"command will clear all existing mode locks and set the new one given, while \002ADD\002 and \002DEL\002 "
"modify the existing mode lock."
"\n\n"
"Example:\n"
" \002%s\032#channel\032%s\032ADD\032+bmnt\032*!*@*aol*\002\n"
"\n\n"
"The \002%s\032SET\002 command allows you to set modes through services. Wildcards * and ? may "
"be given as parameters for list and status modes."
"\n\n"
"Example:\n"
" \002%s\032#channel\032SET\032+v\032*\002\n"
" Sets voice status to all users in the channel."
"\n\n"
" \002%s\032#channel\032SET\032-b\032~c:*\n"
" Clears all extended bans that start with ~c:"
"\n\n"
"The \002%s\032CLEAR\002 command is an easy way to clear modes on a channel. \037what\037 may be "
"any mode name. Examples include bans, excepts, inviteoverrides, ops, halfops, and voices. If \037what\037 "
"is not given then all basic modes are removed."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
@@ -924,13 +934,15 @@ public:
this->SendSyntax(source);
source.Reply(" ");
if (m.first)
source.Reply(_("Gives %s status to the selected nicks on a channel. If \037nick\037 is\n"
"not given, it will %s you."),
m.second.upper().c_str(), m.second.lower().c_str());
{
source.Reply(_("Gives %s status to the selected nicks on a channel. If \037nick\037 is not given, it will %s you."),
m.second.upper().c_str(), m.second.lower().c_str());
}
else
source.Reply(_("Removes %s status from the selected nicks on a channel. If \037nick\037 is\n"
"not given, it will de%s you."),
m.second.upper().c_str(), m.second.lower().c_str());
{
source.Reply(_("Removes %s status from the selected nicks on a channel. If \037nick\037 is not given, it will de%s you."),
m.second.upper().c_str(), m.second.lower().c_str());
}
source.Reply(" ");
source.Reply(_("You must have the %s(ME) privilege on the channel to use this command."), m.second.upper().c_str());
@@ -961,7 +973,7 @@ public:
for (int i = 0; i < conf.CountBlock("command"); ++i)
{
Configuration::Block &block = conf.GetBlock("command", i);
const auto &block = conf.GetBlock("command", i);
const Anope::string &cname = block.Get<const Anope::string>("name"),
&cmd = block.Get<const Anope::string>("command");
+31 -18
View File
@@ -84,28 +84,41 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Registers a channel in the %s database. In order\n"
"to use this command, you must first be a channel operator\n"
"on the channel you're trying to register.\n"
"The description, which is optional, is a\n"
"general description of the channel's purpose.\n"
" \n"
"When you register a channel, you are recorded as the\n"
"\"founder\" of the channel. The channel founder is allowed\n"
"to change all of the channel settings for the channel;\n"
"%s will also automatically give the founder\n"
"channel operator privileges when they enter the channel."),
source.service->nick.c_str(), source.service->nick.c_str());
source.Reply(_(
"Registers a channel in the %s database. In order "
"to use this command, you must first be a channel operator "
"on the channel you're trying to register. "
"The description, which is optional, is a "
"general description of the channel's purpose. "
"\n\n"
"When you register a channel, you are recorded as the "
"\"founder\" of the channel. The channel founder is allowed "
"to change all of the channel settings for the channel; "
"%s will also automatically give the founder "
"channel operator privileges when they enter the channel."
),
source.service->nick.c_str(),
source.service->nick.c_str());
BotInfo *bi;
Anope::string cmd;
if (Command::FindCommandFromService("chanserv/access", bi, cmd))
source.Reply(_(" \n"
"See the \002%s\002 command (\002%s HELP ACCESS\002) for\n"
"information on giving a subset of these privileges to\n"
"other channel users.\n"), cmd.c_str(), bi->GetQueryCommand().c_str());
source.Reply(_(" \n"
"NOTICE: In order to register a channel, you must have\n"
{
source.Reply(" ");
source.Reply(_(
"See the \002%s\002 command (\002%s\032ACCESS\002) for "
"information on giving a subset of these privileges to "
"other channel users."
),
cmd.c_str(),
bi->GetQueryCommand("generic/help").c_str());
}
source.Reply(" ");
source.Reply(_(
"NOTICE: In order to register a channel, you must have "
"first registered your nickname."));
return true;
}
};
+15 -9
View File
@@ -181,13 +181,17 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("The \002STATS\002 command prints out statistics about stored nicks and memory usage."));
source.Reply(_("The \002CLEAR\002 command lets you clean the database by removing all entries from the\n"
"database that were added within \037time\037.\n"
" \n"
source.Reply(_(
"The \002STATS\002 command prints out statistics about stored nicks and memory usage."
"\n\n"
"The \002CLEAR\002 command lets you clean the database by removing all entries from the "
"database that were added within \037time\037."
"\n\n"
"Example:\n"
" %s CLEAR 30m\n"
" Will remove all entries that were added within the last 30 minutes."), source.command.c_str());
" %s\032CLEAR\03230m\n"
" Will remove all entries that were added within the last 30 minutes."
),
source.command.nobreak().c_str());
return true;
}
};
@@ -374,9 +378,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Checks for the last time \037nick\037 was seen joining, leaving,\n"
"or changing nick on the network and tells you when and, depending\n"
"on channel or user settings, where it was."));
source.Reply(_(
"Checks for the last time \037nick\037 was seen joining, leaving, "
"or changing nick on the network and tells you when and, depending "
"on channel or user settings, where it was."
));
return true;
}
};
+147 -88
View File
@@ -31,13 +31,16 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Allows the channel founder to set various channel options\n"
"and other information.\n"
" \n"
source.Reply(_(
"Allows the channel founder to set various channel options "
"and other information."
"\n\n"
"Available options:"));
Anope::string this_name = source.command;
bool hide_privileged_commands = Config->GetBlock("options").Get<bool>("hideprivilegedcommands"),
hide_registered_commands = Config->GetBlock("options").Get<bool>("hideregisteredcommands");
HelpWrapper help;
for (const auto &[c_name, info] : source.service->commands)
{
if (c_name.find_ci(this_name + " ") == 0)
@@ -56,11 +59,13 @@ public:
continue;
source.command = c_name;
c->OnServHelp(source);
c->OnServHelp(source, help);
}
}
source.Reply(_("Type \002%s HELP %s \037option\037\002 for more information on a\n"
"particular option."), source.service->GetQueryCommand().c_str(), this_name.c_str());
help.SendTo(source);
source.Reply(_("Type \002%s\032\037option\037\002 for more information on a particular option."),
source.service->GetQueryCommand("generic/help", this_name).c_str());
return true;
}
};
@@ -121,9 +126,12 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enables or disables %s's autoop feature for a\n"
"channel. When disabled, users who join the channel will\n"
"not automatically gain any status from %s."), source.service->nick.c_str(),
source.Reply(_(
"Enables or disables %s's autoop feature for a "
"channel. When disabled, users who join the channel will "
"not automatically gain any status from %s."
),
source.service->nick.c_str(),
source.service->nick.c_str());
return true;
}
@@ -181,15 +189,17 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the ban type that will be used by services whenever\n"
"they need to ban someone from your channel.\n"
" \n"
"Bantype is a number between 0 and 3 that means:\n"
" \n"
"0: ban in the form *!user@host\n"
"1: ban in the form *!*user@host\n"
"2: ban in the form *!*@host\n"
"3: ban in the form *!*user@*.domain"));
source.Reply(_(
"Sets the ban type that will be used by services whenever "
"they need to ban someone from your channel."
"\n\n"
"Bantype is a number between 0 and 3 that means:"
"\n\n"
"0: ban in the form *!user@host\n"
"1: ban in the form *!*user@host\n"
"2: ban in the form *!*@host\n"
"3: ban in the form *!*user@*.domain"
));
return true;
}
};
@@ -251,8 +261,10 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the description for the channel, which shows up with\n"
"the \002LIST\002 and \002INFO\002 commands."));
source.Reply(_(
"Sets the description for the channel, which shows up with "
"the \002LIST\002 and \002INFO\002 commands."
));
return true;
}
};
@@ -299,6 +311,12 @@ public:
source.Reply(NICK_X_NOT_REGISTERED, params[1].c_str());
return;
}
else if (na->nc->HasExt("NEVEROP"))
{
source.Reply(_("\002%s\002 does not wish to be added to channel access lists."),
na->nc->display.c_str());
return;
}
NickCore *nc = na->nc;
unsigned max_reg = Config->GetModule("chanserv").Get<unsigned>("maxregistered");
@@ -321,8 +339,10 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Changes the founder of a channel. The new nickname must\n"
"be a registered one."));
source.Reply(_(
"Changes the founder of a channel. The new nickname must "
"be a registered one."
));
return true;
}
};
@@ -386,9 +406,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enables or disables keepmodes for the given channel. If keep\n"
"modes is enabled, services will remember modes set on the channel\n"
"and attempt to re-set them the next time the channel is created."));
source.Reply(_(
"Enables or disables keepmodes for the given channel. If keep "
"modes is enabled, services will remember modes set on the channel "
"and attempt to re-set them the next time the channel is created."
));
return true;
}
};
@@ -451,10 +473,13 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enables or disables the \002peace\002 option for a channel.\n"
"When \002peace\002 is set, a user won't be able to kick,\n"
"ban or remove a channel status of a user that has\n"
"a level superior or equal to theirs via %s commands."), source.service->nick.c_str());
source.Reply(_(
"Enables or disables the \002peace\002 option for a channel. "
"When \002peace\002 is set, a user won't be able to kick, "
"ban or remove a channel status of a user that has "
"a level superior or equal to theirs via %s commands."
),
source.service->nick.c_str());
return true;
}
};
@@ -594,26 +619,30 @@ public:
BotInfo *ChanServ = Config->GetClient("ChanServ");
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enables or disables the persistent channel setting.\n"
"When persistent is set, the service bot will remain\n"
"in the channel when it has emptied of users.\n"
" \n"
"If your IRCd does not have a permanent (persistent) channel\n"
"mode you must have a service bot in your channel to\n"
"set persist on, and it can not be unassigned while persist\n"
"is on.\n"
" \n"
"If this network does not have %s enabled and does\n"
"not have a permanent channel mode, %s will\n"
"join your channel when you set persist on (and leave when\n"
"it has been set off).\n"
" \n"
"If your IRCd has a permanent (persistent) channel mode\n"
"and it is set or unset (for any reason, including MODE LOCK),\n"
"persist is automatically set and unset for the channel as well.\n"
"Additionally, services will set or unset this mode when you\n"
"set persist on or off."), BotServ ? BotServ->nick.c_str() : "BotServ",
ChanServ ? ChanServ->nick.c_str() : "ChanServ");
source.Reply(_(
"Enables or disables the persistent channel setting. "
"When persistent is set, the service bot will remain "
"in the channel when it has emptied of users. "
"\n\n"
"If your IRCd does not have a permanent (persistent) channel "
"mode you must have a service bot in your channel to "
"set persist on, and it can not be unassigned while persist "
"is on."
"\n\n"
"If this network does not have %s enabled and does "
"not have a permanent channel mode, %s will "
"join your channel when you set persist on (and leave when "
"it has been set off)."
"\n\n"
"If your IRCd has a permanent (persistent) channel mode "
"and it is set or unset (for any reason, including MODE LOCK), "
"persist is automatically set and unset for the channel as well. "
"Additionally, services will set or unset this mode when you "
"set persist on or off."
),
BotServ ? BotServ->nick.c_str() : "BotServ",
ChanServ ? ChanServ->nick.c_str() : "ChanServ"
);
return true;
}
};
@@ -674,9 +703,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enables or disables the \002restricted access\002 option for a\n"
"channel. When \002restricted access\002 is set, users not on the access list will\n"
"instead be kicked and banned from the channel."));
source.Reply(_(
"Enables or disables the \002restricted access\002 option for a "
"channel. When \002restricted access\002 is set, users not on the access list will "
"instead be kicked and banned from the channel."
));
return true;
}
};
@@ -737,11 +768,13 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enables or disables the \002secure founder\002 option for a channel.\n"
"When \002secure founder\002 is set, only the real founder will be\n"
"able to drop the channel, change its founder and its successor,\n"
"and not those who have founder level access through\n"
"the access/qop command."));
source.Reply(_(
"Enables or disables the \002secure founder\002 option for a channel. "
"When \002secure founder\002 is set, only the real founder will be "
"able to drop the channel, change its founder and its successor, "
"and not those who have founder level access through "
"the access/qop command."
));
return true;
}
};
@@ -802,9 +835,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enables or disables the \002secure ops\002 option for a channel.\n"
"When \002secure ops\002 is set, users who are not on the access list\n"
"will not be allowed channel operator status."));
source.Reply(_(
"Enables or disables the \002secure ops\002 option for a channel. "
"When \002secure ops\002 is set, users who are not on the access list "
"will not be allowed channel operator status."
));
return true;
}
};
@@ -856,8 +891,8 @@ public:
{
ci->Extend<bool>("SIGNKICK_LEVEL");
ci->Shrink<bool>("SIGNKICK");
source.Reply(_("Signed kick option for %s is now \002on\002, but depends of the\n"
"level of the user that is using the command."), ci->name.c_str());
source.Reply(_("Signed kick option for %s is now \002on\002, but depends of the level of the user that is using the command."),
ci->name.c_str());
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable sign kick level";
}
else if (params[1].equals_ci("OFF"))
@@ -875,14 +910,16 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enables or disables signed kicks for a\n"
"channel. When \002SIGNKICK\002 is set, kicks issued with\n"
"the \002KICK\002 command will have the nick that used the\n"
"command in their reason.\n"
" \n"
"If you use \002LEVEL\002, those who have a level that is superior\n"
"or equal to the SIGNKICK level on the channel won't have their\n"
"kicks signed."));
source.Reply(_(
"Enables or disables signed kicks for a "
"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"
"If you use \002LEVEL\002, those who have a level that is superior "
"or equal to the SIGNKICK level on the channel won't have their "
"kicks signed."
));
return true;
}
};
@@ -918,7 +955,15 @@ public:
if (MOD_RESULT == EVENT_STOP)
return;
if (MOD_RESULT != EVENT_ALLOW && (ci->HasExt("SECUREFOUNDER") ? !source.IsFounder(ci) : !source.AccessFor(ci).HasPriv("FOUNDER")) && source.permission.empty() && !source.HasPriv("chanserv/administration"))
auto can_set_successor = ci->HasExt("SECUREFOUNDER")
? source.IsFounder(ci)
: source.AccessFor(ci).HasPriv("FOUNDER");
// Special case: users can remove themselves as successor with no other privs.
if (param.empty() && source.GetAccount() && source.GetAccount() == ci->GetSuccessor())
can_set_successor = true;
if (MOD_RESULT != EVENT_ALLOW && !can_set_successor && source.permission.empty() && !source.HasPriv("chanserv/administration"))
{
source.Reply(ACCESS_DENIED);
return;
@@ -935,6 +980,12 @@ public:
source.Reply(NICK_X_NOT_REGISTERED, param.c_str());
return;
}
else if (na->nc->HasExt("NEVEROP"))
{
source.Reply(_("\002%s\002 does not wish to be added to channel access lists."),
na->nc->display.c_str());
return;
}
if (na->nc == ci->GetFounder())
{
source.Reply(_("%s cannot be the successor on channel %s as they are the founder."), na->nick.c_str(), ci->name.c_str());
@@ -961,22 +1012,28 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Changes the successor of a channel. If the founder's\n"
"nickname expires or is dropped while the channel is still\n"
"registered, the successor will become the new founder of the\n"
"channel. The successor's nickname must be a registered one.\n"
"If there's no successor set, then the first nickname on the\n"
"access list (with the highest access, if applicable) will\n"
"become the new founder, but if the access list is empty, the\n"
"channel will be dropped."));
source.Reply(_(
"Changes the successor of a channel. If the founder's "
"nickname expires or is dropped while the channel is still "
"registered, the successor will become the new founder of the "
"channel. The successor's nickname must be a registered one. "
"If there's no successor set, then the first nickname on the "
"access list (with the highest access, if applicable) will "
"become the new founder, but if the access list is empty, the "
"channel will be dropped."
));
unsigned max_reg = Config->GetModule("chanserv").Get<unsigned>("maxregistered");
if (max_reg)
{
source.Reply(" ");
source.Reply(_("Note, however, if the successor already has too many\n"
"channels registered (%d), they will not be able to\n"
"become the new founder and it will be as if the\n"
"channel had no successor set."), max_reg);
source.Reply(_(
"Note, however, if the successor already has too many "
"channels registered (%u), they will not be able to "
"become the new founder and it will be as if the "
"channel had no successor set."
),
max_reg);
}
return true;
}
@@ -1035,8 +1092,10 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets whether the given channel will expire. Setting this\n"
"to ON prevents the channel from expiring."));
source.Reply(_(
"Sets whether the given channel will expire. Setting this "
"to ON prevents the channel from expiring."
));
return true;
}
};
@@ -1202,10 +1261,10 @@ public:
void OnJoinChannel(User *u, Channel *c) override
{
if (u->server != Me && persist_lower_ts && c->ci && persist.HasExt(c->ci) && c->creation_time > c->ci->time_registered)
if (u->server != Me && persist_lower_ts && c->ci && persist.HasExt(c->ci) && c->created > c->ci->registered)
{
Log(LOG_DEBUG) << "Changing TS of " << c->name << " from " << c->creation_time << " to " << c->ci->time_registered;
c->creation_time = c->ci->time_registered;
Log(LOG_DEBUG) << "Changing TS of " << c->name << " from " << c->created << " to " << c->ci->registered;
c->created = c->ci->registered;
IRCD->SendChannel(c);
c->Reset();
}
+3 -3
View File
@@ -157,12 +157,12 @@ public:
}
}
void OnServHelp(CommandSource &source) override
void OnServHelp(CommandSource &source, HelpWrapper &help) override
{
if (descriptions.count(source.command))
{
this->SetDesc(descriptions[source.command]);
Command::OnServHelp(source);
Command::OnServHelp(source, help);
}
}
@@ -205,7 +205,7 @@ public:
for (int i = 0; i < conf.CountBlock("command"); ++i)
{
Configuration::Block &block = conf.GetBlock("command", i);
const auto &block = conf.GetBlock("command", i);
if (block.Get<const Anope::string>("command") != "chanserv/set/misc")
continue;
+7 -5
View File
@@ -102,11 +102,13 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("This command tells you what a users access is on a channel\n"
"and what access entries, if any, they match. Additionally it\n"
"will tell you of any auto kick entries they match. Usage of\n"
"this command is limited to users who have the ability to modify\n"
"access entries on the channel."));
source.Reply(_(
"This command tells you what a users access is on a channel "
"and what access entries, if any, they match. Additionally it "
"will tell you of any auto kick entries they match. Usage of "
"this command is limited to users who have the ability to modify "
"access entries on the channel."
));
return true;
}
};
+14 -10
View File
@@ -143,14 +143,16 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Disallows anyone from using the given channel.\n"
"May be cancelled by using the \002UNSUSPEND\002\n"
"command to preserve all previous channel data/settings.\n"
"If an expiry is given the channel will be unsuspended after\n"
"that period of time, else the default expiry from the\n"
"configuration is used.\n"
" \n"
"Reason may be required on certain networks."));
source.Reply(_(
"Disallows anyone from using the given channel. "
"May be cancelled by using the \002UNSUSPEND\002 "
"command to preserve all previous channel data/settings. "
"If an expiry is given the channel will be unsuspended after "
"that period of time, else the default expiry from the "
"configuration is used."
"\n\n"
"Reason may be required on certain networks."
));
return true;
}
};
@@ -201,8 +203,10 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Releases a suspended channel. All data and settings\n"
"are preserved from before the suspension."));
source.Reply(_(
"Releases a suspended channel. All data and settings "
"are preserved from before the suspension."
));
return true;
}
};
+4 -2
View File
@@ -47,8 +47,10 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Syncs all modes set on users on the channel with the modes\n"
"they should have based on their access."));
source.Reply(_(
"Syncs all modes set on users on the channel with the modes "
"they should have based on their access."
));
return true;
}
};
+19 -13
View File
@@ -68,11 +68,15 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Enables or disables the \002topic retention\002 option for a\n"
"channel. When \002%s\002 is set, the topic for the\n"
"channel will be remembered by %s even after the\n"
"last user leaves the channel, and will be restored the\n"
"next time the channel is created."), source.command.c_str(), source.service->nick.c_str());
source.Reply(_(
"Enables or disables the \002topic retention\002 option for a "
"channel. When \002%s\002 is set, the topic for the "
"channel will be remembered by %s even after the "
"last user leaves the channel, and will be restored the "
"next time the channel is created."
),
source.command.nobreak().c_str(),
source.service->nick.c_str());
return true;
}
};
@@ -192,14 +196,16 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Allows manipulating the topic of the specified channel.\n"
"The \002SET\002 command changes the topic of the channel to the given topic\n"
"or unsets the topic if no topic is given. The \002APPEND\002 command appends\n"
"the given topic to the existing topic.\n"
" \n"
"\002LOCK\002 and \002UNLOCK\002 may be used to enable and disable topic lock. When\n"
"topic lock is set, the channel topic will be unchangeable by users who do not have\n"
"the \002TOPIC\002 privilege."));
source.Reply(_(
"Allows manipulating the topic of the specified channel. "
"The \002SET\002 command changes the topic of the channel to the given topic "
"or unsets the topic if no topic is given. The \002APPEND\002 command appends "
"the given topic to the existing topic. "
"\n\n"
"\002LOCK\002 and \002UNLOCK\002 may be used to enable and disable topic lock. When "
"topic lock is set, the channel topic will be unchangeable by users who do not have "
"the \002TOPIC\002 privilege."
));
return true;
}
};
+29 -21
View File
@@ -23,7 +23,8 @@ public:
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
ChannelMode *cm = ModeManager::FindChannelModeByName("BAN");
const auto &mode = Config->GetCommand(source).Get<Anope::string>("mode", "BAN");
auto *cm = ModeManager::FindChannelModeByName(mode);
if (!cm)
return;
@@ -44,16 +45,18 @@ public:
if (!ci->c || !(source.AccessFor(ci).HasPriv("UNBAN") || source.AccessFor(ci).HasPriv("UNBANME")))
continue;
if (IRCD->CanClearBans)
{
IRCD->SendClearBans(ci->WhoSends(), ci->c, source.GetUser());
count++;
continue;
}
for (const auto *mode : modes)
{
if (IRCD->CanClearModes.count(mode->name))
{
IRCD->SendClearModes(ci->WhoSends(), ci->c, source.GetUser(), mode->name);
count++;
continue;
}
if (ci->c->Unban(source.GetUser(), mode->name, true))
++count;
}
}
Log(LOG_COMMAND, source, this, NULL) << "on all channels";
@@ -96,13 +99,15 @@ public:
bool override = !source.AccessFor(ci).HasPriv("UNBAN") && source.HasPriv("chanserv/kick");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to unban " << u2->nick;
if (IRCD->CanClearBans)
IRCD->SendClearBans(ci->WhoSends(), ci->c, source.GetUser());
else
for (const auto *mode : modes)
{
for (const auto *mode : modes)
ci->c->Unban(u2, mode->name, source.GetUser() == u2);
if (IRCD->CanClearModes.count(mode->name))
{
IRCD->SendClearModes(ci->WhoSends(), ci->c, u2, mode->name);
continue;
}
ci->c->Unban(u2, mode->name, source.GetUser() == u2);
}
if (u2 == source.GetUser())
@@ -115,13 +120,16 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Tells %s to remove all bans preventing you or the given\n"
"user from entering the given channel. If no channel is\n"
"given, all bans affecting you in channels you have access\n"
"in are removed.\n"
" \n"
"By default, limited to AOPs or those with level 5 access and above\n"
"on the channel."), source.service->nick.c_str());
source.Reply(_(
"Tells %s to remove all bans preventing you or the given "
"user from entering the given channel. If no channel is "
"given, all bans affecting you in channels you have access "
"in are removed."
"\n\n"
"By default, limited to AOPs or those with level 5 access and above "
"on the channel."
),
source.service->nick.c_str());
return true;
}
};
+10 -6
View File
@@ -123,9 +123,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Updates a selected nicks status modes on a channel. If \037nick\037 is\n"
"omitted then your status is updated. If \037channel\037 is omitted then\n"
"your channel status is updated on every channel you are in."));
source.Reply(_(
"Updates a selected nicks status modes on a channel. If \037nick\037 is "
"omitted then your status is updated. If \037channel\037 is omitted then "
"your channel status is updated on every channel you are in."
));
return true;
}
};
@@ -221,9 +223,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Removes a selected nicks status modes on a channel. If \037nick\037 is\n"
"omitted then your status is removed. If \037channel\037 is omitted then\n"
"your channel status is removed on every channel you are in."));
source.Reply(_(
"Removes a selected nicks status modes on a channel. If \037nick\037 is "
"omitted then your status is removed. If \037channel\037 is omitted then "
"your channel status is removed on every channel you are in."
));
return true;
}
};
+63 -41
View File
@@ -234,7 +234,7 @@ private:
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to add " << mask;
FOREACH_MOD(OnAccessAdd, (ci, source, acc));
source.Reply(_("\002%s\002 added to %s %s list."), acc->Mask().c_str(), ci->name.c_str(), source.command.c_str());
source.Reply(_("\002%s\002 added to %s %s list."), acc->Mask().c_str(), ci->name.c_str(), source.command.nobreak().c_str());
}
void DoDel(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
@@ -256,7 +256,7 @@ private:
if (!ci->GetAccessCount())
{
source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.c_str());
source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.nobreak().c_str());
return;
}
@@ -315,11 +315,14 @@ private:
~XOPDelCallback() override
{
if (!deleted)
source.Reply(_("No matching entries on %s %s list."), ci->name.c_str(), source.command.c_str());
source.Reply(_("No matching entries on %s %s list."), ci->name.c_str(), source.command.nobreak().c_str());
else
{
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "to delete " << nicks;
source.Reply(deleted, N_("Deleted %d entry from %s %s list.", "Deleted %d entries from %s %s list."), deleted, ci->name.c_str(), source.command.c_str());
if (deleted == 1)
source.Reply(_("Deleted %s from %s %s list."), nicks.c_str(), ci->name.c_str(), source.command.nobreak().c_str());
else
source.Reply(deleted, N_("Deleted %d entry from %s %s list.", "Deleted %d entries from %s %s list."), deleted, ci->name.c_str(), source.command.nobreak().c_str());
}
}
@@ -360,7 +363,7 @@ private:
{
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to delete " << a->Mask();
source.Reply(_("\002%s\002 deleted from %s %s list."), a->Mask().c_str(), ci->name.c_str(), source.command.c_str());
source.Reply(_("\002%s\002 deleted from %s %s list."), a->Mask().c_str(), ci->name.c_str(), source.command.nobreak().c_str());
ci->EraseAccess(i);
FOREACH_MOD(OnAccessDel, (ci, source, a));
@@ -370,7 +373,7 @@ private:
}
}
source.Reply(_("\002%s\002 not found on %s %s list."), mask.c_str(), ci->name.c_str(), source.command.c_str());
source.Reply(_("\002%s\002 not found on %s %s list."), mask.c_str(), ci->name.c_str(), source.command.nobreak().c_str());
}
}
@@ -389,7 +392,7 @@ private:
if (!ci->GetAccessCount())
{
source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.c_str());
source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.nobreak().c_str());
return;
}
@@ -454,7 +457,7 @@ private:
std::vector<Anope::string> replies;
list.Process(replies);
source.Reply(_("%s list for %s"), source.command.c_str(), ci->name.c_str());
source.Reply(_("%s list for %s"), source.command.nobreak().c_str(), ci->name.c_str());
for (const auto &reply : replies)
source.Reply(reply);
}
@@ -470,7 +473,7 @@ private:
if (!ci->GetAccessCount())
{
source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.c_str());
source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.nobreak().c_str());
return;
}
@@ -495,7 +498,7 @@ private:
FOREACH_MOD(OnAccessClear, (ci, source));
source.Reply(_("Channel %s %s list has been cleared."), ci->name.c_str(), source.command.c_str());
source.Reply(_("Channel %s %s list has been cleared."), ci->name.c_str(), source.command.nobreak().c_str());
}
public:
@@ -509,7 +512,7 @@ public:
const Anope::string GetDesc(CommandSource &source) const override
{
return Anope::printf(Language::Translate(source.GetAccount(), _("Modify the list of %s users")), source.command.upper().c_str());
return Anope::printf(Language::Translate(source.GetAccount(), _("Modify the list of %s users")), source.command.nobreak().c_str());
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
@@ -542,59 +545,78 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Maintains the \002%s list\002 for a channel. Users who match an access entry\n"
"on the %s list receive the following privileges:\n"
" "), cmd.c_str(), cmd.c_str());
source.Reply(_(
"Maintains the \002%s list\002 for a channel. Users who match an access entry "
"on the %s list receive the following privileges:"
),
cmd.c_str(),
cmd.c_str());
source.Reply(" ");
Anope::string buf;
for (const auto &permission : permissions[cmd])
{
buf += ", " + permission;
if (buf.length() > 75)
{
source.Reply(" %s\n", buf.substr(2).c_str());
source.Reply(" %s", buf.substr(2).c_str());
buf.clear();
}
}
if (!buf.empty())
{
source.Reply(" %s\n", buf.substr(2).c_str());
source.Reply(" %s", buf.substr(2).c_str());
buf.clear();
}
source.Reply(_(" \n"
"The \002%s ADD\002 command adds the given nickname to the\n"
"%s list.\n"
" \n"
"The \002%s DEL\002 command removes the given nick from the\n"
"%s list. If a list of entry numbers is given, those\n"
"entries are deleted. (See the example for LIST below.)\n"
" \n"
"The \002%s LIST\002 command displays the %s list. If\n"
"a wildcard mask is given, only those entries matching the\n"
"mask are displayed. If a list of entry numbers is given,\n"
source.Reply(" ");
source.Reply(_(
"The \002%s\032ADD\002 command adds the given nickname to the "
"%s list."
"\n\n"
"The \002%s\032DEL\002 command removes the given nick from the "
"%s list. If a list of entry numbers is given, those "
"entries are deleted. (See the example for LIST below.)"
"\n\n"
"The \002%s\032LIST\002 command displays the %s list. If "
"a wildcard mask is given, only those entries matching the "
"mask are displayed. If a list of entry numbers is given, "
"only those entries are shown; for example:\n"
" \002%s #channel LIST 2-5,7-9\002\n"
" \002%s\032#channel\032LIST\0322-5,7-9\002\n"
" Lists %s entries numbered 2 through 5 and\n"
" 7 through 9.\n"
" \n"
"The \002%s CLEAR\002 command clears all entries of the\n"
"%s list."), cmd.c_str(), cmd.c_str(), cmd.c_str(), cmd.c_str(),
cmd.c_str(), cmd.c_str(), cmd.c_str(), cmd.c_str(), cmd.c_str(), cmd.c_str());
" 7 through 9."
"\n\n"
"The \002%s\032CLEAR\002 command clears all entries of the "
"%s list."
),
cmd.c_str(),
cmd.c_str(),
cmd.c_str(),
cmd.c_str(),
cmd.c_str(),
cmd.c_str(),
cmd.c_str(),
cmd.c_str(),
cmd.c_str(),
cmd.c_str());
BotInfo *access_bi, *flags_bi;
Anope::string access_cmd, flags_cmd;
Command::FindCommandFromService("chanserv/access", access_bi, access_cmd);
Command::FindCommandFromService("chanserv/flags", flags_bi, flags_cmd);
if (!access_cmd.empty() || !flags_cmd.empty())
{
source.Reply(_("Alternative methods of modifying channel access lists are\n"
"available."));
source.Reply(_("Alternative methods of modifying channel access lists are available."));
if (!access_cmd.empty())
source.Reply(_("See \002%s HELP %s\002 for more information\n"
"about the access list."), access_bi->GetQueryCommand().c_str(), access_cmd.c_str());
{
source.Reply(_("See \002%s\002 for more information about the access list."),
access_bi->GetQueryCommand("generic/help", access_cmd).c_str());
}
if (!flags_cmd.empty())
source.Reply(_("See \002%s HELP %s\002 for more information\n"
"about the flags system."), flags_bi->GetQueryCommand().c_str(), flags_cmd.c_str());
{
source.Reply(_("See \002%s\002 for more information about the flags system."),
flags_bi->GetQueryCommand("generic/help", flags_cmd).c_str());
}
}
return true;
}
@@ -621,7 +643,7 @@ public:
for (int i = 0; i < conf.CountBlock("privilege"); ++i)
{
Configuration::Block &block = conf.GetBlock("privilege", i);
const auto &block = conf.GetBlock("privilege", i);
const Anope::string &pname = block.Get<const Anope::string>("name");
Privilege *p = PrivilegeManager::FindPrivilege(pname);
@@ -637,7 +659,7 @@ public:
for (int i = 0; i < conf.CountBlock("command"); ++i)
{
Configuration::Block &block = conf.GetBlock("command", i);
const auto &block = conf.GetBlock("command", i);
const Anope::string &cname = block.Get<const Anope::string>("name"),
&cserv = block.Get<const Anope::string>("command");
if (cname.empty() || cserv != "chanserv/xop")
+1 -1
View File
@@ -499,7 +499,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &block = conf.GetModule(this);
const auto &block = conf.GetModule(this);
prefix = block.Get<const Anope::string>("prefix", "anope_");
SmileysHappy = block.Get<const Anope::string>("SmileysHappy");
SmileysSad = block.Get<const Anope::string>("SmileysSad");
+5 -6
View File
@@ -9,7 +9,6 @@
* Based on the original code of Services by Andy Church.
*/
#include <functional>
#include "module.h"
#include "modules/botserv/badwords.h"
@@ -883,7 +882,7 @@ private:
auto mlock_key = row.Get(); // May not exist.
auto *ci = new ChannelInfo(channel);
ci->time_registered = regtime;
ci->registered = regtime;
ci->last_used = used;
// No equivalent: elnv
@@ -1323,8 +1322,8 @@ private:
}
na = new NickAlias(nick, nc);
na->time_registered = regtime;
na->last_seen = lastseen ? regtime : na->time_registered;
na->registered = regtime;
na->last_seen = lastseen ? regtime : na->registered;
auto *data = userdata.Get(nc);
if (data)
@@ -1376,7 +1375,7 @@ private:
nc = new NickCore(display);
nc->email = email;
nc->time_registered = regtime;
nc->registered = regtime;
ApplyPassword(nc, flags, pass);
// No equivalent: bglmNQrS
@@ -1554,7 +1553,7 @@ public:
flags.clear();
for (int i = 0; i < Config->CountBlock("privilege"); ++i)
{
Configuration::Block &priv = Config->GetBlock("privilege", i);
const auto &priv = Config->GetBlock("privilege", i);
const Anope::string &name = priv.Get<const Anope::string>("name");
const Anope::string &value = priv.Get<const Anope::string>("flag");
if (!name.empty() && !value.empty())
+62 -51
View File
@@ -10,6 +10,7 @@
*/
#include <filesystem>
namespace fs = std::filesystem;
#include "yyjson/yyjson.c"
@@ -99,69 +100,24 @@ private:
// Whether OnLoadDatabase has been called yet.
bool loaded = false;
Anope::string GetDatabaseFile(Module *mod)
void CreateBackup(const Anope::string &backupdir, const fs::path &dbpath, size_t backups, const char *fmt, const char *glob)
{
Anope::string filename;
if (mod)
{
// We are reading the name of a module database.
filename = Config->GetModule(this)
.Get<Anope::string>("module_database", "{name}.module.json")
.replace_all_cs("{name}", mod->name);
}
else
{
// We are reading a the name of the core database.
filename = Config->GetModule(this)
.Get<Anope::string>("database", "anope.json");
}
return Anope::ExpandData(filename);
}
void BackupDatabase(const Anope::string &dbname)
{
namespace fs = std::filesystem;
std::error_code ec;
fs::path dbpath(dbname.str());
if (!fs::exists(dbpath, ec) || ec)
return; // Nothing to backup.
auto &modconf = Config->GetModule(this);
auto backups = modconf.Get<unsigned>("backups", "14");
if (!backups)
return; // No backups
auto ignore_backup_failure = modconf.Get<bool>("ignore_backup_failure");
auto backupdir = Anope::ExpandData(modconf.Get<Anope::string>("backup_directory", "backups"));
if (!fs::is_directory(backupdir.str(), ec) && !ec)
{
fs::create_directories(backupdir.str(), ec);
if (ec)
{
Log(this) << "Failed to create backup directory: " << ec.message();
if (!ignore_backup_failure)
{
Anope::Quitting = true;
Anope::QuitReason = "Failed to create backup directory: " + ec.message();
}
return;
}
}
return;
char timebuf[16];
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d", localtime(&Anope::CurTime));
strftime(timebuf, sizeof(timebuf), fmt, localtime(&Anope::CurTime));
auto backupbase = Anope::Expand(backupdir, dbpath.filename().string()) + ".";
auto backupname = backupbase + timebuf;
std::error_code ec;
Anope::string dbname = dbpath.string();
Log(LOG_DEBUG) << "Copying " << dbname << " to " << backupname;
if (!fs::copy_file(dbname.str(), backupname.str(), fs::copy_options::overwrite_existing, ec))
{
Log(this) << "Failed to copy " << dbname << " to " << backupname << ": " << ec.message();
if (!ignore_backup_failure)
if (!Config->GetModule(this).Get<bool>("ignore_backup_failure"))
{
Anope::Quitting = true;
Anope::QuitReason = "Failed to copy " + dbname + " to " + backupname + ": " + ec.message();
@@ -176,6 +132,9 @@ private:
if (entryname.compare(0, backupbase.length(), backupbase) != 0)
continue; // Not one of our backups.
if (!Anope::Match(entryname.substr(backupbase.length()), glob))
continue; // Not this type of backup.
old_backups.insert(entryname);
if (old_backups.size() <= backups)
continue;
@@ -190,6 +149,58 @@ private:
}
}
Anope::string GetDatabaseFile(Module *mod)
{
Anope::string filename;
if (mod)
{
// We are reading the name of a module database.
filename = Anope::Template(Config->GetModule(this).Get<Anope::string>("module_database", "{name}.module.json"), {
{ "name", mod->name },
});
}
else
{
// We are reading a the name of the core database.
filename = Config->GetModule(this).Get<Anope::string>("database", "anope.json");
}
return Anope::ExpandData(filename);
}
void BackupDatabase(const Anope::string &dbname)
{
std::error_code ec;
fs::path dbpath(dbname.str());
if (!fs::exists(dbpath, ec) || ec)
return; // Nothing to backup.
auto &modconf = Config->GetModule(this);
auto daily_backups = modconf.Get<size_t>("daily_backups", "7");
auto monthly_backups = modconf.Get<size_t>("monthly_backups", "3");
if (!daily_backups && !monthly_backups)
return; // No backups.
auto backupdir = Anope::ExpandData(modconf.Get<Anope::string>("backup_directory", "backups"));
if (!fs::is_directory(backupdir.str(), ec) && !ec)
{
fs::create_directories(backupdir.str(), ec);
if (ec)
{
Log(this) << "Failed to create backup directory: " << ec.message();
if (!modconf.Get<bool>("ignore_backup_failure"))
{
Anope::Quitting = true;
Anope::QuitReason = "Failed to create backup directory: " + ec.message();
}
return;
}
}
CreateBackup(backupdir, dbpath, daily_backups, "%Y-%m-%d", "\?\?\?\?-\?\?-\?\?");
CreateBackup(backupdir, dbpath, monthly_backups, "%Y-%m", "\?\?\?\?-\?\?");
}
DBPair ReadDatabase(const Anope::string &dbname)
{
yyjson_read_err errmsg;
+4 -4
View File
@@ -617,7 +617,7 @@ static void LoadNicks()
for (int c; (c = getc_db(f)) == 1;)
{
Anope::string nick, last_usermask, last_realname, last_quit;
time_t time_registered, last_seen;
time_t registered, last_seen;
READ(read_string(nick, f));
READ(read_string(last_usermask, f));
@@ -626,7 +626,7 @@ static void LoadNicks()
int32_t tmp32;
READ(read_int32(&tmp32, f));
time_registered = tmp32;
registered = tmp32;
READ(read_int32(&tmp32, f));
last_seen = tmp32;
@@ -672,7 +672,7 @@ static void LoadNicks()
na->last_usermask = last_usermask;
na->last_realname = last_realname;
na->last_quit = last_quit;
na->time_registered = time_registered;
na->registered = registered;
na->last_seen = last_seen;
if (tmpu16 & OLD_NS_NO_EXPIRE)
@@ -785,7 +785,7 @@ static void LoadChannels()
int32_t tmp32;
READ(read_int32(&tmp32, f));
ci->time_registered = tmp32;
ci->registered = tmp32;
READ(read_int32(&tmp32, f));
ci->last_used = tmp32;
+1 -1
View File
@@ -173,7 +173,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &block = conf.GetModule(this);
const auto &block = conf.GetModule(this);
this->redis = ServiceReference<Provider>("Redis::Provider", block.Get<const Anope::string>("engine", "redis/main"));
}
+1 -1
View File
@@ -162,7 +162,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &block = conf.GetModule(this);
const auto &block = conf.GetModule(this);
this->sql = ServiceReference<Provider>("SQL::Provider", block.Get<const Anope::string>("engine"));
this->prefix = block.Get<const Anope::string>("prefix", "anope_db_");
this->import = block.Get<bool>("import");
+1 -1
View File
@@ -141,7 +141,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &block = conf.GetModule(this);
const auto &block = conf.GetModule(this);
this->SQL = ServiceReference<Provider>("SQL::Provider", block.Get<const Anope::string>("engine"));
this->prefix = block.Get<const Anope::string>("prefix", "anope_db_");
}
+2 -2
View File
@@ -1047,7 +1047,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &block = conf.GetModule(this);
const auto &block = conf.GetModule(this);
nameserver = block.Get<const Anope::string>("nameserver", "127.0.0.1");
timeout = block.Get<time_t>("timeout", "5");
@@ -1059,7 +1059,7 @@ public:
for (int i = 0; i < block.CountBlock("notify"); ++i)
{
Configuration::Block &n = block.GetBlock("notify", i);
const auto &n = block.GetBlock("notify", i);
Anope::string nip = n.Get<Anope::string>("ip");
short nport = n.Get<short>("port");
+14 -12
View File
@@ -70,14 +70,16 @@ public:
if (reply && reply->allow_account && user->IsIdentified())
return;
Anope::string reason = this->blacklist.reason, addr = user->ip.addr();
reason = reason.replace_all_cs("%n", user->nick);
reason = reason.replace_all_cs("%u", user->GetIdent());
reason = reason.replace_all_cs("%g", user->realname);
reason = reason.replace_all_cs("%h", user->host);
reason = reason.replace_all_cs("%i", addr);
reason = reason.replace_all_cs("%r", reply ? reply->reason : "");
reason = reason.replace_all_cs("%N", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname"));
auto addr = user->ip.addr();
auto reason = Anope::Template(this->blacklist.reason, {
{ "nick", user->nick },
{ "user", user->GetIdent() },
{ "real", user->realname },
{ "host", user->host },
{ "ip", addr },
{ "reply", reply ? reply->reason : "" },
{ "network", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname") },
});
BotInfo *OperServ = Config->GetClient("OperServ");
Log(creator, "dnsbl", OperServ) << user->GetMask() << " (" << addr << ") appears in " << this->blacklist.name;
@@ -112,7 +114,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &block = conf.GetModule(this);
const auto &block = conf.GetModule(this);
this->check_on_connect = block.Get<bool>("check_on_connect");
this->check_on_netburst = block.Get<bool>("check_on_netburst");
this->add_to_akill = block.Get<bool>("add_to_akill", "yes");
@@ -120,7 +122,7 @@ public:
this->blacklists.clear();
for (int i = 0; i < block.CountBlock("blacklist"); ++i)
{
Configuration::Block &bl = block.GetBlock("blacklist", i);
const auto &bl = block.GetBlock("blacklist", i);
Blacklist blacklist;
blacklist.name = bl.Get<Anope::string>("name");
@@ -131,7 +133,7 @@ public:
for (int j = 0; j < bl.CountBlock("reply"); ++j)
{
Configuration::Block &reply = bl.GetBlock("reply", j);
const auto &reply = bl.GetBlock("reply", j);
Blacklist::Reply r;
r.code = reply.Get<int>("code");
@@ -147,7 +149,7 @@ public:
this->exempts.clear();
for (int i = 0; i < block.CountBlock("exempt"); ++i)
{
Configuration::Block &bl = block.GetBlock("exempt", i);
const auto &bl = block.GetBlock("exempt", i);
this->exempts.insert(bl.Get<Anope::string>("ip"));
}
}
+1 -1
View File
@@ -128,7 +128,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
this->defaultprovider = GetAlgorithm(Config->GetModule(this).Get<const Anope::string>("algorithm", "sha256"));
this->defaultprovider = GetAlgorithm(Config->GetModule(this).Get<const Anope::string>("algorithm", "sha512"));
}
EventReturn OnEncrypt(const Anope::string &src, Anope::string &dest) override
+2 -2
View File
@@ -546,7 +546,7 @@ public:
void OnReload(Configuration::Conf &config) override
{
Configuration::Block &conf = config.GetModule(this);
const auto &conf = config.GetModule(this);
for (std::map<Anope::string, LDAPService *>::iterator it = this->LDAPServices.begin(); it != this->LDAPServices.end();)
{
@@ -574,7 +574,7 @@ public:
for (int i = 0; i < conf.CountBlock("ldap"); ++i)
{
Configuration::Block &ldap = conf.GetBlock("ldap", i);
const auto &ldap = conf.GetBlock("ldap", i);
const Anope::string &connname = ldap.Get<const Anope::string>("name", "ldap/main");
+2 -2
View File
@@ -262,7 +262,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &config = conf.GetModule(this);
const auto &config = conf.GetModule(this);
for (std::map<Anope::string, MySQLService *>::iterator it = this->MySQLServices.begin(); it != this->MySQLServices.end();)
{
@@ -287,7 +287,7 @@ public:
for (int i = 0; i < config.CountBlock("mysql"); ++i)
{
Configuration::Block &block = config.GetBlock("mysql", i);
const auto &block = config.GetBlock("mysql", i);
const Anope::string &connname = block.Get<const Anope::string>("name", "mysql/main");
if (this->MySQLServices.find(connname) == this->MySQLServices.end())
+2 -2
View File
@@ -115,7 +115,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &config = conf.GetModule(this);
const auto &config = conf.GetModule(this);
for (std::map<Anope::string, SQLiteService *>::iterator it = this->SQLiteServices.begin(); it != this->SQLiteServices.end();)
{
@@ -139,7 +139,7 @@ public:
for (int i = 0; i < config.CountBlock("sqlite"); ++i)
{
Configuration::Block &block = config.GetBlock("sqlite", i);
const auto &block = config.GetBlock("sqlite", i);
Anope::string connname = block.Get<const Anope::string>("name", "sqlite/main");
if (this->SQLiteServices.find(connname) == this->SQLiteServices.end())
+2 -2
View File
@@ -329,7 +329,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &config = conf.GetModule(this);
const auto &config = conf.GetModule(this);
const Anope::string certfile = Anope::ExpandConfig(config.Get<const Anope::string>("cert", "fullchain.pem"));
const Anope::string keyfile = Anope::ExpandConfig(config.Get<const Anope::string>("key", "privkey.pem"));
@@ -365,7 +365,7 @@ public:
void OnPreServerConnect() override
{
Configuration::Block &config = Config->GetBlock("uplink", Anope::CurrentUplink);
const auto &config = Config->GetBlock("uplink", Anope::CurrentUplink);
if (config.Get<bool>("ssl"))
{
+2 -2
View File
@@ -146,7 +146,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &config = conf.GetModule(this);
const auto &config = conf.GetModule(this);
this->certfile = Anope::ExpandConfig(config.Get<const Anope::string>("cert", "fullchain.pem"));
this->keyfile = Anope::ExpandConfig(config.Get<const Anope::string>("key", "privkey.pem"));
@@ -213,7 +213,7 @@ public:
void OnPreServerConnect() override
{
Configuration::Block &config = Config->GetBlock("uplink", Anope::CurrentUplink);
const auto &config = Config->GetBlock("uplink", Anope::CurrentUplink);
if (config.Get<bool>("ssl"))
{
+12 -10
View File
@@ -67,16 +67,18 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(_(" \n"
"Enables or disables \002fantasy\002 mode on a channel.\n"
"When it is enabled, users will be able to use\n"
"fantasy commands on a channel when prefixed\n"
"with one of the following fantasy characters: \002%s\002\n"
" \n"
"Note that users wanting to use fantasy commands\n"
"MUST have enough access for both the FANTASY\n"
"privilege and the command they are executing."),
Config->GetModule(this->owner).Get<const Anope::string>("fantasycharacter", "!").c_str());
source.Reply(" ");
source.Reply(_(
"Enables or disables \002fantasy\002 mode on a channel. "
"When it is enabled, users will be able to use "
"fantasy commands on a channel when prefixed "
"with one of the following fantasy characters: \002%s\002"
"\n\n"
"Note that users wanting to use fantasy commands "
"MUST have enough access for both the FANTASY "
"privilege and the command they are executing."
),
Config->GetModule(this->owner).Get<const Anope::string>("fantasycharacter", "!").c_str());
return true;
}
};
+7 -6
View File
@@ -77,12 +77,13 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Allows sending messages to all users on the network. The message will be sent\n"
"from \002%s\002.\n"
"\n"
"You can either send a message by specifying it as a parameter or provide no\n"
"parameters to send a previously queued message.\n"
), GetSender(source)->nick.c_str());
"Allows sending messages to all users on the network. The message will be sent "
"from \002%s\002."
"\n\n"
"You can either send a message by specifying it as a parameter or provide no "
"parameters to send a previously queued message."
),
GetSender(source)->nick.c_str());
return true;
}
};
+16 -11
View File
@@ -167,17 +167,22 @@ public:
this->SendSyntax(source);
source.Reply("");
source.Reply(_(
"Allows queueing messages to send to users on the network.\n"
"\n"
"The \002QUEUE ADD\002 command adds the given message to the message queue."
"\n"
"The \002QUEUE CLEAR\002 command clears the message queue."
"\n"
"The \002QUEUE DEL\002 command removes the specified message from the message queue. The\n"
"message number can be obtained from the output of the \002QUEUE LIST\002 command."
"\n"
"The \002QUEUE LIST\002 command lists all messages that are currently in the message queue."
));
"Allows queueing messages to send to users on the network."
"\n\n"
"The \002%s\032ADD\002 command adds the given message to the message queue."
"\n\n"
"The \002%s\032CLEAR\002 command clears the message queue."
"\n\n"
"The \002%s\032DEL\002 command removes the specified message from the message queue. The "
"message number can be obtained from the output of the \002%s\032LIST\002 command."
"\n\n"
"The \002%s\032LIST\002 command lists all messages that are currently in the message queue."
),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str(),
source.command.nobreak().c_str());
return true;
}
};
+7 -6
View File
@@ -84,12 +84,13 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_(
"Allows sending messages to all users on a server. The message will be sent\n"
"from \002%s\002.\n"
"\n"
"You can either send a message by specifying it as a parameter or provide no\n"
"parameters to send a previously queued message.\n"
), GetSender(source)->nick.c_str());
"Allows sending messages to all users on a server. The message will be sent "
"from \002%s\002."
"\n\n"
"You can either send a message by specifying it as a parameter or provide no "
"parameters to send a previously queued message."
),
GetSender(source)->nick.c_str());
return true;
}
};
+20 -14
View File
@@ -67,12 +67,14 @@ public:
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(_(" \n"
"Enables or disables \002greet\002 mode on a channel.\n"
"When it is enabled, the bot will display greet\n"
"messages of users joining the channel, provided\n"
"they have enough access to the channel."));
return true;
source.Reply(" ");
source.Reply(_(
"Enables or disables \002greet\002 mode on a channel. "
"When it is enabled, the bot will display greet "
"messages of users joining the channel, provided "
"they have enough access to the channel."
));
return true;
}
};
@@ -130,10 +132,12 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Makes the given message the greet of your nickname, that\n"
"will be displayed when joining a channel that has GREET\n"
"option enabled, provided that you have the necessary\n"
"access on it."));
source.Reply(_(
"Makes the given message the greet of your nickname, that "
"will be displayed when joining a channel that has GREET "
"option enabled, provided that you have the necessary "
"access on it."
));
return true;
}
};
@@ -157,10 +161,12 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Makes the given message the greet of the nickname, that\n"
"will be displayed when joining a channel that has GREET\n"
"option enabled, provided that the user has the necessary\n"
"access on it."));
source.Reply(_(
"Makes the given message the greet of the nickname, that "
"will be displayed when joining a channel that has GREET "
"option enabled, provided that the user has the necessary "
"access on it."
));
return true;
}
};
+4 -2
View File
@@ -47,6 +47,7 @@ public:
bool hide_privileged_commands = Config->GetBlock("options").Get<bool>("hideprivilegedcommands"),
hide_registered_commands = Config->GetBlock("options").Get<bool>("hideregisteredcommands");
HelpWrapper help;
if (params.empty() || params[0].equals_ci("ALL"))
{
bool all = !params.empty() && params[0].equals_ci("ALL");
@@ -88,9 +89,10 @@ public:
}
source.command = c_name;
c->OnServHelp(source);
c->OnServHelp(source, help);
}
help.SendTo(source);
for (auto &[gr, cmds] : groups)
{
@@ -117,7 +119,7 @@ public:
if (!groups.empty())
{
source.Reply(" ");
source.Reply(_("Use the \002%s ALL\002 command to list all commands and their descriptions."), source_command.c_str());
source.Reply(_("Use the \002%s\032ALL\002 command to list all commands and their descriptions."), source.command.nobreak().c_str());
}
}
else
+2 -4
View File
@@ -46,8 +46,7 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Deletes the vhost assigned to the given nick from the\n"
"database."));
source.Reply(_("Deletes the vhost assigned to the given nick from the database."));
return true;
}
};
@@ -92,8 +91,7 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Deletes the vhost for all nicks in the same group as\n"
"that of the given nick."));
source.Reply(_("Deletes the vhost for all nicks in the same group as that of the given nick."));
return true;
}
};
+6 -4
View File
@@ -67,9 +67,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("This command allows users to set the vhost of their\n"
"CURRENT nick to be the vhost for all nicks in the same\n"
"group."));
source.Reply(_(
"This command allows users to set the vhost of their "
"CURRENT nick to be the vhost for all nicks in the same "
"group."
));
return true;
}
};
@@ -107,7 +109,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
Configuration::Block &block = conf.GetModule(this);
const auto &block = conf.GetModule(this);
syncongroup = block.Get<bool>("syncongroup");
synconset = block.Get<bool>("synconset");
}
+9 -7
View File
@@ -123,13 +123,15 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("This command lists registered vhosts to the operator.\n"
"If a \037key\037 is specified, only entries whose nick or vhost match\n"
"the pattern given in \037key\037 are displayed e.g. Rob* for all\n"
"entries beginning with \"Rob\"\n"
"If a \037#X-Y\037 style is used, only entries between the range of \002X\002\n"
"and \002Y\002 will be displayed, e.g. \002#1-3\002 will display the first 3\n"
"nick/vhost entries."));
source.Reply(_(
"This command lists registered vhosts to the operator. "
"If a \037key\037 is specified, only entries whose nick or vhost match "
"the pattern given in \037key\037 are displayed e.g. Rob* for all "
"entries beginning with \"Rob\". "
"If a \037#X-Y\037 style is used, only entries between the range of \002X\002 "
"and \002Y\002 will be displayed, e.g. \002#1-3\002 will display the first 3 "
"nick/vhost entries."
));
return true;
}
};
+5 -3
View File
@@ -47,9 +47,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Deactivates the vhost currently assigned to the nick in use.\n"
"When you use this command any user who performs a /whois\n"
"on you will see your real host/IP address."));
source.Reply(_(
"Deactivates the vhost currently assigned to the nick in use. "
"When you use this command any user who performs a /whois "
"on you will see your real host/IP address."
));
return true;
}
};
+5 -3
View File
@@ -50,9 +50,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Activates the vhost currently assigned to the nick in use.\n"
"When you use this command any user who performs a /whois\n"
"on you will see the vhost instead of your real host/IP address."));
source.Reply(_(
"Activates the vhost currently assigned to the nick in use. "
"When you use this command any user who performs a /whois "
"on you will see the vhost instead of your real host/IP address."
));
return true;
}
};
+5 -3
View File
@@ -189,9 +189,11 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Request the given vhost to be activated for your nick by the\n"
"network administrators. Please be patient while your request\n"
"is being considered."));
source.Reply(_(
"Request the given vhost to be activated for your nick by the "
"network administrators. Please be patient while your request "
"is being considered."
));
return true;
}
};
+15 -10
View File
@@ -94,10 +94,12 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the vhost for the given nick to that of the given\n"
"hostmask. If your IRCD supports vidents, then using\n"
"SET <nick> <ident>@<hostmask> set idents for users as\n"
"well as vhosts."));
source.Reply(_(
"Sets the vhost for the given nick to that of the given "
"hostmask. If your IRCD supports vidents, then using "
"SET <nick> <ident>@<hostmask> set idents for users as "
"well as vhosts."
));
return true;
}
};
@@ -198,12 +200,15 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Sets the vhost for all nicks in the same group as that\n"
"of the given nick. If your IRCD supports vidents, then\n"
"using SETALL <nick> <ident>@<hostmask> will set idents\n"
"for users as well as vhosts.\n"
"* NOTE, this will not update the vhost for any nicks\n"
"added to the group after this command was used."));
source.Reply(_(
"Sets the vhost for all nicks in the same group as that "
"of the given nick. If your IRCD supports vidents, then "
"using SETALL <nick> <ident>@<hostmask> will set idents "
"for users as well as vhosts."
"\n\n"
"* NOTE, this will not update the vhost for any nicks "
"added to the group after this command was used."
));
return true;
}
};
+2 -2
View File
@@ -362,12 +362,12 @@ public:
void OnReload(Configuration::Conf &config) override
{
Configuration::Block &conf = config.GetModule(this);
const auto &conf = config.GetModule(this);
std::set<Anope::string> existing;
for (int i = 0; i < conf.CountBlock("httpd"); ++i)
{
Configuration::Block &block = conf.GetBlock("httpd", i);
const auto &block = conf.GetBlock("httpd", i);
const Anope::string &hname = block.Get<const Anope::string>("name", "httpd/main");
+2 -2
View File
@@ -19,7 +19,7 @@ void IRC2SQL::OnShutdown()
void IRC2SQL::OnReload(Configuration::Conf &conf)
{
Configuration::Block &block = Config->GetModule(this);
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");
@@ -310,7 +310,7 @@ void IRC2SQL::OnBotNotice(User *u, BotInfo *bi, Anope::string &message, const An
return;
u->Extend<bool>("CTCPVERSION");
auto versionstr = Anope::NormalizeBuffer(message.substr(9, message.length() - 10));
auto versionstr = Anope::NormalizeBuffer(ctcpbody);
if (versionstr.empty())
return;

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