mirror of
https://github.com/anope/anope.git
synced 2026-07-08 22:13:12 +02:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f15f8e3454 | |||
| ff52ade0cc | |||
| 4c81f45232 | |||
| cdccfaf99a | |||
| e47d379d98 | |||
| c784f08002 | |||
| 6de2ae0046 | |||
| c26f742662 | |||
| e3bff85339 | |||
| 5819c1fcf3 | |||
| 4b8f073cb7 | |||
| 67026b184d | |||
| b49f984598 | |||
| b9cacf1d0f | |||
| 09d0bd6987 | |||
| f150ee857f | |||
| d60c80a4a3 | |||
| 44b7493eb1 | |||
| a03e765172 | |||
| 17cd10ef21 | |||
| ca8fcbe119 | |||
| b9d0762f2b | |||
| 4878b1787e | |||
| 0163d92b1d | |||
| a861a059f6 | |||
| 90da25f84f | |||
| ab362c9828 | |||
| d1f6da1817 | |||
| 9280d90aba | |||
| c71f69208d | |||
| d0080b85a7 | |||
| 745e94783d | |||
| c32be6a711 | |||
| 9dd3acfc87 | |||
| 82b6da3763 | |||
| 8e691eac80 | |||
| 2327c6ac9a | |||
| e23ea8f8ea | |||
| 449cfa6503 | |||
| 59c60849b6 | |||
| 6d2c4fb612 | |||
| 01fc7421b6 | |||
| 3a59a81aa4 | |||
| c24de0ca8f | |||
| 18555638c9 | |||
| d5a653fe94 | |||
| ad3be96283 | |||
| d689c0686d | |||
| 4ca2952069 | |||
| caf904c938 | |||
| 8930cc2a92 | |||
| 47b927d788 | |||
| 647a07ff96 | |||
| a856e80b1e | |||
| 55746e1098 | |||
| e0da3bae18 | |||
| c1cf7b0bcc | |||
| 1cf64a49c0 | |||
| 92ed0071d7 | |||
| 9469cb8b0e | |||
| e0b715b185 | |||
| e6d7306202 | |||
| 2107d18d9e | |||
| acb9428635 | |||
| d942da1df5 | |||
| a961259556 | |||
| 27a19dcc52 | |||
| e45814bfd6 | |||
| f12b590a6d | |||
| c0bafe10b4 | |||
| 5f40d0d6bb | |||
| 6b416cc64d |
@@ -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.
|
- [ ] 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.
|
- [ ] 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).
|
- [ ] This pull request does not introduce any incompatible API changes (stable branches only, delete if not applicable).
|
||||||
|
|||||||
@@ -3,21 +3,18 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 0'
|
- cron: 0 0 * * 0
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: "!contains(github.event.head_commit.message, '[skip alpine ci]')"
|
if: "!contains(github.event.head_commit.message, '[skip alpine ci]')"
|
||||||
container: alpine:edge
|
container: alpine:latest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
|
||||||
CXX: ${{ matrix.compiler }}
|
|
||||||
CXXFLAGS: -Werror
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |-
|
||||||
echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
|
echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
|
||||||
apk update
|
apk update
|
||||||
apk add \
|
apk add \
|
||||||
@@ -37,24 +34,36 @@ jobs:
|
|||||||
tre-dev
|
tre-dev
|
||||||
|
|
||||||
- name: Enable extras
|
- 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
|
for MODULE in enc_argon2 enc_posix ldap mysql regex_pcre2 regex_posix regex_tre sqlite ssl_gnutls ssl_openssl
|
||||||
do
|
do
|
||||||
ln -s $PWD/modules/extra/$MODULE.cpp $PWD/modules
|
ln -s $PWD/modules/extra/$MODULE.cpp $PWD/modules
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: |
|
env:
|
||||||
mkdir build && cd build
|
CC: ${{ matrix.compiler.cc }}
|
||||||
cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=DEBUG -DINSTDIR:STRING=$(readlink -f ../run) ..
|
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
|
- name: Build and install
|
||||||
run: |
|
env:
|
||||||
ninja -C build install
|
VERBOSE: ${{ runner.debug }}
|
||||||
|
run: |-
|
||||||
|
ninja -C "build" ${{ runner.debug == '1' && '-v' || '' }} install
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
compiler:
|
compiler:
|
||||||
- clang++
|
- cc: clang
|
||||||
- g++
|
cxx: clang++
|
||||||
|
- cc: gcc
|
||||||
|
cxx: g++
|
||||||
|
|||||||
@@ -3,20 +3,17 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 0'
|
- cron: 0 0 * * 0
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: "!contains(github.event.head_commit.message, '[skip ubuntu ci]')"
|
if: "!contains(github.event.head_commit.message, '[skip ubuntu ci]')"
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-latest
|
||||||
env:
|
|
||||||
CXX: ${{ matrix.compiler }}
|
|
||||||
CXXFLAGS: -Werror
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |-
|
||||||
sudo apt-get update --assume-yes
|
sudo apt-get update --assume-yes
|
||||||
sudo apt-get install --assume-yes --no-install-recommends \
|
sudo apt-get install --assume-yes --no-install-recommends \
|
||||||
clang \
|
clang \
|
||||||
@@ -34,24 +31,36 @@ jobs:
|
|||||||
ninja-build
|
ninja-build
|
||||||
|
|
||||||
- name: Enable extras
|
- 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
|
for MODULE in enc_argon2 enc_posix ldap mysql regex_pcre2 regex_posix regex_tre sqlite ssl_gnutls ssl_openssl
|
||||||
do
|
do
|
||||||
ln -s ${{ github.workspace }}/modules/extra/$MODULE.cpp ${{ github.workspace }}/modules
|
ln -s ${{ github.workspace }}/modules/extra/$MODULE.cpp ${{ github.workspace }}/modules
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
run: |
|
env:
|
||||||
mkdir build && cd build
|
CC: ${{ matrix.compiler.cc }}
|
||||||
cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=DEBUG -DINSTDIR:STRING=${{ github.workspace }}/run ..
|
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
|
- name: Build and install
|
||||||
run: |
|
env:
|
||||||
ninja -C ${{ github.workspace }}/build install
|
VERBOSE: ${{ runner.debug }}
|
||||||
|
run: |-
|
||||||
|
ninja -C "build" ${{ runner.debug == '1' && '-v' || '' }} install
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
compiler:
|
compiler:
|
||||||
- clang++
|
- cc: clang
|
||||||
- g++
|
cxx: clang++
|
||||||
|
- cc: gcc
|
||||||
|
cxx: g++
|
||||||
|
|||||||
@@ -6,77 +6,90 @@ on:
|
|||||||
types:
|
types:
|
||||||
- published
|
- published
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 0'
|
- cron: 0 0 * * 0
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: "!contains(github.event.head_commit.message, '[skip windows ci]')"
|
if: "!contains(github.event.head_commit.message, '[skip windows ci]')"
|
||||||
runs-on: windows-2025
|
runs-on: windows-2025
|
||||||
env:
|
env:
|
||||||
|
BUILD_PATH: ${{ github.workspace }}\build
|
||||||
BUILD_TYPE: ${{ github.event_name == 'release' && 'Release' || 'Debug' }}
|
BUILD_TYPE: ${{ github.event_name == 'release' && 'Release' || 'Debug' }}
|
||||||
|
CONAN_FILE: ${{ github.workspace }}\src\win32\conanfile.txt
|
||||||
CONAN_HOME: ${{ github.workspace }}\build\conan
|
CONAN_HOME: ${{ github.workspace }}\build\conan
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Install NSIS
|
- name: Setup MSVC
|
||||||
uses: negrutiu/nsis-install@v2
|
uses: TheMrMilchmann/setup-msvc-dev@v4
|
||||||
|
with:
|
||||||
|
arch: x64
|
||||||
|
|
||||||
|
- name: Setup NSIS
|
||||||
|
uses: negrutiu/nsis-install@v3
|
||||||
with:
|
with:
|
||||||
distro: official
|
distro: official
|
||||||
|
|
||||||
- name: Setup MSBuild
|
|
||||||
uses: microsoft/setup-msbuild@v3
|
|
||||||
|
|
||||||
- name: Setup Conan
|
- name: Setup Conan
|
||||||
uses: turtlebrowser/get-conan@v1.2
|
uses: turtlebrowser/get-conan@v1.2
|
||||||
|
|
||||||
- name: Create Conan profile
|
- name: Create Conan configuration
|
||||||
run: |-
|
run: |-
|
||||||
conan profile detect
|
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('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
|
(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 '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
|
- name: Try to restore libraries from the cache
|
||||||
uses: actions/cache/restore@v5
|
if: github.event_name != 'release'
|
||||||
|
uses: actions/cache/restore@v6
|
||||||
id: library-cache
|
id: library-cache
|
||||||
with:
|
with:
|
||||||
key: conan-${{ env.BUILD_TYPE }}-${{ hashFiles('src\win32\conanfile.txt') }}
|
key: Conan VS${{ env.VisualStudioVersion }} ${{ env.BUILD_TYPE }} ${{ hashFiles(env.CONAN_FILE) }}
|
||||||
path: ${{ env.CONAN_HOME }}\p
|
path: ${{ env.CONAN_HOME }}/p
|
||||||
|
|
||||||
- name: Install libraries
|
- name: Install libraries
|
||||||
run: |
|
working-directory: ${{ env.BUILD_PATH }}
|
||||||
(Get-Content ${{ github.workspace }}\src\win32\conanfile.txt).replace('##', '') | Set-Content ${{ github.workspace }}\src\win32\conanfile.txt
|
run: |-
|
||||||
conan install ${{ github.workspace }}\src\win32 --build missing --deployer runtime_deploy --deployer-folder ${{ github.workspace }}\build\extradll --output-folder .
|
(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
|
- 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
|
uses: actions/cache/save@v6
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.library-cache.outputs.cache-primary-key }}
|
key: ${{ steps.library-cache.outputs.cache-primary-key }}
|
||||||
path: ${{ env.CONAN_HOME }}\p
|
path: ${{ env.CONAN_HOME }}\p
|
||||||
|
|
||||||
- name: Run CMake
|
- name: Run CMake
|
||||||
shell: cmd # work around a conan-io/conan-center-index bug #21823
|
working-directory: ${{ env.BUILD_PATH }}
|
||||||
working-directory: ${{ github.workspace }}\build
|
run: |-
|
||||||
run: |
|
cmake -D "CMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }}" `
|
||||||
call ${{ github.workspace }}\conanbuild.bat
|
-D "CMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake" `
|
||||||
cmake -A x64 -D "CMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }}" -D CMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -G "Visual Studio 17 2022" ..
|
-G "Ninja Multi-Config" `
|
||||||
|
-S "${{ github.workspace }}" `
|
||||||
|
-Wdeprecated `
|
||||||
|
-Wdev
|
||||||
|
|
||||||
- name: Build Anope
|
- name: Build installer
|
||||||
working-directory: ${{ github.workspace }}\build
|
working-directory: ${{ env.BUILD_PATH }}
|
||||||
run: |
|
run: |-
|
||||||
msbuild PACKAGE.vcxproj /M:5 /P:Configuration=${{ env.BUILD_TYPE }} /P:Platform=x64 /VERBOSITY:MINIMAL
|
ninja -f "build-${{ env.BUILD_TYPE }}.ninja" ${{ runner.debug == '1' && '-v' || '' }} package
|
||||||
|
|
||||||
- name: Upload installer
|
- name: Upload installer
|
||||||
if: "${{ github.event_name == 'release' }}"
|
if: github.event_name == 'release'
|
||||||
working-directory: ${{ github.workspace }}\build
|
working-directory: ${{ env.BUILD_PATH }}
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
gh release upload ${{ github.event.release.tag_name }} $(Get-ChildItem anope-*.exe)
|
gh release upload ${{ github.event.release.tag_name }} $(Get-ChildItem anope-*.exe)
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
if: "${{ github.event_name != 'release' }}"
|
if: github.event_name != 'release'
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: windows-installer
|
name: windows-installer
|
||||||
|
|||||||
@@ -0,0 +1,223 @@
|
|||||||
|
name: irctest
|
||||||
|
|
||||||
|
# Last checked: 2026-06-29
|
||||||
|
env:
|
||||||
|
INSPIRCD_REF: v4.11.0 # 2026-06-06
|
||||||
|
IRCTEST_REF: ff6ef19d96cacd79ea8033dda2cf660fe5cdba52 # 2026-06-20
|
||||||
|
SOLANUM_REF: a17cc145a7de564e49b84807d335289f30b12d00 # 2026-06-23
|
||||||
|
UNREALIRCD_REF: 1250b7f014dbbe1dae13138dbef6e52c6dcd5557 # 2026-05-15 (6.2.5)
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
schedule:
|
||||||
|
- cron: 0 0 * * 0
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-skip:
|
||||||
|
if: "!contains(github.event.head_commit.message, '[skip irctest ci]')"
|
||||||
|
runs-on: ubuntu-26.04-arm
|
||||||
|
steps:
|
||||||
|
- run: true # Avoids skip check duplication.
|
||||||
|
|
||||||
|
build-anope:
|
||||||
|
needs:
|
||||||
|
- check-skip
|
||||||
|
runs-on: ubuntu-26.04-arm
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |-
|
||||||
|
sudo apt-get install build-essential cmake --assume-yes
|
||||||
|
cmake \
|
||||||
|
-B "${{ github.workspace }}/build" \
|
||||||
|
-D "CMAKE_UNITY_BUILD=ON" \
|
||||||
|
-D "CMAKE_UNITY_BUILD_BATCH_SIZE=0" \
|
||||||
|
-D "INSTDIR=$HOME/software/anope" \
|
||||||
|
-G "Ninja" \
|
||||||
|
-S "${{ github.workspace }}"
|
||||||
|
ninja -C "${{ github.workspace }}/build" install
|
||||||
|
|
||||||
|
- name: Make artifact
|
||||||
|
run: |-
|
||||||
|
tar \
|
||||||
|
--auto-compress \
|
||||||
|
--create \
|
||||||
|
--file installed-anope.tar.gz \
|
||||||
|
$HOME/software/anope
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: installed-anope
|
||||||
|
path: installed-anope.tar.gz
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
build-inspircd:
|
||||||
|
needs:
|
||||||
|
- check-skip
|
||||||
|
runs-on: ubuntu-26.04-arm
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
ref: ${{ env.INSPIRCD_REF }}
|
||||||
|
repository: inspircd/inspircd
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |-
|
||||||
|
sudo apt-get install build-essential --assume-yes
|
||||||
|
./configure \
|
||||||
|
--development \
|
||||||
|
--disable-auto-extras \
|
||||||
|
--prefix $HOME/software/inspircd
|
||||||
|
export CXXFLAGS="-DINSPIRCD_UNLIMITED_MAINLOOP"
|
||||||
|
make -j$(($(getconf _NPROCESSORS_ONLN) + 1)) install
|
||||||
|
|
||||||
|
- name: Make artifact
|
||||||
|
run: |-
|
||||||
|
tar \
|
||||||
|
--auto-compress \
|
||||||
|
--create \
|
||||||
|
--file installed-inspircd.tar.gz \
|
||||||
|
$HOME/software/inspircd
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: installed-inspircd
|
||||||
|
path: installed-inspircd.tar.gz
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
build-solanum:
|
||||||
|
needs:
|
||||||
|
- check-skip
|
||||||
|
runs-on: ubuntu-26.04-arm
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
ref: ${{ env.SOLANUM_REF }}
|
||||||
|
repository: solanum-ircd/solanum
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |-
|
||||||
|
sudo apt-get install build-essential libltdl-dev --assume-yes
|
||||||
|
./autogen.sh
|
||||||
|
./configure \
|
||||||
|
--enable-fhs-paths \
|
||||||
|
--prefix $HOME/software/solanum
|
||||||
|
make -j$(($(getconf _NPROCESSORS_ONLN) + 1)) install
|
||||||
|
|
||||||
|
- name: Make artifact
|
||||||
|
run: |-
|
||||||
|
tar \
|
||||||
|
--auto-compress \
|
||||||
|
--create \
|
||||||
|
--file installed-solanum.tar.gz \
|
||||||
|
$HOME/software/solanum
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: installed-solanum
|
||||||
|
path: installed-solanum.tar.gz
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
build-unrealircd:
|
||||||
|
needs:
|
||||||
|
- check-skip
|
||||||
|
runs-on: ubuntu-26.04-arm
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
ref: ${{ env.UNREALIRCD_REF }}
|
||||||
|
repository: unrealircd/unrealircd
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |-
|
||||||
|
sudo apt-get install build-essential libssl-dev --assume-yes
|
||||||
|
wget --output-document src/modules/third/metadata2.c https://raw.githubusercontent.com/progval/unrealircd-contrib/metadata2/files/metadata2.c
|
||||||
|
echo "BASEPATH=$HOME/software/unrealircd" >> config.settings
|
||||||
|
echo "GEOIP=none" >> config.settings
|
||||||
|
yes "" | ./Config
|
||||||
|
make -j$(($(getconf _NPROCESSORS_ONLN) + 1)) install
|
||||||
|
|
||||||
|
- name: Make artifact
|
||||||
|
run: |-
|
||||||
|
tar \
|
||||||
|
--auto-compress \
|
||||||
|
--create \
|
||||||
|
--file installed-unrealircd.tar.gz \
|
||||||
|
$HOME/software/unrealircd
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: installed-unrealircd
|
||||||
|
path: installed-unrealircd.tar.gz
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-26.04-arm
|
||||||
|
needs:
|
||||||
|
- build-anope
|
||||||
|
- build-inspircd
|
||||||
|
- build-solanum
|
||||||
|
- build-unrealircd
|
||||||
|
steps:
|
||||||
|
- name: Download Anope artifact
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: installed-anope
|
||||||
|
|
||||||
|
- name: Download server artifact
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: installed-${{ matrix.server }}
|
||||||
|
|
||||||
|
- name: Unpack artifacts
|
||||||
|
run: |-
|
||||||
|
for ARCHIVE in installed-anope installed-${{ matrix.server }}
|
||||||
|
do
|
||||||
|
tar \
|
||||||
|
--directory / \
|
||||||
|
--extract \
|
||||||
|
--file ${ARCHIVE}.tar.gz
|
||||||
|
done
|
||||||
|
for SOFTWARE in $HOME/software/*
|
||||||
|
do
|
||||||
|
echo "Adding ${SOFTWARE} to the PATH"
|
||||||
|
export PATH=$SOFTWARE/bin:$SOFTWARE/sbin:$PATH
|
||||||
|
done
|
||||||
|
echo PATH=$PATH >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Checkout irctest
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
ref: ${{ env.IRCTEST_REF }}
|
||||||
|
repository: progval/irctest
|
||||||
|
|
||||||
|
- name: Install irctest dependencies
|
||||||
|
run: |-
|
||||||
|
sudo apt-get install faketime
|
||||||
|
pip3 install --requirement requirements.txt pytest-xdist pytest-timeout
|
||||||
|
|
||||||
|
- name: Run irctest
|
||||||
|
env:
|
||||||
|
IRCTEST_DEBUG_LOGS: ${{ runner.debug }}
|
||||||
|
PYTEST_ARGS: --color=yes --verbose
|
||||||
|
run: |-
|
||||||
|
make ${{ matrix.server}}-anope
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
server:
|
||||||
|
- inspircd
|
||||||
|
- solanum
|
||||||
|
- unrealircd
|
||||||
@@ -51,7 +51,8 @@ Robby <robby@chatbelgie.be> <robby@chat.be>
|
|||||||
Robert Scheck <robert@fedoraproject.org> <robert-scheck@users.noreply.github.com>
|
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> <rburchell@5417fbe8-f217-4b02-8779-1006273d7864>
|
||||||
Robin Burchell <w00t@inspircd.org> <Robin Burchell w00t@inspircd.org@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 Barfurth <github@afreshmelon.com>
|
||||||
Sebastian V. <hal9000@denorastats.org>
|
Sebastian V. <hal9000@denorastats.org>
|
||||||
Sebastian V. <hal9000@denorastats.org> <pimpmylinux@5417fbe8-f217-4b02-8779-1006273d7864>
|
Sebastian V. <hal9000@denorastats.org> <pimpmylinux@5417fbe8-f217-4b02-8779-1006273d7864>
|
||||||
|
|||||||
+42
-31
@@ -1,8 +1,8 @@
|
|||||||
# This usage of CMake requires at least version 3.20
|
# This usage of CMake requires at least version 3.20
|
||||||
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
|
||||||
|
|
||||||
# Set the project as C++ primarily
|
# Set the project as C++ primarily with C for the vendored libraries
|
||||||
project(Anope CXX)
|
project(Anope CXX C)
|
||||||
|
|
||||||
# Force the locale to C for later uses of things like gcc so the messages come up in English, not the user's default language
|
# Force the locale to C for later uses of things like gcc so the messages come up in English, not the user's default language
|
||||||
set(ENV{LC_ALL} C)
|
set(ENV{LC_ALL} C)
|
||||||
@@ -25,6 +25,7 @@ include(CheckFunctionExists)
|
|||||||
include(CheckTypeSize)
|
include(CheckTypeSize)
|
||||||
include(CheckLibraryExists)
|
include(CheckLibraryExists)
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
|
include(CheckPIESupported)
|
||||||
|
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
include(FindPkgConfig)
|
include(FindPkgConfig)
|
||||||
@@ -40,15 +41,19 @@ if(EXTRA_LIBS)
|
|||||||
link_directories(${EXTRA_LIBS})
|
link_directories(${EXTRA_LIBS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Enable -fPIC for all targets.
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
check_pie_supported()
|
||||||
|
|
||||||
# Find gettext
|
# Find gettext
|
||||||
find_package(Gettext)
|
find_package(Gettext)
|
||||||
find_package(Intl)
|
find_package(Intl)
|
||||||
if(GETTEXT_FOUND AND Intl_FOUND)
|
if(Gettext_FOUND AND Intl_FOUND)
|
||||||
set(HAVE_LOCALIZATION ON)
|
set(HAVE_LOCALIZATION ON)
|
||||||
include_directories(${Intl_INCLUDE_DIRS})
|
include_directories(${Intl_INCLUDE_DIRS})
|
||||||
link_libraries(${Intl_LIBRARIES})
|
link_libraries(${Intl_LIBRARIES})
|
||||||
else()
|
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)
|
set(HAVE_LOCALIZATION OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -144,28 +149,37 @@ elseif(NOT CMAKE_INSTALL_PREFIX)
|
|||||||
set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/anope-${VERSION_MAJOR}-${VERSION_MINOR}")
|
set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/anope-${VERSION_MAJOR}-${VERSION_MINOR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
function(configure_path VARIABLE DEFAULT)
|
||||||
|
if(NOT DEFINED ${VARIABLE})
|
||||||
|
set(${VARIABLE} ${DEFAULT} CACHE PATH "Location of the ${DEFAULT} directory")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(ABSOLUTE_${VARIABLE} ${${VARIABLE}})
|
||||||
|
else()
|
||||||
|
cmake_path(
|
||||||
|
APPEND CMAKE_INSTALL_PREFIX "${${VARIABLE}}"
|
||||||
|
OUTPUT_VARIABLE ABSOLUTE_${VARIABLE}
|
||||||
|
)
|
||||||
|
cmake_path(NORMAL_PATH ABSOLUTE_${VARIABLE})
|
||||||
|
endif()
|
||||||
|
set(ABSOLUTE_${VARIABLE} ${ABSOLUTE_${VARIABLE}} CACHE INTERNAL "" FORCE)
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY
|
||||||
|
DESTINATION ${${VARIABLE}}
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
# Set default paths for various directories if not already defined
|
# Set default paths for various directories if not already defined
|
||||||
if(NOT BIN_DIR)
|
configure_path(BIN_DIR "bin")
|
||||||
set(BIN_DIR "bin")
|
configure_path(DATA_DIR "data")
|
||||||
endif()
|
configure_path(DOC_DIR "doc")
|
||||||
if(NOT DATA_DIR)
|
configure_path(CONF_DIR "conf")
|
||||||
set(DATA_DIR "data")
|
configure_path(MODULE_DIR "modules")
|
||||||
endif()
|
configure_path(LOCALE_DIR "locale")
|
||||||
if(NOT DOC_DIR)
|
configure_path(LOG_DIR "logs")
|
||||||
set(DOC_DIR "doc")
|
|
||||||
endif()
|
|
||||||
if(NOT CONF_DIR)
|
|
||||||
set(CONF_DIR "conf")
|
|
||||||
endif()
|
|
||||||
if(NOT MODULE_DIR)
|
|
||||||
set(MODULE_DIR "modules")
|
|
||||||
endif()
|
|
||||||
if(NOT LOCALE_DIR)
|
|
||||||
set(LOCALE_DIR "locale")
|
|
||||||
endif()
|
|
||||||
if(NOT LOG_DIR)
|
|
||||||
set(LOG_DIR "logs")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Version number processing
|
# Version number processing
|
||||||
# Find all lines in src/version.sh that start with VERSION_
|
# Find all lines in src/version.sh that start with VERSION_
|
||||||
@@ -218,12 +232,9 @@ set(SERVICES_BINARY "$<TARGET_FILE:${PROGRAM_NAME}>")
|
|||||||
cmake_path(GET SERVICES_BINARY FILENAME SERVICES_BINARY)
|
cmake_path(GET SERVICES_BINARY FILENAME SERVICES_BINARY)
|
||||||
|
|
||||||
# At install time, create the following additional directories
|
# At install time, create the following additional directories
|
||||||
file(REAL_PATH ${DATA_DIR} ABSOLUTE_DATA_DIR BASE_DIRECTORY ${CMAKE_INSTALL_PREFIX})
|
install(DIRECTORY DESTINATION "${DATA_DIR}/backups")
|
||||||
file(REAL_PATH ${LOG_DIR} ABSOLUTE_LOG_DIR BASE_DIRECTORY ${CMAKE_INSTALL_PREFIX})
|
|
||||||
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${ABSOLUTE_DATA_DIR}/backups\")")
|
|
||||||
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${ABSOLUTE_LOG_DIR}\")")
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${ABSOLUTE_DATA_DIR}/runtime\")")
|
install(DIRECTORY DESTINATION "${DATA_DIR}/runtime")
|
||||||
endif()
|
endif()
|
||||||
# On non-Windows platforms, if RUNGROUP is set, change the permissions of the below directories, as well as the group of the data directory
|
# On non-Windows platforms, if RUNGROUP is set, change the permissions of the below directories, as well as the group of the data directory
|
||||||
if(NOT WIN32 AND RUNGROUP)
|
if(NOT WIN32 AND RUNGROUP)
|
||||||
@@ -238,7 +249,6 @@ if(WIN32)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(REAL_PATH ${MODULE_DIR} ABSOLUTE_MODULE_DIR BASE_DIRECTORY ${CMAKE_INSTALL_PREFIX})
|
|
||||||
install(CODE "file(REMOVE_RECURSE \"$ENV{DESTDIR}${ABSOLUTE_MODULE_DIR}\")")
|
install(CODE "file(REMOVE_RECURSE \"$ENV{DESTDIR}${ABSOLUTE_MODULE_DIR}\")")
|
||||||
|
|
||||||
# Only process the CPack section if we have CPack
|
# Only process the CPack section if we have CPack
|
||||||
@@ -289,6 +299,7 @@ endif()
|
|||||||
add_subdirectory(data)
|
add_subdirectory(data)
|
||||||
add_subdirectory(docs)
|
add_subdirectory(docs)
|
||||||
add_subdirectory(language)
|
add_subdirectory(language)
|
||||||
|
add_subdirectory(vendor)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(modules)
|
add_subdirectory(modules)
|
||||||
add_subdirectory(include)
|
add_subdirectory(include)
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ Run_Build_System () {
|
|||||||
CMAKE_COMMAND="${CMAKE_COMMAND} -D EXTRA_LIBS=$EXTRA_LIB_DIRS"
|
CMAKE_COMMAND="${CMAKE_COMMAND} -D EXTRA_LIBS=$EXTRA_LIB_DIRS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$EXTRA_CONFIG_ARGS" != "" ] ; then
|
||||||
|
CMAKE_COMMAND="${CMAKE_COMMAND} $EXTRA_CONFIG_ARGS"
|
||||||
|
fi
|
||||||
|
|
||||||
echo $CMAKE_COMMAND
|
echo $CMAKE_COMMAND
|
||||||
$CMAKE_COMMAND
|
$CMAKE_COMMAND
|
||||||
|
|
||||||
|
|||||||
@@ -1296,7 +1296,7 @@ module
|
|||||||
/** The memory hardness in kibibytes of the Argon2 algorithm. Defaults to
|
/** The memory hardness in kibibytes of the Argon2 algorithm. Defaults to
|
||||||
* 128 mebibytes.
|
* 128 mebibytes.
|
||||||
*/
|
*/
|
||||||
#memory_cost = 121072
|
#memory_cost = 131072
|
||||||
|
|
||||||
/** The time hardness (iterations) of the Argon2 algorithm. Defaults to 3.
|
/** The time hardness (iterations) of the Argon2 algorithm. Defaults to 3.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ privilege
|
|||||||
rank = 10
|
rank = 10
|
||||||
level = 3
|
level = 3
|
||||||
flag = "f"
|
flag = "f"
|
||||||
|
flag_migration_requires = "ACCESS_CHANGE"
|
||||||
xop = "VOP"
|
xop = "VOP"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,6 +497,7 @@ privilege
|
|||||||
rank = 110
|
rank = 110
|
||||||
level = 4
|
level = 4
|
||||||
flag = "h"
|
flag = "h"
|
||||||
|
flag_migration_requires = "HALFOP"
|
||||||
xop = "HOP"
|
xop = "HOP"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,6 +640,7 @@ privilege
|
|||||||
rank = 220
|
rank = 220
|
||||||
level = 5
|
level = 5
|
||||||
flag = "o"
|
flag = "o"
|
||||||
|
flag_migration_requires = "OP"
|
||||||
xop = "AOP"
|
xop = "AOP"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,6 +713,7 @@ privilege
|
|||||||
rank = 300
|
rank = 300
|
||||||
level = 10
|
level = 10
|
||||||
flag = "a"
|
flag = "a"
|
||||||
|
flag_migration_requires = "PROTECT"
|
||||||
xop = "SOP"
|
xop = "SOP"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,6 +857,7 @@ privilege
|
|||||||
rank = 60
|
rank = 60
|
||||||
level = 3
|
level = 3
|
||||||
flag = "v"
|
flag = "v"
|
||||||
|
flag_migration_requires = "VOICE"
|
||||||
xop = "VOP"
|
xop = "VOP"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -201,6 +201,19 @@ module
|
|||||||
{
|
{
|
||||||
name = "hs_request"
|
name = "hs_request"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How long after a requested vhost is activated does a user have to wait
|
||||||
|
* before they can request a new vhost. Defaults to 24 hours.
|
||||||
|
*/
|
||||||
|
#activationcooldown = 24h
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How long after a requested vhost is rejected does a user have to wait
|
||||||
|
* before they can request a new vhost. Defaults to 24 hours.
|
||||||
|
*/
|
||||||
|
#rejectioncooldown = 24h
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If set, Anope will send a memo to the user requesting a vhost when it's been
|
* If set, Anope will send a memo to the user requesting a vhost when it's been
|
||||||
* approved or rejected.
|
* approved or rejected.
|
||||||
|
|||||||
@@ -120,6 +120,10 @@ module
|
|||||||
* - ns_keep_modes: Enables keepmodes, which retains user modes across sessions
|
* - ns_keep_modes: Enables keepmodes, which retains user modes across sessions
|
||||||
* - protect: Protects the registered nickname from use by unidentified users.
|
* - protect: Protects the registered nickname from use by unidentified users.
|
||||||
* - ns_stats: Enable Chanstats for newly registered nicks
|
* - ns_stats: Enable Chanstats for newly registered nicks
|
||||||
|
* - ns_flexible: Set FLEXIBLE as layout for messages from services (can not be set at the same
|
||||||
|
* time as ns_monospace)
|
||||||
|
* - ns_monospace: Set MONOSPACE as layout for messages from services (can not be set as the same
|
||||||
|
* time as ns_flexible)
|
||||||
*
|
*
|
||||||
* This directive is optional, if left blank, the options will default to memo_signon, and
|
* This directive is optional, if left blank, the options will default to memo_signon, and
|
||||||
* memo_receive. If you really want no defaults, use "none" by itself as the option.
|
* memo_receive. If you really want no defaults, use "none" by itself as the option.
|
||||||
@@ -128,9 +132,9 @@ module
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The minimum length of time between consecutive uses of NickServ's REGISTER command. This
|
* 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.
|
* The length of time before a nick's registration expires.
|
||||||
@@ -416,6 +420,12 @@ module
|
|||||||
{
|
{
|
||||||
name = "ns_group"
|
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.
|
* The maximum number of nicks allowed in a group.
|
||||||
*
|
*
|
||||||
@@ -741,6 +751,9 @@ command { service = "NickServ"; name = "SASET LAYOUT"; command = "nickserv/saset
|
|||||||
*
|
*
|
||||||
* misc_description: A description of the command to show in the help.
|
* misc_description: A description of the command to show in the help.
|
||||||
* misc_title: A human-readable description of the stored data.
|
* 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
|
* misc_pattern: If defined then a regex pattern (using the engine specified
|
||||||
* in <options:regexengine> to validate the data with).
|
* in <options:regexengine> to validate the data with).
|
||||||
* misc_syntax: If defined then the syntax to show in the help output and, if
|
* misc_syntax: If defined then the syntax to show in the help output and, if
|
||||||
|
|||||||
+3
-3
@@ -3,7 +3,7 @@ and other useful contributions to Anope. These people, ordered by the number of
|
|||||||
contributions they have made, are:
|
contributions they have made, are:
|
||||||
|
|
||||||
* Adam <adam@anope.org>
|
* Adam <adam@anope.org>
|
||||||
* Sadie Powell <sadie@witchery.services>
|
* Sadie Powell <sadie@sadiepowell.dev>
|
||||||
* Robin Burchell <w00t@inspircd.org>
|
* Robin Burchell <w00t@inspircd.org>
|
||||||
* Naram Qashat <cyberbotx@anope.org>
|
* Naram Qashat <cyberbotx@anope.org>
|
||||||
* Pieter Bootsma <geniusdex@anope.org>
|
* Pieter Bootsma <geniusdex@anope.org>
|
||||||
@@ -20,8 +20,8 @@ contributions they have made, are:
|
|||||||
* Adam Kramer <ribosome@anope.org>
|
* Adam Kramer <ribosome@anope.org>
|
||||||
* Attila Molnar <attilamolnar@hush.com>
|
* Attila Molnar <attilamolnar@hush.com>
|
||||||
* Michael Wobst <wobst.michael@web.de>
|
* Michael Wobst <wobst.michael@web.de>
|
||||||
* Matt Schatz <genius3000@g3k.solutions>
|
|
||||||
* PeGaSuS <droider.pc@gmail.com>
|
* PeGaSuS <droider.pc@gmail.com>
|
||||||
|
* Matt Schatz <genius3000@g3k.solutions>
|
||||||
* Mark Summers <mark@goopler.net>
|
* Mark Summers <mark@goopler.net>
|
||||||
* Daniel Vassdal <shutter@canternet.org>
|
* Daniel Vassdal <shutter@canternet.org>
|
||||||
* MatthewM <mcm@they-got.us>
|
* MatthewM <mcm@they-got.us>
|
||||||
@@ -49,6 +49,7 @@ contributions they have made, are:
|
|||||||
* Robert Scheck <robert@fedoraproject.org>
|
* Robert Scheck <robert@fedoraproject.org>
|
||||||
* Dennis Friis <peavey@inspircd.org>
|
* Dennis Friis <peavey@inspircd.org>
|
||||||
* Filippo Cortigiani <simos@simosnap.org>
|
* Filippo Cortigiani <simos@simosnap.org>
|
||||||
|
* KidProtect
|
||||||
* Michał Zegan <webczat_200@poczta.onet.pl>
|
* Michał Zegan <webczat_200@poczta.onet.pl>
|
||||||
* AlphaTech <alphat3ch@icloud.com>
|
* AlphaTech <alphat3ch@icloud.com>
|
||||||
* Austin Ellis <siniStar@IRC4Fun.net>
|
* Austin Ellis <siniStar@IRC4Fun.net>
|
||||||
@@ -71,7 +72,6 @@ contributions they have made, are:
|
|||||||
* Jason Foster <retsofaj@gmail.com>
|
* Jason Foster <retsofaj@gmail.com>
|
||||||
* Jeremy <jeremy@ssnet.ca>
|
* Jeremy <jeremy@ssnet.ca>
|
||||||
* Josh Soref
|
* Josh Soref
|
||||||
* KidProtect
|
|
||||||
* KindOne <ineedalifetoday@live.com>
|
* KindOne <ineedalifetoday@live.com>
|
||||||
* linuxdaemon
|
* linuxdaemon
|
||||||
* Mantas Mikulėnas <grawity@gmail.com>
|
* Mantas Mikulėnas <grawity@gmail.com>
|
||||||
|
|||||||
+17
-1
@@ -1,6 +1,22 @@
|
|||||||
# Anope Change Log
|
# Anope Change Log
|
||||||
|
|
||||||
## Anope 2.1.24 (unreleased)
|
## 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
|
### Breaking Changes
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -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
|
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!
|
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
|
If you have finished a language file translation and you want others to use it, please file a pull request on GitHub.
|
||||||
or send it to team@anope.org (don't forget to mention clearly your (nick)name, your email and the language name).
|
|
||||||
You'll of course get full credit for it.
|
You'll of course get full credit for it.
|
||||||
|
|
||||||
3) Using languages with modules
|
3) Using languages with modules
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual ChanAccess *Create() = 0;
|
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:
|
private:
|
||||||
static std::list<AccessProvider *> Providers;
|
static std::list<AccessProvider *> Providers;
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -362,10 +362,6 @@ namespace Anope
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
using unordered_map = std::unordered_map<string, T, hash_ci, compare>;
|
using unordered_map = std::unordered_map<string, T, hash_ci, compare>;
|
||||||
|
|
||||||
#if !REPRODUCIBLE_BUILD
|
|
||||||
static const char *const compiled = __TIME__ " " __DATE__;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** The time Anope started.
|
/** The time Anope started.
|
||||||
*/
|
*/
|
||||||
extern CoreExport time_t StartTime;
|
extern CoreExport time_t StartTime;
|
||||||
|
|||||||
+13
-10
@@ -18,6 +18,7 @@
|
|||||||
#include "regchannel.h"
|
#include "regchannel.h"
|
||||||
#include "users.h"
|
#include "users.h"
|
||||||
#include "opertype.h"
|
#include "opertype.h"
|
||||||
|
#include "miscutils.h"
|
||||||
|
|
||||||
namespace Configuration
|
namespace Configuration
|
||||||
{
|
{
|
||||||
@@ -26,14 +27,15 @@ namespace Configuration
|
|||||||
friend class Configuration::Conf;
|
friend class Configuration::Conf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef Anope::map<Anope::string> item_map;
|
typedef Anope::map<Anope::string> ItemMap;
|
||||||
typedef Anope::multimap<Block> block_map;
|
typedef Anope::multimap<Block> BlockMap;
|
||||||
|
typedef Anope::iterator_range<BlockMap::const_iterator> BlockList;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Anope::string name;
|
Anope::string name;
|
||||||
item_map items;
|
ItemMap items;
|
||||||
block_map blocks;
|
BlockMap blocks;
|
||||||
int linenum;
|
unsigned linenum;
|
||||||
|
|
||||||
/* Represents a missing tag. */
|
/* Represents a missing tag. */
|
||||||
static Block EmptyBlock;
|
static Block EmptyBlock;
|
||||||
@@ -41,9 +43,10 @@ namespace Configuration
|
|||||||
public:
|
public:
|
||||||
Block(const Anope::string &);
|
Block(const Anope::string &);
|
||||||
const Anope::string &GetName() const;
|
const Anope::string &GetName() const;
|
||||||
int CountBlock(const Anope::string &name) const;
|
size_t CountBlock(const Anope::string &name) const;
|
||||||
const Block &GetBlock(const Anope::string &name, int num = 0) const;
|
BlockList GetBlocks(const Anope::string &name) const;
|
||||||
Block *GetMutableBlock(const Anope::string &name, int num = 0);
|
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
|
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);
|
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;
|
template<> CoreExport const Anope::string Block::Get(const Anope::string &tag, const Anope::string &def) const;
|
||||||
@@ -85,7 +88,7 @@ namespace Configuration
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/** Replaces defined variables within a string. */
|
/** 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:
|
public:
|
||||||
/* options:readtimeout */
|
/* options:readtimeout */
|
||||||
|
|||||||
@@ -142,10 +142,6 @@ namespace Language
|
|||||||
#define CHAN_ACCESS_LEVEL_RANGE _("Access level must be between %d and %d inclusive.")
|
#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_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_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_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_INFO_HEADER _("Information about channel \002%s\002:")
|
||||||
#define CHAN_LIMIT_EXCEEDED _("You have already exceeded your limit of \002%d\002 channels.")
|
#define CHAN_LIMIT_EXCEEDED _("You have already exceeded your limit of \002%d\002 channels.")
|
||||||
|
|||||||
@@ -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); }
|
||||||
|
};
|
||||||
@@ -194,12 +194,13 @@ namespace DNS
|
|||||||
/** Used to time out the query, xalls OnError and lets the TimerManager
|
/** Used to time out the query, xalls OnError and lets the TimerManager
|
||||||
* delete this request.
|
* delete this request.
|
||||||
*/
|
*/
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
Log(LOG_DEBUG_2) << "Resolver: timeout for query " << this->name;
|
Log(LOG_DEBUG_2) << "Resolver: timeout for query " << this->name;
|
||||||
Query rr(*this);
|
Query rr(*this);
|
||||||
rr.error = ERROR_TIMEDOUT;
|
rr.error = ERROR_TIMEDOUT;
|
||||||
this->OnError(&rr);
|
this->OnError(&rr);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -173,4 +173,14 @@ public:
|
|||||||
* @param attributes The attributes to modify
|
* @param attributes The attributes to modify
|
||||||
*/
|
*/
|
||||||
virtual void Modify(LDAPInterface *i, const Anope::string &base, LDAPMods &attributes) = 0;
|
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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
#define NICKSERV_AJOIN_LIST_EXT "ajoinlist"
|
||||||
|
|
||||||
|
struct AJoinEntry;
|
||||||
|
|
||||||
|
struct AJoinList
|
||||||
|
: Serialize::Checker<std::vector<AJoinEntry *> >
|
||||||
|
{
|
||||||
|
AJoinList(Extensible *) : Serialize::Checker<std::vector<AJoinEntry *> >("AJoinEntry") { }
|
||||||
|
virtual ~AJoinList() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AJoinEntry final
|
||||||
|
: Serializable
|
||||||
|
{
|
||||||
|
Serialize::Reference<NickCore> owner;
|
||||||
|
Anope::string channel;
|
||||||
|
Anope::string key;
|
||||||
|
|
||||||
|
AJoinEntry(Extensible *) : Serializable("AJoinEntry") { }
|
||||||
|
|
||||||
|
~AJoinEntry() override
|
||||||
|
{
|
||||||
|
auto *channels = owner->GetExt<AJoinList>(NICKSERV_AJOIN_LIST_EXT);
|
||||||
|
if (channels)
|
||||||
|
{
|
||||||
|
auto it = std::find((*channels)->begin(), (*channels)->end(), this);
|
||||||
|
if (it != (*channels)->end())
|
||||||
|
(*channels)->erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
+9
-1
@@ -58,6 +58,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual bool Parse(const Anope::string &message, Anope::map<Anope::string> &tags, Anope::string &source, Anope::string &command, std::vector<Anope::string> ¶ms);
|
virtual bool Parse(const Anope::string &message, Anope::map<Anope::string> &tags, Anope::string &source, Anope::string &command, std::vector<Anope::string> ¶ms);
|
||||||
|
|
||||||
|
/* Populates the tags that should be sent on all messages.
|
||||||
|
* @param tags The location to store tags.
|
||||||
|
* @param source Source of the message.
|
||||||
|
* @param command Command name.
|
||||||
|
* @param params Any extra parameters.
|
||||||
|
*/
|
||||||
|
virtual void PopulateTags(Anope::map<Anope::string> &tags, const MessageSource &source, const Anope::string &command, const std::vector<Anope::string> ¶ms);
|
||||||
|
|
||||||
/* Formats an outgoing message so it can be sent to the IRC server.
|
/* Formats an outgoing message so it can be sent to the IRC server.
|
||||||
* @param message The location to store the formatted message.
|
* @param message The location to store the formatted message.
|
||||||
* @param tags IRCv3 message tags.
|
* @param tags IRCv3 message tags.
|
||||||
@@ -279,7 +287,7 @@ public:
|
|||||||
virtual void SendSVSHold(const Anope::string &, time_t) { }
|
virtual void SendSVSHold(const Anope::string &, time_t) { }
|
||||||
virtual void SendSVSHoldDel(const Anope::string &) { }
|
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) { }
|
virtual void SendSWhoisDel(const MessageSource &source, User *target, const Anope::string &tag, const Anope::string &message) { }
|
||||||
|
|
||||||
/** Introduces a server to the uplink
|
/** Introduces a server to the uplink
|
||||||
|
|||||||
@@ -79,6 +79,12 @@ namespace Anope
|
|||||||
*/
|
*/
|
||||||
extern CoreExport Anope::string FormatCTCP(const Anope::string &name, const Anope::string &body = "");
|
extern CoreExport Anope::string FormatCTCP(const Anope::string &name, const Anope::string &body = "");
|
||||||
|
|
||||||
|
/** Formats a date/time as an IS0 8601 timestamp.
|
||||||
|
* @param ts UNIX timestamp to format.
|
||||||
|
* @param ms Number of milliseconds to format.
|
||||||
|
*/
|
||||||
|
extern CoreExport Anope::string FormatISO8601(time_t ts, unsigned long long ms);
|
||||||
|
|
||||||
/** Parses a CTCP message received from a client.
|
/** Parses a CTCP message received from a client.
|
||||||
* @param text The raw message to parse.
|
* @param text The raw message to parse.
|
||||||
* @param name The location to store the name of the CTCP.
|
* @param name The location to store the name of the CTCP.
|
||||||
|
|||||||
+3
-14
@@ -31,23 +31,17 @@ private:
|
|||||||
*/
|
*/
|
||||||
time_t secs;
|
time_t secs;
|
||||||
|
|
||||||
/** True if this is a repeating timer
|
|
||||||
*/
|
|
||||||
bool repeat;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructor, initializes the triggering time
|
/** Constructor, initializes the triggering time
|
||||||
* @param time_from_now The number of seconds from now to trigger 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(time_t time_from_now, bool repeating = false);
|
Timer(time_t time_from_now);
|
||||||
|
|
||||||
/** Constructor, initializes the triggering time
|
/** Constructor, initializes the triggering time
|
||||||
* @param creator The creator of the timer
|
* @param creator The creator of the timer
|
||||||
* @param time_from_now The number of seconds from now to trigger 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
|
/** Destructor, removes the timer from the list
|
||||||
*/
|
*/
|
||||||
@@ -63,11 +57,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
time_t GetTimer() const;
|
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
|
/** Set the interval between ticks
|
||||||
* @paramt t The new interval
|
* @paramt t The new interval
|
||||||
*/
|
*/
|
||||||
@@ -86,7 +75,7 @@ public:
|
|||||||
/** Called when the timer ticks
|
/** Called when the timer ticks
|
||||||
* This should be overridden with something useful
|
* 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.
|
/** This class manages sets of Timers, and triggers them at their defined times.
|
||||||
|
|||||||
+17
-2
@@ -18,6 +18,8 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "sysconf.h"
|
||||||
|
|
||||||
static std::string get_git_hash(const std::string &git_dir)
|
static std::string get_git_hash(const std::string &git_dir)
|
||||||
{
|
{
|
||||||
std::fstream fd;
|
std::fstream fd;
|
||||||
@@ -78,14 +80,18 @@ static bool read_version_sh(const std::string &version_sh, std::map<std::string,
|
|||||||
|
|
||||||
static bool write_build_h(const std::string &buildh, const std::string &git_version)
|
static bool write_build_h(const std::string &buildh, const std::string &git_version)
|
||||||
{
|
{
|
||||||
std::fstream fd(buildh.c_str(), std::ios::in);
|
std::fstream fd;
|
||||||
|
|
||||||
std::string build = "#define BUILD 1";
|
std::string build = "#define BUILD 1";
|
||||||
|
|
||||||
|
#if !REPRODUCIBLE_BUILD
|
||||||
|
fd.open(buildh.c_str(), std::ios::in);
|
||||||
|
|
||||||
if (fd.is_open())
|
if (fd.is_open())
|
||||||
{
|
{
|
||||||
for (std::string filebuf; getline(fd, filebuf);)
|
for (std::string filebuf; getline(fd, filebuf);)
|
||||||
{
|
{
|
||||||
if (!filebuf.find("#define BUILD"))
|
if (!filebuf.find("#define BUILD\t"))
|
||||||
{
|
{
|
||||||
size_t tab = filebuf.find(' ');
|
size_t tab = filebuf.find(' ');
|
||||||
|
|
||||||
@@ -101,6 +107,8 @@ static bool write_build_h(const std::string &buildh, const std::string &git_vers
|
|||||||
}
|
}
|
||||||
|
|
||||||
fd.clear();
|
fd.clear();
|
||||||
|
#endif
|
||||||
|
|
||||||
fd.open(buildh.c_str(), std::ios::out);
|
fd.open(buildh.c_str(), std::ios::out);
|
||||||
if (!fd.is_open())
|
if (!fd.is_open())
|
||||||
{
|
{
|
||||||
@@ -111,6 +119,13 @@ static bool write_build_h(const std::string &buildh, const std::string &git_vers
|
|||||||
fd << "/* This file is automatically generated by version.cpp - do not edit it! */" << std::endl
|
fd << "/* This file is automatically generated by version.cpp - do not edit it! */" << std::endl
|
||||||
<< "#pragma once" << std::endl
|
<< "#pragma once" << std::endl
|
||||||
<< build << std::endl;
|
<< build << std::endl;
|
||||||
|
#if !REPRODUCIBLE_BUILD
|
||||||
|
auto time_now = time(NULL);
|
||||||
|
auto *local_tm = localtime(&time_now);
|
||||||
|
char buffer[100];
|
||||||
|
strftime(buffer, sizeof(buffer), "%a %b %e %Y %T %Z", local_tm);
|
||||||
|
fd << "#define BUILD_DATE \"" << buffer << "\"" << std::endl;
|
||||||
|
#endif
|
||||||
if (!git_version.empty())
|
if (!git_version.empty())
|
||||||
fd << "#define VERSION_GIT \"" << git_version << "\"" << std::endl;
|
fd << "#define VERSION_GIT \"" << git_version << "\"" << std::endl;
|
||||||
fd.close();
|
fd.close();
|
||||||
|
|||||||
+42
-24
@@ -16,13 +16,13 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Anope\n"
|
"Project-Id-Version: Anope\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-04-26 18:25+0100\n"
|
"POT-Creation-Date: 2026-05-21 11:52+0100\n"
|
||||||
"PO-Revision-Date: 2026-04-26 18:25+0100\n"
|
"PO-Revision-Date: 2026-05-21 11:52+0100\n"
|
||||||
"Last-Translator: Sadie Powell <sadie@witchery.services>\n"
|
"Last-Translator: Sadie Powell <sadie@sadiepowell.dev>\n"
|
||||||
"Language-Team: English\n"
|
"Language-Team: English\n"
|
||||||
"Language: en_US\n"
|
"Language: en_US\n"
|
||||||
"MIME-Version: 1.0\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"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 3.4.2\n"
|
"X-Generator: Poedit 3.4.2\n"
|
||||||
@@ -129,7 +129,12 @@ msgstr ""
|
|||||||
msgid "%s already exists on the EXCEPTION list."
|
msgid "%s already exists on the EXCEPTION list."
|
||||||
msgstr ""
|
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
|
#, c-format
|
||||||
msgid "%s can not be migrated to the %s access system because they have privileges that you do not."
|
msgid "%s can not be migrated to the %s access system because they have privileges that you do not."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -215,7 +220,7 @@ msgstr ""
|
|||||||
msgid "%s has been joined to %s."
|
msgid "%s has been joined to %s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../include/language.h
|
#: ../modules/chanserv/cs_flags.cpp
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%s has been migrated to the %s access system."
|
msgid "%s has been migrated to the %s access system."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -428,14 +433,21 @@ msgstr ""
|
|||||||
msgid "%s will now permanently be ignored."
|
msgid "%s will now permanently be ignored."
|
||||||
msgstr ""
|
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
|
#, c-format
|
||||||
msgid "%u entry can not be migrated to the %s access system because they have privileges that you do not."
|
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."
|
msgid_plural "%u entries can not be migrated to the %s access system because they have privileges that you do not."
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
|
||||||
#: ../include/language.h
|
#: ../modules/chanserv/cs_flags.cpp
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%u entry has been migrated to the %s access system."
|
msgid "%u entry has been migrated to the %s access system."
|
||||||
msgid_plural "%u entries have been migrated to the %s access system."
|
msgid_plural "%u entries have been migrated to the %s access system."
|
||||||
@@ -2475,10 +2487,7 @@ msgid "Bans a given nick or mask on a channel"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../modules/chanserv/cs_ban.cpp
|
#: ../modules/chanserv/cs_ban.cpp
|
||||||
msgid ""
|
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."
|
||||||
"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."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../modules/chanserv/cs_enforce.cpp
|
#: ../modules/chanserv/cs_enforce.cpp
|
||||||
@@ -2671,6 +2680,11 @@ msgstr ""
|
|||||||
msgid "Bot won't kick for repeats anymore."
|
msgid "Bot won't kick for repeats anymore."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../src/access.cpp
|
||||||
|
#, c-format
|
||||||
|
msgid "By default, the %s command is limited to:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../modules/operserv/os_info.cpp
|
#: ../modules/operserv/os_info.cpp
|
||||||
msgid "CLEAR target"
|
msgid "CLEAR target"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -4000,6 +4014,10 @@ msgstr ""
|
|||||||
msgid "Fixed layout"
|
msgid "Fixed layout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../modules/chanserv/cs_flags.cpp
|
||||||
|
msgid "Flag"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../modules/chanserv/cs_flags.cpp
|
#: ../modules/chanserv/cs_flags.cpp
|
||||||
msgid "Flags"
|
msgid "Flags"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -4307,10 +4325,7 @@ msgid "Kicks a specified nick from a channel"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../modules/chanserv/cs_kick.cpp
|
#: ../modules/chanserv/cs_kick.cpp
|
||||||
msgid ""
|
msgid "Kicks a specified nick from a channel. Channel founders can also specify masks."
|
||||||
"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."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../modules/operserv/os_kill.cpp
|
#: ../modules/operserv/os_kill.cpp
|
||||||
@@ -6896,18 +6911,12 @@ msgstr ""
|
|||||||
|
|
||||||
#: ../modules/chanserv/cs_invite.cpp
|
#: ../modules/chanserv/cs_invite.cpp
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
msgid "Tells %s to invite you or an optionally specified nick into the given channel."
|
||||||
"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."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../modules/chanserv/cs_unban.cpp
|
#: ../modules/chanserv/cs_unban.cpp
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid ""
|
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."
|
||||||
"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."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../modules/operserv/os_jupe.cpp
|
#: ../modules/operserv/os_jupe.cpp
|
||||||
@@ -7234,6 +7243,11 @@ msgstr ""
|
|||||||
msgid "The registration confirmation code you specified for %s is incorrect."
|
msgid "The registration confirmation code you specified for %s is incorrect."
|
||||||
msgstr ""
|
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
|
#: ../modules/nickserv/ns_info.cpp
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "The services access status of %s will now be hidden from %s INFO displays."
|
msgid "The services access status of %s will now be hidden from %s INFO displays."
|
||||||
@@ -7990,6 +8004,10 @@ msgstr ""
|
|||||||
msgid "Word"
|
msgid "Word"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../modules/chanserv/cs_xop.cpp
|
||||||
|
msgid "XOP"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../modules/nickserv/ns_group.cpp
|
#: ../modules/nickserv/ns_group.cpp
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "You are already a member of the account of %s."
|
msgid "You are already a member of the account of %s."
|
||||||
|
|||||||
+2001
-13
File diff suppressed because it is too large
Load Diff
+2000
-12
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,6 @@ find ../ \
|
|||||||
-print0 | sort -z | xargs -0 -I {} \
|
-print0 | sort -z | xargs -0 -I {} \
|
||||||
xgettext \
|
xgettext \
|
||||||
--language=C++ \
|
--language=C++ \
|
||||||
--sort-output \
|
|
||||||
--default-domain=Anope \
|
--default-domain=Anope \
|
||||||
--join-existing \
|
--join-existing \
|
||||||
--output=anope.pot \
|
--output=anope.pot \
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ macro(inline_cmake TARGET FILE)
|
|||||||
set(CODE "${CODE}\n${CLEAN_LINE}")
|
set(CODE "${CODE}\n${CLEAN_LINE}")
|
||||||
endif()
|
endif()
|
||||||
elseif(LINE MATCHES "^/// BEGIN CMAKE$")
|
elseif(LINE MATCHES "^/// BEGIN CMAKE$")
|
||||||
message(STATUS "Executing inline CMake code for ${TARGET}")
|
message(DEBUG "Executing inline CMake code for ${TARGET}")
|
||||||
set(IN_CODE ON)
|
set(IN_CODE ON)
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
@@ -77,6 +77,12 @@ macro(build_module SRC MODULE_SRC)
|
|||||||
PREFIX ""
|
PREFIX ""
|
||||||
SUFFIX ""
|
SUFFIX ""
|
||||||
)
|
)
|
||||||
|
list(LENGTH MODULE_SRC MODULE_SRC_COUNT)
|
||||||
|
if(MODULE_SRC_COUNT LESS_EQUAL 1)
|
||||||
|
set_target_properties(${SO} PROPERTIES
|
||||||
|
UNITY_BUILD OFF
|
||||||
|
)
|
||||||
|
endif()
|
||||||
add_dependencies(${SO} ${PROGRAM_NAME})
|
add_dependencies(${SO} ${PROGRAM_NAME})
|
||||||
if(HAVE_LOCALIZATION)
|
if(HAVE_LOCALIZATION)
|
||||||
add_dependencies(${SO} module_language)
|
add_dependencies(${SO} module_language)
|
||||||
|
|||||||
@@ -1030,11 +1030,11 @@ class BanDataPurger final
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BanDataPurger(Module *o)
|
BanDataPurger(Module *o)
|
||||||
: Timer(o, 300, true)
|
: Timer(o, 300)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
Log(LOG_DEBUG) << "bs_main: Running bandata purger";
|
Log(LOG_DEBUG) << "bs_main: Running bandata purger";
|
||||||
|
|
||||||
@@ -1048,6 +1048,7 @@ public:
|
|||||||
c->Shrink<BanData>("bandata");
|
c->Shrink<BanData>("bandata");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -92,11 +92,12 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
Channel *c = Channel::Find(chname);
|
Channel *c = Channel::Find(chname);
|
||||||
if (c)
|
if (c)
|
||||||
c->RemoveMode(NULL, "BAN", mask);
|
c->RemoveMode(NULL, "BAN", mask);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -82,10 +82,10 @@ public:
|
|||||||
/** Called when the delay is up
|
/** Called when the delay is up
|
||||||
* @param The current time
|
* @param The current time
|
||||||
*/
|
*/
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
if (!c)
|
if (!c)
|
||||||
return;
|
return false; // Dead channel.
|
||||||
|
|
||||||
/* In the event we don't part */
|
/* In the event we don't part */
|
||||||
c->RemoveMode(NULL, "SECRET");
|
c->RemoveMode(NULL, "SECRET");
|
||||||
@@ -101,6 +101,8 @@ public:
|
|||||||
/* If someone has rejoined this channel in the meantime, don't part the bot */
|
/* If someone has rejoined this channel in the meantime, don't part the bot */
|
||||||
else if (c->users.size() <= 1)
|
else if (c->users.size() <= 1)
|
||||||
c->ci->bi->Part(c);
|
c->ci->bi->Part(c);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,13 @@ public:
|
|||||||
{
|
{
|
||||||
return new AccessChanAccess(this);
|
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;
|
AccessAccessProvider *AccessAccessProvider::me;
|
||||||
|
|
||||||
@@ -956,10 +963,8 @@ public:
|
|||||||
{
|
{
|
||||||
defaultLevels.clear();
|
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");
|
const Anope::string &pname = priv.Get<const Anope::string>("name");
|
||||||
|
|
||||||
Privilege *p = PrivilegeManager::FindPrivilege(pname);
|
Privilege *p = PrivilegeManager::FindPrivilege(pname);
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ private:
|
|||||||
Anope::string mode;
|
Anope::string mode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
bool ticked = false;
|
||||||
|
|
||||||
TempBan(time_t seconds, Channel *c, const Anope::string &banmask, const Anope::string &mod)
|
TempBan(time_t seconds, Channel *c, const Anope::string &banmask, const Anope::string &mod)
|
||||||
: Timer(me, seconds)
|
: Timer(me, seconds)
|
||||||
, channel(c->name)
|
, channel(c->name)
|
||||||
@@ -51,11 +53,17 @@ public:
|
|||||||
&& bmask == this->mask;
|
&& 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);
|
Channel *c = Channel::Find(this->channel);
|
||||||
if (c)
|
if (c)
|
||||||
c->RemoveMode(NULL, mode, this->mask);
|
c->RemoveMode(NULL, mode, this->mask);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -264,11 +272,12 @@ public:
|
|||||||
source.Reply(_(
|
source.Reply(_(
|
||||||
"Bans a given nick or mask on a channel. An optional expiry may "
|
"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 "
|
"be given to cause services to remove the ban after a set amount "
|
||||||
"of time."
|
"of time. Channel founders may ban masks."
|
||||||
"\n\n"
|
|
||||||
"By default, limited to AOPs or those with level 5 access "
|
|
||||||
"and above on the channel. Channel founders may ban masks."
|
|
||||||
));
|
));
|
||||||
|
|
||||||
|
source.Reply(" ");
|
||||||
|
AccessProvider::SendAccess(source, "BAN");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -290,7 +299,7 @@ public:
|
|||||||
{
|
{
|
||||||
for (const auto *tempban : tempbans)
|
for (const auto *tempban : tempbans)
|
||||||
{
|
{
|
||||||
if (tempban->Matches(c, cmode, param))
|
if (!tempban->ticked && tempban->Matches(c, cmode, param))
|
||||||
{
|
{
|
||||||
delete tempban;
|
delete tempban;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -299,11 +299,7 @@ public:
|
|||||||
{
|
{
|
||||||
Anope::map<Anope::string> tags;
|
Anope::map<Anope::string> tags;
|
||||||
if (timestamp)
|
if (timestamp)
|
||||||
{
|
tags["time"] = Anope::FormatISO8601(message->when, 0);
|
||||||
char timebuf[32];
|
|
||||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S.000Z", gmtime(&message->when));
|
|
||||||
tags["time"] = timebuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (u->ShouldPrivmsg())
|
if (u->ShouldPrivmsg())
|
||||||
IRCD->SendContextPrivmsg(c->ci->WhoSends(), u, c, message->message, tags);
|
IRCD->SendContextPrivmsg(c->ci->WhoSends(), u, c, message->message, tags);
|
||||||
|
|||||||
@@ -14,7 +14,15 @@
|
|||||||
|
|
||||||
#include "module.h"
|
#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 std::map<Anope::string, char> defaultFlags;
|
||||||
|
static Anope::map<Anope::string> migrationRequires;
|
||||||
|
|
||||||
class FlagsChanAccess final
|
class FlagsChanAccess final
|
||||||
: public ChanAccess
|
: public ChanAccess
|
||||||
@@ -76,6 +84,13 @@ public:
|
|||||||
{
|
{
|
||||||
return new FlagsChanAccess(this);
|
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;
|
FlagsAccessProvider *FlagsAccessProvider::ap;
|
||||||
|
|
||||||
@@ -303,8 +318,8 @@ class CommandCSFlags final
|
|||||||
return;
|
return;
|
||||||
auto *access = anope_dynamic_static_cast<FlagsChanAccess *>(provider->Create());
|
auto *access = anope_dynamic_static_cast<FlagsChanAccess *>(provider->Create());
|
||||||
access->SetMask(mask, ci);
|
access->SetMask(mask, ci);
|
||||||
access->creator = source.GetNick();
|
access->creator = source.GetNick();
|
||||||
access->description = current ? current->description : description;
|
access->description = current && description.empty() ? current->description : description;
|
||||||
access->last_seen = current ? current->last_seen : 0;
|
access->last_seen = current ? current->last_seen : 0;
|
||||||
access->created = Anope::CurTime;
|
access->created = Anope::CurTime;
|
||||||
access->flags = current_flags;
|
access->flags = current_flags;
|
||||||
@@ -411,10 +426,9 @@ class CommandCSFlags final
|
|||||||
void DoMigrate(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms)
|
void DoMigrate(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms)
|
||||||
{
|
{
|
||||||
auto override = false;
|
auto override = false;
|
||||||
const auto source_access = source.AccessFor(ci);
|
|
||||||
|
|
||||||
unsigned migrated = 0, notmigrated = 0;
|
unsigned migrated = 0, notmigratable = 0, notmigrated = 0;
|
||||||
Anope::string migratedmask, notmigratedmask;
|
Anope::string migratedmask, notmigratablemask, notmigratedmask;
|
||||||
const auto &entry = params.size() > 2 ? params[2] : "*";
|
const auto &entry = params.size() > 2 ? params[2] : "*";
|
||||||
for (auto idx = ci->GetAccessCount(); idx > 0; --idx)
|
for (auto idx = ci->GetAccessCount(); idx > 0; --idx)
|
||||||
{
|
{
|
||||||
@@ -428,34 +442,52 @@ class CommandCSFlags final
|
|||||||
std::set<char> newflags;
|
std::set<char> newflags;
|
||||||
for (auto &[priv, flag] : defaultFlags)
|
for (auto &[priv, flag] : defaultFlags)
|
||||||
{
|
{
|
||||||
if (access->HasPriv(priv))
|
if (!access->HasPriv(priv))
|
||||||
continue; // Source doesn't have this flag.
|
continue; // Source doesn't have this flag.
|
||||||
|
|
||||||
// Check that the source has access to set this entry.
|
// 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 (!override && !source_access.HasPriv(priv) && !source_access.founder)
|
||||||
{
|
{
|
||||||
if (!source.HasPriv("chanserv/access/modify"))
|
if (!source.HasPriv("chanserv/access/modify"))
|
||||||
{
|
{
|
||||||
notmigrated++;
|
notmigrated++;
|
||||||
notmigratedmask = access->Mask();
|
notmigratedmask = access->Mask();
|
||||||
|
Log(LOG_DEBUG) << source.GetNick() << " does not have the access to migrate " << access->Mask() << " to flags";
|
||||||
continue; // No privs
|
continue; // No privs
|
||||||
}
|
}
|
||||||
|
|
||||||
override = true;
|
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);
|
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++;
|
migrated++;
|
||||||
migratedmask = access->Mask();
|
migratedmask = access->Mask();
|
||||||
|
|
||||||
auto *newaccess = anope_dynamic_static_cast<FlagsChanAccess *>(FlagsAccessProvider::ap->Create());
|
auto *newaccess = anope_dynamic_static_cast<FlagsChanAccess *>(FlagsAccessProvider::ap->Create());
|
||||||
newaccess->SetMask(access->Mask(), ci);
|
newaccess->SetMask(access->Mask(), ci);
|
||||||
|
newaccess->created = access->created;
|
||||||
newaccess->creator = access->creator;
|
newaccess->creator = access->creator;
|
||||||
newaccess->description = access->description;
|
newaccess->description = access->description;
|
||||||
newaccess->created = access->created;
|
|
||||||
newaccess->flags = newflags;
|
newaccess->flags = newflags;
|
||||||
|
newaccess->last_seen = access->last_seen;
|
||||||
|
|
||||||
ci->EraseAccess(idx - 1);
|
ci->EraseAccess(idx - 1);
|
||||||
FOREACH_MOD(OnAccessDel, (ci, source, access, true));
|
FOREACH_MOD(OnAccessDel, (ci, source, access, true));
|
||||||
@@ -468,18 +500,23 @@ class CommandCSFlags final
|
|||||||
if (migrated == 1)
|
if (migrated == 1)
|
||||||
{
|
{
|
||||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to migrate " << migratedmask;
|
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)
|
else if (migrated > 1)
|
||||||
{
|
{
|
||||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to migrate " << migrated << " access entries";
|
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)
|
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)
|
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)
|
void DoClear(CommandSource &source, ChannelInfo *ci)
|
||||||
@@ -624,10 +661,8 @@ public:
|
|||||||
{
|
{
|
||||||
defaultFlags.clear();
|
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");
|
const Anope::string &pname = priv.Get<const Anope::string>("name");
|
||||||
|
|
||||||
Privilege *p = PrivilegeManager::FindPrivilege(pname);
|
Privilege *p = PrivilegeManager::FindPrivilege(pname);
|
||||||
@@ -638,6 +673,10 @@ public:
|
|||||||
if (value.empty())
|
if (value.empty())
|
||||||
continue;
|
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];
|
defaultFlags[p->name] = value[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,11 +95,12 @@ public:
|
|||||||
source.Reply(_(
|
source.Reply(_(
|
||||||
"Tells %s to invite you or an optionally specified "
|
"Tells %s to invite you or an optionally specified "
|
||||||
"nick into the given channel."
|
"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.service->nick.c_str());
|
||||||
|
|
||||||
|
source.Reply(" ");
|
||||||
|
AccessProvider::SendAccess(source, "INVITE");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -134,12 +134,11 @@ public:
|
|||||||
{
|
{
|
||||||
this->SendSyntax(source);
|
this->SendSyntax(source);
|
||||||
source.Reply(" ");
|
source.Reply(" ");
|
||||||
source.Reply(_(
|
source.Reply(_("Kicks a specified nick from a channel. Channel founders can also specify masks."));
|
||||||
"Kicks a specified nick from a channel."
|
|
||||||
"\n\n"
|
source.Reply(" ");
|
||||||
"By default, limited to AOPs or those with level 5 access "
|
AccessProvider::SendAccess(source, "KICK");
|
||||||
"and above on the channel. Channel founders can also specify masks."
|
|
||||||
));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -331,10 +331,8 @@ public:
|
|||||||
const auto &block = conf.GetModule(this);
|
const auto &block = conf.GetModule(this);
|
||||||
defaults.clear();
|
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;
|
LogDefault ld;
|
||||||
|
|
||||||
ld.service = def.Get<const Anope::string>("service");
|
ld.service = def.Get<const Anope::string>("service");
|
||||||
|
|||||||
@@ -999,10 +999,8 @@ public:
|
|||||||
{
|
{
|
||||||
modes.clear();
|
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"),
|
const Anope::string &cname = block.Get<const Anope::string>("name"),
|
||||||
&cmd = block.Get<const Anope::string>("command");
|
&cmd = block.Get<const Anope::string>("command");
|
||||||
|
|
||||||
|
|||||||
@@ -268,9 +268,9 @@ public:
|
|||||||
void OnReload(Configuration::Conf &conf) override
|
void OnReload(Configuration::Conf &conf) override
|
||||||
{
|
{
|
||||||
command_data.clear();
|
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")
|
if (block.Get<const Anope::string>("command") != "chanserv/set/misc")
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@@ -128,11 +128,12 @@ public:
|
|||||||
"user from entering the given channel. If no channel is "
|
"user from entering the given channel. If no channel is "
|
||||||
"given, all bans affecting you in channels you have access "
|
"given, all bans affecting you in channels you have access "
|
||||||
"in are removed."
|
"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.service->nick.c_str());
|
||||||
|
|
||||||
|
source.Reply(" ");
|
||||||
|
AccessProvider::SendAccess(source, "UNBAN");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -100,6 +100,19 @@ public:
|
|||||||
{
|
{
|
||||||
return new XOPChanAccess(this);
|
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
|
class CommandCSXOP final
|
||||||
@@ -675,9 +688,8 @@ public:
|
|||||||
order.clear();
|
order.clear();
|
||||||
permissions.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");
|
const Anope::string &pname = block.Get<const Anope::string>("name");
|
||||||
|
|
||||||
Privilege *p = PrivilegeManager::FindPrivilege(pname);
|
Privilege *p = PrivilegeManager::FindPrivilege(pname);
|
||||||
@@ -691,9 +703,8 @@ public:
|
|||||||
permissions[xop].push_back(pname);
|
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"),
|
const Anope::string &cname = block.Get<const Anope::string>("name"),
|
||||||
&cserv = block.Get<const Anope::string>("command");
|
&cserv = block.Get<const Anope::string>("command");
|
||||||
if (cname.empty() || cserv != "chanserv/xop")
|
if (cname.empty() || cserv != "chanserv/xop")
|
||||||
|
|||||||
@@ -353,14 +353,16 @@ class MChanstats final
|
|||||||
"(nick_, '', 'total'), (nick_, '', 'monthly'),"
|
"(nick_, '', 'total'), (nick_, '', 'monthly'),"
|
||||||
"(nick_, '', 'weekly'), (nick_, '', 'daily');"
|
"(nick_, '', 'weekly'), (nick_, '', 'daily');"
|
||||||
"END IF;"
|
"END IF;"
|
||||||
|
"SET @echan = chan_;"
|
||||||
|
"SET @enick = nick_;"
|
||||||
"SET @update_query = CONCAT('UPDATE `" + prefix + "chanstats` SET line=line+', line_, ',"
|
"SET @update_query = CONCAT('UPDATE `" + prefix + "chanstats` SET line=line+', line_, ',"
|
||||||
"letters=letters+', letters_, ' , words=words+', words_, ', actions=actions+', actions_, ', "
|
"letters=letters+', letters_, ' , words=words+', words_, ', actions=actions+', actions_, ', "
|
||||||
"smileys_happy=smileys_happy+', sm_h_, ', smileys_sad=smileys_sad+', sm_s_, ', "
|
"smileys_happy=smileys_happy+', sm_h_, ', smileys_sad=smileys_sad+', sm_s_, ', "
|
||||||
"smileys_other=smileys_other+', sm_o_, ', kicks=kicks+', kicks_, ', kicked=kicked+', kicked_, ', "
|
"smileys_other=smileys_other+', sm_o_, ', kicks=kicks+', kicks_, ', kicked=kicked+', kicked_, ', "
|
||||||
"modes=modes+', modes_, ', topics=topics+', topics_, ', ', time_ , '=', time_, '+', line_ ,' "
|
"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;"
|
"PREPARE update_query FROM @update_query;"
|
||||||
"EXECUTE update_query;"
|
"EXECUTE update_query using @enick, @echan;"
|
||||||
"DEALLOCATE PREPARE update_query;"
|
"DEALLOCATE PREPARE update_query;"
|
||||||
"END";
|
"END";
|
||||||
this->RunQuery(query);
|
this->RunQuery(query);
|
||||||
|
|||||||
+181
-24
@@ -12,6 +12,7 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "modules/botserv/badwords.h"
|
#include "modules/botserv/badwords.h"
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
#include "modules/chanserv/mode.h"
|
#include "modules/chanserv/mode.h"
|
||||||
#include "modules/hostserv/request.h"
|
#include "modules/hostserv/request.h"
|
||||||
#include "modules/info.h"
|
#include "modules/info.h"
|
||||||
|
#include "modules/nickserv/ajoin.h"
|
||||||
#include "modules/nickserv/cert.h"
|
#include "modules/nickserv/cert.h"
|
||||||
#include "modules/operserv/forbid.h"
|
#include "modules/operserv/forbid.h"
|
||||||
#include "modules/operserv/news.h"
|
#include "modules/operserv/news.h"
|
||||||
@@ -73,10 +75,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves the remaining data in the row.
|
// Retrieves the remaining data in the row.
|
||||||
Anope::string GetRemaining()
|
Anope::string GetRemaining(bool allow_empty = false)
|
||||||
{
|
{
|
||||||
auto remaining = stream.GetRemaining();
|
auto remaining = stream.GetRemaining();
|
||||||
if (remaining.empty())
|
if (remaining.empty() && !allow_empty)
|
||||||
error++;
|
error++;
|
||||||
return remaining;
|
return remaining;
|
||||||
}
|
}
|
||||||
@@ -120,14 +122,49 @@ struct ModeLockData final
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FounderSuccessorCandidate
|
||||||
|
{
|
||||||
|
// Flags ranked from founder down, for successor candidate ranking
|
||||||
|
static const Anope::string FLAG_PRIORITY;
|
||||||
|
|
||||||
|
NickCore* nc;
|
||||||
|
size_t priority;
|
||||||
|
time_t mtime;
|
||||||
|
|
||||||
|
FounderSuccessorCandidate()
|
||||||
|
: nc(nullptr)
|
||||||
|
, priority(99) // arbitrary; for log readability
|
||||||
|
, mtime(std::numeric_limits<std::time_t>::max())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FounderSuccessorCandidate(NickCore *c, const Anope::string &flags, time_t m)
|
||||||
|
: nc(c)
|
||||||
|
, priority(FLAG_PRIORITY.find_first_of(flags))
|
||||||
|
, mtime(m)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const FounderSuccessorCandidate& other)
|
||||||
|
{
|
||||||
|
return std::tie(priority, mtime) < std::tie(other.priority, other.mtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
FounderSuccessorCandidate& operator=(const FounderSuccessorCandidate& other) = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Anope::string FounderSuccessorCandidate::FLAG_PRIORITY = "FSRsaOoHh";
|
||||||
|
|
||||||
struct ChannelData final
|
struct ChannelData final
|
||||||
{
|
{
|
||||||
Anope::unordered_map<ChanServ::AutoKick *> akicks;
|
Anope::unordered_map<ChanServ::AutoKick *> akicks;
|
||||||
Anope::string bot;
|
Anope::string bot;
|
||||||
|
FounderSuccessorCandidate founder_candidate;
|
||||||
Anope::string info_adder;
|
Anope::string info_adder;
|
||||||
Anope::string info_message;
|
Anope::string info_message;
|
||||||
time_t info_ts = 0;
|
time_t info_ts = 0;
|
||||||
std::vector<ModeLockData> mlocks;
|
std::vector<ModeLockData> mlocks;
|
||||||
|
FounderSuccessorCandidate successor_candidate;
|
||||||
Anope::string suspend_by;
|
Anope::string suspend_by;
|
||||||
Anope::string suspend_reason;
|
Anope::string suspend_reason;
|
||||||
time_t suspend_ts = 0;
|
time_t suspend_ts = 0;
|
||||||
@@ -135,6 +172,7 @@ struct ChannelData final
|
|||||||
|
|
||||||
struct UserData final
|
struct UserData final
|
||||||
{
|
{
|
||||||
|
Anope::map<Anope::string> ajoins;
|
||||||
Anope::string info_adder;
|
Anope::string info_adder;
|
||||||
Anope::string info_message;
|
Anope::string info_message;
|
||||||
time_t info_ts = 0;
|
time_t info_ts = 0;
|
||||||
@@ -236,21 +274,40 @@ private:
|
|||||||
{ "XL", &DBAtheme::HandleXL },
|
{ "XL", &DBAtheme::HandleXL },
|
||||||
};
|
};
|
||||||
|
|
||||||
void ApplyAccess(Anope::string &in, char flag, Anope::string &out, std::initializer_list<const char*> privs)
|
static void RemoveAll(Anope::string& in, const Anope::string& unwanted)
|
||||||
{
|
{
|
||||||
for (const auto *priv : privs)
|
auto it = std::remove_if(in.begin(), in.end(), [&](char c){
|
||||||
|
return unwanted.find_first_of(c) != unwanted.npos;
|
||||||
|
});
|
||||||
|
in.erase(it, in.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool RemoveFirstOccurrence(Anope::string& in, char c)
|
||||||
|
{
|
||||||
|
auto pos = in.find(c);
|
||||||
|
if (pos != Anope::string::npos)
|
||||||
{
|
{
|
||||||
auto pos = in.find(flag);
|
in.erase(pos, 1);
|
||||||
if (pos != Anope::string::npos)
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ApplyAccess(Anope::string &in, char flag, Anope::string &out, std::initializer_list<const char*> privs)
|
||||||
|
{
|
||||||
|
const bool flag_found = RemoveFirstOccurrence(in, flag);
|
||||||
|
if (flag_found)
|
||||||
|
{
|
||||||
|
for (const auto *priv : privs)
|
||||||
{
|
{
|
||||||
auto privchar = flags.find(priv);
|
auto privchar = flags.find(priv);
|
||||||
if (privchar != flags.end())
|
if (privchar != flags.end())
|
||||||
{
|
{
|
||||||
out.push_back(privchar->second);
|
out.push_back(privchar->second);
|
||||||
in.erase(pos, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return flag_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyFlags(Extensible *ext, Anope::string &flags, char flag, const char *extname, bool extend = true)
|
void ApplyFlags(Extensible *ext, Anope::string &flags, char flag, const char *extname, bool extend = true)
|
||||||
@@ -609,16 +666,17 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto *data = chandata.Require(ci);
|
||||||
|
|
||||||
auto *nc = NickCore::Find(mask);
|
auto *nc = NickCore::Find(mask);
|
||||||
if (flags.find('b') != Anope::string::npos)
|
if (flags.find('b') != Anope::string::npos)
|
||||||
{
|
{
|
||||||
if (ChanServ::akick_service)
|
if (!ChanServ::akick_service)
|
||||||
{
|
{
|
||||||
Log(this) << "Unable to import channel akick for " << ci->name << " as cs_akick is not loaded";
|
Log(this) << "Unable to import channel akick for " << ci->name << " as cs_akick is not loaded";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *data = chandata.Require(ci);
|
|
||||||
if (nc)
|
if (nc)
|
||||||
data->akicks[mask] = ChanServ::akick_service->AddAKick(ci, setter, nc, "", modifiedtime, modifiedtime);
|
data->akicks[mask] = ChanServ::akick_service->AddAKick(ci, setter, nc, "", modifiedtime, modifiedtime);
|
||||||
else
|
else
|
||||||
@@ -638,7 +696,6 @@ private:
|
|||||||
ApplyAccess(flags, 'a', accessflags, { "AUTOPROTECT", "PROTECT", "PROTECTME" });
|
ApplyAccess(flags, 'a', accessflags, { "AUTOPROTECT", "PROTECT", "PROTECTME" });
|
||||||
ApplyAccess(flags, 'e', accessflags, { "GETKEY", "NOKICK", "UNBANME" });
|
ApplyAccess(flags, 'e', accessflags, { "GETKEY", "NOKICK", "UNBANME" });
|
||||||
ApplyAccess(flags, 'f', accessflags, { "ACCESS_CHANGE" });
|
ApplyAccess(flags, 'f', accessflags, { "ACCESS_CHANGE" });
|
||||||
ApplyAccess(flags, 'F', accessflags, { "FOUNDER" });
|
|
||||||
ApplyAccess(flags, 'H', accessflags, { "AUTOHALFOP" });
|
ApplyAccess(flags, 'H', accessflags, { "AUTOHALFOP" });
|
||||||
ApplyAccess(flags, 'h', accessflags, { "HALFOP", "HALFOPME" });
|
ApplyAccess(flags, 'h', accessflags, { "HALFOP", "HALFOPME" });
|
||||||
ApplyAccess(flags, 'i', accessflags, { "INVITE" });
|
ApplyAccess(flags, 'i', accessflags, { "INVITE" });
|
||||||
@@ -662,6 +719,35 @@ private:
|
|||||||
ci->AddAccess(access);
|
ci->AddAccess(access);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Atheme allows multiple founders and picks a successor based on rank if one is not explicitly assigned.
|
||||||
|
bool is_founder_candidate = RemoveFirstOccurrence(flags, 'F');
|
||||||
|
RemoveAll(flags, "SR");
|
||||||
|
|
||||||
|
FounderSuccessorCandidate current_candidate(nc, originalflags, modifiedtime);
|
||||||
|
|
||||||
|
if (nc && current_candidate < data->successor_candidate)
|
||||||
|
{
|
||||||
|
if (is_founder_candidate && current_candidate < data->founder_candidate)
|
||||||
|
{
|
||||||
|
Log(LOG_DEBUG) << ci->name << ": Demoting founder candidate ("
|
||||||
|
<< ( data->founder_candidate.nc ? data->founder_candidate.nc->display : "NONE" )
|
||||||
|
<< ", " << data->founder_candidate.priority
|
||||||
|
<< ") to successor; replacing with (" << current_candidate.nc->display
|
||||||
|
<< ", " << current_candidate.priority << ")";
|
||||||
|
data->successor_candidate = data->founder_candidate;
|
||||||
|
data->founder_candidate = current_candidate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(LOG_DEBUG) << ci->name << ": Replacing successor candidate ("
|
||||||
|
<< ( data->successor_candidate.nc ? data->successor_candidate.nc->display : "NONE" )
|
||||||
|
<< ", " << data->successor_candidate.priority
|
||||||
|
<< ") with (" << current_candidate.nc->display
|
||||||
|
<< ", " << current_candidate.priority << ")";
|
||||||
|
data->successor_candidate = current_candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (flags != "+")
|
if (flags != "+")
|
||||||
Log(this) << "Unable to convert channel access flags " << flags << " for " << mask << " on " << ci->name;
|
Log(this) << "Unable to convert channel access flags " << flags << " for " << mask << " on " << ci->name;
|
||||||
|
|
||||||
@@ -788,7 +874,7 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *xl = new XLine(user + "@" + host, setby, settime + duration, reason);
|
auto *xl = new XLine(user + "@" + host, setby, duration ? settime + duration : 0, reason);
|
||||||
xl->id = id;
|
xl->id = id;
|
||||||
sglinemgr->AddXLine(xl);
|
sglinemgr->AddXLine(xl);
|
||||||
return true;
|
return true;
|
||||||
@@ -879,6 +965,7 @@ private:
|
|||||||
ci->last_used = used;
|
ci->last_used = used;
|
||||||
|
|
||||||
// No equivalent: elnv
|
// No equivalent: elnv
|
||||||
|
RemoveFirstOccurrence(flags, 'v'); // verbose, com
|
||||||
ApplyFlags(ci, flags, 'h', "CS_NO_EXPIRE");
|
ApplyFlags(ci, flags, 'h', "CS_NO_EXPIRE");
|
||||||
ApplyFlags(ci, flags, 'k', "KEEPTOPIC");
|
ApplyFlags(ci, flags, 'k', "KEEPTOPIC");
|
||||||
ApplyFlags(ci, flags, 'o', "NOAUTOOP");
|
ApplyFlags(ci, flags, 'o', "NOAUTOOP");
|
||||||
@@ -985,6 +1072,10 @@ private:
|
|||||||
if (akick != data->akicks.end())
|
if (akick != data->akicks.end())
|
||||||
akick->second->reason = value;
|
akick->second->reason = value;
|
||||||
}
|
}
|
||||||
|
else if (key == "expires")
|
||||||
|
{
|
||||||
|
Log(this) << "Unable to set access expiration for " << mask << " on " << ci->name << ": unimplemented";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Log(this) << "Unknown channel access metadata for " << mask << " on " << ci->name << ": " << key << " = " << value;
|
Log(this) << "Unknown channel access metadata for " << mask << " on " << ci->name << ": " << key << " = " << value;
|
||||||
|
|
||||||
@@ -1146,10 +1237,7 @@ private:
|
|||||||
// MDU <display> <key> <value>
|
// MDU <display> <key> <value>
|
||||||
auto display = row.Get();
|
auto display = row.Get();
|
||||||
auto key = row.Get();
|
auto key = row.Get();
|
||||||
auto value = row.GetRemaining();
|
auto value = row.GetRemaining(true);
|
||||||
|
|
||||||
if (!row)
|
|
||||||
return row.LogError(this);
|
|
||||||
|
|
||||||
auto *nc = NickCore::Find(display);
|
auto *nc = NickCore::Find(display);
|
||||||
if (!nc)
|
if (!nc)
|
||||||
@@ -1160,7 +1248,17 @@ private:
|
|||||||
|
|
||||||
auto *data = userdata.Require(nc);
|
auto *data = userdata.Require(nc);
|
||||||
if (key == "private:autojoin")
|
if (key == "private:autojoin")
|
||||||
return true; // TODO
|
{
|
||||||
|
commasepstream autojoins(value, true);
|
||||||
|
for (Anope::string autojoin; autojoins.GetToken(autojoin); )
|
||||||
|
{
|
||||||
|
spacesepstream entry(autojoin);
|
||||||
|
Anope::string cname, ckey;
|
||||||
|
if (entry.GetToken(cname))
|
||||||
|
entry.GetToken(ckey);
|
||||||
|
data->ajoins[cname] = ckey;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (key == "private:doenforce")
|
else if (key == "private:doenforce")
|
||||||
data->protect = true;
|
data->protect = true;
|
||||||
else if (key == "private:enforcetime")
|
else if (key == "private:enforcetime")
|
||||||
@@ -1189,6 +1287,12 @@ private:
|
|||||||
data->info_adder = value;
|
data->info_adder = value;
|
||||||
else if (key == "private:mark:timestamp")
|
else if (key == "private:mark:timestamp")
|
||||||
data->info_ts = Anope::Convert<time_t>(value, 0);
|
data->info_ts = Anope::Convert<time_t>(value, 0);
|
||||||
|
else if (key == "private:sendpass:sender")
|
||||||
|
return HandleIgnoreMetadata(nc->display, key, value);
|
||||||
|
else if (key == "private:sendpass:timestamp")
|
||||||
|
return HandleIgnoreMetadata(nc->display, key, value);
|
||||||
|
else if (key == "private:setpass:key")
|
||||||
|
return HandleIgnoreMetadata(nc->display, key, value);
|
||||||
else if (key == "private:swhois")
|
else if (key == "private:swhois")
|
||||||
return HandleIgnoreMetadata(nc->display, key, value);
|
return HandleIgnoreMetadata(nc->display, key, value);
|
||||||
else if (key == "private:usercloak")
|
else if (key == "private:usercloak")
|
||||||
@@ -1410,6 +1514,7 @@ private:
|
|||||||
ApplyPassword(nc, flags, pass);
|
ApplyPassword(nc, flags, pass);
|
||||||
|
|
||||||
// No equivalent: bglmNQrS
|
// No equivalent: bglmNQrS
|
||||||
|
RemoveFirstOccurrence(flags, 'b'); // nick b flag is ephemeral, ignore
|
||||||
ApplyFlags(nc, flags, 'E', "PROTECT");
|
ApplyFlags(nc, flags, 'E', "PROTECT");
|
||||||
ApplyFlags(nc, flags, 'e', "MEMO_MAIL");
|
ApplyFlags(nc, flags, 'e', "MEMO_MAIL");
|
||||||
ApplyFlags(nc, flags, 'n', "NEVEROP");
|
ApplyFlags(nc, flags, 'n', "NEVEROP");
|
||||||
@@ -1499,7 +1604,7 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *xl = new XLine(nick, setby, settime + duration, reason);
|
auto *xl = new XLine(nick, setby, duration ? settime + duration : 0, reason);
|
||||||
xl->id = id;
|
xl->id = id;
|
||||||
sqlinemgr->AddXLine(xl);
|
sqlinemgr->AddXLine(xl);
|
||||||
return true;
|
return true;
|
||||||
@@ -1561,7 +1666,7 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *xl = new XLine(real, setby, settime + duration, reason);
|
auto *xl = new XLine(real, setby, duration ? settime + duration : 0, reason);
|
||||||
xl->id = id;
|
xl->id = id;
|
||||||
snlinemgr->AddXLine(xl);
|
snlinemgr->AddXLine(xl);
|
||||||
return true;
|
return true;
|
||||||
@@ -1584,9 +1689,8 @@ public:
|
|||||||
const auto &modconf = conf.GetModule(this);
|
const auto &modconf = conf.GetModule(this);
|
||||||
|
|
||||||
csmiscdata.clear();
|
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 &anope = data.Get<const Anope::string>("anope");
|
||||||
const auto &atheme = data.Get<const Anope::string>("atheme");
|
const auto &atheme = data.Get<const Anope::string>("atheme");
|
||||||
if (!anope.empty() && !atheme.empty())
|
if (!anope.empty() && !atheme.empty())
|
||||||
@@ -1594,9 +1698,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsmiscdata.clear();
|
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 &anope = data.Get<const Anope::string>("anope");
|
||||||
const auto &atheme = data.Get<const Anope::string>("atheme");
|
const auto &atheme = data.Get<const Anope::string>("atheme");
|
||||||
if (!anope.empty() && !atheme.empty())
|
if (!anope.empty() && !atheme.empty())
|
||||||
@@ -1604,9 +1707,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
flags.clear();
|
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 &name = priv.Get<const Anope::string>("name");
|
||||||
const Anope::string &value = priv.Get<const Anope::string>("flag");
|
const Anope::string &value = priv.Get<const Anope::string>("flag");
|
||||||
if (!name.empty() && !value.empty())
|
if (!name.empty() && !value.empty())
|
||||||
@@ -1684,6 +1786,12 @@ public:
|
|||||||
si.when = data->suspend_ts;
|
si.when = data->suspend_ts;
|
||||||
ci->Extend("CS_SUSPENDED", si);
|
ci->Extend("CS_SUSPENDED", si);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->founder_candidate.nc)
|
||||||
|
ci->SetFounder(data->founder_candidate.nc);
|
||||||
|
|
||||||
|
if (data->successor_candidate.nc)
|
||||||
|
ci->SetSuccessor(data->successor_candidate.nc);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &[_, nc] : *NickCoreList)
|
for (const auto &[_, nc] : *NickCoreList)
|
||||||
@@ -1692,6 +1800,55 @@ public:
|
|||||||
if (!data)
|
if (!data)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!data->ajoins.empty())
|
||||||
|
{
|
||||||
|
auto *channels = nc->Require<AJoinList>(NICKSERV_AJOIN_LIST_EXT);
|
||||||
|
if (channels)
|
||||||
|
{
|
||||||
|
for (const auto& ajoin : data->ajoins)
|
||||||
|
{
|
||||||
|
auto &channel = ajoin.first, &key = ajoin.second;
|
||||||
|
if (!key.empty())
|
||||||
|
{
|
||||||
|
Channel *c = Channel::Find(channel);
|
||||||
|
Anope::string k;
|
||||||
|
if (c && c->GetParam("KEY", k) && key != k)
|
||||||
|
{
|
||||||
|
Log(this) << "Skipping ajoin with incorrect key for channel " << channel
|
||||||
|
<< ", user " << nc->display;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IRCD->IsChannelValid(channel))
|
||||||
|
{
|
||||||
|
Log(this) << "Invalid ajoin channel " << channel << " for " << nc->display;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto it = std::find_if((*channels)->cbegin(), (*channels)->cend(), [&](const AJoinEntry* a){
|
||||||
|
return a->channel == channel;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it != (*channels)->cend())
|
||||||
|
{
|
||||||
|
Log(this) << "Skipping duplicate ajoin channel" << channel << " for " << nc->display;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto* entry = new AJoinEntry(nc);
|
||||||
|
entry->owner = nc;
|
||||||
|
entry->channel = channel;
|
||||||
|
entry->key = key;
|
||||||
|
(*channels)->push_back(entry); // ignore ajoinmax for non-disruptive migration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(this) << "Unable to convert autojoins for " << nc->display << " as ns_ajoin is not loaded";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!data->info_message.empty())
|
if (!data->info_message.empty())
|
||||||
{
|
{
|
||||||
auto *oil = nc->Require<OperInfoList>("operinfo");
|
auto *oil = nc->Require<OperInfoList>("operinfo");
|
||||||
|
|||||||
@@ -12,10 +12,14 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
/// BEGIN CMAKE
|
||||||
|
/// target_link_libraries(${SO} PRIVATE "vendored_yyjson")
|
||||||
|
/// END CMAKE
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
#include "yyjson/yyjson.c"
|
#include "yyjson/yyjson.h"
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
|
||||||
|
|||||||
+6
-5
@@ -534,8 +534,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Times out after a few seconds */
|
/* Times out after a few seconds */
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reply(Packet *p) override
|
void Reply(Packet *p) override
|
||||||
@@ -718,7 +719,7 @@ public:
|
|||||||
|
|
||||||
MyManager(Module *creator)
|
MyManager(Module *creator)
|
||||||
: Manager(creator)
|
: Manager(creator)
|
||||||
, Timer(300, true)
|
, Timer(300)
|
||||||
, serial(Anope::CurTime)
|
, serial(Anope::CurTime)
|
||||||
, cur_id(Anope::RandomNumber())
|
, cur_id(Anope::RandomNumber())
|
||||||
{
|
{
|
||||||
@@ -1011,7 +1012,7 @@ public:
|
|||||||
return serial;
|
return serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
Log(LOG_DEBUG_2) << "Resolver: Purging DNS cache";
|
Log(LOG_DEBUG_2) << "Resolver: Purging DNS cache";
|
||||||
|
|
||||||
@@ -1025,6 +1026,7 @@ public:
|
|||||||
if (req.created + static_cast<time_t>(req.ttl) < Anope::CurTime)
|
if (req.created + static_cast<time_t>(req.ttl) < Anope::CurTime)
|
||||||
this->cache.erase(it);
|
this->cache.erase(it);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -1093,9 +1095,8 @@ public:
|
|||||||
refresh = block.Get<int>("refresh", "3600");
|
refresh = block.Get<int>("refresh", "3600");
|
||||||
|
|
||||||
std::vector<std::pair<Anope::string, short> > notify;
|
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 nip = n.Get<Anope::string>("ip");
|
||||||
auto nport = n.Get<short>("port");
|
auto nport = n.Get<short>("port");
|
||||||
|
|
||||||
|
|||||||
+3
-6
@@ -126,9 +126,8 @@ public:
|
|||||||
this->add_to_akill = block.Get<bool>("add_to_akill", "yes");
|
this->add_to_akill = block.Get<bool>("add_to_akill", "yes");
|
||||||
|
|
||||||
this->blacklists.clear();
|
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 blacklist;
|
||||||
|
|
||||||
blacklist.name = bl.Get<Anope::string>("name");
|
blacklist.name = bl.Get<Anope::string>("name");
|
||||||
@@ -137,9 +136,8 @@ public:
|
|||||||
blacklist.bantime = bl.Get<time_t>("time", "4h");
|
blacklist.bantime = bl.Get<time_t>("time", "4h");
|
||||||
blacklist.reason = bl.Get<Anope::string>("reason");
|
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;
|
Blacklist::Reply r;
|
||||||
|
|
||||||
r.code = reply.Get<int>("code");
|
r.code = reply.Get<int>("code");
|
||||||
@@ -153,9 +151,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->exempts.clear();
|
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"));
|
this->exempts.insert(bl.Get<Anope::string>("ip"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,17 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
/// BEGIN CMAKE
|
||||||
|
/// target_link_libraries(${SO} PRIVATE "vendored_bcrypt")
|
||||||
|
/// END CMAKE
|
||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
#include "bcrypt/crypt_blowfish.c"
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "bcrypt/crypt_blowfish.h"
|
||||||
|
}
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "modules/encryption.h"
|
#include "modules/encryption.h"
|
||||||
|
|||||||
@@ -12,10 +12,17 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
/// BEGIN CMAKE
|
||||||
|
/// target_link_libraries(${SO} PRIVATE "vendored_md5")
|
||||||
|
/// END CMAKE
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "modules/encryption.h"
|
#include "modules/encryption.h"
|
||||||
|
|
||||||
#include "md5/md5.c"
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "md5/md5.h"
|
||||||
|
}
|
||||||
|
|
||||||
class MD5Context final
|
class MD5Context final
|
||||||
: public Encryption::Context
|
: public Encryption::Context
|
||||||
|
|||||||
@@ -12,10 +12,14 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
/// BEGIN CMAKE
|
||||||
|
/// target_link_libraries(${SO} PRIVATE "vendored_sha1")
|
||||||
|
/// END CMAKE
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "modules/encryption.h"
|
#include "modules/encryption.h"
|
||||||
|
|
||||||
#include "sha1/sha1.c"
|
#include "sha1/sha1.h"
|
||||||
|
|
||||||
class SHA1Context final
|
class SHA1Context final
|
||||||
: public Encryption::Context
|
: public Encryption::Context
|
||||||
|
|||||||
@@ -12,10 +12,14 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
/// BEGIN CMAKE
|
||||||
|
/// target_link_libraries(${SO} PRIVATE "vendored_sha2")
|
||||||
|
/// END CMAKE
|
||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
#include "sha2/sha2.c"
|
#include "sha2/sha2.h"
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "modules/encryption.h"
|
#include "modules/encryption.h"
|
||||||
|
|||||||
+76
-4
@@ -405,6 +405,80 @@ public:
|
|||||||
QueueRequest(mod);
|
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:
|
private:
|
||||||
void BuildReply(int res, LDAPRequest *req)
|
void BuildReply(int res, LDAPRequest *req)
|
||||||
{
|
{
|
||||||
@@ -560,7 +634,7 @@ public:
|
|||||||
{
|
{
|
||||||
const Anope::string &cname = it->first;
|
const Anope::string &cname = it->first;
|
||||||
LDAPService *s = it->second;
|
LDAPService *s = it->second;
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
++it;
|
++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");
|
const Anope::string &connname = ldap.Get<const Anope::string>("name", "ldap/main");
|
||||||
|
|
||||||
if (this->LDAPServices.find(connname) == this->LDAPServices.end())
|
if (this->LDAPServices.find(connname) == this->LDAPServices.end())
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ public:
|
|||||||
{
|
{
|
||||||
const Anope::string &cname = it->first;
|
const Anope::string &cname = it->first;
|
||||||
MySQLService *s = it->second;
|
MySQLService *s = it->second;
|
||||||
int i;
|
size_t i;
|
||||||
|
|
||||||
++it;
|
++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");
|
const Anope::string &connname = block.Get<const Anope::string>("name", "mysql/main");
|
||||||
|
|
||||||
if (this->MySQLServices.find(connname) == this->MySQLServices.end())
|
if (this->MySQLServices.find(connname) == this->MySQLServices.end())
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ public:
|
|||||||
{
|
{
|
||||||
const Anope::string &cname = it->first;
|
const Anope::string &cname = it->first;
|
||||||
SQLiteService *s = it->second;
|
SQLiteService *s = it->second;
|
||||||
int i, num;
|
size_t i, num;
|
||||||
++it;
|
++it;
|
||||||
|
|
||||||
for (i = 0, num = config.CountBlock("sqlite"); i < num; ++i)
|
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");
|
Anope::string connname = block.Get<const Anope::string>("name", "sqlite/main");
|
||||||
|
|
||||||
if (this->SQLiteServices.find(connname) == this->SQLiteServices.end())
|
if (this->SQLiteServices.find(connname) == this->SQLiteServices.end())
|
||||||
|
|||||||
@@ -331,10 +331,8 @@ public:
|
|||||||
throw ConfigException("Unable to find http reference, is httpd loaded?");
|
throw ConfigException("Unable to find http reference, is httpd loaded?");
|
||||||
|
|
||||||
xmlrpcinterface.tokens.clear();
|
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;
|
RPC::Token token;
|
||||||
token.token = block.Get<const Anope::string>("token");
|
token.token = block.Get<const Anope::string>("token");
|
||||||
if (!token.token.empty())
|
if (!token.token.empty())
|
||||||
|
|||||||
@@ -156,7 +156,12 @@ public:
|
|||||||
if (server)
|
if (server)
|
||||||
this->ServerGlobal(sender, server, false, line);
|
this->ServerGlobal(sender, server, false, line);
|
||||||
else
|
else
|
||||||
this->ServerGlobal(sender, Servers::GetUplink(), true, line);
|
{
|
||||||
|
auto* uplink = Servers::GetUplink();
|
||||||
|
if (!uplink)
|
||||||
|
return false;
|
||||||
|
this->ServerGlobal(sender, uplink, true, line);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,29 @@ namespace
|
|||||||
Anope::string validation_record;
|
Anope::string validation_record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SharedData final
|
||||||
|
{
|
||||||
|
// How long after a requested vhost is activated does a user have to wait before they can request a new vhost.
|
||||||
|
time_t activationcooldown = 0;
|
||||||
|
|
||||||
|
// How long after a requested vhost is rejected does a user have to wait before they can request a new vhost.
|
||||||
|
time_t rejectioncooldown = 0;
|
||||||
|
|
||||||
|
// How long should users have to wait between attempts at DNS validation.
|
||||||
|
time_t validationcooldown = 0;
|
||||||
|
|
||||||
|
// Extensible that stores the time a user had a vhost activated/rejected.
|
||||||
|
SerializableExtensibleItem<time_t> requestcooldown;
|
||||||
|
|
||||||
|
// The name of the DNS record used for validation.
|
||||||
|
Anope::string validationrecord;
|
||||||
|
|
||||||
|
SharedData(Module *mod)
|
||||||
|
: requestcooldown(mod, "HS_REQUEST_COOLDOWN")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct HostRequestImpl final
|
struct HostRequestImpl final
|
||||||
: HostServ::HostRequest
|
: HostServ::HostRequest
|
||||||
, Serializable
|
, Serializable
|
||||||
@@ -105,6 +128,7 @@ private:
|
|||||||
Command *command;
|
Command *command;
|
||||||
Reference<NickAlias> nickalias;
|
Reference<NickAlias> nickalias;
|
||||||
CommandSource source;
|
CommandSource source;
|
||||||
|
SharedData &data;
|
||||||
|
|
||||||
void HandleError(HostRequestImpl *hr)
|
void HandleError(HostRequestImpl *hr)
|
||||||
{
|
{
|
||||||
@@ -119,11 +143,12 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DNSHostResolver(Command *cmd, HostServ::HostRequest *hr, NickAlias *na, const CommandSource &src)
|
DNSHostResolver(Command *cmd, HostServ::HostRequest *hr, NickAlias *na, const CommandSource &src, SharedData &sd)
|
||||||
: Request(dnsmanager, cmd->module, hr->host, DNS::QUERY_TXT, false)
|
: Request(dnsmanager, cmd->module, hr->host, DNS::QUERY_TXT, false)
|
||||||
, command(cmd)
|
, command(cmd)
|
||||||
, nickalias(na)
|
, nickalias(na)
|
||||||
, source(src)
|
, source(src)
|
||||||
|
, data(sd)
|
||||||
{
|
{
|
||||||
hr->last_validation = Anope::CurTime;
|
hr->last_validation = Anope::CurTime;
|
||||||
Log(LOG_DEBUG) << "Checking " << hr->host << " for " << hr->validation_token;
|
Log(LOG_DEBUG) << "Checking " << hr->host << " for " << hr->validation_token;
|
||||||
@@ -171,6 +196,8 @@ public:
|
|||||||
|
|
||||||
source.Reply(_("VHost for %s has been validated using DNS."), na->nick.c_str());
|
source.Reply(_("VHost for %s has been validated using DNS."), na->nick.c_str());
|
||||||
Log(LOG_COMMAND, source, command) << "for " << na->nick << " for vhost " << hr->Mask();
|
Log(LOG_COMMAND, source, command) << "for " << na->nick << " for vhost " << hr->Mask();
|
||||||
|
|
||||||
|
data.requestcooldown.Set(na, Anope::CurTime + data.activationcooldown);
|
||||||
na->Shrink<HostRequestImpl>(HOSTSERV_HOST_REQUEST_EXT);
|
na->Shrink<HostRequestImpl>(HOSTSERV_HOST_REQUEST_EXT);
|
||||||
|
|
||||||
return; // We're done.
|
return; // We're done.
|
||||||
@@ -183,8 +210,13 @@ public:
|
|||||||
class CommandHSRequest final
|
class CommandHSRequest final
|
||||||
: public Command
|
: public Command
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
SharedData &data;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CommandHSRequest(Module *creator) : Command(creator, "hostserv/request", 1, 1)
|
CommandHSRequest(Module *creator, SharedData &sd)
|
||||||
|
: Command(creator, "hostserv/request", 1, 1)
|
||||||
|
, data(sd)
|
||||||
{
|
{
|
||||||
this->SetDesc(_("Request a vhost for your nick"));
|
this->SetDesc(_("Request a vhost for your nick"));
|
||||||
this->SetSyntax(_("vhost"));
|
this->SetSyntax(_("vhost"));
|
||||||
@@ -263,12 +295,25 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t send_delay = Config->GetModule("memoserv").Get<time_t>("senddelay");
|
time_t waituntil = 0;
|
||||||
if (Config->GetModule(this->owner).Get<bool>("memooper") && send_delay > 0 && u && u->lastmemosend + send_delay > Anope::CurTime)
|
|
||||||
{
|
{
|
||||||
auto waitperiod = (u->lastmemosend + send_delay) - Anope::CurTime;
|
// Check whether the user is on a request cooldown.
|
||||||
|
const auto *last_req = data.requestcooldown.Get(na);
|
||||||
|
if (last_req)
|
||||||
|
waituntil = *last_req;
|
||||||
|
}
|
||||||
|
if (Config->GetModule(this->owner).Get<bool>("memooper"))
|
||||||
|
{
|
||||||
|
// Check whether the user can send a memo to opers yet.
|
||||||
|
const auto send_delay = Config->GetModule("memoserv").Get<time_t>("senddelay");
|
||||||
|
if (send_delay > 0 && u && u->lastmemosend)
|
||||||
|
waituntil = std::max(waituntil, u->lastmemosend + send_delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waituntil && waituntil > Anope::CurTime)
|
||||||
|
{
|
||||||
|
const auto waitperiod = waituntil - Anope::CurTime;
|
||||||
source.Reply(_("Please wait %s before requesting a new vhost."), Anope::Duration(waitperiod, source.GetAccount()).c_str());
|
source.Reply(_("Please wait %s before requesting a new vhost."), Anope::Duration(waitperiod, source.GetAccount()).c_str());
|
||||||
u->lastmemosend = Anope::CurTime;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,8 +364,13 @@ public:
|
|||||||
class CommandHSActivate final
|
class CommandHSActivate final
|
||||||
: public Command
|
: public Command
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
SharedData &data;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CommandHSActivate(Module *creator) : Command(creator, "hostserv/activate", 1, 1)
|
CommandHSActivate(Module *creator, SharedData &sd)
|
||||||
|
: Command(creator, "hostserv/activate", 1, 1)
|
||||||
|
, data(sd)
|
||||||
{
|
{
|
||||||
this->SetDesc(_("Approve the requested vhost of a user"));
|
this->SetDesc(_("Approve the requested vhost of a user"));
|
||||||
this->SetSyntax(_("\037nick\037"));
|
this->SetSyntax(_("\037nick\037"));
|
||||||
@@ -348,6 +398,8 @@ public:
|
|||||||
|
|
||||||
source.Reply(_("VHost for %s has been activated."), na->nick.c_str());
|
source.Reply(_("VHost for %s has been activated."), na->nick.c_str());
|
||||||
Log(LOG_COMMAND, source, this) << "for " << na->nick << " for vhost " << (!req->ident.empty() ? req->ident + "@" : "") << req->host;
|
Log(LOG_COMMAND, source, this) << "for " << na->nick << " for vhost " << (!req->ident.empty() ? req->ident + "@" : "") << req->host;
|
||||||
|
|
||||||
|
data.requestcooldown.Set(na, Anope::CurTime + data.activationcooldown);
|
||||||
na->Shrink<HostRequestImpl>(HOSTSERV_HOST_REQUEST_EXT);
|
na->Shrink<HostRequestImpl>(HOSTSERV_HOST_REQUEST_EXT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -369,8 +421,13 @@ public:
|
|||||||
class CommandHSReject final
|
class CommandHSReject final
|
||||||
: public Command
|
: public Command
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
SharedData &data;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CommandHSReject(Module *creator) : Command(creator, "hostserv/reject", 1, 2)
|
CommandHSReject(Module *creator, SharedData &sd)
|
||||||
|
: Command(creator, "hostserv/reject", 1, 2)
|
||||||
|
, data(sd)
|
||||||
{
|
{
|
||||||
this->SetDesc(_("Reject the requested vhost of a user"));
|
this->SetDesc(_("Reject the requested vhost of a user"));
|
||||||
this->SetSyntax(_("\037nick\037 [\037reason\037]"));
|
this->SetSyntax(_("\037nick\037 [\037reason\037]"));
|
||||||
@@ -391,6 +448,7 @@ public:
|
|||||||
auto *req = HostRequestImpl::Get(na);
|
auto *req = HostRequestImpl::Get(na);
|
||||||
if (req)
|
if (req)
|
||||||
{
|
{
|
||||||
|
data.requestcooldown.Set(na, Anope::CurTime + data.rejectioncooldown);
|
||||||
na->Shrink<HostRequestImpl>(HOSTSERV_HOST_REQUEST_EXT);
|
na->Shrink<HostRequestImpl>(HOSTSERV_HOST_REQUEST_EXT);
|
||||||
|
|
||||||
if (Config->GetModule(this->owner).Get<bool>("memouser") && MemoServ::service)
|
if (Config->GetModule(this->owner).Get<bool>("memouser") && MemoServ::service)
|
||||||
@@ -481,11 +539,13 @@ public:
|
|||||||
class CommandHSValidate final
|
class CommandHSValidate final
|
||||||
: public Command
|
: public Command
|
||||||
{
|
{
|
||||||
public:
|
private:
|
||||||
time_t cooldown;
|
SharedData &data;
|
||||||
|
|
||||||
CommandHSValidate(Module *creator)
|
public:
|
||||||
|
CommandHSValidate(Module *creator, SharedData &sd)
|
||||||
: Command(creator, "hostserv/validate", 0)
|
: Command(creator, "hostserv/validate", 0)
|
||||||
|
, data(sd)
|
||||||
{
|
{
|
||||||
this->SetDesc(_("Validates a previously requested vhost using DNS"));
|
this->SetDesc(_("Validates a previously requested vhost using DNS"));
|
||||||
}
|
}
|
||||||
@@ -512,7 +572,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto next_validation = req->last_validation + cooldown;
|
auto next_validation = req->last_validation + data.validationcooldown;
|
||||||
if (req->last_validation && next_validation > Anope::CurTime)
|
if (req->last_validation && next_validation > Anope::CurTime)
|
||||||
{
|
{
|
||||||
source.Reply(_("You must wait for %s before trying DNS validation again."),
|
source.Reply(_("You must wait for %s before trying DNS validation again."),
|
||||||
@@ -526,7 +586,7 @@ public:
|
|||||||
if (!dnsmanager)
|
if (!dnsmanager)
|
||||||
throw SocketException("DNS is not available");
|
throw SocketException("DNS is not available");
|
||||||
|
|
||||||
res = new DNSHostResolver(this, req, na, source);
|
res = new DNSHostResolver(this, req, na, source, data);
|
||||||
dnsmanager->Process(res);
|
dnsmanager->Process(res);
|
||||||
}
|
}
|
||||||
catch (const SocketException &ex)
|
catch (const SocketException &ex)
|
||||||
@@ -553,8 +613,10 @@ public:
|
|||||||
class HSRequest final
|
class HSRequest final
|
||||||
: public Module
|
: public Module
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
SharedData data;
|
||||||
CommandHSRequest commandhsrequest;
|
CommandHSRequest commandhsrequest;
|
||||||
CommandHSActivate commandhsactive;
|
CommandHSActivate commandhsactivate;
|
||||||
CommandHSReject commandhsreject;
|
CommandHSReject commandhsreject;
|
||||||
CommandHSWaiting commandhswaiting;
|
CommandHSWaiting commandhswaiting;
|
||||||
CommandHSValidate commandhsvalidate;
|
CommandHSValidate commandhsvalidate;
|
||||||
@@ -564,11 +626,12 @@ class HSRequest final
|
|||||||
public:
|
public:
|
||||||
HSRequest(const Anope::string &modname, const Anope::string &creator)
|
HSRequest(const Anope::string &modname, const Anope::string &creator)
|
||||||
: Module(modname, creator, VENDOR)
|
: Module(modname, creator, VENDOR)
|
||||||
, commandhsrequest(this)
|
, data(this)
|
||||||
, commandhsactive(this)
|
, commandhsrequest(this, data)
|
||||||
, commandhsreject(this)
|
, commandhsactivate(this, data)
|
||||||
|
, commandhsreject(this, data)
|
||||||
, commandhswaiting(this)
|
, commandhswaiting(this)
|
||||||
, commandhsvalidate(this)
|
, commandhsvalidate(this, data)
|
||||||
, hostrequest(this, HOSTSERV_HOST_REQUEST_EXT)
|
, hostrequest(this, HOSTSERV_HOST_REQUEST_EXT)
|
||||||
{
|
{
|
||||||
if (!IRCD || !IRCD->CanSetVHost)
|
if (!IRCD || !IRCD->CanSetVHost)
|
||||||
@@ -578,7 +641,9 @@ public:
|
|||||||
void OnReload(Configuration::Conf &conf) override
|
void OnReload(Configuration::Conf &conf) override
|
||||||
{
|
{
|
||||||
const auto &block = conf.GetModule(this);
|
const auto &block = conf.GetModule(this);
|
||||||
commandhsvalidate.cooldown = block.Get<time_t>("validationcooldown", "5m");
|
data.activationcooldown = block.Get<time_t>("activationcooldown", "24h");
|
||||||
|
data.rejectioncooldown = block.Get<time_t>("rejectioncooldown", "24h");
|
||||||
|
data.validationcooldown = block.Get<time_t>("validationcooldown", "5m");
|
||||||
validation_record = block.Get<const Anope::string>("validationrecord", "anope-dns-validation");
|
validation_record = block.Get<const Anope::string>("validationrecord", "anope-dns-validation");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+4
-6
@@ -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)
|
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)
|
: Socket(-1, i.find(':') == Anope::string::npos ? AF_INET : AF_INET6)
|
||||||
, HTTP::Provider(c, n, i, p, s)
|
, HTTP::Provider(c, n, i, p, s)
|
||||||
, Timer(c, 10, true)
|
, Timer(c, 10)
|
||||||
, timeout(t)
|
, timeout(t)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
while (!this->clients.empty())
|
while (!this->clients.empty())
|
||||||
{
|
{
|
||||||
@@ -314,6 +314,7 @@ public:
|
|||||||
delete c;
|
delete c;
|
||||||
this->clients.pop_front();
|
this->clients.pop_front();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientSocket *OnAccept(int fd, const sockaddrs &addr) override
|
ClientSocket *OnAccept(int fd, const sockaddrs &addr) override
|
||||||
@@ -371,11 +372,8 @@ public:
|
|||||||
const auto &conf = config.GetModule(this);
|
const auto &conf = config.GetModule(this);
|
||||||
std::set<Anope::string> existing;
|
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");
|
const Anope::string &hname = block.Get<const Anope::string>("name", "httpd/main");
|
||||||
existing.insert(hname);
|
existing.insert(hname);
|
||||||
|
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ public:
|
|||||||
if (ii->admin_bind)
|
if (ii->admin_bind)
|
||||||
{
|
{
|
||||||
auto sf = Anope::Template(search_filter, {
|
auto sf = Anope::Template(search_filter, {
|
||||||
{ "account", ii->req->GetAccount() },
|
{ "account", ii->lprov->EscapeSF(ii->req->GetAccount()) },
|
||||||
{ "object_class", object_class },
|
{ "object_class", object_class },
|
||||||
});
|
});
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -310,7 +310,7 @@ public:
|
|||||||
attributes[3].name = this->password_attribute;
|
attributes[3].name = this->password_attribute;
|
||||||
attributes[3].values.push_back(pass);
|
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);
|
this->ldap->Add(&this->orinterface, new_dn, attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,13 +125,13 @@ public:
|
|||||||
if (!this->binddn.empty())
|
if (!this->binddn.empty())
|
||||||
{
|
{
|
||||||
auto bdn = Anope::Template(this->binddn, {
|
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());
|
this->ldap->Bind(NULL, bdn, this->password.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto af = Anope::Template(this->filter, {
|
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);
|
this->ldap->Search(new IdentifyInterface(this, u), this->basedn, af);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,16 +61,17 @@ public:
|
|||||||
return na;
|
return na;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
if (!u || !na || !NickServ::service)
|
if (!u || !na || !NickServ::service)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
/* If they identified or don't exist anymore, don't kill them. */
|
/* If they identified or don't exist anymore, don't kill them. */
|
||||||
if (u->Account() == na->nc || u->timestamp > ts)
|
if (u->Account() == na->nc || u->timestamp > ts)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
NickServ::service->Collide(u, na);
|
NickServ::service->Collide(u, na);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -90,10 +91,11 @@ public:
|
|||||||
n->Extend<bool>("HELD");
|
n->Extend<bool>("HELD");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
if (na)
|
if (na)
|
||||||
na->Shrink<bool>("HELD");
|
na->Shrink<bool>("HELD");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -133,8 +135,9 @@ public:
|
|||||||
NickServReleases.erase(this->nick);
|
NickServReleases.erase(this->nick);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -13,34 +13,15 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
#include "modules/nickserv/ajoin.h"
|
||||||
|
|
||||||
struct AJoinEntry;
|
struct AJoinListImpl final : public AJoinList
|
||||||
|
|
||||||
struct AJoinList final
|
|
||||||
: Serialize::Checker<std::vector<AJoinEntry *> >
|
|
||||||
{
|
{
|
||||||
AJoinList(Extensible *) : Serialize::Checker<std::vector<AJoinEntry *> >("AJoinEntry") { }
|
AJoinListImpl(Extensible * e) : AJoinList(e) { }
|
||||||
~AJoinList();
|
~AJoinListImpl()
|
||||||
};
|
|
||||||
|
|
||||||
struct AJoinEntry final
|
|
||||||
: Serializable
|
|
||||||
{
|
|
||||||
Serialize::Reference<NickCore> owner;
|
|
||||||
Anope::string channel;
|
|
||||||
Anope::string key;
|
|
||||||
|
|
||||||
AJoinEntry(Extensible *) : Serializable("AJoinEntry") { }
|
|
||||||
|
|
||||||
~AJoinEntry() override
|
|
||||||
{
|
{
|
||||||
auto *channels = owner->GetExt<AJoinList>("ajoinlist");
|
for (const auto *ajoin : *(*this))
|
||||||
if (channels)
|
delete ajoin;
|
||||||
{
|
|
||||||
auto it = std::find((*channels)->begin(), (*channels)->end(), this);
|
|
||||||
if (it != (*channels)->end())
|
|
||||||
(*channels)->erase(it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -93,12 +74,6 @@ struct AJoinEntryType final
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AJoinList::~AJoinList()
|
|
||||||
{
|
|
||||||
for (const auto *ajoin : *(*this))
|
|
||||||
delete ajoin;
|
|
||||||
}
|
|
||||||
|
|
||||||
class CommandNSAJoin final
|
class CommandNSAJoin final
|
||||||
: public Command
|
: public Command
|
||||||
{
|
{
|
||||||
@@ -321,7 +296,7 @@ class NSAJoin final
|
|||||||
: public Module
|
: public Module
|
||||||
{
|
{
|
||||||
CommandNSAJoin commandnsajoin;
|
CommandNSAJoin commandnsajoin;
|
||||||
ExtensibleItem<AJoinList> ajoinlist;
|
ExtensibleItem<AJoinListImpl> ajoinlist;
|
||||||
AJoinEntryType ajoinentry_type;
|
AJoinEntryType ajoinentry_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -164,12 +164,12 @@ public:
|
|||||||
if (newit != this->certs.end())
|
if (newit != this->certs.end())
|
||||||
{
|
{
|
||||||
// The cert we're upgrading to already exists.
|
// The cert we're upgrading to already exists.
|
||||||
delete *newit;
|
delete *oldit;
|
||||||
this->certs.erase(newit);
|
this->certs.erase(oldit);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *cert = *newit;
|
auto *cert = *oldit;
|
||||||
cert->fingerprint = newentry;
|
cert->fingerprint = newentry;
|
||||||
certmap[newentry] = cert;
|
certmap[newentry] = cert;
|
||||||
FOREACH_MOD(OnNickAddCert, (this->nc, cert));
|
FOREACH_MOD(OnNickAddCert, (this->nc, cert));
|
||||||
|
|||||||
@@ -145,8 +145,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
NickAlias *target, *na = NickAlias::Find(source.GetNick());
|
NickAlias *target, *na = NickAlias::Find(source.GetNick());
|
||||||
time_t reg_delay = Config->GetModule("nickserv").Get<time_t>("regdelay");
|
auto &modconf = Config->GetModule(this->owner);
|
||||||
auto maxaliases = Config->GetModule(this->owner).Get<unsigned>("maxaliases");
|
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)))
|
if (!(target = NickAlias::Find(nick)))
|
||||||
source.Reply(NICK_X_NOT_REGISTERED, nick.c_str());
|
source.Reply(NICK_X_NOT_REGISTERED, nick.c_str());
|
||||||
else if (user && Anope::CurTime < user->lastnickreg + reg_delay)
|
else if (user && Anope::CurTime < user->lastnickreg + reg_delay)
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
time_t nickregdelay = Config->GetModule(this->owner).Get<time_t>("nickregdelay");
|
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)
|
if (u && !u->HasMode("OPER") && nickregdelay && Anope::CurTime - u->timestamp < nickregdelay)
|
||||||
{
|
{
|
||||||
auto waitperiod = (u->timestamp + nickregdelay) - Anope::CurTime;
|
auto waitperiod = (u->timestamp + nickregdelay) - Anope::CurTime;
|
||||||
@@ -275,18 +275,28 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *passcode = nc->GetExt<Anope::string>("passcode");
|
if (!nc->HasExt("UNCONFIRMED"))
|
||||||
if (!passcode)
|
|
||||||
{
|
{
|
||||||
source.Reply(_("There is no registration confirmation pending for %s."),
|
source.Reply(_("There is no registration confirmation pending for %s."),
|
||||||
na->nick.c_str());
|
na->nick.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!code.empty() && !code.equals_cs(*passcode))
|
|
||||||
|
if (!code.empty())
|
||||||
{
|
{
|
||||||
source.Reply(_("The registration confirmation code you specified for %s is incorrect."),
|
auto *passcode = nc->GetExt<Anope::string>("passcode");
|
||||||
na->nick.c_str());
|
if (passcode && !code.equals_cs(*passcode))
|
||||||
return;
|
{
|
||||||
|
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");
|
nc->Shrink<Anope::string>("passcode");
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public:
|
|||||||
|
|
||||||
SASLService(Module *o)
|
SASLService(Module *o)
|
||||||
: SASL::Service(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));
|
this->SendMessage(session, "M", buf.empty() ? "" : buf.substr(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
for (auto it = badpasswords.begin(); it != badpasswords.end(); )
|
for (auto it = badpasswords.begin(); it != badpasswords.end(); )
|
||||||
{
|
{
|
||||||
@@ -240,6 +240,7 @@ public:
|
|||||||
sessions.erase(uid);
|
sessions.erase(uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,14 +26,15 @@ struct CommandData final
|
|||||||
Anope::string pattern;
|
Anope::string pattern;
|
||||||
Anope::string syntax;
|
Anope::string syntax;
|
||||||
Anope::string title;
|
Anope::string title;
|
||||||
|
time_t priority = 0;
|
||||||
bool swhois = false;
|
bool swhois = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Anope::map<CommandData> command_data;
|
static Anope::map<CommandData> command_data;
|
||||||
|
|
||||||
|
|
||||||
struct NSMiscData;
|
struct NSMiscData;
|
||||||
static Anope::map<ExtensibleItem<NSMiscData> *> items;
|
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)
|
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 *nc = u->Account();
|
||||||
auto *data = nc ? ext->Get(nc) : nullptr;
|
auto *data = nc ? ext->Get(nc) : nullptr;
|
||||||
if (data)
|
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
|
else
|
||||||
IRCD->SendSWhoisDel(nickserv, u, name, "");
|
IRCD->SendSWhoisDel(nickserv, u, name, "");
|
||||||
}
|
}
|
||||||
@@ -327,9 +328,11 @@ public:
|
|||||||
void OnReload(Configuration::Conf &conf) override
|
void OnReload(Configuration::Conf &conf) override
|
||||||
{
|
{
|
||||||
command_data.clear();
|
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");
|
const Anope::string &cmd = block.Get<const Anope::string>("command");
|
||||||
if (cmd != "nickserv/set/misc" && cmd != "nickserv/saset/misc")
|
if (cmd != "nickserv/set/misc" && cmd != "nickserv/saset/misc")
|
||||||
continue;
|
continue;
|
||||||
@@ -341,7 +344,7 @@ public:
|
|||||||
|
|
||||||
// Force creation of the extension item.
|
// Force creation of the extension item.
|
||||||
const auto extname = GetAttribute(cname);
|
const auto extname = GetAttribute(cname);
|
||||||
GetItem(extname);
|
auto item = GetItem(extname);
|
||||||
|
|
||||||
auto &data = command_data[extname];
|
auto &data = command_data[extname];
|
||||||
if (cmd == "nickserv/saset/misc")
|
if (cmd == "nickserv/saset/misc")
|
||||||
@@ -350,12 +353,22 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default_priority += 1000;
|
||||||
|
|
||||||
data.set_description = desc;
|
data.set_description = desc;
|
||||||
data.pattern = block.Get<const Anope::string>("misc_pattern");
|
data.pattern = block.Get<const Anope::string>("misc_pattern");
|
||||||
data.syntax = block.Get<const Anope::string>("misc_syntax");
|
data.syntax = block.Get<const Anope::string>("misc_syntax");
|
||||||
data.title = block.Get<const Anope::string>("misc_title");
|
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");
|
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
|
void OnUserLogin(User *u) override
|
||||||
@@ -374,7 +387,7 @@ public:
|
|||||||
|
|
||||||
void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool) override
|
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);
|
NSMiscData *data = e->Get(na->nc);
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
for (unsigned i = 0; !show_blocks[i].empty(); ++i)
|
for (unsigned i = 0; !show_blocks[i].empty(); ++i)
|
||||||
{
|
{
|
||||||
const auto &block = Config->GetBlock(show_blocks[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());
|
ListFormatter lflist(source.GetAccount());
|
||||||
lflist.AddColumn(_("Name")).AddColumn(_("Value"));
|
lflist.AddColumn(_("Name")).AddColumn(_("Value"));
|
||||||
@@ -84,10 +84,9 @@ public:
|
|||||||
lflist.AddColumn(_("Module Name")).AddColumn(_("Name")).AddColumn(_("Value"));
|
lflist.AddColumn(_("Module Name")).AddColumn(_("Name")).AddColumn(_("Value"));
|
||||||
lflist.SetFlexible(_("\002{}{module_name}}:{name}\002 = {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 auto &items = block.GetItems();
|
||||||
const Configuration::Block::item_map &items = block.GetItems();
|
|
||||||
|
|
||||||
if (items.size() <= 1)
|
if (items.size() <= 1)
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ public:
|
|||||||
timeout = NULL;
|
timeout = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
if (DConfig.defaultlevel != level)
|
if (DConfig.defaultlevel != level)
|
||||||
{
|
{
|
||||||
@@ -146,6 +146,7 @@ public:
|
|||||||
|
|
||||||
runDefCon();
|
runDefCon();
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -529,10 +529,8 @@ public:
|
|||||||
fileforbids.clear();
|
fileforbids.clear();
|
||||||
|
|
||||||
const auto &modconf = conf.GetModule(this);
|
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 reasonstr = fileblock.Get<const Anope::string>("reason");
|
||||||
|
|
||||||
const auto typestr = fileblock.Get<const Anope::string>("type");
|
const auto typestr = fileblock.Get<const Anope::string>("type");
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ public:
|
|||||||
{
|
{
|
||||||
bool all = params.size() > 2 && params[2].equals_ci("ALL");
|
bool all = params.size() > 2 && params[2].equals_ci("ALL");
|
||||||
|
|
||||||
for (const auto &[mode, data] : c->GetModes())
|
auto cmodes = c->GetModes();
|
||||||
|
for (const auto &[mode, data] : cmodes)
|
||||||
c->RemoveMode(c->WhoSends(), mode, data.value, false);
|
c->RemoveMode(c->WhoSends(), mode, data.value, false);
|
||||||
|
|
||||||
if (!c)
|
if (!c)
|
||||||
|
|||||||
@@ -587,7 +587,7 @@ public:
|
|||||||
Uplink::Send(source, "SVSPART", u->GetUID(), chan);
|
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)
|
if (!IRCD->CanSendMultipleSWhois)
|
||||||
{
|
{
|
||||||
@@ -598,7 +598,7 @@ public:
|
|||||||
{
|
{
|
||||||
// New style SWHOIS.
|
// New style SWHOIS.
|
||||||
Uplink::Send("METADATA", target->GetUID(), "specialwhois", Anope::Format("+ @%s s %ld :%s",
|
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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,7 +734,7 @@ public:
|
|||||||
bool IsTagValid(const Anope::string &tname, const Anope::string &tvalue) override
|
bool IsTagValid(const Anope::string &tname, const Anope::string &tvalue) override
|
||||||
{
|
{
|
||||||
// InspIRCd accepts arbitrary message tags.
|
// InspIRCd accepts arbitrary message tags.
|
||||||
return true;
|
return Me->IsSynced();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -346,10 +346,10 @@ private:
|
|||||||
Uplink::Send("SENDUMODE", 'o', "From " + source.GetName() + ": " + buf);
|
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;
|
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
|
void SendSWhoisDel(const MessageSource &source, User *target, const Anope::string &tag, const Anope::string &message) override
|
||||||
|
|||||||
@@ -218,11 +218,11 @@ class ModuleProxyScan final
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConnectionTimeout(Module *c, time_t timeout)
|
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;)
|
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)
|
if (p->created + this->GetSecs() < Anope::CurTime)
|
||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} connectionTimeout;
|
} connectionTimeout;
|
||||||
|
|
||||||
@@ -308,9 +309,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->proxyscans.clear();
|
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;
|
ProxyCheck p;
|
||||||
Anope::string token;
|
Anope::string token;
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -173,10 +173,8 @@ public:
|
|||||||
{
|
{
|
||||||
Rewrite::rewrites.clear();
|
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"))
|
if (!block.Get<bool>("rewrite"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,17 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
/// BEGIN CMAKE
|
||||||
|
/// target_link_libraries(${SO} PRIVATE "vendored_yyjson")
|
||||||
|
/// END CMAKE
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "modules/rpc.h"
|
#include "modules/rpc.h"
|
||||||
#include "modules/httpd.h"
|
#include "modules/httpd.h"
|
||||||
|
|
||||||
#include "yyjson/yyjson.c"
|
#include "yyjson/yyjson.h"
|
||||||
|
|
||||||
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
||||||
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||||
@@ -313,10 +319,9 @@ public:
|
|||||||
throw ConfigException("Unable to find http reference, is httpd loaded?");
|
throw ConfigException("Unable to find http reference, is httpd loaded?");
|
||||||
|
|
||||||
jsonrpcinterface.tokens.clear();
|
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;
|
RPC::Token token;
|
||||||
token.token = block.Get<const Anope::string>("token");
|
token.token = block.Get<const Anope::string>("token");
|
||||||
if (!token.token.empty())
|
if (!token.token.empty())
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ if(HAVE_LOCALIZATION)
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Install the new language file
|
# Install the new language file
|
||||||
install(CODE "FILE(MAKE_DIRECTORY ${LOCALE_DIR}/${LANG_LANG}/LC_MESSAGES/)")
|
install(DIRECTORY DESTINATION "${LOCALE_DIR}/${LANG_LANG}/LC_MESSAGES")
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${LANG_MO} DESTINATION ${LOCALE_DIR}/${LANG_LANG}/LC_MESSAGES RENAME ${LANG_DOMAIN}.mo PERMISSIONS ${PERMS})
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${LANG_MO} DESTINATION ${LOCALE_DIR}/${LANG_LANG}/LC_MESSAGES RENAME ${LANG_DOMAIN}.mo PERMISSIONS ${PERMS})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
|||||||
@@ -94,6 +94,27 @@ const std::list<AccessProvider *>& AccessProvider::GetProviders()
|
|||||||
return Providers;
|
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)
|
ChanAccess::ChanAccess(AccessProvider *p)
|
||||||
: Serializable(CHANACCESS_TYPE)
|
: Serializable(CHANACCESS_TYPE)
|
||||||
, provider(p)
|
, provider(p)
|
||||||
|
|||||||
+1
-1
@@ -402,5 +402,5 @@ bool Command::FindFromService(const Anope::string &command_service, BotInfo *&bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return name.empty();
|
return !name.empty();
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-47
@@ -38,28 +38,37 @@ const Anope::string &Configuration::Block::GetName() const
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Configuration::Block::CountBlock(const Anope::string &bname) const
|
size_t Configuration::Block::CountBlock(const Anope::string &bname) const
|
||||||
{
|
{
|
||||||
return blocks.count(bname);
|
return blocks.count(bname);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Configuration::Block &Configuration::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)
|
if (i == num)
|
||||||
return it.first->second;
|
return it.first->second;
|
||||||
|
}
|
||||||
return EmptyBlock;
|
return EmptyBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
Configuration::Block *Configuration::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)
|
if (i == num)
|
||||||
return &it.first->second;
|
return &it.first->second;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +78,7 @@ bool Configuration::Block::Set(const Anope::string &tag, const Anope::string &va
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Configuration::Block::item_map &Configuration::Block::GetItems() const
|
const Configuration::Block::ItemMap &Configuration::Block::GetItems() const
|
||||||
{
|
{
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
@@ -125,10 +134,8 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
|
|
||||||
this->LoadConf(ServicesConf);
|
this->LoadConf(ServicesConf);
|
||||||
|
|
||||||
for (int i = 0; i < this->CountBlock("include"); ++i)
|
for (const auto &[_, include] : this->GetBlocks("include"))
|
||||||
{
|
{
|
||||||
const auto &include = this->GetBlock("include", i);
|
|
||||||
|
|
||||||
const Anope::string &type = include.Get<const Anope::string>("type"),
|
const Anope::string &type = include.Get<const Anope::string>("type"),
|
||||||
&file = include.Get<const Anope::string>("name");
|
&file = include.Get<const Anope::string>("name");
|
||||||
|
|
||||||
@@ -205,10 +212,8 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
this->TimeoutCheck = options.Get<time_t>("timeoutcheck");
|
this->TimeoutCheck = options.Get<time_t>("timeoutcheck");
|
||||||
this->NickChars = networkinfo.Get<Anope::string>("nick_chars");
|
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 auto &uplink = this->GetBlock("uplink", i);
|
|
||||||
|
|
||||||
int protocol;
|
int protocol;
|
||||||
const Anope::string &protocolstr = uplink.Get<const Anope::string>("protocol", "ipv4");
|
const Anope::string &protocolstr = uplink.Get<const Anope::string>("protocol", "ipv4");
|
||||||
if (protocolstr == "ipv4")
|
if (protocolstr == "ipv4")
|
||||||
@@ -238,10 +243,8 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
this->Uplinks.emplace_back(host, port, password, protocol);
|
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 auto &module = this->GetBlock("module", i);
|
|
||||||
|
|
||||||
const Anope::string &modname = module.Get<const Anope::string>("name");
|
const Anope::string &modname = module.Get<const Anope::string>("name");
|
||||||
|
|
||||||
ValidateNotEmptyOrSpaces("module", "name", modname);
|
ValidateNotEmptyOrSpaces("module", "name", modname);
|
||||||
@@ -249,10 +252,8 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
this->ModulesAutoLoad.push_back(modname);
|
this->ModulesAutoLoad.push_back(modname);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < this->CountBlock("opertype"); ++i)
|
for (const auto &[_, opertype] : this->GetBlocks("opertype"))
|
||||||
{
|
{
|
||||||
const auto &opertype = this->GetBlock("opertype", i);
|
|
||||||
|
|
||||||
const Anope::string &oname = opertype.Get<const Anope::string>("name"),
|
const Anope::string &oname = opertype.Get<const Anope::string>("name"),
|
||||||
&modes = opertype.Get<const Anope::string>("modes"),
|
&modes = opertype.Get<const Anope::string>("modes"),
|
||||||
&inherits = opertype.Get<const Anope::string>("inherits"),
|
&inherits = opertype.Get<const Anope::string>("inherits"),
|
||||||
@@ -292,10 +293,8 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
this->MyOperTypes.push_back(ot);
|
this->MyOperTypes.push_back(ot);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < this->CountBlock("oper"); ++i)
|
for (const auto &[_, oper] : this->GetBlocks("oper"))
|
||||||
{
|
{
|
||||||
const auto &oper = this->GetBlock("oper", i);
|
|
||||||
|
|
||||||
const Anope::string &nname = oper.Get<const Anope::string>("name"),
|
const Anope::string &nname = oper.Get<const Anope::string>("name"),
|
||||||
&type = oper.Get<const Anope::string>("type"),
|
&type = oper.Get<const Anope::string>("type"),
|
||||||
&password = oper.Get<const Anope::string>("password"),
|
&password = oper.Get<const Anope::string>("password"),
|
||||||
@@ -330,10 +329,9 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
|
|
||||||
for (const auto &[_, bi] : *BotListByNick)
|
for (const auto &[_, bi] : *BotListByNick)
|
||||||
bi->conf = false;
|
bi->conf = false;
|
||||||
for (int i = 0; i < this->CountBlock("service"); ++i)
|
|
||||||
{
|
|
||||||
const auto &service = this->GetBlock("service", i);
|
|
||||||
|
|
||||||
|
for (const auto &[_, service] : this->GetBlocks("service"))
|
||||||
|
{
|
||||||
const Anope::string &nick = service.Get<const Anope::string>("nick"),
|
const Anope::string &nick = service.Get<const Anope::string>("nick"),
|
||||||
&user = service.Get<const Anope::string>("user", nick.lower()),
|
&user = service.Get<const Anope::string>("user", nick.lower()),
|
||||||
&host = service.Get<const Anope::string>("host", servername),
|
&host = service.Get<const Anope::string>("host", servername),
|
||||||
@@ -421,10 +419,8 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < this->CountBlock("log"); ++i)
|
for (const auto &[_, log] : this->GetBlocks("log"))
|
||||||
{
|
{
|
||||||
const auto &log = this->GetBlock("log", i);
|
|
||||||
|
|
||||||
int logage = log.Get<int>("logage");
|
int logage = log.Get<int>("logage");
|
||||||
bool rawio = log.Get<bool>("rawio");
|
bool rawio = log.Get<bool>("rawio");
|
||||||
bool debug = log.Get<bool>("debug");
|
bool debug = log.Get<bool>("debug");
|
||||||
@@ -447,10 +443,8 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
|
|
||||||
for (const auto &[_, bi] : *BotListByNick)
|
for (const auto &[_, bi] : *BotListByNick)
|
||||||
bi->commands.clear();
|
bi->commands.clear();
|
||||||
for (int i = 0; i < this->CountBlock("command"); ++i)
|
for (const auto &[_, command] : this->GetBlocks("command"))
|
||||||
{
|
{
|
||||||
const auto &command = this->GetBlock("command", i);
|
|
||||||
|
|
||||||
const Anope::string &service = command.Get<const Anope::string>("service"),
|
const Anope::string &service = command.Get<const Anope::string>("service"),
|
||||||
&nname = command.Get<const Anope::string>("name"),
|
&nname = command.Get<const Anope::string>("name"),
|
||||||
&cmd = command.Get<const Anope::string>("command"),
|
&cmd = command.Get<const Anope::string>("command"),
|
||||||
@@ -472,10 +466,8 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
}
|
}
|
||||||
|
|
||||||
PrivilegeManager::ClearPrivileges();
|
PrivilegeManager::ClearPrivileges();
|
||||||
for (int i = 0; i < this->CountBlock("privilege"); ++i)
|
for (const auto &[_, privilege] : this->GetBlocks("privilege"))
|
||||||
{
|
{
|
||||||
const auto &privilege = this->GetBlock("privilege", i);
|
|
||||||
|
|
||||||
const Anope::string &nname = privilege.Get<const Anope::string>("name"),
|
const Anope::string &nname = privilege.Get<const Anope::string>("name"),
|
||||||
&desc = privilege.Get<const Anope::string>("desc");
|
&desc = privilege.Get<const Anope::string>("desc");
|
||||||
int rank = privilege.Get<int>("rank");
|
int rank = privilege.Get<int>("rank");
|
||||||
@@ -483,10 +475,8 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
PrivilegeManager::AddPrivilege(Privilege(nname, desc, rank));
|
PrivilegeManager::AddPrivilege(Privilege(nname, desc, rank));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < this->CountBlock("fantasy"); ++i)
|
for (const auto &[_, fantasy] : this->GetBlocks("fantasy"))
|
||||||
{
|
{
|
||||||
const auto &fantasy = this->GetBlock("fantasy", i);
|
|
||||||
|
|
||||||
const Anope::string &nname = fantasy.Get<const Anope::string>("name"),
|
const Anope::string &nname = fantasy.Get<const Anope::string>("name"),
|
||||||
&service = fantasy.Get<const Anope::string>("command"),
|
&service = fantasy.Get<const Anope::string>("command"),
|
||||||
&permission = fantasy.Get<const Anope::string>("permission"),
|
&permission = fantasy.Get<const Anope::string>("permission"),
|
||||||
@@ -504,10 +494,8 @@ Configuration::Conf::Conf() : Configuration::Block("")
|
|||||||
c.require_privilege = fantasy.Get<bool>("require_privilege", "yes");
|
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 auto &command_group = this->GetBlock("command_group", i);
|
|
||||||
|
|
||||||
const Anope::string &nname = command_group.Get<const Anope::string>("name"),
|
const Anope::string &nname = command_group.Get<const Anope::string>("name"),
|
||||||
&description = command_group.Get<const Anope::string>("description");
|
&description = command_group.Get<const Anope::string>("description");
|
||||||
|
|
||||||
@@ -655,7 +643,7 @@ Configuration::Block &Configuration::Conf::GetModule(const Anope::string &mname)
|
|||||||
auto *&block = modules[mname];
|
auto *&block = modules[mname];
|
||||||
|
|
||||||
/* Search for the block */
|
/* 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)
|
||||||
{
|
{
|
||||||
auto &b = iters.first->second;
|
auto &b = iters.first->second;
|
||||||
|
|
||||||
@@ -688,7 +676,7 @@ const Configuration::Block &Configuration::Conf::GetCommand(CommandSource &sourc
|
|||||||
{
|
{
|
||||||
const Anope::string &block_name = source.c ? "fantasy" : "command";
|
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)
|
||||||
{
|
{
|
||||||
auto &b = iters.first->second;
|
auto &b = iters.first->second;
|
||||||
|
|
||||||
@@ -782,7 +770,7 @@ void Configuration::Conf::LoadConf(Configuration::File &file)
|
|||||||
|
|
||||||
Anope::string itemname, wordbuffer;
|
Anope::string itemname, wordbuffer;
|
||||||
std::stack<Configuration::Block *> block_stack;
|
std::stack<Configuration::Block *> block_stack;
|
||||||
int linenumber = 0;
|
unsigned linenumber = 0;
|
||||||
bool in_word = false, in_quote = false, in_comment = false;
|
bool in_word = false, in_quote = false, in_comment = false;
|
||||||
|
|
||||||
Log(LOG_DEBUG) << "Start to read conf " << file.GetPath();
|
Log(LOG_DEBUG) << "Start to read conf " << file.GetPath();
|
||||||
@@ -984,7 +972,7 @@ void Configuration::Conf::LoadConf(Configuration::File &file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Anope::string Configuration::Conf::ReplaceVars(const Anope::string &str, const Configuration::File &file, int linenumber)
|
Anope::string Configuration::Conf::ReplaceVars(const Anope::string &str, const Configuration::File &file, unsigned linenumber)
|
||||||
{
|
{
|
||||||
Anope::string ret;
|
Anope::string ret;
|
||||||
for (auto it = str.begin(); it != str.end(); )
|
for (auto it = str.begin(); it != str.end(); )
|
||||||
@@ -1020,9 +1008,8 @@ Anope::string Configuration::Conf::ReplaceVars(const Anope::string &str, const C
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto found = false;
|
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");
|
const auto defname = define.Get<const Anope::string>("name");
|
||||||
if (defname == var)
|
if (defname == var)
|
||||||
{
|
{
|
||||||
|
|||||||
+2
-2
@@ -537,8 +537,8 @@ bool Anope::Init(int ac, char **av)
|
|||||||
|
|
||||||
/* load modules */
|
/* load modules */
|
||||||
Log() << "Loading modules...";
|
Log() << "Loading modules...";
|
||||||
for (int i = 0; i < Config->CountBlock("module"); ++i)
|
for (const auto &[_, block] : Config->GetBlocks("module"))
|
||||||
ModuleManager::LoadModule(Config->GetBlock("module", i).Get<const Anope::string>("name"), NULL);
|
ModuleManager::LoadModule(block.Get<const Anope::string>("name"), NULL);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
/* If we're root, issue a warning now */
|
/* If we're root, issue a warning now */
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ void Language::InitLanguages()
|
|||||||
Languages.push_back(language);
|
Languages.push_back(language);
|
||||||
}
|
}
|
||||||
#else
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -50,13 +50,14 @@ class UpdateTimer final
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
UpdateTimer(time_t timeout)
|
UpdateTimer(time_t timeout)
|
||||||
: Timer(timeout, true)
|
: Timer(timeout)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
Anope::SaveDatabases();
|
Anope::SaveDatabases();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,13 +66,14 @@ class ExpireTimer final
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ExpireTimer(time_t timeout)
|
ExpireTimer(time_t timeout)
|
||||||
: Timer(timeout, true)
|
: Timer(timeout)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
FOREACH_MOD(OnExpireTick, ());
|
FOREACH_MOD(OnExpireTick, ());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+24
-4
@@ -686,7 +686,9 @@ Anope::string Anope::strftime(time_t t, const NickCore *nc, bool short_output)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char buf[256];
|
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)
|
if (nc)
|
||||||
{
|
{
|
||||||
@@ -950,9 +952,9 @@ Anope::string Anope::VersionShort()
|
|||||||
Anope::string Anope::VersionBuildString()
|
Anope::string Anope::VersionBuildString()
|
||||||
{
|
{
|
||||||
#if REPRODUCIBLE_BUILD
|
#if REPRODUCIBLE_BUILD
|
||||||
Anope::string s = "build #" + Anope::ToString(BUILD);
|
auto s = Anope::Format("build #%u", BUILD);
|
||||||
#else
|
#else
|
||||||
Anope::string s = "build #" + Anope::ToString(BUILD) + ", compiled " + Anope::compiled;
|
auto s = Anope::Format("build #%u, compiled %s", BUILD, BUILD_DATE);
|
||||||
#endif
|
#endif
|
||||||
Anope::string flags;
|
Anope::string flags;
|
||||||
|
|
||||||
@@ -963,7 +965,7 @@ Anope::string Anope::VersionBuildString()
|
|||||||
flags += "G";
|
flags += "G";
|
||||||
#endif
|
#endif
|
||||||
#if REPRODUCIBLE_BUILD
|
#if REPRODUCIBLE_BUILD
|
||||||
flags += "R"
|
flags += "R";
|
||||||
#endif
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
flags += "W";
|
flags += "W";
|
||||||
@@ -1176,6 +1178,24 @@ Anope::string Anope::FormatCTCP(const Anope::string &name, const Anope::string &
|
|||||||
return Anope::Format("\1%s %s\1", name.c_str(), value.c_str());
|
return Anope::Format("\1%s %s\1", name.c_str(), value.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Anope::string Anope::FormatISO8601(time_t ts, unsigned long long ms)
|
||||||
|
{
|
||||||
|
static time_t last_ts = -1;
|
||||||
|
static unsigned long long last_ms = -1;
|
||||||
|
static Anope::string timestamp;
|
||||||
|
if (ts != last_ts || ms != last_ms)
|
||||||
|
{
|
||||||
|
last_ts = ts;
|
||||||
|
last_ms = ms;
|
||||||
|
char timebuf[32];
|
||||||
|
const auto *tm = gmtime(&ts);
|
||||||
|
strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", tm);
|
||||||
|
timestamp = Anope::Format("%s.%03lldZ", timebuf, ms);
|
||||||
|
}
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Anope::ParseCTCP(const Anope::string &text, Anope::string &name, Anope::string &body)
|
bool Anope::ParseCTCP(const Anope::string &text, Anope::string &name, Anope::string &body)
|
||||||
{
|
{
|
||||||
// According to draft-oakley-irc-ctcp-02 a valid CTCP must begin with SOH and
|
// According to draft-oakley-irc-ctcp-02 a valid CTCP must begin with SOH and
|
||||||
|
|||||||
@@ -88,10 +88,11 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/* Generate the filename for the temporary copy of the module */
|
/* 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)
|
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;
|
return MOD_ERR_FILE_IO;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -100,6 +100,13 @@ void Anope::ProcessInternal(MessageSource &src, const Anope::string &command, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IRCDProto::PopulateTags(Anope::map<Anope::string> &tags, const MessageSource &source, const Anope::string &command, const std::vector<Anope::string> ¶ms)
|
||||||
|
{
|
||||||
|
auto it = tags.find("time"); // https://ircv3.net/specs/extensions/server-time
|
||||||
|
if (it == tags.end())
|
||||||
|
tags["time"] = Anope::FormatISO8601(Anope::CurTime, Anope::CurTimeNs / 1'000'000);
|
||||||
|
}
|
||||||
|
|
||||||
bool IRCDProto::Parse(const Anope::string &buffer, Anope::map<Anope::string> &tags, Anope::string &source, Anope::string &command, std::vector<Anope::string> ¶ms)
|
bool IRCDProto::Parse(const Anope::string &buffer, Anope::map<Anope::string> &tags, Anope::string &source, Anope::string &command, std::vector<Anope::string> ¶ms)
|
||||||
{
|
{
|
||||||
MessageTokenizer tokens(buffer);
|
MessageTokenizer tokens(buffer);
|
||||||
|
|||||||
+4
-16
@@ -17,20 +17,15 @@
|
|||||||
|
|
||||||
std::multimap<time_t, Timer *> TimerManager::Timers;
|
std::multimap<time_t, Timer *> TimerManager::Timers;
|
||||||
|
|
||||||
Timer::Timer(time_t time_from_now, bool repeating)
|
Timer::Timer(time_t time_from_now)
|
||||||
: trigger(Anope::CurTime + std::abs(time_from_now))
|
: Timer(nullptr, time_from_now)
|
||||||
, secs(time_from_now)
|
|
||||||
, repeat(repeating)
|
|
||||||
{
|
{
|
||||||
if (time_from_now)
|
|
||||||
TimerManager::AddTimer(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer::Timer(Module *creator, time_t time_from_now, bool repeating)
|
Timer::Timer(Module *creator, time_t time_from_now)
|
||||||
: owner(creator)
|
: owner(creator)
|
||||||
, trigger(Anope::CurTime + std::abs(time_from_now))
|
, trigger(Anope::CurTime + std::abs(time_from_now))
|
||||||
, secs(time_from_now)
|
, secs(time_from_now)
|
||||||
, repeat(repeating)
|
|
||||||
{
|
{
|
||||||
if (time_from_now)
|
if (time_from_now)
|
||||||
TimerManager::AddTimer(this);
|
TimerManager::AddTimer(this);
|
||||||
@@ -53,11 +48,6 @@ time_t Timer::GetTimer() const
|
|||||||
return trigger;
|
return trigger;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Timer::GetRepeat() const
|
|
||||||
{
|
|
||||||
return repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timer::SetSecs(time_t t)
|
void Timer::SetSecs(time_t t)
|
||||||
{
|
{
|
||||||
TimerManager::DelTimer(this);
|
TimerManager::DelTimer(this);
|
||||||
@@ -104,9 +94,7 @@ void TimerManager::TickTimers()
|
|||||||
if (t->GetTimer() > Anope::CurTime)
|
if (t->GetTimer() > Anope::CurTime)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
t->Tick();
|
if (t->Tick())
|
||||||
|
|
||||||
if (t->GetRepeat())
|
|
||||||
t->SetTimer(Anope::CurTime + t->GetSecs());
|
t->SetTimer(Anope::CurTime + t->GetSecs());
|
||||||
else
|
else
|
||||||
delete t;
|
delete t;
|
||||||
|
|||||||
@@ -47,11 +47,19 @@ algorithm = sys.argv[1]
|
|||||||
password = sys.argv[2] if len(sys.argv) >= 3 else getpass.getpass()
|
password = sys.argv[2] if len(sys.argv) >= 3 else getpass.getpass()
|
||||||
|
|
||||||
def do_argon2(variant, password):
|
def do_argon2(variant, password):
|
||||||
ph = argon2.PasswordHasher(type=variant)
|
ph = argon2.PasswordHasher(
|
||||||
|
time_cost=int(os.getenv("ARGON2_TIME_COST", 3)),
|
||||||
|
memory_cost=int(os.getenv("ARGON2_TIME_COST", 131_072)),
|
||||||
|
parallelism=int(os.getenv("ARGON2_PARALLELISM", 1)),
|
||||||
|
hash_len=int(os.getenv("ARGON2_SALT_LENGTH", 32)),
|
||||||
|
salt_len=int(os.getenv("ARGON2_HASH_LENGTH", 32)),
|
||||||
|
type=variant,
|
||||||
|
)
|
||||||
return ph.hash(password)
|
return ph.hash(password)
|
||||||
|
|
||||||
def do_bcrypt(password):
|
def do_bcrypt(password):
|
||||||
salt = bcrypt.gensalt(16)
|
rounds = int(os.getenv("BCRYPT_ROUNDS", 10))
|
||||||
|
salt = bcrypt.gensalt(rounds)
|
||||||
return bcrypt.hashpw(password.encode('utf-8'), salt).decode('utf-8')
|
return bcrypt.hashpw(password.encode('utf-8'), salt).decode('utf-8')
|
||||||
|
|
||||||
def do_hmac(digest, password):
|
def do_hmac(digest, password):
|
||||||
@@ -112,5 +120,8 @@ if config:
|
|||||||
token = "{password_hash}"
|
token = "{password_hash}"
|
||||||
token_hash = "{algorithm}"
|
token_hash = "{algorithm}"
|
||||||
""").lstrip())
|
""").lstrip())
|
||||||
|
else:
|
||||||
|
print(f"The {algorithm} algorithm can not be used in an oper or a jsonrpc/xmlrpc token.")
|
||||||
|
print()
|
||||||
|
|
||||||
print(f"Make sure you have the {module} module loaded!");
|
print(f"Make sure you have the {module} module loaded!");
|
||||||
|
|||||||
+14
-6
@@ -29,7 +29,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tick() override
|
bool Tick() override
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -39,6 +39,7 @@ public:
|
|||||||
{
|
{
|
||||||
Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].str() << "): " << ex.GetReason();
|
Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].str() << "): " << ex.GetReason();
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,8 +73,11 @@ void Uplink::SendInternal(const Anope::map<Anope::string> &tags, const MessageSo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Anope::map<Anope::string> fulltags(tags);
|
||||||
|
IRCD->PopulateTags(fulltags, source, command, params);
|
||||||
|
|
||||||
Anope::string message;
|
Anope::string message;
|
||||||
if (!IRCD->Format(message, tags, source, command, params))
|
if (!IRCD->Format(message, fulltags, source, command, params))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UplinkSock->sent_msgs++;
|
UplinkSock->sent_msgs++;
|
||||||
@@ -82,13 +86,17 @@ void Uplink::SendInternal(const Anope::map<Anope::string> &tags, const MessageSo
|
|||||||
Log(LOG_RAWIO) << "Sent " << message;
|
Log(LOG_RAWIO) << "Sent " << message;
|
||||||
if (Anope::ProtocolDebug)
|
if (Anope::ProtocolDebug)
|
||||||
{
|
{
|
||||||
if (tags.empty())
|
auto sent_tag = false;
|
||||||
Log() << "\tNo tags";
|
for (const auto &[tname, tvalue] : fulltags)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
for (const auto &[tname, tvalue] : tags)
|
if (IRCD->IsTagValid(tname, tvalue))
|
||||||
|
{
|
||||||
Log() << "\tTag " << tname << ": " << tvalue;
|
Log() << "\tTag " << tname << ": " << tvalue;
|
||||||
|
sent_tag = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (!sent_tag)
|
||||||
|
Log() << "\tNo tags";
|
||||||
|
|
||||||
if (source.GetSource().empty())
|
if (source.GetSource().empty())
|
||||||
Log() << "\tNo source";
|
Log() << "\tNo source";
|
||||||
|
|||||||
+1
-2
@@ -351,10 +351,9 @@ void User::SendMessage(BotInfo *source, const Anope::string &msg)
|
|||||||
|
|
||||||
void User::SendMessage(CommandSource &source, const Anope::string &msg)
|
void User::SendMessage(CommandSource &source, const Anope::string &msg)
|
||||||
{
|
{
|
||||||
// TODO: remove support for the draft tag when other software catches up.
|
|
||||||
Anope::map<Anope::string> tags;
|
Anope::map<Anope::string> tags;
|
||||||
if (!source.msgid.empty())
|
if (!source.msgid.empty())
|
||||||
tags["+draft/reply"] = tags["+reply"] = source.msgid;
|
tags["+reply"] = source.msgid;
|
||||||
|
|
||||||
SendMessageInternal(*source.service, this, msg, tags);
|
SendMessageInternal(*source.service, this, msg, tags);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
VERSION_MAJOR=2
|
VERSION_MAJOR=2
|
||||||
VERSION_MINOR=1
|
VERSION_MINOR=1
|
||||||
VERSION_PATCH=24
|
VERSION_PATCH=25
|
||||||
VERSION_EXTRA=""
|
VERSION_EXTRA="-git"
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
|
# Last updated: 2026-05-16
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
argon2/20190702
|
argon2/20190702
|
||||||
libgettext/0.26
|
libgettext/0.26
|
||||||
libmysqlclient/8.1.0
|
libmysqlclient/8.1.0
|
||||||
openssl/3.6.1
|
openssl/3.6.2
|
||||||
pcre2/10.44
|
pcre2/10.44
|
||||||
sqlite3/3.51.0
|
sqlite3/3.53.1
|
||||||
tre/cci.20230717
|
tre/cci.20230717
|
||||||
|
|
||||||
[tool_requires]
|
[tool_requires]
|
||||||
gettext/0.26
|
gettext/1.0
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
*/*:shared=True
|
*/*:shared=True
|
||||||
|
|||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
file(GLOB LIBRARIES CONFIGURE_DEPENDS "*")
|
||||||
|
foreach(LIBRARY IN LISTS LIBRARIES)
|
||||||
|
if(IS_DIRECTORY ${LIBRARY})
|
||||||
|
file(GLOB_RECURSE LIBRARY_SOURCES CONFIGURE_DEPENDS
|
||||||
|
"${LIBRARY}/*.c"
|
||||||
|
"${LIBRARY}/*.cc"
|
||||||
|
"${LIBRARY}/*.cpp"
|
||||||
|
)
|
||||||
|
if(LIBRARY_SOURCES)
|
||||||
|
cmake_path(GET LIBRARY FILENAME LIBRARY_NAME)
|
||||||
|
set(LIBRARY_TARGET "vendored_${LIBRARY_NAME}")
|
||||||
|
add_library(${LIBRARY_TARGET} STATIC ${LIBRARY_SOURCES})
|
||||||
|
target_compile_options(${LIBRARY_TARGET} PRIVATE "$<IF:$<BOOL:${MSVC}>,/W0,-w>")
|
||||||
|
set_target_properties(${LIBRARY_TARGET} PROPERTIES
|
||||||
|
FOLDER "VendoredLibraries"
|
||||||
|
PREFIX ""
|
||||||
|
UNITY_BUILD OFF
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
Reference in New Issue
Block a user