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

Compare commits

...

72 Commits

Author SHA1 Message Date
Sadie Powell a861a059f6 Fix the config parser using int for values that can not be negative. 2026-06-08 15:41:00 +01:00
Sadie Powell 90da25f84f Add Block::GetBlocks which returns an iterable list of blocks. 2026-06-08 15:39:28 +01:00
Sadie Powell ab362c9828 Pascalize some typedefs in Configuration::Block. 2026-06-08 14:17:30 +01:00
Kufat d1f6da1817 Allow specifying the order of ns_set_misc entries. 2026-06-08 09:36:18 +01:00
Sadie Powell 9280d90aba Make it clear that the hmac-* algos can't be used in the config. 2026-06-08 09:09:19 +01:00
Sadie Powell c71f69208d Add various config options to the argon2 algo in anope-mkpasswd. 2026-06-08 09:08:19 +01:00
Sadie Powell d0080b85a7 Fix a typo in the default Argon2 priority in the example config. 2026-06-08 09:07:16 +01:00
Sadie Powell 745e94783d Respect BCRYPT_ROUNDS from the environment in anope-mkpasswd. 2026-06-08 08:58:15 +01:00
Sadie Powell c32be6a711 Fix a missing colon when REPRODUCIBLE_BUILD is defined. 2026-06-08 08:54:46 +01:00
Kufat 9dd3acfc87 Append EXTRA_CONFIG_ARGS to CMake command 2026-06-05 20:34:09 +01:00
Sadie Powell 82b6da3763 Merge branch '2.0' into 2.1. 2026-05-26 10:48:07 +01:00
Sadie Powell 8e691eac80 Update the change log. 2026-05-26 10:44:44 +01:00
Sadie Powell 2327c6ac9a Fix an escaped value that wasn't escaped enough in chanstats. 2026-05-26 10:36:50 +01:00
Sadie Powell e23ea8f8ea Escape user-provided values in ldap_authentication and ldap_oper. 2026-05-26 09:30:15 +01:00
Sadie Powell 449cfa6503 Add EscapeDN and EscapeSF to the LDAP API. 2026-05-26 09:29:57 +01:00
Sadie Powell 59c60849b6 Remove hard coded references to default access levels. 2026-05-21 11:52:32 +01:00
Sadie Powell 6d2c4fb612 Merge branch '2.0' into 2.1. 2026-05-20 22:14:37 +01:00
Sadie Powell 01fc7421b6 Backport the pull request checks from 2.0. 2026-05-20 22:13:38 +01:00
TehPeGaSuS 3a59a81aa4 Update the Portuguese translation. 2026-05-20 20:57:10 +01:00
Sadie Powell c24de0ca8f Fix update.sh on recent gettext. 2026-05-20 17:42:17 +01:00
KidProtect 18555638c9 Update the Romanian translation. 2026-05-20 09:59:48 +01:00
Sadie Powell d5a653fe94 Make it clearer how to enable localisation. 2026-05-19 16:14:14 +01:00
Sadie Powell ad3be96283 Increase {nickserv}:regdelay to 15 minutes, add {ns_group}:delay. 2026-05-17 16:06:42 +01:00
Sadie Powell d689c0686d Update the Conan dependencies. 2026-05-16 20:57:44 +01:00
Sadie Powell 4ca2952069 Update the change log. 2026-05-16 20:57:44 +01:00
Sadie Powell caf904c938 Fix updating the access description in cs_flags. 2026-05-16 11:23:25 +01:00
Sadie Powell 8930cc2a92 Avoid potential crashes from calling strftime on a weird value. 2026-05-15 19:51:57 +01:00
Sadie Powell 47b927d788 Fix a crash from an uninitialised field in migrated flags. 2026-05-15 19:45:28 +01:00
Sadie Powell 647a07ff96 Fix an crash when a user migrates their own access. 2026-05-15 15:54:57 +01:00
Sadie Powell a856e80b1e Move migration messages to cs_flags, split non-migratable and non-migrated. 2026-05-15 09:06:02 +01:00
Sadie Powell 55746e1098 Fix users getting extra privileges when migrating to flags. 2026-05-15 08:43:03 +01:00
Sadie Powell e0da3bae18 Fix confirming accounts when admin-only confirmation is enabled. 2026-05-14 19:24:29 +01:00
Sadie Powell c1cf7b0bcc Fix checking if an access entry has a flag when migrating.
Closes #574.
2026-05-13 23:41:01 +01:00
Sadie Powell 1cf64a49c0 Fix the unique runtime library names on Windows. 2026-05-12 14:20:21 +01:00
Sadie Powell 92ed0071d7 Make the runtime copy error more verbose. 2026-05-12 14:10:04 +01:00
Sadie Powell 9469cb8b0e Merge branch '2.0' into 2.1 2026-05-12 13:53:36 +01:00
Sadie Powell e0b715b185 Sync the CI scripts. 2026-05-12 11:28:28 +01:00
Sadie Powell e6d7306202 Backport the mailmap changes from 2.1. 2026-05-12 11:26:06 +01:00
Sadie Powell 2107d18d9e Remove suggestion to email language file updates to team@.
Its 2026 and its way easier for everyone involved to just file a
pull request.
2026-05-11 13:00:55 +01:00
Sadie Powell acb9428635 Backport the locales-all advice from 2.1. 2026-05-11 12:58:47 +01:00
Sadie Powell d942da1df5 Update author list. 2026-05-06 12:01:57 +01:00
Sadie Powell a961259556 Merge branch '2.0' into 2.1. 2026-05-06 12:00:21 +01:00
Sadie Powell 27a19dcc52 Update the mailmap. 2026-05-06 11:59:03 +01:00
Sadie Powell e45814bfd6 Deduplicate the timer constructors with delegation. 2026-05-02 15:40:19 +01:00
Sadie Powell f12b590a6d Change Timer::Tick to return bool, get rid of the repeating field. 2026-05-02 15:40:19 +01:00
Sadie Powell c0bafe10b4 Avoid double deleting the ban timer in cs_ban. 2026-05-02 10:55:25 +01:00
dependabot[bot] 5f40d0d6bb Bump negrutiu/nsis-install from 2 to 3
Bumps [negrutiu/nsis-install](https://github.com/negrutiu/nsis-install) from 2 to 3.
- [Release notes](https://github.com/negrutiu/nsis-install/releases)
- [Commits](https://github.com/negrutiu/nsis-install/compare/v2...v3)

---
updated-dependencies:
- dependency-name: negrutiu/nsis-install
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-01 21:27:36 +01:00
Sadie Powell 6b416cc64d Bump for 2.1.25-git. 2026-05-01 12:39:20 +01:00
Sadie Powell 331c33c350 Release 2.1.24. 2026-05-01 12:38:33 +01:00
Sadie Powell 10eef1af23 Update the change log. 2026-05-01 12:38:18 +01:00
Sadie Powell 90ff716ed3 Remove using statements that break unity builds. 2026-04-30 13:37:03 +01:00
Sadie Powell f67c70e485 Get rid of the using statement for Configuration::Uplink.
This breaks unity builds.
2026-04-30 13:23:06 +01:00
Sadie Powell fd5e10c54c Fix an inverted default for should_commit. 2026-04-27 20:10:53 +01:00
Sadie Powell 029565c894 Convert some messages in cs_enforce to use format strings. 2026-04-26 18:26:23 +01:00
Sadie Powell 9b8862826c Sort the files before running xgettext so we get consistent output. 2026-04-26 18:24:19 +01:00
Sadie Powell e2dc77641a Add some helper methods to CommandSource for translation. 2026-04-26 18:07:56 +01:00
Sadie Powell 7eb710a009 Update the change log. 2026-04-26 12:57:03 +01:00
Sadie Powell b33b5a6630 Use versioned prefixes for the SQL database tables. 2026-04-26 12:49:54 +01:00
Sadie Powell f4d5b1f01d Clean up the Config script a bit. 2026-04-26 12:45:57 +01:00
Sadie Powell b61daf81b0 Allow as many dashes as provided on Config options. 2026-04-23 19:23:12 +01:00
Sadie Powell da3f667188 Update the change log. 2026-04-23 19:08:55 +01:00
Sadie Powell 040cd99027 Add more debug logging to db_json. 2026-04-23 19:08:55 +01:00
Sadie Powell 6c7977f239 Remove duplicate objects from corrupt databases on database write. 2026-04-23 19:08:55 +01:00
Sadie Powell 9b8570a2ee Banish Redis support to the shadow realm.
Nobody actually uses this and it hasn't been tested in years so it
a massive pain to maintain. It may be replaced with an alternate
NoSQL database such as MongoDB in the future.
2026-04-23 17:42:42 +01:00
Sadie Powell 64f386e29e Skip deserialising the old cert column when its empty. 2026-04-23 13:48:12 +01:00
Sadie Powell 9434be29bc Delete the cert object after removing it from the cert list. 2026-04-23 13:41:11 +01:00
Sadie Powell 9aff71fb2f Merge branch '2.0' into 2.1. 2026-04-16 11:54:36 +01:00
Sadie Powell ba26d9a15c Add a missing FNAME handler on InspIRCd 3+.
Closes #572.
2026-04-16 11:50:10 +01:00
Sadie Powell 22dc33de9f Add support for the ratified channel-context tag. 2026-04-09 12:01:16 +01:00
dependabot[bot] 11d6f58a1a Bump microsoft/setup-msbuild from 2 to 3
Bumps [microsoft/setup-msbuild](https://github.com/microsoft/setup-msbuild) from 2 to 3.
- [Release notes](https://github.com/microsoft/setup-msbuild/releases)
- [Commits](https://github.com/microsoft/setup-msbuild/compare/v2...v3)

---
updated-dependencies:
- dependency-name: microsoft/setup-msbuild
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 22:06:38 +01:00
Sadie Powell f32d6453f5 Bump for 2.1.24-git. 2026-04-01 10:58:23 +01:00
Sadie Powell 9834040948 Fix checking the wrong config option in os_stats. 2026-03-11 16:41:50 +00:00
107 changed files with 5083 additions and 2214 deletions
+2 -1
View File
@@ -35,5 +35,6 @@ 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.
- [ ] If the pull request contains a security fix I have followed the reporting rules mentioned in [the security policy](https://github.com/anope/anope/security/policy) (delete if not applicable).
- [ ] I have documented any features added by this pull request (delete if not applicable).
- [ ] This pull request does not introduce any incompatible API changes (stable branches only, delete if not applicable).
+24 -15
View File
@@ -3,21 +3,18 @@ on:
pull_request:
push:
schedule:
- cron: '0 0 * * 0'
- cron: 0 0 * * 0
workflow_dispatch:
jobs:
build:
if: "!contains(github.event.head_commit.message, '[skip alpine ci]')"
container: alpine:edge
container: alpine:latest
runs-on: ubuntu-latest
env:
CXX: ${{ matrix.compiler }}
CXXFLAGS: -Werror
steps:
- uses: actions/checkout@v6
- name: Install dependencies
run: |
run: |-
echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
apk update
apk add \
@@ -37,24 +34,36 @@ jobs:
tre-dev
- name: Enable extras
run: |
run: |-
for MODULE in enc_argon2 enc_posix ldap mysql regex_pcre2 regex_posix regex_tre sqlite ssl_gnutls ssl_openssl
do
ln -s $PWD/modules/extra/$MODULE.cpp $PWD/modules
done
- name: Run CMake
run: |
mkdir build && cd build
cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=DEBUG -DINSTDIR:STRING=$(readlink -f ../run) ..
env:
CC: ${{ matrix.compiler.cc }}
CXX: ${{ matrix.compiler.cxx }}
CXXFLAGS: -Werror
run: |-
cmake -B "build" \
-D "CMAKE_BUILD_TYPE=Debug" \
-D "INSTDIR=$(readlink -f ../run)" \
-G "Ninja" \
-Wdeprecated \
-Wdev
- name: Build Anope
run: |
ninja -C build install
- name: Build and install
env:
VERBOSE: ${{ runner.debug }}
run: |-
ninja -C "build" ${{ runner.debug == '1' && '-v' || '' }} install
strategy:
fail-fast: false
matrix:
compiler:
- clang++
- g++
- cc: clang
cxx: clang++
- cc: gcc
cxx: g++
+24 -15
View File
@@ -3,20 +3,17 @@ on:
pull_request:
push:
schedule:
- cron: '0 0 * * 0'
- cron: 0 0 * * 0
workflow_dispatch:
jobs:
build:
if: "!contains(github.event.head_commit.message, '[skip ubuntu ci]')"
runs-on: ubuntu-24.04
env:
CXX: ${{ matrix.compiler }}
CXXFLAGS: -Werror
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install dependencies
run: |
run: |-
sudo apt-get update --assume-yes
sudo apt-get install --assume-yes --no-install-recommends \
clang \
@@ -34,24 +31,36 @@ jobs:
ninja-build
- name: Enable extras
run: |
run: |-
for MODULE in enc_argon2 enc_posix ldap mysql regex_pcre2 regex_posix regex_tre sqlite ssl_gnutls ssl_openssl
do
ln -s ${{ github.workspace }}/modules/extra/$MODULE.cpp ${{ github.workspace }}/modules
done
- name: Run CMake
run: |
mkdir build && cd build
cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=DEBUG -DINSTDIR:STRING=${{ github.workspace }}/run ..
env:
CC: ${{ matrix.compiler.cc }}
CXX: ${{ matrix.compiler.cxx }}
CXXFLAGS: -Werror
run: |-
cmake -B "build" \
-D "CMAKE_BUILD_TYPE=Debug" \
-D "INSTDIR=${{ github.workspace }}/run" \
-G "Ninja" \
-Wdeprecated \
-Wdev
- name: Build Anope
run: |
ninja -C ${{ github.workspace }}/build install
- name: Build and install
env:
VERBOSE: ${{ runner.debug }}
run: |-
ninja -C "build" ${{ runner.debug == '1' && '-v' || '' }} install
strategy:
fail-fast: false
matrix:
compiler:
- clang++
- g++
- cc: clang
cxx: clang++
- cc: gcc
cxx: g++
+38 -25
View File
@@ -6,77 +6,90 @@ on:
types:
- published
schedule:
- cron: '0 0 * * 0'
- cron: 0 0 * * 0
workflow_dispatch:
jobs:
build:
if: "!contains(github.event.head_commit.message, '[skip windows ci]')"
runs-on: windows-2025
env:
BUILD_PATH: ${{ github.workspace }}\build
BUILD_TYPE: ${{ github.event_name == 'release' && 'Release' || 'Debug' }}
CONAN_FILE: ${{ github.workspace }}\src\win32\conanfile.txt
CONAN_HOME: ${{ github.workspace }}\build\conan
steps:
- uses: actions/checkout@v6
- name: Install NSIS
uses: negrutiu/nsis-install@v2
- name: Setup MSVC
uses: TheMrMilchmann/setup-msvc-dev@v4
with:
arch: x64
- name: Setup NSIS
uses: negrutiu/nsis-install@v3
with:
distro: official
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2
- name: Setup Conan
uses: turtlebrowser/get-conan@v1.2
- name: Create Conan profile
- name: Create Conan configuration
run: |-
conan profile detect
(Get-Content ${{ env.CONAN_HOME }}\profiles\default).replace('build_type=Release', 'build_type=${{ env.BUILD_TYPE }}') | Set-Content ${{ env.CONAN_HOME }}\profiles\default
(Get-Content ${{ env.CONAN_HOME }}\profiles\default).replace('compiler.cppstd=14', 'compiler.cppstd=17') | Set-Content ${{ env.CONAN_HOME }}\profiles\default
Write-Output 'core.sources:download_urls=["origin", "https://c3i.jfrog.io/artifactory/conan-center-backup-sources/"]' | Out-File -Append ${{ env.CONAN_HOME }}\global.conf
Write-Output 'tools.cmake.cmaketoolchain:generator=Ninja' | Out-File -Append ${{ env.CONAN_HOME }}\global.conf
Write-Output 'user.openssl:windows_use_jom=True' | Out-File -Append ${{ env.CONAN_HOME }}\global.conf
- name: Try to restore libraries from the cache
if: github.event_name != 'release'
uses: actions/cache/restore@v5
id: library-cache
with:
key: conan-${{ env.BUILD_TYPE }}-${{ hashFiles('src\win32\conanfile.txt') }}
path: ${{ env.CONAN_HOME }}\p
key: Conan VS${{ env.VisualStudioVersion }} ${{ env.BUILD_TYPE }} ${{ hashFiles(env.CONAN_FILE) }}
path: ${{ env.CONAN_HOME }}/p
- name: Install libraries
run: |
(Get-Content ${{ github.workspace }}\src\win32\conanfile.txt).replace('##', '') | Set-Content ${{ github.workspace }}\src\win32\conanfile.txt
conan install ${{ github.workspace }}\src\win32 --build missing --deployer runtime_deploy --deployer-folder ${{ github.workspace }}\build\extradll --output-folder .
working-directory: ${{ env.BUILD_PATH }}
run: |-
(Get-Content ${{ env.CONAN_FILE }}).replace('##', '') | Set-Content ${{ env.CONAN_FILE }}
conan install ${{ env.CONAN_FILE }} --build missing --deployer runtime_deploy --deployer-folder extradll --output-folder .
conan cache clean "*"
- name: Save libraries to the cache
if: ${{ steps.library-cache.outputs.cache-hit != 'true' }}
if: steps.library-cache.outputs.cache-hit != 'true' && github.event_name != 'release'
uses: actions/cache/save@v5
with:
key: ${{ steps.library-cache.outputs.cache-primary-key }}
path: ${{ env.CONAN_HOME }}\p
- name: Run CMake
shell: cmd # work around a conan-io/conan-center-index bug #21823
working-directory: ${{ github.workspace }}\build
run: |
call ${{ github.workspace }}\conanbuild.bat
cmake -A x64 -D "CMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }}" -D CMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -G "Visual Studio 17 2022" ..
working-directory: ${{ env.BUILD_PATH }}
run: |-
cmake -D "CMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }}" `
-D "CMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake" `
-G "Ninja Multi-Config" `
-S "${{ github.workspace }}" `
-Wdeprecated `
-Wdev
- name: Build Anope
working-directory: ${{ github.workspace }}\build
run: |
msbuild PACKAGE.vcxproj /M:5 /P:Configuration=${{ env.BUILD_TYPE }} /P:Platform=x64 /VERBOSITY:MINIMAL
- name: Build installer
working-directory: ${{ env.BUILD_PATH }}
run: |-
ninja -f "build-${{ env.BUILD_TYPE }}.ninja" ${{ runner.debug == '1' && '-v' || '' }} package
- name: Upload installer
if: "${{ github.event_name == 'release' }}"
working-directory: ${{ github.workspace }}\build
if: github.event_name == 'release'
working-directory: ${{ env.BUILD_PATH }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload ${{ github.event.release.tag_name }} $(Get-ChildItem anope-*.exe)
- name: Upload artifact
if: "${{ github.event_name != 'release' }}"
if: github.event_name != 'release'
uses: actions/upload-artifact@v7
with:
name: windows-installer
+2 -1
View File
@@ -51,7 +51,8 @@ Robby <robby@chatbelgie.be> <robby@chat.be>
Robert Scheck <robert@fedoraproject.org> <robert-scheck@users.noreply.github.com>
Robin Burchell <w00t@inspircd.org> <rburchell@5417fbe8-f217-4b02-8779-1006273d7864>
Robin Burchell <w00t@inspircd.org> <Robin Burchell w00t@inspircd.org@5417fbe8-f217-4b02-8779-1006273d7864>
Sadie Powell <sadie@witchery.services> <petpow@saberuk.com>
Sadie Powell <sadie@sadiepowell.dev> <petpow@saberuk.com>
Sadie Powell <sadie@sadiepowell.dev> <sadie@witchery.services>
Sebastian Barfurth <github@afreshmelon.com>
Sebastian V. <hal9000@denorastats.org>
Sebastian V. <hal9000@denorastats.org> <pimpmylinux@5417fbe8-f217-4b02-8779-1006273d7864>
+2 -2
View File
@@ -43,12 +43,12 @@ endif()
# Find gettext
find_package(Gettext)
find_package(Intl)
if(GETTEXT_FOUND AND Intl_FOUND)
if(Gettext_FOUND AND Intl_FOUND)
set(HAVE_LOCALIZATION ON)
include_directories(${Intl_INCLUDE_DIRS})
link_libraries(${Intl_LIBRARIES})
else()
message("Unable to find gettext and libintl; disabling localization")
message(STATUS "Unable to find gettext and/or libintl -- read docs/LANGUAGE for how to enable localization")
set(HAVE_LOCALIZATION OFF)
endif()
+25 -26
View File
@@ -29,43 +29,41 @@ Load_Cache () {
}
Run_Build_System () {
WITH_INST=""
WITH_RUN=""
WITH_PERM=""
EXTRA_INCLUDE=""
EXTRA_LIBS=""
BUILD_DIR="${SOURCE_DIR}/build"
CMAKE_COMMAND="${CMAKE:-cmake} -B ${BUILD_DIR} -S ${SOURCE_DIR}"
if [ "$INSTDIR" != "" ] ; then
WITH_INST="-DINSTDIR=$INSTDIR"
CMAKE_COMMAND="${CMAKE_COMMAND} -D INSTDIR=$INSTDIR"
fi
if [ "$RUNGROUP" != "" ] ; then
WITH_RUN="-DRUNGROUP=$RUNGROUP"
CMAKE_COMMAND="${CMAKE_COMMAND} -D RUNGROUP=$RUNGROUP"
fi
if [ "$UMASK" != "" ] ; then
WITH_PERM="-DDEFUMASK=$UMASK"
CMAKE_COMMAND="${CMAKE_COMMAND} -D DEFUMASK=$UMASK"
fi
if [ "$DEBUG" = "yes" ] ; then
BUILD_TYPE="-DCMAKE_BUILD_TYPE=Debug"
CMAKE_COMMAND="${CMAKE_COMMAND} -D CMAKE_BUILD_TYPE=Debug"
else
BUILD_TYPE="-DCMAKE_BUILD_TYPE=Release"
CMAKE_COMMAND="${CMAKE_COMMAND} -D CMAKE_BUILD_TYPE=Release"
fi
if [ "$EXTRA_INCLUDE_DIRS" != "" ] ; then
EXTRA_INCLUDE="-DEXTRA_INCLUDE=$EXTRA_INCLUDE_DIRS"
CMAKE_COMMAND="${CMAKE_COMMAND} -D EXTRA_INCLUDE=$EXTRA_INCLUDE_DIRS"
fi
if [ "$EXTRA_LIB_DIRS" != "" ] ; then
EXTRA_LIBS="-DEXTRA_LIBS=$EXTRA_LIB_DIRS"
CMAKE_COMMAND="${CMAKE_COMMAND} -D EXTRA_LIBS=$EXTRA_LIB_DIRS"
fi
BUILD_PATHS="-B ${SOURCE_DIR}/build ${SOURCE_DIR}"
if [ "$EXTRA_CONFIG_ARGS" != "" ] ; then
CMAKE_COMMAND="${CMAKE_COMMAND} $EXTRA_CONFIG_ARGS"
fi
CMAKE="cmake $GEN_TYPE $WITH_INST $WITH_RUN $WITH_PERM $BUILD_TYPE $EXTRA_INCLUDE $EXTRA_LIBS $EXTRA_CONFIG_ARGS $BUILD_PATHS"
echo $CMAKE
$CMAKE
echo $CMAKE_COMMAND
$CMAKE_COMMAND
if [ $? -ne 0 ]; then
echo "You should fix these issues and then run ./Config -quick to rerun CMake."
@@ -73,11 +71,7 @@ Run_Build_System () {
fi
echo ""
if [ "$PWD" = "${SOURCE_DIR}/build" ]; then
echo "Now run make to build Anope."
else
echo "Now cd build, then run make to build Anope."
fi
echo "Now run 'make -C ${BUILD_DIR#"$PWD/"} install' to build and install Anope."
}
###########################################################################
@@ -98,7 +92,12 @@ CAN_QUICK="no"
###########################################################################
while [ $# -ge 1 ] ; do
if [ $1 = "--help" ] ; then
OPTION=$1
while [ "${OPTION#-}" != "$OPTION" ]; do
OPTION="${OPTION#-}"
done
if [ "$OPTION" = "--help" ] ; then
echo "Config utility for Anope"
echo "------------------------"
echo "Syntax: ./Config [options]"
@@ -106,15 +105,15 @@ while [ $# -ge 1 ] ; do
echo "-nointro Skip intro (disclaimer, etc)"
echo "-quick Skip questions, go straight to cmake"
exit 0
elif [ $1 = "-devel" ] ; then
elif [ "$OPTION" = "devel" ] ; then
DEBUG="yes"
DEVEL="yes"
INSTDIR="$SOURCE_DIR/run"
elif [ $1 = "-nocache" ] ; then
elif [ "$OPTION" = "nocache" ] ; then
IGNORE_CACHE="1"
elif [ $1 = "-nointro" ] ; then
elif [ "$OPTION" = "nointro" ] ; then
NO_INTRO="1"
elif [ $1 = "-quick" -o $1 = "-q" ] ; then
elif [ "$OPTION" = "quick" -o "$OPTION" = "q" ] ; then
Load_Cache
if [ "$CAN_QUICK" = "yes" ] ; then
Run_Build_System
+2 -22
View File
@@ -1228,7 +1228,7 @@ module
* An optional prefix to prepended to the name of each created table.
* Do not use the same prefix for other programs.
*/
#prefix = "anope_db_"
#prefix = "anope21_"
/*
* Whether or not to import data from another database module in to SQL on
@@ -1248,26 +1248,6 @@ module
import = no
}
/*
* db_redis.
*
* This module allows using Redis (https://redis.io/) as a database backend.
* This module requires that redis is loaded and configured properly.
*
* Redis 2.8 supports keyspace notifications which allows Redis to push notifications
* to Anope about outside modifications to the database. This module supports this and
* will internally reflect any changes made to the database immediately once notified.
* See docs/REDIS for more information regarding this.
*/
#module
{
name = "db_redis"
/*
* Redis database to use. This must be configured with redis.
*/
engine = "redis/main"
}
/*
* [RECOMMENDED] Encryption modules.
@@ -1316,7 +1296,7 @@ module
/** The memory hardness in kibibytes of the Argon2 algorithm. Defaults to
* 128 mebibytes.
*/
#memory_cost = 121072
#memory_cost = 131072
/** The time hardness (iterations) of the Argon2 algorithm. Defaults to 3.
*/
+5
View File
@@ -252,6 +252,7 @@ privilege
rank = 10
level = 3
flag = "f"
flag_migration_requires = "ACCESS_CHANGE"
xop = "VOP"
}
@@ -496,6 +497,7 @@ privilege
rank = 110
level = 4
flag = "h"
flag_migration_requires = "HALFOP"
xop = "HOP"
}
@@ -638,6 +640,7 @@ privilege
rank = 220
level = 5
flag = "o"
flag_migration_requires = "OP"
xop = "AOP"
}
@@ -710,6 +713,7 @@ privilege
rank = 300
level = 10
flag = "a"
flag_migration_requires = "PROTECT"
xop = "SOP"
}
@@ -853,6 +857,7 @@ privilege
rank = 60
level = 3
flag = "v"
flag_migration_requires = "VOICE"
xop = "VOP"
}
+1 -1
View File
@@ -22,7 +22,7 @@ module
* An optional prefix to prepended to the name of each created table.
* Do not use the same prefix for other programs.
*/
prefix = "anope_"
#prefix = "chanstats21_"
smileyshappy = ":) :-) ;) ;-) :D :-D :P :-P"
smileyssad = ":( :-( ;( ;-("
-24
View File
@@ -374,30 +374,6 @@ module { name = "help" }
}
}
/*
* redis
*
* This module allows other modules to use Redis.
*/
#module
{
name = "redis"
/* A redis database */
redis
{
/* The name of this service */
name = "redis/main"
/*
* The redis database to use. New connections default to 0.
*/
db = 0
ip = "127.0.0.1"
port = 6379
}
}
/*
* [EXTRA] regex_pcre2
+11 -2
View File
@@ -128,9 +128,9 @@ module
/*
* The minimum length of time between consecutive uses of NickServ's REGISTER command. This
* directive is optional, but recommended. If not set, this restriction will be disabled.
* directive is optional, but recommended. If not set, it defaults to 15 minutes.
*/
regdelay = 5m
regdelay = 15m
/*
* The length of time before a nick's registration expires.
@@ -416,6 +416,12 @@ module
{
name = "ns_group"
/*
* The minimum length of time between consecutive uses of the GROUP command. This directive is
* optional, but recommended. If not set, it defaults to 5 minutes.
*/
delay = 5m
/*
* The maximum number of nicks allowed in a group.
*
@@ -741,6 +747,9 @@ command { service = "NickServ"; name = "SASET LAYOUT"; command = "nickserv/saset
*
* misc_description: A description of the command to show in the help.
* misc_title: A human-readable description of the stored data.
* misc_priority: Positive integer representing display order in nickserv/info
* and (if enabled) WHOIS output. Entries with unspecified
* priority will be prioritized in the order of declaration.
* misc_pattern: If defined then a regex pattern (using the engine specified
* in <options:regexengine> to validate the data with).
* misc_syntax: If defined then the syntax to show in the help output and, if
+3 -3
View File
@@ -3,7 +3,7 @@ and other useful contributions to Anope. These people, ordered by the number of
contributions they have made, are:
* Adam <adam@anope.org>
* Sadie Powell <sadie@witchery.services>
* Sadie Powell <sadie@sadiepowell.dev>
* Robin Burchell <w00t@inspircd.org>
* Naram Qashat <cyberbotx@anope.org>
* Pieter Bootsma <geniusdex@anope.org>
@@ -20,8 +20,8 @@ contributions they have made, are:
* Adam Kramer <ribosome@anope.org>
* Attila Molnar <attilamolnar@hush.com>
* Michael Wobst <wobst.michael@web.de>
* Matt Schatz <genius3000@g3k.solutions>
* PeGaSuS <droider.pc@gmail.com>
* Matt Schatz <genius3000@g3k.solutions>
* Mark Summers <mark@goopler.net>
* Daniel Vassdal <shutter@canternet.org>
* MatthewM <mcm@they-got.us>
@@ -49,6 +49,7 @@ contributions they have made, are:
* Robert Scheck <robert@fedoraproject.org>
* Dennis Friis <peavey@inspircd.org>
* Filippo Cortigiani <simos@simosnap.org>
* KidProtect
* Michał Zegan <webczat_200@poczta.onet.pl>
* AlphaTech <alphat3ch@icloud.com>
* Austin Ellis <siniStar@IRC4Fun.net>
@@ -71,7 +72,6 @@ contributions they have made, are:
* Jason Foster <retsofaj@gmail.com>
* Jeremy <jeremy@ssnet.ca>
* Josh Soref
* KidProtect
* KindOne <ineedalifetoday@live.com>
* linuxdaemon
* Mantas Mikulėnas <grawity@gmail.com>
+42
View File
@@ -1,5 +1,47 @@
# Anope Change Log
## Anope 2.1.25 (unreleased)
### Changes
* Fixed a crash when a temporary ban expires.
* Fixed a potential crash caused by unusual timestamps being passed to `Anope::strftime`.
* Fixed confirming accounts when `{ns_register}:registration` is set to "admin".
* Fixed migrating access entries from xop to flags granting new privileges in cases where multiple privileges share the same flag.
* Fixed migrating access entries sometimes giving the wrong flags.
* Fixed not being able to update the description of a flags access entry.
## Anope 2.1.24 (2026-04-01)
### Breaking Changes
* If a database contains duplicate corrupt entries from a prior write failure the oldest ones will now be purged from the database. This is a destructive action so make sure you take a manual backup of your database before upgrading.
* Removed support for storing the Anope database in Redis. The Redis code was extremely bitrotted, had not been tested in years, and to our knowledge has almost no (if any) users. It is recommended that db_redis users migrate to db_json or db_sql.
* SQL tables now use versioned prefixes by default. For the SQL database backends the default is `anope21_` and for ChanStats the default is `chanstats21_`. If you do not have a prefix explicitly set in your config you will need to add one it. Alternatively, you may also want to consider exporting to db_json and re-importing to update your SQL schema for the recent database layout changes.
### Changes
* Added some helper methods to `CommandSource` to allow quickly translting messages.
* Changed the Config script to allow multiple dashes in front of options, i.e. `-quick` and `--quick` are now equivalent.
* Converted some language strings to use format strings instead of concatenation.
* Fixed a rare crash in the ns_cert module.
* Fixed building Anope as a unity build.
* Fixed the ns_cert module erasing certificate entries if using an old database.
* Fixed users having the wrong real name in log messages on InspIRCd if it has been previously changed with `CHGNAME` or `SETNAME`.
## Anope 2.1.23 (2026-04-01)
### Changes
+1 -2
View File
@@ -32,8 +32,7 @@ Anope Multi Language Support
but 0x1B is special to Anope and is used to prevent the automatic linewrapper from breaking messages in the middle of
text that should not be split (e.g. commands). Your editor may not show these so be careful you don't delete them!
If you have finished a language file translation and you want others to use it, please file a pull request on GitHub
or send it to team@anope.org (don't forget to mention clearly your (nick)name, your email and the language name).
If you have finished a language file translation and you want others to use it, please file a pull request on GitHub.
You'll of course get full credit for it.
3) Using languages with modules
-160
View File
@@ -1,160 +0,0 @@
Anope has Redis database support (https://redis.io/).
This document explains the data structure used by Anope, and explains how
keyspace notification works.
This is not a tutorial on how to use Redis, see https://redis.io/documentation
for that.
Table of Contents
-----------------
1) Data structure
2) Keyspace notifications
3) Examples of modifying, deleting, and creating objects
1) Data structure
There are 4 key namespaces in Anope, they are:
id - The keys in id are used to atomically create object ids for new
objects. For example, if I were to create a new BotInfo I would first:
redis 127.0.0.1:6379> INCR id:BotInfo
To get the object ID of the new object.
ids - The keys in ids contain a set of all object ids of the given type.
For example:
redis 127.0.0.1:6379> SMEMBERS ids:BotInfo
Returns "1", "2", "3", "4", "5", "6", "7", "8" because I have 8 bots that
have IDs 1, 2, 3, 4, 5, 6, 7, and 8, respectively.
hash - The keys in hash are the actual objects, stored as hashes. For
example, if I had just looked up all BotInfo ids and wanted to iterate
over all of them, I would start by:
redis 127.0.0.1:6379> HGETALL hash:BotInfo:1
Which gets all keys and values from the hash of type BotInfo with id 1.
This may return:
"nick" -> "BotServ"
"user" -> "services"
"host" -> "services.anope.org"
"created" -> "1368704765"
value - The keys in value only exist to aid looking up object IDs. They
are sets of object IDs and are used to map key+value pairs to objects.
For example:
redis 127.0.0.1:6379> SMEMBERS value:NickAlias:nick:Adam
Returns a set of object ids of NickAlias objects that have the key
'nick' set to the value 'Adam' in its hash. Clearly this can only
ever contain at most one object, since it is not possible to have
more than one registered nick with the same name, but other keys
will contain more than one, such as:
redis 127.0.0.1:6379> SMEMBERS value:NickCore:email:adam@anope.org
Which would return all accounts with the email "adam@anope.org".
redis 127.0.0.1:6379> SMEMBERS value:ChanAccess:mask:Adam
Which would return all access entries set on the account "Adam".
Behavior similar to SQL's AND, can be achieved using the
SINTER command, which does set intersection on one or more sets.
2) Keyspace notifications
Redis 2.7 (unstable) and 2.8 (stable) and newer support keyspace notifications
(https://redis.io/topics/notifications). This allows Redis to notify Anope of
any external changes to objects in the database. Once notified, Anope will
immediately update the object. Otherwise, Anope keeps all objects in memory
and will not regularly read from the database once started.
You can use this to modify objects in Redis and have them immediately reflected
back into Anope. Additionally you can use this feature to run multiple Anope
instances simultaneously from the same database (see also, Redis database
replication).
To use keyspace notifications you MUST execute
redis 127.0.0.1:6379> CONFIG SET notify-keyspace-events KA
OK
or set notify-keyspace-events in redis.conf properly. Anope always executes
CONFIG SET when it first connects.
If you do not enable keyspace events properly Anope will be UNABLE to see any
object modifications you do.
The key space ids and value are managed entirely by Anope, you do
not (and should not) modify them. Once you modify the object (hash), Anope will
update them for you to correctly reflect any changes made to the object.
Finally, always use atomic operations. If you are inserting a new object with
multiple commands, or inserting multiple objects at once, specifically if the
objects depend on each other, you MUST use a transaction.
3) Examples of modifying, deleting, and creating objects
These examples will ONLY work if you meet the criteria in section 2.
If I want to change the email account 'Adam' to 'Adam@anope.org', I would execute the following:
redis 127.0.0.1:6379> SMEMBERS value:NickCore:display:Adam
Which returns a value of "1", which is the object id I want to modify.
Now to change the email:
redis 127.0.0.1:6379> HSET hash:NickCore:1 email Adam@anope.org
You can now see this in NickServ's INFO command:
-NickServ- Email address: Adam@anope.org
If I want to drop the account "Adam", I would execute the following:
redis 127.0.0.1:6379> SMEMBERS value:NickCore:display:Adam
Which returns a value of "1". I would then check:
redis 127.0.0.1:6379> SMEMBERS value:NickAlias:nc:Adam
To see what nicknames depend on this account to exist, as I will
have to remove those too. This returns the values "2", and "3".
Finally, I can drop the nick using a transaction via:
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> DEL hash:NickAlias:2
QUEUED
redis 127.0.0.1:6379> DEL hash:NickAlias:3
QUEUED
redis 127.0.0.1:6379> DEL hash:NickCore:1
QUEUED
redis 127.0.0.1:6379> EXEC
Or alternatively simply:
redis 127.0.0.1:6379> DEL hash:NickAlias:2 hash:NickAlias:3 hash:NickCore:1
If I wanted to create a BotServ bot, I would execute the following:
redis 127.0.0.1:6379> INCR id:BotInfo
Which returns a new object ID for me, in this example it will be "8".
Now I can create the object:
HMSET hash:BotInfo:8 nick redis user redis host services.anope.org realname "Anope IRC Services"
Note if you are using HSET instead of HMSET you will need to use a transaction, as shown in the above example.
If you are watching your services logs you will immediately see:
USERS: redis!redis@services.anope.org (Anope IRC Services) connected to the network (services.anope.org)
And the bot redis will be in BotServ's bot list.
Notice how ids:BotInfo and the value keys are updated automatically.
+3
View File
@@ -67,6 +67,9 @@ public:
*/
virtual ChanAccess *Create() = 0;
virtual void GetAccess(CommandSource& source, const Privilege *p, Anope::map<Anope::string> &access) = 0;
static void SendAccess(CommandSource &source, const Anope::string &pname);
private:
static std::list<AccessProvider *> Providers;
public:
+5
View File
@@ -90,6 +90,11 @@ public:
void Reply(int count, const char *singular, const char *plural, ...) ATTR_FORMAT(4, 5);
void Reply(const Anope::string &message);
const char *Translate(const char *message);
const char *Translate(const Anope::string &message);
const char *Translate(int count, const char *single, const char *plural);
const char *Translate(int count, const Anope::string &single, const Anope::string &plural);
bool HasCommand(const Anope::string &cmd);
bool HasPriv(const Anope::string &cmd);
bool IsServicesOper();
+13 -10
View File
@@ -18,6 +18,7 @@
#include "regchannel.h"
#include "users.h"
#include "opertype.h"
#include "miscutils.h"
namespace Configuration
{
@@ -26,14 +27,15 @@ namespace Configuration
friend class Configuration::Conf;
public:
typedef Anope::map<Anope::string> item_map;
typedef Anope::multimap<Block> block_map;
typedef Anope::map<Anope::string> ItemMap;
typedef Anope::multimap<Block> BlockMap;
typedef Anope::iterator_range<BlockMap::const_iterator> BlockList;
private:
Anope::string name;
item_map items;
block_map blocks;
int linenum;
ItemMap items;
BlockMap blocks;
unsigned linenum;
/* Represents a missing tag. */
static Block EmptyBlock;
@@ -41,9 +43,10 @@ namespace Configuration
public:
Block(const Anope::string &);
const Anope::string &GetName() const;
int CountBlock(const Anope::string &name) const;
const Block &GetBlock(const Anope::string &name, int num = 0) const;
Block *GetMutableBlock(const Anope::string &name, int num = 0);
size_t CountBlock(const Anope::string &name) const;
BlockList GetBlocks(const Anope::string &name) const;
const Block &GetBlock(const Anope::string &name, size_t num = 0) const;
Block *GetMutableBlock(const Anope::string &name, size_t num = 0);
template<typename T> T Get(const Anope::string &tag, const Anope::string &def = "") const
{
@@ -51,7 +54,7 @@ namespace Configuration
}
bool Set(const Anope::string &tag, const Anope::string &value);
const item_map &GetItems() const;
const ItemMap &GetItems() const;
};
template<> CoreExport const Anope::string Block::Get(const Anope::string &tag, const Anope::string &def) const;
@@ -85,7 +88,7 @@ namespace Configuration
{
private:
/** Replaces defined variables within a string. */
Anope::string ReplaceVars(const Anope::string &str, const File &file, int linenumber);
Anope::string ReplaceVars(const Anope::string &str, const File &file, unsigned linenumber);
public:
/* options:readtimeout */
-4
View File
@@ -142,10 +142,6 @@ namespace Language
#define CHAN_ACCESS_LEVEL_RANGE _("Access level must be between %d and %d inclusive.")
#define CHAN_ACCESS_MALFORMED _("You cannot add a malformed mask to an access list. Did you mean to add %s instead?")
#define CHAN_ACCESS_FOREIGN N_("%u access entry from other access systems not shown; use \002%s\033ALL\002 to view all access entries.", "%u access entries from other access systems not shown; use \002%s\033ALL\002 to view all access entries.")
#define CHAN_ACCESS_MIGRATED_1 _("\002%s\002 has been migrated to the %s access system.")
#define CHAN_ACCESS_MIGRATED_N N_("\002%u\002 entry has been migrated to the %s access system.", "\002%u\002 entries have been migrated to the %s access system.")
#define CHAN_ACCESS_NOT_MIGRATED_1 _("\002%s\002 can not be migrated to the %s access system because they have privileges that you do not.")
#define CHAN_ACCESS_NOT_MIGRATED_N N_("\002%u\002 entry can not be migrated to the %s access system because they have privileges that you do not.", "\002%u\002 entries can not be migrated to the %s access system because they have privileges that you do not.")
#define CHAN_EXCEPTED _("\002%s\002 matches an except on %s and cannot be banned until the except has been removed.")
#define CHAN_INFO_HEADER _("Information about channel \002%s\002:")
#define CHAN_LIMIT_EXCEEDED _("You have already exceeded your limit of \002%d\002 channels.")
+87
View File
@@ -0,0 +1,87 @@
// Anope IRC Services <https://www.anope.org/>
//
// Copyright (C) 2003-2026 Anope Contributors
//
// Anope is free software. You can use, modify, and/or distribute it under the
// terms of version 2 of the GNU General Public License. See docs/LICENSE.txt
// for the complete terms of this license and docs/AUTHORS.txt for a list of
// contributors.
//
// Based on the original code of Epona by Lara
// Based on the original code of Services by Andy Church
//
// SPDX-License-Identifier: GPL-2.0-only
#pragma once
#include <iterator>
#include <utility>
namespace Anope
{
template <typename Iterator>
class iterator_range;
/** Returns a range containing all elements equivalent to \p value.
* @param collection The collection to search within.
* @param value The value to search for.
*/
template <typename Collection, typename Value>
auto equal_range(const Collection& collection, const Value& value)
{
return iterator_range(collection.equal_range(value));
}
/** Returns a range representing a reverse iterator for the specified colleciton.
* @param collection The collection to create a reverse iterator for.
*/
template <typename Collection>
auto reverse_range(const Collection& collection)
{
return iterator_range(collection.rbegin(), collection.rend());
}
}
/** Represents a range of iterators. */
template <typename Iterator>
class Anope::iterator_range final
{
private:
/** An iterator which points to the start of the range. */
const Iterator begini;
/* An iterator which points to one past the end of the range. */
const Iterator endi;
public:
/** Initialises a new iterator range with the specified iterators.
* @param begin An iterator which points to the start of the range.
* @param end An iterator which points to one past the end of the range.
*/
explicit iterator_range(Iterator begin, Iterator end)
: begini(begin)
, endi(end)
{
}
/** Initialises a new iterator range from a pair of iterators.
* @param range A pair of iterators in the format [first, last).
*/
explicit iterator_range(std::pair<Iterator, Iterator> range)
: begini(range.first)
, endi(range.second)
{
}
/** Determines whether the iterator range is empty. */
bool empty() const { return begini == endi; }
/** Retrieves an iterator which points to the start of the range. */
const Iterator& begin() const { return begini; }
/** Retrieves an iterator which points to one past the end of the range. */
const Iterator& end() const { return endi; }
/** Retrieves the number of hops within the iterator range. */
typename std::iterator_traits<Iterator>::difference_type count() const { return std::distance(begini, endi); }
};
+2 -1
View File
@@ -194,12 +194,13 @@ namespace DNS
/** Used to time out the query, xalls OnError and lets the TimerManager
* delete this request.
*/
void Tick() override
bool Tick() override
{
Log(LOG_DEBUG_2) << "Resolver: timeout for query " << this->name;
Query rr(*this);
rr.error = ERROR_TIMEDOUT;
this->OnError(&rr);
return false;
}
};
+10
View File
@@ -173,4 +173,14 @@ public:
* @param attributes The attributes to modify
*/
virtual void Modify(LDAPInterface *i, const Anope::string &base, LDAPMods &attributes) = 0;
/** Escapes a LDAP string for use in a DN.
* @param str The string to escape.
*/
virtual Anope::string EscapeDN(const Anope::string &str) const = 0;
/** Escapes a LDAP string for use in a search filter.
* @param str The string to escape.
*/
virtual Anope::string EscapeSF(const Anope::string &str) const = 0;
};
-83
View File
@@ -1,83 +0,0 @@
// Anope IRC Services <https://www.anope.org/>
//
// Copyright (C) 2003-2026 Anope Contributors
//
// Anope is free software. You can use, modify, and/or distribute it under the
// terms of version 2 of the GNU General Public License. See docs/LICENSE.txt
// for the complete terms of this license and docs/AUTHORS.txt for a list of
// contributors.
//
// Based on the original code of Epona by Lara
// Based on the original code of Services by Andy Church
//
// SPDX-License-Identifier: GPL-2.0-only
#pragma once
namespace Redis
{
struct Reply final
{
enum Type
{
NOT_PARSED,
NOT_OK,
OK,
INT,
BULK,
MULTI_BULK
}
type;
Reply() { Clear(); }
~Reply() { Clear(); }
void Clear()
{
type = NOT_PARSED;
i = 0;
bulk.clear();
multi_bulk_size = 0;
for (const auto *reply : multi_bulk)
delete reply;
multi_bulk.clear();
}
int64_t i;
Anope::string bulk;
int multi_bulk_size;
std::deque<Reply *> multi_bulk;
};
class Interface
{
public:
Module *owner;
Interface(Module *m) : owner(m) { }
virtual ~Interface() = default;
virtual void OnResult(const Reply &r) = 0;
virtual void OnError(const Anope::string &error) { Log(owner) << error; }
};
class Provider
: public Service
{
public:
Provider(Module *c, const Anope::string &n) : Service(c, "Redis::Provider", n) { }
virtual bool IsSocketDead() = 0;
virtual void SendCommand(Interface *i, const std::vector<Anope::string> &cmds) = 0;
virtual void SendCommand(Interface *i, const Anope::string &str) = 0;
virtual bool BlockAndProcess() = 0;
virtual void Subscribe(Interface *i, const Anope::string &pattern) = 0;
virtual void Unsubscribe(const Anope::string &pattern) = 0;
virtual void StartTransaction() = 0;
virtual void CommitTransaction() = 0;
};
}
+1 -1
View File
@@ -279,7 +279,7 @@ public:
virtual void SendSVSHold(const Anope::string &, time_t) { }
virtual void SendSVSHoldDel(const Anope::string &) { }
virtual void SendSWhois(const MessageSource &source, User *target, const Anope::string &tag, const Anope::string &message) { };
virtual void SendSWhois(const MessageSource &source, User *target, const Anope::string &tag, time_t priority, const Anope::string &message) { };
virtual void SendSWhoisDel(const MessageSource &source, User *target, const Anope::string &tag, const Anope::string &message) { }
/** Introduces a server to the uplink
+20 -3
View File
@@ -74,6 +74,8 @@ private:
size_t last_commit = 0;
/* The last time this object was committed to the database */
time_t last_commit_time = 0;
/** Whether this object should be committed to the database. */
bool should_commit = true;
protected:
Serializable(const Anope::string &serialize_type);
@@ -81,6 +83,20 @@ protected:
Serializable &operator=(const Serializable &);
template<typename Container,
typename Key = typename Container::key_type,
typename Value = typename Container::mapped_type>
bool InsertUnique(Container &container, const Key &key)
{
auto res = container.emplace(key, static_cast<Value>(this));
if (res.second)
return true;
res.first->second->should_commit = false;
res.first->second = static_cast<Value>(this);
return false;
}
public:
using Id = uint64_t;
virtual ~Serializable();
@@ -88,13 +104,13 @@ public:
/* Unique ID (per type, not globally) for this object */
Id object_id = 0;
/* Only used by redis, to ignore updates */
unsigned short redis_ignore = 0;
/** Marks the object as potentially being updated "soon".
*/
void QueueUpdate();
/** Determines whether the object should be committed to the database. */
bool ShouldCommit() const { return this->should_commit; }
bool IsCached(Serialize::Data &);
void UpdateCache(Serialize::Data &);
@@ -105,6 +121,7 @@ public:
* @return The serializable object type
*/
Serialize::Type *GetSerializableType() const { return this->s_type; }
const auto &GetSerializableName() const { return this->s_name; }
static const std::list<Serializable *> &GetItems();
};
+3 -14
View File
@@ -31,23 +31,17 @@ private:
*/
time_t secs;
/** True if this is a repeating timer
*/
bool repeat;
public:
/** Constructor, initializes the triggering time
* @param time_from_now The number of seconds from now to trigger the timer
* @param repeating Repeat this timer every time_from_now if this is true
*/
Timer(time_t time_from_now, bool repeating = false);
Timer(time_t time_from_now);
/** Constructor, initializes the triggering time
* @param creator The creator of the timer
* @param time_from_now The number of seconds from now to trigger the timer
* @param repeating Repeat this timer every time_from_now if this is true
*/
Timer(Module *creator, time_t time_from_now, bool repeating = false);
Timer(Module *creator, time_t time_from_now);
/** Destructor, removes the timer from the list
*/
@@ -63,11 +57,6 @@ public:
*/
time_t GetTimer() const;
/** Returns true if the timer is set to repeat
* @return Returns true if the timer is set to repeat
*/
bool GetRepeat() const;
/** Set the interval between ticks
* @paramt t The new interval
*/
@@ -86,7 +75,7 @@ public:
/** Called when the timer ticks
* This should be overridden with something useful
*/
virtual void Tick() = 0;
virtual bool Tick() = 0;
};
/** This class manages sets of Timers, and triggers them at their defined times.
+164 -141
View File
@@ -16,13 +16,13 @@ msgid ""
msgstr ""
"Project-Id-Version: Anope\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-03-19 00:00+0000\n"
"PO-Revision-Date: 2026-03-19 00:00+0000\n"
"Last-Translator: Sadie Powell <sadie@witchery.services>\n"
"POT-Creation-Date: 2026-05-21 11:52+0100\n"
"PO-Revision-Date: 2026-05-21 11:52+0100\n"
"Last-Translator: Sadie Powell <sadie@sadiepowell.dev>\n"
"Language-Team: English\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-1\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.4.2\n"
@@ -129,7 +129,12 @@ msgstr ""
msgid "%s already exists on the EXCEPTION list."
msgstr ""
#: ../include/language.h
#: ../modules/chanserv/cs_flags.cpp
#, c-format
msgid "%s can not be migrated to the %s access system because they have no migratable privileges."
msgstr ""
#: ../modules/chanserv/cs_flags.cpp
#, c-format
msgid "%s can not be migrated to the %s access system because they have privileges that you do not."
msgstr ""
@@ -215,7 +220,7 @@ msgstr ""
msgid "%s has been joined to %s."
msgstr ""
#: ../include/language.h
#: ../modules/chanserv/cs_flags.cpp
#, c-format
msgid "%s has been migrated to the %s access system."
msgstr ""
@@ -273,7 +278,7 @@ msgstr ""
msgid "%s is already on the ignore list."
msgstr ""
#: ../modules/nickserv/ns_suspend.cpp ../modules/chanserv/cs_suspend.cpp
#: ../modules/chanserv/cs_suspend.cpp ../modules/nickserv/ns_suspend.cpp
#, c-format
msgid "%s is already suspended."
msgstr ""
@@ -428,14 +433,21 @@ msgstr ""
msgid "%s will now permanently be ignored."
msgstr ""
#: ../include/language.h
#: ../modules/chanserv/cs_flags.cpp
#, c-format
msgid "%u entry can not be migrated to the %s access system because they have no migratable privileges."
msgid_plural "%u entries can not be migrated to the %s access system because they have no migratable privileges."
msgstr[0] ""
msgstr[1] ""
#: ../modules/chanserv/cs_flags.cpp
#, c-format
msgid "%u entry can not be migrated to the %s access system because they have privileges that you do not."
msgid_plural "%u entries can not be migrated to the %s access system because they have privileges that you do not."
msgstr[0] ""
msgstr[1] ""
#: ../include/language.h
#: ../modules/chanserv/cs_flags.cpp
#, c-format
msgid "%u entry has been migrated to the %s access system."
msgid_plural "%u entries have been migrated to the %s access system."
@@ -580,10 +592,10 @@ msgstr ""
msgid "botname {ON|OFF}"
msgstr ""
#: ../modules/chanserv/cs_log.cpp ../modules/chanserv/cs_info.cpp
#: ../modules/chanserv/cs_sync.cpp ../modules/chanserv/cs_getkey.cpp
#: ../modules/chanserv/cs_suspend.cpp ../modules/chanserv/cs_fantasy_top.cpp
#: ../modules/botserv/bs_assign.cpp
#: ../modules/botserv/bs_assign.cpp ../modules/chanserv/cs_fantasy_top.cpp
#: ../modules/chanserv/cs_getkey.cpp ../modules/chanserv/cs_info.cpp
#: ../modules/chanserv/cs_log.cpp ../modules/chanserv/cs_suspend.cpp
#: ../modules/chanserv/cs_sync.cpp
msgid "channel"
msgstr ""
@@ -603,7 +615,7 @@ msgstr ""
msgid "channel modes"
msgstr ""
#: ../modules/chanserv/cs_set.cpp ../modules/botserv/bs_assign.cpp
#: ../modules/botserv/bs_assign.cpp ../modules/chanserv/cs_set.cpp
msgid "channel nick"
msgstr ""
@@ -655,9 +667,9 @@ msgstr ""
msgid "channel APPEND topic"
msgstr ""
#: ../modules/chanserv/cs_access.cpp ../modules/chanserv/cs_akick.cpp
#: ../modules/chanserv/cs_flags.cpp ../modules/chanserv/cs_entrymsg.cpp
#: ../modules/chanserv/cs_xop.cpp ../modules/botserv/bs_badwords.cpp
#: ../modules/botserv/bs_badwords.cpp ../modules/chanserv/cs_access.cpp
#: ../modules/chanserv/cs_akick.cpp ../modules/chanserv/cs_entrymsg.cpp
#: ../modules/chanserv/cs_flags.cpp ../modules/chanserv/cs_xop.cpp
msgid "channel CLEAR"
msgstr ""
@@ -697,7 +709,7 @@ msgstr ""
msgid "channel LIST [mask | entry-num | list]"
msgstr ""
#: ../modules/chanserv/cs_xop.cpp ../modules/botserv/bs_badwords.cpp
#: ../modules/botserv/bs_badwords.cpp ../modules/chanserv/cs_xop.cpp
msgid "channel LIST [mask | list]"
msgstr ""
@@ -750,12 +762,12 @@ msgstr ""
msgid "channel [code]"
msgstr ""
#: ../modules/chanserv/cs_set.cpp ../modules/chanserv/cs_register.cpp
#: ../modules/chanserv/cs_register.cpp ../modules/chanserv/cs_set.cpp
msgid "channel [description]"
msgstr ""
#: ../modules/chanserv/cs_unban.cpp ../modules/chanserv/cs_invite.cpp
#: ../modules/chanserv/cs_set.cpp
#: ../modules/chanserv/cs_invite.cpp ../modules/chanserv/cs_set.cpp
#: ../modules/chanserv/cs_unban.cpp
msgid "channel [nick]"
msgstr ""
@@ -787,7 +799,7 @@ msgstr ""
msgid "channel [UNLOCK|LOCK]"
msgstr ""
#: ../modules/fantasy.cpp ../modules/greet.cpp ../modules/botserv/bs_assign.cpp
#: ../modules/botserv/bs_assign.cpp ../modules/fantasy.cpp ../modules/greet.cpp
msgid "channel {ON|OFF}"
msgstr ""
@@ -815,13 +827,13 @@ msgstr ""
msgid "channel {ON | LEVEL | OFF}"
msgstr ""
#: ../modules/chanstats.cpp ../modules/chanserv/cs_list.cpp
#: ../modules/botserv/bs_kick.cpp ../modules/chanserv/cs_list.cpp
#: ../modules/chanserv/cs_set.cpp ../modules/chanserv/cs_topic.cpp
#: ../modules/botserv/bs_kick.cpp
#: ../modules/chanstats.cpp
msgid "channel {ON | OFF}"
msgstr ""
#: ../modules/nickserv/ns_register.cpp ../modules/nickserv/ns_email.cpp
#: ../modules/nickserv/ns_email.cpp ../modules/nickserv/ns_register.cpp
msgid "code"
msgstr ""
@@ -829,11 +841,11 @@ msgstr ""
msgid "email"
msgstr ""
#: ../modules/memoserv/ms_staff.cpp ../modules/memoserv/ms_sendall.cpp
#: ../modules/memoserv/ms_sendall.cpp ../modules/memoserv/ms_staff.cpp
msgid "memo-text"
msgstr ""
#: ../modules/operserv/os_module.cpp ../modules/operserv/os_modinfo.cpp
#: ../modules/operserv/os_modinfo.cpp ../modules/operserv/os_module.cpp
msgid "modname"
msgstr ""
@@ -849,8 +861,8 @@ msgstr ""
msgid "new-password"
msgstr ""
#: ../modules/hostserv/hs_del.cpp ../modules/hostserv/hs_request.cpp
#: ../modules/chanserv/cs_fantasy_stats.cpp ../modules/chanserv/cs_seen.cpp
#: ../modules/hostserv/hs_del.cpp ../modules/hostserv/hs_request.cpp
#: ../modules/memoserv/ms_check.cpp
msgid "nick"
msgstr ""
@@ -936,10 +948,10 @@ msgstr ""
msgid "nickname {ON | delay | OFF}"
msgstr ""
#: ../modules/nickserv/ns_set.cpp ../modules/nickserv/ns_set_keepmodes.cpp
#: ../modules/nickserv/ns_set_op.cpp ../modules/nickserv/ns_cert.cpp
#: ../modules/nickserv/ns_set_message.cpp ../modules/nickserv/ns_list.cpp
#: ../modules/chanstats.cpp
#: ../modules/chanstats.cpp ../modules/nickserv/ns_cert.cpp
#: ../modules/nickserv/ns_list.cpp ../modules/nickserv/ns_set.cpp
#: ../modules/nickserv/ns_set_keepmodes.cpp
#: ../modules/nickserv/ns_set_message.cpp ../modules/nickserv/ns_set_op.cpp
msgid "nickname {ON | OFF}"
msgstr ""
@@ -959,7 +971,7 @@ msgstr ""
msgid "option nickname parameters"
msgstr ""
#: ../modules/nickserv/ns_set.cpp ../modules/memoserv/ms_set.cpp
#: ../modules/memoserv/ms_set.cpp ../modules/nickserv/ns_set.cpp
msgid "option parameters"
msgstr ""
@@ -1273,8 +1285,8 @@ msgstr ""
msgid "%s cannot be the successor on channel %s as they are the founder."
msgstr ""
#: ../modules/hostserv/hostserv.cpp ../modules/operserv/operserv.cpp
#: ../modules/global/global.cpp
#: ../modules/global/global.cpp ../modules/hostserv/hostserv.cpp
#: ../modules/operserv/operserv.cpp
#, c-format
msgid "%s commands:"
msgstr ""
@@ -1653,7 +1665,7 @@ msgstr ""
msgid ". %s is still online."
msgstr ""
#: ../modules/nickserv/ns_register.cpp ../modules/nickserv/ns_email.cpp
#: ../modules/nickserv/ns_email.cpp ../modules/nickserv/ns_register.cpp
msgid "@nickname"
msgstr ""
@@ -1814,7 +1826,7 @@ msgstr ""
msgid "Account"
msgstr ""
#: ../modules/nickserv/ns_identify.cpp ../modules/nickserv/ns_cert.cpp
#: ../modules/nickserv/ns_cert.cpp ../modules/nickserv/ns_identify.cpp
#, c-format
msgid "Account %s has already reached the maximum number of simultaneous logins (%u)."
msgstr ""
@@ -2435,7 +2447,8 @@ msgid "Available timezones in the %s region:"
msgstr ""
#: ../modules/chanserv/cs_enforce.cpp
msgid "BANS enforced by "
#, c-format
msgid "BANS enforced by %s"
msgstr ""
#: ../modules/botserv/bs_kick.cpp
@@ -2474,10 +2487,7 @@ msgid "Bans a given nick or mask on a channel"
msgstr ""
#: ../modules/chanserv/cs_ban.cpp
msgid ""
"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."
msgid "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. Channel founders may ban masks."
msgstr ""
#: ../modules/chanserv/cs_enforce.cpp
@@ -2670,6 +2680,11 @@ msgstr ""
msgid "Bot won't kick for repeats anymore."
msgstr ""
#: ../src/access.cpp
#, c-format
msgid "By default, the %s command is limited to:"
msgstr ""
#: ../modules/operserv/os_info.cpp
msgid "CLEAR target"
msgstr ""
@@ -3181,23 +3196,23 @@ msgstr ""
msgid "Copy all settings from one channel to another"
msgstr ""
#: ../modules/hostserv/hs_offer.cpp ../modules/hostserv/hs_list.cpp
#: ../modules/hostserv/hs_request.cpp ../modules/nickserv/ns_cert.cpp
#: ../modules/chanserv/cs_akick.cpp ../modules/chanserv/cs_mode.cpp
#: ../modules/chanserv/cs_flags.cpp ../modules/chanserv/cs_entrymsg.cpp
#: ../modules/operserv/os_akill.cpp ../modules/operserv/os_session.cpp
#: ../modules/operserv/os_sxline.cpp ../modules/operserv/os_news.cpp
#: ../modules/botserv/bs_info.cpp
#: ../modules/botserv/bs_info.cpp ../modules/chanserv/cs_akick.cpp
#: ../modules/chanserv/cs_entrymsg.cpp ../modules/chanserv/cs_flags.cpp
#: ../modules/chanserv/cs_mode.cpp ../modules/hostserv/hs_list.cpp
#: ../modules/hostserv/hs_offer.cpp ../modules/hostserv/hs_request.cpp
#: ../modules/nickserv/ns_cert.cpp ../modules/operserv/os_akill.cpp
#: ../modules/operserv/os_news.cpp ../modules/operserv/os_session.cpp
#: ../modules/operserv/os_sxline.cpp
msgid "Created"
msgstr ""
#: ../modules/hostserv/hs_offer.cpp ../modules/hostserv/hs_list.cpp
#: ../modules/nickserv/ns_cert.cpp ../modules/chanserv/cs_access.cpp
#: ../modules/chanserv/cs_akick.cpp ../modules/chanserv/cs_mode.cpp
#: ../modules/chanserv/cs_flags.cpp ../modules/chanserv/cs_entrymsg.cpp
#: ../modules/operserv/os_akill.cpp ../modules/operserv/os_session.cpp
#: ../modules/operserv/os_sxline.cpp ../modules/operserv/os_news.cpp
#: ../modules/operserv/os_forbid.cpp ../modules/operserv/os_ignore.cpp
#: ../modules/chanserv/cs_access.cpp ../modules/chanserv/cs_akick.cpp
#: ../modules/chanserv/cs_entrymsg.cpp ../modules/chanserv/cs_flags.cpp
#: ../modules/chanserv/cs_mode.cpp ../modules/hostserv/hs_list.cpp
#: ../modules/hostserv/hs_offer.cpp ../modules/nickserv/ns_cert.cpp
#: ../modules/operserv/os_akill.cpp ../modules/operserv/os_forbid.cpp
#: ../modules/operserv/os_ignore.cpp ../modules/operserv/os_news.cpp
#: ../modules/operserv/os_session.cpp ../modules/operserv/os_sxline.cpp
msgid "Creator"
msgstr ""
@@ -3508,10 +3523,10 @@ msgstr ""
msgid "Depooled %s."
msgstr ""
#: ../modules/nickserv/ns_cert.cpp ../modules/nickserv/ns_alist.cpp
#: ../modules/chanserv/cs_access.cpp ../modules/chanserv/cs_list.cpp
#: ../modules/chanserv/cs_flags.cpp ../modules/chanserv/cs_info.cpp
#: ../modules/chanserv/cs_xop.cpp
#: ../modules/chanserv/cs_access.cpp ../modules/chanserv/cs_flags.cpp
#: ../modules/chanserv/cs_info.cpp ../modules/chanserv/cs_list.cpp
#: ../modules/chanserv/cs_xop.cpp ../modules/nickserv/ns_alist.cpp
#: ../modules/nickserv/ns_cert.cpp
msgid "Description"
msgstr ""
@@ -3857,7 +3872,7 @@ msgstr ""
msgid "End of list - %d channels shown."
msgstr ""
#: ../modules/nickserv/ns_list.cpp ../modules/chanserv/cs_list.cpp
#: ../modules/chanserv/cs_list.cpp ../modules/nickserv/ns_list.cpp
#, c-format
msgid "End of list - %d/%d matches shown."
msgstr ""
@@ -3940,11 +3955,11 @@ msgstr ""
msgid "Exception for %s has been updated to %d."
msgstr ""
#: ../modules/hostserv/hs_offer.cpp ../modules/nickserv/nickserv.cpp
#: ../modules/nickserv/ns_group.cpp ../modules/chanserv/chanserv.cpp
#: ../modules/operserv/os_akill.cpp ../modules/operserv/os_session.cpp
#: ../modules/operserv/os_sxline.cpp ../modules/operserv/os_forbid.cpp
#: ../modules/operserv/os_ignore.cpp
#: ../modules/chanserv/chanserv.cpp ../modules/hostserv/hs_offer.cpp
#: ../modules/nickserv/nickserv.cpp ../modules/nickserv/ns_group.cpp
#: ../modules/operserv/os_akill.cpp ../modules/operserv/os_forbid.cpp
#: ../modules/operserv/os_ignore.cpp ../modules/operserv/os_session.cpp
#: ../modules/operserv/os_sxline.cpp
msgid "Expires"
msgstr ""
@@ -3999,6 +4014,10 @@ msgstr ""
msgid "Fixed layout"
msgstr ""
#: ../modules/chanserv/cs_flags.cpp
msgid "Flag"
msgstr ""
#: ../modules/chanserv/cs_flags.cpp
msgid "Flags"
msgstr ""
@@ -4075,7 +4094,7 @@ msgstr ""
msgid "Forcefully part a user from a channel."
msgstr ""
#: ../modules/nickserv/ns_alist.cpp ../modules/chanserv/cs_info.cpp
#: ../modules/chanserv/cs_info.cpp ../modules/nickserv/ns_alist.cpp
msgid "Founder"
msgstr ""
@@ -4269,16 +4288,16 @@ msgstr ""
msgid "Italics kicker"
msgstr ""
#: ../modules/nickserv/ns_set_keepmodes.cpp ../modules/chanserv/cs_set.cpp
#: ../modules/chanserv/cs_set.cpp ../modules/nickserv/ns_set_keepmodes.cpp
msgid "Keep modes"
msgstr ""
#: ../modules/nickserv/ns_set_keepmodes.cpp ../modules/chanserv/cs_set.cpp
#: ../modules/chanserv/cs_set.cpp ../modules/nickserv/ns_set_keepmodes.cpp
#, c-format
msgid "Keep modes for %s is now off."
msgstr ""
#: ../modules/nickserv/ns_set_keepmodes.cpp ../modules/chanserv/cs_set.cpp
#: ../modules/chanserv/cs_set.cpp ../modules/nickserv/ns_set_keepmodes.cpp
#, c-format
msgid "Keep modes for %s is now on."
msgstr ""
@@ -4296,7 +4315,7 @@ msgstr ""
msgid "Kick a user from a channel"
msgstr ""
#: ../modules/chanserv/cs_kick.cpp ../modules/chanserv/cs_ban.cpp
#: ../modules/chanserv/cs_ban.cpp ../modules/chanserv/cs_kick.cpp
#, c-format
msgid "Kicked %d/%d users matching %s from %s."
msgstr ""
@@ -4306,10 +4325,7 @@ msgid "Kicks a specified nick from a channel"
msgstr ""
#: ../modules/chanserv/cs_kick.cpp
msgid ""
"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."
msgid "Kicks a specified nick from a channel. Channel founders can also specify masks."
msgstr ""
#: ../modules/operserv/os_kill.cpp
@@ -4317,7 +4333,8 @@ msgid "Kill a user"
msgstr ""
#: ../modules/chanserv/cs_enforce.cpp
msgid "LIMIT enforced by "
#, c-format
msgid "LIMIT enforced by %s"
msgstr ""
#: ../modules/chanserv/cs_enforce.cpp
@@ -4341,7 +4358,7 @@ msgstr ""
msgid "LIST [mask | list]"
msgstr ""
#: ../modules/nickserv/ns_cert.cpp ../modules/nickserv/ns_ajoin.cpp
#: ../modules/nickserv/ns_ajoin.cpp ../modules/nickserv/ns_cert.cpp
msgid "LIST [nickname]"
msgstr ""
@@ -4368,7 +4385,7 @@ msgstr ""
msgid "Last quit message"
msgstr ""
#: ../modules/nickserv/ns_info.cpp ../modules/chanserv/cs_access.cpp
#: ../modules/chanserv/cs_access.cpp ../modules/nickserv/ns_info.cpp
msgid "Last seen"
msgstr ""
@@ -4439,7 +4456,7 @@ msgstr ""
msgid "List loaded modules"
msgstr ""
#: ../modules/nickserv/ns_list.cpp ../modules/chanserv/cs_list.cpp
#: ../modules/chanserv/cs_list.cpp ../modules/nickserv/ns_list.cpp
#, c-format
msgid "List of entries matching %s:"
msgstr ""
@@ -4841,13 +4858,13 @@ msgstr ""
msgid "Manipulate the topic of the specified channel"
msgstr ""
#: ../modules/botserv/bs_botlist.cpp ../modules/botserv/bs_info.cpp
#: ../modules/chanserv/cs_access.cpp ../modules/chanserv/cs_akick.cpp
#: ../modules/chanserv/cs_flags.cpp ../modules/chanserv/cs_xop.cpp
#: ../modules/operserv/os_akill.cpp ../modules/operserv/os_list.cpp
#: ../modules/operserv/os_session.cpp ../modules/operserv/os_sxline.cpp
#: ../modules/memoserv/ms_ignore.cpp ../modules/operserv/os_akill.cpp
#: ../modules/operserv/os_forbid.cpp ../modules/operserv/os_ignore.cpp
#: ../modules/memoserv/ms_ignore.cpp ../modules/botserv/bs_info.cpp
#: ../modules/botserv/bs_botlist.cpp
#: ../modules/operserv/os_list.cpp ../modules/operserv/os_session.cpp
#: ../modules/operserv/os_sxline.cpp
msgid "Mask"
msgstr ""
@@ -5063,7 +5080,7 @@ msgid "NOTICE: In order to register a channel, you must have first registered yo
msgstr ""
#: ../modules/chanserv/cs_access.cpp ../modules/chanserv/cs_list.cpp
#: ../modules/operserv/os_list.cpp ../modules/operserv/os_config.cpp
#: ../modules/operserv/os_config.cpp ../modules/operserv/os_list.cpp
msgid "Name"
msgstr ""
@@ -5084,9 +5101,9 @@ msgstr ""
msgid "Never op"
msgstr ""
#: ../modules/hostserv/hs_list.cpp ../modules/hostserv/hs_request.cpp
#: ../modules/nickserv/ns_group.cpp ../modules/nickserv/ns_list.cpp
#: ../modules/botserv/bs_botlist.cpp
#: ../modules/botserv/bs_botlist.cpp ../modules/hostserv/hs_list.cpp
#: ../modules/hostserv/hs_request.cpp ../modules/nickserv/ns_group.cpp
#: ../modules/nickserv/ns_list.cpp
msgid "Nick"
msgstr ""
@@ -5110,7 +5127,7 @@ msgstr ""
msgid "Nick %s is an illegal nickname and cannot be used."
msgstr ""
#: ../modules/operserv/os_svs.cpp ../modules/botserv/bs_bot.cpp
#: ../modules/botserv/bs_bot.cpp ../modules/operserv/os_svs.cpp
#, c-format
msgid "Nick %s is currently in use."
msgstr ""
@@ -5237,7 +5254,7 @@ msgstr ""
msgid "No bot"
msgstr ""
#: ../modules/nickserv/ns_set.cpp ../modules/chanserv/cs_set.cpp
#: ../modules/chanserv/cs_set.cpp ../modules/nickserv/ns_set.cpp
msgid "No expiry"
msgstr ""
@@ -5352,7 +5369,7 @@ msgstr ""
msgid "No such info \"%s\" on %s."
msgstr ""
#: ../modules/chanserv/cs_kick.cpp ../modules/chanserv/cs_ban.cpp
#: ../modules/chanserv/cs_ban.cpp ../modules/chanserv/cs_kick.cpp
#, c-format
msgid "No users on %s match %s."
msgstr ""
@@ -5372,7 +5389,7 @@ msgstr ""
msgid "Non-status modes cleared on %s."
msgstr ""
#: ../modules/operserv/os_dns.cpp ../modules/botserv/bs_info.cpp
#: ../modules/botserv/bs_info.cpp ../modules/operserv/os_dns.cpp
msgid "None"
msgstr ""
@@ -5394,15 +5411,15 @@ msgstr ""
msgid "Now"
msgstr ""
#: ../modules/hostserv/hs_offer.cpp ../modules/hostserv/hs_list.cpp
#: ../modules/hostserv/hs_request.cpp ../modules/nickserv/ns_ajoin.cpp
#: ../modules/nickserv/ns_alist.cpp ../modules/chanserv/cs_access.cpp
#: ../modules/chanserv/cs_log.cpp ../modules/chanserv/cs_akick.cpp
#: ../modules/chanserv/cs_flags.cpp ../modules/chanserv/cs_entrymsg.cpp
#: ../modules/chanserv/cs_xop.cpp ../modules/operserv/os_akill.cpp
#: ../modules/botserv/bs_badwords.cpp ../modules/chanserv/cs_access.cpp
#: ../modules/chanserv/cs_akick.cpp ../modules/chanserv/cs_entrymsg.cpp
#: ../modules/chanserv/cs_flags.cpp ../modules/chanserv/cs_log.cpp
#: ../modules/chanserv/cs_xop.cpp ../modules/global/gl_queue.cpp
#: ../modules/hostserv/hs_list.cpp ../modules/hostserv/hs_offer.cpp
#: ../modules/hostserv/hs_request.cpp ../modules/memoserv/ms_list.cpp
#: ../modules/nickserv/ns_ajoin.cpp ../modules/nickserv/ns_alist.cpp
#: ../modules/operserv/os_akill.cpp ../modules/operserv/os_news.cpp
#: ../modules/operserv/os_session.cpp ../modules/operserv/os_sxline.cpp
#: ../modules/operserv/os_news.cpp ../modules/global/gl_queue.cpp
#: ../modules/memoserv/ms_list.cpp ../modules/botserv/bs_badwords.cpp
msgid "Number"
msgstr ""
@@ -5640,8 +5657,8 @@ msgstr ""
msgid "Prevents users being kicked by services"
msgstr ""
#: ../modules/nickserv/ns_list.cpp ../modules/chanserv/cs_list.cpp
#: ../modules/botserv/bs_info.cpp
#: ../modules/botserv/bs_info.cpp ../modules/chanserv/cs_list.cpp
#: ../modules/nickserv/ns_list.cpp
msgid "Private"
msgstr ""
@@ -5718,11 +5735,13 @@ msgid "Puts an AKILL for every nick on the specified channel. It uses the entire
msgstr ""
#: ../modules/chanserv/cs_enforce.cpp
msgid "REGONLY enforced by "
#, c-format
msgid "REGONLY enforced by %s"
msgstr ""
#: ../modules/chanserv/cs_enforce.cpp
msgid "RESTRICTED enforced by "
#, c-format
msgid "RESTRICTED enforced by %s"
msgstr ""
#: ../modules/operserv/os_noop.cpp
@@ -5747,7 +5766,7 @@ msgstr ""
msgid "Read a memo or memos"
msgstr ""
#: ../modules/botserv/bs_info.cpp ../modules/botserv/bs_botlist.cpp
#: ../modules/botserv/bs_botlist.cpp ../modules/botserv/bs_info.cpp
msgid "Real name"
msgstr ""
@@ -5755,10 +5774,10 @@ msgstr ""
msgid "Realname"
msgstr ""
#: ../modules/hostserv/hs_offer.cpp ../modules/chanserv/cs_akick.cpp
#: ../modules/operserv/os_akill.cpp ../modules/operserv/os_session.cpp
#: ../modules/operserv/os_sxline.cpp ../modules/operserv/os_forbid.cpp
#: ../modules/operserv/os_ignore.cpp
#: ../modules/chanserv/cs_akick.cpp ../modules/hostserv/hs_offer.cpp
#: ../modules/operserv/os_akill.cpp ../modules/operserv/os_forbid.cpp
#: ../modules/operserv/os_ignore.cpp ../modules/operserv/os_session.cpp
#: ../modules/operserv/os_sxline.cpp
msgid "Reason"
msgstr ""
@@ -5788,9 +5807,9 @@ msgstr ""
msgid "Regex matches are also supported using the %s engine. Enclose your mask in // if this is desired."
msgstr ""
#: ../modules/nickserv/ns_list.cpp ../modules/chanserv/cs_list.cpp
#: ../modules/operserv/os_list.cpp ../modules/operserv/os_forbid.cpp
#: ../modules/operserv/os_ignore.cpp
#: ../modules/chanserv/cs_list.cpp ../modules/nickserv/ns_list.cpp
#: ../modules/operserv/os_forbid.cpp ../modules/operserv/os_ignore.cpp
#: ../modules/operserv/os_list.cpp
#, c-format
msgid "Regex matches are also supported using the %s engine. Enclose your pattern in // if this is desired."
msgstr ""
@@ -5803,7 +5822,7 @@ msgstr ""
msgid "Register a nickname"
msgstr ""
#: ../modules/nickserv/ns_group.cpp ../modules/chanserv/cs_info.cpp
#: ../modules/chanserv/cs_info.cpp ../modules/nickserv/ns_group.cpp
msgid "Registered"
msgstr ""
@@ -6049,7 +6068,8 @@ msgid "SSL only enforced on %s."
msgstr ""
#: ../modules/chanserv/cs_enforce.cpp
msgid "SSLONLY enforced by "
#, c-format
msgid "SSLONLY enforced by %s"
msgstr ""
#: ../modules/operserv/os_shutdown.cpp
@@ -6203,7 +6223,7 @@ msgstr ""
msgid "Server %s already exists."
msgstr ""
#: ../modules/operserv/os_noop.cpp ../modules/operserv/os_dns.cpp
#: ../modules/operserv/os_dns.cpp ../modules/operserv/os_noop.cpp
#, c-format
msgid "Server %s does not exist."
msgstr ""
@@ -6327,7 +6347,7 @@ msgstr ""
msgid "Services ignore list:"
msgstr ""
#: ../modules/operserv/os_mode.cpp ../modules/operserv/os_kick.cpp
#: ../modules/operserv/os_kick.cpp ../modules/operserv/os_mode.cpp
msgid "Services is unable to change modes. Are your servers' U:lines configured correctly?"
msgstr ""
@@ -6746,7 +6766,7 @@ msgstr ""
msgid "Stricter control of chanop status"
msgstr ""
#: ../modules/nickserv/ns_alist.cpp ../modules/chanserv/cs_info.cpp
#: ../modules/chanserv/cs_info.cpp ../modules/nickserv/ns_alist.cpp
msgid "Successor"
msgstr ""
@@ -6768,20 +6788,20 @@ msgstr ""
msgid "Suspend a given nick"
msgstr ""
#: ../modules/nickserv/ns_suspend.cpp ../modules/chanserv/cs_suspend.cpp
#: ../modules/chanserv/cs_suspend.cpp ../modules/nickserv/ns_suspend.cpp
msgid "Suspend reason"
msgstr ""
#: ../modules/nickserv/ns_list.cpp ../modules/nickserv/ns_suspend.cpp
#: ../modules/chanserv/cs_suspend.cpp
#: ../modules/chanserv/cs_suspend.cpp ../modules/nickserv/ns_list.cpp
#: ../modules/nickserv/ns_suspend.cpp
msgid "Suspended"
msgstr ""
#: ../modules/nickserv/ns_suspend.cpp ../modules/chanserv/cs_suspend.cpp
#: ../modules/chanserv/cs_suspend.cpp ../modules/nickserv/ns_suspend.cpp
msgid "Suspended by"
msgstr ""
#: ../modules/nickserv/ns_suspend.cpp ../modules/chanserv/cs_suspend.cpp
#: ../modules/chanserv/cs_suspend.cpp ../modules/nickserv/ns_suspend.cpp
msgid "Suspended on"
msgstr ""
@@ -6789,7 +6809,7 @@ msgstr ""
msgid "Suspends a registered nickname, which prevents it from being used while keeping all the data for that nick. If an expiry is given the nick will be unsuspended after that period of time, else the default expiry from the configuration is used."
msgstr ""
#: ../modules/nickserv/ns_suspend.cpp ../modules/chanserv/cs_suspend.cpp
#: ../modules/chanserv/cs_suspend.cpp ../modules/nickserv/ns_suspend.cpp
msgid "Suspension expires"
msgstr ""
@@ -6891,18 +6911,12 @@ msgstr ""
#: ../modules/chanserv/cs_invite.cpp
#, c-format
msgid ""
"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."
msgid "Tells %s to invite you or an optionally specified nick into the given channel."
msgstr ""
#: ../modules/chanserv/cs_unban.cpp
#, c-format
msgid ""
"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."
msgid "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."
msgstr ""
#: ../modules/operserv/os_jupe.cpp
@@ -7229,6 +7243,11 @@ msgstr ""
msgid "The registration confirmation code you specified for %s is incorrect."
msgstr ""
#: ../modules/nickserv/ns_register.cpp
#, c-format
msgid "The registration of %s can only be confirmed by an administrator."
msgstr ""
#: ../modules/nickserv/ns_info.cpp
#, c-format
msgid "The services access status of %s will now be hidden from %s INFO displays."
@@ -7585,7 +7604,7 @@ msgstr ""
msgid "Turns chanstats statistics ON or OFF."
msgstr ""
#: ../modules/operserv/os_forbid.cpp ../modules/botserv/bs_badwords.cpp
#: ../modules/botserv/bs_badwords.cpp ../modules/operserv/os_forbid.cpp
msgid "Type"
msgstr ""
@@ -7599,13 +7618,13 @@ msgstr ""
msgid "Type %scommand for help on any of the above commands."
msgstr ""
#: ../modules/chanserv/cs_set.cpp ../modules/botserv/bs_set.cpp
#: ../modules/botserv/bs_set.cpp ../modules/chanserv/cs_set.cpp
#, c-format
msgid "Type %soption for more information on a particular option."
msgstr ""
#: ../modules/nickserv/ns_set.cpp ../modules/nickserv/ns_confirm.cpp
#: ../modules/memoserv/ms_set.cpp
#: ../modules/memoserv/ms_set.cpp ../modules/nickserv/ns_confirm.cpp
#: ../modules/nickserv/ns_set.cpp
#, c-format
msgid "Type %soption for more information on a specific option."
msgstr ""
@@ -7828,7 +7847,7 @@ msgstr ""
msgid "Users list:"
msgstr ""
#: ../modules/hostserv/hs_offer.cpp ../modules/hostserv/hs_list.cpp
#: ../modules/hostserv/hs_list.cpp ../modules/hostserv/hs_offer.cpp
#: ../modules/hostserv/hs_request.cpp ../modules/nickserv/ns_info.cpp
msgid "VHost"
msgstr ""
@@ -7985,6 +8004,10 @@ msgstr ""
msgid "Word"
msgstr ""
#: ../modules/chanserv/cs_xop.cpp
msgid "XOP"
msgstr ""
#: ../modules/nickserv/ns_group.cpp
#, c-format
msgid "You are already a member of the account of %s."
@@ -8457,7 +8480,7 @@ msgstr ""
msgid "Your SSL certificate fingerprint %s has been automatically added to your certificate list."
msgstr ""
#: ../modules/sql_authentication.cpp ../modules/ldap_authentication.cpp
#: ../modules/ldap_authentication.cpp ../modules/sql_authentication.cpp
#, c-format
msgid "Your account %s has been successfully created."
msgstr ""
@@ -8588,7 +8611,7 @@ msgstr ""
msgid "Your vhost %s has been requested. If the requested vhost is for a valid DNS name you can add a TXT record for %s with the value %s and automatically approve your vhost using %s."
msgstr ""
#: ../modules/hostserv/hs_on.cpp ../modules/hostserv/hostserv.cpp
#: ../modules/hostserv/hostserv.cpp ../modules/hostserv/hs_on.cpp
#, c-format
msgid "Your vhost of %s is now activated."
msgstr ""
@@ -8702,7 +8725,7 @@ msgstr ""
msgid "[language]"
msgstr ""
#: ../modules/greet.cpp ../modules/global/gl_global.cpp
#: ../modules/global/gl_global.cpp ../modules/greet.cpp
msgid "[message]"
msgstr ""
@@ -8718,8 +8741,8 @@ msgstr ""
msgid "[nickname [REVALIDATE]]"
msgstr ""
#: ../modules/nickserv/ns_info.cpp ../modules/nickserv/ns_group.cpp
#: ../modules/nickserv/ns_register.cpp ../modules/nickserv/ns_alist.cpp
#: ../modules/nickserv/ns_alist.cpp ../modules/nickserv/ns_group.cpp
#: ../modules/nickserv/ns_info.cpp ../modules/nickserv/ns_register.cpp
msgid "[nickname]"
msgstr ""
@@ -8785,7 +8808,7 @@ msgstr ""
msgid "not assigned yet"
msgstr ""
#: ../modules/nickserv/ns_set_misc.cpp ../modules/chanserv/cs_set_misc.cpp
#: ../modules/chanserv/cs_set_misc.cpp ../modules/nickserv/ns_set_misc.cpp
msgid "value"
msgstr ""
+2001 -13
View File
File diff suppressed because it is too large Load Diff
+2000 -12
View File
File diff suppressed because it is too large Load Diff
+2 -3
View File
@@ -21,10 +21,9 @@ find ../ \
-o -name '*.h' \
-o -name '*.conf' \
\) \
-exec \
-print0 | sort -z | xargs -0 -I {} \
xgettext \
--language=C++ \
--sort-output \
--default-domain=Anope \
--join-existing \
--output=anope.pot \
@@ -32,7 +31,7 @@ find ../ \
--keyword \
--keyword=_ \
--keyword=N_:1,2 \
{} +
{}
for f in *.po
do
+4 -4
View File
@@ -58,7 +58,7 @@ public:
info[_("Real name")] = bi->realname;
info[_("Created")] = Anope::strftime(bi->created, source.GetAccount());
info[_("Options")] = bi->oper_only ? _("Private") : _("None");
info[_("Used on")] = Anope::Format(Language::Translate(source.nc, bi->GetChannelCount(), N_("%u channel", "%u channels")), bi->GetChannelCount());
info[_("Used on")] = Anope::Format(source.Translate(bi->GetChannelCount(), N_("%u channel", "%u channels")), bi->GetChannelCount());
FOREACH_MOD(OnBotInfo, (source, bi, ci, info));
info.SendTo(source);
@@ -83,8 +83,8 @@ public:
source.Reply(CHAN_INFO_HEADER, ci->name.c_str());
info[_("Bot nick")] = ci->bi ? ci->bi->nick : _("not assigned yet");
Anope::string enabled = Language::Translate(source.nc, _("Enabled"));
Anope::string disabled = Language::Translate(source.nc, _("Disabled"));
Anope::string enabled = source.Translate(_("Enabled"));
Anope::string disabled = source.Translate(_("Disabled"));
FOREACH_MOD(OnBotInfo, (source, bi, ci, info));
info.SendTo(source);
@@ -120,7 +120,7 @@ public:
Anope::string GetDesc(CommandSource &source) const override
{
return Anope::Format(Language::Translate(source.GetAccount(), _("Allows you to see %s information about a channel or a bot")), source.service->nick.c_str());
return Anope::Format(source.Translate(_("Allows you to see %s information about a channel or a bot")), source.service->nick.c_str());
}
};
+5 -4
View File
@@ -1030,11 +1030,11 @@ class BanDataPurger final
{
public:
BanDataPurger(Module *o)
: Timer(o, 300, true)
: Timer(o, 300)
{
}
void Tick() override
bool Tick() override
{
Log(LOG_DEBUG) << "bs_main: Running bandata purger";
@@ -1048,6 +1048,7 @@ public:
c->Shrink<BanData>("bandata");
}
}
return true;
}
};
@@ -1151,8 +1152,8 @@ public:
if (!ci)
return;
Anope::string enabled = Language::Translate(source.nc, _("Enabled"));
Anope::string disabled = Language::Translate(source.nc, _("Disabled"));
Anope::string enabled = source.Translate(_("Enabled"));
Anope::string disabled = source.Translate(_("Disabled"));
auto *kd = kickerdata.Get(ci);
if (kd && kd->badwords)
+2 -1
View File
@@ -92,11 +92,12 @@ public:
{
}
void Tick() override
bool Tick() override
{
Channel *c = Channel::Find(chname);
if (c)
c->RemoveMode(NULL, "BAN", mask);
return false;
}
};
+4 -2
View File
@@ -82,10 +82,10 @@ public:
/** Called when the delay is up
* @param The current time
*/
void Tick() override
bool Tick() override
{
if (!c)
return;
return false; // Dead channel.
/* In the event we don't part */
c->RemoveMode(NULL, "SECRET");
@@ -101,6 +101,8 @@ public:
/* If someone has rejoined this channel in the meantime, don't part the bot */
else if (c->users.size() <= 1)
c->ci->bi->Part(c);
return false;
}
};
+11 -6
View File
@@ -26,10 +26,10 @@ static inline void reset_levels(ChannelInfo *ci)
static Anope::string LevelToString(CommandSource &source, int16_t level)
{
if (level == ACCESS_INVALID)
return Language::Translate(source.GetAccount(), _("(disabled)"));
return source.Translate(_("(disabled)"));
if (level == ACCESS_FOUNDER)
return Language::Translate(source.GetAccount(), _("(founder only)"));
return source.Translate(_("(founder only)"));
return Anope::ToString(level);
}
@@ -92,6 +92,13 @@ public:
{
return new AccessChanAccess(this);
}
void GetAccess(CommandSource& source, const Privilege *p, Anope::map<Anope::string> &access) override
{
auto it = defaultLevels.find(p->name);
if (it != defaultLevels.end())
access[_("Level")] = LevelToString(source, it->second);
}
};
AccessAccessProvider *AccessAccessProvider::me;
@@ -893,7 +900,7 @@ public:
ListFormatter::ListEntry entry;
entry["Name"] = p.name;
entry["Default"] = LevelToString(source, defaultLevels[p.name]);
entry["Description"] = Language::Translate(source.nc, p.desc.c_str());
entry["Description"] = source.Translate(p.desc.c_str());
list.AddEntry(entry);
}
@@ -956,10 +963,8 @@ public:
{
defaultLevels.clear();
for (int i = 0; i < conf.CountBlock("privilege"); ++i)
for (const auto &[_, priv] : conf.GetBlocks("privilege"))
{
const auto &priv = conf.GetBlock("privilege", i);
const Anope::string &pname = priv.Get<const Anope::string>("name");
Privilege *p = PrivilegeManager::FindPrivilege(pname);
+15 -6
View File
@@ -28,6 +28,8 @@ private:
Anope::string mode;
public:
bool ticked = false;
TempBan(time_t seconds, Channel *c, const Anope::string &banmask, const Anope::string &mod)
: Timer(me, seconds)
, channel(c->name)
@@ -51,11 +53,17 @@ public:
&& bmask == this->mask;
}
void Tick() override
bool Tick() override
{
// We need to do this to prevent the remove-on-unban logic from double
// deleting the timer.
ticked = true;
Channel *c = Channel::Find(this->channel);
if (c)
c->RemoveMode(NULL, mode, this->mask);
return false;
}
};
@@ -264,11 +272,12 @@ public:
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."
"of time. Channel founders may ban masks."
));
source.Reply(" ");
AccessProvider::SendAccess(source, "BAN");
return true;
}
};
@@ -290,7 +299,7 @@ public:
{
for (const auto *tempban : tempbans)
{
if (tempban->Matches(c, cmode, param))
if (!tempban->ticked && tempban->Matches(c, cmode, param))
{
delete tempban;
break;
+5 -5
View File
@@ -64,7 +64,7 @@ private:
for (auto *user : users)
{
Anope::string mask = ci->GetIdealBan(user);
Anope::string reason = Language::Translate(user, _("RESTRICTED enforced by ")) + source.GetNick();
Anope::string reason = Anope::Format(Language::Translate(user, _("RESTRICTED enforced by %s")), source.GetNick().c_str());
ci->c->SetMode(NULL, "BAN", mask);
ci->c->Kick(NULL, user, reason);
}
@@ -92,7 +92,7 @@ private:
for (auto *user : users)
{
Anope::string mask = ci->GetIdealBan(user);
Anope::string reason = Language::Translate(user, _("REGONLY enforced by ")) + source.GetNick();
Anope::string reason = Anope::Format(Language::Translate(user, _("REGONLY enforced by %s")), source.GetNick().c_str());
if (!ci->c->HasMode("REGISTEREDONLY"))
ci->c->SetMode(NULL, "BAN", mask);
ci->c->Kick(NULL, user, reason);
@@ -121,7 +121,7 @@ private:
for (auto *user : users)
{
Anope::string mask = ci->GetIdealBan(user);
Anope::string reason = Language::Translate(user, _("SSLONLY enforced by ")) + source.GetNick();
Anope::string reason = Anope::Format(Language::Translate(user, _("SSLONLY enforced by %s")), source.GetNick().c_str());
if (!ci->c->HasMode("SSL"))
ci->c->SetMode(NULL, "BAN", mask);
ci->c->Kick(NULL, user, reason);
@@ -149,7 +149,7 @@ private:
for (auto *user : users)
{
Anope::string reason = Language::Translate(user, _("BANS enforced by ")) + source.GetNick();
Anope::string reason = Anope::Format(Language::Translate(user, _("BANS enforced by %s")), source.GetNick().c_str());
ci->c->Kick(NULL, user, reason);
}
@@ -197,7 +197,7 @@ private:
for (auto *user : users)
{
Anope::string reason = Language::Translate(user, _("LIMIT enforced by ")) + source.GetNick();
Anope::string reason = Anope::Format(Language::Translate(user, _("LIMIT enforced by %s")), source.GetNick().c_str());
ci->c->Kick(NULL, user, reason);
}
+1 -1
View File
@@ -86,7 +86,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
const auto &block = conf.GetModule("chanstats");
prefix = block.Get<const Anope::string>("prefix", "anope_");
prefix = block.Get<const Anope::string>("prefix", "chanstats21_");
this->sql.SetServiceName(block.Get<const Anope::string>("engine"));
}
+1 -1
View File
@@ -114,7 +114,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
const auto &block = conf.GetModule("chanstats");
prefix = block.Get<const Anope::string>("prefix", "anope_");
prefix = block.Get<const Anope::string>("prefix", "chanstats21_");
this->sql.SetServiceName(block.Get<const Anope::string>("engine"));
}
+54 -15
View File
@@ -14,7 +14,15 @@
#include "module.h"
#define FLAGS_MIGRATED_1 _("\002%s\002 has been migrated to the %s access system.")
#define FLAGS_MIGRATED_N N_("\002%u\002 entry has been migrated to the %s access system.", "\002%u\002 entries have been migrated to the %s access system.")
#define FLAGS_NOT_MIGRATABLE_1 _("\002%s\002 can not be migrated to the %s access system because they have no migratable privileges.")
#define FLAGS_NOT_MIGRATABLE_N N_("\002%u\002 entry can not be migrated to the %s access system because they have no migratable privileges.", "\002%u\002 entries can not be migrated to the %s access system because they have no migratable privileges.")
#define FLAGS_NOT_MIGRATED_1 _("\002%s\002 can not be migrated to the %s access system because they have privileges that you do not.")
#define FLAGS_NOT_MIGRATED_N N_("\002%u\002 entry can not be migrated to the %s access system because they have privileges that you do not.", "\002%u\002 entries can not be migrated to the %s access system because they have privileges that you do not.")
static std::map<Anope::string, char> defaultFlags;
static Anope::map<Anope::string> migrationRequires;
class FlagsChanAccess final
: public ChanAccess
@@ -76,6 +84,13 @@ public:
{
return new FlagsChanAccess(this);
}
void GetAccess(CommandSource& source, const Privilege *p, Anope::map<Anope::string> &access) override
{
auto it = defaultFlags.find(p->name);
if (it != defaultFlags.end())
access[_("Flag")] = Anope::ToString(it->second);
}
};
FlagsAccessProvider *FlagsAccessProvider::ap;
@@ -303,8 +318,8 @@ class CommandCSFlags final
return;
auto *access = anope_dynamic_static_cast<FlagsChanAccess *>(provider->Create());
access->SetMask(mask, ci);
access->creator = source.GetNick();
access->description = current ? current->description : description;
access->creator = source.GetNick();
access->description = current && description.empty() ? current->description : description;
access->last_seen = current ? current->last_seen : 0;
access->created = Anope::CurTime;
access->flags = current_flags;
@@ -411,10 +426,9 @@ class CommandCSFlags final
void DoMigrate(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
{
auto override = false;
const auto source_access = source.AccessFor(ci);
unsigned migrated = 0, notmigrated = 0;
Anope::string migratedmask, notmigratedmask;
unsigned migrated = 0, notmigratable = 0, notmigrated = 0;
Anope::string migratedmask, notmigratablemask, notmigratedmask;
const auto &entry = params.size() > 2 ? params[2] : "*";
for (auto idx = ci->GetAccessCount(); idx > 0; --idx)
{
@@ -428,34 +442,52 @@ class CommandCSFlags final
std::set<char> newflags;
for (auto &[priv, flag] : defaultFlags)
{
if (access->HasPriv(priv))
if (!access->HasPriv(priv))
continue; // Source doesn't have this flag.
// Check that the source has access to set this entry.
const auto source_access = source.AccessFor(ci);
if (!override && !source_access.HasPriv(priv) && !source_access.founder)
{
if (!source.HasPriv("chanserv/access/modify"))
{
notmigrated++;
notmigratedmask = access->Mask();
Log(LOG_DEBUG) << source.GetNick() << " does not have the access to migrate " << access->Mask() << " to flags";
continue; // No privs
}
override = true;
}
auto req = migrationRequires.find(priv);
if (req != migrationRequires.end() && !access->HasPriv(req->second))
{
Log(LOG_DEBUG) << access->Mask() << " has " << priv << " but not " << req->second << " so it will be lost on migration to flags";
continue; // Required flag missing.
}
newflags.insert(flag);
}
if (newflags.empty())
{
notmigratable++;
notmigratablemask = access->Mask();
Log(LOG_DEBUG) << access->Mask() << " has " << access->AccessSerialize() << " that can not be migrated to flags";
continue; // No privs that are migratable
}
migrated++;
migratedmask = access->Mask();
auto *newaccess = anope_dynamic_static_cast<FlagsChanAccess *>(FlagsAccessProvider::ap->Create());
newaccess->SetMask(access->Mask(), ci);
newaccess->created = access->created;
newaccess->creator = access->creator;
newaccess->description = access->description;
newaccess->created = access->created;
newaccess->flags = newflags;
newaccess->last_seen = access->last_seen;
ci->EraseAccess(idx - 1);
FOREACH_MOD(OnAccessDel, (ci, source, access, true));
@@ -468,18 +500,23 @@ class CommandCSFlags final
if (migrated == 1)
{
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to migrate " << migratedmask;
source.Reply(CHAN_ACCESS_MIGRATED_1, migratedmask.c_str(), source.command.nobreak().c_str());
source.Reply(FLAGS_MIGRATED_1, migratedmask.c_str(), source.command.nobreak().c_str());
}
else if (migrated > 1)
{
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to migrate " << migrated << " access entries";
source.Reply(migrated, CHAN_ACCESS_MIGRATED_N, migrated, source.command.nobreak().c_str());
source.Reply(migrated, FLAGS_MIGRATED_N, migrated, source.command.nobreak().c_str());
}
if (notmigratable == 1)
source.Reply(FLAGS_NOT_MIGRATABLE_1, notmigratablemask.c_str(), source.command.nobreak().c_str());
else if (notmigratable > 1)
source.Reply(notmigratable, FLAGS_NOT_MIGRATABLE_N, notmigratable, source.command.nobreak().c_str());
if (notmigrated == 1)
source.Reply(CHAN_ACCESS_NOT_MIGRATED_1, notmigratedmask.c_str(), source.command.nobreak().c_str());
source.Reply(FLAGS_NOT_MIGRATED_1, notmigratedmask.c_str(), source.command.nobreak().c_str());
else if (notmigrated > 1)
source.Reply(migrated, CHAN_ACCESS_NOT_MIGRATED_N, notmigrated, source.command.nobreak().c_str());
source.Reply(notmigrated, FLAGS_NOT_MIGRATED_N, notmigrated, source.command.nobreak().c_str());
}
void DoClear(CommandSource &source, ChannelInfo *ci)
@@ -599,7 +636,7 @@ public:
Privilege *p = PrivilegeManager::FindPrivilege(priv);
if (p == NULL)
continue;
source.Reply(" %c - %s", flag, Language::Translate(source.nc, p->desc.c_str()));
source.Reply(" %c - %s", flag, source.Translate(p->desc.c_str()));
}
return true;
@@ -624,10 +661,8 @@ public:
{
defaultFlags.clear();
for (int i = 0; i < conf.CountBlock("privilege"); ++i)
for (const auto &[_, priv] : conf.GetBlocks("privilege"))
{
const auto &priv = conf.GetBlock("privilege", i);
const Anope::string &pname = priv.Get<const Anope::string>("name");
Privilege *p = PrivilegeManager::FindPrivilege(pname);
@@ -638,6 +673,10 @@ public:
if (value.empty())
continue;
const auto &migration_requires = priv.Get<const Anope::string>("flag_migration_requires");
if (!migration_requires.empty())
migrationRequires[p->name] = migration_requires;
defaultFlags[p->name] = value[0];
}
}
+4 -3
View File
@@ -95,11 +95,12 @@ public:
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());
source.Reply(" ");
AccessProvider::SendAccess(source, "INVITE");
return true;
}
};
+5 -6
View File
@@ -134,12 +134,11 @@ 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 "
"and above on the channel. Channel founders can also specify masks."
));
source.Reply(_("Kicks a specified nick from a channel. Channel founders can also specify masks."));
source.Reply(" ");
AccessProvider::SendAccess(source, "KICK");
return true;
}
};
+1 -1
View File
@@ -122,7 +122,7 @@ public:
ListFormatter::ListEntry entry;
entry["Name"] = (isnoexpire ? "!" : "") + ci->name;
if (ci->HasExt("CS_SUSPENDED"))
entry["Description"] = Language::Translate(source.GetAccount(), _("[Suspended]"));
entry["Description"] = source.Translate(_("[Suspended]"));
else
entry["Description"] = ci->desc;
list.AddEntry(entry);
+1 -3
View File
@@ -331,10 +331,8 @@ public:
const auto &block = conf.GetModule(this);
defaults.clear();
for (int i = 0; i < block.CountBlock("default"); ++i)
for (const auto &[_, def] : block.GetBlocks("default"))
{
const auto &def = block.GetBlock("default", i);
LogDefault ld;
ld.service = def.Get<const Anope::string>("service");
+3 -5
View File
@@ -945,9 +945,9 @@ public:
if (!m.second.empty())
{
if (m.first)
return Anope::Format(Language::Translate(source.GetAccount(), _("Gives you or the specified nick %s status on a channel")), m.second.c_str());
return Anope::Format(source.Translate(_("Gives you or the specified nick %s status on a channel")), m.second.c_str());
else
return Anope::Format(Language::Translate(source.GetAccount(), _("Removes %s status from you or the specified nick on a channel")), m.second.c_str());
return Anope::Format(source.Translate(_("Removes %s status from you or the specified nick on a channel")), m.second.c_str());
}
else
return "";
@@ -999,10 +999,8 @@ public:
{
modes.clear();
for (int i = 0; i < conf.CountBlock("command"); ++i)
for (const auto &[_, block] : conf.GetBlocks("command"))
{
const auto &block = conf.GetBlock("command", i);
const Anope::string &cname = block.Get<const Anope::string>("name"),
&cmd = block.Get<const Anope::string>("command");
+3 -3
View File
@@ -281,7 +281,7 @@ public:
if (u2)
onlinestatus = ".";
else
onlinestatus = Anope::Format(Language::Translate(source.nc, _(" but %s mysteriously dematerialized.")), target.c_str());
onlinestatus = Anope::Format(source.Translate(_(" but %s mysteriously dematerialized.")), target.c_str());
Anope::string timebuf = Anope::Duration(Anope::CurTime - info->last, source.nc);
Anope::string timebuf2 = Anope::strftime(info->last, source.nc, true);
@@ -295,9 +295,9 @@ public:
{
u2 = User::Find(info->nick2, true);
if (u2)
onlinestatus = Anope::Format(Language::Translate(source.nc, _(". %s is still online.")), u2->nick.c_str());
onlinestatus = Anope::Format(source.Translate(_(". %s is still online.")), u2->nick.c_str());
else
onlinestatus = Anope::Format(Language::Translate(source.nc, _(", but %s mysteriously dematerialized.")), info->nick2.c_str());
onlinestatus = Anope::Format(source.Translate(_(", but %s mysteriously dematerialized.")), info->nick2.c_str());
source.Reply(_("%s (%s) was last seen changing nick to %s %s ago%s"),
target.c_str(), info->vhost.c_str(), info->nick2.c_str(), timebuf.c_str(), onlinestatus.c_str());
+5 -5
View File
@@ -222,7 +222,7 @@ public:
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply("%s", Language::Translate(source.nc, it->second.description.c_str()));
source.Reply("%s", source.Translate(it->second.description.c_str()));
return true;
}
return false;
@@ -237,8 +237,8 @@ public:
this->ClearSyntax();
this->SetSyntax(Anope::Format(
Language::Translate(source.nc, _("\037channel\037 [\037%s\037]")),
Language::Translate(source.nc, value)
source.Translate(_("\037channel\037 [\037%s\037]")),
source.Translate(value)
));
Command::SendSyntax(source);
@@ -268,9 +268,9 @@ public:
void OnReload(Configuration::Conf &conf) override
{
command_data.clear();
for (int i = 0; i < conf.CountBlock("command"); ++i)
for (const auto &[_, block] : conf.GetBlocks("command"))
{
const auto &block = conf.GetBlock("command", i);
if (block.Get<const Anope::string>("command") != "chanserv/set/misc")
continue;
+4 -3
View File
@@ -128,11 +128,12 @@ public:
"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());
source.Reply(" ");
AccessProvider::SendAccess(source, "UNBAN");
return true;
}
};
+16 -5
View File
@@ -100,6 +100,19 @@ public:
{
return new XOPChanAccess(this);
}
void GetAccess(CommandSource& source, const Privilege *p, Anope::map<Anope::string> &access) override
{
for (const auto& xop : order)
{
const auto &privs = permissions[xop];
if (std::find(privs.begin(), privs.end(), p->name) != privs.end())
{
access[_("XOP")] = xop;
return;
}
}
}
};
class CommandCSXOP final
@@ -543,7 +556,7 @@ public:
Anope::string GetDesc(CommandSource &source) const override
{
return Anope::Format(Language::Translate(source.GetAccount(), _("Modify the list of %s users")), source.command.nobreak().c_str());
return Anope::Format(source.Translate(_("Modify the list of %s users")), source.command.nobreak().c_str());
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
@@ -675,9 +688,8 @@ public:
order.clear();
permissions.clear();
for (int i = 0; i < conf.CountBlock("privilege"); ++i)
for (const auto &[_, block] : conf.GetBlocks("privilege"))
{
const auto &block = conf.GetBlock("privilege", i);
const Anope::string &pname = block.Get<const Anope::string>("name");
Privilege *p = PrivilegeManager::FindPrivilege(pname);
@@ -691,9 +703,8 @@ public:
permissions[xop].push_back(pname);
}
for (int i = 0; i < conf.CountBlock("command"); ++i)
for (const auto &[_, block] : conf.GetBlocks("command"))
{
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")
+5 -3
View File
@@ -353,14 +353,16 @@ class MChanstats final
"(nick_, '', 'total'), (nick_, '', 'monthly'),"
"(nick_, '', 'weekly'), (nick_, '', 'daily');"
"END IF;"
"SET @echan = chan_;"
"SET @enick = nick_;"
"SET @update_query = CONCAT('UPDATE `" + prefix + "chanstats` SET line=line+', line_, ',"
"letters=letters+', letters_, ' , words=words+', words_, ', actions=actions+', actions_, ', "
"smileys_happy=smileys_happy+', sm_h_, ', smileys_sad=smileys_sad+', sm_s_, ', "
"smileys_other=smileys_other+', sm_o_, ', kicks=kicks+', kicks_, ', kicked=kicked+', kicked_, ', "
"modes=modes+', modes_, ', topics=topics+', topics_, ', ', time_ , '=', time_, '+', line_ ,' "
"WHERE (nick='''' OR nick=''', nick_, ''') AND (chan='''' OR chan=''', chan_, ''')');"
"WHERE (nick='''' OR nick=?) AND (chan='''' OR chan=?)');"
"PREPARE update_query FROM @update_query;"
"EXECUTE update_query;"
"EXECUTE update_query using @enick, @echan;"
"DEALLOCATE PREPARE update_query;"
"END";
this->RunQuery(query);
@@ -509,7 +511,7 @@ public:
void OnReload(Configuration::Conf &conf) override
{
const auto &block = conf.GetModule(this);
prefix = block.Get<const Anope::string>("prefix", "anope_");
prefix = block.Get<const Anope::string>("prefix", "chanstats21_");
SmileysHappy = block.Get<const Anope::string>("SmileysHappy");
SmileysSad = block.Get<const Anope::string>("SmileysSad");
SmileysOther = block.Get<const Anope::string>("SmileysOther");
+3 -6
View File
@@ -1584,9 +1584,8 @@ public:
const auto &modconf = conf.GetModule(this);
csmiscdata.clear();
for (auto idx = 0; idx < modconf.CountBlock("cs_set_misc"); ++idx)
for (const auto &[_, data] : modconf.GetBlocks("cs_set_misc"))
{
const auto &data = modconf.GetBlock("cs_set_misc", idx);
const auto &anope = data.Get<const Anope::string>("anope");
const auto &atheme = data.Get<const Anope::string>("atheme");
if (!anope.empty() && !atheme.empty())
@@ -1594,9 +1593,8 @@ public:
}
nsmiscdata.clear();
for (auto idx = 0; idx < modconf.CountBlock("ns_set_misc"); ++idx)
for (const auto &[_, data] : modconf.GetBlocks("ns_set_misc"))
{
const auto &data = modconf.GetBlock("ns_set_misc", idx);
const auto &anope = data.Get<const Anope::string>("anope");
const auto &atheme = data.Get<const Anope::string>("atheme");
if (!anope.empty() && !atheme.empty())
@@ -1604,9 +1602,8 @@ public:
}
flags.clear();
for (int i = 0; i < Config->CountBlock("privilege"); ++i)
for (const auto &[_, priv] : conf.GetBlocks("privilege"))
{
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())
+9
View File
@@ -412,9 +412,18 @@ public:
// Step 2: store the new data.
for (auto *item : Serializable::GetItems())
{
if (!item->ShouldCommit())
{
Log(LOG_DEBUG) << "Not committing dead " << item->GetSerializableName() << " object: " << item;
continue; // Non-committable object.
}
auto *s_type = item->GetSerializableType();
if (!s_type)
{
Log(LOG_DEBUG) << "Not committing orphaned " << item->GetSerializableName() << " object: " << item;
continue; // Provider has been unloaded.
}
// This should always be found because we create it in the previous step.
auto it = databases.find(s_type->GetOwner());
-648
View File
@@ -1,648 +0,0 @@
// Anope IRC Services <https://www.anope.org/>
//
// Copyright (C) 2003-2026 Anope Contributors
//
// Anope is free software. You can use, modify, and/or distribute it under the
// terms of version 2 of the GNU General Public License. See docs/LICENSE.txt
// for the complete terms of this license and docs/AUTHORS.txt for a list of
// contributors.
//
// Based on the original code of Epona by Lara
// Based on the original code of Services by Andy Church
//
// SPDX-License-Identifier: GPL-2.0-only
#include "module.h"
#include "modules/redis.h"
using namespace Redis;
class DatabaseRedis;
static DatabaseRedis *me;
class Data final
: public Serialize::Data
{
public:
Anope::unordered_map<Anope::string> data;
bool LoadInternal(const Anope::string &key, Anope::string &value) override
{
auto it = this->data.find(key);
if (it == this->data.end())
return false;
value = it->second;
return true;
}
bool StoreInternal(const Anope::string &key, const Anope::string &value) override
{
this->data[key] = value;
return true;
}
size_t Hash() const override
{
size_t hash = 0;
for (const auto &[_, value] : this->data)
if (!value.empty())
hash ^= Anope::hash_cs()(value);
return hash;
}
};
class TypeLoader final
: public Interface
{
Anope::string type;
public:
TypeLoader(Module *creator, const Anope::string &t) : Interface(creator), type(t) { }
void OnResult(const Reply &r) override;
};
class ObjectLoader final
: public Interface
{
Anope::string type;
int64_t id;
public:
ObjectLoader(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { }
void OnResult(const Reply &r) override;
};
class IDInterface final
: public Interface
{
Reference<Serializable> o;
public:
IDInterface(Module *creator, Serializable *obj) : Interface(creator), o(obj) { }
void OnResult(const Reply &r) override;
};
class Deleter final
: public Interface
{
Anope::string type;
int64_t id;
public:
Deleter(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { }
void OnResult(const Reply &r) override;
};
class Updater final
: public Interface
{
Anope::string type;
int64_t id;
public:
Updater(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { }
void OnResult(const Reply &r) override;
};
class ModifiedObject final
: public Interface
{
Anope::string type;
int64_t id;
public:
ModifiedObject(Module *creator, const Anope::string &t, int64_t i) : Interface(creator), type(t), id(i) { }
void OnResult(const Reply &r) override;
};
class SubscriptionListener final
: public Interface
{
public:
SubscriptionListener(Module *creator) : Interface(creator) { }
void OnResult(const Reply &r) override;
};
class DatabaseRedis final
: public Module
, public Pipe
{
SubscriptionListener sl;
std::set<Serializable *> updated_items;
public:
ServiceReference<Provider> redis;
DatabaseRedis(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, DATABASE | VENDOR)
, sl(this)
, redis("Redis::Provider")
{
me = this;
}
/* Insert or update an object */
void InsertObject(Serializable *obj)
{
Serialize::Type *t = obj->GetSerializableType();
/* If there is no id yet for this object, get one */
if (!obj->object_id)
redis->SendCommand(new IDInterface(this, obj), "INCR id:" + t->GetName());
else
{
Data data;
t->Serialize(obj, data);
if (obj->IsCached(data))
return;
obj->UpdateCache(data);
std::vector<Anope::string> args;
args.emplace_back("HGETALL");
args.push_back("hash:" + t->GetName() + ":" + Anope::ToString(obj->object_id));
/* Get object attrs to clear before updating */
redis->SendCommand(new Updater(this, t->GetName(), obj->object_id), args);
}
}
void OnNotify() override
{
for (auto *obj : this->updated_items)
{
this->InsertObject(obj);
}
this->updated_items.clear();
}
void OnReload(Configuration::Conf &conf) override
{
const auto &block = conf.GetModule(this);
this->redis.SetServiceName(block.Get<const Anope::string>("engine", "redis/main"));
}
EventReturn OnLoadDatabase() override
{
if (!redis)
{
Log(this) << "Unable to load database - unable to find redis provider";
return EVENT_CONTINUE;
}
for (const auto &type_order : Serialize::Type::GetTypeOrder())
{
Serialize::Type *sb = Serialize::Type::Find(type_order);
this->OnSerializeTypeCreate(sb);
}
while (!redis->IsSocketDead() && redis->BlockAndProcess());
if (redis->IsSocketDead())
{
Log(this) << "I/O error while loading redis database - is it online?";
return EVENT_CONTINUE;
}
redis->Subscribe(&this->sl, "__keyspace@*__:hash:*");
return EVENT_STOP;
}
void OnSerializeTypeCreate(Serialize::Type *sb) override
{
if (!redis)
return;
std::vector<Anope::string> args;
args.emplace_back("SMEMBERS");
args.push_back("ids:" + sb->GetName());
redis->SendCommand(new TypeLoader(this, sb->GetName()), args);
}
void OnSerializableConstruct(Serializable *obj) override
{
this->updated_items.insert(obj);
this->Notify();
}
void OnSerializableDestruct(Serializable *obj) override
{
Serialize::Type *t = obj->GetSerializableType();
if (t == NULL)
{
/* This is probably the module providing the type unloading.
*
* The types get registered after the extensible container is
* registered so that unserialization on module load can insert
* into the extensible container. So, the type destructs prior to
* the extensible container, which then triggers this
*/
return;
}
std::vector<Anope::string> args;
args.emplace_back("HGETALL");
args.push_back("hash:" + t->GetName() + ":" + Anope::ToString(obj->object_id));
/* Get all of the attributes for this object */
redis->SendCommand(new Deleter(this, t->GetName(), obj->object_id), args);
this->updated_items.erase(obj);
t->objects.erase(obj->object_id);
this->Notify();
}
void OnSerializableUpdate(Serializable *obj) override
{
this->updated_items.insert(obj);
this->Notify();
}
};
void TypeLoader::OnResult(const Reply &r)
{
if (r.type != Reply::MULTI_BULK || !me->redis)
{
delete this;
return;
}
for (auto *reply : r.multi_bulk)
{
if (reply->type != Reply::BULK)
continue;
auto i = Anope::TryConvert<int64_t>(reply->bulk);
if (!i)
continue;
auto id = i.value();
std::vector<Anope::string> args;
args.emplace_back("HGETALL");
args.push_back("hash:" + this->type + ":" + Anope::ToString(id));
me->redis->SendCommand(new ObjectLoader(me, this->type, id), args);
}
delete this;
}
void ObjectLoader::OnResult(const Reply &r)
{
Serialize::Type *st = Serialize::Type::Find(this->type);
if (r.type != Reply::MULTI_BULK || r.multi_bulk.empty() || !me->redis || !st)
{
delete this;
return;
}
Data data;
for (unsigned i = 0; i + 1 < r.multi_bulk.size(); i += 2)
{
const Reply *key = r.multi_bulk[i],
*value = r.multi_bulk[i + 1];
data.StoreInternal(key->bulk, value->bulk);
}
Serializable *&obj = st->objects[this->id];
obj = st->Unserialize(obj, data);
if (obj)
{
obj->object_id = this->id;
obj->UpdateCache(data);
}
delete this;
}
void IDInterface::OnResult(const Reply &r)
{
if (!o || r.type != Reply::INT || !r.i)
{
delete this;
return;
}
Serializable *&obj = o->GetSerializableType()->objects[r.i];
if (obj)
/* This shouldn't be possible */
obj->object_id = 0;
o->object_id = r.i;
obj = o;
/* Now that we have the id, insert this object for real */
anope_dynamic_static_cast<DatabaseRedis *>(this->owner)->InsertObject(o);
delete this;
}
void Deleter::OnResult(const Reply &r)
{
if (r.type != Reply::MULTI_BULK || !me->redis || r.multi_bulk.empty())
{
delete this;
return;
}
/* Transaction start */
me->redis->StartTransaction();
std::vector<Anope::string> args;
args.emplace_back("DEL");
args.push_back("hash:" + this->type + ":" + Anope::ToString(this->id));
/* Delete hash object */
me->redis->SendCommand(NULL, args);
args.clear();
args.emplace_back("SREM");
args.push_back("ids:" + this->type);
args.push_back(Anope::ToString(this->id));
/* Delete id from ids set */
me->redis->SendCommand(NULL, args);
for (unsigned i = 0; i + 1 < r.multi_bulk.size(); i += 2)
{
const Reply *key = r.multi_bulk[i],
*value = r.multi_bulk[i + 1];
args.clear();
args.emplace_back("SREM");
args.push_back("value:" + this->type + ":" + key->bulk + ":" + value->bulk);
args.push_back(Anope::ToString(this->id));
/* Delete value -> object id */
me->redis->SendCommand(NULL, args);
}
/* Transaction end */
me->redis->CommitTransaction();
delete this;
}
void Updater::OnResult(const Reply &r)
{
Serialize::Type *st = Serialize::Type::Find(this->type);
if (!st)
{
delete this;
return;
}
Serializable *obj = st->objects[this->id];
if (!obj)
{
delete this;
return;
}
Data data;
st->Serialize(obj, data);
/* Transaction start */
me->redis->StartTransaction();
for (unsigned i = 0; i + 1 < r.multi_bulk.size(); i += 2)
{
const Reply *key = r.multi_bulk[i],
*value = r.multi_bulk[i + 1];
std::vector<Anope::string> args;
args.emplace_back("SREM");
args.push_back("value:" + this->type + ":" + key->bulk + ":" + value->bulk);
args.push_back(Anope::ToString(this->id));
/* Delete value -> object id */
me->redis->SendCommand(NULL, args);
}
/* Add object id to id set for this type */
std::vector<Anope::string> args;
args.emplace_back("SADD");
args.push_back("ids:" + this->type);
args.push_back(Anope::ToString(obj->object_id));
me->redis->SendCommand(NULL, args);
args.clear();
args.emplace_back("HMSET");
args.push_back("hash:" + this->type + ":" + Anope::ToString(obj->object_id));
for (const auto &[key, value] : data.data)
{
args.push_back(key);
args.emplace_back(value);
std::vector<Anope::string> args2;
args2.emplace_back("SADD");
args2.push_back("value:" + this->type + ":" + key + ":" + value);
args2.push_back(Anope::ToString(obj->object_id));
/* Add to value -> object id set */
me->redis->SendCommand(NULL, args2);
}
++obj->redis_ignore;
/* Add object */
me->redis->SendCommand(NULL, args);
/* Transaction end */
me->redis->CommitTransaction();
delete this;
}
void SubscriptionListener::OnResult(const Reply &r)
{
/*
* [May 15 13:59:35.645839 2013] Debug: pmessage
* [May 15 13:59:35.645866 2013] Debug: __keyspace@*__:anope:hash:*
* [May 15 13:59:35.645880 2013] Debug: __keyspace@0__:anope:hash:type:id
* [May 15 13:59:35.645893 2013] Debug: hset
*/
if (r.multi_bulk.size() != 4)
return;
size_t sz = r.multi_bulk[2]->bulk.find(':');
if (sz == Anope::string::npos)
return;
const Anope::string &key = r.multi_bulk[2]->bulk.substr(sz + 1),
&op = r.multi_bulk[3]->bulk;
sz = key.rfind(':');
if (sz == Anope::string::npos)
return;
const Anope::string &id = key.substr(sz + 1);
size_t sz2 = key.rfind(':', sz - 1);
if (sz2 == Anope::string::npos)
return;
const Anope::string &type = key.substr(sz2 + 1, sz - sz2 - 1);
Serialize::Type *s_type = Serialize::Type::Find(type);
if (s_type == NULL)
return;
auto oid = Anope::TryConvert<Serializable::Id>(id);
if (!oid.has_value())
return;
auto obj_id = oid.value();
if (op == "hset" || op == "hdel")
{
Serializable *s = s_type->objects[obj_id];
if (s && s->redis_ignore)
{
--s->redis_ignore;
Log(LOG_DEBUG) << "redis: notify: got modify for object id " << obj_id << " of type " << type << ", but I am ignoring it";
}
else
{
Log(LOG_DEBUG) << "redis: notify: got modify for object id " << obj_id << " of type " << type;
std::vector<Anope::string> args;
args.emplace_back("HGETALL");
args.push_back("hash:" + type + ":" + id);
me->redis->SendCommand(new ModifiedObject(me, type, obj_id), args);
}
}
else if (op == "del")
{
Serializable *&s = s_type->objects[obj_id];
if (s == NULL)
return;
Log(LOG_DEBUG) << "redis: notify: deleting object id " << obj_id << " of type " << type;
Data data;
s_type->Serialize(s, data);
/* Transaction start */
me->redis->StartTransaction();
for (const auto &[k, value] : data.data)
{
std::vector<Anope::string> args;
args.emplace_back("SREM");
args.push_back("value:" + type + ":" + k + ":" + value);
args.push_back(id);
/* Delete value -> object id */
me->redis->SendCommand(NULL, args);
}
std::vector<Anope::string> args;
args.emplace_back("SREM");
args.push_back("ids:" + type);
args.push_back(Anope::ToString(s->object_id));
/* Delete object from id set */
me->redis->SendCommand(NULL, args);
/* Transaction end */
me->redis->CommitTransaction();
delete s;
s = NULL;
}
}
void ModifiedObject::OnResult(const Reply &r)
{
Serialize::Type *st = Serialize::Type::Find(this->type);
if (!st)
{
delete this;
return;
}
Serializable *&obj = st->objects[this->id];
/* Transaction start */
me->redis->StartTransaction();
/* Erase old object values */
if (obj)
{
Data data;
st->Serialize(obj, data);
for (auto &[key, value] : data.data)
{
std::vector<Anope::string> args;
args.emplace_back("SREM");
args.push_back("value:" + st->GetName() + ":" + key + ":" + value);
args.push_back(Anope::ToString(this->id));
/* Delete value -> object id */
me->redis->SendCommand(NULL, args);
}
}
Data data;
for (unsigned i = 0; i + 1 < r.multi_bulk.size(); i += 2)
{
const Reply *key = r.multi_bulk[i],
*value = r.multi_bulk[i + 1];
data.StoreInternal(key->bulk, value->bulk);
}
obj = st->Unserialize(obj, data);
if (obj)
{
obj->object_id = this->id;
obj->UpdateCache(data);
/* Insert new object values */
for (const auto &[key, value] : data.data)
{
std::vector<Anope::string> args;
args.emplace_back("SADD");
args.push_back("value:" + st->GetName() + ":" + key + ":" + value);
args.push_back(Anope::ToString(obj->object_id));
/* Add to value -> object id set */
me->redis->SendCommand(NULL, args);
}
std::vector<Anope::string> args;
args.emplace_back("SADD");
args.push_back("ids:" + st->GetName());
args.push_back(Anope::ToString(obj->object_id));
/* Add to type -> id set */
me->redis->SendCommand(NULL, args);
}
/* Transaction end */
me->redis->CommitTransaction();
delete this;
}
MODULE_INIT(DatabaseRedis)
+7 -1
View File
@@ -120,6 +120,12 @@ public:
{
if (this->sql)
{
if (!obj->ShouldCommit())
{
OnSerializableDestruct(obj);
continue; // Non-committable object.
}
Serialize::Type *s_type = obj->GetSerializableType();
if (!s_type)
continue;
@@ -168,7 +174,7 @@ public:
{
const auto &block = conf.GetModule(this);
this->sql.SetServiceName(block.Get<const Anope::string>("engine"));
this->prefix = block.Get<const Anope::string>("prefix", "anope_db_");
this->prefix = block.Get<const Anope::string>("prefix", "anope21_");
this->import = block.Get<bool>("import");
}
+7 -1
View File
@@ -104,6 +104,12 @@ public:
{
if (obj && this->SQL)
{
if (!obj->ShouldCommit())
{
OnSerializableDestruct(obj);
continue; // Non-committable object.
}
Serialize::Type *s_type = obj->GetSerializableType();
if (!s_type)
continue;
@@ -152,7 +158,7 @@ public:
const auto &block = conf.GetModule(this);
this->SQL.SetServiceName(block.Get<const Anope::string>("engine"));
this->prefix = block.Get<const Anope::string>("prefix", "anope_db_");
this->prefix = block.Get<const Anope::string>("prefix", "anope21_");
}
void OnSerializableConstruct(Serializable *obj) override
+6 -5
View File
@@ -534,8 +534,9 @@ public:
}
/* Times out after a few seconds */
void Tick() override
bool Tick() override
{
return false;
}
void Reply(Packet *p) override
@@ -718,7 +719,7 @@ public:
MyManager(Module *creator)
: Manager(creator)
, Timer(300, true)
, Timer(300)
, serial(Anope::CurTime)
, cur_id(Anope::RandomNumber())
{
@@ -1011,7 +1012,7 @@ public:
return serial;
}
void Tick() override
bool Tick() override
{
Log(LOG_DEBUG_2) << "Resolver: Purging DNS cache";
@@ -1025,6 +1026,7 @@ public:
if (req.created + static_cast<time_t>(req.ttl) < Anope::CurTime)
this->cache.erase(it);
}
return true;
}
private:
@@ -1093,9 +1095,8 @@ public:
refresh = block.Get<int>("refresh", "3600");
std::vector<std::pair<Anope::string, short> > notify;
for (int i = 0; i < block.CountBlock("notify"); ++i)
for (const auto &[_, n] : block.GetBlocks("notify"))
{
const auto &n = block.GetBlock("notify", i);
auto nip = n.Get<Anope::string>("ip");
auto nport = n.Get<short>("port");
+3 -6
View File
@@ -126,9 +126,8 @@ public:
this->add_to_akill = block.Get<bool>("add_to_akill", "yes");
this->blacklists.clear();
for (int i = 0; i < block.CountBlock("blacklist"); ++i)
for (const auto &[_, bl] : block.GetBlocks("blacklist"))
{
const auto &bl = block.GetBlock("blacklist", i);
Blacklist blacklist;
blacklist.name = bl.Get<Anope::string>("name");
@@ -137,9 +136,8 @@ public:
blacklist.bantime = bl.Get<time_t>("time", "4h");
blacklist.reason = bl.Get<Anope::string>("reason");
for (int j = 0; j < bl.CountBlock("reply"); ++j)
for (const auto &[_, reply] : block.GetBlocks("reply"))
{
const auto &reply = bl.GetBlock("reply", j);
Blacklist::Reply r;
r.code = reply.Get<int>("code");
@@ -153,9 +151,8 @@ public:
}
this->exempts.clear();
for (int i = 0; i < block.CountBlock("exempt"); ++i)
for (const auto &[_, bl] : block.GetBlocks("exempt"))
{
const auto &bl = block.GetBlock("exempt", i);
this->exempts.insert(bl.Get<Anope::string>("ip"));
}
}
+76 -4
View File
@@ -405,6 +405,80 @@ public:
QueueRequest(mod);
}
Anope::string EscapeDN(const Anope::string &str) const override
{
if (str.empty())
return str;
Anope::string newstr;
newstr.str().reserve(str.length());
for (size_t idx = 0; idx < str.length(); ++idx)
{
const char chr = str[idx];
if (chr == '\0')
{
newstr.append("\\00");
}
else if (chr == '"' || chr == '+' || chr == ',' || chr == ';' ||
chr == '<' || chr == '=' || chr == '>' || chr == '\\')
{
newstr.push_back('\\');
newstr.push_back(chr);
}
else if (idx == 0 && (chr == '#' || chr == ' '))
{
newstr.push_back('\\');
newstr.push_back(chr);
}
else if (idx == str.length() - 1 && chr == ' ')
{
newstr.push_back('\\');
newstr.push_back(chr);
}
else
{
newstr.push_back(chr);
}
}
return newstr;
}
Anope::string EscapeSF(const Anope::string &str) const override
{
if (str.empty())
return str;
Anope::string newstr;
newstr.str().reserve(str.length());
for (size_t idx = 0; idx < str.length(); ++idx)
{
const char chr = str[idx];
switch (chr)
{
case '\0':
newstr.append("\\00");
break;
case '(':
newstr.append("\\28");
break;
case ')':
newstr.append("\\29");
break;
case '*':
newstr.append("\\2A");
break;
case '\\':
newstr.append("\\5C");
break;
default:
newstr.push_back(chr);
break;
}
}
return newstr;
}
private:
void BuildReply(int res, LDAPRequest *req)
{
@@ -560,7 +634,7 @@ public:
{
const Anope::string &cname = it->first;
LDAPService *s = it->second;
int i;
size_t i;
++it;
@@ -580,10 +654,8 @@ public:
}
}
for (int i = 0; i < conf.CountBlock("ldap"); ++i)
for (const auto &[_, ldap] : conf.GetBlocks("ldap"))
{
const auto &ldap = conf.GetBlock("ldap", i);
const Anope::string &connname = ldap.Get<const Anope::string>("name", "ldap/main");
if (this->LDAPServices.find(connname) == this->LDAPServices.end())
+2 -3
View File
@@ -281,7 +281,7 @@ public:
{
const Anope::string &cname = it->first;
MySQLService *s = it->second;
int i;
size_t i;
++it;
@@ -298,9 +298,8 @@ public:
}
}
for (int i = 0; i < config.CountBlock("mysql"); ++i)
for (const auto &[_, block] : config.GetBlocks("mysql"))
{
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 -3
View File
@@ -129,7 +129,7 @@ public:
{
const Anope::string &cname = it->first;
SQLiteService *s = it->second;
int i, num;
size_t i, num;
++it;
for (i = 0, num = config.CountBlock("sqlite"); i < num; ++i)
@@ -145,9 +145,8 @@ public:
}
}
for (int i = 0; i < config.CountBlock("sqlite"); ++i)
for (const auto &[_, block] : config.GetBlocks("sqlite"))
{
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())
+1 -3
View File
@@ -331,10 +331,8 @@ public:
throw ConfigException("Unable to find http reference, is httpd loaded?");
xmlrpcinterface.tokens.clear();
for (int i = 0; i < modconf.CountBlock("token"); ++i)
for (const auto &[_, block] : modconf.GetBlocks("token"))
{
const auto &block = modconf.GetBlock("token", i);
RPC::Token token;
token.token = block.Get<const Anope::string>("token");
if (!token.token.empty())
+2 -2
View File
@@ -669,7 +669,7 @@ public:
{
if (!show_all)
return;
mask = Anope::Format(Language::Translate(source.GetAccount(), _("%s [Invalid]")), mask.c_str());
mask = Anope::Format(source.Translate(_("%s [Invalid]")), mask.c_str());
}
ListFormatter::ListEntry entry;
@@ -835,7 +835,7 @@ private:
{
if (!show_all)
continue;
mask = Anope::Format(Language::Translate(source.GetAccount(), _("%s [Invalid]")), mask.c_str());
mask = Anope::Format(source.Translate(_("%s [Invalid]")), mask.c_str());
}
ListFormatter::ListEntry entry;
+1 -1
View File
@@ -401,7 +401,7 @@ public:
else
message = _("Your requested vhost has been rejected.");
MemoServ::service->Send(source.service->nick, nick, Language::Translate(source.GetAccount(), message.c_str()), true);
MemoServ::service->Send(source.service->nick, nick, source.Translate(message.c_str()), true);
}
source.Reply(_("VHost for %s has been rejected."), nick.c_str());
+4 -6
View File
@@ -298,12 +298,12 @@ public:
MyHTTPProvider(Module *c, const Anope::string &n, const Anope::string &i, const unsigned short p, const int t, bool s)
: Socket(-1, i.find(':') == Anope::string::npos ? AF_INET : AF_INET6)
, HTTP::Provider(c, n, i, p, s)
, Timer(c, 10, true)
, Timer(c, 10)
, timeout(t)
{
}
void Tick() override
bool Tick() override
{
while (!this->clients.empty())
{
@@ -314,6 +314,7 @@ public:
delete c;
this->clients.pop_front();
}
return true;
}
ClientSocket *OnAccept(int fd, const sockaddrs &addr) override
@@ -371,11 +372,8 @@ public:
const auto &conf = config.GetModule(this);
std::set<Anope::string> existing;
for (int i = 0; i < conf.CountBlock("httpd"); ++i)
for (const auto &[_, block] : conf.GetBlocks("httpd"))
{
const auto &block = conf.GetBlock("httpd", i);
const Anope::string &hname = block.Get<const Anope::string>("name", "httpd/main");
existing.insert(hname);
+3 -3
View File
@@ -92,8 +92,8 @@ public:
if (ii->admin_bind)
{
auto sf = Anope::Template(search_filter, {
{ "account", ii->req->GetAccount() },
{ "object_class", object_class },
{ "account", ii->lprov->EscapeSF(ii->req->GetAccount()) },
{ "object_class", object_class },
});
try
{
@@ -310,7 +310,7 @@ public:
attributes[3].name = this->password_attribute;
attributes[3].values.push_back(pass);
Anope::string new_dn = username_attribute + "=" + na->nick + "," + basedn;
Anope::string new_dn = username_attribute + "=" + this->ldap->EscapeDN(na->nick) + "," + basedn;
this->ldap->Add(&this->orinterface, new_dn, attributes);
}
+2 -2
View File
@@ -125,13 +125,13 @@ public:
if (!this->binddn.empty())
{
auto bdn = Anope::Template(this->binddn, {
{ "account", u->Account()->display },
{ "account", this->ldap->EscapeDN(u->Account()->display) },
});
this->ldap->Bind(NULL, bdn, this->password.c_str());
}
auto af = Anope::Template(this->filter, {
{ "account", u->Account()->display },
{ "account", this->ldap->EscapeSF(u->Account()->display) },
});
this->ldap->Search(new IdentifyInterface(this, u), this->basedn, af);
}
+8 -5
View File
@@ -61,16 +61,17 @@ public:
return na;
}
void Tick() override
bool Tick() override
{
if (!u || !na || !NickServ::service)
return;
return false;
/* If they identified or don't exist anymore, don't kill them. */
if (u->Account() == na->nc || u->timestamp > ts)
return;
return false;
NickServ::service->Collide(u, na);
return false;
}
};
@@ -90,10 +91,11 @@ public:
n->Extend<bool>("HELD");
}
void Tick() override
bool Tick() override
{
if (na)
na->Shrink<bool>("HELD");
return false;
}
};
@@ -133,8 +135,9 @@ public:
NickServReleases.erase(this->nick);
}
void Tick() override
bool Tick() override
{
return false;
}
};
+2 -2
View File
@@ -63,11 +63,11 @@ public:
Anope::string privstr;
if (ci->GetFounder() == nc)
{
privstr = Language::Translate(source.GetAccount(), _("Founder"));
privstr = source.Translate(_("Founder"));
}
else if (ci->GetSuccessor() == nc)
{
privstr += Language::Translate(source.GetAccount(), _("Successor"));
privstr += source.Translate(_("Successor"));
}
AccessGroup access = ci->AccessFor(nc, false);
+7 -3
View File
@@ -184,8 +184,8 @@ public:
FOREACH_MOD(OnNickClearCert, (this->nc));
for (const auto *cert : certs)
{
delete cert;
certmap.erase(cert->fingerprint);
delete cert;
}
this->certs.clear();
}
@@ -207,19 +207,23 @@ public:
if (s->GetSerializableType()->GetName() != NICKCORE_TYPE)
return;
const auto certstr = data.Load("cert");
if (certstr.empty())
return; // Nothing to do.
auto *nc = anope_dynamic_static_cast<NickCore *>(e);
auto *cl = this->Require(nc);
// Delete the old cert list.
for (const auto *cert : cl->certs)
{
delete cert;
certmap.erase(cert->fingerprint);
delete cert;
}
cl->certs.clear();
// Add the new cert list
spacesepstream sep(data.Load("cert"));
spacesepstream sep(certstr);
for (Anope::string buf; sep.GetToken(buf); )
{
auto *cert = new NSCertInfo(e);
+3 -2
View File
@@ -145,8 +145,9 @@ public:
}
NickAlias *target, *na = NickAlias::Find(source.GetNick());
time_t reg_delay = Config->GetModule("nickserv").Get<time_t>("regdelay");
auto maxaliases = Config->GetModule(this->owner).Get<unsigned>("maxaliases");
auto &modconf = Config->GetModule(this->owner);
time_t reg_delay = modconf.Get<time_t>("delay", Config->GetModule("nickserv").Get<time_t>("regdelay", "5m"));
auto maxaliases = modconf.Get<unsigned>("maxaliases");
if (!(target = NickAlias::Find(nick)))
source.Reply(NICK_X_NOT_REGISTERED, nick.c_str());
else if (user && Anope::CurTime < user->lastnickreg + reg_delay)
+1 -1
View File
@@ -91,7 +91,7 @@ public:
InfoFormatter info(source.nc);
info[_("Account")] = Anope::Format(Language::Translate(source.nc, _("%s (ID: %zu)")), na->nc->display.c_str(), na->nc->GetId());
info[_("Account")] = Anope::Format(source.Translate(_("%s (ID: %zu)")), na->nc->display.c_str(), na->nc->GetId());
info[_("Account registered")] = Anope::strftime(na->nc->registered, source.GetAccount());
info[_("Nick registered")] = Anope::strftime(na->registered, source.GetAccount());
+2 -2
View File
@@ -110,9 +110,9 @@ public:
auto &status = entry["Status"];
if (na->nc->HasExt("NS_SUSPENDED"))
status = Language::Translate(source.GetAccount(), _("Suspended"));
status = source.Translate(_("Suspended"));
else if (na->nc->HasExt("UNCONFIRMED"))
status = Language::Translate(source.GetAccount(), _("Unconfirmed"));
status = source.Translate(_("Unconfirmed"));
list.AddEntry(entry);
}
++count;
+17 -7
View File
@@ -66,7 +66,7 @@ public:
}
time_t nickregdelay = Config->GetModule(this->owner).Get<time_t>("nickregdelay");
time_t reg_delay = Config->GetModule("nickserv").Get<time_t>("regdelay");
time_t reg_delay = Config->GetModule("nickserv").Get<time_t>("regdelay", "15m");
if (u && !u->HasMode("OPER") && nickregdelay && Anope::CurTime - u->timestamp < nickregdelay)
{
auto waitperiod = (u->timestamp + nickregdelay) - Anope::CurTime;
@@ -275,18 +275,28 @@ public:
return;
}
auto *passcode = nc->GetExt<Anope::string>("passcode");
if (!passcode)
if (!nc->HasExt("UNCONFIRMED"))
{
source.Reply(_("There is no registration confirmation pending for %s."),
na->nick.c_str());
return;
}
if (!code.empty() && !code.equals_cs(*passcode))
if (!code.empty())
{
source.Reply(_("The registration confirmation code you specified for %s is incorrect."),
na->nick.c_str());
return;
auto *passcode = nc->GetExt<Anope::string>("passcode");
if (passcode && !code.equals_cs(*passcode))
{
source.Reply(_("The registration confirmation code you specified for %s is incorrect."),
na->nick.c_str());
return;
}
else if (!passcode)
{
source.Reply(_("The registration of %s can only be confirmed by an administrator."),
na->nick.c_str());
return;
}
}
nc->Shrink<Anope::string>("passcode");
+3 -2
View File
@@ -29,7 +29,7 @@ public:
SASLService(Module *o)
: SASL::Service(o)
, Timer(o, 60, true)
, Timer(o, 60)
{
}
@@ -221,7 +221,7 @@ public:
this->SendMessage(session, "M", buf.empty() ? "" : buf.substr(1));
}
void Tick() override
bool Tick() override
{
for (auto it = badpasswords.begin(); it != badpasswords.end(); )
{
@@ -240,6 +240,7 @@ public:
sessions.erase(uid);
}
}
return true;
}
};
+23 -10
View File
@@ -26,14 +26,15 @@ struct CommandData final
Anope::string pattern;
Anope::string syntax;
Anope::string title;
time_t priority = 0;
bool swhois = false;
};
static Anope::map<CommandData> command_data;
struct NSMiscData;
static Anope::map<ExtensibleItem<NSMiscData> *> items;
static std::vector<std::pair<time_t, ExtensibleItem<NSMiscData> *>> items_by_priority;
static ExtensibleItem<NSMiscData> *GetItem(const Anope::string &name)
{
@@ -132,7 +133,7 @@ static void CheckSWhois(User* u, const Anope::string &name, ExtensibleItem<NSMis
auto *nc = u->Account();
auto *data = nc ? ext->Get(nc) : nullptr;
if (data)
IRCD->SendSWhois(nickserv, u, name, Anope::Format("%s: %s", GetTitle(ext), data->data.c_str()));
IRCD->SendSWhois(nickserv, u, name, it->second.priority, Anope::Format("%s: %s", GetTitle(ext), data->data.c_str()));
else
IRCD->SendSWhoisDel(nickserv, u, name, "");
}
@@ -253,7 +254,7 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply("%s", Language::Translate(source.nc, desc.c_str()));
source.Reply("%s", source.Translate(desc.c_str()));
return true;
}
@@ -265,7 +266,7 @@ public:
value = it->second.syntax.c_str();
this->ClearSyntax();
this->SetSyntax(Anope::Format("[\037%s\037]", Language::Translate(source.nc, value)));
this->SetSyntax(Anope::Format("[\037%s\037]", source.Translate(value)));
Command::SendSyntax(source);
}
@@ -294,8 +295,8 @@ public:
this->ClearSyntax();
this->SetSyntax(Anope::Format(
Language::Translate(source.nc, _("\037nickname\037 [\037%s\037]")),
Language::Translate(source.nc, value)
source.Translate(_("\037nickname\037 [\037%s\037]")),
source.Translate(value)
));
Command::SendSyntax(source);
@@ -327,9 +328,11 @@ public:
void OnReload(Configuration::Conf &conf) override
{
command_data.clear();
for (int i = 0; i < conf.CountBlock("command"); ++i)
items_by_priority.clear();
time_t default_priority = 0;
for (const auto &[_, block] : conf.GetBlocks("command"))
{
const auto &block = conf.GetBlock("command", i);
const Anope::string &cmd = block.Get<const Anope::string>("command");
if (cmd != "nickserv/set/misc" && cmd != "nickserv/saset/misc")
continue;
@@ -341,7 +344,7 @@ public:
// Force creation of the extension item.
const auto extname = GetAttribute(cname);
GetItem(extname);
auto item = GetItem(extname);
auto &data = command_data[extname];
if (cmd == "nickserv/saset/misc")
@@ -350,12 +353,22 @@ public:
continue;
}
default_priority += 1000;
data.set_description = desc;
data.pattern = block.Get<const Anope::string>("misc_pattern");
data.syntax = block.Get<const Anope::string>("misc_syntax");
data.title = block.Get<const Anope::string>("misc_title");
data.priority = block.Get<time_t>("misc_priority", "0");
if (data.priority <= 0)
{
// If no priority is specified, go by order processed
data.priority = default_priority;
}
data.swhois = block.Get<bool>("misc_swhois");
items_by_priority.emplace_back(data.priority, item);
}
std::sort(items_by_priority.begin(), items_by_priority.end());
}
void OnUserLogin(User *u) override
@@ -374,7 +387,7 @@ public:
void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool) override
{
for (const auto &[_, e] : items)
for (const auto &[_, e] : items_by_priority)
{
NSMiscData *data = e->Get(na->nc);
+3 -4
View File
@@ -61,7 +61,7 @@ public:
for (unsigned i = 0; !show_blocks[i].empty(); ++i)
{
const auto &block = Config->GetBlock(show_blocks[i]);
const Configuration::Block::item_map &items = block.GetItems();
const auto &items = block.GetItems();
ListFormatter lflist(source.GetAccount());
lflist.AddColumn(_("Name")).AddColumn(_("Value"));
@@ -84,10 +84,9 @@ public:
lflist.AddColumn(_("Module Name")).AddColumn(_("Name")).AddColumn(_("Value"));
lflist.SetFlexible(_("\002{}{module_name}}:{name}\002 = {value}"));
for (int i = 0; i < Config->CountBlock("module"); ++i)
for (const auto &[_, block] : Config->GetBlocks("module"))
{
const auto &block = Config->GetBlock("module", i);
const Configuration::Block::item_map &items = block.GetItems();
const auto &items = block.GetItems();
if (items.size() <= 1)
continue;
+2 -1
View File
@@ -125,7 +125,7 @@ public:
timeout = NULL;
}
void Tick() override
bool Tick() override
{
if (DConfig.defaultlevel != level)
{
@@ -146,6 +146,7 @@ public:
runDefCon();
}
return false;
}
};
+5 -5
View File
@@ -253,7 +253,7 @@ class CommandOSDNS final
ListFormatter::ListEntry entry;
entry["Server"] = s->GetName();
entry["Limit"] = s->GetLimit() ? Anope::ToString(s->GetLimit()) : Language::Translate(source.GetAccount(), _("None"));
entry["Limit"] = s->GetLimit() ? Anope::ToString(s->GetLimit()) : source.Translate(_("None"));
Anope::string ip_str;
for (const auto &ip : s->GetIPs())
@@ -264,14 +264,14 @@ class CommandOSDNS final
entry["IP"] = ip_str;
if (s->Active())
entry["State"] = Language::Translate(source.GetAccount(), _("Pooled/Active"));
entry["State"] = source.Translate(_("Pooled/Active"));
else if (s->Pooled())
entry["State"] = Language::Translate(source.GetAccount(), _("Pooled/Not Active"));
entry["State"] = source.Translate(_("Pooled/Not Active"));
else
entry["State"] = Language::Translate(source.GetAccount(), _("Unpooled"));
entry["State"] = source.Translate(_("Unpooled"));
if (!srv)
entry["State"] += Anope::string(" ") + Language::Translate(source.GetAccount(), _("(Split)"));
entry["State"] += Anope::string(" ") + source.Translate(_("(Split)"));
lf.AddEntry(entry);
}
+1 -3
View File
@@ -529,10 +529,8 @@ public:
fileforbids.clear();
const auto &modconf = conf.GetModule(this);
for (auto i = 0; i < modconf.CountBlock("file"); ++i)
for (const auto &[_, fileblock] : modconf.GetBlocks("file"))
{
const auto &fileblock = modconf.GetBlock("file", i);
const auto reasonstr = fileblock.Get<const Anope::string>("reason");
const auto typestr = fileblock.Get<const Anope::string>("type");
+2 -2
View File
@@ -77,7 +77,7 @@ public:
Anope::string GetDesc(CommandSource &source) const override
{
return Anope::Format(Language::Translate(source.GetAccount(), _("Login to %s")), source.service->nick.c_str());
return Anope::Format(source.Translate(_("Login to %s")), source.service->nick.c_str());
}
};
@@ -123,7 +123,7 @@ public:
Anope::string GetDesc(CommandSource &source) const override
{
return Anope::Format(Language::Translate(source.GetAccount(), _("Logout from %s")), source.service->nick.c_str());
return Anope::Format(source.Translate(_("Logout from %s")), source.service->nick.c_str());
}
};
+1 -1
View File
@@ -247,7 +247,7 @@ public:
Anope::string GetDesc(CommandSource &source) const override
{
return Anope::Format(Language::Translate(source.GetAccount(), _("Manipulate the %s list")), source.command.nobreak().c_str());
return Anope::Format(source.Translate(_("Manipulate the %s list")), source.command.nobreak().c_str());
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
+19 -2
View File
@@ -587,7 +587,7 @@ public:
Uplink::Send(source, "SVSPART", u->GetUID(), chan);
}
void SendSWhois(const MessageSource &source, User *target, const Anope::string &tag, const Anope::string &message) override
void SendSWhois(const MessageSource &source, User *target, const Anope::string &tag, time_t priority, const Anope::string &message) override
{
if (!IRCD->CanSendMultipleSWhois)
{
@@ -598,7 +598,7 @@ public:
{
// New style SWHOIS.
Uplink::Send("METADATA", target->GetUID(), "specialwhois", Anope::Format("+ @%s s %ld :%s",
tag.c_str(), Anope::CurTime, message.c_str()));
tag.c_str(), priority ? priority : Anope::CurTime, message.c_str()));
}
}
@@ -1709,6 +1709,21 @@ struct IRCDMessageFIdent final
}
};
struct IRCDMessageFName final
: IRCDMessage
{
IRCDMessageFName(Module *creator)
: IRCDMessage(creator, "FNAME", 1)
{
SetFlag(FLAG_REQUIRE_USER);
}
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override
{
source.GetUser()->SetRealname(params[0]);
}
};
struct IRCDMessageKick final
: IRCDMessage
{
@@ -2466,6 +2481,7 @@ class ProtoInspIRCd final
IRCDMessageEndburst message_endburst;
IRCDMessageFHost message_fhost;
IRCDMessageFIdent message_fident;
IRCDMessageFName message_fname;
IRCDMessageFJoin message_fjoin;
IRCDMessageFMode message_fmode;
IRCDMessageFTopic message_ftopic;
@@ -2517,6 +2533,7 @@ public:
, message_endburst(this)
, message_fhost(this)
, message_fident(this)
, message_fname(this)
, message_fjoin(this)
, message_fmode(this)
, message_ftopic(this)
+2 -2
View File
@@ -346,10 +346,10 @@ private:
Uplink::Send("SENDUMODE", 'o', "From " + source.GetName() + ": " + buf);
}
void SendSWhois(const MessageSource &source, User *target, const Anope::string &tag, const Anope::string &message) override
void SendSWhois(const MessageSource &source, User *target, const Anope::string &tag, time_t priority, const Anope::string &message) override
{
const auto utag = tag.empty() ? source.GetName() : tag;
Uplink::Send(source, "SWHOIS", target->GetUID(), "+", utag, 0, message);
Uplink::Send(source, "SWHOIS", target->GetUID(), "+", utag, priority, message);
}
void SendSWhoisDel(const MessageSource &source, User *target, const Anope::string &tag, const Anope::string &message) override
+5 -4
View File
@@ -218,11 +218,11 @@ class ModuleProxyScan final
{
public:
ConnectionTimeout(Module *c, time_t timeout)
: Timer(c, timeout, true)
: Timer(c, timeout)
{
}
void Tick() override
bool Tick() override
{
for (auto it = ProxyConnect::proxies.begin(), it_end = ProxyConnect::proxies.end(); it != it_end;)
{
@@ -232,6 +232,7 @@ class ModuleProxyScan final
if (p->created + this->GetSecs() < Anope::CurTime)
delete p;
}
return true;
}
} connectionTimeout;
@@ -308,9 +309,9 @@ public:
}
this->proxyscans.clear();
for (int i = 0; i < config.CountBlock("proxyscan"); ++i)
for (const auto &[_, block] : config.GetBlocks("proxyscan"))
{
const auto &block = config.GetBlock("proxyscan", i);
ProxyCheck p;
Anope::string token;
-615
View File
@@ -1,615 +0,0 @@
// Anope IRC Services <https://www.anope.org/>
//
// Copyright (C) 2003-2026 Anope Contributors
//
// Anope is free software. You can use, modify, and/or distribute it under the
// terms of version 2 of the GNU General Public License. See docs/LICENSE.txt
// for the complete terms of this license and docs/AUTHORS.txt for a list of
// contributors.
//
// Based on the original code of Epona by Lara
// Based on the original code of Services by Andy Church
//
// SPDX-License-Identifier: GPL-2.0-only
#include "module.h"
#include "modules/redis.h"
using namespace Redis;
class MyRedisService;
class RedisSocket final
: public BinarySocket
, public ConnectionSocket
{
size_t ParseReply(Reply &r, const char *buf, size_t l);
public:
MyRedisService *provider;
std::deque<Interface *> interfaces;
std::map<Anope::string, Interface *> subinterfaces;
RedisSocket(MyRedisService *pro, bool v6) : Socket(-1, v6 ? AF_INET6 : AF_INET), provider(pro) { }
~RedisSocket() override;
void OnConnect() override;
void OnError(const Anope::string &error) override;
bool Read(const char *buffer, size_t l) override;
};
class Transaction final
: public Interface
{
public:
std::deque<Interface *> interfaces;
Transaction(Module *creator) : Interface(creator) { }
~Transaction() override
{
for (auto *iface : interfaces)
{
if (!iface)
continue;
iface->OnError("Interface going away");
}
}
void OnResult(const Reply &r) override
{
/* This is a multi bulk reply of the results of the queued commands
* in this transaction
*/
Log(LOG_DEBUG_2) << "redis: transaction complete with " << r.multi_bulk.size() << " results";
for (auto *result : r.multi_bulk)
{
if (interfaces.empty())
break;
Interface *inter = interfaces.front();
interfaces.pop_front();
if (inter)
inter->OnResult(*result);
}
}
};
class MyRedisService final
: public Provider
{
public:
Anope::string host;
int port;
unsigned db;
RedisSocket *sock = nullptr, *sub = nullptr;
Transaction ti;
bool in_transaction = false;
MyRedisService(Module *c, const Anope::string &n, const Anope::string &h, int p, unsigned d) : Provider(c, n), host(h), port(p), db(d), ti(c)
{
sock = new RedisSocket(this, host.find(':') != Anope::string::npos);
sock->Connect(host, port);
sub = new RedisSocket(this, host.find(':') != Anope::string::npos);
sub->Connect(host, port);
}
~MyRedisService() override
{
if (sock)
{
sock->flags[SF_DEAD] = true;
sock->provider = NULL;
}
if (sub)
{
sub->flags[SF_DEAD] = true;
sub->provider = NULL;
}
}
private:
static inline void Pack(std::vector<char> &buffer, const char *buf, size_t sz = 0)
{
if (!sz)
sz = strlen(buf);
size_t old_size = buffer.size();
buffer.resize(old_size + sz);
std::copy(buf, buf + sz, buffer.begin() + old_size);
}
void Send(RedisSocket *s, Interface *i, const std::vector<std::pair<const char *, size_t> > &args)
{
std::vector<char> buffer;
Pack(buffer, "*");
Pack(buffer, Anope::ToString(args.size()).c_str());
Pack(buffer, "\r\n");
for (const auto &[key, value] : args)
{
Pack(buffer, "$");
Pack(buffer, Anope::ToString(value).c_str());
Pack(buffer, "\r\n");
Pack(buffer, key, value);
Pack(buffer, "\r\n");
}
if (buffer.empty())
return;
s->Write(&buffer[0], buffer.size());
if (in_transaction)
{
ti.interfaces.push_back(i);
s->interfaces.push_back(NULL); // For the +Queued response
}
else
s->interfaces.push_back(i);
}
public:
bool IsSocketDead() override
{
return this->sock && this->sock->flags[SF_DEAD];
}
void SendCommand(RedisSocket *s, Interface *i, const std::vector<Anope::string> &cmds)
{
std::vector<std::pair<const char *, size_t> > args;
for (const auto &cmd : cmds)
args.emplace_back(cmd.c_str(), cmd.length());
this->Send(s, i, args);
}
void SendCommand(RedisSocket *s, Interface *i, const Anope::string &str)
{
std::vector<Anope::string> args;
spacesepstream(str).GetTokens(args);
this->SendCommand(s, i, args);
}
void Send(Interface *i, const std::vector<std::pair<const char *, size_t> > &args)
{
if (!sock)
{
sock = new RedisSocket(this, host.find(':') != Anope::string::npos);
sock->Connect(host, port);
}
this->Send(sock, i, args);
}
void SendCommand(Interface *i, const std::vector<Anope::string> &cmds) override
{
std::vector<std::pair<const char *, size_t> > args;
for (const auto &cmd : cmds)
args.emplace_back(cmd.c_str(), cmd.length());
this->Send(i, args);
}
void SendCommand(Interface *i, const Anope::string &str) override
{
std::vector<Anope::string> args;
spacesepstream(str).GetTokens(args);
this->SendCommand(i, args);
}
public:
bool BlockAndProcess() override
{
if (!this->sock->ProcessWrite())
this->sock->flags[SF_DEAD] = true;
this->sock->SetBlocking(true);
if (!this->sock->ProcessRead())
this->sock->flags[SF_DEAD] = true;
this->sock->SetBlocking(false);
return !this->sock->interfaces.empty();
}
void Subscribe(Interface *i, const Anope::string &pattern) override
{
if (sub == NULL)
{
sub = new RedisSocket(this, host.find(':') != Anope::string::npos);
sub->Connect(host, port);
}
std::vector<Anope::string> args;
args.emplace_back("PSUBSCRIBE");
args.push_back(pattern);
this->SendCommand(sub, NULL, args);
sub->subinterfaces[pattern] = i;
}
void Unsubscribe(const Anope::string &pattern) override
{
if (sub)
sub->subinterfaces.erase(pattern);
}
void StartTransaction() override
{
if (in_transaction)
throw ModuleException("Tried to start a transaction while one was already in progress");
this->SendCommand(NULL, "MULTI");
in_transaction = true;
}
void CommitTransaction() override
{
/* The result of the transaction comes back to the reply of EXEC as a multi bulk.
* The reply to the individual commands that make up the transaction when executed
* is a simple +QUEUED
*/
in_transaction = false;
this->SendCommand(&this->ti, "EXEC");
}
};
RedisSocket::~RedisSocket()
{
if (provider)
{
if (provider->sock == this)
provider->sock = NULL;
else if (provider->sub == this)
provider->sub = NULL;
}
for (auto *iface : interfaces)
{
if (!iface)
continue;
iface->OnError("Interface going away");
}
}
void RedisSocket::OnConnect()
{
Log() << "redis: Successfully connected to " << provider->name << (this == this->provider->sub ? " (sub)" : "");
this->provider->SendCommand(NULL, "CLIENT SETNAME Anope");
this->provider->SendCommand(NULL, "SELECT " + Anope::ToString(provider->db));
if (this != this->provider->sub)
{
this->provider->SendCommand(this, NULL, "CONFIG SET notify-keyspace-events KA");
}
}
void RedisSocket::OnError(const Anope::string &error)
{
Log() << "redis: Error on " << provider->name << (this == this->provider->sub ? " (sub)" : "") << ": " << error;
}
size_t RedisSocket::ParseReply(Reply &r, const char *buffer, size_t l)
{
size_t used = 0;
if (!l)
return used;
if (r.type == Reply::MULTI_BULK)
goto multi_bulk_cont;
switch (*buffer)
{
case '+':
{
Anope::string reason(buffer, 1, l - 1);
size_t nl = reason.find("\r\n");
Log(LOG_DEBUG_2) << "redis: status ok: " << reason.substr(0, nl);
if (nl != Anope::string::npos)
{
r.type = Reply::OK;
used = 1 + nl + 2;
}
break;
}
case '-':
{
Anope::string reason(buffer, 1, l - 1);
size_t nl = reason.find("\r\n");
Log(LOG_DEBUG) << "redis: status error: " << reason.substr(0, nl);
if (nl != Anope::string::npos)
{
r.type = Reply::NOT_OK;
used = 1 + nl + 2;
}
break;
}
case ':':
{
Anope::string ibuf(buffer, 1, l - 1);
size_t nl = ibuf.find("\r\n");
if (nl != Anope::string::npos)
{
if (auto i = Anope::TryConvert<int64_t>(ibuf.substr(0, nl)))
r.i = i.value();
r.type = Reply::INT;
used = 1 + nl + 2;
}
break;
}
case '$':
{
Anope::string reply(buffer + 1, l - 1);
/* This assumes one bulk can always fit in our recv buffer */
size_t nl = reply.find("\r\n");
if (nl != Anope::string::npos)
{
if (auto l = Anope::TryConvert<int>(reply.substr(0, nl)))
{
int len = l.value();
if (len >= 0)
{
if (1 + nl + 2 + len + 2 <= l)
{
used = 1 + nl + 2 + len + 2;
r.bulk = reply.substr(nl + 2, len);
r.type = Reply::BULK;
}
}
else
{
used = 1 + nl + 2 + 2;
r.type = Reply::BULK;
}
}
}
break;
}
multi_bulk_cont:
case '*':
{
if (r.type != Reply::MULTI_BULK)
{
Anope::string reply(buffer + 1, l - 1);
size_t nl = reply.find("\r\n");
if (nl != Anope::string::npos)
{
r.type = Reply::MULTI_BULK;
if (auto size = Anope::TryConvert<int>(reply.substr(0, nl)))
r.multi_bulk_size = size.value();
used = 1 + nl + 2;
}
else
break;
}
else if (r.multi_bulk_size >= 0 && r.multi_bulk.size() == static_cast<unsigned>(r.multi_bulk_size))
{
/* This multi bulk is already complete, so check the sub bulks */
for (auto &bulk : r.multi_bulk)
if (bulk->type == Reply::MULTI_BULK)
ParseReply(*bulk, buffer + used, l - used);
break;
}
for (int i = r.multi_bulk.size(); i < r.multi_bulk_size; ++i)
{
auto *reply = new Reply();
size_t u = ParseReply(*reply, buffer + used, l - used);
if (!u)
{
Log(LOG_DEBUG) << "redis: ran out of data to parse";
delete reply;
break;
}
r.multi_bulk.push_back(reply);
used += u;
}
break;
}
default:
Log(LOG_DEBUG) << "redis: unknown reply " << *buffer;
}
return used;
}
bool RedisSocket::Read(const char *buffer, size_t l)
{
static std::vector<char> save;
std::vector<char> copy;
if (!save.empty())
{
std::copy(buffer, buffer + l, std::back_inserter(save));
copy = save;
buffer = &copy[0];
l = copy.size();
}
while (l)
{
static Reply r;
size_t used = this->ParseReply(r, buffer, l);
if (!used)
{
Log(LOG_DEBUG) << "redis: used == 0 ?";
r.Clear();
break;
}
else if (used > l)
{
Log(LOG_DEBUG) << "redis: used > l ?";
r.Clear();
break;
}
/* Full result is not here yet */
if (r.type == Reply::MULTI_BULK && static_cast<unsigned>(r.multi_bulk_size) != r.multi_bulk.size())
{
buffer += used;
l -= used;
break;
}
if (this == provider->sub)
{
if (r.multi_bulk.size() == 4)
{
/* pmessage
* pattern subscribed to
* __keyevent@0__:set
* key
*/
auto it = this->subinterfaces.find(r.multi_bulk[1]->bulk);
if (it != this->subinterfaces.end())
it->second->OnResult(r);
}
}
else
{
if (this->interfaces.empty())
{
Log(LOG_DEBUG) << "redis: no interfaces?";
}
else
{
Interface *i = this->interfaces.front();
this->interfaces.pop_front();
if (i)
{
if (r.type != Reply::NOT_OK)
i->OnResult(r);
else
i->OnError(r.bulk);
}
}
}
buffer += used;
l -= used;
r.Clear();
}
if (l)
{
save.resize(l);
std::copy(buffer, buffer + l, save.begin());
}
else
std::vector<char>().swap(save);
return true;
}
class ModuleRedis final
: public Module
{
std::map<Anope::string, MyRedisService *> services;
public:
ModuleRedis(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR)
{
}
~ModuleRedis() override
{
for (auto &[_, p] : services)
{
delete p->sock;
p->sock = NULL;
delete p->sub;
p->sub = NULL;
delete p;
}
}
void OnReload(Configuration::Conf &conf) override
{
const auto &block = conf.GetModule(this);
std::vector<Anope::string> new_services;
for (int i = 0; i < block.CountBlock("redis"); ++i)
{
const auto &redis = block.GetBlock("redis", i);
const Anope::string &n = redis.Get<const Anope::string>("name"),
&ip = redis.Get<const Anope::string>("ip");
int port = redis.Get<int>("port");
auto db = redis.Get<unsigned>("db");
delete services[n];
services[n] = new MyRedisService(this, n, ip, port, db);
new_services.push_back(n);
}
for (auto it = services.begin(); it != services.end();)
{
Provider *p = it->second;
++it;
if (std::find(new_services.begin(), new_services.end(), p->name) == new_services.end())
delete it->second;
}
}
void OnModuleUnload(User *, Module *m) override
{
for (auto &[_, p] : services)
{
if (p->sock)
for (unsigned i = p->sock->interfaces.size(); i > 0; --i)
{
Interface *inter = p->sock->interfaces[i - 1];
if (inter && inter->owner == m)
{
inter->OnError(m->name + " being unloaded");
p->sock->interfaces.erase(p->sock->interfaces.begin() + i - 1);
}
}
if (p->sub)
for (unsigned i = p->sub->interfaces.size(); i > 0; --i)
{
Interface *inter = p->sub->interfaces[i - 1];
if (inter && inter->owner == m)
{
inter->OnError(m->name + " being unloaded");
p->sub->interfaces.erase(p->sub->interfaces.begin() + i - 1);
}
}
for (unsigned i = p->ti.interfaces.size(); i > 0; --i)
{
Interface *inter = p->ti.interfaces[i - 1];
if (inter && inter->owner == m)
{
inter->OnError(m->name + " being unloaded");
p->ti.interfaces.erase(p->ti.interfaces.begin() + i - 1);
}
}
}
}
};
MODULE_INIT(ModuleRedis)
+1 -3
View File
@@ -173,10 +173,8 @@ public:
{
Rewrite::rewrites.clear();
for (int i = 0; i < conf.CountBlock("command"); ++i)
for (const auto &[_, block] : conf.GetBlocks("command"))
{
const auto &block = conf.GetBlock("command", i);
if (!block.Get<bool>("rewrite"))
continue;
+2 -3
View File
@@ -313,10 +313,9 @@ public:
throw ConfigException("Unable to find http reference, is httpd loaded?");
jsonrpcinterface.tokens.clear();
for (int i = 0; i < modconf.CountBlock("token"); ++i)
{
const auto &block = modconf.GetBlock("token", i);
for (const auto &[_, block] : modconf.GetBlocks("token"))
{
RPC::Token token;
token.token = block.Get<const Anope::string>("token");
if (!token.token.empty())
+21
View File
@@ -94,6 +94,27 @@ const std::list<AccessProvider *>& AccessProvider::GetProviders()
return Providers;
}
void AccessProvider::SendAccess(CommandSource &source, const Anope::string& pname)
{
auto *p = PrivilegeManager::FindPrivilege(pname);
if (!p)
return; // Privilege missing.
Anope::map<Anope::string> access;
for (auto *service : Service::GetServices("AccessProvider"))
{
auto *accessprovider = static_cast<AccessProvider *>(service);
accessprovider->GetAccess(source, p, access);
}
if (access.empty())
return; // No access systems???
source.Reply(_("By default, the \002%s\002 command is limited to:"), source.command.c_str());
for (const auto& [system, privilege] : access)
source.Reply(" \002%s\002: %s", source.Translate(system), privilege.c_str());
}
ChanAccess::ChanAccess(AccessProvider *p)
: Serializable(CHANACCESS_TYPE)
, provider(p)
+26 -8
View File
@@ -112,7 +112,7 @@ bool CommandSource::IsOper()
void CommandSource::Reply(const char *message, ...)
{
const char *translated_message = Language::Translate(this->nc, message);
const char *translated_message = Translate(message);
Anope::string buf;
ANOPE_FORMAT(message, translated_message, buf);
@@ -121,7 +121,7 @@ void CommandSource::Reply(const char *message, ...)
void CommandSource::Reply(int count, const char *single, const char *plural, ...)
{
const char *translated_message = Language::Translate(this->nc, count, single, plural);
const char *translated_message = Translate(count, single, plural);
Anope::string buf;
ANOPE_FORMAT(plural, translated_message, buf);
@@ -130,10 +130,30 @@ void CommandSource::Reply(int count, const char *single, const char *plural, ...
void CommandSource::Reply(const Anope::string &message)
{
const char *translated_message = Language::Translate(this->nc, message.c_str());
const char *translated_message = Translate(message.c_str());
this->reply->SendMessage(*this, translated_message);
}
const char *CommandSource::Translate(const char *message)
{
return Language::Translate(GetAccount(), message);
}
const char *CommandSource::Translate(const Anope::string &message)
{
return Language::Translate(GetAccount(), message.c_str());
}
const char *CommandSource::Translate(int count, const Anope::string &single, const Anope::string &plural)
{
return Language::Translate(GetAccount(), count, single.c_str(), plural.c_str());
}
const char *CommandSource::Translate(int count, const char *single, const char *plural)
{
return Language::Translate(GetAccount(), count, single, plural);
}
Command::Command(Module *o, const Anope::string &sname, size_t minparams, size_t maxparams) : Service(o, "Command", sname), max_params(maxparams), min_params(minparams), module(o)
{
}
@@ -160,7 +180,7 @@ void Command::SendSyntax(CommandSource &source)
const auto *monospace = !flexible && sourcenc && sourcenc->HasExt("NS_MONOSPACE") ? "\021" : "";
auto first = true;
Anope::string prefix = Language::Translate(source.GetAccount(), _("Syntax"));
Anope::string prefix = source.Translate(_("Syntax"));
Anope::string padding(prefix.utf8length(), ' ');
for (const auto &[syntax, predicate] : this->syntax)
{
@@ -171,14 +191,12 @@ void Command::SendSyntax(CommandSource &source)
{
first = false;
source.Reply("%s%s: \002%s %s\002", monospace, prefix.c_str(),
source.command.nobreak().c_str(),
Language::Translate(source.GetAccount(), syntax.c_str()));
source.command.nobreak().c_str(), source.Translate(syntax));
}
else
{
source.Reply("%s%s \002%s %s\002", monospace, padding.c_str(),
source.command.nobreak().c_str(),
Language::Translate(source.GetAccount(), syntax.c_str()));
source.command.nobreak().c_str(), source.Translate(syntax));
}
}
+74 -91
View File
@@ -23,62 +23,67 @@
#include <stack>
#include <stdexcept>
using Configuration::File;
using Configuration::Conf;
using Configuration::Block;
using Configuration::Uplink;
Configuration::File ServicesConf("anope.conf", false); // Configuration file name
File ServicesConf("anope.conf", false); // Configuration file name
Conf *Config = NULL;
Configuration::Conf *Config = NULL;
Block Block::EmptyBlock("");
Configuration::Block Configuration::Block::EmptyBlock("");
Block::Block(const Anope::string &n) : name(n), linenum(-1)
Configuration::Block::Block(const Anope::string &n) : name(n), linenum(-1)
{
}
const Anope::string &Block::GetName() const
const Anope::string &Configuration::Block::GetName() const
{
return name;
}
int Block::CountBlock(const Anope::string &bname) const
size_t Configuration::Block::CountBlock(const Anope::string &bname) const
{
return blocks.count(bname);
}
const Block &Block::GetBlock(const Anope::string &bname, int num) const
Configuration::Block::BlockList Configuration::Block::GetBlocks(const Anope::string &bname) const
{
std::pair<block_map::const_iterator, block_map::const_iterator> it = blocks.equal_range(bname);
return Anope::equal_range(blocks, bname);
}
for (int i = 0; it.first != it.second; ++it.first, ++i)
const Configuration::Block &Configuration::Block::GetBlock(const Anope::string &bname, size_t num) const
{
auto it = blocks.equal_range(bname);
for (size_t i = 0; it.first != it.second; ++it.first, ++i)
{
if (i == num)
return it.first->second;
}
return EmptyBlock;
}
Block *Block::GetMutableBlock(const Anope::string &bname, int num)
Configuration::Block *Configuration::Block::GetMutableBlock(const Anope::string &bname, size_t num)
{
std::pair<block_map::iterator, block_map::iterator> it = blocks.equal_range(bname);
auto it = blocks.equal_range(bname);
for (int i = 0; it.first != it.second; ++it.first, ++i)
for (size_t i = 0; it.first != it.second; ++it.first, ++i)
{
if (i == num)
return &it.first->second;
}
return NULL;
}
bool Block::Set(const Anope::string &tag, const Anope::string &value)
bool Configuration::Block::Set(const Anope::string &tag, const Anope::string &value)
{
items[tag] = value;
return true;
}
const Block::item_map &Block::GetItems() const
const Configuration::Block::ItemMap &Configuration::Block::GetItems() const
{
return items;
}
template<> const Anope::string Block::Get(const Anope::string &tag, const Anope::string &def) const
template<> const Anope::string Configuration::Block::Get(const Anope::string &tag, const Anope::string &def) const
{
auto it = items.find(tag);
if (it != items.end())
@@ -87,12 +92,12 @@ template<> const Anope::string Block::Get(const Anope::string &tag, const Anope:
return def;
}
template<> time_t Block::Get(const Anope::string &tag, const Anope::string &def) const
template<> time_t Configuration::Block::Get(const Anope::string &tag, const Anope::string &def) const
{
return Anope::DoTime(Get<const Anope::string>(tag, def));
}
template<> bool Block::Get(const Anope::string &tag, const Anope::string &def) const
template<> bool Configuration::Block::Get(const Anope::string &tag, const Anope::string &def) const
{
const Anope::string &str = Get<const Anope::string>(tag, def);
return !str.empty() && !str.equals_ci("no") && !str.equals_ci("off") && !str.equals_ci("false") && !str.equals_ci("0");
@@ -122,21 +127,19 @@ template<typename T> static void ValidateNotZero(const Anope::string &block, con
throw ConfigException("The value for <" + block + ":" + name + "> cannot be zero!");
}
Conf::Conf() : Block("")
Configuration::Conf::Conf() : Configuration::Block("")
{
ReadTimeout = 0;
DefPrivmsg = false;
this->LoadConf(ServicesConf);
for (int i = 0; i < this->CountBlock("include"); ++i)
for (const auto &[_, include] : this->GetBlocks("include"))
{
const Block &include = this->GetBlock("include", i);
const Anope::string &type = include.Get<const Anope::string>("type"),
&file = include.Get<const Anope::string>("name");
File f(file, type == "executable");
Configuration::File f(file, type == "executable");
this->LoadConf(f);
}
@@ -168,7 +171,7 @@ Conf::Conf() : Block("")
}
}
const Block &serverinfo = this->GetBlock("serverinfo"), &options = this->GetBlock("options"),
const auto &serverinfo = this->GetBlock("serverinfo"), &options = this->GetBlock("options"),
&mail = this->GetBlock("mail"), &networkinfo = this->GetBlock("networkinfo");
const Anope::string &servername = serverinfo.Get<Anope::string>("name");
@@ -209,10 +212,8 @@ Conf::Conf() : Block("")
this->TimeoutCheck = options.Get<time_t>("timeoutcheck");
this->NickChars = networkinfo.Get<Anope::string>("nick_chars");
for (int i = 0; i < this->CountBlock("uplink"); ++i)
for (const auto &[_, uplink] : this->GetBlocks("uplink"))
{
const Block &uplink = this->GetBlock("uplink", i);
int protocol;
const Anope::string &protocolstr = uplink.Get<const Anope::string>("protocol", "ipv4");
if (protocolstr == "ipv4")
@@ -242,10 +243,8 @@ Conf::Conf() : Block("")
this->Uplinks.emplace_back(host, port, password, protocol);
}
for (int i = 0; i < this->CountBlock("module"); ++i)
for (const auto &[_, module] : this->GetBlocks("module"))
{
const Block &module = this->GetBlock("module", i);
const Anope::string &modname = module.Get<const Anope::string>("name");
ValidateNotEmptyOrSpaces("module", "name", modname);
@@ -253,10 +252,8 @@ Conf::Conf() : Block("")
this->ModulesAutoLoad.push_back(modname);
}
for (int i = 0; i < this->CountBlock("opertype"); ++i)
for (const auto &[_, opertype] : this->GetBlocks("opertype"))
{
const Block &opertype = this->GetBlock("opertype", i);
const Anope::string &oname = opertype.Get<const Anope::string>("name"),
&modes = opertype.Get<const Anope::string>("modes"),
&inherits = opertype.Get<const Anope::string>("inherits"),
@@ -296,10 +293,8 @@ Conf::Conf() : Block("")
this->MyOperTypes.push_back(ot);
}
for (int i = 0; i < this->CountBlock("oper"); ++i)
for (const auto &[_, oper] : this->GetBlocks("oper"))
{
const Block &oper = this->GetBlock("oper", i);
const Anope::string &nname = oper.Get<const Anope::string>("name"),
&type = oper.Get<const Anope::string>("type"),
&password = oper.Get<const Anope::string>("password"),
@@ -334,10 +329,9 @@ Conf::Conf() : Block("")
for (const auto &[_, bi] : *BotListByNick)
bi->conf = false;
for (int i = 0; i < this->CountBlock("service"); ++i)
{
const Block &service = this->GetBlock("service", i);
for (const auto &[_, service] : this->GetBlocks("service"))
{
const Anope::string &nick = service.Get<const Anope::string>("nick"),
&user = service.Get<const Anope::string>("user", nick.lower()),
&host = service.Get<const Anope::string>("host", servername),
@@ -425,10 +419,8 @@ Conf::Conf() : Block("")
}
}
for (int i = 0; i < this->CountBlock("log"); ++i)
for (const auto &[_, log] : this->GetBlocks("log"))
{
const Block &log = this->GetBlock("log", i);
int logage = log.Get<int>("logage");
bool rawio = log.Get<bool>("rawio");
bool debug = log.Get<bool>("debug");
@@ -451,10 +443,8 @@ Conf::Conf() : Block("")
for (const auto &[_, bi] : *BotListByNick)
bi->commands.clear();
for (int i = 0; i < this->CountBlock("command"); ++i)
for (const auto &[_, command] : this->GetBlocks("command"))
{
const Block &command = this->GetBlock("command", i);
const Anope::string &service = command.Get<const Anope::string>("service"),
&nname = command.Get<const Anope::string>("name"),
&cmd = command.Get<const Anope::string>("command"),
@@ -476,10 +466,8 @@ Conf::Conf() : Block("")
}
PrivilegeManager::ClearPrivileges();
for (int i = 0; i < this->CountBlock("privilege"); ++i)
for (const auto &[_, privilege] : this->GetBlocks("privilege"))
{
const Block &privilege = this->GetBlock("privilege", i);
const Anope::string &nname = privilege.Get<const Anope::string>("name"),
&desc = privilege.Get<const Anope::string>("desc");
int rank = privilege.Get<int>("rank");
@@ -487,10 +475,8 @@ Conf::Conf() : Block("")
PrivilegeManager::AddPrivilege(Privilege(nname, desc, rank));
}
for (int i = 0; i < this->CountBlock("fantasy"); ++i)
for (const auto &[_, fantasy] : this->GetBlocks("fantasy"))
{
const Block &fantasy = this->GetBlock("fantasy", i);
const Anope::string &nname = fantasy.Get<const Anope::string>("name"),
&service = fantasy.Get<const Anope::string>("command"),
&permission = fantasy.Get<const Anope::string>("permission"),
@@ -508,10 +494,8 @@ Conf::Conf() : Block("")
c.require_privilege = fantasy.Get<bool>("require_privilege", "yes");
}
for (int i = 0; i < this->CountBlock("command_group"); ++i)
for (const auto &[_, command_group] : this->GetBlocks("command_group"))
{
const Block &command_group = this->GetBlock("command_group", i);
const Anope::string &nname = command_group.Get<const Anope::string>("name"),
&description = command_group.Get<const Anope::string>("description");
@@ -567,7 +551,7 @@ Conf::Conf() : Block("")
Anope::CaseMapRebuild();
}
Conf::~Conf()
Configuration::Conf::~Conf()
{
for (const auto *opertype : MyOperTypes)
delete opertype;
@@ -576,7 +560,7 @@ Conf::~Conf()
delete oper;
}
void Conf::Post(Conf *old)
void Configuration::Conf::Post(Configuration::Conf *old)
{
/* Apply module changes */
for (const auto &mod : old->ModulesAutoLoad)
@@ -625,7 +609,7 @@ void Conf::Post(Conf *old)
}
}
Anope::string Uplink::str() const
Anope::string Configuration::Uplink::str() const
{
switch (protocol)
{
@@ -642,26 +626,26 @@ Anope::string Uplink::str() const
}
Block &Conf::GetModule(const Module *m)
Configuration::Block &Configuration::Conf::GetModule(const Module *m)
{
if (!m)
return Block::EmptyBlock;
return Configuration::Block::EmptyBlock;
return GetModule(m->name);
}
Block &Conf::GetModule(const Anope::string &mname)
Configuration::Block &Configuration::Conf::GetModule(const Anope::string &mname)
{
auto it = modules.find(mname);
if (it != modules.end())
return *it->second;
Block *&block = modules[mname];
auto *&block = modules[mname];
/* Search for the block */
for (std::pair<block_map::iterator, block_map::iterator> iters = blocks.equal_range("module"); iters.first != iters.second; ++iters.first)
for (auto iters = blocks.equal_range("module"); iters.first != iters.second; ++iters.first)
{
Block &b = iters.first->second;
auto &b = iters.first->second;
if (b.Get<const Anope::string>("name") == mname)
{
@@ -671,70 +655,70 @@ Block &Conf::GetModule(const Anope::string &mname)
}
if (!block)
block = &Block::EmptyBlock;
block = &Configuration::Block::EmptyBlock;
return GetModule(mname);
}
BotInfo *Conf::GetClient(const Anope::string &cname)
BotInfo *Configuration::Conf::GetClient(const Anope::string &cname)
{
auto it = bots.find(cname);
if (it != bots.end())
return BotInfo::Find(!it->second.empty() ? it->second : cname, true);
Block &block = GetModule(cname.lower());
auto &block = GetModule(cname.lower());
const Anope::string &client = block.Get<const Anope::string>("client");
bots[cname] = client;
return GetClient(cname);
}
const Block &Conf::GetCommand(CommandSource &source)
const Configuration::Block &Configuration::Conf::GetCommand(CommandSource &source)
{
const Anope::string &block_name = source.c ? "fantasy" : "command";
for (std::pair<block_map::iterator, block_map::iterator> iters = blocks.equal_range(block_name); iters.first != iters.second; ++iters.first)
for (auto iters = blocks.equal_range(block_name); iters.first != iters.second; ++iters.first)
{
Block &b = iters.first->second;
auto &b = iters.first->second;
if (b.Get<Anope::string>("name") == source.command)
return b;
}
return Block::EmptyBlock;
return Configuration::Block::EmptyBlock;
}
File::File(const Anope::string &n, bool e) : name(n), executable(e)
Configuration::File::File(const Anope::string &n, bool e) : name(n), executable(e)
{
}
File::~File()
Configuration::File::~File()
{
this->Close();
}
const Anope::string &File::GetName() const
const Anope::string &Configuration::File::GetName() const
{
return this->name;
}
Anope::string File::GetPath() const
Anope::string Configuration::File::GetPath() const
{
return this->executable ? this->name : Anope::ExpandConfig(this->name);
}
bool File::IsOpen() const
bool Configuration::File::IsOpen() const
{
return this->fp != NULL;
}
bool File::Open()
bool Configuration::File::Open()
{
this->Close();
this->fp = (this->executable ? popen(GetPath().c_str(), "r") : fopen(GetPath().c_str(), "r"));
return this->fp != NULL;
}
void File::Close()
void Configuration::File::Close()
{
if (this->fp != NULL)
{
@@ -746,12 +730,12 @@ void File::Close()
}
}
bool File::End() const
bool Configuration::File::End() const
{
return !this->IsOpen() || feof(this->fp);
}
Anope::string File::Read()
Anope::string Configuration::File::Read()
{
Anope::string ret;
char buf[1024];
@@ -773,20 +757,20 @@ Anope::string File::Read()
return ret;
}
void Conf::LoadConf(File &file)
void Configuration::Conf::LoadConf(Configuration::File &file)
{
if (file.GetName().empty())
return;
if (!file.Open())
{
throw ConfigException(Anope::Format("File %s could not be opened: %s.",
throw ConfigException(Anope::Format("Configuration::File %s could not be opened: %s.",
file.GetPath().c_str(), strerror(errno)));
}
Anope::string itemname, wordbuffer;
std::stack<Block *> block_stack;
int linenumber = 0;
std::stack<Configuration::Block *> block_stack;
unsigned linenumber = 0;
bool in_word = false, in_quote = false, in_comment = false;
Log(LOG_DEBUG) << "Start to read conf " << file.GetPath();
@@ -894,7 +878,7 @@ void Conf::LoadConf(File &file)
continue;
}
Block *b = block_stack.empty() ? this : block_stack.top();
auto *b = block_stack.empty() ? this : block_stack.top();
auto it = b->blocks.emplace(wordbuffer, Configuration::Block(wordbuffer));
b = &it->second;
b->linenum = linenumber;
@@ -946,7 +930,7 @@ void Conf::LoadConf(File &file)
throw ConfigException("Stray ';' outside of block: " + file.GetName() + ":" + Anope::ToString(linenumber));
}
Block *b = block_stack.top();
auto *b = block_stack.top();
if (b)
{
Log(LOG_DEBUG) << "ln " << linenumber << " EOL: s='" << b->name << "' '" << itemname << "' set to '" << wordbuffer << "'";
@@ -988,7 +972,7 @@ void Conf::LoadConf(File &file)
}
}
Anope::string Conf::ReplaceVars(const Anope::string &str, const File &file, int linenumber)
Anope::string Configuration::Conf::ReplaceVars(const Anope::string &str, const Configuration::File &file, unsigned linenumber)
{
Anope::string ret;
for (auto it = str.begin(); it != str.end(); )
@@ -1024,9 +1008,8 @@ Anope::string Conf::ReplaceVars(const Anope::string &str, const File &file, int
}
auto found = false;
for (int i = 0; i < this->CountBlock("define"); ++i)
for (const auto &[_, define] : this->GetBlocks("define"))
{
const auto &define = this->GetBlock("define", i);
const auto defname = define.Get<const Anope::string>("name");
if (defname == var)
{
+2 -2
View File
@@ -537,8 +537,8 @@ bool Anope::Init(int ac, char **av)
/* load modules */
Log() << "Loading modules...";
for (int i = 0; i < Config->CountBlock("module"); ++i)
ModuleManager::LoadModule(Config->GetBlock("module", i).Get<const Anope::string>("name"), NULL);
for (const auto &[_, block] : Config->GetBlocks("module"))
ModuleManager::LoadModule(block.Get<const Anope::string>("name"), NULL);
#ifndef _WIN32
/* If we're root, issue a warning now */
+1 -1
View File
@@ -54,7 +54,7 @@ void Language::InitLanguages()
Languages.push_back(language);
}
#else
Log() << "Unable to initialize languages, gettext is not installed";
Log() << "Unable to initialize languages, gettext and/or libintl were not installed at build time";
#endif
}
+6 -4
View File
@@ -50,13 +50,14 @@ class UpdateTimer final
{
public:
UpdateTimer(time_t timeout)
: Timer(timeout, true)
: Timer(timeout)
{
}
void Tick() override
bool Tick() override
{
Anope::SaveDatabases();
return true;
}
};
@@ -65,13 +66,14 @@ class ExpireTimer final
{
public:
ExpireTimer(time_t timeout)
: Timer(timeout, true)
: Timer(timeout)
{
}
void Tick() override
bool Tick() override
{
FOREACH_MOD(OnExpireTick, ());
return true;
}
};
+22 -24
View File
@@ -24,14 +24,12 @@
#include "channels.h"
#include "numeric.h"
using namespace Message;
void Away::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Away::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
source.GetUser()->SetAway(params.empty() ? "" : params[0]);
}
void Capab::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Capab::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
if (params.size() == 1)
{
@@ -47,26 +45,26 @@ void Capab::Run(MessageSource &source, const std::vector<Anope::string> &params,
}
}
void Error::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Error::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
Anope::QuitReason = "Received an error from the uplink: " + params.back();
Anope::Quitting = true;
Log(LOG_TERMINAL) << Anope::QuitReason;
}
Ignore::Ignore(Module *creator, const Anope::string &mname)
Message::Ignore::Ignore(Module *creator, const Anope::string &mname)
: IRCDMessage(creator, mname, 0)
{
SetFlag(FLAG_SOFT_LIMIT);
}
void Ignore::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Ignore::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
Log(LOG_DEBUG_3) << "Intentionally ignoring " << name << " message";
}
void Invite::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Invite::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *targ = User::Find(params[0]);
Channel *c = Channel::Find(params[1]);
@@ -77,7 +75,7 @@ void Invite::Run(MessageSource &source, const std::vector<Anope::string> &params
FOREACH_MOD(OnInvite, (source.GetUser(), c, targ));
}
void Join::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Join::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *user = source.GetUser();
const Anope::string &channels = params[0];
@@ -111,7 +109,7 @@ void Join::Run(MessageSource &source, const std::vector<Anope::string> &params,
}
}
void Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, const Anope::string &modes, const std::vector<Anope::string> &modeparams, const std::list<SJoinUser> &users)
void Message::Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, const Anope::string &modes, const std::vector<Anope::string> &modeparams, const std::list<SJoinUser> &users)
{
bool created;
Channel *c = Channel::FindOrCreate(chan, created, ts ? ts : Anope::CurTime);
@@ -177,7 +175,7 @@ void Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, co
}
}
void Kick::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Kick::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
const Anope::string &channel = params[0];
const Anope::string &users = params[1];
@@ -194,7 +192,7 @@ void Kick::Run(MessageSource &source, const std::vector<Anope::string> &params,
c->KickInternal(source, user, reason);
}
void Kill::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Kill::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *u = User::Find(params[0]);
BotInfo *bi;
@@ -237,7 +235,7 @@ void Message::Mode::Run(MessageSource &source, const std::vector<Anope::string>
}
/* XXX We should cache the file somewhere not open/read/close it on every request */
void MOTD::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::MOTD::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
Server *s = Server::Find(params[0]);
if (s != Me)
@@ -257,7 +255,7 @@ void MOTD::Run(MessageSource &source, const std::vector<Anope::string> &params,
IRCD->SendNumeric(RPL_ENDOFMOTD, source.GetSource(), "End of /MOTD command.");
}
void Notice::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Notice::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
Anope::string message = params[1];
@@ -273,7 +271,7 @@ void Notice::Run(MessageSource &source, const std::vector<Anope::string> &params
}
}
void Part::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Part::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *u = source.GetUser();
const Anope::string &reason = params.size() > 1 ? params[1] : "";
@@ -295,12 +293,12 @@ void Part::Run(MessageSource &source, const std::vector<Anope::string> &params,
}
}
void Ping::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Ping::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
IRCD->SendPong(params.size() > 1 ? params[1] : Me->GetSID(), params[0]);
}
void Privmsg::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Privmsg::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
const Anope::string &receiver = params[0];
Anope::string message = params[1];
@@ -358,7 +356,7 @@ void Privmsg::Run(MessageSource &source, const std::vector<Anope::string> &param
return;
}
void Quit::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Quit::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
const Anope::string &reason = params[0];
User *user = source.GetUser();
@@ -368,7 +366,7 @@ void Quit::Run(MessageSource &source, const std::vector<Anope::string> &params,
user->Quit(reason);
}
void SQuit::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::SQuit::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
Server *s = Server::Find(params[0]);
@@ -389,7 +387,7 @@ void SQuit::Run(MessageSource &source, const std::vector<Anope::string> &params,
s->Delete(s->GetName() + " " + s->GetUplink()->GetName());
}
void Stats::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Stats::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *u = source.GetUser();
@@ -439,7 +437,7 @@ void Stats::Run(MessageSource &source, const std::vector<Anope::string> &params,
return;
}
void Time::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Time::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
const auto *tm = localtime(&Anope::CurTime);
char timebuf[64];
@@ -448,7 +446,7 @@ void Time::Run(MessageSource &source, const std::vector<Anope::string> &params,
IRCD->SendNumeric(RPL_TIME, source.GetSource(), Me->GetName(), timestr);
}
void Topic::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Topic::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
Channel *c = Channel::Find(params[0]);
if (c)
@@ -457,14 +455,14 @@ void Topic::Run(MessageSource &source, const std::vector<Anope::string> &params,
return;
}
void Version::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Version::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
Module *enc = ModuleManager::FindFirstOf(ENCRYPTION);
IRCD->SendNumeric(RPL_VERSION, source.GetSource(), "Anope-" + Anope::Version(), Me->GetName(), Anope::Format("%s -(%s) -- %s",
IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)", Anope::VersionBuildString().c_str()));
}
void Whois::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
void Message::Whois::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
{
User *u = User::Find(params[0]);
+7 -5
View File
@@ -340,8 +340,8 @@ void ExampleWrapper::SendTo(CommandSource &source)
header = false;
}
const auto *trans_example = Language::Translate(source.nc, entry.example.c_str());
const auto *trans_description = Language::Translate(source.nc, entry.description.c_str());
const auto *trans_example = source.Translate(entry.example);
const auto *trans_description = source.Translate(entry.description);
if (flexible)
{
source.Reply("\002%s%s%s\002: %s", source.command.c_str(), *trans_example ? " " : "",
@@ -381,7 +381,7 @@ void HelpWrapper::SendTo(CommandSource &source)
for (const auto &[entry_name, entry_desc] : entries)
{
const auto *trans_desc = Language::Translate(source.nc, entry_desc.c_str());
const auto *trans_desc = source.Translate(entry_desc);
if (flexible)
{
source.Reply("\002%s\002: %s", entry_name.c_str(), trans_desc);
@@ -686,7 +686,9 @@ Anope::string Anope::strftime(time_t t, const NickCore *nc, bool short_output)
}
char buf[256];
strftime(buf, sizeof(buf), "%c", (nc ? localtime(&t) : gmtime(&t)));
const auto *ts = nc ? localtime(&t) : gmtime(&t);
if (!ts || !strftime(buf, sizeof(buf), "%c", ts))
snprintf(buf, sizeof(buf), "(invalid timestamp)");
if (nc)
{
@@ -963,7 +965,7 @@ Anope::string Anope::VersionBuildString()
flags += "G";
#endif
#if REPRODUCIBLE_BUILD
flags += "R"
flags += "R";
#endif
#ifdef _WIN32
flags += "W";
+3 -2
View File
@@ -88,10 +88,11 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
#ifdef _WIN32
/* Generate the filename for the temporary copy of the module */
auto pbuf = Anope::ExpandData("runtime/" + modname + DLL_EXT ".XXXXXX");
auto pbuf = Anope::ExpandData("runtime/" + modname + "." + Anope::ToString(Anope::CurTime) + DLL_EXT);
if (!fs::copy_file(modpath.str(), pbuf.str(), fs::copy_options::overwrite_existing, ec) || ec)
{
Log(LOG_TERMINAL) << "Error while loading " << modname << ": " << ec.message();
Log(LOG_TERMINAL) << "Error while copying " << modname << " from " << modpath
<< " to " << pbuf << ": " << ec.message();
return MOD_ERR_FILE_IO;
}
#else
+1 -1
View File
@@ -37,7 +37,7 @@ NickAlias::NickAlias(const Anope::string &nickname, NickCore *nickcore)
if (this->nick.equals_ci(nickcore->display))
nickcore->na = this;
if (!NickAliasList->insert_or_assign(this->nick, this).second)
if (!this->InsertUnique(*NickAliasList, this->nick))
Log(LOG_DEBUG) << "Duplicate nick " << this->nick << " in NickAlias table";
if (this->nc->o == NULL)
+2 -2
View File
@@ -31,11 +31,11 @@ NickCore::NickCore(const Anope::string &coredisplay, uint64_t coreid)
if (coredisplay.empty())
throw CoreException("Empty display passed to NickCore constructor");
if (!NickCoreList->insert_or_assign(this->display, this).second)
if (!this->InsertUnique(*NickCoreList, this->display))
Log(LOG_DEBUG) << "Duplicate account " << this->display << " in NickCore table";
// Upgrading users may not have an account identifier.
if (this->uniqueid && !NickCoreIdList->insert_or_assign(this->uniqueid, this).second)
if (this->uniqueid && !this->InsertUnique(*NickCoreIdList, this->uniqueid))
Log(LOG_DEBUG) << "Duplicate account id " << this->uniqueid << " in NickCore table";
FOREACH_MOD(OnNickCoreCreate, (this));
+2
View File
@@ -395,6 +395,7 @@ Anope::string IRCDProto::NormalizeMask(const Anope::string &mask)
void IRCDProto::SendContextNotice(BotInfo *bi, User *target, Channel *context, const Anope::string &msg, const Anope::map<Anope::string> &tags)
{
auto newtags = tags;
newtags["+channel-context"] = context->name;
newtags["+draft/channel-context"] = context->name;
IRCD->SendNotice(bi, target->GetUID(), Anope::Format("[%s] %s", context->name.c_str(), msg.c_str()), newtags);
}
@@ -402,6 +403,7 @@ void IRCDProto::SendContextNotice(BotInfo *bi, User *target, Channel *context, c
void IRCDProto::SendContextPrivmsg(BotInfo *bi, User *target, Channel *context, const Anope::string &msg, const Anope::map<Anope::string> &tags)
{
auto newtags = tags;
newtags["+channel-context"] = context->name;
newtags["+draft/channel-context"] = context->name;
IRCD->SendPrivmsg(bi, target->GetUID(), Anope::Format("[%s] %s", context->name.c_str(), msg.c_str()), newtags);
}

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