mirror of
https://github.com/anope/anope.git
synced 2026-06-20 12:24:46 +02:00
Compare commits
170 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0bb51f6551 | |||
| 28ce7bccb6 | |||
| a70ef47359 | |||
| 90ac540960 | |||
| 909a77efb9 | |||
| 59c8867e64 | |||
| 08d47a5dad | |||
| 41403c7e36 | |||
| b8ef28509c | |||
| cf6e56130a | |||
| a3f6ffd2c7 | |||
| b9554f8539 | |||
| 84dc0f3cc8 | |||
| 75f764e353 | |||
| 302c4f334e | |||
| 5148b349b7 | |||
| bbe31a6a38 | |||
| 8cb310c72e | |||
| 4a1ad182d4 | |||
| 75a893b18d | |||
| 753db88ae9 | |||
| 9f6f0b445b | |||
| dfa0bf5e5d | |||
| cc35c22d2a | |||
| 1dafc96521 | |||
| 5d1dd21887 | |||
| 8b6c6fdd81 | |||
| 1a5d49b7f6 | |||
| 0b3e55ed8f | |||
| 7a09cebcfb | |||
| da5c68f274 | |||
| 9782c1f94b | |||
| ee6b022f4d | |||
| 85b0e9d02f | |||
| da799bd6f1 | |||
| 4dada51e08 | |||
| 1275fd01a7 | |||
| 5b8018eb80 | |||
| b2026fe739 | |||
| 3390d82ebe | |||
| 4762e306f9 | |||
| fd759f7bd3 | |||
| 003ddde09d | |||
| c021d7134e | |||
| a792088a62 | |||
| 03e2ebe2d2 | |||
| 0238f0a9e3 | |||
| c2dfb9a447 | |||
| bd8435a061 | |||
| 2cd67c9f36 | |||
| 45ab094d63 | |||
| 54389f474b | |||
| ac2b38b1b6 | |||
| df551bee03 | |||
| 59bb9d3d06 | |||
| 3b2d798e76 | |||
| ff6d6bdb3c | |||
| 411b3ce65a | |||
| ad19603818 | |||
| 535ff9b839 | |||
| 51916a50d2 | |||
| 42e58952cc | |||
| ba9f4e93c2 | |||
| 679a313ae2 | |||
| 390975e6c4 | |||
| d631885495 | |||
| 8e337c6592 | |||
| 9d89d8233d | |||
| 6f27418381 | |||
| 1932081c27 | |||
| f73159159f | |||
| eccb338cdd | |||
| 4021c0bb68 | |||
| 7dfb40cb58 | |||
| 0fbd3095c4 | |||
| 6d426ec386 | |||
| 1b33a51695 | |||
| 168a1173ed | |||
| 59c777d4ff | |||
| 43f88524e2 | |||
| 04de41ad7f | |||
| dd13846cad | |||
| 6864bc6171 | |||
| 003cb55409 | |||
| d15b8ee949 | |||
| 70de2b7de2 | |||
| e5c5689985 | |||
| 928d4260dc | |||
| 5e8561a7f1 | |||
| 4dd3075ddf | |||
| dbef7a7c64 | |||
| cd0f00a819 | |||
| b2d40d4189 | |||
| e6e812c43c | |||
| 2dbd41d244 | |||
| 02aeb254ee | |||
| 1245b43ade | |||
| 5a3f9f3f87 | |||
| 2c6f4d7c27 | |||
| 64f8449bf4 | |||
| 0e1f6b403b | |||
| 206192abdc | |||
| 32d3ddc0e4 | |||
| 4410e5ccce | |||
| d5f2232140 | |||
| 6d754b7d73 | |||
| 4d2870fa45 | |||
| 5948c2ea53 | |||
| ace7d99797 | |||
| 52595b90fa | |||
| b39f002d1b | |||
| 5df95d9f86 | |||
| a56d9a4096 | |||
| ce7bb15c18 | |||
| 6873630f2e | |||
| 44a4d62654 | |||
| 97389cd105 | |||
| 80c0adf7c8 | |||
| 6a539277b9 | |||
| 9930fa01ac | |||
| 40929a0490 | |||
| 783be31f64 | |||
| 0f5f2aef2e | |||
| 6cc997c4e9 | |||
| eda6d8cc0f | |||
| 3440b38a21 | |||
| fca421aa2a | |||
| 035905d321 | |||
| d1cd57d98e | |||
| 48daeeac1d | |||
| 9bcf46f8ea | |||
| 0b6c7ce5d6 | |||
| a0d21b207b | |||
| 3cc5b5143f | |||
| da738126a4 | |||
| 0bb1bc5c67 | |||
| 72010cd1a9 | |||
| c48b3af3d4 | |||
| 85c129701b | |||
| a9e5a79e91 | |||
| adc1343d6c | |||
| 8aa1102c7a | |||
| 1a89d32926 | |||
| ad06853edf | |||
| 66ae20e0f2 | |||
| 2850e3c65c | |||
| 80b8856254 | |||
| 21c8164539 | |||
| a4abd27ffd | |||
| b912b403f0 | |||
| 59e9d47667 | |||
| 1108e54250 | |||
| 8b37cdb5d5 | |||
| c5bff3a099 | |||
| 61b0c82884 | |||
| c4c159d197 | |||
| 04a32be1e1 | |||
| fe4b8ee669 | |||
| 34b451f36c | |||
| 16aff210fd | |||
| 5702fb9145 | |||
| 783ba3fd74 | |||
| f1ddd7cd02 | |||
| c424c4d24d | |||
| 2d88383d9e | |||
| c73a6c621f | |||
| 96a503b4d9 | |||
| 0632abd111 | |||
| 1043e2189c | |||
| 85f0d56c39 |
@@ -4,6 +4,7 @@ on:
|
||||
push:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
if: "!contains(github.event.head_commit.message, '[skip alpine ci]')"
|
||||
@@ -13,7 +14,7 @@ jobs:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
CXXFLAGS: -Werror
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
name: Ubuntu CI
|
||||
on:
|
||||
- pull_request
|
||||
- push
|
||||
pull_request:
|
||||
push:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
if: "!contains(github.event.head_commit.message, '[skip ubuntu ci]')"
|
||||
@@ -10,7 +13,7 @@ jobs:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
CXXFLAGS: -Werror
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
@@ -7,6 +7,7 @@ on:
|
||||
- published
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
if: "!contains(github.event.head_commit.message, '[skip windows ci]')"
|
||||
@@ -16,7 +17,7 @@ jobs:
|
||||
CONAN_USER_HOME: ${{ github.workspace }}/win/build
|
||||
CONAN_USER_HOME_SHORT: None
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Setup NSIS
|
||||
run: |-
|
||||
|
||||
@@ -14,5 +14,6 @@ modules/ssl_openssl.cpp
|
||||
modules/stats
|
||||
modules/xmlrpc.cpp
|
||||
run/
|
||||
*.diff
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
+4
-2
@@ -107,6 +107,7 @@ include(CheckFunctionExists)
|
||||
include(CheckTypeSize)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(FindPkgConfig)
|
||||
|
||||
# If extra include directories were specified, tell cmake about them.
|
||||
if(EXTRA_INCLUDE)
|
||||
@@ -121,7 +122,7 @@ endif()
|
||||
# setup conan
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/conanbuildinfo.cmake")
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/conanbuildinfo.cmake")
|
||||
conan_basic_setup()
|
||||
conan_basic_setup(TARGETS)
|
||||
endif()
|
||||
|
||||
# Find gettext
|
||||
@@ -159,7 +160,8 @@ if(MSVC)
|
||||
# Otherwise, we're not using Visual Studio
|
||||
else()
|
||||
# Set the compile flags to have all warnings on (including shadowed variables)
|
||||
set(CXXFLAGS "${CXXFLAGS} -fvisibility=hidden -fvisibility-inlines-hidden -Wall -Wextra -Wformat=2 -Wmissing-format-attribute -Wpedantic -Wno-format-nonliteral -Wno-format-zero-length -Wno-unused-parameter ${CMAKE_CXX_FLAGS}")
|
||||
set(CXXFLAGS "${CXXFLAGS} -fvisibility=hidden -fvisibility-inlines-hidden -Wall -Wextra -Wformat=2 -Wmissing-format-attribute -Wpedantic")
|
||||
set(CXXFLAGS "${CXXFLAGS} -Wno-format-nonliteral -Wno-format-y2k -Wno-format-zero-length -Wno-date-time -Wno-unused-parameter ${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
# If CMake has found that the given system requires a special library for dl* calls, include it with the linker flags
|
||||
|
||||
@@ -13,14 +13,6 @@
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
exists () { # because some shells don't have test -e
|
||||
if [ -f $1 -o -d $1 -o -p $1 -o -c $1 -o -b $1 ] ; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
Load_Cache () {
|
||||
if [ -f $SOURCE_DIR/config.cache -a -r $SOURCE_DIR/config.cache -a ! "$IGNORE_CACHE" ] ; then
|
||||
echo "Using defaults from config.cache. To ignore, $SOURCE_DIR/Config -nocache"
|
||||
@@ -208,7 +200,7 @@ while [ $ok -eq 0 ] ; do
|
||||
INPUT=$INSTDIR
|
||||
fi
|
||||
if [ ! -d "$INPUT" ] ; then
|
||||
if exists "$INPUT" ; then
|
||||
if [ -e "$INPUT" ]; then
|
||||
echo "$INPUT exists, but is not a directory!"
|
||||
else
|
||||
echo "$INPUT does not exist. Create it?"
|
||||
@@ -220,7 +212,7 @@ while [ $ok -eq 0 ] ; do
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
elif exists "$INPUT/include/services.h" ; then
|
||||
elif [ -e "$INPUT/include/services.h" ]; then
|
||||
echo "You cannot use the Anope source directory as a target directory."
|
||||
else
|
||||
ok=1
|
||||
|
||||
BIN
Binary file not shown.
+26
-84
@@ -1,87 +1,3 @@
|
||||
###############################################################################
|
||||
# calculate_libraries(<source filename> <output variable for linker flags> <output variable for extra depends>)
|
||||
#
|
||||
# This macro is used in most of the module (sub)directories to calculate the
|
||||
# library dependencies for the given source file.
|
||||
###############################################################################
|
||||
macro(calculate_libraries SRC SRC_LDFLAGS EXTRA_DEPENDS)
|
||||
# Set up a temporary LDFLAGS for this file
|
||||
set(THIS_LDFLAGS "${LDFLAGS}")
|
||||
# Reset extra dependencies
|
||||
set(EXTRA_DEPENDENCIES)
|
||||
# Reset library paths
|
||||
set(LIBRARY_PATHS)
|
||||
# Reset libraries
|
||||
set(LIBRARIES)
|
||||
# Check to see if there are any lines matching: /* RequiredLibraries: [something] */
|
||||
if(WIN32)
|
||||
file(STRINGS ${SRC} REQUIRED_LIBRARIES REGEX "/\\*[ \t]*RequiredWindowsLibraries:[ \t]*.*[ \t]*\\*/")
|
||||
else()
|
||||
file(STRINGS ${SRC} REQUIRED_LIBRARIES REGEX "/\\*[ \t]*RequiredLibraries:[ \t]*.*[ \t]*\\*/")
|
||||
endif()
|
||||
# Iterate through those lines
|
||||
foreach(REQUIRED_LIBRARY ${REQUIRED_LIBRARIES})
|
||||
# Strip off the /* RequiredLibraries: and */ from the line
|
||||
string(REGEX REPLACE "/\\*[ \t]*Required.*Libraries:[ \t]*([^ \t]*)[ \t]*\\*/" "\\1" REQUIRED_LIBRARY ${REQUIRED_LIBRARY})
|
||||
# Replace all commas with semicolons
|
||||
string(REGEX REPLACE "," ";" REQUIRED_LIBRARY ${REQUIRED_LIBRARY})
|
||||
# Iterate through the libraries given
|
||||
foreach(LIBRARY ${REQUIRED_LIBRARY})
|
||||
# If the library has multiple names extract the alternate.
|
||||
unset(LIBRARY_ALT)
|
||||
if (${LIBRARY} MATCHES "^.+\\|.+$")
|
||||
string(REGEX REPLACE ".+\\|(.*)" "\\1" LIBRARY_ALT ${LIBRARY})
|
||||
string(REGEX REPLACE "(.+)\\|.*" "\\1" LIBRARY ${LIBRARY})
|
||||
endif()
|
||||
# Locate the library to see if it exists
|
||||
if(DEFAULT_LIBRARY_DIRS OR DEFINED $ENV{VCINSTALLDIR})
|
||||
find_library(FOUND_${LIBRARY}_LIBRARY NAMES ${LIBRARY} ${LIBRARY_ALT} PATHS ${DEFAULT_LIBRARY_DIRS} $ENV{VCINSTALLDIR}/lib ${EXTRA_INCLUDE} ${EXTRA_LIBS})
|
||||
else()
|
||||
find_library(FOUND_${LIBRARY}_LIBRARY NAMES ${LIBRARY} ${LIBRARY_ALT} PATHS ${EXTRA_INCLUDE} ${EXTRA_LIBS} NO_DEFAULT_PATH)
|
||||
find_library(FOUND_${LIBRARY}_LIBRARY NAMES ${LIBRARY} ${LIBRARY_ALT} PATHS ${EXTRA_INCLUDE} ${EXTRA_LIBS})
|
||||
endif()
|
||||
# If the library was found, we will add it to the linker flags
|
||||
if(FOUND_${LIBRARY}_LIBRARY)
|
||||
if(MSVC)
|
||||
# For Visual Studio, instead of editing the linker flags, we'll add the library to a separate list of extra dependencies
|
||||
list(APPEND EXTRA_DEPENDENCIES "${FOUND_${LIBRARY}_LIBRARY}")
|
||||
else()
|
||||
# Get the path only of the library, to add it to library paths.
|
||||
get_filename_component(LIBRARY_PATH ${FOUND_${LIBRARY}_LIBRARY} PATH)
|
||||
list(APPEND LIBRARY_PATHS "${LIBRARY_PATH}")
|
||||
# Extract the library short name, add it to the library path
|
||||
get_filename_component(LIBRARY_NAME ${FOUND_${LIBRARY}_LIBRARY} NAME_WE)
|
||||
string(REGEX REPLACE "^lib" "" LIBRARY_NAME ${LIBRARY_NAME})
|
||||
list(APPEND LIBRARIES ${LIBRARY_NAME})
|
||||
endif()
|
||||
else()
|
||||
# In the case of the library not being found, we fatally error so CMake stops trying to generate
|
||||
message(FATAL_ERROR "${SRC} needs library ${LIBRARY} but we were unable to locate that library! Check that the library is within the search path of your OS.")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
# Remove duplicates from the library paths
|
||||
if(LIBRARY_PATHS)
|
||||
list(REMOVE_DUPLICATES LIBRARY_PATHS)
|
||||
endif()
|
||||
# Remove diplicates from the libraries
|
||||
if(LIBRARIES)
|
||||
list(REMOVE_DUPLICATES LIBRARIES)
|
||||
endif()
|
||||
# Iterate through library paths and add them to the linker flags
|
||||
foreach(LIBRARY_PATH ${LIBRARY_PATHS})
|
||||
if(NOT "${LIBRARY_PATH}" IN_LIST DEFAULT_LIBRARY_DIRS)
|
||||
set(THIS_LDFLAGS "${THIS_LDFLAGS} -L${LIBRARY_PATH}")
|
||||
endif()
|
||||
endforeach()
|
||||
# Iterate through libraries and add them to the linker flags
|
||||
foreach(LIBRARY ${LIBRARIES})
|
||||
list(APPEND EXTRA_DEPENDENCIES "${LIBRARY}")
|
||||
endforeach()
|
||||
set(${SRC_LDFLAGS} "${THIS_LDFLAGS}")
|
||||
set(${EXTRA_DEPENDS} "${EXTRA_DEPENDENCIES}")
|
||||
endmacro()
|
||||
|
||||
###############################################################################
|
||||
# add_to_cpack_ignored_files(<item> [TRUE])
|
||||
#
|
||||
@@ -104,3 +20,29 @@ macro(add_to_cpack_ignored_files ITEM)
|
||||
set(ENV{CPACK_IGNORED_FILES} "${REAL_ITEM}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
###############################################################################
|
||||
# inline_cmake(TARGET FILE)
|
||||
#
|
||||
# A macro to execute inline CMake instructions from within a module source.
|
||||
###############################################################################
|
||||
macro(inline_cmake TARGET FILE)
|
||||
file(STRINGS ${FILE} SRC)
|
||||
set(CODE "")
|
||||
set(IN_CODE OFF)
|
||||
foreach(LINE IN LISTS SRC)
|
||||
if(IN_CODE)
|
||||
string(REGEX REPLACE "/// " "" CLEAN_LINE ${LINE})
|
||||
if(CLEAN_LINE MATCHES "^END CMAKE$")
|
||||
cmake_language(EVAL CODE "${CODE}")
|
||||
set(CODE "")
|
||||
set(IN_CODE OFF)
|
||||
else()
|
||||
set(CODE "${CODE}\n${CLEAN_LINE}")
|
||||
endif()
|
||||
elseif(LINE MATCHES "^/// BEGIN CMAKE$")
|
||||
message(STATUS "Executing inline CMake code for ${TARGET}")
|
||||
set(IN_CODE ON)
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Only install cron.example.sh and anope.example.conf from this directory
|
||||
# NOTE: I would've had this just find all files in the directory, but that would include files not needed (like this file)
|
||||
set(DATA cron.example.sh anope.example.conf botserv.example.conf hostserv.example.conf modules.example.conf operserv.example.conf chanserv.example.conf global.example.conf memoserv.example.conf nickserv.example.conf chanstats.example.conf irc2sql.example.conf stats.standalone.example.conf)
|
||||
set(DATA cron.example.sh anope.example.conf botserv.example.conf hostserv.example.conf modules.example.conf operserv.example.conf chanserv.example.conf global.example.conf memoserv.example.conf nickserv.example.conf chanstats.example.conf)
|
||||
install(FILES ${DATA}
|
||||
DESTINATION ${CONF_DIR}
|
||||
)
|
||||
|
||||
+29
-105
@@ -65,10 +65,6 @@
|
||||
* will typically be disabled. If this is not the case, more
|
||||
* information will be given in the documentation.
|
||||
*
|
||||
* [DISCOURAGED]
|
||||
* Indicates a directive which may cause undesirable side effects if
|
||||
* specified.
|
||||
*
|
||||
* [DEPRECATED]
|
||||
* Indicates a directive which will disappear in a future version of
|
||||
* Anope, usually because its functionality has been either
|
||||
@@ -87,8 +83,9 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* The services.host define is used in multiple different locations throughout the
|
||||
* configuration for the server name and pseudoclient hostnames.
|
||||
* The "services.host" define is used in multiple different locations throughout
|
||||
* the configuration for the server name and pseudoclient hostnames. You should
|
||||
* change the value to the hostname you wish to use for your services server.
|
||||
*/
|
||||
define
|
||||
{
|
||||
@@ -130,8 +127,9 @@ define
|
||||
* and serverinfo configuration would look like:
|
||||
*
|
||||
* # This goes in inspircd.conf, *NOT* your Anope config!
|
||||
* <module name="account">
|
||||
* <module name="hidechans">
|
||||
* <module name="services_account">
|
||||
* <module name="services">
|
||||
* <module name="spanningtree">
|
||||
* <bind address="127.0.0.1" port="7000" type="servers">
|
||||
* <link name="services.example.com"
|
||||
@@ -139,7 +137,7 @@ define
|
||||
* port="7000"
|
||||
* sendpass="mypassword"
|
||||
* recvpass="mypassword">
|
||||
* <uline server="services.example.com" silent="yes">
|
||||
* <services server="services.example.com" silent="yes">
|
||||
*
|
||||
* An example configuration for UnrealIRCd that is compatible with the below uplink
|
||||
* and serverinfo configuration would look like:
|
||||
@@ -347,7 +345,7 @@ networkinfo
|
||||
*
|
||||
* It is recommended you DON'T change this.
|
||||
*/
|
||||
disallow_start_or_end = ".-"
|
||||
disallow_start_or_end = ".-/"
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -512,7 +510,7 @@ options
|
||||
*
|
||||
* Removing .UTF-8 will instead use the default encoding for the language, e.g. iso-8859-1 for western European languages.
|
||||
*/
|
||||
languages = "de_DE.UTF-8 el_GR.UTF-8 es_ES.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 nl_NL.UTF-8 pl_PL.UTF-8 pt_PT.UTF-8 tr_TR.UTF-8"
|
||||
languages = "de_DE.UTF-8 el_GR.UTF-8 es_ES.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 nl_NL.UTF-8 pl_PL.UTF-8 pt_PT.UTF-8 ro_RO.UTF-8 tr_TR.UTF-8"
|
||||
|
||||
/*
|
||||
* Default language that non- and newly-registered nicks will receive messages in.
|
||||
@@ -587,7 +585,7 @@ include
|
||||
}
|
||||
|
||||
/*
|
||||
* [OPTIONAL] NickServ
|
||||
* [RECOMMENDED] NickServ
|
||||
*
|
||||
* Includes nickserv.example.conf, which is necessary for NickServ functionality.
|
||||
*
|
||||
@@ -745,11 +743,13 @@ log
|
||||
* nickserv/alist - Can see the channel access list of other users
|
||||
* nickserv/auspex - Can see any information with /NICKSERV INFO
|
||||
* nickserv/cert - Can modify other users certificate lists
|
||||
* nickserv/confirm - Can confirm other users nicknames
|
||||
* nickserv/confirm/email - Can confirm other users email address change
|
||||
* nickserv/confirm/register - Can confirm other users account registration
|
||||
* nickserv/drop - Can drop other users nicks
|
||||
* nickserv/drop/display - Allows dropping display nicks when preservedisplay is enabled
|
||||
* nickserv/drop/override - Allows dropping nicks without using a confirmation code
|
||||
* nickserv/recover - Can recover other users nicks
|
||||
* nickserv/resend - Can resend confirmation codes via email
|
||||
* operserv/config - Can modify services's configuration
|
||||
* operserv/oper/modify - Can add and remove operators with at most the same privileges
|
||||
* protected - Can not be kicked from channels by services
|
||||
@@ -814,10 +814,10 @@ opertype
|
||||
inherits = "Helper, Another Helper"
|
||||
|
||||
/* What commands (see above) this opertype may use */
|
||||
commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline"
|
||||
commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/resend nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline"
|
||||
|
||||
/* What privs (see above) this opertype has */
|
||||
privs = "chanserv/auspex chanserv/no-register-limit memoserv/* nickserv/auspex nickserv/confirm"
|
||||
privs = "chanserv/auspex chanserv/no-register-limit memoserv/* nickserv/auspex nickserv/confirm/*"
|
||||
|
||||
/*
|
||||
* Modes to be set on users when they identify to accounts linked to this opertype.
|
||||
@@ -994,7 +994,7 @@ mail
|
||||
registration_message = "Hi,
|
||||
|
||||
You have requested to register the nickname {nick} on {network}.
|
||||
Please type \" /msg NickServ CONFIRM {code} \" to complete registration.
|
||||
Please type \" /msg NickServ CONFIRM REGISTER {code} \" to complete registration.
|
||||
|
||||
If you don't know why this mail was sent to you, please ignore it silently.
|
||||
|
||||
@@ -1012,7 +1012,7 @@ mail
|
||||
reset_message = "Hi,
|
||||
|
||||
You have requested to have the password for {nick} reset.
|
||||
To reset your password, type \" /msg NickServ CONFIRM {nick} {code} \"
|
||||
To reset your password, type \" /msg NickServ CONFIRM RESETPASS {nick} {code} \"
|
||||
|
||||
If you don't know why this mail was sent to you, please ignore it silently.
|
||||
|
||||
@@ -1032,7 +1032,7 @@ mail
|
||||
emailchange_message = "Hi,
|
||||
|
||||
You have requested to change your email address from {old_email} to {new_email}.
|
||||
Please type \" /msg NickServ CONFIRM {code} \" to confirm this change.
|
||||
Please type \" /msg NickServ CONFIRM EMAIL {code} \" to confirm this change.
|
||||
|
||||
If you don't know why this mail was sent to you, please ignore it silently.
|
||||
|
||||
@@ -1066,97 +1066,44 @@ mail
|
||||
* have will not be stored!
|
||||
*/
|
||||
|
||||
/*
|
||||
* [DEPRECATED] db_old
|
||||
*
|
||||
* This is the old binary database format from late Anope 1.7.x, Anope 1.8.x, and
|
||||
* early Anope 1.9.x. This module only loads these databases, and will NOT save them.
|
||||
* You should only use this to upgrade old databases to a newer database format by loading
|
||||
* other database modules in addition to this one, which will be used when saving databases.
|
||||
*/
|
||||
#module
|
||||
{
|
||||
name = "db_old"
|
||||
|
||||
/*
|
||||
* This is the encryption type used by the databases. This must be set correctly or
|
||||
* your passwords will not work. Valid options are: md5, oldmd5, sha1, and plain.
|
||||
* You must also be sure to load the correct encryption module below in the Encryption
|
||||
* Modules section so that your passwords work.
|
||||
*/
|
||||
#hash = "md5"
|
||||
}
|
||||
|
||||
/*
|
||||
* db_atheme
|
||||
*
|
||||
* This allows importing databases from Atheme. You should load another database module as
|
||||
* well as this as it can only read Atheme databases not write them.
|
||||
* This allows importing databases from Atheme. You should load another database
|
||||
* module like db_json as well as this as it can only read Atheme databases not
|
||||
* write them.
|
||||
*/
|
||||
#module
|
||||
{
|
||||
name = "db_atheme"
|
||||
|
||||
/*
|
||||
* The database name db_atheme should use.
|
||||
* The file that db_atheme will import your main database from.
|
||||
*/
|
||||
database = "atheme.db"
|
||||
}
|
||||
|
||||
/*
|
||||
* [RECOMMENDED] db_flatfile
|
||||
* [DEPRECATED] db_flatfile
|
||||
*
|
||||
* This is the default flatfile database format.
|
||||
* This allows importing databases from the custom flat file format used between
|
||||
* Anope 1.9.6 and 2.1.17. You should load another database module like db_json
|
||||
* as well as this as it can only read db_flatfile databases not write them.
|
||||
*/
|
||||
module
|
||||
#module
|
||||
{
|
||||
name = "db_flatfile"
|
||||
|
||||
/*
|
||||
* The database name db_flatfile should use
|
||||
* The file that db_flatfile will import your main database from.
|
||||
*/
|
||||
database = "anope.db"
|
||||
|
||||
/*
|
||||
* Sets the number of days backups of databases are kept. If you don't give it,
|
||||
* or if you set it to 0, Anope won't backup the databases.
|
||||
*
|
||||
* This directive is optional, but recommended.
|
||||
*/
|
||||
keepbackups = 7
|
||||
|
||||
/*
|
||||
* Allows Anope to continue file write operations (i.e. database saving)
|
||||
* even if the original file cannot be backed up. Enabling this option may
|
||||
* allow Anope to continue operation under conditions where it might
|
||||
* otherwise fail, such as a nearly-full disk.
|
||||
*
|
||||
* NOTE: Enabling this option can cause irrecoverable data loss under some
|
||||
* conditions, so make CERTAIN you know what you're doing when you enable it!
|
||||
*
|
||||
* This directive is optional, and you are discouraged against enabling it.
|
||||
*/
|
||||
#nobackupokay = yes
|
||||
|
||||
/*
|
||||
* If enabled, services will fork a child process to save databases.
|
||||
*
|
||||
* This is only useful with very large databases, with hundreds
|
||||
* of thousands of objects, that have a noticeable delay from
|
||||
* writing databases.
|
||||
*/
|
||||
fork = no
|
||||
}
|
||||
|
||||
/*
|
||||
* db_json
|
||||
* [RECOMMENDED] db_json
|
||||
*
|
||||
* Stores your database in a JSON file.
|
||||
*
|
||||
* IMPORTANT: This will become the default database module in the future but is
|
||||
* currently experimental and has not been fully tested so make sure you have
|
||||
* db_flatfile loaded as a secondary database module if you use this as your
|
||||
* primary database module.
|
||||
*/
|
||||
module
|
||||
{
|
||||
@@ -1374,7 +1321,7 @@ module
|
||||
#module { name = "enc_posix" }
|
||||
|
||||
/*
|
||||
* [DEPRECATED] enc_md5, enc_none, enc_old, enc_sha1, enc_sha256
|
||||
* [DEPRECATED] enc_md5, enc_none, enc_sha1, enc_sha256
|
||||
*
|
||||
* Provides verify-only support for passwords encrypted using encryption methods
|
||||
* from older versions of Anope. These methods are no longer considered secure
|
||||
@@ -1384,8 +1331,6 @@ module
|
||||
* enc_md5: Verifies passwords encrypted with the MD5 algorithm
|
||||
* enc_none: Verifies passwords that are not encrypted
|
||||
* enc_sha1: Verifies passwords encrypted with the SHA1 algorithm
|
||||
* enc_old: Verifies passwords encrypted with the broken MD5 algorithm used
|
||||
* before 1.7.17.
|
||||
* enc_sha256: Verifies passwords encrypted with the SHA256 algorithm using a
|
||||
* custom initialisation vector as a salt.
|
||||
*
|
||||
@@ -1394,7 +1339,6 @@ module
|
||||
*/
|
||||
#module { name = "enc_md5" }
|
||||
#module { name = "enc_none" }
|
||||
#module { name = "enc_old" }
|
||||
#module { name = "enc_sha1" }
|
||||
#module { name = "enc_sha256" }
|
||||
|
||||
@@ -1414,23 +1358,3 @@ include
|
||||
type = "file"
|
||||
name = "chanstats.example.conf"
|
||||
}
|
||||
|
||||
/*
|
||||
* [DEPRECATED] IRC2SQL Gateway
|
||||
*
|
||||
* This module collects data about users, channels and servers. It doesn't build stats
|
||||
* itself, however, it gives you the database, it's up to you how you use it.
|
||||
*
|
||||
* This module is deprecated in favour of the RPC interface and the rpc_data
|
||||
* module. This should provide almost all of the same information as irc2sql but
|
||||
* without requiring MySQL and with much better performance. If you have a use
|
||||
* case which is not covered by rpc_data then please open an issue so we can
|
||||
* extend rpc_data before irc2sql is removed.
|
||||
*
|
||||
* Requires a MySQL Database and MySQL version 5.5 or higher
|
||||
*/
|
||||
#include
|
||||
{
|
||||
type = "file"
|
||||
name = "irc2sql.example.conf"
|
||||
}
|
||||
|
||||
@@ -296,11 +296,9 @@ command { service = "BotServ"; name = "KICK ITALICS"; command = "botserv/kick/it
|
||||
command { service = "BotServ"; name = "KICK REPEAT"; command = "botserv/kick/repeat"; }
|
||||
command { service = "BotServ"; name = "KICK REVERSES"; command = "botserv/kick/reverses"; }
|
||||
command { service = "BotServ"; name = "KICK UNDERLINES"; command = "botserv/kick/underlines"; }
|
||||
|
||||
command { service = "BotServ"; name = "SET DONTKICKOPS"; command = "botserv/set/dontkickops"; }
|
||||
command { service = "BotServ"; name = "SET DONTKICKVOICES"; command = "botserv/set/dontkickvoices"; }
|
||||
|
||||
|
||||
/*
|
||||
* bs_set
|
||||
*
|
||||
@@ -341,7 +339,6 @@ privilege
|
||||
xop = "AOP"
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fantasy
|
||||
*
|
||||
@@ -387,7 +384,7 @@ fantasy { name = "ENFORCE"; command = "chanserv/enforce"; }
|
||||
fantasy { name = "ENTRYMSG"; command = "chanserv/entrymsg"; }
|
||||
fantasy { name = "FLAGS"; command = "chanserv/flags"; }
|
||||
fantasy { name = "HALFOP"; command = "chanserv/modes"; }
|
||||
fantasy { name = "HELP"; command = "generic/help"; prepend_channel = no; }
|
||||
fantasy { name = "HELP"; command = "generic/help"; prepend_channel = no; require_privilege = no; }
|
||||
fantasy { name = "HOP"; command = "chanserv/xop"; }
|
||||
fantasy { name = "INFO"; command = "chanserv/info"; prepend_channel = no; }
|
||||
fantasy { name = "INVITE"; command = "chanserv/invite"; }
|
||||
|
||||
+25
-23
@@ -100,6 +100,7 @@ module
|
||||
* not in use.
|
||||
* - cs_no_expire: Enables no expire. Needs founder, successor (if set) or anyone in the access list
|
||||
* to be a registered nick, otherwise the channel will be dropped.
|
||||
* - cs_stats: Enable Chanstats for newly registered channels
|
||||
* - none: No defaults
|
||||
*
|
||||
* This directive is optional, if left blank, the options will default to cs_keep_modes, keeptopic, peace,
|
||||
@@ -946,7 +947,7 @@ command { service = "ChanServ"; name = "AKICK"; command = "chanserv/akick"; grou
|
||||
* Used for banning users from channels.
|
||||
*/
|
||||
module { name = "cs_ban" }
|
||||
command { service = "ChanServ"; name = "BAN"; command = "chanserv/ban"; }
|
||||
command { service = "ChanServ"; name = "BAN"; command = "chanserv/ban"; group = "chanserv/management"; }
|
||||
|
||||
/*
|
||||
* cs_clone
|
||||
@@ -989,8 +990,20 @@ module
|
||||
{
|
||||
name = "cs_entrymsg"
|
||||
|
||||
/* The maximum number of entrymsgs allowed per channel. If not set, defaults to 5. */
|
||||
/*
|
||||
* The maximum number of entry messages allowed per channel.
|
||||
*
|
||||
* Defaults to 5
|
||||
*/
|
||||
maxentries = 5
|
||||
|
||||
/*
|
||||
* Whether to include an IRCv3 time tag for the original add time on entry
|
||||
* messages.
|
||||
*
|
||||
* Defaults to yes.
|
||||
*/
|
||||
#timestamp = no
|
||||
}
|
||||
command { service = "ChanServ"; name = "ENTRYMSG"; command = "chanserv/entrymsg"; group = "chanserv/management"; }
|
||||
|
||||
@@ -1047,7 +1060,7 @@ command { service = "ChanServ"; name = "INVITE"; command = "chanserv/invite"; }
|
||||
* Used for kicking users from channels.
|
||||
*/
|
||||
module { name = "cs_kick" }
|
||||
command { service = "ChanServ"; name = "KICK"; command = "chanserv/kick"; }
|
||||
command { service = "ChanServ"; name = "KICK"; command = "chanserv/kick"; group = "chanserv/management"; }
|
||||
|
||||
/*
|
||||
* cs_list
|
||||
@@ -1066,10 +1079,8 @@ module
|
||||
listmax = 50
|
||||
}
|
||||
command { service = "ChanServ"; name = "LIST"; command = "chanserv/list"; }
|
||||
|
||||
command { service = "ChanServ"; name = "SET PRIVATE"; command = "chanserv/set/private"; }
|
||||
|
||||
|
||||
/*
|
||||
* cs_log
|
||||
*
|
||||
@@ -1155,7 +1166,6 @@ command { service = "ChanServ"; name = "DEHALFOP"; command = "chanserv/modes"; g
|
||||
command { service = "ChanServ"; name = "VOICE"; command = "chanserv/modes"; group = "chanserv/status"; set = "VOICE" }
|
||||
command { service = "ChanServ"; name = "DEVOICE"; command = "chanserv/modes"; group = "chanserv/status"; unset = "VOICE" }
|
||||
|
||||
|
||||
/*
|
||||
* cs_register
|
||||
*
|
||||
@@ -1178,9 +1188,6 @@ module
|
||||
{
|
||||
name = "cs_seen"
|
||||
|
||||
/* If set, uses the older 1.8 style seen, which is less resource intensive */
|
||||
simple = no
|
||||
|
||||
/* Sets the time to keep seen entries in the seen database. */
|
||||
purgetime = 90d
|
||||
}
|
||||
@@ -1271,6 +1278,14 @@ module { name = "cs_status" }
|
||||
command { service = "ChanServ"; name = "STATUS"; command = "chanserv/status"; }
|
||||
command { service = "ChanServ"; name = "WHY"; command = "chanserv/status"; hide = yes; }
|
||||
|
||||
/*
|
||||
* cs_statusupdate
|
||||
*
|
||||
* This module automatically updates users' status on channels when the
|
||||
* channel's access list is modified.
|
||||
*/
|
||||
module { name = "cs_statusupdate" }
|
||||
|
||||
/*
|
||||
* cs_suspend
|
||||
*
|
||||
@@ -1330,7 +1345,7 @@ command { service = "ChanServ"; name = "SET KEEPTOPIC"; command = "chanserv/set/
|
||||
* Used for unbanning users from channels.
|
||||
*/
|
||||
module { name = "cs_unban" }
|
||||
command { service = "ChanServ"; name = "UNBAN"; command = "chanserv/unban"; }
|
||||
command { service = "ChanServ"; name = "UNBAN"; command = "chanserv/unban"; group = "chanserv/management"; }
|
||||
|
||||
/*
|
||||
* cs_updown
|
||||
@@ -1363,16 +1378,3 @@ command { service = "ChanServ"; name = "SOP"; command = "chanserv/xop"; group =
|
||||
command { service = "ChanServ"; name = "AOP"; command = "chanserv/xop"; group = "chanserv/access"; }
|
||||
command { service = "ChanServ"; name = "HOP"; command = "chanserv/xop"; group = "chanserv/access"; }
|
||||
command { service = "ChanServ"; name = "VOP"; command = "chanserv/xop"; group = "chanserv/access"; }
|
||||
|
||||
|
||||
/*
|
||||
* Extra ChanServ related modules.
|
||||
*/
|
||||
|
||||
/*
|
||||
* cs_statusupdate
|
||||
*
|
||||
* This module automatically updates users' status on channels when the
|
||||
* channel's access list is modified.
|
||||
*/
|
||||
module { name = "cs_statusupdate" }
|
||||
|
||||
@@ -93,7 +93,7 @@ module
|
||||
#globaloncycleup = "Services are now back online - have a nice day"
|
||||
|
||||
/*
|
||||
* If set, Anope will hide the IRC Operator's nick in a global
|
||||
* If set, Anope will hide the Services Operator's nick in a global
|
||||
* message/notice.
|
||||
*
|
||||
* This directive is optional.
|
||||
|
||||
@@ -168,7 +168,13 @@ command { service = "HostServ"; name = "ON"; command = "hostserv/on"; }
|
||||
/*
|
||||
* hs_request
|
||||
*
|
||||
* Provides the commands hostserv/request, hostserv/activate, hostserv/reject, and hostserv/waiting.
|
||||
* Provides the commands:
|
||||
* hostserv/request - Requests a vhost.
|
||||
* hostserv/activate - Approves a requested vhost.
|
||||
* hostserv/reject - Rejects a requested vhost.
|
||||
* hostserv/waiting - Lists pending vhost requests.
|
||||
* hostserv/validate - Allows self-service approval of vhosts using DNS
|
||||
* validation (requires the dns module).
|
||||
*
|
||||
* Used to manage vhosts requested by users.
|
||||
*/
|
||||
@@ -186,11 +192,24 @@ module
|
||||
* If set, Anope will send a memo to all services staff when a new vhost is requested.
|
||||
*/
|
||||
#memooper = yes
|
||||
|
||||
/*
|
||||
* If DNS validation is enabled, how long should users have to wait between
|
||||
* attempts at DNS validation. Defaults to 5 minutes.
|
||||
*/
|
||||
#validationcooldown = 5m
|
||||
|
||||
/*
|
||||
* If DNS validation is enabled, the TXT record to look for when determining
|
||||
* if the requester controls the domain. Defaults to anope-dns-validation.
|
||||
*/
|
||||
#validationrecord = "anope-dns-validation"
|
||||
}
|
||||
command { service = "HostServ"; name = "REQUEST"; command = "hostserv/request"; }
|
||||
command { service = "HostServ"; name = "ACTIVATE"; command = "hostserv/activate"; permission = "hostserv/set"; }
|
||||
command { service = "HostServ"; name = "REJECT"; command = "hostserv/reject"; permission = "hostserv/set"; }
|
||||
command { service = "HostServ"; name = "WAITING"; command = "hostserv/waiting"; permission = "hostserv/set"; }
|
||||
#command { service = "HostServ"; name = "VALIDATE"; command = "hostserv/validate"; }
|
||||
|
||||
/*
|
||||
* hs_set
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Example configuration file for the irc2sql gateway
|
||||
*
|
||||
*/
|
||||
|
||||
service
|
||||
{
|
||||
/*
|
||||
* The name of the StatServ client.
|
||||
*/
|
||||
nick = "StatServ"
|
||||
|
||||
/*
|
||||
* The username of the StatServ client.
|
||||
*/
|
||||
user = "StatServ"
|
||||
|
||||
/*
|
||||
* The hostname of the StatServ client.
|
||||
*/
|
||||
host = "${services.host}"
|
||||
|
||||
/*
|
||||
* The realname of the StatServ client.
|
||||
*/
|
||||
real = "Statistical Service"
|
||||
|
||||
/*
|
||||
* The modes this client should use.
|
||||
* Do not modify this unless you know what you are doing.
|
||||
*
|
||||
* These modes are very IRCd specific. If left commented, sane defaults
|
||||
* are used based on what protocol module you have loaded.
|
||||
*
|
||||
* Note that setting this option incorrectly could potentially BREAK some, if
|
||||
* not all, usefulness of the client. We will not support you if this client is
|
||||
* unable to do certain things if this option is enabled.
|
||||
*/
|
||||
#modes = "+o"
|
||||
|
||||
/*
|
||||
* An optional comma separated list of channels this service should join. Outside
|
||||
* of log channels this is not very useful, as the service will just idle in the
|
||||
* specified channels, and will not accept any types of commands.
|
||||
*
|
||||
* Prefixes may be given to the channels in the form of mode characters or prefix symbols.
|
||||
*/
|
||||
#channels = "@#stats,#mychan"
|
||||
}
|
||||
|
||||
module
|
||||
{
|
||||
name = "irc2sql"
|
||||
|
||||
/*
|
||||
* The name of the client that should send the CTCP VERSION requests.
|
||||
* It must already exist or must be defined in the following service block.
|
||||
*/
|
||||
client = "StatServ"
|
||||
|
||||
/*
|
||||
* The name of the SQL engine to use.
|
||||
* This must be MySQL and must match the name in the mysql{} block
|
||||
*/
|
||||
engine = "mysql/main"
|
||||
|
||||
/*
|
||||
* An optional prefix to prepended to the name of each created table.
|
||||
* Do not use the same prefix for other programs.
|
||||
*/
|
||||
prefix = "anope_"
|
||||
|
||||
/*
|
||||
* GeoIP - Automatically adds users geoip location to the user table.
|
||||
* Tables are created by irc2sql, you have to run the
|
||||
* geoipupdate script after you started Anope to download
|
||||
* and import the GeoIP database.
|
||||
*
|
||||
* The geoip database can be the smaller "country" database or the
|
||||
* larger "city" database. Comment to disable geoip lookup.
|
||||
*/
|
||||
geoip_database = "country"
|
||||
|
||||
/*
|
||||
* Get the CTCP version from users
|
||||
* The users connecting to the network will receive a CTCP VERSION
|
||||
* request from the above configured stats client
|
||||
*/
|
||||
ctcpuser = "yes"
|
||||
|
||||
/*
|
||||
* Send out CTCP VERSION requests to users during burst.
|
||||
* Disable this if you restart Anope often and don't want to
|
||||
* annoy your users.
|
||||
*/
|
||||
ctcpeob = "yes"
|
||||
}
|
||||
@@ -196,8 +196,6 @@ command { service = "MemoServ"; name = "READ"; command = "memoserv/read"; }
|
||||
* Provides the command memoserv/rsend.
|
||||
*
|
||||
* Used to send a memo requiring a receipt be sent back once it is read.
|
||||
*
|
||||
* Requires configuring memoserv:memoreceipt.
|
||||
*/
|
||||
#module
|
||||
{
|
||||
|
||||
+16
-18
@@ -41,7 +41,6 @@ module { name = "help" }
|
||||
*/
|
||||
timeout = 5
|
||||
|
||||
|
||||
/* Only edit below if you are expecting to use os_dns or otherwise answer DNS queries. */
|
||||
|
||||
/*
|
||||
@@ -54,7 +53,6 @@ module { name = "help" }
|
||||
ip = "0.0.0.0"
|
||||
port = 53
|
||||
|
||||
|
||||
/*
|
||||
* SOA record information.
|
||||
*/
|
||||
@@ -65,7 +63,7 @@ module { name = "help" }
|
||||
/* This should be the names of the public facing nameservers serving the records. */
|
||||
nameservers = "ns1.example.com ns2.example.com"
|
||||
|
||||
/* The time slave servers are allowed to cache. This should be reasonably low
|
||||
/* The time secondary servers are allowed to cache for. This should be reasonably low
|
||||
* if you want your records to be updated without much delay.
|
||||
*/
|
||||
refresh = 3600
|
||||
@@ -233,7 +231,7 @@ module { name = "help" }
|
||||
}
|
||||
|
||||
/*
|
||||
* ldap [EXTRA]
|
||||
* [EXTRA] ldap
|
||||
*
|
||||
* This module allows other modules to use LDAP. By itself, this module does nothing useful.
|
||||
*/
|
||||
@@ -304,13 +302,13 @@ module { name = "help" }
|
||||
*
|
||||
* If not set, then registration is not blocked.
|
||||
*/
|
||||
#disable_register_reason = "To register on this network visit https://some.misconfigured.site/register"
|
||||
#disable_register_reason = "To register on this network visit https://some.misconfigured.site.example/register"
|
||||
|
||||
/*
|
||||
* If set, the reason to give the users who try to "/msg NickServ SET EMAIL".
|
||||
* If not set, then email changing is not blocked.
|
||||
*/
|
||||
#disable_email_reason = "To change your email address visit https://some.misconfigured.site"
|
||||
#disable_email_reason = "To change your email address visit https://some.misconfigured.site.example"
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -355,7 +353,7 @@ module { name = "help" }
|
||||
}
|
||||
|
||||
/*
|
||||
* mysql [EXTRA]
|
||||
* [EXTRA] mysql
|
||||
*
|
||||
* This module allows other modules to use MySQL.
|
||||
*/
|
||||
@@ -402,7 +400,7 @@ module { name = "help" }
|
||||
}
|
||||
|
||||
/*
|
||||
* regex_pcre2 [EXTRA]
|
||||
* [EXTRA] regex_pcre2
|
||||
*
|
||||
* Provides the regex engine regex/pcre, which uses version 2 of the Perl Compatible Regular
|
||||
* Expressions library.
|
||||
@@ -410,7 +408,7 @@ module { name = "help" }
|
||||
#module { name = "regex_pcre2" }
|
||||
|
||||
/*
|
||||
* regex_posix [EXTRA]
|
||||
* [EXTRA] regex_posix
|
||||
*
|
||||
* Provides the regex engine regex/posix, which uses the POSIX compliant regular expressions.
|
||||
*/
|
||||
@@ -440,7 +438,7 @@ module
|
||||
}
|
||||
|
||||
/*
|
||||
* regex_tre [EXTRA]
|
||||
* [EXTRA] regex_tre
|
||||
*
|
||||
* Provides the regex engine regex/tre, which uses the TRE regex library.
|
||||
*/
|
||||
@@ -559,7 +557,7 @@ module
|
||||
}
|
||||
|
||||
/*
|
||||
* ssl_gnutls [EXTRA]
|
||||
* [EXTRA] ssl_gnutls
|
||||
*
|
||||
* This module provides SSL services to Anope using GnuTLS, for example to
|
||||
* connect to the uplink server(s) via SSL.
|
||||
@@ -598,7 +596,7 @@ module
|
||||
}
|
||||
|
||||
/*
|
||||
* ssl_openssl [EXTRA]
|
||||
* [EXTRA] ssl_openssl
|
||||
*
|
||||
* This module provides SSL services to Anope using OpenSSL, for example to
|
||||
* connect to the uplink server(s) via SSL.
|
||||
@@ -691,20 +689,20 @@ module
|
||||
* If set, the reason to give the users who try to "/msg NickServ REGISTER".
|
||||
* If not set, then registration is not blocked.
|
||||
*/
|
||||
#disable_reason = "To register on this network visit https://some.misconfigured.site/register"
|
||||
#disable_reason = "To register on this network visit https://some.misconfigured.site.example/register"
|
||||
|
||||
/*
|
||||
* If set, the reason to give the users who try to "/msg NickServ SET EMAIL".
|
||||
* If not set, then email changing is not blocked.
|
||||
*/
|
||||
#disable_email_reason = "To change your email address visit https://some.misconfigured.site"
|
||||
#disable_email_reason = "To change your email address visit https://some.misconfigured.site.example"
|
||||
}
|
||||
|
||||
/*
|
||||
* sql_log
|
||||
*
|
||||
* This module adds an additional target option to log{} blocks
|
||||
* that allows logging Service's logs to SQL. To log to SQL, add
|
||||
* that allows logging Services' logs to SQL. To log to SQL, add
|
||||
* the SQL service name to log:targets prefixed by sql_log:. For
|
||||
* example:
|
||||
*
|
||||
@@ -723,8 +721,8 @@ module
|
||||
/*
|
||||
* sql_oper
|
||||
*
|
||||
* This module allows granting users services operator privileges and possibly IRC Operator
|
||||
* privileges based on an external SQL database using a custom query.
|
||||
* This module allows granting users Services Operator privileges based on an
|
||||
* external SQL database using a custom query.
|
||||
*/
|
||||
#module
|
||||
{
|
||||
@@ -747,7 +745,7 @@ module
|
||||
}
|
||||
|
||||
/*
|
||||
* sqlite [EXTRA]
|
||||
* [EXTRA] sqlite
|
||||
*
|
||||
* This module allows other modules to use SQLite.
|
||||
*/
|
||||
|
||||
+138
-37
@@ -118,6 +118,7 @@ module
|
||||
* - msg: Messages will be sent as PRIVMSGs instead of NOTICEs
|
||||
* - ns_keep_modes: Enables keepmodes, which retains user modes across sessions
|
||||
* - protect: Protects the registered nickname from use by unidentified users.
|
||||
* - ns_stats: Enable Chanstats for newly registered nicks
|
||||
*
|
||||
* This directive is optional, if left blank, the options will default to memo_signon, and
|
||||
* memo_receive. If you really want no defaults, use "none" by itself as the option.
|
||||
@@ -250,8 +251,8 @@ module
|
||||
maxpasslen = 50
|
||||
|
||||
/*
|
||||
* Whether all of the secondary nicks of a nick group have to expire or be
|
||||
dropped before the display nick can expire or be dropped.
|
||||
* Whether all of the secondary nicks of an account have to expire or be
|
||||
* dropped before the display nick can expire or be dropped.
|
||||
*/
|
||||
preservedisplay = no
|
||||
}
|
||||
@@ -335,6 +336,16 @@ module
|
||||
}
|
||||
command { service = "NickServ"; name = "CERT"; command = "nickserv/cert"; }
|
||||
|
||||
/*
|
||||
* ns_confirm
|
||||
*
|
||||
* Provides the command nickserv/confirm.
|
||||
*
|
||||
* Used for confirming previous account actions.
|
||||
*/
|
||||
module { name = "ns_confirm" }
|
||||
command { service = "NickServ"; name = "CONFIRM"; command = "nickserv/confirm"; }
|
||||
|
||||
/*
|
||||
* ns_drop
|
||||
*
|
||||
@@ -351,6 +362,7 @@ command { service = "NickServ"; name = "DROP"; command = "nickserv/drop"; }
|
||||
* Provides various functionality relating to email addresses. This includes the
|
||||
* following commands:
|
||||
*
|
||||
* - nickserv/confirm/email: Used for confirming email changes.
|
||||
* - nickserv/getemail: Used for getting accounts by searching for emails.
|
||||
* - nickserv/set/email, nickserv/saset/email: Used for setting an account's
|
||||
* emailvaddress.
|
||||
@@ -359,6 +371,12 @@ module
|
||||
{
|
||||
name = "ns_email"
|
||||
|
||||
/*
|
||||
* The amount of time a user has after requesting a change of email address
|
||||
* before it expires. Defaults to 1 day.
|
||||
*/
|
||||
#changeexpire = 1d
|
||||
|
||||
/*
|
||||
* The limit to how many registered accounts can use the same email address.
|
||||
* If set to 0 or left commented there will be no limit enforced when
|
||||
@@ -373,7 +391,7 @@ module
|
||||
*/
|
||||
#remove_aliases = yes
|
||||
}
|
||||
|
||||
command { service = "NickServ"; name = "CONFIRM EMAIL"; command = "nickserv/confirm/email"; }
|
||||
command { service = "NickServ"; name = "GETEMAIL"; command = "nickserv/getemail"; permission = "nickserv/getemail"; group = "nickserv/admin"; }
|
||||
command { service = "NickServ"; name = "SET EMAIL"; command = "nickserv/set/email"; }
|
||||
command { service = "NickServ"; name = "SASET EMAIL"; command = "nickserv/saset/email"; permission = "nickserv/saset/email"; }
|
||||
@@ -381,9 +399,14 @@ command { service = "NickServ"; name = "SASET EMAIL"; command = "nickserv/saset/
|
||||
/*
|
||||
* ns_group
|
||||
*
|
||||
* Provides the commands nickserv/group, nickserv/glist, and nickserv/ungroup.
|
||||
* Provides the commands:
|
||||
* nickserv/group
|
||||
* nickserv/ungroup
|
||||
* nickserv/glist
|
||||
* nickserv/saset/display
|
||||
* nickserv/set/display
|
||||
*
|
||||
* Used for controlling nick groups.
|
||||
* Used for controlling grouped nicknames.
|
||||
*/
|
||||
module
|
||||
{
|
||||
@@ -408,6 +431,12 @@ module
|
||||
command { service = "NickServ"; name = "GLIST"; command = "nickserv/glist"; }
|
||||
command { service = "NickServ"; name = "GROUP"; command = "nickserv/group"; }
|
||||
command { service = "NickServ"; name = "UNGROUP"; command = "nickserv/ungroup"; }
|
||||
command { service = "NickServ"; name = "SET DISPLAY"; command = "nickserv/set/display"; }
|
||||
command { service = "NickServ"; name = "SASET DISPLAY"; command = "nickserv/saset/display"; permission = "nickserv/saset/display"; }
|
||||
|
||||
# For compatibility with Atheme.
|
||||
command { service = "NickServ"; name = "SET ACCOUNTNAME"; command = "nickserv/set/display"; hide = yes; }
|
||||
command { service = "NickServ"; name = "SASET ACCOUNTNAME"; command = "nickserv/saset/display"; permission = "nickserv/saset/display"; hide = yes; }
|
||||
|
||||
/*
|
||||
* ns_identify
|
||||
@@ -442,7 +471,6 @@ command { service = "NickServ"; name = "INFO"; command = "nickserv/info"; }
|
||||
command { service = "NickServ"; name = "SET HIDE"; command = "nickserv/set/hide"; }
|
||||
command { service = "NickServ"; name = "SASET HIDE"; command = "nickserv/saset/hide"; permission = "nickserv/saset/hide"; }
|
||||
|
||||
|
||||
/*
|
||||
* ns_list
|
||||
*
|
||||
@@ -461,11 +489,9 @@ module
|
||||
listmax = 50
|
||||
}
|
||||
command { service = "NickServ"; name = "LIST"; command = "nickserv/list"; }
|
||||
|
||||
command { service = "NickServ"; name = "SET PRIVATE"; command = "nickserv/set/private"; }
|
||||
command { service = "NickServ"; name = "SASET PRIVATE"; command = "nickserv/saset/private"; permission = "nickserv/saset/private"; }
|
||||
|
||||
|
||||
/*
|
||||
* ns_logout
|
||||
*
|
||||
@@ -504,7 +530,7 @@ command { service = "NickServ"; name = "RELEASE"; command = "nickserv/recover";
|
||||
/*
|
||||
* ns_register
|
||||
*
|
||||
* Provides the commands nickserv/confirm, nickserv/register, and nickserv/resend.
|
||||
* Provides the commands nickserv/confirm/register, nickserv/register, and nickserv/resend.
|
||||
*
|
||||
* Used for registering accounts.
|
||||
*/
|
||||
@@ -513,11 +539,15 @@ module
|
||||
name = "ns_register"
|
||||
|
||||
/*
|
||||
* Registration confirmation setting. Set to "none" for no registration confirmation,
|
||||
* "mail" for email confirmation, and "admin" to have services operators manually confirm
|
||||
* every registration. Set to "disable" to completely disable all registrations.
|
||||
* The method for confirming account registrations. Possible values are:
|
||||
*
|
||||
* "admin" to require confirmation by a Services Operator.
|
||||
* "code" to require confirmation with a code provided via IRC.
|
||||
* "disable" to disable account registration.
|
||||
* "mail" to require confirmation with a code provided via email.
|
||||
* "none" to automatically confirm (this is the default).
|
||||
*/
|
||||
registration = "none"
|
||||
registration = "code"
|
||||
|
||||
/*
|
||||
* The minimum length of time between consecutive uses of NickServ's RESEND command.
|
||||
@@ -532,7 +562,7 @@ module
|
||||
*
|
||||
* This directive is optional.
|
||||
*/
|
||||
nickregdelay = 15s
|
||||
#nickregdelay = 1m
|
||||
|
||||
/*
|
||||
* The length of time a user using an unconfirmed account has
|
||||
@@ -540,20 +570,33 @@ module
|
||||
*/
|
||||
#unconfirmedexpire = 1d
|
||||
}
|
||||
command { service = "NickServ"; name = "CONFIRM"; command = "nickserv/confirm"; }
|
||||
command { service = "NickServ"; name = "CONFIRM REGISTER"; command = "nickserv/confirm/register"; }
|
||||
command { service = "NickServ"; name = "REGISTER"; command = "nickserv/register"; }
|
||||
command { service = "NickServ"; name = "RESEND"; command = "nickserv/resend"; }
|
||||
|
||||
/*
|
||||
* ns_resetpass
|
||||
*
|
||||
* Provides the command nickserv/resetpass.
|
||||
* Provides the command nickserv/confirm/resetpass and nickserv/resetpass.
|
||||
*
|
||||
* Used for resetting passwords by emailing users a temporary one.
|
||||
*/
|
||||
module { name = "ns_resetpass" }
|
||||
module
|
||||
{
|
||||
name = "ns_resetpass"
|
||||
|
||||
/*
|
||||
* The amount of time a user has after requesting a password reset before it
|
||||
* expires. Defaults to 1 day.
|
||||
*/
|
||||
#resetexpire = 1d
|
||||
}
|
||||
command { service = "NickServ"; name = "CONFIRM RESETPASS"; command = "nickserv/confirm/resetpass"; }
|
||||
command { service = "NickServ"; name = "RESETPASS"; command = "nickserv/resetpass"; }
|
||||
|
||||
# For compatibility with Anope 2.0.
|
||||
command { service = "NickServ"; name = "GETPASS"; command = "nickserv/resetpass"; hide = yes; }
|
||||
|
||||
/*
|
||||
* ns_sasl
|
||||
*
|
||||
@@ -573,17 +616,46 @@ module
|
||||
* The nick of the client which operates as the SASL agent.
|
||||
*/
|
||||
#agent = "NickServ"
|
||||
|
||||
/*
|
||||
* Sets the number of invalid SASL authentication attempts before services
|
||||
* removes a partially-connected user from the network. If not defined then
|
||||
* the value specified in options:badpasslimit will be used instead.
|
||||
*/
|
||||
#badpasslimit = 1
|
||||
|
||||
/*
|
||||
* Sets the time after which invalid SASL authentication attempts are
|
||||
* forgotten about. If a user does not fail to authenticate in this amount
|
||||
* of time, the incorrect password count will reset to zero. If not defined
|
||||
* then the value specified in options:badpasstimeout will be used instead.
|
||||
*/
|
||||
#badpasstimeout = 15m
|
||||
}
|
||||
|
||||
/*
|
||||
* ns_sasl_anonymous, ns_sasl_external, ns_sasl_plain
|
||||
*
|
||||
* Provides support for the following SASL mechanisms:
|
||||
*
|
||||
* ns_sasl_anonymous: Adds the ANONYMOUS mechanism which allows logging out of
|
||||
* an account. See RFC 4505 for more details.
|
||||
* ns_sasl_external: Adds the EXTERNAL mechanism which allows logging into an
|
||||
account using a TLS client certificate. See RFC 4422 for
|
||||
for more details.
|
||||
* ns_sasl_plain: Adds the PLAIN mechanism which allows logging in to an
|
||||
account using a plain text username and password. See RFC
|
||||
4422 for more details.
|
||||
*/
|
||||
module { name = "ns_sasl_anonymous" }
|
||||
module { name = "ns_sasl_external" }
|
||||
module { name = "ns_sasl_plain" }
|
||||
|
||||
/*
|
||||
* ns_set
|
||||
*
|
||||
* Provides the commands:
|
||||
* nickserv/set, nickserv/saset - Dummy help wrappers for the SET and SASET commands.
|
||||
* nickserv/set/autoop, nickserv/saset/autoop - Determines whether or not modes are automatically set users when joining a channel.
|
||||
* nickserv/set/display, nickserv/saset/display - Used for setting a users display name.
|
||||
* nickserv/set/keepmodes, nickserv/saset/keepmodes - Configure whether or not services should retain a user's modes across sessions.
|
||||
* nickserv/set/neverop, nickserv/saset/neverop - Used to configure whether a user can be added to access lists
|
||||
* nickserv/saset/noexpire - Used for configuring noexpire, which prevents nicks from expiring.
|
||||
* nickserv/set/password, nickserv/saset/password - Used for changing a users password.
|
||||
*/
|
||||
@@ -592,18 +664,9 @@ module { name = "ns_set" }
|
||||
command { service = "NickServ"; name = "SET"; command = "nickserv/set"; }
|
||||
command { service = "NickServ"; name = "SASET"; command = "nickserv/saset"; permission = "nickserv/saset/"; group = "nickserv/admin"; }
|
||||
|
||||
command { service = "NickServ"; name = "SET AUTOOP"; command = "nickserv/set/autoop"; }
|
||||
command { service = "NickServ"; name = "SASET AUTOOP"; command = "nickserv/saset/autoop"; permission = "nickserv/saset/autoop"; }
|
||||
|
||||
command { service = "NickServ"; name = "SET DISPLAY"; command = "nickserv/set/display"; }
|
||||
command { service = "NickServ"; name = "SASET DISPLAY"; command = "nickserv/saset/display"; permission = "nickserv/saset/display"; }
|
||||
|
||||
command { service = "NickServ"; name = "SET PASSWORD"; command = "nickserv/set/password"; }
|
||||
command { service = "NickServ"; name = "SASET PASSWORD"; command = "nickserv/saset/password"; permission = "nickserv/saset/password"; }
|
||||
|
||||
command { service = "NickServ"; name = "SET NEVEROP"; command = "nickserv/set/neverop"; }
|
||||
command { service = "NickServ"; name = "SASET NEVEROP"; command = "nickserv/saset/neverop"; permission = "nickserv/saset/neverop"; }
|
||||
|
||||
command { service = "NickServ"; name = "SASET NOEXPIRE"; command = "nickserv/saset/noexpire"; permission = "nickserv/saset/noexpire"; }
|
||||
|
||||
/*
|
||||
@@ -638,6 +701,17 @@ module { name = "ns_set_language" }
|
||||
command { service = "NickServ"; name = "SET LANGUAGE"; command = "nickserv/set/language"; }
|
||||
command { service = "NickServ"; name = "SASET LANGUAGE"; command = "nickserv/saset/language"; permission = "nickserv/saset/language"; }
|
||||
|
||||
/*
|
||||
* ns_set_layout
|
||||
*
|
||||
* Provides the command nickserv/set/layout and nickserv/saset/layout.
|
||||
*
|
||||
* Allows configuring the layout that services uses.
|
||||
*/
|
||||
module { name = "ns_set_layout" }
|
||||
command { service = "NickServ"; name = "SET LAYOUT"; command = "nickserv/set/layout"; }
|
||||
command { service = "NickServ"; name = "SASET LAYOUT"; command = "nickserv/saset/layout"; permission = "nickserv/saset/layout"; }
|
||||
|
||||
/*
|
||||
* ns_set_message
|
||||
*
|
||||
@@ -664,29 +738,56 @@ command { service = "NickServ"; name = "SASET LANGUAGE"; command = "nickserv/sas
|
||||
module { name = "ns_set_misc" }
|
||||
command { service = "NickServ"; name = "SET URL"; command = "nickserv/set/misc"; misc_description = _("Associate a URL with your account"); }
|
||||
command { service = "NickServ"; name = "SASET URL"; command = "nickserv/saset/misc"; misc_description = _("Associate a URL with this account"); permission = "nickserv/saset/url"; group = "nickserv/admin"; }
|
||||
#command { service = "NickServ"; name = "SET DISCORD"; command = "nickserv/set/misc"; misc_description = _("Associate a Discord account with your account"); }
|
||||
#command { service = "NickServ"; name = "SASET DISCORD"; command = "nickserv/saset/misc"; misc_description = _("Associate a Discord account with this account"); permission = "nickserv/saset/discord"; group = "nickserv/admin"; }
|
||||
#command { service = "NickServ"; name = "SET MASTODON"; command = "nickserv/set/misc"; misc_description = _("Associate a Mastodon account with your account"); }
|
||||
#command { service = "NickServ"; name = "SASET MASTODON"; command = "nickserv/saset/misc"; misc_description = _("Associate a Mastodon account with this account"); permission = "nickserv/saset/mastodon"; group = "nickserv/admin"; }
|
||||
#command { service = "NickServ"; name = "SET TIMEZONE"; command = "nickserv/set/misc"; misc_description = _("Associate a time zone with your account"); }
|
||||
#command { service = "NickServ"; name = "SASET TIMEZONE"; command = "nickserv/saset/misc"; misc_description = _("Associate a time zone with this account"); permission = "nickserv/saset/timezone"; group = "nickserv/admin"; }
|
||||
#command { service = "NickServ"; name = "SET LOCATION"; command = "nickserv/set/misc"; misc_description = _("Associate a location with your account"); }
|
||||
#command { service = "NickServ"; name = "SASET LOCATION"; command = "nickserv/saset/misc"; misc_description = _("Associate a location with this account"); permission = "nickserv/saset/location"; group = "nickserv/admin"; }
|
||||
|
||||
/*
|
||||
* ns_set_op
|
||||
*
|
||||
* Provides the commands:
|
||||
* nickserv/set/autoop, nickserv/saset/autoop - Allows configuring whether status modes are automatically granted when joining a channel.
|
||||
* nickserv/set/neverop, nickserv/saset/neverop - Allows configuring whether a user can be added to access lists.
|
||||
*/
|
||||
module { name = "ns_set_op" }
|
||||
|
||||
command { service = "NickServ"; name = "SET AUTOOP"; command = "nickserv/set/autoop"; }
|
||||
command { service = "NickServ"; name = "SASET AUTOOP"; command = "nickserv/saset/autoop"; permission = "nickserv/saset/autoop"; }
|
||||
|
||||
command { service = "NickServ"; name = "SET NEVEROP"; command = "nickserv/set/neverop"; }
|
||||
command { service = "NickServ"; name = "SASET NEVEROP"; command = "nickserv/saset/neverop"; permission = "nickserv/saset/neverop"; }
|
||||
|
||||
# For compatibility with DALnet Services.
|
||||
command { service = "NickServ"; name = "SET NOOP"; command = "nickserv/set/neverop"; hide = yes; }
|
||||
command { service = "NickServ"; name = "SASET NOOP"; command = "nickserv/saset/neverop"; permission = "nickserv/saset/neverop"; hide = yes; }
|
||||
|
||||
/*
|
||||
* ns_set_protect
|
||||
*
|
||||
* Provides the commands nickserv/set/protect and kickserv/saset/protect.
|
||||
* Provides the commands nickserv/set/protect and nickserv/saset/protect.
|
||||
*
|
||||
* Used for configuring nickname protection.
|
||||
*/
|
||||
module { name = "ns_set_protect" }
|
||||
|
||||
command { service = "NickServ"; name = "SET PROTECT"; command = "nickserv/set/protect"; }
|
||||
command { service = "NickServ"; name = "SASET PROTECT"; command = "nickserv/saset/protect"; permission = "nickserv/saset/kill"; }
|
||||
command { service = "NickServ"; name = "SASET PROTECT"; command = "nickserv/saset/protect"; permission = "nickserv/saset/protect"; }
|
||||
|
||||
# For compatibility with Anope 2.0.
|
||||
command { service = "NickServ"; name = "SET KILL"; command = "nickserv/set/protect"; hide = yes; }
|
||||
command { service = "NickServ"; name = "SASET KILL"; command = "nickserv/saset/protect"; permission = "nickserv/saset/protect"; hide = yes; }
|
||||
|
||||
/*
|
||||
* ns_set_timezone
|
||||
*
|
||||
* Provides the command nickserv/set/timezone and nickserv/saset/timezone.
|
||||
*
|
||||
* Allows configuring the timezone that services uses.
|
||||
*/
|
||||
module { name = "ns_set_timezone" }
|
||||
command { service = "NickServ"; name = "SET TIMEZONE"; command = "nickserv/set/timezone"; }
|
||||
command { service = "NickServ"; name = "SASET TIMEZONE"; command = "nickserv/saset/timezone"; permission = "nickserv/saset/timezone"; }
|
||||
|
||||
/*
|
||||
* ns_suspend
|
||||
*
|
||||
|
||||
@@ -111,7 +111,7 @@ module
|
||||
killonsqline = yes
|
||||
|
||||
/*
|
||||
* Adds the nickname of the IRC Operator issuing an AKILL to the kill reason.
|
||||
* Adds the nickname of the Services Operator issuing an AKILL to the kill reason.
|
||||
*
|
||||
* This directive is optional.
|
||||
*/
|
||||
@@ -287,15 +287,15 @@ command { service = "OperServ"; name = "CHANKILL"; command = "operserv/chankill"
|
||||
* To use this module you must set a nameserver record for services
|
||||
* so that DNS queries go to services.
|
||||
*
|
||||
* Alternatively, you may use a slave DNS server to hide service's IP,
|
||||
* Alternatively, you may use a secondary DNS server to hide services' IP,
|
||||
* provide query caching, and provide better fault tolerance.
|
||||
*
|
||||
* To do this using BIND, configure similar to:
|
||||
*
|
||||
* options { max-refresh-time 60; };
|
||||
* zone "irc.example.com" IN {
|
||||
* type slave;
|
||||
* masters { 127.0.0.1 port 5353; };
|
||||
* type secondary;
|
||||
* primaries { 127.0.0.1 port 5353; };
|
||||
* };
|
||||
*
|
||||
* Where 127.0.0.1:5353 is the IP and port services are listening on.
|
||||
|
||||
@@ -1,514 +0,0 @@
|
||||
/*
|
||||
* Example configuration file for Anope. After making the appropriate
|
||||
* changes to this file, place it in the Anope conf directory (as
|
||||
* specified in the "Config" script, default /home/username/anope/conf)
|
||||
* under the name "anope.conf".
|
||||
*
|
||||
* The format of this file is fairly simple: three types of comments are supported:
|
||||
* - All text after a '#' on a line is ignored, as in shell scripting
|
||||
* - All text after '//' on a line is ignored, as in C++
|
||||
* - A block of text like this one is ignored, as in C
|
||||
*
|
||||
* Outside of comments, there are three structures: blocks, keys, and values.
|
||||
*
|
||||
* A block is a named container, which contains a number of key to value pairs
|
||||
* - you may think of this as an array.
|
||||
*
|
||||
* A block is created like so:
|
||||
* foobar
|
||||
* {
|
||||
* moo = "cow"
|
||||
* foo = bar
|
||||
* }
|
||||
*
|
||||
* Note that nameless blocks are allowed and are often used with comments to allow
|
||||
* easily commenting an entire block, for example:
|
||||
* #foobar
|
||||
* {
|
||||
* moo = "cow"
|
||||
* foo = bar
|
||||
* }
|
||||
* is an entirely commented block.
|
||||
*
|
||||
* Keys are case insensitive. Values depend on what key - generally, information is
|
||||
* given in the key comment. The quoting of values (and most other syntax) is quite
|
||||
* flexible, however, please do not forget to quote your strings:
|
||||
*
|
||||
* "This is a parameter string with spaces in it"
|
||||
*
|
||||
* If you need to include a double quote inside a quoted string, precede it
|
||||
* by a backslash:
|
||||
*
|
||||
* "This string has \"double quotes\" in it"
|
||||
*
|
||||
* Time parameters can be specified either as an integer representing a
|
||||
* number of seconds (e.g. "3600" = 1 hour), or as an integer with a unit
|
||||
* specifier: "s" = seconds, "m" = minutes, "h" = hours, "d" = days.
|
||||
* Combinations (such as "1h30m") are not permitted. Examples (all of which
|
||||
* represent the same length of time, one day):
|
||||
*
|
||||
* "86400", "86400s", "1440m", "24h", "1d"
|
||||
*
|
||||
* In the documentation for each directive, one of the following will be
|
||||
* included to indicate whether an option is required:
|
||||
*
|
||||
* [REQUIRED]
|
||||
* Indicates a directive which must be given. Without it, Anope will
|
||||
* not start.
|
||||
*
|
||||
* [RECOMMENDED]
|
||||
* Indicates a directive which may be omitted, but omitting it may cause
|
||||
* undesirable side effects.
|
||||
*
|
||||
* [OPTIONAL]
|
||||
* Indicates a directive which is optional. If not given, the feature
|
||||
* will typically be disabled. If this is not the case, more
|
||||
* information will be given in the documentation.
|
||||
*
|
||||
* [DISCOURAGED]
|
||||
* Indicates a directive which may cause undesirable side effects if
|
||||
* specified.
|
||||
*
|
||||
* [DEPRECATED]
|
||||
* Indicates a directive which will disappear in a future version of
|
||||
* Anope, usually because its functionality has been either
|
||||
* superseded by that of other directives or incorporated into the main
|
||||
* program.
|
||||
*/
|
||||
|
||||
/*
|
||||
* [OPTIONAL] Defines
|
||||
*
|
||||
* You can use defines for repeated information, which can be used to easily change many
|
||||
* values in the configuration at once.
|
||||
*
|
||||
* To use a define called foo.bar you use ${foo.bar} in your config file. You can also use
|
||||
* environment variables by prefixing their name with "env." like ${env.USER}.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The services.host define is used in multiple different locations throughout the
|
||||
* configuration for the server name and pseudoclient hostnames.
|
||||
*/
|
||||
define
|
||||
{
|
||||
name = "services.host"
|
||||
value = "stats.example.com"
|
||||
}
|
||||
|
||||
/*
|
||||
* [OPTIONAL] Additional Includes
|
||||
*
|
||||
* You can include additional configuration files here.
|
||||
* You may also include executable files, which will be executed and
|
||||
* the output from it will be included into your configuration.
|
||||
*/
|
||||
|
||||
#include
|
||||
{
|
||||
type = "file"
|
||||
name = "some.conf"
|
||||
}
|
||||
|
||||
#include
|
||||
{
|
||||
type = "executable"
|
||||
name = "/usr/bin/wget -q -O - https://some.misconfigured.network.com/stats.conf"
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] IRCd Config
|
||||
*
|
||||
* This section is used to set up Anope to connect to your IRC network.
|
||||
* This section can be included multiple times, and Anope will attempt to
|
||||
* connect to each server until it finally connects.
|
||||
*
|
||||
* Each uplink IRCd should have a corresponding configuration to allow Anope
|
||||
* to link to it.
|
||||
*
|
||||
* An example configuration for InspIRCd that is compatible with the below uplink
|
||||
* and serverinfo configuration would look like:
|
||||
*
|
||||
* # This goes in inspircd.conf, *NOT* your Anope config!
|
||||
* <link name="stats.example.com"
|
||||
* ipaddr="127.0.0.1"
|
||||
* port="7000"
|
||||
* sendpass="mypassword"
|
||||
* recvpass="mypassword">
|
||||
* <uline server="stats.example.com" silent="yes">
|
||||
* <bind address="127.0.0.1" port="7000" type="servers">
|
||||
*
|
||||
* An example configuration for UnrealIRCd that is compatible with the below uplink
|
||||
* and serverinfo configuration would look like:
|
||||
*
|
||||
* // This goes in unrealircd.conf, *NOT* your Anope config!
|
||||
* listen {
|
||||
* ip 127.0.0.1;
|
||||
* port 7000;
|
||||
* options {
|
||||
* serversonly;
|
||||
* };
|
||||
* };
|
||||
* link stats.example.com {
|
||||
* incoming {
|
||||
* mask *@127.0.0.1;
|
||||
* };
|
||||
* password "mypassword";
|
||||
* class servers;
|
||||
* };
|
||||
* ulines { stats.example.com; };
|
||||
*/
|
||||
uplink
|
||||
{
|
||||
/*
|
||||
* The IP address, hostname, or UNIX socket path of the IRC server you wish
|
||||
* to connect Anope to.
|
||||
* Usually, you will want to connect over 127.0.0.1 (aka localhost).
|
||||
*
|
||||
* NOTE: On some shell providers, this will not be an option.
|
||||
*/
|
||||
host = "127.0.0.1"
|
||||
|
||||
/*
|
||||
* The protocol that Anope should use when connecting to the uplink. Can
|
||||
* be set to "ipv4" (the default), "ipv6", or "unix".
|
||||
*/
|
||||
protocol = "ipv4"
|
||||
|
||||
/*
|
||||
* Enable if Anope should connect using SSL.
|
||||
* You must have an SSL module loaded for this to work.
|
||||
*/
|
||||
ssl = no
|
||||
|
||||
/*
|
||||
* The port to connect to.
|
||||
* The IRCd *MUST* be configured to listen on this port, and to accept
|
||||
* server connections.
|
||||
*
|
||||
* Refer to your IRCd documentation for how this is to be done.
|
||||
*/
|
||||
port = 7000
|
||||
|
||||
/*
|
||||
* The password to send to the IRC server for authentication.
|
||||
* This must match the link block on your IRCd.
|
||||
*
|
||||
* Refer to your IRCd documentation for more information on link blocks.
|
||||
*/
|
||||
password = "mypassword"
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] Server Information
|
||||
*
|
||||
* This section contains information about the services server.
|
||||
*/
|
||||
serverinfo
|
||||
{
|
||||
/*
|
||||
* The hostname that Anope will be seen as, it must have no conflicts with any
|
||||
* other server names on the rest of your IRC network. Note that it does not have
|
||||
* to be an existing hostname, just one that isn't on your network already.
|
||||
*/
|
||||
name = "${services.host}"
|
||||
|
||||
/*
|
||||
* The text which should appear as the server's information in /WHOIS and similar
|
||||
* queries.
|
||||
*/
|
||||
description = "Anope IRC Statistics"
|
||||
|
||||
/*
|
||||
* The local address that Anope will bind to before connecting to the remote
|
||||
* server. This may be useful for multihomed hosts. If omitted, Anope will let
|
||||
* the Operating System choose the local address. This directive is optional.
|
||||
*
|
||||
* If you don't know what this means or don't need to use it, just leave this
|
||||
* directive commented out.
|
||||
*/
|
||||
#localhost = "nowhere."
|
||||
|
||||
/*
|
||||
* What Server ID to use for this connection?
|
||||
* Note: This should *ONLY* be used for TS6/P10 IRCds. Refer to your IRCd documentation
|
||||
* to see if this is needed.
|
||||
*/
|
||||
#id = "00A"
|
||||
|
||||
/*
|
||||
* The filename containing the Anope process ID. The path is relative to the
|
||||
* data directory.
|
||||
*/
|
||||
pid = "anope.pid"
|
||||
|
||||
/*
|
||||
* The filename containing the Message of the Day. The path is relative to the
|
||||
* config directory.
|
||||
*/
|
||||
motd = "motd.txt"
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] Protocol module
|
||||
*
|
||||
* This directive tells Anope which IRCd Protocol to speak when connecting.
|
||||
* You MUST modify this to match the IRCd you run.
|
||||
*
|
||||
* Supported:
|
||||
* - hybrid
|
||||
* - inspircd
|
||||
* - ngircd
|
||||
* - plexus
|
||||
* - ratbox
|
||||
* - solanum
|
||||
* - unrealircd
|
||||
*/
|
||||
module
|
||||
{
|
||||
name = "inspircd"
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] Network Information
|
||||
*
|
||||
* This section contains information about the IRC network that Anope will be
|
||||
* connecting to.
|
||||
*/
|
||||
networkinfo
|
||||
{
|
||||
/*
|
||||
* This is the name of the network that Anope will be running on.
|
||||
*/
|
||||
networkname = "LocalNet"
|
||||
|
||||
/*
|
||||
* Set this to the maximum allowed nick length on your network.
|
||||
* Be sure to set this correctly, as setting this wrong can result in
|
||||
* Anope being disconnected from the network. Defaults to 31.
|
||||
*/
|
||||
#nicklen = 31
|
||||
|
||||
/* Set this to the maximum allowed ident length on your network.
|
||||
* Be sure to set this correctly, as setting this wrong can result in
|
||||
* Anope being disconnected from the network. Defaults to 10.
|
||||
*/
|
||||
#userlen = 10
|
||||
|
||||
/* Set this to the maximum allowed hostname length on your network.
|
||||
* Be sure to set this correctly, as setting this wrong can result in
|
||||
* Anope being disconnected from the network. Defaults to 64.
|
||||
*/
|
||||
#hostlen = 64
|
||||
|
||||
/* Set this to the maximum allowed channel length on your network.
|
||||
* Defaults to 64.
|
||||
*/
|
||||
#chanlen = 32
|
||||
|
||||
/* The maximum number of list modes settable on a channel (such as b, e, I).
|
||||
* Comment out or set to 0 to disable.
|
||||
*/
|
||||
modelistsize = 100
|
||||
|
||||
/*
|
||||
* The characters allowed in hostnames. This is used for validating hostnames given
|
||||
* to services, such as BotServ bot hostnames and user vhosts. Changing this is not
|
||||
* recommended unless you know for sure your IRCd supports whatever characters you are
|
||||
* wanting to use. Telling services to set a vhost containing characters your IRCd
|
||||
* disallows could potentially break the IRCd and/or Anope.
|
||||
*
|
||||
* It is recommended you DON'T change this.
|
||||
*/
|
||||
vhost_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"
|
||||
|
||||
/*
|
||||
* If enabled, allows vhosts to not contain dots (.).
|
||||
* Newer IRCds generally do not have a problem with this, but the same warning as
|
||||
* vhost_chars applies.
|
||||
*
|
||||
* It is recommended you DON'T change this.
|
||||
*/
|
||||
allow_undotted_vhosts = no
|
||||
|
||||
/*
|
||||
* The characters that are not allowed to be at the very beginning or very ending
|
||||
* of a vhost. The same warning as vhost_chars applies.
|
||||
*
|
||||
* It is recommended you DON'T change this.
|
||||
*/
|
||||
disallow_start_or_end = ".-"
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] Anope Options
|
||||
*
|
||||
* This section contains various options which determine how Anope will operate.
|
||||
*/
|
||||
options
|
||||
{
|
||||
/*
|
||||
* On Linux/UNIX systems Anope can setuid and setgid to this user and group
|
||||
* after starting up. This is useful if Anope has to bind to privileged ports.
|
||||
*/
|
||||
#user = "anope"
|
||||
#group = "anope"
|
||||
|
||||
/*
|
||||
* The case mapping used by services. This must be set to a valid locale name
|
||||
* installed on your machine. Anope uses this case map to compare, with
|
||||
* case insensitivity, things such as nick names, channel names, etc.
|
||||
*
|
||||
* We provide two special casemaps shipped with Anope, ascii and rfc1459.
|
||||
*
|
||||
* This value should be set to what your IRCd uses, which is probably rfc1459,
|
||||
* however Anope has always used ascii for comparison, so the default is ascii.
|
||||
*
|
||||
* Changing this value once set is not recommended.
|
||||
*/
|
||||
casemap = "ascii"
|
||||
|
||||
/*
|
||||
* Sets the timeout period for reading from the uplink.
|
||||
*/
|
||||
readtimeout = 5s
|
||||
|
||||
/*
|
||||
* If set, Anope will only show /stats o to IRC Operators. This directive
|
||||
* is optional.
|
||||
*/
|
||||
#hidestatso = yes
|
||||
|
||||
/*
|
||||
* A space-separated list of U-lined servers on your network, it is assumed that
|
||||
* the servers in this list are allowed to set channel modes and Anope will
|
||||
* not attempt to reverse their mode changes.
|
||||
*
|
||||
* WARNING: Do NOT put your normal IRC user servers in this directive.
|
||||
*
|
||||
* This directive is optional.
|
||||
*/
|
||||
#ulineservers = "services.your.network"
|
||||
|
||||
/*
|
||||
* How long to wait between connection retries with the uplink(s).
|
||||
*/
|
||||
retrywait = 60s
|
||||
}
|
||||
|
||||
/*
|
||||
* [RECOMMENDED] Logging Configuration
|
||||
*
|
||||
* This section is used for configuring what is logged and where it is logged to.
|
||||
* You may have multiple log blocks if you wish. Remember to properly secure any
|
||||
* channels you choose to have Anope log to!
|
||||
*/
|
||||
log
|
||||
{
|
||||
/*
|
||||
* Target(s) to log to, which may be one of the following:
|
||||
* - a channel name
|
||||
* - a filename
|
||||
* - globops
|
||||
*/
|
||||
target = "stats.log"
|
||||
|
||||
/* Log to both stats.log and the channel #stats
|
||||
*
|
||||
* Note that some older IRCds, such as Ratbox, require services to be in the
|
||||
* log channel to be able to message it. To do this, configure service:channels to
|
||||
* join your logging channel.
|
||||
*/
|
||||
#target = "stats.log #stats"
|
||||
|
||||
/*
|
||||
* The source(s) to only accept log messages from. Leave commented to allow all sources.
|
||||
* This can be a users name, a channel name, one of our clients (e.g. OperServ), or a server name.
|
||||
*/
|
||||
#source = ""
|
||||
|
||||
/*
|
||||
* The bot used to log generic messages which have no predefined sender if there
|
||||
* is a channel in the target directive.
|
||||
*/
|
||||
bot = "Global"
|
||||
|
||||
/*
|
||||
* The number of days to keep log files, only useful if you are logging to a file.
|
||||
* Set to 0 to never delete old log files.
|
||||
*
|
||||
* Note that Anope must run 24 hours a day for this feature to work correctly.
|
||||
*/
|
||||
logage = 7
|
||||
|
||||
/*
|
||||
* What types of log messages should be logged by this block. There are nine general categories:
|
||||
*
|
||||
* servers - Server actions, linking, squitting, etc.
|
||||
* channels - Actions in channels such as joins, parts, kicks, etc.
|
||||
* users - User actions such as connecting, disconnecting, changing name, etc.
|
||||
* other - All other messages without a category.
|
||||
* rawio - Logs raw input and output from services
|
||||
* debug - Debug messages (log files can become VERY large from this).
|
||||
*
|
||||
* These options determine what messages from the categories should be logged. Wildcards are accepted, and
|
||||
* you can also negate values with a ~. For example, "~operserv/akill operserv/*" would log all operserv
|
||||
* messages except for operserv/akill. Note that processing stops at the first matching option, which
|
||||
* means "* ~operserv/*" would log everything because * matches everything.
|
||||
*
|
||||
* Valid server options are:
|
||||
* connect, quit, sync, squit
|
||||
*
|
||||
* Valid channel options are:
|
||||
* create, destroy, join, part, kick, leave, mode
|
||||
*
|
||||
* Valid user options are:
|
||||
* connect, disconnect, quit, nick, ident, host, mode, maxusers, oper, away
|
||||
*
|
||||
* Rawio and debug are simple yes/no answers, there are no types for them.
|
||||
*
|
||||
* Note that modules may add their own values to these options.
|
||||
*/
|
||||
servers = "*"
|
||||
#channels = "~mode *"
|
||||
users = "connect disconnect nick"
|
||||
other = "*"
|
||||
rawio = no
|
||||
debug = no
|
||||
}
|
||||
|
||||
/*
|
||||
* [REQUIRED] MySQL Database configuration.
|
||||
*
|
||||
* mysql
|
||||
*
|
||||
* This module allows other modules to use MySQL.
|
||||
*/
|
||||
module
|
||||
{
|
||||
name = "mysql"
|
||||
|
||||
mysql
|
||||
{
|
||||
/* The name of this service. */
|
||||
name = "mysql/main"
|
||||
database = "anope"
|
||||
server = "127.0.0.1"
|
||||
username = "anope"
|
||||
password = "mypassword"
|
||||
port = 3306
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* IRC2SQL Gateway
|
||||
* This module collects data about users, channels and servers. It doesn't build stats
|
||||
* itself, however, it gives you the database, it's up to you how you use it.
|
||||
*
|
||||
* Requires a MySQL Database and MySQL version 5.5 or higher
|
||||
*/
|
||||
include
|
||||
{
|
||||
type = "file"
|
||||
name = "irc2sql.example.conf"
|
||||
}
|
||||
+1
-1
@@ -22,9 +22,9 @@ contributions they have made, are:
|
||||
* Michael Wobst <wobst.michael@web.de>
|
||||
* Mark Summers <mark@goopler.net>
|
||||
* Matt Schatz <genius3000@g3k.solutions>
|
||||
* PeGaSuS <droider.pc@gmail.com>
|
||||
* Daniel Vassdal <shutter@canternet.org>
|
||||
* MatthewM <mcm@they-got.us>
|
||||
* PeGaSuS <droider.pc@gmail.com>
|
||||
* Sebastian V. <hal9000@denorastats.org>
|
||||
* Alvaro Toledo <atoledo@keldon.org>
|
||||
* Dragone2 <dragone2@risposteinformatiche.it>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# Anope Change Log
|
||||
|
||||
## Anope 2.1.19 (2025-11-01)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* `pkg-config` is now required to find dependencies for the following modules on UNIX systems:
|
||||
- enc_argon2
|
||||
- ldap
|
||||
- mysql
|
||||
- regex_pcre2
|
||||
- regex_tre
|
||||
|
||||
* Support for InspIRCd v3 has been dropped ahead of it going EOL in two months. Please migrate to InspIRCd v4 to keep using Anope 2.1 with InspIRCd.
|
||||
|
||||
### Changes
|
||||
|
||||
* Added a Romanian translation (contributed by @KidProtect on GitHub).
|
||||
|
||||
* Added support for associating a timezone with an account to allow users to receive timestamps in their local timezone.
|
||||
|
||||
```
|
||||
/NICKSERV SET TIMEZONE Europe/London
|
||||
-NickServ- Timezone changed to Europe/Berlin.
|
||||
|
||||
/NICKSERV INFO test
|
||||
-NickServ- Account registered: Thu 09 Oct 2025 15:22:45 CEST (45 seconds ago)
|
||||
```
|
||||
|
||||
NOTE: This requires a compiler with C++20 timezone support.
|
||||
|
||||
* Added support for IRCv3 message tags when using Solanum git.
|
||||
|
||||
* Added support for language-specific time formats.
|
||||
|
||||
```
|
||||
/NICKSERV SET LANGUAGE tr_TR.UTF-8
|
||||
-NickServ- Dil Türkçe olarak değiştirildi.
|
||||
|
||||
/NICKSERV INFO test
|
||||
-NickServ- Hesap kaydedildi: Prş 09 Eki 2025 15:22:45 (6 dakika, 16 saniye önce)
|
||||
```
|
||||
|
||||
* Channel entry messages are now tagged with an IRCv3 time tag for the time they were created on supporting IRCds. This defaults to on but can be disabled using `{cs_entrymsg}:timestamp`.
|
||||
|
||||
* Reordered the information in the `nickserv/info` command output to show the registration dates before the seen information.
|
||||
|
||||
* Updated the Turkish translation (contributed by @CaPaCuL on GitHub).
|
||||
|
||||
* Updated the vendored libraries.
|
||||
+1
-1
@@ -7,7 +7,7 @@ if(WIN32)
|
||||
# Add README.txt to list of files for CPack to ignore
|
||||
add_to_cpack_ignored_files("README.txt$" TRUE)
|
||||
endif()
|
||||
set(DOCS Changes Changes.conf DEFCON FAQ INSTALL LANGUAGE MODULES ${CMAKE_CURRENT_BINARY_DIR}/README.txt WIN32.txt)
|
||||
set(DOCS CHANGES.md DEFCON FAQ INSTALL LANGUAGE MODULES ${CMAKE_CURRENT_BINARY_DIR}/README.txt WIN32.txt)
|
||||
install(FILES ${DOCS}
|
||||
DESTINATION ${DOC_DIR}
|
||||
)
|
||||
|
||||
+2
-7
@@ -10,14 +10,9 @@ Anope Multi Language Support
|
||||
|
||||
To build Anope with gettext support, gettext and its development libraries must be installed on the system.
|
||||
|
||||
On Debian install the locales-all package.
|
||||
On Debian-based systems install the locales-all package.
|
||||
|
||||
On Ubuntu run locale-gen for each language you want to enable.
|
||||
For example:
|
||||
locale-gen es_ES.UTF-8
|
||||
|
||||
Then execute:
|
||||
dpkg-reconfigure locales
|
||||
On RHEL-based systems run `yum list glibc-langpack-*` and install the languages you want to enable.
|
||||
|
||||
If you have already built Anope you will need to delete the build directory and rebuild from scratch.
|
||||
|
||||
|
||||
+1
-1
@@ -166,7 +166,7 @@ Table of Contents
|
||||
|
||||
Anope currently works with:
|
||||
|
||||
* InspIRCd 3 or later
|
||||
* InspIRCd 4 or later
|
||||
* ircd-hybrid 8.2.34 or later
|
||||
* ircd-ratbox 3 or later
|
||||
* ngIRCd 19.2 or later
|
||||
|
||||
@@ -1,3 +1,54 @@
|
||||
Anope Version 2.1.18
|
||||
--------------------
|
||||
Added a check that a non-deprecated database module is loaded.
|
||||
Added support for flexible and monospace layouts to make text easier to read on clients that use a variable-width font.
|
||||
Added support for logging about deprecated modules on boot.
|
||||
Added support for per-IRCd hints when a link fails.
|
||||
Added support for self-service validation of vhosts using DNS TXT records.
|
||||
Added support for separate bad password limits for pre-connection SASL authentication.
|
||||
Added support for SRV and TXT records to the dns module.
|
||||
Added the --nodb option to disable database and encrytption module checks.
|
||||
Added the nickname registration date to the nickserv/glist output.
|
||||
Changed db_flatfile to be import-only (migrate to db_json).
|
||||
Changed the default registration confirmation type to code validation.
|
||||
Changed the fantasy !help command to not require the FANTASY privilege by default.
|
||||
Changed various length measurement code to be UTF-8 aware.
|
||||
Disabled the nickname registration delay by default.
|
||||
Fixed reporting the MySQL version that the mysql module was built against.
|
||||
Improved the layout of the nickserv/info command.
|
||||
Modularised the ns_sasl module to make it easier to pick SASL mechanisms.
|
||||
Moved duration rounding logic from Anope::Expires to Anope::Duration.
|
||||
Removed support for importing old databases from 1.8.
|
||||
Removed support for verifying "old MD5" passwords from 1.7.
|
||||
Reworked how memory is allocated when formatting messages.
|
||||
|
||||
Anope Version 2.1.17
|
||||
--------------------
|
||||
Allowed opers to resend passwords for users in nickserv/resend.
|
||||
Fixed HostServ using a different valid username character set to the protocol module.
|
||||
Fixed losing the channel and nickname registration time when upgrading from an earlier 2.1 release.
|
||||
Improved the messages sent when a user is forced off a protected nickname.
|
||||
Simplified copying modules to the runtime directory on Windows.
|
||||
|
||||
Anope Version 2.1.16
|
||||
--------------------
|
||||
Added support for on-IRC code confirmation.
|
||||
Added the ability for fantasy commands to be executable without the FANTASY privilege.
|
||||
Added the ability to prepend to topics as well as appending to them.
|
||||
Changed various fields to serialize to the database as a string not an integer.
|
||||
Disabled db_flatfile by default in preparation for becoming import-only.
|
||||
Fixed a memory leak in the db_json module.
|
||||
Fixed building on OpenSSL 1.1.1 (for now).
|
||||
Fixed removed and later re-added temporary bans being removed automatically.
|
||||
Fixed sometimes sending malformed LMODE messages on InspIRCd.
|
||||
Fixed the "did you mean" message suggesting unloaded commands.
|
||||
Fixed various issues with the example config files.
|
||||
Marked db_json as the recommended database module.
|
||||
Moved the BAN, UNBAN, and KICK commands to the chanserv/management group.
|
||||
Removed support for the 1.8-style seen command.
|
||||
Reworked confirmation to allow confirmation of multiple account actions.
|
||||
When dropping a display nickname the new display will now be the oldest in the group.
|
||||
|
||||
Anope Version 2.1.15
|
||||
--------------------
|
||||
Added a workaround to the jsonrpc module for JavaScript truncating big integers.
|
||||
@@ -1,3 +1,43 @@
|
||||
Anope Version 2.1.18
|
||||
--------------------
|
||||
Added the hostserv/validate command.
|
||||
Added the nickserv/saset/layout command.
|
||||
Added the nickserv/set/layout command.
|
||||
Added the ns_sasl_anonymous module.
|
||||
Added the ns_sasl_external module.
|
||||
Added the ns_sasl_plain module.
|
||||
Added the ns_set_layout module.
|
||||
Added the ns_set_op module.
|
||||
Added {hs_request}:validationcooldown (defaults to 5 minutes).
|
||||
Added {hs_request}:validationrecord (defaults to "anope-dns-validation").
|
||||
Added {ns_sasl}:badpasslimit (defaults to options:badpasslimit).
|
||||
Added {ns_sasl}:badpasstimeout (defaults to options:badpasstimeout).
|
||||
Moved nickserv/set/autoop and nickserv/saset/autoop to the ns_set_op module.
|
||||
Moved nickserv/set/display and nickserv/saset/display to the ns_set_group module.
|
||||
Moved nickserv/set/neverop and nickserv/saset/neverop to the ns_set_op module.
|
||||
Removed the db_old module.
|
||||
Removed the enc_old module.
|
||||
Removed {db_flatfile}:fork (module is now import-only).
|
||||
Removed {db_flatfile}:keepbackups (module is now import-only).
|
||||
Removed {db_flatfile}:nobackupokay (module is now import-only).
|
||||
|
||||
Anope Version 2.1.17
|
||||
--------------------
|
||||
Added the nickserv/resend oper privilege.
|
||||
|
||||
Anope Version 2.1.16
|
||||
--------------------
|
||||
Added fantasy:require_privilege (defaults to yes).
|
||||
Added the nickserv/confirm/email command.
|
||||
Added the nickserv/confirm/email oper privilege.
|
||||
Added the nickserv/confirm/register command.
|
||||
Added the ns_confirm module.
|
||||
Added {ns_email}:changeexpire (defaults to 1 day).
|
||||
Added {ns_resetpass}:resetexpire (defaults to 1 day).
|
||||
Removed the irc2sql module (migrate to JSON-RPC instead).
|
||||
Removed {ns_seen}:simple (1.8-style seen has been removed).
|
||||
Renamed the nickserv/confirm oper privilege to nickserv/confirm/register.
|
||||
|
||||
Anope Version 2.1.15
|
||||
--------------------
|
||||
Added the ns_email module.
|
||||
+6
-7
@@ -48,11 +48,10 @@ private:
|
||||
public:
|
||||
Anope::string nick;
|
||||
Anope::string last_quit;
|
||||
Anope::string last_realname;
|
||||
/* Last usermask this nick was seen on, eg user@host */
|
||||
Anope::string last_usermask;
|
||||
/* Last uncloaked usermask, requires nickserv/auspex to see */
|
||||
Anope::string last_realhost;
|
||||
/* Last cloaked user@host this nick was seen using. */
|
||||
Anope::string last_userhost;
|
||||
/* Last real user@host this nick was seen using. */
|
||||
Anope::string last_userhost_real;
|
||||
time_t registered = Anope::CurTime;
|
||||
time_t last_seen = Anope::CurTime;
|
||||
|
||||
@@ -164,7 +163,7 @@ public:
|
||||
/* Unsaved data */
|
||||
|
||||
/** The display nick for this account. */
|
||||
NickAlias *na = nullptr;
|
||||
Serialize::Reference<NickAlias> na;
|
||||
/* Number of channels registered by this account */
|
||||
uint16_t channelcount = 0;
|
||||
/* Users online now logged into this account */
|
||||
@@ -185,7 +184,7 @@ public:
|
||||
/** Checks whether this account is a services oper or not.
|
||||
* @return True if this account is a services oper, false otherwise.
|
||||
*/
|
||||
virtual bool IsServicesOper() const;
|
||||
bool IsServicesOper() const;
|
||||
|
||||
/** Retrieves the account id for this user */
|
||||
uint64_t GetId();
|
||||
|
||||
+8
-78
@@ -15,6 +15,9 @@
|
||||
|
||||
#include "hashcomp.h"
|
||||
|
||||
#define UTF_CPP_CPLUSPLUS 201703L
|
||||
#include "utfcpp/unchecked.h"
|
||||
|
||||
namespace Anope
|
||||
{
|
||||
/**
|
||||
@@ -52,6 +55,7 @@ namespace Anope
|
||||
string(const char *_str, size_type n) : _string(_str, n) { }
|
||||
string(const std::string &_str) : _string(_str) { }
|
||||
string(const ci::string &_str) : _string(_str.c_str()) { }
|
||||
string(const std::string_view &_sv) : _string(_sv.begin(), _sv.end()) { }
|
||||
string(const string &_str, size_type pos, size_type n = npos) : _string(_str._string, pos, n) { }
|
||||
template <class InputIterator> string(InputIterator first, InputIterator last) : _string(first, last) { }
|
||||
string(const string &) = default;
|
||||
@@ -129,6 +133,7 @@ namespace Anope
|
||||
* Returns the string's length.
|
||||
*/
|
||||
inline size_type length() const { return this->_string.length(); }
|
||||
inline size_type utf8length() const { return utf8::unchecked::distance(str().begin(), str().end()); }
|
||||
|
||||
/**
|
||||
* Returns the size of the currently allocated storage space in the string object.
|
||||
@@ -383,7 +388,7 @@ namespace Anope
|
||||
|
||||
/** Other command line options.
|
||||
*/
|
||||
extern CoreExport bool ReadOnly, NoFork, NoThird, NoPID, NoExpire, ProtocolDebug;
|
||||
extern CoreExport bool ReadOnly, NoFork, NoThird, NoDB, NoPID, NoExpire, ProtocolDebug;
|
||||
|
||||
/** The root of the Anope installation. Usually ~/anope
|
||||
*/
|
||||
@@ -463,33 +468,12 @@ namespace Anope
|
||||
extern CoreExport void Unhex(const string &src, string &dest);
|
||||
extern CoreExport void Unhex(const string &src, char *dest, size_t sz);
|
||||
|
||||
/** Base 64 encode a string
|
||||
* @param src The string to encode
|
||||
* @param target Where the encoded string is placed
|
||||
*/
|
||||
extern CoreExport void B64Encode(const string &src, string &target);
|
||||
|
||||
/** Base 64 decode a string
|
||||
* @param src The base64 encoded string
|
||||
* @param target The plain text result
|
||||
*/
|
||||
extern CoreExport void B64Decode(const string &src, string &target);
|
||||
|
||||
/** Encrypts what is in 'src' to 'dest'
|
||||
* @param src The source string to encrypt
|
||||
* @param dest The destination where the encrypted string is placed
|
||||
*/
|
||||
extern CoreExport bool Encrypt(const Anope::string &src, Anope::string &dest);
|
||||
|
||||
/** Returns a sequence of data formatted as the format argument specifies.
|
||||
** After the format parameter, the function expects at least as many
|
||||
** additional arguments as specified in format.
|
||||
* @param fmt Format of the Message
|
||||
* @param ... any number of parameters
|
||||
* @return a Anope::string
|
||||
*/
|
||||
extern CoreExport string printf(const char *fmt, ...) ATTR_FORMAT(1, 2);
|
||||
|
||||
/** Return the last error code
|
||||
* @return The error code
|
||||
*/
|
||||
@@ -513,9 +497,10 @@ namespace Anope
|
||||
/** Retrieves a human readable string representing the time in seconds
|
||||
* @param seconds The time on seconds, eg 60
|
||||
* @param nc The account to use language settings for to translate this string, if applicable
|
||||
* @param round Whether to round the duration to produce a shorter output.
|
||||
* @return A human readable string, eg "1 minute"
|
||||
*/
|
||||
extern CoreExport Anope::string Duration(time_t seconds, const NickCore *nc = NULL);
|
||||
extern CoreExport Anope::string Duration(time_t seconds, const NickCore *nc = nullptr, bool round = false);
|
||||
|
||||
/** Generates a human readable string of type "expires in ..."
|
||||
* @param expires time in seconds
|
||||
@@ -531,12 +516,6 @@ namespace Anope
|
||||
*/
|
||||
extern CoreExport Anope::string strftime(time_t t, const NickCore *nc = NULL, bool short_output = false);
|
||||
|
||||
/** Normalize buffer, stripping control characters and colors
|
||||
* @param A string to be parsed for control and color codes
|
||||
* @return A string stripped of control and color codes
|
||||
*/
|
||||
extern CoreExport Anope::string NormalizeBuffer(const Anope::string &);
|
||||
|
||||
/** Parses a raw message from the uplink and calls its command handler.
|
||||
* @param message Raw message from the uplink
|
||||
*/
|
||||
@@ -572,57 +551,8 @@ namespace Anope
|
||||
/** Generate a random number. */
|
||||
extern CoreExport int RandomNumber();
|
||||
|
||||
/** Calculates the levenshtein distance between two strings.
|
||||
* @param s1 The first string.
|
||||
* @param s2 The second string.
|
||||
*/
|
||||
extern CoreExport size_t Distance(const Anope::string &s1, const Anope::string &s2);
|
||||
|
||||
/** Update the current time. */
|
||||
extern CoreExport void UpdateTime();
|
||||
|
||||
/** Expands a path fragment that is relative to the base directory.
|
||||
* @param base The base directory that it is relative to.
|
||||
* @param fragment The fragment to expand.
|
||||
*/
|
||||
extern CoreExport Anope::string Expand(const Anope::string &base, const Anope::string &fragment);
|
||||
|
||||
/** Expands a config path. */
|
||||
inline auto ExpandConfig(const Anope::string &path) { return Expand(ConfigDir, path); }
|
||||
|
||||
/** Expands a data path. */
|
||||
inline auto ExpandData(const Anope::string &path) { return Expand(DataDir, path); }
|
||||
|
||||
/** Expands a locale path. */
|
||||
inline auto ExpandLocale(const Anope::string &path) { return Expand(LocaleDir, path); }
|
||||
|
||||
/** Expands a log path. */
|
||||
inline auto ExpandLog(const Anope::string &path) { return Expand(LogDir, path); }
|
||||
|
||||
/** Expands a module path. */
|
||||
inline auto ExpandModule(const Anope::string &path) { return Expand(ModuleDir, path); }
|
||||
|
||||
/** Formats a CTCP message for sending to a client.
|
||||
* @param name The name of the CTCP.
|
||||
* @param body If present then the body of the CTCP.
|
||||
* @return A formatted CTCP ready to send to a client.
|
||||
*/
|
||||
extern CoreExport Anope::string FormatCTCP(const Anope::string &name, const Anope::string &body = "");
|
||||
|
||||
/** Parses a CTCP message received from a client.
|
||||
* @param text The raw message to parse.
|
||||
* @param name The location to store the name of the CTCP.
|
||||
* @param body The location to store body of the CTCP if one is present.
|
||||
* @return True if the message was a well formed CTCP; otherwise, false.
|
||||
*/
|
||||
extern CoreExport bool ParseCTCP(const Anope::string &text, Anope::string &name, Anope::string &body);
|
||||
|
||||
/** Replaces template variables within a string with values from a map.
|
||||
* @param str The string to template from.
|
||||
* @param vars The variables to replace within the string.
|
||||
* @return The specified string with all variables replaced within it.
|
||||
*/
|
||||
extern CoreExport Anope::string Template(const Anope::string &str, const Anope::map<Anope::string> &vars);
|
||||
}
|
||||
|
||||
/** sepstream allows for splitting token separated lists.
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ public:
|
||||
* @param message The users' message
|
||||
* @params tags Message tags
|
||||
*/
|
||||
virtual void OnMessage(User *u, const Anope::string &message, const Anope::map<Anope::string> &tags);
|
||||
void OnMessage(User *u, const Anope::string &message, const Anope::map<Anope::string> &tags);
|
||||
|
||||
/** Link a command name to a command in services
|
||||
* @param cname The command name
|
||||
|
||||
+4
-2
@@ -32,10 +32,12 @@ struct CommandInfo final
|
||||
Anope::string permission;
|
||||
/* Group this command is in */
|
||||
Anope::string group;
|
||||
/* whether or not to hide this command in help output */
|
||||
/* Whether to hide this command in help and suggestions */
|
||||
bool hide = false;
|
||||
/* Only used with fantasy */
|
||||
/* Whether to prepend the channel name (only used with fantasy) */
|
||||
bool prepend_channel = false;
|
||||
/* Whether to require the FANTASY privilege (only used with fantasy) */
|
||||
bool require_privilege = true;
|
||||
};
|
||||
|
||||
/* Where the replies from commands go to. User inherits from this and is the normal
|
||||
|
||||
+12
-7
@@ -35,6 +35,14 @@ namespace Language
|
||||
*/
|
||||
extern void InitLanguages();
|
||||
|
||||
/** Sets the locale to the specified language.
|
||||
* @param lang The language to translate to.
|
||||
*/
|
||||
extern CoreExport void SetLocale(const char* lang);
|
||||
|
||||
/** Sets the locale back to the default. */
|
||||
extern CoreExport void ResetLocale();
|
||||
|
||||
/** Translates a string to the default language.
|
||||
* @param string A string to translate
|
||||
* @return The translated string if found, else the original string.
|
||||
@@ -101,8 +109,11 @@ namespace Language
|
||||
|
||||
/* Commonly used language strings */
|
||||
#define CONFIRM_DROP _("Please confirm that you want to drop \002%s\002 with \002%s\032%s\032%s\002")
|
||||
#define CONFIRM_REGISTER_ADMIN _("All new accounts must be confirmed by an administrator. Please wait for your registration to be confirmed.")
|
||||
#define CONFIRM_REGISTER_CODE _("All new accounts must be confirmed. To confirm your account, type \002%s\002.")
|
||||
#define CONFIRM_REGISTER_MAIL _("All new accounts must be confirmed. To confirm your account, follow the instructions that were emailed to you.")
|
||||
#define SERVICE_UNAVAILABLE _("Sorry, %s is temporarily unavailable.")
|
||||
#define MORE_INFO _("\002%s\002 for more information.")
|
||||
#define MORE_INFO _("Type \002%s\002 for more information.")
|
||||
#define BAD_USERHOST_MASK _("Mask must be in the form \037user\037@\037host\037.")
|
||||
#define BAD_EXPIRY_TIME _("Invalid expiry time.")
|
||||
#define USERHOST_MASK_TOO_WIDE _("%s coverage is too wide; Please use a more specific mask.")
|
||||
@@ -114,7 +125,6 @@ namespace Language
|
||||
"cannot contain the space or tab characters.")
|
||||
#define PASSWORD_TOO_SHORT _("Your password is too short. It must be longer than %u characters.")
|
||||
#define PASSWORD_TOO_LONG _("Your password is too long. It must be shorter than %u characters.")
|
||||
#define NICK_NOT_REGISTERED _("Your nick isn't registered.")
|
||||
#define NICK_X_NOT_REGISTERED _("Nick \002%s\002 isn't registered.")
|
||||
#define NICK_X_NOT_IN_USE _("Nick \002%s\002 isn't currently in use.")
|
||||
#define NICK_X_NOT_ON_CHAN _("\002%s\002 is not currently on channel %s.")
|
||||
@@ -127,14 +137,9 @@ namespace Language
|
||||
#define UNKNOWN _("<unknown>")
|
||||
#define NO_EXPIRE _("does not expire")
|
||||
#define LIST_INCORRECT_RANGE _("Incorrect range specified. The correct syntax is \002#\037from\037-\037to\037\002.")
|
||||
#define NICK_IS_SECURE _("This nickname is registered and protected. If it is your " \
|
||||
"nick, type \002%s\032\037password\037\002. Otherwise, " \
|
||||
"please choose a different nick.")
|
||||
#define FORCENICKCHANGE_NOW _("This nickname has been registered; you may not use it.")
|
||||
#define NICK_CANNOT_BE_REGISTERED _("Nickname \002%s\002 may not be registered.")
|
||||
#define NICK_ALREADY_REGISTERED _("Nickname \002%s\002 is already registered!")
|
||||
#define NICK_SET_DISPLAY_CHANGED _("The new display is now \002%s\002.")
|
||||
#define NICK_CONFIRM_INVALID _("Invalid passcode has been entered, please check the email again, and retry.")
|
||||
#define CHAN_NOT_ALLOWED_TO_JOIN _("You are not permitted to be on this channel.")
|
||||
#define CHAN_X_INVALID _("Channel %s is not a valid channel.")
|
||||
#define CHAN_REACHED_CHANNEL_LIMIT _("Sorry, you have already reached your limit of \002%d\002 channels.")
|
||||
|
||||
@@ -57,35 +57,3 @@ public:
|
||||
*/
|
||||
virtual bool InvalidRange(const Anope::string &list);
|
||||
};
|
||||
|
||||
/** This class handles formatting LIST/VIEW replies.
|
||||
*/
|
||||
class CoreExport ListFormatter final
|
||||
{
|
||||
public:
|
||||
typedef std::map<Anope::string, Anope::string> ListEntry;
|
||||
private:
|
||||
NickCore *nc;
|
||||
std::vector<Anope::string> columns;
|
||||
std::vector<ListEntry> entries;
|
||||
public:
|
||||
ListFormatter(NickCore *nc);
|
||||
ListFormatter &AddColumn(const Anope::string &name);
|
||||
void AddEntry(const ListEntry &entry);
|
||||
bool IsEmpty() const;
|
||||
void Process(std::vector<Anope::string> &);
|
||||
};
|
||||
|
||||
/** This class handles formatting INFO replies
|
||||
*/
|
||||
class CoreExport InfoFormatter final
|
||||
{
|
||||
NickCore *nc;
|
||||
std::vector<std::pair<Anope::string, Anope::string> > replies;
|
||||
unsigned longest = 0;
|
||||
public:
|
||||
InfoFormatter(NickCore *nc);
|
||||
void Process(std::vector<Anope::string> &);
|
||||
Anope::string &operator[](const Anope::string &key);
|
||||
void AddOption(const Anope::string &opt);
|
||||
};
|
||||
|
||||
+15
-10
@@ -70,11 +70,6 @@ public:
|
||||
*/
|
||||
Mode(const Anope::string &mname, ModeClass mclass, char mc, ModeType type);
|
||||
virtual ~Mode() = default;
|
||||
|
||||
/** Can a user set this mode, used for mlock
|
||||
* @param u The user
|
||||
*/
|
||||
virtual bool CanSet(User *u) const;
|
||||
};
|
||||
|
||||
/** This class is a user mode, all user modes use this/inherit from this
|
||||
@@ -88,6 +83,12 @@ public:
|
||||
* @param mc The mode char
|
||||
*/
|
||||
UserMode(const Anope::string &name, char mc);
|
||||
|
||||
/** Can a user set this mode, used for mlock
|
||||
* @param source The user who is setting the mode.
|
||||
* @param target The user the mode is being set on.
|
||||
*/
|
||||
virtual bool CanSet(User *source, User *target) const { return true; }
|
||||
};
|
||||
|
||||
class CoreExport UserModeParam
|
||||
@@ -122,7 +123,11 @@ public:
|
||||
*/
|
||||
ChannelMode(const Anope::string &name, char mc);
|
||||
|
||||
bool CanSet(User *u) const override;
|
||||
/** Can a user set this mode, used for mlock
|
||||
* @param u The user who is setting the mode.
|
||||
* @param c The channel the mode is being set on.
|
||||
*/
|
||||
virtual bool CanSet(User *u, Channel *c) const;
|
||||
|
||||
virtual void Check() { }
|
||||
|
||||
@@ -270,7 +275,7 @@ class CoreExport UserModeOperOnly
|
||||
public:
|
||||
UserModeOperOnly(const Anope::string &mname, char um) : UserMode(mname, um) { }
|
||||
|
||||
bool CanSet(User *u) const override;
|
||||
bool CanSet(User *source, User *target) const override;
|
||||
};
|
||||
|
||||
class CoreExport UserModeNoone
|
||||
@@ -279,7 +284,7 @@ class CoreExport UserModeNoone
|
||||
public:
|
||||
UserModeNoone(const Anope::string &mname, char um) : UserMode(mname, um) { }
|
||||
|
||||
bool CanSet(User *u) const override;
|
||||
bool CanSet(User *source, User *target) const override;
|
||||
};
|
||||
|
||||
/** Channel mode +k (key)
|
||||
@@ -302,7 +307,7 @@ public:
|
||||
ChannelModeOperOnly(const Anope::string &mname, char mc) : ChannelMode(mname, mc) { }
|
||||
|
||||
/* Opers only */
|
||||
bool CanSet(User *u) const override;
|
||||
bool CanSet(User *u, Channel *c) const override;
|
||||
};
|
||||
|
||||
/** This class is used for channel modes only servers may set
|
||||
@@ -313,7 +318,7 @@ class CoreExport ChannelModeNoone
|
||||
public:
|
||||
ChannelModeNoone(const Anope::string &mname, char mc) : ChannelMode(mname, mc) { }
|
||||
|
||||
bool CanSet(User *u) const override;
|
||||
bool CanSet(User *u, Channel *c) const override;
|
||||
};
|
||||
|
||||
/** This is the mode manager
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "services.h"
|
||||
#include "socketengine.h"
|
||||
#include "sockets.h"
|
||||
#include "textproc.h"
|
||||
#include "threadengine.h"
|
||||
#include "timers.h"
|
||||
#include "uplink.h"
|
||||
|
||||
+7
-3
@@ -158,7 +158,9 @@ enum
|
||||
PSEUDOCLIENT = 1 << 5,
|
||||
/* Module provides IRCd protocol support */
|
||||
PROTOCOL = 1 << 6,
|
||||
MT_END = 1 << 7
|
||||
/* Module is deprecated */
|
||||
DEPRECATED = 1 << 7,
|
||||
MT_END = DEPRECATED,
|
||||
};
|
||||
typedef unsigned short ModType;
|
||||
|
||||
@@ -1046,9 +1048,10 @@ public:
|
||||
|
||||
/** Called to determine if a channel mode can be set by a user
|
||||
* @param u The user
|
||||
* @param c The channel
|
||||
* @param cm The mode
|
||||
*/
|
||||
virtual EventReturn OnCanSet(User *u, const ChannelMode *cm) ATTR_NOT_NULL(2, 3) { throw NotImplementedException(); }
|
||||
virtual EventReturn OnCanSet(User *u, Channel *c, const ChannelMode *cm) ATTR_NOT_NULL(2, 3) { throw NotImplementedException(); }
|
||||
|
||||
virtual EventReturn OnCheckDelete(Channel *c) ATTR_NOT_NULL(2) { throw NotImplementedException(); }
|
||||
|
||||
@@ -1245,9 +1248,10 @@ public:
|
||||
|
||||
/** Find the first module of a certain type
|
||||
* @param type The module type
|
||||
* @param ignoredeprecated Whether to ignore deprecated modules.
|
||||
* @return The module
|
||||
*/
|
||||
static Module *FindFirstOf(ModType type);
|
||||
static Module *FindFirstOf(ModType type, bool ignoredeprecated = false);
|
||||
|
||||
/** Checks whether this version of Anope is at least major.minor.patch.build
|
||||
* Throws a ModuleException if not
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace DNS
|
||||
{
|
||||
/** Valid query types
|
||||
@@ -29,8 +31,12 @@ namespace DNS
|
||||
QUERY_SOA = 6,
|
||||
/* Reverse DNS lookup */
|
||||
QUERY_PTR = 12,
|
||||
/* TXT lookup */
|
||||
QUERY_TXT = 16,
|
||||
/* IPv6 AAAA lookup */
|
||||
QUERY_AAAA = 28,
|
||||
/** SRV lookup */
|
||||
QUERY_SRV = 33,
|
||||
/* Zone transfer */
|
||||
QUERY_AXFR = 252,
|
||||
/* A lookup for any record */
|
||||
@@ -88,11 +94,23 @@ namespace DNS
|
||||
};
|
||||
};
|
||||
|
||||
namespace Record
|
||||
{
|
||||
struct SRV final
|
||||
{
|
||||
uint16_t priority = UINT16_MAX;
|
||||
uint16_t weight = 0;
|
||||
uint16_t port = 0;
|
||||
Anope::string host;
|
||||
};
|
||||
}
|
||||
|
||||
struct ResourceRecord final
|
||||
: Question
|
||||
{
|
||||
unsigned int ttl = 0;
|
||||
Anope::string rdata;
|
||||
std::shared_ptr<void> rdataobj;
|
||||
time_t created;
|
||||
|
||||
ResourceRecord(const Anope::string &n, QueryType t, unsigned short c = 1) : Question(n, t, c), created(Anope::CurTime) { }
|
||||
|
||||
@@ -18,6 +18,8 @@ public:
|
||||
Anope::string ident;
|
||||
Anope::string host;
|
||||
time_t time = 0;
|
||||
Anope::string validation_token;
|
||||
time_t last_validation = 0;
|
||||
|
||||
virtual ~HostRequest() = default;
|
||||
};
|
||||
|
||||
@@ -151,7 +151,7 @@ struct SASL::Session
|
||||
if (u)
|
||||
return u->GetMask();
|
||||
if (!hostname.empty() && !ip.empty())
|
||||
return Anope::printf("%s (%s)", hostname.c_str(), ip.c_str());
|
||||
return Anope::Format("%s (%s)", hostname.c_str(), ip.c_str());
|
||||
return "A user";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,13 +15,6 @@ enum NewsType
|
||||
NEWS_OPER
|
||||
};
|
||||
|
||||
struct NewsMessages final
|
||||
{
|
||||
NewsType type;
|
||||
Anope::string name;
|
||||
const char *msgs[10];
|
||||
};
|
||||
|
||||
struct NewsItem
|
||||
: Serializable
|
||||
{
|
||||
|
||||
@@ -228,9 +228,7 @@ public:
|
||||
if (header.compare(0, 7, "Bearer ", 7) != 0)
|
||||
return false; // No token provided.
|
||||
|
||||
Anope::string rawtoken;
|
||||
Anope::B64Decode(header.substr(7), rawtoken);
|
||||
|
||||
auto rawtoken = Anope::B64Decode(header.substr(7));
|
||||
for (const auto &token : tokens)
|
||||
{
|
||||
if (!CompareToken(token, rawtoken))
|
||||
|
||||
+9
-5
@@ -131,11 +131,15 @@ public:
|
||||
/* The maximum length of a username. */
|
||||
size_t MaxUser = 0;
|
||||
|
||||
|
||||
/* Retrieves the next free UID or SID */
|
||||
virtual Anope::string UID_Retrieve();
|
||||
virtual Anope::string SID_Retrieve();
|
||||
|
||||
/** Retrieves advice on what might be the problem when a link fails.
|
||||
* @param advice The location to store the advice.
|
||||
*/
|
||||
virtual void GetLinkAdvice(std::vector<Anope::string> &advice) { }
|
||||
|
||||
/** Extracts a timestamp from a string. */
|
||||
virtual time_t ExtractTimestamp(const Anope::string &str);
|
||||
|
||||
@@ -211,8 +215,8 @@ public:
|
||||
virtual void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) = 0;
|
||||
virtual void SendGlobalPrivmsg(BotInfo *bi, const Server *desc, const Anope::string &msg) = 0;
|
||||
|
||||
virtual void SendContextNotice(BotInfo *bi, User *target, Channel *context, const Anope::string &msg);
|
||||
virtual void SendContextPrivmsg(BotInfo *bi, User *target, Channel *context, const Anope::string &msg);
|
||||
virtual void SendContextNotice(BotInfo *bi, User *target, Channel *context, const Anope::string &msg, const Anope::map<Anope::string> &tags = {});
|
||||
virtual void SendContextPrivmsg(BotInfo *bi, User *target, Channel *context, const Anope::string &msg, const Anope::map<Anope::string> &tags = {});
|
||||
|
||||
virtual void SendQuit(User *u, const Anope::string &msg = "", const Anope::string &opermsg = "");
|
||||
virtual void SendPing(const Anope::string &servname, const Anope::string &who);
|
||||
@@ -276,9 +280,9 @@ public:
|
||||
virtual void SendServer(const Server *) = 0;
|
||||
virtual void SendSquit(Server *, const Anope::string &message);
|
||||
|
||||
virtual void SendNumericInternal(int numeric, const Anope::string &dest, const std::vector<Anope::string> ¶ms);
|
||||
virtual void SendNumericInternal(unsigned numeric, const Anope::string &dest, const std::vector<Anope::string> ¶ms);
|
||||
template <typename... Args>
|
||||
void SendNumeric(int numeric, const Anope::string &dest, Args &&...args)
|
||||
void SendNumeric(unsigned numeric, const Anope::string &dest, Args &&...args)
|
||||
{
|
||||
SendNumericInternal(numeric, dest, { Anope::ToString(args)... });
|
||||
}
|
||||
|
||||
@@ -11,6 +11,93 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ANOPE_FORMAT(LAST, FORMAT, BUFFER) \
|
||||
do { \
|
||||
va_list _valist; \
|
||||
va_start(_valist, LAST); \
|
||||
(BUFFER) = Anope::Format(_valist, (FORMAT)); \
|
||||
va_end(_valist); \
|
||||
} while (false);
|
||||
|
||||
namespace Anope
|
||||
{
|
||||
/** Encode a string as base-64.
|
||||
* @param str The string to encode as base-64 .
|
||||
*/
|
||||
extern CoreExport Anope::string B64Encode(const Anope::string &str);
|
||||
|
||||
/** Decode a string from base-64.
|
||||
* @param str The string to decode from base-64.
|
||||
*/
|
||||
extern CoreExport Anope::string B64Decode(const Anope::string &str);
|
||||
|
||||
/** Calculates the levenshtein distance between two strings.
|
||||
* @param s1 The first string.
|
||||
* @param s2 The second string.
|
||||
*/
|
||||
extern CoreExport size_t Distance(const Anope::string &s1, const Anope::string &s2);
|
||||
|
||||
/** Expands a path fragment that is relative to the base directory.
|
||||
* @param base The base directory that it is relative to.
|
||||
* @param fragment The fragment to expand.
|
||||
*/
|
||||
extern CoreExport Anope::string Expand(const Anope::string &base, const Anope::string &fragment);
|
||||
|
||||
/** Expands a config path. */
|
||||
inline auto ExpandConfig(const Anope::string &path) { return Expand(ConfigDir, path); }
|
||||
|
||||
/** Expands a data path. */
|
||||
inline auto ExpandData(const Anope::string &path) { return Expand(DataDir, path); }
|
||||
|
||||
/** Expands a locale path. */
|
||||
inline auto ExpandLocale(const Anope::string &path) { return Expand(LocaleDir, path); }
|
||||
|
||||
/** Expands a log path. */
|
||||
inline auto ExpandLog(const Anope::string &path) { return Expand(LogDir, path); }
|
||||
|
||||
/** Expands a module path. */
|
||||
inline auto ExpandModule(const Anope::string &path) { return Expand(ModuleDir, path); }
|
||||
|
||||
/** Formats a string using one or more values. This uses snprintf internally but with a flexible buffer.
|
||||
* @param fmt The message to format.
|
||||
*/
|
||||
extern CoreExport Anope::string Format(const char *fmt, ...) ATTR_FORMAT(1, 2);
|
||||
|
||||
/** Formats a string using a list of values. This uses snprintf internally but with a flexible buffer.
|
||||
* @param valist A list of values to format the message with.
|
||||
* @param fmt The message to format.
|
||||
*/
|
||||
extern CoreExport Anope::string Format(va_list &valist, const char *fmt) ATTR_FORMAT(2, 0);
|
||||
|
||||
/** Formats a CTCP message for sending to a client.
|
||||
* @param name The name of the CTCP.
|
||||
* @param body If present then the body of the CTCP.
|
||||
* @return A formatted CTCP ready to send to a client.
|
||||
*/
|
||||
extern CoreExport Anope::string FormatCTCP(const Anope::string &name, const Anope::string &body = "");
|
||||
|
||||
/** Parses a CTCP message received from a client.
|
||||
* @param text The raw message to parse.
|
||||
* @param name The location to store the name of the CTCP.
|
||||
* @param body The location to store body of the CTCP if one is present.
|
||||
* @return True if the message was a well formed CTCP; otherwise, false.
|
||||
*/
|
||||
extern CoreExport bool ParseCTCP(const Anope::string &text, Anope::string &name, Anope::string &body);
|
||||
|
||||
/** Remove all formatting characters from a string.
|
||||
* @param text A string containing formatting characters.
|
||||
* @return A copy of \p text with all formatting characters removed.
|
||||
*/
|
||||
extern CoreExport Anope::string RemoveFormatting(const Anope::string &text);
|
||||
|
||||
/** Replaces template variables within a string with values from a map.
|
||||
* @param str The string to template from.
|
||||
* @param vars The variables to replace within the string.
|
||||
* @return The specified string with all variables replaced within it.
|
||||
*/
|
||||
extern CoreExport Anope::string Template(const Anope::string &str, const Anope::map<Anope::string> &vars);
|
||||
}
|
||||
|
||||
class CoreExport HelpWrapper final
|
||||
{
|
||||
private:
|
||||
@@ -22,6 +109,21 @@ public:
|
||||
void SendTo(CommandSource &source);
|
||||
};
|
||||
|
||||
class CoreExport InfoFormatter final
|
||||
{
|
||||
private:
|
||||
size_t longest = 0;
|
||||
NickCore *nc;
|
||||
std::vector<Anope::string> options;
|
||||
std::vector<std::pair<Anope::string, Anope::string>> replies;
|
||||
|
||||
public:
|
||||
InfoFormatter(NickCore *nc);
|
||||
Anope::string &operator[](const Anope::string &key);
|
||||
void AddOption(const Anope::string &opt);
|
||||
void SendTo(CommandSource &source);
|
||||
};
|
||||
|
||||
class CoreExport LineWrapper final
|
||||
{
|
||||
private:
|
||||
@@ -34,3 +136,26 @@ public:
|
||||
bool GetLine(Anope::string &out);
|
||||
};
|
||||
|
||||
class CoreExport ListFormatter final
|
||||
{
|
||||
public:
|
||||
using ListEntry = std::map<Anope::string, Anope::string>;
|
||||
using FlexibleFormatFn = std::function<Anope::string(ListEntry &)>;
|
||||
|
||||
private:
|
||||
std::vector<Anope::string> columns;
|
||||
std::vector<ListEntry> entries;
|
||||
FlexibleFormatFn flexiblerow;
|
||||
NickCore *nc;
|
||||
void SendFixed(CommandSource &source);
|
||||
void SendFlexible(CommandSource &source);
|
||||
|
||||
public:
|
||||
ListFormatter(NickCore *nc);
|
||||
ListFormatter &AddColumn(const Anope::string &name);
|
||||
void AddEntry(const ListEntry &entry);
|
||||
bool IsEmpty() const;
|
||||
void SendTo(CommandSource &source);
|
||||
void SetFlexible(const Anope::string &format);
|
||||
void SetFlexible(const FlexibleFormatFn &formatter);
|
||||
};
|
||||
|
||||
+1
-1
@@ -253,7 +253,7 @@ public:
|
||||
*/
|
||||
bool HasPriv(const Anope::string &privstr);
|
||||
|
||||
/** Update the last usermask stored for a user. */
|
||||
/** Update the last mask stored for a user. */
|
||||
void UpdateHost();
|
||||
|
||||
/** Update the away state for a user. */
|
||||
|
||||
@@ -6607,7 +6607,7 @@ msgid "Service"
|
||||
msgstr "Server gefunden: %d"
|
||||
|
||||
#, fuzzy, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Die Services haben den Nicknamen wieder verfügbar gemacht."
|
||||
|
||||
#, fuzzy
|
||||
|
||||
@@ -6832,7 +6832,7 @@ msgid "Service"
|
||||
msgstr "Τα services είναι ενεργά για %s"
|
||||
|
||||
#, fuzzy, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Οι υπηρεσίες απελευθέρωααν το ψευδώνυμό σου."
|
||||
|
||||
#, fuzzy
|
||||
|
||||
+469
-216
File diff suppressed because it is too large
Load Diff
@@ -6273,7 +6273,7 @@ msgid "Service"
|
||||
msgstr "Servicio"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "El nick %s retenido por los servicios ha sido liberado."
|
||||
|
||||
#, fuzzy
|
||||
|
||||
@@ -6155,7 +6155,7 @@ msgid "Service"
|
||||
msgstr "Service"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "La tutelle des Services sur %s a été enlevée."
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
@@ -6146,7 +6146,7 @@ msgid "Service"
|
||||
msgstr "Servizio"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Il blocco dei servizi sul nick %s è stato rilasciato."
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
@@ -6182,7 +6182,7 @@ msgid "Service"
|
||||
msgstr "Service"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Nick %s werd vrijgegeven."
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
@@ -6123,7 +6123,7 @@ msgid "Service"
|
||||
msgstr "Usługa"
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr "Serwisy właśnie zwolniły nicka %s."
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
@@ -5675,7 +5675,7 @@ msgid "Service"
|
||||
msgstr ""
|
||||
|
||||
#, c-format
|
||||
msgid "Service's hold on %s has been released."
|
||||
msgid "Services' hold on %s has been released."
|
||||
msgstr ""
|
||||
|
||||
msgid "Services Operator commands"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+1906
-3639
File diff suppressed because it is too large
Load Diff
+9
-35
@@ -36,7 +36,7 @@ macro(build_modules SRC)
|
||||
if(NOT ${SRC} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR} AND EXISTS "${SRC}/CMakeLists.txt")
|
||||
add_subdirectory("${SRC}")
|
||||
else()
|
||||
file(GLOB MODULES_SRCS "${SRC}/*")
|
||||
file(GLOB MODULES_SRCS CONFIGURE_DEPENDS "${SRC}/*")
|
||||
foreach(MODULE_SRC ${MODULES_SRCS})
|
||||
if(IS_DIRECTORY "${MODULE_SRC}")
|
||||
build_modules("${MODULE_SRC}")
|
||||
@@ -52,12 +52,6 @@ macro(build_modules SRC)
|
||||
file(RELATIVE_PATH FNAME ${SRC} ${MODULE_SRC})
|
||||
# Convert the real source file extension to have a library extension
|
||||
string(REGEX REPLACE "\\.cpp$" "${CMAKE_SHARED_LIBRARY_SUFFIX}" SO ${FNAME})
|
||||
# Reset linker flags
|
||||
set(TEMP_LDFLAGS)
|
||||
# Reset extra dependencies
|
||||
set(TEMP_DEPENDENCIES)
|
||||
# Calculate the library dependencies for the given source file
|
||||
calculate_libraries(${MODULE_SRC} TEMP_LDFLAGS TEMP_DEPENDENCIES)
|
||||
# For Visual Studio only, include win32_memory static library, required to override Visual Studio's overrides of the new/delete operators
|
||||
if(MSVC)
|
||||
set(WIN32_MEMORY win32_memory)
|
||||
@@ -66,6 +60,8 @@ macro(build_modules SRC)
|
||||
endif()
|
||||
# Generate the module and set its linker flags, also set it to depend on the main Anope executable to be built beforehand
|
||||
add_library(${SO} MODULE ${MODULE_SRC})
|
||||
# Execute inline CMake code for the module
|
||||
inline_cmake(${SO} ${MODULE_SRC})
|
||||
# Windows requires this because it's weird
|
||||
if(WIN32)
|
||||
set(WIN32_NO_LIBS "/nodefaultlib:\"libcmt.lib\" /OPT:NOREF")
|
||||
@@ -77,7 +73,7 @@ macro(build_modules SRC)
|
||||
FOLDER "Modules"
|
||||
INSTALL_RPATH_USE_LINK_PATH ON
|
||||
LINKER_LANGUAGE CXX
|
||||
LINK_FLAGS "${TEMP_LDFLAGS} ${WIN32_NO_LIBS}"
|
||||
LINK_FLAGS "${WIN32_NO_LIBS}"
|
||||
PREFIX ""
|
||||
SUFFIX ""
|
||||
)
|
||||
@@ -85,13 +81,12 @@ macro(build_modules SRC)
|
||||
if(HAVE_LOCALIZATION)
|
||||
add_dependencies(${SO} module_language)
|
||||
endif()
|
||||
target_link_libraries(${SO} ${TEMP_DEPENDENCIES})
|
||||
# For Windows only, have the module link to the export library of Anope as well as wsock32 and Ws2_32 libraries (most of the modules probably don't need this, but this is to be on the safe side), also set its version
|
||||
if(WIN32)
|
||||
target_link_libraries(${SO} ${PROGRAM_NAME} wsock32 Ws2_32 ${WIN32_MEMORY})
|
||||
target_link_libraries(${SO} PUBLIC ${PROGRAM_NAME} wsock32 Ws2_32 ${WIN32_MEMORY})
|
||||
set_target_properties(${PROGRAM_NAME} PROPERTIES VERSION "${VERSION_DOTTED}")
|
||||
elseif(APPLE)
|
||||
target_link_libraries(${SO} ${PROGRAM_NAME})
|
||||
target_link_libraries(${SO} PUBLIC ${PROGRAM_NAME})
|
||||
endif()
|
||||
# Set the module to be installed to the module directory under the data directory
|
||||
install(TARGETS ${SO}
|
||||
@@ -104,7 +99,7 @@ macro(build_modules SRC)
|
||||
endmacro()
|
||||
|
||||
macro(build_subdir)
|
||||
file(GLOB_RECURSE MODULES_SUBDIR_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp")
|
||||
file(GLOB_RECURSE MODULES_SUBDIR_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS "*.cpp")
|
||||
list(SORT MODULES_SUBDIR_SRCS)
|
||||
|
||||
GET_FILENAME_COMPONENT(FOLDER_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
@@ -113,31 +108,11 @@ macro(build_subdir)
|
||||
# Set all the files to use C++ as well as set their compile flags (use the module-specific compile flags, though)
|
||||
set_source_files_properties(${MODULES_SUBDIR_SRCS} PROPERTIES LANGUAGE CXX COMPILE_FLAGS "${CXXFLAGS}")
|
||||
|
||||
# Iterate through the source files in the subdirectory
|
||||
foreach(SRC ${MODULES_SUBDIR_SRCS})
|
||||
# Reset linker flags
|
||||
set(TEMP_LDFLAGS)
|
||||
# Reset extra dependencies
|
||||
set(TEMP_DEPENDENCIES)
|
||||
# Calculate the library dependencies for the given source file
|
||||
calculate_libraries(${SRC} SKIP_LIBRARIES MODULE TEMP_LDFLAGS TEMP_DEPENDENCIES)
|
||||
|
||||
# Append this source file's linker flags to the subdirectoy's linker flags, if there are any to append
|
||||
if(TEMP_DEPENDENCIES)
|
||||
list(APPEND SUBDIR_EXTRA_DEPENDS ${TEMP_DEPENDENCIES})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Remove duplicates from the linker flags
|
||||
if(SUBDIR_LDFLAGS)
|
||||
list(REMOVE_DUPLICATES SUBDIR_LDFLAGS)
|
||||
endif()
|
||||
|
||||
# Remove duplicates from the extra dependencies
|
||||
if(SUBDIR_EXTRA_DEPENDS)
|
||||
list(REMOVE_DUPLICATES SUBDIR_EXTRA_DEPENDS)
|
||||
endif()
|
||||
|
||||
# For Visual Studio only, include win32_memory static library, required to override Visual Studio's overrides of the new/delete operators
|
||||
if(MSVC)
|
||||
set(WIN32_MEMORY win32_memory)
|
||||
@@ -160,13 +135,12 @@ macro(build_subdir)
|
||||
if(HAVE_LOCALIZATION)
|
||||
add_dependencies(${SO} module_language)
|
||||
endif()
|
||||
target_link_libraries(${SO} ${SUBDIR_EXTRA_DEPENDS})
|
||||
# For Windows only, have the module link to the export library of Anope as well as wsock32 and Ws2_32 libraries (most of the modules probably don't need this, but this is to be on the safe side), also set it's version
|
||||
if(WIN32)
|
||||
target_link_libraries(${SO} ${PROGRAM_NAME} wsock32 Ws2_32 ${WIN32_MEMORY})
|
||||
target_link_libraries(${SO} PUBLIC ${PROGRAM_NAME} PUBLIC wsock32 Ws2_32 ${WIN32_MEMORY})
|
||||
set_target_properties(${PROGRAM_NAME} PROPERTIES VERSION "${VERSION_DOTTED}")
|
||||
elseif(APPLE)
|
||||
target_link_libraries(${SO} ${PROGRAM_NAME})
|
||||
target_link_libraries(${SO} PUBLIC ${PROGRAM_NAME})
|
||||
endif()
|
||||
|
||||
# Set the module to be installed to the module directory under the data directory
|
||||
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
{
|
||||
ChannelMode *cm = ModeManager::FindChannelModeByName("OP");
|
||||
char symbol = cm ? anope_dynamic_static_cast<ChannelModeStatus *>(cm)->symbol : 0;
|
||||
const auto message = Anope::printf("%s invited %s into the channel.", user->nick.c_str(), user->nick.c_str());
|
||||
const auto message = Anope::Format("%s invited %s into the channel.", user->nick.c_str(), user->nick.c_str());
|
||||
IRCD->SendNotice(bi, (symbol ? Anope::string(symbol) : "") + c->name, message);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,39 @@
|
||||
#include "module.h"
|
||||
#include "modules/botserv/badwords.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
Anope::string TypeToString(BadWordType bw)
|
||||
{
|
||||
switch (bw)
|
||||
{
|
||||
case BW_ANY:
|
||||
return "ANY";
|
||||
case BW_SINGLE:
|
||||
return "SINGLE";
|
||||
case BW_START:
|
||||
return "START";
|
||||
case BW_END:
|
||||
return "END";
|
||||
}
|
||||
return ""; // Should never happen.
|
||||
}
|
||||
|
||||
BadWordType StringToType(const Anope::string &bw)
|
||||
{
|
||||
if (bw.equals_ci("ANY") || bw.equals_ci("0"))
|
||||
return BW_ANY;
|
||||
if (bw.equals_ci("SINGLE") || bw.equals_ci("1"))
|
||||
return BW_SINGLE;
|
||||
if (bw.equals_ci("START") || bw.equals_ci("2"))
|
||||
return BW_START;
|
||||
if (bw.equals_ci("END") || bw.equals_ci("3"))
|
||||
return BW_END;
|
||||
|
||||
return BW_ANY; // Should never happen.
|
||||
}
|
||||
}
|
||||
|
||||
struct BadWordImpl final
|
||||
: BadWord
|
||||
, Serializable
|
||||
@@ -33,7 +66,7 @@ struct BadWordTypeImpl final
|
||||
const auto *bw = static_cast<const BadWordImpl *>(obj);
|
||||
data.Store("ci", bw->chan);
|
||||
data.Store("word", bw->word);
|
||||
data.Store("type", bw->type);
|
||||
data.Store("type", TypeToString(bw->type));
|
||||
}
|
||||
|
||||
Serializable *Unserialize(Serializable *obj, Serialize::Data &) const override;
|
||||
@@ -138,7 +171,7 @@ Serializable *BadWordTypeImpl::Unserialize(Serializable *obj, Serialize::Data &d
|
||||
if (!ci)
|
||||
return NULL;
|
||||
|
||||
unsigned int n;
|
||||
Anope::string n;
|
||||
data["type"] >> n;
|
||||
|
||||
BadWordImpl *bw;
|
||||
@@ -148,7 +181,7 @@ Serializable *BadWordTypeImpl::Unserialize(Serializable *obj, Serialize::Data &d
|
||||
bw = new BadWordImpl();
|
||||
bw->chan = sci;
|
||||
bw->word = sword;
|
||||
bw->type = static_cast<BadWordType>(n);
|
||||
bw->type = StringToType(n);
|
||||
|
||||
BadWordsImpl *bws = ci->Require<BadWordsImpl>("badwords");
|
||||
if (!obj)
|
||||
@@ -213,11 +246,12 @@ private:
|
||||
{
|
||||
bool override = !source.AccessFor(ci).HasPriv("BADWORDS");
|
||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "LIST";
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
BadWords *bw = ci->GetExt<BadWords>("badwords");
|
||||
|
||||
list.AddColumn(_("Number")).AddColumn(_("Word")).AddColumn(_("Type"));
|
||||
list.SetFlexible(_("{number}: \002{word}\002 -- type: {type}"));
|
||||
|
||||
BadWords *bw = ci->GetExt<BadWords>("badwords");
|
||||
if (!bw || !bw->GetBadWordCount())
|
||||
{
|
||||
source.Reply(_("%s bad words list is empty."), ci->name.c_str());
|
||||
@@ -244,7 +278,7 @@ private:
|
||||
ListFormatter::ListEntry entry;
|
||||
entry["Number"] = Anope::ToString(Number);
|
||||
entry["Word"] = b->word;
|
||||
entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : ""));
|
||||
entry["Type"] = TypeToString(b->type);
|
||||
this->list.AddEntry(entry);
|
||||
}
|
||||
}
|
||||
@@ -263,7 +297,7 @@ private:
|
||||
ListFormatter::ListEntry entry;
|
||||
entry["Number"] = Anope::ToString(i + 1);
|
||||
entry["Word"] = b->word;
|
||||
entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : ""));
|
||||
entry["Type"] = TypeToString(b->type);
|
||||
list.AddEntry(entry);
|
||||
}
|
||||
}
|
||||
@@ -272,14 +306,8 @@ private:
|
||||
source.Reply(_("No matching entries on %s bad words list."), ci->name.c_str());
|
||||
else
|
||||
{
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
source.Reply(_("Bad words list for %s:"), ci->name.c_str());
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
|
||||
list.SendTo(source);
|
||||
source.Reply(_("End of bad words list."));
|
||||
}
|
||||
}
|
||||
@@ -295,14 +323,7 @@ private:
|
||||
{
|
||||
Anope::string opt = word.substr(pos + 1);
|
||||
if (!opt.empty())
|
||||
{
|
||||
if (opt.equals_ci("SINGLE"))
|
||||
bwtype = BW_SINGLE;
|
||||
else if (opt.equals_ci("START"))
|
||||
bwtype = BW_START;
|
||||
else if (opt.equals_ci("END"))
|
||||
bwtype = BW_END;
|
||||
}
|
||||
bwtype = StringToType(opt);
|
||||
realword = word.substr(0, pos);
|
||||
}
|
||||
|
||||
@@ -460,7 +481,8 @@ public:
|
||||
"that starts with \037word\037. If END is specified, a kick "
|
||||
"will be done if a user says a word that ends with "
|
||||
"\037word\037. If you don't specify anything, a kick will "
|
||||
"be issued every time \037word\037 is said by a user."
|
||||
"be issued every time \037word\037 is said by a user. This "
|
||||
"will be shown in the \002LIST\002 output as ANY."
|
||||
"\n\n"
|
||||
"The \002DEL\002 command removes the given word from the "
|
||||
"bad words list. If a list of entry numbers is given, those "
|
||||
|
||||
@@ -88,7 +88,6 @@ private:
|
||||
source.Reply(_("%s!%s@%s (%s) added to the bot list."), bi->nick.c_str(), bi->GetIdent().c_str(), bi->host.c_str(), bi->realname.c_str());
|
||||
|
||||
FOREACH_MOD(OnBotCreate, (bi));
|
||||
return;
|
||||
}
|
||||
|
||||
void DoChange(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
@@ -227,7 +226,6 @@ private:
|
||||
Log(LOG_ADMIN, source, this) << "CHANGE " << oldnick << " to " << bi->GetMask() << " " << bi->realname;
|
||||
|
||||
FOREACH_MOD(OnBotChange, (bi));
|
||||
return;
|
||||
}
|
||||
|
||||
void DoDel(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
@@ -259,7 +257,6 @@ private:
|
||||
|
||||
source.Reply(_("Bot \002%s\002 has been deleted."), nick.c_str());
|
||||
delete bi;
|
||||
return;
|
||||
}
|
||||
public:
|
||||
CommandBSBot(Module *creator) : Command(creator, "botserv/bot", 1, 6)
|
||||
@@ -339,8 +336,6 @@ public:
|
||||
}
|
||||
else
|
||||
this->OnSyntaxError(source, "");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
|
||||
|
||||
@@ -41,11 +41,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
unsigned count = 0;
|
||||
ListFormatter list(source.GetAccount());
|
||||
|
||||
list.AddColumn(_("Nick")).AddColumn(_("Mask")).AddColumn(_("Real name"));
|
||||
list.SetFlexible(_("\002{nick}\002 ({mask}) [{real_name}]"));
|
||||
|
||||
unsigned count = 0;
|
||||
for (const auto &[_, bi] : *BotListByNick)
|
||||
{
|
||||
if (is_admin || !bi->oper_only)
|
||||
@@ -66,9 +66,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
if (!count)
|
||||
{
|
||||
source.Reply(_(
|
||||
@@ -79,10 +76,7 @@ public:
|
||||
else
|
||||
{
|
||||
source.Reply(_("Bot list:"));
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
|
||||
list.SendTo(source);
|
||||
source.Reply(_("%d bots available."), count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,15 +55,10 @@ public:
|
||||
info[_("Real name")] = bi->realname;
|
||||
info[_("Created")] = Anope::strftime(bi->created, source.GetAccount());
|
||||
info[_("Options")] = bi->oper_only ? _("Private") : _("None");
|
||||
info[_("Used on")] = Anope::printf(Language::Translate(source.nc, bi->GetChannelCount(), N_("%u channel", "%u channels")), bi->GetChannelCount());
|
||||
info[_("Used on")] = Anope::Format(Language::Translate(source.nc, bi->GetChannelCount(), N_("%u channel", "%u channels")), bi->GetChannelCount());
|
||||
|
||||
FOREACH_MOD(OnBotInfo, (source, bi, ci, info));
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
info.Process(replies);
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
info.SendTo(source);
|
||||
|
||||
if (source.HasPriv("botserv/administration"))
|
||||
{
|
||||
@@ -89,12 +84,7 @@ public:
|
||||
Anope::string disabled = Language::Translate(source.nc, _("Disabled"));
|
||||
|
||||
FOREACH_MOD(OnBotInfo, (source, bi, ci, info));
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
info.Process(replies);
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
info.SendTo(source);
|
||||
}
|
||||
else
|
||||
source.Reply(_("\002%s\002 is not a valid bot or registered channel."), query.c_str());
|
||||
@@ -116,7 +106,7 @@ public:
|
||||
|
||||
const Anope::string GetDesc(CommandSource &source) const override
|
||||
{
|
||||
return Anope::printf(Language::Translate(source.GetAccount(), _("Allows you to see %s information about a channel or a bot")), source.service->nick.c_str());
|
||||
return Anope::Format(Language::Translate(source.GetAccount(), _("Allows you to see %s information about a channel or a bot")), source.service->nick.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+18
-22
@@ -1112,18 +1112,14 @@ class BSKick final
|
||||
|
||||
static void bot_kick(ChannelInfo *ci, User *u, const char *message, ...) ATTR_FORMAT(3, 4)
|
||||
{
|
||||
va_list args;
|
||||
char buf[1024];
|
||||
|
||||
if (!ci || !ci->bi || !ci->c || !u || u->IsProtected() || !ci->c->FindUser(u))
|
||||
return;
|
||||
|
||||
Anope::string fmt = Language::Translate(u, message);
|
||||
va_start(args, message);
|
||||
vsnprintf(buf, sizeof(buf), fmt.c_str(), args);
|
||||
va_end(args);
|
||||
const auto *fmt = Language::Translate(u, message);
|
||||
|
||||
ci->c->Kick(ci->bi, u, Anope::string(buf));
|
||||
Anope::string buf;
|
||||
ANOPE_FORMAT(message, fmt, buf);
|
||||
ci->c->Kick(ci->bi, u, buf);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -1157,7 +1153,7 @@ public:
|
||||
if (kd && kd->badwords)
|
||||
{
|
||||
if (kd->ttb[TTB_BADWORDS])
|
||||
info[_("Bad words kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BADWORDS]);
|
||||
info[_("Bad words kicker")] = Anope::Format("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BADWORDS]);
|
||||
else
|
||||
info[_("Bad words kicker")] = enabled;
|
||||
}
|
||||
@@ -1167,7 +1163,7 @@ public:
|
||||
if (kd && kd->bolds)
|
||||
{
|
||||
if (kd->ttb[TTB_BOLDS])
|
||||
info[_("Bolds kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BOLDS]);
|
||||
info[_("Bolds kicker")] = Anope::Format("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BOLDS]);
|
||||
else
|
||||
info[_("Bolds kicker")] = enabled;
|
||||
}
|
||||
@@ -1177,9 +1173,9 @@ public:
|
||||
if (kd && kd->caps)
|
||||
{
|
||||
if (kd->ttb[TTB_CAPS])
|
||||
info[_("Caps kicker")] = Anope::printf(_("%s (%d kick(s) to ban; minimum %d/%d%%)"), enabled.c_str(), kd->ttb[TTB_CAPS], kd->capsmin, kd->capspercent);
|
||||
info[_("Caps kicker")] = Anope::Format(_("%s (%d kick(s) to ban; minimum %d/%d%%)"), enabled.c_str(), kd->ttb[TTB_CAPS], kd->capsmin, kd->capspercent);
|
||||
else
|
||||
info[_("Caps kicker")] = Anope::printf(_("%s (minimum %d/%d%%)"), enabled.c_str(), kd->capsmin, kd->capspercent);
|
||||
info[_("Caps kicker")] = Anope::Format(_("%s (minimum %d/%d%%)"), enabled.c_str(), kd->capsmin, kd->capspercent);
|
||||
}
|
||||
else
|
||||
info[_("Caps kicker")] = disabled;
|
||||
@@ -1187,7 +1183,7 @@ public:
|
||||
if (kd && kd->colors)
|
||||
{
|
||||
if (kd->ttb[TTB_COLORS])
|
||||
info[_("Colors kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_COLORS]);
|
||||
info[_("Colors kicker")] = Anope::Format(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_COLORS]);
|
||||
else
|
||||
info[_("Colors kicker")] = enabled;
|
||||
}
|
||||
@@ -1197,9 +1193,9 @@ public:
|
||||
if (kd && kd->flood)
|
||||
{
|
||||
if (kd->ttb[TTB_FLOOD])
|
||||
info[_("Flood kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d lines in %ds)"), enabled.c_str(), kd->ttb[TTB_FLOOD], kd->floodlines, kd->floodsecs);
|
||||
info[_("Flood kicker")] = Anope::Format(_("%s (%d kick(s) to ban; %d lines in %ds)"), enabled.c_str(), kd->ttb[TTB_FLOOD], kd->floodlines, kd->floodsecs);
|
||||
else
|
||||
info[_("Flood kicker")] = Anope::printf(_("%s (%d lines in %ds)"), enabled.c_str(), kd->floodlines, kd->floodsecs);
|
||||
info[_("Flood kicker")] = Anope::Format(_("%s (%d lines in %ds)"), enabled.c_str(), kd->floodlines, kd->floodsecs);
|
||||
}
|
||||
else
|
||||
info[_("Flood kicker")] = disabled;
|
||||
@@ -1207,9 +1203,9 @@ public:
|
||||
if (kd && kd->repeat)
|
||||
{
|
||||
if (kd->ttb[TTB_REPEAT])
|
||||
info[_("Repeat kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d times)"), enabled.c_str(), kd->ttb[TTB_REPEAT], kd->repeattimes);
|
||||
info[_("Repeat kicker")] = Anope::Format(_("%s (%d kick(s) to ban; %d times)"), enabled.c_str(), kd->ttb[TTB_REPEAT], kd->repeattimes);
|
||||
else
|
||||
info[_("Repeat kicker")] = Anope::printf(_("%s (%d times)"), enabled.c_str(), kd->repeattimes);
|
||||
info[_("Repeat kicker")] = Anope::Format(_("%s (%d times)"), enabled.c_str(), kd->repeattimes);
|
||||
}
|
||||
else
|
||||
info[_("Repeat kicker")] = disabled;
|
||||
@@ -1217,7 +1213,7 @@ public:
|
||||
if (kd && kd->reverses)
|
||||
{
|
||||
if (kd->ttb[TTB_REVERSES])
|
||||
info[_("Reverses kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_REVERSES]);
|
||||
info[_("Reverses kicker")] = Anope::Format(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_REVERSES]);
|
||||
else
|
||||
info[_("Reverses kicker")] = enabled;
|
||||
}
|
||||
@@ -1227,7 +1223,7 @@ public:
|
||||
if (kd && kd->underlines)
|
||||
{
|
||||
if (kd->ttb[TTB_UNDERLINES])
|
||||
info[_("Underlines kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_UNDERLINES]);
|
||||
info[_("Underlines kicker")] = Anope::Format(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_UNDERLINES]);
|
||||
else
|
||||
info[_("Underlines kicker")] = enabled;
|
||||
}
|
||||
@@ -1237,7 +1233,7 @@ public:
|
||||
if (kd && kd->italics)
|
||||
{
|
||||
if (kd->ttb[TTB_ITALICS])
|
||||
info[_("Italics kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_ITALICS]);
|
||||
info[_("Italics kicker")] = Anope::Format(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_ITALICS]);
|
||||
else
|
||||
info[_("Italics kicker")] = enabled;
|
||||
}
|
||||
@@ -1247,7 +1243,7 @@ public:
|
||||
if (kd && kd->amsgs)
|
||||
{
|
||||
if (kd->ttb[TTB_AMSGS])
|
||||
info[_("AMSG kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_AMSGS]);
|
||||
info[_("AMSG kicker")] = Anope::Format(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_AMSGS]);
|
||||
else
|
||||
info[_("AMSG kicker")] = enabled;
|
||||
}
|
||||
@@ -1369,7 +1365,7 @@ public:
|
||||
BadWords *badwords = ci->GetExt<BadWords>("badwords");
|
||||
|
||||
/* Normalize the buffer */
|
||||
Anope::string nbuf = Anope::NormalizeBuffer(realbuf);
|
||||
Anope::string nbuf = Anope::RemoveFormatting(realbuf);
|
||||
bool casesensitive = Config->GetModule("botserv").Get<bool>("casesensitive");
|
||||
|
||||
/* Normalize can return an empty string if this only contains control codes etc */
|
||||
|
||||
@@ -173,7 +173,7 @@ class CommandBSSetPrivate final
|
||||
public:
|
||||
CommandBSSetPrivate(Module *creator, const Anope::string &sname = "botserv/set/private") : Command(creator, sname, 2, 2)
|
||||
{
|
||||
this->SetDesc(_("Prevent a bot from being assigned by non IRC operators"));
|
||||
this->SetDesc(_("Prevent a bot from being assigned by non Services Operators"));
|
||||
this->SetSyntax(_("\037botname\037 {\037ON|OFF\037}"));
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ public:
|
||||
source.Reply(" ");
|
||||
source.Reply(_(
|
||||
"This option prevents a bot from being assigned to a "
|
||||
"channel by users that aren't IRC Operators."
|
||||
"channel by users that aren't Services Operators."
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ public:
|
||||
ci->Extend<bool>(def.upper());
|
||||
}
|
||||
|
||||
EventReturn OnCanSet(User *u, const ChannelMode *cm) override
|
||||
EventReturn OnCanSet(User *u, Channel *c, const ChannelMode *cm) override
|
||||
{
|
||||
if (Config->GetModule(this).Get<const Anope::string>("nomlock").find(cm->mchar) != Anope::string::npos
|
||||
|| Config->GetModule(this).Get<const Anope::string>("require").find(cm->mchar) != Anope::string::npos)
|
||||
|
||||
@@ -109,7 +109,7 @@ private:
|
||||
entry["Number"] = Anope::ToString(number);
|
||||
entry["Level"] = access->AccessSerialize();
|
||||
entry["Mask"] = access->Mask();
|
||||
entry["By"] = access->creator;
|
||||
entry["Creator"] = access->creator;
|
||||
entry["Last seen"] = timebuf;
|
||||
entry["Description"] = access->description;
|
||||
list.AddEntry(entry);
|
||||
@@ -382,8 +382,6 @@ private:
|
||||
|
||||
source.Reply(_("\002%s\002 not found on %s access list."), mask.c_str(), ci->name.c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void ProcessList(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms, ListFormatter &list)
|
||||
@@ -435,18 +433,10 @@ private:
|
||||
source.Reply(_("No matching entries on %s access list."), ci->name.c_str());
|
||||
else
|
||||
{
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
source.Reply(_("Access list for %s:"), ci->name.c_str());
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
|
||||
list.SendTo(source);
|
||||
source.Reply(_("End of access list"));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void DoList(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms)
|
||||
@@ -459,6 +449,13 @@ private:
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Number")).AddColumn(_("Level")).AddColumn(_("Mask")).AddColumn(_("Description"));
|
||||
list.SetFlexible([](ListFormatter::ListEntry &row)
|
||||
{
|
||||
return row["Description"].empty()
|
||||
? _("{number}: \002{mask}\002 = {level}")
|
||||
: _("{number}: \002{mask}\002 = {level} ({description})");
|
||||
});
|
||||
|
||||
this->ProcessList(source, ci, params, list);
|
||||
}
|
||||
|
||||
@@ -471,7 +468,14 @@ private:
|
||||
}
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Number")).AddColumn(_("Level")).AddColumn(_("Mask")).AddColumn(_("By")).AddColumn(_("Last seen")).AddColumn(_("Description"));
|
||||
list.AddColumn(_("Number")).AddColumn(_("Level")).AddColumn(_("Mask")).AddColumn(_("Creator")).AddColumn(_("Last seen")).AddColumn(_("Description"));
|
||||
list.SetFlexible([](ListFormatter::ListEntry &row)
|
||||
{
|
||||
return row["Description"].empty()
|
||||
? _("{number}: \002{mask}\002 = {level} -- created by {creator}; last seen {last_seen}")
|
||||
: _("{number}: \002{mask}\002 = {level} -- created by {creator}; last seen {last_seen} ({description})");
|
||||
});
|
||||
|
||||
this->ProcessList(source, ci, params, list);
|
||||
}
|
||||
|
||||
@@ -490,8 +494,6 @@ private:
|
||||
bool override = !source.IsFounder(ci);
|
||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to clear the access list";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -559,8 +561,6 @@ public:
|
||||
this->DoClear(source, ci);
|
||||
else
|
||||
this->OnSyntaxError(source, "");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
|
||||
@@ -724,6 +724,7 @@ class CommandCSLevels final
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Name")).AddColumn(_("Level"));
|
||||
list.SetFlexible(_("\002{name}\002 = {level}"));
|
||||
|
||||
const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges();
|
||||
|
||||
@@ -744,11 +745,7 @@ class CommandCSLevels final
|
||||
list.AddEntry(entry);
|
||||
}
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
list.SendTo(source);
|
||||
}
|
||||
|
||||
void DoReset(CommandSource &source, ChannelInfo *ci)
|
||||
@@ -760,7 +757,6 @@ class CommandCSLevels final
|
||||
FOREACH_MOD(OnLevelChange, (source, ci, "ALL", 0));
|
||||
|
||||
source.Reply(_("Access levels for \002%s\002 reset to defaults."), ci->name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -813,8 +809,6 @@ public:
|
||||
this->DoReset(source, ci);
|
||||
else
|
||||
this->OnSyntaxError(source, "");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
|
||||
@@ -825,6 +819,7 @@ public:
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Name")).AddColumn(_("Description"));
|
||||
list.SetFlexible(_("\002{name}\002: {description}"));
|
||||
|
||||
for (const auto &p : PrivilegeManager::GetPrivileges())
|
||||
{
|
||||
@@ -834,11 +829,7 @@ public:
|
||||
list.AddEntry(entry);
|
||||
}
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
list.SendTo(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -141,7 +141,7 @@ class CommandCSAKick final
|
||||
}
|
||||
}
|
||||
|
||||
/* Match against the lastusermask of all nickalias's with equal
|
||||
/* Match against the last mask of all nickalias's with equal
|
||||
* or higher access. - Viper */
|
||||
for (const auto &[_, na2] : *NickAliasList)
|
||||
{
|
||||
@@ -150,7 +150,7 @@ class CommandCSAKick final
|
||||
AccessGroup nc_access = ci->AccessFor(na->nc), u_access = source.AccessFor(ci);
|
||||
if (na->nc && (na->nc == ci->GetFounder() || nc_access >= u_access))
|
||||
{
|
||||
Anope::string buf = na->nick + "!" + na->last_usermask;
|
||||
Anope::string buf = na->nick + "!" + na->last_userhost;
|
||||
if (Anope::Match(buf, mask))
|
||||
{
|
||||
source.Reply(ACCESS_DENIED);
|
||||
@@ -378,14 +378,8 @@ class CommandCSAKick final
|
||||
source.Reply(_("No matching entries on %s autokick list."), ci->name.c_str());
|
||||
else
|
||||
{
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
source.Reply(_("Autokick list for %s:"), ci->name.c_str());
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
|
||||
list.SendTo(source);
|
||||
source.Reply(_("End of autokick list"));
|
||||
}
|
||||
}
|
||||
@@ -400,6 +394,13 @@ class CommandCSAKick final
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("Reason"));
|
||||
list.SetFlexible([](ListFormatter::ListEntry &row)
|
||||
{
|
||||
return row["Reason"].empty()
|
||||
? _("{number}: \002{mask}\002")
|
||||
: _("{number}: \002{mask}\002 ({reason})");
|
||||
});
|
||||
|
||||
this->ProcessList(source, ci, params, list);
|
||||
}
|
||||
|
||||
@@ -413,6 +414,13 @@ class CommandCSAKick final
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("Creator")).AddColumn(_("Created")).AddColumn(_("Last used")).AddColumn(_("Reason"));
|
||||
list.SetFlexible([](ListFormatter::ListEntry &row)
|
||||
{
|
||||
return row["Reason"].empty()
|
||||
? _("{number}: \002{mask}\002 -- added by {creator} on {created}; last used: {last_used}")
|
||||
: _("{number}: \002{mask}\002 -- added by {creator} on {created}; last used: {last_used} ({reason})");
|
||||
});
|
||||
|
||||
this->ProcessList(source, ci, params, list);
|
||||
}
|
||||
|
||||
@@ -491,8 +499,6 @@ public:
|
||||
this->DoClear(source, ci);
|
||||
else
|
||||
this->OnSyntaxError(source, "");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
|
||||
@@ -506,7 +512,7 @@ public:
|
||||
"%s will ban that user from the channel, then kick "
|
||||
"the user."
|
||||
"\n\n"
|
||||
"The \002%s\032ADD\002 command adds the given nick or usermask "
|
||||
"The \002%s\032ADD\002 command adds the given nick or mask "
|
||||
"to the AutoKick list. If a \037reason\037 is given with "
|
||||
"the command, that reason will be used when the user is "
|
||||
"kicked; if not, the default reason is \"User has been "
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
|
||||
static Module *me;
|
||||
|
||||
class TempBan;
|
||||
static std::vector<TempBan *> tempbans;
|
||||
|
||||
class TempBan final
|
||||
: public Timer
|
||||
{
|
||||
@@ -28,6 +31,21 @@ public:
|
||||
, mask(banmask)
|
||||
, mode(mod)
|
||||
{
|
||||
tempbans.push_back(this);
|
||||
}
|
||||
|
||||
~TempBan()
|
||||
{
|
||||
auto it = std::find(tempbans.begin(), tempbans.end(), this);
|
||||
if (it != tempbans.end())
|
||||
tempbans.erase(it);
|
||||
}
|
||||
|
||||
bool Matches(Channel *chan, ChannelMode *cmode, const Anope::string &bmask) const
|
||||
{
|
||||
return chan->name.equals_ci(this->channel)
|
||||
&& cmode->name == this->mode
|
||||
&& bmask == this->mask;
|
||||
}
|
||||
|
||||
void Tick() override
|
||||
@@ -258,10 +276,25 @@ class CSBan final
|
||||
CommandCSBan commandcsban;
|
||||
|
||||
public:
|
||||
CSBan(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandcsban(this)
|
||||
CSBan(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, VENDOR)
|
||||
, commandcsban(this)
|
||||
{
|
||||
me = this;
|
||||
}
|
||||
|
||||
EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *cmode, const Anope::string ¶m) override
|
||||
{
|
||||
for (const auto *tempban : tempbans)
|
||||
{
|
||||
if (tempban->Matches(c, cmode, param))
|
||||
{
|
||||
delete tempban;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return EVENT_CONTINUE;
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_INIT(CSBan)
|
||||
|
||||
@@ -128,6 +128,8 @@ private:
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Number")).AddColumn(_("Creator")).AddColumn(_("Created")).AddColumn(_("Message"));
|
||||
list.SetFlexible(_("{number}: {message} -- created by {creator} at {created}"));
|
||||
|
||||
for (unsigned i = 0; i < (*messages)->size(); ++i)
|
||||
{
|
||||
EntryMsg *msg = (*messages)->at(i);
|
||||
@@ -140,11 +142,7 @@ private:
|
||||
list.AddEntry(entry);
|
||||
}
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
|
||||
list.SendTo(source);
|
||||
source.Reply(_("End of entry message list."));
|
||||
}
|
||||
|
||||
@@ -298,12 +296,21 @@ public:
|
||||
if (!messages)
|
||||
return;
|
||||
|
||||
const auto timestamp = Config->GetModule(this).Get<bool>("timestamp", "yes");
|
||||
for (const auto &message : *(*messages))
|
||||
{
|
||||
Anope::map<Anope::string> tags;
|
||||
if (timestamp)
|
||||
{
|
||||
char timebuf[32];
|
||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S.000Z", gmtime(&message->when));
|
||||
tags["time"] = timebuf;
|
||||
}
|
||||
|
||||
if (u->ShouldPrivmsg())
|
||||
IRCD->SendContextPrivmsg(c->ci->WhoSends(), u, c, message->message);
|
||||
IRCD->SendContextPrivmsg(c->ci->WhoSends(), u, c, message->message, tags);
|
||||
else
|
||||
IRCD->SendContextNotice(c->ci->WhoSends(), u, c, message->message);
|
||||
IRCD->SendContextNotice(c->ci->WhoSends(), u, c, message->message, tags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,8 +309,13 @@ class CommandCSFlags final
|
||||
}
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
|
||||
list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("Flags")).AddColumn(_("Creator")).AddColumn(_("Created")).AddColumn(_("Description"));
|
||||
list.SetFlexible([](ListFormatter::ListEntry &row)
|
||||
{
|
||||
return row["Description"].empty()
|
||||
? _("{number}: \002{mask}\002 = {flags} -- added by {creator} at {created}")
|
||||
: _("{number}: \002{mask}\002 = {flags} -- added by {creator} at {created} ({description})");
|
||||
});
|
||||
|
||||
unsigned count = 0;
|
||||
for (unsigned i = 0, end = ci->GetAccessCount(); i < end; ++i)
|
||||
@@ -348,12 +353,8 @@ class CommandCSFlags final
|
||||
source.Reply(_("No matching entries on %s access list."), ci->name.c_str());
|
||||
else
|
||||
{
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
source.Reply(_("Flags list for %s"), ci->name.c_str());
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
list.SendTo(source);
|
||||
if (count == ci->GetAccessCount())
|
||||
source.Reply(_("End of access list."));
|
||||
else
|
||||
@@ -376,8 +377,6 @@ class CommandCSFlags final
|
||||
bool override = !source.IsFounder(ci);
|
||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to clear the access list";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@@ -62,12 +62,7 @@ public:
|
||||
}
|
||||
|
||||
FOREACH_MOD(OnChanInfo, (source, ci, info, show_all));
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
info.Process(replies);
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
info.SendTo(source);
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
|
||||
|
||||
@@ -76,6 +76,12 @@ public:
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Name")).AddColumn(_("Description"));
|
||||
list.SetFlexible([](ListFormatter::ListEntry &row)
|
||||
{
|
||||
return row["Description"].empty()
|
||||
? _("\002{name}\002")
|
||||
: _("\002{name}\002 ({description})");
|
||||
});
|
||||
|
||||
Anope::map<ChannelInfo *> ordered_map;
|
||||
for (const auto &[cname, ci] : *RegisteredChannelList)
|
||||
@@ -122,12 +128,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
|
||||
list.SendTo(source);
|
||||
source.Reply(_("End of list - %d/%d matches shown."), nchans > listmax ? listmax : nchans, nchans);
|
||||
}
|
||||
|
||||
@@ -228,8 +229,6 @@ public:
|
||||
}
|
||||
else
|
||||
this->OnSyntaxError(source, "PRIVATE");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &) override
|
||||
|
||||
@@ -138,7 +138,8 @@ public:
|
||||
else
|
||||
{
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Number")).AddColumn(_("Service")).AddColumn(_("Command")).AddColumn(_("Method")).AddColumn("");
|
||||
list.AddColumn(_("Number")).AddColumn(_("Service")).AddColumn(_("Command")).AddColumn(_("Method"));
|
||||
list.SetFlexible(_("{number}: {command} on {service}: {method}"));
|
||||
|
||||
for (unsigned i = 0; i < (*ls)->size(); ++i)
|
||||
{
|
||||
@@ -147,19 +148,13 @@ public:
|
||||
ListFormatter::ListEntry entry;
|
||||
entry["Number"] = Anope::ToString(i + 1);
|
||||
entry["Service"] = log->command_service;
|
||||
entry["Command"] = !log->command_name.empty() ? log->command_name : log->service_name;
|
||||
entry["Method"] = log->method;
|
||||
entry[""] = log->extra;
|
||||
entry["Command"] = !log->command_name.empty() ? log->command_name.upper() : log->service_name;
|
||||
entry["Method"] = log->method + (log->extra.empty() ? "" : " ") + log->extra;
|
||||
list.AddEntry(entry);
|
||||
}
|
||||
|
||||
source.Reply(_("Log list for %s:"), ci->name.c_str());
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
list.SendTo(source);
|
||||
}
|
||||
}
|
||||
else if (params.size() > 2)
|
||||
|
||||
@@ -288,7 +288,7 @@ class CommandCSMode final
|
||||
for (auto *ml : mlocks)
|
||||
{
|
||||
ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name);
|
||||
if (cm && cm->CanSet(source.GetUser()))
|
||||
if (cm && cm->CanSet(source.GetUser(), ci->c))
|
||||
modelocks->RemoveMLock(cm, ml->set, ml->param);
|
||||
}
|
||||
}
|
||||
@@ -320,7 +320,7 @@ class CommandCSMode final
|
||||
source.Reply(_("Unknown mode character %c ignored."), mode);
|
||||
break;
|
||||
}
|
||||
else if (u && !cm->CanSet(u))
|
||||
else if (u && !cm->CanSet(u, ci->c))
|
||||
{
|
||||
source.Reply(_("You may not (un)lock mode %c."), mode);
|
||||
break;
|
||||
@@ -412,7 +412,7 @@ class CommandCSMode final
|
||||
source.Reply(_("Unknown mode character %c ignored."), mode);
|
||||
break;
|
||||
}
|
||||
else if (u && !cm->CanSet(u))
|
||||
else if (u && !cm->CanSet(u, ci->c))
|
||||
{
|
||||
source.Reply(_("You may not (un)lock mode %c."), mode);
|
||||
break;
|
||||
@@ -450,6 +450,12 @@ class CommandCSMode final
|
||||
{
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Mode")).AddColumn(_("Param")).AddColumn(_("Creator")).AddColumn(_("Created"));
|
||||
list.SetFlexible([](ListFormatter::ListEntry &row)
|
||||
{
|
||||
return row["Param"].empty()
|
||||
? _("{mode} -- created by {creator} on {created}")
|
||||
: _("{mode} {param} -- created by {creator} on {created}");
|
||||
});
|
||||
|
||||
for (auto *ml : mlocks)
|
||||
{
|
||||
@@ -458,7 +464,7 @@ class CommandCSMode final
|
||||
continue;
|
||||
|
||||
ListFormatter::ListEntry entry;
|
||||
entry["Mode"] = Anope::printf("%c%c", ml->set ? '+' : '-', cm->mchar);
|
||||
entry["Mode"] = Anope::Format("%c%c", ml->set ? '+' : '-', cm->mchar);
|
||||
entry["Param"] = ml->param;
|
||||
entry["Creator"] = ml->setter;
|
||||
entry["Created"] = Anope::strftime(ml->created, NULL, true);
|
||||
@@ -466,12 +472,7 @@ class CommandCSMode final
|
||||
}
|
||||
|
||||
source.Reply(_("Mode locks for %s:"), ci->name.c_str());
|
||||
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
list.SendTo(source);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -508,7 +509,7 @@ class CommandCSMode final
|
||||
{
|
||||
ChannelMode *cm = ModeManager::GetChannelModes()[j];
|
||||
|
||||
if (!u || cm->CanSet(u) || can_override)
|
||||
if (!u || cm->CanSet(u, ci->c) || can_override)
|
||||
{
|
||||
if (cm->type == MODE_REGULAR || (!adding && cm->type == MODE_PARAM))
|
||||
{
|
||||
@@ -524,7 +525,7 @@ class CommandCSMode final
|
||||
if (adding == -1)
|
||||
break;
|
||||
ChannelMode *cm = ModeManager::FindChannelModeByChar(mode);
|
||||
if (!cm || (u && !cm->CanSet(u) && !can_override))
|
||||
if (!cm || (u && !cm->CanSet(u, ci->c) && !can_override))
|
||||
continue;
|
||||
switch (cm->type)
|
||||
{
|
||||
@@ -917,9 +918,9 @@ public:
|
||||
if (!m.second.empty())
|
||||
{
|
||||
if (m.first)
|
||||
return Anope::printf(Language::Translate(source.GetAccount(), _("Gives you or the specified nick %s status on a channel")), m.second.c_str());
|
||||
return Anope::Format(Language::Translate(source.GetAccount(), _("Gives you or the specified nick %s status on a channel")), m.second.c_str());
|
||||
else
|
||||
return Anope::printf(Language::Translate(source.GetAccount(), _("Removes %s status from you or the specified nick on a channel")), m.second.c_str());
|
||||
return Anope::Format(Language::Translate(source.GetAccount(), _("Removes %s status from you or the specified nick on a channel")), m.second.c_str());
|
||||
}
|
||||
else
|
||||
return "";
|
||||
|
||||
@@ -16,7 +16,6 @@ enum TypeInfo
|
||||
NEW, NICK_TO, NICK_FROM, JOIN, PART, QUIT, KICK
|
||||
};
|
||||
|
||||
static bool simple;
|
||||
struct SeenInfo;
|
||||
static SeenInfo *FindInfo(const Anope::string &nick);
|
||||
typedef Anope::unordered_map<SeenInfo *> database_map;
|
||||
@@ -53,12 +52,54 @@ struct SeenInfoType final
|
||||
{
|
||||
}
|
||||
|
||||
static Anope::string TypeToString(TypeInfo ti)
|
||||
{
|
||||
switch (ti)
|
||||
{
|
||||
case NEW:
|
||||
return "NEW";
|
||||
case NICK_TO:
|
||||
return "NICK_TO";
|
||||
case NICK_FROM:
|
||||
return "NICK_FROM";
|
||||
case JOIN:
|
||||
return "JOIN";
|
||||
case PART:
|
||||
return "PART";
|
||||
case QUIT:
|
||||
return "QUIT";
|
||||
case KICK:
|
||||
return "KICK";
|
||||
}
|
||||
return ""; // Should never happen.
|
||||
}
|
||||
|
||||
static TypeInfo StringToType(const Anope::string &ti)
|
||||
{
|
||||
if (ti.equals_ci("NEW") || ti.equals_ci("0"))
|
||||
return NEW;
|
||||
if (ti.equals_ci("NICK_TO") || ti.equals_ci("1"))
|
||||
return NICK_TO;
|
||||
if (ti.equals_ci("NICK_FROM") || ti.equals_ci("2"))
|
||||
return NICK_FROM;
|
||||
if (ti.equals_ci("JOIN") || ti.equals_ci("3"))
|
||||
return JOIN;
|
||||
if (ti.equals_ci("PART") || ti.equals_ci("4"))
|
||||
return PART;
|
||||
if (ti.equals_ci("QUIT") || ti.equals_ci("5"))
|
||||
return QUIT;
|
||||
if (ti.equals_ci("KICK") || ti.equals_ci("6"))
|
||||
return KICK;
|
||||
|
||||
return NEW; // Should never happen.
|
||||
}
|
||||
|
||||
void Serialize(Serializable *obj, Serialize::Data &data) const override
|
||||
{
|
||||
const auto *s = static_cast<const SeenInfo *>(obj);
|
||||
data.Store("nick", s->nick);
|
||||
data.Store("vhost", s->vhost);
|
||||
data.Store("type", s->type);
|
||||
data.Store("type", TypeToString(s->type));
|
||||
data.Store("nick2", s->nick2);
|
||||
data.Store("channel", s->channel);
|
||||
data.Store("message", s->message);
|
||||
@@ -84,9 +125,9 @@ struct SeenInfoType final
|
||||
|
||||
s->nick = snick;
|
||||
data["vhost"] >> s->vhost;
|
||||
unsigned int n;
|
||||
Anope::string n;
|
||||
data["type"] >> n;
|
||||
s->type = static_cast<TypeInfo>(n);
|
||||
s->type = StringToType(n);
|
||||
data["nick2"] >> s->nick2;
|
||||
data["channel"] >> s->channel;
|
||||
data["message"] >> s->message;
|
||||
@@ -199,76 +240,6 @@ public:
|
||||
class CommandSeen final
|
||||
: public Command
|
||||
{
|
||||
static void SimpleSeen(CommandSource &source, const std::vector<Anope::string> ¶ms)
|
||||
{
|
||||
if (!source.c || !source.c->ci)
|
||||
{
|
||||
if (source.IsOper())
|
||||
source.Reply("Seen in simple mode is designed as a fantasy command only!");
|
||||
return;
|
||||
}
|
||||
|
||||
BotInfo *bi = BotInfo::Find(params[0], true);
|
||||
if (bi)
|
||||
{
|
||||
if (bi == source.c->ci->bi)
|
||||
source.Reply(_("You found me, %s!"), source.GetNick().c_str());
|
||||
else
|
||||
source.Reply(_("%s is a network service."), bi->nick.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
NickAlias *na = NickAlias::Find(params[0]);
|
||||
if (!na)
|
||||
{
|
||||
source.Reply(_("I don't know who %s is."), params[0].c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (source.GetAccount() == na->nc)
|
||||
{
|
||||
source.Reply(_("Looking for yourself, eh %s?"), source.GetNick().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
User *target = User::Find(params[0], true);
|
||||
|
||||
if (target && source.c->FindUser(target))
|
||||
{
|
||||
source.Reply(_("%s is on the channel right now!"), target->nick.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &[_, uc] : source.c->users)
|
||||
{
|
||||
User *u = uc->user;
|
||||
|
||||
if (u->Account() == na->nc)
|
||||
{
|
||||
source.Reply(_("%s is on the channel right now (as %s)!"), params[0].c_str(), u->nick.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AccessGroup ag = source.c->ci->AccessFor(na->nc);
|
||||
time_t last = 0;
|
||||
for (const auto &p : ag.paths)
|
||||
{
|
||||
if (p.empty())
|
||||
continue;
|
||||
|
||||
ChanAccess *a = p[p.size() - 1];
|
||||
|
||||
if (a->GetAccount() == na->nc && a->last_seen > last)
|
||||
last = a->last_seen;
|
||||
}
|
||||
|
||||
if (last > Anope::CurTime || !last)
|
||||
source.Reply(_("I've never seen %s on this channel."), na->nick.c_str());
|
||||
else
|
||||
source.Reply(_("%s was last seen here %s ago."), na->nick.c_str(), Anope::Duration(Anope::CurTime - last, source.GetAccount()).c_str());
|
||||
}
|
||||
|
||||
public:
|
||||
CommandSeen(Module *creator) : Command(creator, "chanserv/seen", 1, 2)
|
||||
{
|
||||
@@ -281,9 +252,6 @@ public:
|
||||
{
|
||||
const Anope::string &target = params[0];
|
||||
|
||||
if (simple)
|
||||
return this->SimpleSeen(source, params);
|
||||
|
||||
if (target.length() > IRCD->MaxNick)
|
||||
{
|
||||
source.Reply(_("Nick too long, max length is %zu characters."), IRCD->MaxNick);
|
||||
@@ -314,7 +282,7 @@ public:
|
||||
if (u2)
|
||||
onlinestatus = ".";
|
||||
else
|
||||
onlinestatus = Anope::printf(Language::Translate(source.nc, _(" but %s mysteriously dematerialized.")), target.c_str());
|
||||
onlinestatus = Anope::Format(Language::Translate(source.nc, _(" but %s mysteriously dematerialized.")), target.c_str());
|
||||
|
||||
Anope::string timebuf = Anope::Duration(Anope::CurTime - info->last, source.nc);
|
||||
Anope::string timebuf2 = Anope::strftime(info->last, source.nc, true);
|
||||
@@ -328,9 +296,9 @@ public:
|
||||
{
|
||||
u2 = User::Find(info->nick2, true);
|
||||
if (u2)
|
||||
onlinestatus = Anope::printf(Language::Translate(source.nc, _(". %s is still online.")), u2->nick.c_str());
|
||||
onlinestatus = Anope::Format(Language::Translate(source.nc, _(". %s is still online.")), u2->nick.c_str());
|
||||
else
|
||||
onlinestatus = Anope::printf(Language::Translate(source.nc, _(", but %s mysteriously dematerialized.")), info->nick2.c_str());
|
||||
onlinestatus = Anope::Format(Language::Translate(source.nc, _(", but %s mysteriously dematerialized.")), info->nick2.c_str());
|
||||
|
||||
source.Reply(_("%s (%s) was last seen changing nick to %s %s ago%s"),
|
||||
target.c_str(), info->vhost.c_str(), info->nick2.c_str(), timebuf.c_str(), onlinestatus.c_str());
|
||||
@@ -401,17 +369,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void OnReload(Configuration::Conf &conf) override
|
||||
{
|
||||
simple = conf.GetModule(this).Get<bool>("simple");
|
||||
}
|
||||
|
||||
void OnExpireTick() override
|
||||
{
|
||||
size_t previous_size = database.size();
|
||||
time_t purgetime = Config->GetModule(this).Get<time_t>("purgetime");
|
||||
auto purgetime = Config->GetModule(this).Get<time_t>("purgetime", "90d");
|
||||
if (!purgetime)
|
||||
purgetime = Anope::DoTime("30d");
|
||||
return;
|
||||
|
||||
auto previous_size = database.size();
|
||||
for (database_map::iterator it = database.begin(), it_end = database.end(); it != it_end;)
|
||||
{
|
||||
database_map::iterator cur = it;
|
||||
@@ -461,7 +425,7 @@ public:
|
||||
private:
|
||||
static void UpdateUser(const User *u, const TypeInfo Type, const Anope::string &nick, const Anope::string &nick2, const Anope::string &channel, const Anope::string &message)
|
||||
{
|
||||
if (simple || !u->server->IsSynced())
|
||||
if (!u->server->IsSynced())
|
||||
return;
|
||||
|
||||
SeenInfo *&info = database[nick];
|
||||
|
||||
@@ -253,8 +253,6 @@ public:
|
||||
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to unset the description";
|
||||
source.Reply(_("Description of %s unset."), ci->name.c_str());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &) override
|
||||
@@ -331,8 +329,6 @@ public:
|
||||
ci->SetFounder(nc);
|
||||
|
||||
source.Reply(_("Founder of \002%s\002 changed to \002%s\002."), ci->name.c_str(), na->nick.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &) override
|
||||
@@ -465,8 +461,6 @@ public:
|
||||
}
|
||||
else
|
||||
this->OnSyntaxError(source, "PEACE");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &) override
|
||||
@@ -1004,8 +998,6 @@ public:
|
||||
source.Reply(_("Successor for \002%s\002 changed to \002%s\002."), ci->name.c_str(), nc->display.c_str());
|
||||
else
|
||||
source.Reply(_("Successor for \002%s\002 unset."), ci->name.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &) override
|
||||
@@ -1084,8 +1076,6 @@ public:
|
||||
}
|
||||
else
|
||||
this->OnSyntaxError(source, "NOEXPIRE");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &) override
|
||||
@@ -1333,7 +1323,7 @@ public:
|
||||
if (persist.HasExt(ci))
|
||||
info.AddOption(_("Persistent"));
|
||||
if (noexpire.HasExt(ci))
|
||||
info.AddOption(_("No expire"));
|
||||
info.AddOption(_("No expiry"));
|
||||
if (keep_modes.HasExt(ci))
|
||||
info.AddOption(_("Keep modes"));
|
||||
if (noautoop.HasExt(ci))
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
static Module *me;
|
||||
|
||||
static Anope::map<Anope::string> descriptions;
|
||||
static Anope::map<uint16_t> numerics;
|
||||
static Anope::map<unsigned> numerics;
|
||||
|
||||
struct CSMiscData;
|
||||
static Anope::map<ExtensibleItem<CSMiscData> *> items;
|
||||
@@ -171,6 +171,7 @@ public:
|
||||
if (descriptions.count(source.command))
|
||||
{
|
||||
this->SendSyntax(source);
|
||||
source.Reply(" ");
|
||||
source.Reply("%s", Language::Translate(source.nc, descriptions[source.command].c_str()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -195,8 +195,6 @@ public:
|
||||
source.Reply(_("Channel \002%s\002 is now released."), ci->name.c_str());
|
||||
|
||||
FOREACH_MOD(OnChanUnsuspend, (ci));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
|
||||
|
||||
@@ -132,14 +132,18 @@ class CommandCSTopic final
|
||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << (!topic.empty() ? "to change the topic to: " : "to unset the topic") << (!topic.empty() ? topic : "");
|
||||
}
|
||||
|
||||
void Append(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms)
|
||||
void Combine(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms, bool append)
|
||||
{
|
||||
const Anope::string &topic = params[2];
|
||||
|
||||
Anope::string new_topic;
|
||||
if (!ci->c->topic.empty())
|
||||
{
|
||||
new_topic = ci->c->topic + " " + topic;
|
||||
if (append)
|
||||
new_topic = ci->c->topic + " " + topic;
|
||||
else
|
||||
new_topic = topic + " " + ci->c->topic;
|
||||
|
||||
ci->last_topic.clear();
|
||||
}
|
||||
else
|
||||
@@ -155,6 +159,7 @@ public:
|
||||
this->SetDesc(_("Manipulate the topic of the specified channel"));
|
||||
this->SetSyntax(_("\037channel\037 [SET] [\037topic\037]"));
|
||||
this->SetSyntax(_("\037channel\037 APPEND \037topic\037"));
|
||||
this->SetSyntax(_("\037channel\037 PREPEND \037topic\037"));
|
||||
this->SetSyntax(_("\037channel\037 [UNLOCK|LOCK]"));
|
||||
}
|
||||
|
||||
@@ -174,7 +179,9 @@ public:
|
||||
else if (!ci->c)
|
||||
source.Reply(CHAN_X_NOT_IN_USE, ci->name.c_str());
|
||||
else if (subcmd.equals_ci("APPEND") && params.size() > 2)
|
||||
this->Append(source, ci, params);
|
||||
this->Combine(source, ci, params, true);
|
||||
else if (subcmd.equals_ci("PREPEND") && params.size() > 2)
|
||||
this->Combine(source, ci, params, false);
|
||||
else
|
||||
{
|
||||
Anope::string topic;
|
||||
|
||||
@@ -397,6 +397,12 @@ private:
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("Description"));
|
||||
list.SetFlexible([](ListFormatter::ListEntry &row)
|
||||
{
|
||||
return row["Description"].empty()
|
||||
? _("{number}: \002{mask}\002")
|
||||
: _("{number}: \002{mask}\002 ({description})");
|
||||
});
|
||||
|
||||
if (!nick.empty() && nick.find_first_not_of("1234567890,-") == Anope::string::npos)
|
||||
{
|
||||
@@ -453,12 +459,8 @@ private:
|
||||
source.Reply(_("No matching entries on %s access list."), ci->name.c_str());
|
||||
else
|
||||
{
|
||||
std::vector<Anope::string> replies;
|
||||
list.Process(replies);
|
||||
|
||||
source.Reply(_("%s list for %s"), source.command.nobreak().c_str(), ci->name.c_str());
|
||||
for (const auto &reply : replies)
|
||||
source.Reply(reply);
|
||||
list.SendTo(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,7 +513,7 @@ public:
|
||||
|
||||
const Anope::string GetDesc(CommandSource &source) const override
|
||||
{
|
||||
return Anope::printf(Language::Translate(source.GetAccount(), _("Modify the list of %s users")), source.command.nobreak().c_str());
|
||||
return Anope::Format(Language::Translate(source.GetAccount(), _("Modify the list of %s users")), source.command.nobreak().c_str());
|
||||
}
|
||||
|
||||
void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) override
|
||||
|
||||
@@ -134,9 +134,9 @@ struct UserData final
|
||||
Anope::string info_adder;
|
||||
Anope::string info_message;
|
||||
time_t info_ts = 0;
|
||||
Anope::string last_mask;
|
||||
Anope::string last_quit;
|
||||
Anope::string last_real_mask;
|
||||
Anope::string last_userhost;
|
||||
Anope::string last_userhost_real;
|
||||
bool noexpire = false;
|
||||
bool protect = false;
|
||||
std::optional<time_t> protectafter;
|
||||
@@ -432,7 +432,7 @@ private:
|
||||
// crypt3-md5 Converted to enc_posix
|
||||
// crypt3-sha2-256 Converted to enc_posix
|
||||
// crypt3-sha2-512 Converted to enc_posix
|
||||
// ircservices Converted to enc_old
|
||||
// ircservices NO
|
||||
// pbkdf2 NO
|
||||
// pbkdf2v2 NO
|
||||
// rawmd5 Converted to enc_md5
|
||||
@@ -443,10 +443,9 @@ private:
|
||||
if (pass.compare(0, 18, "$anope$enc_sha256$", 18) == 0)
|
||||
{
|
||||
auto sep = pass.find('$', 18);
|
||||
Anope::string iv, pass;
|
||||
Anope::B64Decode(pass.substr(18, sep - 18), iv);
|
||||
Anope::B64Decode(pass.substr(sep + 1), pass);
|
||||
nc->pass = "sha256:" + Anope::Hex(pass) + ":" + Anope::Hex(iv);
|
||||
auto iv = Anope::B64Decode(pass.substr(18, sep - 18));
|
||||
auto pw = Anope::B64Decode(pass.substr(sep + 1));
|
||||
nc->pass = "sha256:" + Anope::Hex(pw) + ":" + Anope::Hex(iv);
|
||||
}
|
||||
|
||||
else if (pass.compare(0, 9, "$argon2d$", 9) == 0)
|
||||
@@ -460,14 +459,10 @@ private:
|
||||
|
||||
else if (pass.compare(0, 8, "$base64$", 8) == 0)
|
||||
{
|
||||
Anope::string rawpass;
|
||||
Anope::B64Decode(pass.substr(8), rawpass);
|
||||
auto rawpass = Anope::B64Decode(pass.substr(8));
|
||||
Anope::Encrypt(rawpass, nc->pass);
|
||||
}
|
||||
|
||||
else if (pass.compare(0, 13, "$ircservices$", 13) == 0)
|
||||
nc->pass = "oldmd5:" + pass.substr(13);
|
||||
|
||||
else if (pass.compare(0, 8, "$rawmd5$", 8) == 0)
|
||||
nc->pass = "md5:" + pass.substr(8);
|
||||
|
||||
@@ -512,7 +507,7 @@ private:
|
||||
|
||||
if (!forbid_service)
|
||||
{
|
||||
Log(this) << "Unable to convert forbidden email " << email << " as os_forbid is not loaded";
|
||||
Log(this) << "Unable to convert forbidden email address " << email << " as os_forbid is not loaded";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -625,6 +620,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
auto originalflags = flags;
|
||||
Anope::string accessflags;
|
||||
ApplyAccess(flags, 'A', accessflags, { "ACCESS_LIST" });
|
||||
ApplyAccess(flags, 'a', accessflags, { "AUTOPROTECT", "PROTECT", "PROTECTME" });
|
||||
@@ -647,7 +643,7 @@ private:
|
||||
auto *access = accessprov->Create();
|
||||
access->SetMask(mask, ci);
|
||||
access->creator = setter;
|
||||
access->description = "Imported from Atheme";
|
||||
access->description = "Imported from Atheme: " + flags;
|
||||
access->last_seen = modifiedtime;
|
||||
access->created = modifiedtime;
|
||||
access->AccessUnserialize(accessflags);
|
||||
@@ -805,7 +801,7 @@ private:
|
||||
|
||||
auto *ni = news_service->CreateNewsItem();
|
||||
ni->type = NEWS_LOGON;
|
||||
ni->text = Anope::printf("[%s] %s", subject.c_str(), body.c_str());
|
||||
ni->text = Anope::Format("[%s] %s", subject.c_str(), body.c_str());
|
||||
ni->who = setter;
|
||||
ni->time = ts;
|
||||
news_service->AddNewsItem(ni);
|
||||
@@ -831,7 +827,7 @@ private:
|
||||
|
||||
auto *ni = news_service->CreateNewsItem();
|
||||
ni->type = NEWS_OPER;
|
||||
ni->text = Anope::printf("[%s] %s", subject.c_str(), body.c_str());
|
||||
ni->text = Anope::Format("[%s] %s", subject.c_str(), body.c_str());
|
||||
ni->who = setter;
|
||||
ni->time = ts;
|
||||
news_service->AddNewsItem(ni);
|
||||
@@ -1145,9 +1141,9 @@ private:
|
||||
else if (key == "private:freeze:timestamp")
|
||||
data->suspend_ts = Anope::Convert<time_t>(value, 0);
|
||||
else if (key == "private:host:actual")
|
||||
data->last_real_mask = value;
|
||||
data->last_userhost_real = value;
|
||||
else if (key == "private:host:vhost")
|
||||
data->last_mask = value;
|
||||
data->last_userhost = value;
|
||||
else if (key == "private:lastquit:message")
|
||||
data->last_quit = value;
|
||||
else if (key == "private:loginfail:failnum")
|
||||
@@ -1313,14 +1309,14 @@ private:
|
||||
auto *data = userdata.Get(nc);
|
||||
if (data)
|
||||
{
|
||||
if (!data->last_mask.empty())
|
||||
na->last_usermask = data->last_mask;
|
||||
if (!data->last_userhost.empty())
|
||||
na->last_userhost = data->last_userhost;
|
||||
|
||||
if (!data->last_quit.empty())
|
||||
na->last_quit = data->last_quit;
|
||||
|
||||
if (!data->last_real_mask.empty())
|
||||
na->last_realhost = data->last_real_mask;
|
||||
if (!data->last_userhost_real.empty())
|
||||
na->last_userhost_real = data->last_userhost_real;
|
||||
|
||||
if (data->noexpire)
|
||||
na->Extend<bool>("NS_NO_EXPIRE");
|
||||
|
||||
@@ -11,31 +11,6 @@
|
||||
|
||||
#include "module.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
class SaveData final
|
||||
: public Serialize::Data
|
||||
{
|
||||
public:
|
||||
Anope::string last;
|
||||
std::fstream *fs = nullptr;
|
||||
|
||||
std::iostream &operator[](const Anope::string &key) override
|
||||
{
|
||||
if (key != last)
|
||||
{
|
||||
*fs << "\nDATA " << key << " ";
|
||||
last = key;
|
||||
}
|
||||
|
||||
return *fs;
|
||||
}
|
||||
};
|
||||
|
||||
class LoadData final
|
||||
: public Serialize::Data
|
||||
{
|
||||
@@ -97,133 +72,14 @@ public:
|
||||
|
||||
class DBFlatFile final
|
||||
: public Module
|
||||
, public Pipe
|
||||
{
|
||||
/* Day the last backup was on */
|
||||
int last_day = 0;
|
||||
private:
|
||||
bool loaded = false;
|
||||
|
||||
int child_pid = -1;
|
||||
|
||||
void BackupDatabase()
|
||||
{
|
||||
tm *tm = localtime(&Anope::CurTime);
|
||||
|
||||
if (tm->tm_mday != last_day)
|
||||
{
|
||||
last_day = tm->tm_mday;
|
||||
|
||||
std::set<Anope::string> dbs;
|
||||
dbs.insert(Config->GetModule(this).Get<const Anope::string>("database", "anope.db"));
|
||||
|
||||
for (const auto &type_order : Serialize::Type::GetTypeOrder())
|
||||
{
|
||||
Serialize::Type *stype = Serialize::Type::Find(type_order);
|
||||
|
||||
if (stype && stype->GetOwner())
|
||||
dbs.insert("module_" + stype->GetOwner()->name + ".db");
|
||||
}
|
||||
|
||||
const auto backupdir = Anope::ExpandData("backups");
|
||||
for (const auto &db : dbs)
|
||||
{
|
||||
const auto oldname = Anope::ExpandData(db);
|
||||
const auto basename = Anope::Expand(backupdir, db + "-");
|
||||
const auto newname = Anope::printf("%s%04i-%02i-%02i", basename.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||
|
||||
/* Backup already exists or no database to backup */
|
||||
if (Anope::IsFile(newname) || !Anope::IsFile(oldname))
|
||||
continue;
|
||||
|
||||
Log(LOG_DEBUG) << "db_flatfile: Attempting to rename " << db << " to " << newname;
|
||||
if (rename(oldname.c_str(), newname.c_str()))
|
||||
{
|
||||
Anope::string err = Anope::LastError();
|
||||
Log(this) << "Unable to back up database " << db << " (" << err << ")!";
|
||||
|
||||
if (!Config->GetModule(this).Get<bool>("nobackupokay"))
|
||||
{
|
||||
Anope::Quitting = true;
|
||||
Anope::QuitReason = "Unable to back up database " + db + " (" + err + ")";
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto keepbackups = Config->GetModule(this).Get<unsigned>("keepbackups", "7");
|
||||
if (!keepbackups)
|
||||
continue;
|
||||
|
||||
std::error_code ec;
|
||||
std::set<Anope::string> old_backups;
|
||||
for (const auto &entry : std::filesystem::directory_iterator(backupdir.str(), ec))
|
||||
{
|
||||
Anope::string entryname = entry.path().string();
|
||||
if (entryname.compare(0, basename.length(), basename) != 0)
|
||||
continue;
|
||||
|
||||
old_backups.insert(entryname);
|
||||
if (old_backups.size() <= keepbackups)
|
||||
continue;
|
||||
|
||||
Log(LOG_DEBUG) << "Deleting expired backup " << *old_backups.begin();
|
||||
if (!std::filesystem::remove(old_backups.begin()->str(), ec))
|
||||
{
|
||||
Log(this) << "Failed to delete expired backup " << *old_backups.begin() << ": " << ec.message();
|
||||
continue;
|
||||
}
|
||||
old_backups.erase(old_backups.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DBFlatFile(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR)
|
||||
DBFlatFile(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, DATABASE | DEPRECATED | VENDOR)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void OnRestart() override
|
||||
{
|
||||
OnShutdown();
|
||||
}
|
||||
|
||||
void OnShutdown() override
|
||||
{
|
||||
if (child_pid > -1)
|
||||
{
|
||||
Log(this) << "Waiting for child to exit...";
|
||||
|
||||
int status;
|
||||
waitpid(child_pid, &status, 0);
|
||||
|
||||
Log(this) << "Done";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void OnNotify() override
|
||||
{
|
||||
char buf[512];
|
||||
int i = this->Read(buf, sizeof(buf) - 1);
|
||||
if (i <= 0)
|
||||
return;
|
||||
buf[i] = 0;
|
||||
|
||||
child_pid = -1;
|
||||
|
||||
if (!*buf)
|
||||
{
|
||||
Log(this) << "Finished saving databases";
|
||||
return;
|
||||
}
|
||||
|
||||
Log(this) << "Error saving databases: " << buf;
|
||||
|
||||
if (!Config->GetModule(this).Get<bool>("nobackupokay"))
|
||||
Anope::Quitting = true;
|
||||
}
|
||||
|
||||
EventReturn OnLoadDatabase() override
|
||||
@@ -270,110 +126,6 @@ public:
|
||||
return EVENT_STOP;
|
||||
}
|
||||
|
||||
|
||||
void OnSaveDatabase() override
|
||||
{
|
||||
if (child_pid > -1)
|
||||
{
|
||||
Log(this) << "Database save is already in progress!";
|
||||
return;
|
||||
}
|
||||
|
||||
BackupDatabase();
|
||||
|
||||
int i = -1;
|
||||
#ifndef _WIN32
|
||||
if (!Anope::Quitting && Config->GetModule(this).Get<bool>("fork"))
|
||||
{
|
||||
i = fork();
|
||||
if (i > 0)
|
||||
{
|
||||
child_pid = i;
|
||||
return;
|
||||
}
|
||||
else if (i < 0)
|
||||
Log(this) << "Unable to fork for database save";
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
std::map<Module *, std::fstream *> databases;
|
||||
|
||||
/* First open the databases of all of the registered types. This way, if we have a type with 0 objects, that database will be properly cleared */
|
||||
for (const auto &[_, s_type] : Serialize::Type::GetTypes())
|
||||
{
|
||||
if (databases[s_type->GetOwner()])
|
||||
continue;
|
||||
|
||||
Anope::string db_name;
|
||||
if (s_type->GetOwner())
|
||||
db_name = Anope::ExpandData("module_" + s_type->GetOwner()->name + ".db");
|
||||
else
|
||||
db_name = Anope::ExpandData(Config->GetModule(this).Get<const Anope::string>("database", "anope.db"));
|
||||
|
||||
std::fstream *fs = databases[s_type->GetOwner()] = new std::fstream((db_name + ".tmp").c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
|
||||
|
||||
if (!fs->is_open())
|
||||
Log(this) << "Unable to open " << db_name << " for writing";
|
||||
}
|
||||
|
||||
SaveData data;
|
||||
const std::list<Serializable *> &items = Serializable::GetItems();
|
||||
for (auto *base : items)
|
||||
{
|
||||
Serialize::Type *s_type = base->GetSerializableType();
|
||||
if (!s_type)
|
||||
continue;
|
||||
|
||||
data.fs = databases[s_type->GetOwner()];
|
||||
if (!data.fs || !data.fs->is_open())
|
||||
continue;
|
||||
|
||||
*data.fs << "OBJECT " << s_type->GetName();
|
||||
if (base->id)
|
||||
*data.fs << "\nID " << base->id;
|
||||
s_type->Serialize(base, data);
|
||||
*data.fs << "\nEND\n";
|
||||
}
|
||||
|
||||
for (auto &[mod, f] : databases)
|
||||
{
|
||||
const auto db_name = Anope::ExpandData((mod ? (mod->name + ".db") : Config->GetModule(this).Get<const Anope::string>("database", "anope.db")));
|
||||
|
||||
if (!f->is_open() || !f->good())
|
||||
{
|
||||
this->Write("Unable to write database " + db_name);
|
||||
|
||||
f->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
f->close();
|
||||
#ifdef _WIN32
|
||||
/* Windows rename() fails if the file already exists. */
|
||||
remove(db_name.c_str());
|
||||
#endif
|
||||
rename((db_name + ".tmp").c_str(), db_name.c_str());
|
||||
}
|
||||
|
||||
delete f;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (i)
|
||||
throw;
|
||||
}
|
||||
|
||||
if (!i)
|
||||
{
|
||||
this->Notify();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Load just one type. Done if a module is reloaded during runtime */
|
||||
void OnSerializeTypeCreate(Serialize::Type *stype) override
|
||||
{
|
||||
if (!loaded)
|
||||
|
||||
+181
-152
@@ -20,23 +20,13 @@ namespace fs = std::filesystem;
|
||||
|
||||
// TODO:
|
||||
// * forking into background
|
||||
// * stable key order
|
||||
|
||||
inline Anope::string yyjson_mut_get_astr(yyjson_mut_val *val)
|
||||
inline Anope::string yyjson_get_astr(yyjson_val *val)
|
||||
{
|
||||
const auto *str = yyjson_mut_get_str(val);
|
||||
const auto *str = yyjson_get_str(val);
|
||||
return str ? str : "";
|
||||
}
|
||||
|
||||
inline void yyjson_mut_obj_upsert(yyjson_mut_doc *doc, yyjson_mut_val *obj, const char *key, yyjson_mut_val *val)
|
||||
{
|
||||
auto *oldval = yyjson_mut_obj_get(obj, key);
|
||||
if (oldval)
|
||||
yyjson_mut_obj_replace(obj, yyjson_mut_str(doc, key), val);
|
||||
else
|
||||
yyjson_mut_obj_add_val(doc, obj, key, val);
|
||||
}
|
||||
|
||||
class Data final
|
||||
: public Serialize::Data
|
||||
{
|
||||
@@ -48,37 +38,42 @@ public:
|
||||
Anope::map<std::stringstream> data;
|
||||
|
||||
// Used when writing data.
|
||||
Data() = default;
|
||||
Data(Serialize::Type *s_type, Serializable *obj)
|
||||
{
|
||||
if (obj->id)
|
||||
this->id = obj->id;
|
||||
s_type->Serialize(obj, *this);
|
||||
}
|
||||
|
||||
// Used when reading data.
|
||||
Data(yyjson_mut_val *elem)
|
||||
Data(yyjson_val *elem)
|
||||
{
|
||||
size_t idx, max;
|
||||
yyjson_mut_val *key, *value;
|
||||
yyjson_mut_obj_foreach(elem, idx, max, key, value)
|
||||
yyjson_val *key, *value;
|
||||
yyjson_obj_foreach(elem, idx, max, key, value)
|
||||
{
|
||||
if (yyjson_mut_get_type(key) != YYJSON_TYPE_STR)
|
||||
if (yyjson_get_type(key) != YYJSON_TYPE_STR)
|
||||
continue;
|
||||
|
||||
Anope::string akey(yyjson_mut_get_str(key));
|
||||
auto akey = yyjson_get_astr(key);
|
||||
if (akey.equals_ci("@id"))
|
||||
{
|
||||
this->id = yyjson_mut_get_uint(value);
|
||||
this->id = yyjson_get_uint(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (yyjson_mut_is_bool(value))
|
||||
data[akey] << yyjson_mut_get_bool(value);
|
||||
else if (yyjson_mut_is_int(value))
|
||||
data[akey] << yyjson_mut_get_int(value);
|
||||
else if (yyjson_mut_is_null(value))
|
||||
if (yyjson_is_bool(value))
|
||||
data[akey] << yyjson_get_bool(value);
|
||||
else if (yyjson_is_int(value))
|
||||
data[akey] << yyjson_get_int(value);
|
||||
else if (yyjson_is_null(value))
|
||||
data[akey];
|
||||
else if (yyjson_mut_is_real(value))
|
||||
data[akey] << yyjson_mut_get_real(value);
|
||||
else if (yyjson_mut_is_str(value))
|
||||
data[akey] << yyjson_mut_get_str(value);
|
||||
else if (yyjson_mut_is_uint(value))
|
||||
data[akey] << yyjson_mut_get_uint(value);
|
||||
else if (yyjson_is_real(value))
|
||||
data[akey] << yyjson_get_real(value);
|
||||
else if (yyjson_is_str(value))
|
||||
data[akey] << yyjson_get_astr(value);
|
||||
else if (yyjson_is_uint(value))
|
||||
data[akey] << yyjson_get_uint(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,16 +81,29 @@ public:
|
||||
{
|
||||
return data[key];
|
||||
}
|
||||
|
||||
size_t Hash() const override
|
||||
{
|
||||
size_t hash = 0;
|
||||
for (const auto &[_, value] : this->data)
|
||||
{
|
||||
auto valuestr = value.str();
|
||||
if (!valuestr.empty())
|
||||
hash ^= Anope::hash_cs()(valuestr);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
class DBJSON final
|
||||
: public Module
|
||||
{
|
||||
private:
|
||||
using DBPair = std::pair<yyjson_mut_doc *, yyjson_mut_val *>;
|
||||
// Multimap from serializable type to serializable data.
|
||||
using DBData = Anope::multimap<Data>;
|
||||
|
||||
// The databases which have already been loaded from disk.
|
||||
std::unordered_map<Module *, DBPair> databases;
|
||||
std::unordered_map<Module *, DBData> databases;
|
||||
|
||||
// Whether OnLoadDatabase has been called yet.
|
||||
bool loaded = false;
|
||||
@@ -182,7 +190,7 @@ private:
|
||||
return; // No backups.
|
||||
|
||||
auto backupdir = Anope::ExpandData(modconf.Get<Anope::string>("backup_directory", "backups"));
|
||||
if (!fs::is_directory(backupdir.str(), ec) && !ec)
|
||||
if (!fs::is_directory(backupdir.str(), ec))
|
||||
{
|
||||
fs::create_directories(backupdir.str(), ec);
|
||||
if (ec)
|
||||
@@ -201,71 +209,131 @@ private:
|
||||
CreateBackup(backupdir, dbpath, monthly_backups, "%Y-%m", "\?\?\?\?-\?\?");
|
||||
}
|
||||
|
||||
void LoadType(Serialize::Type *s_type, yyjson_mut_val *data)
|
||||
void LoadType(Serialize::Type *s_type, DBData &data)
|
||||
{
|
||||
auto *entries = yyjson_mut_obj_get(data, s_type->GetName().c_str());
|
||||
if (!entries || !yyjson_mut_is_arr(entries))
|
||||
auto entries = data.equal_range(s_type->GetName());
|
||||
if (entries.first == entries.second)
|
||||
return;
|
||||
|
||||
Log(LOG_DEBUG) << "Loading " << yyjson_mut_arr_size(entries) << " " << s_type->GetName() << " records";
|
||||
size_t idx, max;
|
||||
yyjson_mut_val *elem;
|
||||
yyjson_mut_arr_foreach(entries, idx, max, elem)
|
||||
{
|
||||
Data ld(elem);
|
||||
s_type->Unserialize(nullptr, ld);
|
||||
}
|
||||
for (auto it = entries.first; it != entries.second; ++it)
|
||||
s_type->Unserialize(nullptr, it->second);
|
||||
}
|
||||
|
||||
DBPair ReadDatabase(const Anope::string &dbname)
|
||||
std::optional<DBData> ReadDatabase(const Anope::string &dbname)
|
||||
{
|
||||
yyjson_read_err errmsg;
|
||||
const auto flags = YYJSON_READ_ALLOW_TRAILING_COMMAS | YYJSON_READ_ALLOW_INVALID_UNICODE;
|
||||
auto *idoc = yyjson_read_file(dbname.c_str(), flags, nullptr, &errmsg);
|
||||
if (!idoc)
|
||||
auto *doc = yyjson_read_file(dbname.c_str(), flags, nullptr, &errmsg);
|
||||
if (!doc)
|
||||
{
|
||||
Log(this) << "Unable to read " << dbname << ": error #" << errmsg.code << ": " << errmsg.msg;
|
||||
return { nullptr, nullptr };
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// We operate on a mutable document because we need to write to it later.
|
||||
auto *doc = yyjson_doc_mut_copy(idoc, nullptr);
|
||||
yyjson_doc_free(idoc);
|
||||
|
||||
auto *root = yyjson_mut_doc_get_root(doc);
|
||||
if (!yyjson_mut_is_obj(root))
|
||||
auto *root = yyjson_doc_get_root(doc);
|
||||
if (!yyjson_is_obj(root))
|
||||
{
|
||||
Log(this) << "Unable to read " << dbname << ": root element is not an object";
|
||||
return { nullptr, nullptr };
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto version = yyjson_mut_get_uint(yyjson_mut_obj_get(root, "version"));
|
||||
auto version = yyjson_get_uint(yyjson_obj_get(root, "version"));
|
||||
if (version && version != ANOPE_DATABASE_VERSION)
|
||||
{
|
||||
Log(this) << "Refusing to load an unsupported database version: " << version;
|
||||
return { nullptr, nullptr };
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto generator = yyjson_mut_get_astr(yyjson_mut_obj_get(root, "generator"));
|
||||
auto updated = yyjson_mut_get_uint(yyjson_mut_obj_get(root, "updated"));
|
||||
auto generator = yyjson_get_astr(yyjson_obj_get(root, "generator"));
|
||||
auto updated = yyjson_get_uint(yyjson_obj_get(root, "updated"));
|
||||
Log(LOG_DEBUG) << "Database " << dbname << " was generated on " << Anope::strftime(updated) << " by " << generator;
|
||||
|
||||
auto *data = yyjson_mut_obj_get(root, "data");
|
||||
if (!data || !yyjson_mut_is_obj(data))
|
||||
auto *data = yyjson_obj_get(root, "data");
|
||||
if (!data || !yyjson_is_obj(data))
|
||||
{
|
||||
Log(this) << "Unable to read " << dbname << ": data element is missing or not an object";
|
||||
return { nullptr, nullptr };
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return { doc, data };
|
||||
DBData ret;
|
||||
|
||||
size_t idx, max;
|
||||
yyjson_val *key, *val;
|
||||
yyjson_obj_foreach(data, idx, max, key, val)
|
||||
{
|
||||
if (!yyjson_is_str(key))
|
||||
{
|
||||
Log(this) << "Unable to read part of " << dbname << ": key of data element #" << idx << " is not a string";
|
||||
continue;
|
||||
}
|
||||
|
||||
auto keystr = yyjson_get_astr(key);
|
||||
if (!yyjson_is_arr(val))
|
||||
{
|
||||
Log(this) << "Unable to read part of " << dbname << ": " << keystr << " value of data element #" << idx << " is not an array";
|
||||
continue;
|
||||
}
|
||||
|
||||
Log(LOG_DEBUG) << "Loading " << yyjson_arr_size(val) << " " << keystr << " records";
|
||||
|
||||
size_t idx, max;
|
||||
yyjson_val *elem;
|
||||
yyjson_arr_foreach(val, idx, max, elem)
|
||||
{
|
||||
Data ld(elem);
|
||||
ret.emplace(keystr, std::move(ld));
|
||||
}
|
||||
}
|
||||
|
||||
yyjson_doc_free(doc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void UpdateMetadata(yyjson_mut_doc *doc, yyjson_mut_val *obj)
|
||||
void SaveType(yyjson_mut_doc *doc, yyjson_mut_val *obj, const Anope::string &typestr, const Data &data)
|
||||
{
|
||||
const auto generator = "Anope " + Anope::Version() + " " + Anope::VersionBuildString();
|
||||
yyjson_mut_obj_upsert(doc, obj, "generator", yyjson_mut_strncpy(doc, generator.c_str(), generator.length()));
|
||||
yyjson_mut_obj_upsert(doc, obj, "version", yyjson_mut_uint(doc, ANOPE_DATABASE_VERSION));
|
||||
yyjson_mut_obj_upsert(doc, obj, "updated", yyjson_mut_int(doc, Anope::CurTime));
|
||||
auto *type = yyjson_mut_obj_getn(obj, typestr.c_str(), typestr.length());
|
||||
if (!type || !yyjson_mut_is_arr(type))
|
||||
{
|
||||
// We haven't seen this element before.
|
||||
type = yyjson_mut_arr(doc);
|
||||
yyjson_mut_obj_add_val(doc, obj, typestr.c_str(), type);
|
||||
}
|
||||
|
||||
auto *elem = yyjson_mut_obj(doc);
|
||||
if (data.id)
|
||||
yyjson_mut_obj_add_uint(doc, elem, "@id", data.id);
|
||||
|
||||
for (const auto &[key, value] : data.data)
|
||||
{
|
||||
yyjson_mut_val *v;
|
||||
switch (data.GetType(key))
|
||||
{
|
||||
case Serialize::DataType::BOOL:
|
||||
v = yyjson_mut_bool(doc, Anope::Convert<bool>(value.str(), false));
|
||||
break;
|
||||
case Serialize::DataType::FLOAT:
|
||||
v = yyjson_mut_real(doc, Anope::Convert<double>(value.str(), 0.0));
|
||||
break;
|
||||
case Serialize::DataType::INT:
|
||||
v = yyjson_mut_int(doc, Anope::Convert<int64_t>(value.str(), 0));
|
||||
break;
|
||||
case Serialize::DataType::TEXT:
|
||||
{
|
||||
auto str = value.str();
|
||||
v = str.empty() ? yyjson_mut_null(doc) : yyjson_mut_strncpy(doc, str.c_str(), str.length());
|
||||
break;
|
||||
}
|
||||
case Serialize::DataType::UINT:
|
||||
v = yyjson_mut_uint(doc, Anope::Convert<uint64_t>(value.str(), 0));
|
||||
break;
|
||||
}
|
||||
|
||||
auto *k = yyjson_mut_strncpy(doc, key.c_str(), key.length());
|
||||
yyjson_mut_obj_add(elem, k, v);
|
||||
}
|
||||
|
||||
yyjson_mut_arr_add_val(type, elem);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -278,15 +346,15 @@ public:
|
||||
{
|
||||
auto dbname = GetDatabaseFile(nullptr);
|
||||
|
||||
auto [doc, data] = ReadDatabase(dbname);
|
||||
if (!data)
|
||||
auto db = ReadDatabase(dbname);
|
||||
if (!db)
|
||||
return EVENT_STOP;
|
||||
|
||||
for (const auto &type : Serialize::Type::GetTypeOrder())
|
||||
{
|
||||
auto *s_type = Serialize::Type::Find(type);
|
||||
if (s_type && !s_type->GetOwner())
|
||||
LoadType(s_type, data);
|
||||
LoadType(s_type, db.value());
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
@@ -295,111 +363,73 @@ public:
|
||||
|
||||
void OnSaveDatabase() override
|
||||
{
|
||||
std::set<Module *> updated;
|
||||
for (const auto &[_, s_type] : Serialize::Type::GetTypes())
|
||||
// Step 1: clear the old data.
|
||||
for (const auto &type : Serialize::Type::GetTypeOrder())
|
||||
{
|
||||
auto *s_type = Serialize::Type::Find(type);
|
||||
if (!s_type)
|
||||
continue; // Provider has been unloaded.
|
||||
|
||||
auto it = databases.find(s_type->GetOwner());
|
||||
if (it == databases.end())
|
||||
{
|
||||
auto *doc = yyjson_mut_doc_new(nullptr);
|
||||
|
||||
auto *root = yyjson_mut_obj(doc);
|
||||
yyjson_mut_doc_set_root(doc, root);
|
||||
|
||||
UpdateMetadata(doc, root);
|
||||
|
||||
auto *data = yyjson_mut_obj(doc);
|
||||
yyjson_mut_obj_add_val(doc, root, "data", data);
|
||||
|
||||
databases[s_type->GetOwner()] = { doc, data };
|
||||
databases.emplace(s_type->GetOwner(), DBData());
|
||||
continue; // We just need to create for this type.
|
||||
}
|
||||
else if (updated.find(s_type->GetOwner()) == updated.end())
|
||||
{
|
||||
auto *doc = it->second.first;
|
||||
auto *root = yyjson_mut_doc_get_root(doc);
|
||||
|
||||
UpdateMetadata(doc, root);
|
||||
updated.insert(s_type->GetOwner());
|
||||
}
|
||||
// As this type has been written before we need to clear the entries
|
||||
// from the previous writes so we can update it in the next loop. We
|
||||
// have to do it this way so we don't purge any entries for unloaded
|
||||
// modules.
|
||||
it->second.erase(s_type->GetName());
|
||||
}
|
||||
|
||||
std::set<Serialize::Type *> seen;
|
||||
// Step 2: store the new data.
|
||||
for (auto *item : Serializable::GetItems())
|
||||
{
|
||||
auto *s_type = item->GetSerializableType();
|
||||
if (!s_type)
|
||||
continue; // Provider has been unloaded.
|
||||
|
||||
// This should always be found because we create it in the previous step.
|
||||
auto it = databases.find(s_type->GetOwner());
|
||||
if (it == databases.end())
|
||||
continue; // Type has not been registered?
|
||||
|
||||
auto &[doc, data] = it->second;
|
||||
|
||||
// If the type object doesn't exist then create it. Otherwise, clear.
|
||||
// all of the previous objects stored in it.
|
||||
auto *type = yyjson_mut_obj_getn(data, s_type->GetName().c_str(), s_type->GetName().length());
|
||||
if (!type || yyjson_mut_get_type(type) != YYJSON_TYPE_ARR)
|
||||
{
|
||||
// We haven't seen this element before.
|
||||
type = yyjson_mut_arr(doc);
|
||||
yyjson_mut_obj_add_val(doc, data, s_type->GetName().c_str(), type);
|
||||
}
|
||||
else if (seen.find(s_type) == seen.end())
|
||||
{
|
||||
// We are reusing an existing element, clear it.
|
||||
yyjson_mut_arr_clear(type);
|
||||
seen.insert(s_type);
|
||||
}
|
||||
|
||||
auto *elem = yyjson_mut_arr_add_obj(doc, type);
|
||||
if (item->id)
|
||||
yyjson_mut_obj_add_uint(doc, elem, "@id", item->id);
|
||||
|
||||
Data sd;
|
||||
s_type->Serialize(item, sd);
|
||||
for (const auto &[key, value] : sd.data)
|
||||
{
|
||||
yyjson_mut_val *v;
|
||||
switch (sd.GetType(key))
|
||||
{
|
||||
case Serialize::DataType::BOOL:
|
||||
v = yyjson_mut_bool(doc, Anope::Convert<bool>(value.str(), false));
|
||||
break;
|
||||
case Serialize::DataType::FLOAT:
|
||||
v = yyjson_mut_real(doc, Anope::Convert<double>(value.str(), 0.0));
|
||||
break;
|
||||
case Serialize::DataType::INT:
|
||||
v = yyjson_mut_int(doc, Anope::Convert<int64_t>(value.str(), 0));
|
||||
break;
|
||||
case Serialize::DataType::TEXT:
|
||||
{
|
||||
auto str = value.str();
|
||||
v = str.empty() ? yyjson_mut_null(doc) : yyjson_mut_strncpy(doc, str.c_str(), str.length());
|
||||
break;
|
||||
}
|
||||
case Serialize::DataType::UINT:
|
||||
v = yyjson_mut_uint(doc, Anope::Convert<uint64_t>(value.str(), 0));
|
||||
break;
|
||||
}
|
||||
|
||||
auto *k = yyjson_mut_strncpy(doc, key.c_str(), key.length());
|
||||
yyjson_mut_obj_add(elem, k, v);
|
||||
}
|
||||
if (it != databases.end())
|
||||
it->second.emplace(s_type->GetName(), Data(s_type, item));
|
||||
}
|
||||
|
||||
// Step 3: serialize to JSON.
|
||||
for (auto &[mod, database] : databases)
|
||||
{
|
||||
auto dbname = GetDatabaseFile(mod);
|
||||
BackupDatabase(dbname);
|
||||
|
||||
auto *doc = yyjson_mut_doc_new(nullptr);
|
||||
|
||||
auto *root = yyjson_mut_obj(doc);
|
||||
yyjson_mut_doc_set_root(doc, root);
|
||||
|
||||
const auto generator = "Anope " + Anope::Version() + " " + Anope::VersionBuildString();
|
||||
yyjson_mut_obj_add_strncpy(doc, root, "generator", generator.c_str(), generator.length());
|
||||
yyjson_mut_obj_add_uint(doc, root, "version", ANOPE_DATABASE_VERSION);
|
||||
yyjson_mut_obj_add_int(doc, root, "updated", Anope::CurTime);
|
||||
|
||||
auto *data = yyjson_mut_obj(doc);
|
||||
yyjson_mut_obj_add_val(doc, root, "data", data);
|
||||
|
||||
for (const auto &[name, items] : database)
|
||||
SaveType(doc, data, name, items);
|
||||
|
||||
Log(LOG_DEBUG) << "Writing " << dbname;
|
||||
|
||||
yyjson_write_err errmsg;
|
||||
const auto flags = YYJSON_WRITE_ALLOW_INVALID_UNICODE | YYJSON_WRITE_NEWLINE_AT_END | YYJSON_WRITE_PRETTY;
|
||||
if (!yyjson_mut_write_file(dbname.c_str(), database.first, flags, nullptr, &errmsg))
|
||||
if (!yyjson_mut_write_file(dbname.c_str(), doc, flags, nullptr, &errmsg))
|
||||
{
|
||||
Log(this) << "Unable to write " << dbname << ": error #" << errmsg.code << ": " << errmsg.msg;
|
||||
// TODO: exit??? retry???
|
||||
}
|
||||
|
||||
yyjson_mut_doc_free(doc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,14 +445,13 @@ public:
|
||||
const auto dbname = GetDatabaseFile(s_type->GetOwner());
|
||||
|
||||
auto db = ReadDatabase(dbname);
|
||||
if (!db.second)
|
||||
if (!db)
|
||||
return; // Not much we can do here.
|
||||
|
||||
it = databases.emplace(s_type->GetOwner(), db).first;
|
||||
it = databases.emplace(s_type->GetOwner(), std::move(db.value())).first;
|
||||
}
|
||||
|
||||
auto &[_, data] = it->second;
|
||||
LoadType(s_type, data);
|
||||
LoadType(s_type, it->second);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -174,9 +174,9 @@ public:
|
||||
if (!this->CheckInit() || obj->GetTimestamp() == Anope::CurTime)
|
||||
return;
|
||||
|
||||
Anope::string sql = Anope::printf("SELECT * from `%s`", GetTableName(obj).c_str());
|
||||
Anope::string sql = Anope::Format("SELECT * from `%s`", GetTableName(obj).c_str());
|
||||
if (obj->GetTimestamp())
|
||||
sql += Anope::printf(" WHERE (`timestamp` >= %s OR `timestamp` IS NULL)", this->SQL->FromUnixtime(obj->GetTimestamp()).c_str());
|
||||
sql += Anope::Format(" WHERE (`timestamp` >= %s OR `timestamp` IS NULL)", this->SQL->FromUnixtime(obj->GetTimestamp()).c_str());
|
||||
|
||||
Query query(sql);
|
||||
|
||||
|
||||
+41
-3
@@ -142,7 +142,7 @@ class Packet final
|
||||
record.ttl = (input[pos] << 24) | (input[pos + 1] << 16) | (input[pos + 2] << 8) | input[pos + 3];
|
||||
pos += 4;
|
||||
|
||||
//record.rdlength = input[pos] << 8 | input[pos + 1];
|
||||
auto rdlength = input[pos] << 8 | input[pos + 1];
|
||||
pos += 2;
|
||||
|
||||
switch (record.type)
|
||||
@@ -192,6 +192,44 @@ class Packet final
|
||||
|
||||
break;
|
||||
}
|
||||
case DNS::QUERY_TXT:
|
||||
{
|
||||
if (pos + rdlength > input_size)
|
||||
throw SocketException("Unable to unpack TXT resource record");
|
||||
|
||||
auto txtlength = input[pos++];
|
||||
if (pos + txtlength > input_size)
|
||||
throw SocketException("Unable to unpack TXT resource record");
|
||||
|
||||
record.rdata = Anope::string(reinterpret_cast<const char* >(input + pos), txtlength);
|
||||
pos += rdlength - 1;
|
||||
break;
|
||||
}
|
||||
case DNS::QUERY_SRV:
|
||||
{
|
||||
if (rdlength < 6 || pos + rdlength > input_size)
|
||||
throw SocketException("Unable to unpack SRV resource record");
|
||||
|
||||
auto srv = std::make_shared<DNS::Record::SRV>();
|
||||
|
||||
srv->priority = input[pos] << 8 | input[pos + 1];
|
||||
pos += 2;
|
||||
|
||||
srv->weight = input[pos] << 8 | input[pos + 1];
|
||||
pos += 2;
|
||||
|
||||
srv->port = input[pos] << 8 | input[pos + 1];
|
||||
pos += 2;
|
||||
|
||||
srv->host = this->UnpackName(input, input_size, pos);
|
||||
if (!IsValidName(srv->host))
|
||||
throw SocketException("Invalid name in SRV resource record");
|
||||
|
||||
record.rdata = Anope::Format("%hu %hu %hu %s", srv->priority,
|
||||
srv->weight, srv->port, srv->host.c_str());
|
||||
record.rdataobj = srv;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -638,7 +676,7 @@ public:
|
||||
if (!packet)
|
||||
return false;
|
||||
|
||||
Log(LOG_DEBUG_2) << "Resolver: Notifying slave " << packet->addr.addr();
|
||||
Log(LOG_DEBUG_2) << "Resolver: Notifying secondary " << packet->addr.addr();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -939,7 +977,7 @@ public:
|
||||
|
||||
void Notify(const Anope::string &zone) override
|
||||
{
|
||||
/* notify slaves of the update */
|
||||
/* notify secondaries of the update */
|
||||
for (const auto &[ip, port] : notify)
|
||||
{
|
||||
sockaddrs addr;
|
||||
|
||||
@@ -49,7 +49,7 @@ private:
|
||||
|
||||
public:
|
||||
EMD5(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, ENCRYPTION | VENDOR)
|
||||
: Module(modname, creator, DEPRECATED | ENCRYPTION | VENDOR)
|
||||
, md5provider(this, "md5", 16, 64)
|
||||
{
|
||||
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
|
||||
|
||||
@@ -14,7 +14,7 @@ class ENone final
|
||||
{
|
||||
public:
|
||||
ENone(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, ENCRYPTION | VENDOR)
|
||||
: Module(modname, creator, DEPRECATED | ENCRYPTION | VENDOR)
|
||||
{
|
||||
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
|
||||
throw ModuleException("enc_none is deprecated and can not be used as a primary encryption method");
|
||||
@@ -35,9 +35,7 @@ public:
|
||||
if (!hash_method.equals_cs("plain"))
|
||||
return;
|
||||
|
||||
Anope::string b64pass;
|
||||
Anope::B64Encode(req->GetPassword(), b64pass);
|
||||
auto enc = "plain:" + b64pass;
|
||||
auto enc = "plain:" + Anope::B64Encode(req->GetPassword());
|
||||
if (nc->pass.equals_cs(enc))
|
||||
{
|
||||
// If we are NOT the first encryption module we want to re-encrypt
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/* Include file for high-level encryption routines.
|
||||
*
|
||||
* (C) 2003-2025 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*
|
||||
* Based on the original code of Epona by Lara.
|
||||
* Based on the original code of Services by Andy Church.
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/encryption.h"
|
||||
|
||||
class EOld final
|
||||
: public Module
|
||||
{
|
||||
private:
|
||||
ServiceReference<Encryption::Provider> md5;
|
||||
|
||||
Anope::string EncryptInternal(const Anope::string &src)
|
||||
{
|
||||
if (!md5)
|
||||
return {};
|
||||
|
||||
char digest[32];
|
||||
memset(digest, 0, sizeof(digest));
|
||||
|
||||
auto hash = md5->Encrypt(src);
|
||||
if (hash.length() != sizeof(digest))
|
||||
return {}; // Probably a bug?
|
||||
memcpy(digest, hash.data(), hash.length());
|
||||
|
||||
char digest2[16];
|
||||
for (size_t i = 0; i < sizeof(digest); i += 2)
|
||||
digest2[i / 2] = XTOI(digest[i]) << 4 | XTOI(digest[i + 1]);
|
||||
|
||||
return Anope::Hex(digest2, sizeof(digest2));
|
||||
}
|
||||
|
||||
inline static char XTOI(char c)
|
||||
{
|
||||
return c > 9 ? c - 'A' + 10 : c - '0';
|
||||
}
|
||||
|
||||
public:
|
||||
EOld(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, ENCRYPTION | VENDOR)
|
||||
, md5("Encryption::Provider", "md5")
|
||||
{
|
||||
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
|
||||
throw ModuleException("enc_old is deprecated and can not be used as a primary encryption method");
|
||||
|
||||
ModuleManager::LoadModule("enc_md5", User::Find(creator, true));
|
||||
if (!md5)
|
||||
throw ModuleException("Unable to find md5 reference");
|
||||
}
|
||||
|
||||
void OnCheckAuthentication(User *, IdentifyRequest *req) override
|
||||
{
|
||||
const auto *na = NickAlias::Find(req->GetAccount());
|
||||
if (!na)
|
||||
return;
|
||||
|
||||
NickCore *nc = na->nc;
|
||||
size_t pos = nc->pass.find(':');
|
||||
if (pos == Anope::string::npos)
|
||||
return;
|
||||
|
||||
Anope::string hash_method(nc->pass.begin(), nc->pass.begin() + pos);
|
||||
if (!hash_method.equals_cs("oldmd5"))
|
||||
return;
|
||||
|
||||
auto enc = EncryptInternal(req->GetPassword());
|
||||
if (!enc.empty() && nc->pass.equals_cs(enc))
|
||||
{
|
||||
// If we are NOT the first encryption module we want to re-encrypt
|
||||
// the password with the primary encryption method.
|
||||
if (ModuleManager::FindFirstOf(ENCRYPTION) != this)
|
||||
Anope::Encrypt(req->GetPassword(), nc->pass);
|
||||
req->Success(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_INIT(EOld)
|
||||
@@ -173,7 +173,7 @@ private:
|
||||
|
||||
public:
|
||||
ESHA1(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, ENCRYPTION | VENDOR)
|
||||
: Module(modname, creator, DEPRECATED | ENCRYPTION | VENDOR)
|
||||
, sha1provider(this, "sha1", 20, 64)
|
||||
{
|
||||
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
|
||||
|
||||
@@ -17,14 +17,6 @@ class ESHA256 final
|
||||
{
|
||||
private:
|
||||
unsigned iv[8];
|
||||
bool use_iv;
|
||||
|
||||
/* initializes the IV with a new random value */
|
||||
void NewRandomIV()
|
||||
{
|
||||
for (auto &ivsegment : iv)
|
||||
ivsegment = static_cast<uint32_t>(Anope::RandomNumber());
|
||||
}
|
||||
|
||||
/* returns the IV as base64-encrypted string */
|
||||
Anope::string GetIVString()
|
||||
@@ -50,11 +42,6 @@ private:
|
||||
|
||||
Anope::string EncryptInternal(const Anope::string &src)
|
||||
{
|
||||
if (!use_iv)
|
||||
NewRandomIV();
|
||||
else
|
||||
use_iv = false;
|
||||
|
||||
sha256_ctx ctx;
|
||||
sha256_init(&ctx);
|
||||
for (size_t i = 0; i < 8; ++i)
|
||||
@@ -69,9 +56,8 @@ private:
|
||||
|
||||
public:
|
||||
ESHA256(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, ENCRYPTION | VENDOR)
|
||||
: Module(modname, creator, DEPRECATED | ENCRYPTION | VENDOR)
|
||||
{
|
||||
use_iv = false;
|
||||
if (ModuleManager::FindFirstOf(ENCRYPTION) == this)
|
||||
throw ModuleException("enc_sha256 is deprecated and can not be used as a primary encryption method");
|
||||
}
|
||||
@@ -92,7 +78,6 @@ public:
|
||||
return;
|
||||
|
||||
GetIVFromPass(nc->pass);
|
||||
use_iv = true;
|
||||
auto enc = EncryptInternal(req->GetPassword());
|
||||
if (nc->pass.equals_cs(enc))
|
||||
{
|
||||
|
||||
@@ -8,8 +8,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* RequiredLibraries: argon2 */
|
||||
/* RequiredWindowsLibraries: argon2 */
|
||||
/// BEGIN CMAKE
|
||||
/// if(WIN32)
|
||||
/// target_link_libraries(${SO} PRIVATE CONAN_PKG::argon2)
|
||||
/// else()
|
||||
/// pkg_check_modules("ARGON2" IMPORTED_TARGET REQUIRED "libargon2")
|
||||
/// target_link_libraries(${SO} PRIVATE PkgConfig::ARGON2)
|
||||
/// endif()
|
||||
/// END CMAKE
|
||||
|
||||
#include <climits>
|
||||
#include <random>
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* RequiredLibraries: crypt */
|
||||
|
||||
#include "module.h"
|
||||
|
||||
class EPOSIX final
|
||||
|
||||
@@ -9,7 +9,12 @@
|
||||
* Based on the original code of Services by Andy Church.
|
||||
*/
|
||||
|
||||
/* RequiredLibraries: ldap_r|ldap,lber */
|
||||
/// BEGIN CMAKE
|
||||
/// if(NOT WIN32)
|
||||
/// pkg_check_modules("OPENLDAP" IMPORTED_TARGET REQUIRED "lber" "ldap")
|
||||
/// target_link_libraries(${SO} PRIVATE PkgConfig::OPENLDAP)
|
||||
/// endif()
|
||||
/// END CMAKE
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/ldap.h"
|
||||
|
||||
+14
-8
@@ -6,8 +6,14 @@
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
/* RequiredLibraries: mysqlclient */
|
||||
/* RequiredWindowsLibraries: libmysql */
|
||||
/// BEGIN CMAKE
|
||||
/// if(WIN32)
|
||||
/// target_link_libraries(${SO} PRIVATE CONAN_PKG::libmysqlclient)
|
||||
/// else()
|
||||
/// pkg_search_module("MYSQL" IMPORTED_TARGET REQUIRED "mysqlclient" "mariadb")
|
||||
/// target_link_libraries(${SO} PRIVATE PkgConfig::MYSQL)
|
||||
/// endif()
|
||||
/// END CMAKE
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/sql.h"
|
||||
@@ -200,7 +206,7 @@ public:
|
||||
|
||||
Anope::string GetColumn(Serialize::DataType dt)
|
||||
{
|
||||
return Anope::printf("%s %s DEFAULT %s",
|
||||
return Anope::Format("%s %s DEFAULT %s",
|
||||
GetColumnType(dt),
|
||||
GetColumnNull(dt) ? "NULL" : "NOT NULL",
|
||||
GetColumnDefault(dt));
|
||||
@@ -245,7 +251,7 @@ public:
|
||||
DThread = new DispatcherThread();
|
||||
DThread->Start();
|
||||
|
||||
Log(this) << "Module was compiled against MySQL version " << (MYSQL_VERSION_ID / 10000) << "." << (MYSQL_VERSION_ID / 100 % 100) << "." << (MYSQL_VERSION_ID % 100) << " and is running against version " << mysql_get_client_info();
|
||||
Log(this) << "Module was compiled against MySQL version " << MYSQL_SERVER_VERSION << " and is running against version " << mysql_get_client_info();
|
||||
}
|
||||
|
||||
~ModuleSQL()
|
||||
@@ -498,24 +504,24 @@ std::vector<Query> MySQLService::CreateTable(const Anope::string &table, const D
|
||||
{
|
||||
// We can't just use MODIFY COLUMN here because the value may not
|
||||
// be valid and we may need to replace with the default.
|
||||
auto res = this->RunQuery(Anope::printf("ALTER TABLE `%s` ADD COLUMN `%s_new` %s; ",
|
||||
auto res = this->RunQuery(Anope::Format("ALTER TABLE `%s` ADD COLUMN `%s_new` %s; ",
|
||||
table.c_str(), column.c_str(), GetColumn(stype).c_str()));
|
||||
|
||||
if (res)
|
||||
{
|
||||
res = this->RunQuery(Anope::printf("UPDATE IGNORE `%s` SET `%s_new` = %s; ",
|
||||
res = this->RunQuery(Anope::Format("UPDATE IGNORE `%s` SET `%s_new` = %s; ",
|
||||
table.c_str(), column.c_str(), column.c_str()));
|
||||
}
|
||||
|
||||
if (res)
|
||||
{
|
||||
res = this->RunQuery(Anope::printf("ALTER TABLE `%s` DROP COLUMN `%s`; ",
|
||||
res = this->RunQuery(Anope::Format("ALTER TABLE `%s` DROP COLUMN `%s`; ",
|
||||
table.c_str(), column.c_str()));
|
||||
}
|
||||
|
||||
if (res)
|
||||
{
|
||||
res = this->RunQuery(Anope::printf("ALTER TABLE `%s` RENAME COLUMN `%s_new` TO `%s`; ",
|
||||
res = this->RunQuery(Anope::Format("ALTER TABLE `%s` RENAME COLUMN `%s_new` TO `%s`; ",
|
||||
table.c_str(), column.c_str(), column.c_str()));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,14 @@
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
/* RequiredLibraries: pcre2-8 */
|
||||
/* RequiredWindowsLibraries: pcre2-8 */
|
||||
/// BEGIN CMAKE
|
||||
/// if(WIN32)
|
||||
/// target_link_libraries(${SO} PRIVATE CONAN_PKG::pcre2)
|
||||
/// else()
|
||||
/// pkg_check_modules("PCRE2" IMPORTED_TARGET REQUIRED "libpcre2-8")
|
||||
/// target_link_libraries(${SO} PRIVATE PkgConfig::PCRE2)
|
||||
/// endif()
|
||||
/// END CMAKE
|
||||
|
||||
#include "module.h"
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
/* RequiredLibraries: tre */
|
||||
/// BEGIN CMAKE
|
||||
/// pkg_check_modules("TRE" IMPORTED_TARGET REQUIRED "tre")
|
||||
/// target_link_libraries(${SO} PRIVATE PkgConfig::TRE)
|
||||
/// END CMAKE
|
||||
|
||||
#include "module.h"
|
||||
#include <tre/regex.h>
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
/* RequiredLibraries: sqlite3 */
|
||||
/* RequiredWindowsLibraries: sqlite3 */
|
||||
/// BEGIN CMAKE
|
||||
/// find_package("SQLite3" REQUIRED)
|
||||
/// target_link_libraries(${SO} PRIVATE SQLite::SQLite3)
|
||||
/// END CMAKE
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/sql.h"
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
/* RequiredLibraries: gnutls */
|
||||
/* RequiredWindowsLibraries: libgnutls-30 */
|
||||
/// BEGIN CMAKE
|
||||
/// find_package("GnuTLS" REQUIRED)
|
||||
/// target_link_libraries(${SO} PRIVATE GnuTLS::GnuTLS)
|
||||
/// END CMAKE
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/ssl.h"
|
||||
|
||||
@@ -6,13 +6,15 @@
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
/* RequiredLibraries: ssl,crypto */
|
||||
/* RequiredWindowsLibraries: libssl,libcrypto */
|
||||
/// BEGIN CMAKE
|
||||
/// find_package("OpenSSL" REQUIRED)
|
||||
/// target_link_libraries(${SO} PRIVATE OpenSSL::Crypto OpenSSL::SSL)
|
||||
/// END CMAKE
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/ssl.h"
|
||||
|
||||
#define OPENSSL_API_COMPAT 0x10100000L
|
||||
#define OPENSSL_API_COMPAT 0x10101000L
|
||||
#define OPENSSL_NO_DEPRECATED
|
||||
|
||||
#include <openssl/bio.h>
|
||||
@@ -126,7 +128,9 @@ public:
|
||||
SSL_CTX_set_session_id_context(client_ctx, reinterpret_cast<const unsigned char *>(context_name.c_str()), context_name.length());
|
||||
SSL_CTX_set_session_id_context(server_ctx, reinterpret_cast<const unsigned char *>(context_name.c_str()), context_name.length());
|
||||
|
||||
#ifdef OPENSSL_VERSION_STR
|
||||
Log(this) << "Module was compiled against OpenSSL version " << OPENSSL_VERSION_STR << " and is running against version " << OpenSSL_version(OPENSSL_VERSION_STRING);
|
||||
#endif
|
||||
}
|
||||
|
||||
~SSLModule()
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
|
||||
/* RequiredLibraries: xmlrpc */
|
||||
/// BEGIN CMAKE
|
||||
/// find_library("XMLRPC" "xmlrpc" REQUIRED)
|
||||
/// message(STATUS "Found XMLRPC: ${XMLRPC}")
|
||||
/// target_link_libraries(${SO} PRIVATE ${XMLRPC})
|
||||
/// END CMAKE
|
||||
|
||||
#include <xmlrpc-c/base.h>
|
||||
|
||||
@@ -148,7 +151,7 @@ public:
|
||||
|
||||
if (request.data.size() < event->GetMinParams())
|
||||
{
|
||||
auto error = Anope::printf("Not enough parameters (given %zu, expected %zu)",
|
||||
auto error = Anope::Format("Not enough parameters (given %zu, expected %zu)",
|
||||
request.data.size(), event->GetMinParams());
|
||||
xmlrpc_env_set_fault(&env, RPC::ERR_INVALID_PARAMS, error.c_str());
|
||||
SendError(reply, env);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user