diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml deleted file mode 100644 index 485733521..000000000 --- a/.github/workflows/ccpp.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: C/C++ CI - -on: - pull_request: - branches: - - develop - -jobs: - build: - name: compile test - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: install dependencies - run: sudo apt-get install tcl tcl-dev openssl libssl-dev - - name: configure - run: ./configure - - name: make config - run: make config - - name: make - run: make - - name: make install - run: make install diff --git a/.github/workflows/configure_flags.yml b/.github/workflows/configure_flags.yml deleted file mode 100644 index 60a8c07bb..000000000 --- a/.github/workflows/configure_flags.yml +++ /dev/null @@ -1,41 +0,0 @@ -on: - workflow_dispatch: - inputs: - name: - description: 'Test configure flags' - -jobs: - configure-nosslflag: - name: Configure, --disable-tls - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: sudo apt-get install tcl tcl-dev - - run: ./configure --disable-tls - - run: make config - - run: make - - run: make install - - - configure-noipv6: - name: Configure, --disable-ipv6 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: sudo apt-get install tcl tcl-dev - - run: ./configure --disable-ipv6 - - run: make config - - run: make - - run: make install - - - configure-notdns: - name: Configure, --disable-tdns - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: sudo apt-get install tcl tcl-dev - - run: ./configure --disable-tdns - - run: make config - - run: make - - run: make install diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml new file mode 100644 index 000000000..d76a5e6c7 --- /dev/null +++ b/.github/workflows/dependencies.yml @@ -0,0 +1,96 @@ +name: Tcl/SSL Versions + +on: + pull_request: + branches: [ develop ] + push: + branches: [ develop ] + +jobs: + tcl-versions: + name: Tcl Versions + strategy: + matrix: + tcl_version: [ '8.5.19', '8.6.14', '8.7a5', '9.0b2' ] + continue-on-error: true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: install dependencies + run: sudo apt-get install openssl libssl-dev + - name: Build Tcl + run: | + wget http://prdownloads.sourceforge.net/tcl/tcl${{ matrix.tcl_version }}-src.tar.gz && \ + tar xzf tcl${{ matrix.tcl_version }}-src.tar.gz && \ + cd tcl${{ matrix.tcl_version }}/unix && \ + ./configure --prefix=$HOME/tcl && \ + make -j4 && make install + - name: Build + run: ./configure --with-tcl=$HOME/tcl/lib && LD_LIBRARY_PATH=$HOME/tcl/lib make config eggdrop + ssl-version-10: + name: OpenSSL 1.0 + continue-on-error: true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: 'eggdrop' + - name: install dependencies + run: sudo apt-get install tcl tcl-dev + - name: Build OpenSSL + run: | + wget https://www.openssl.org/source/old/1.0.2/openssl-1.0.2u.tar.gz && tar xzf openssl-1.0.2u.tar.gz && \ + cd openssl-1.0.2u && ./config --prefix=$HOME/ssl -fPIC && make -j4 && make install_sw + - name: Build + run: cd $GITHUB_WORKSPACE/eggdrop && ./configure --with-sslinc=$HOME/ssl/include --with-ssllib=$HOME/ssl/lib && LD_LIBRARY_PATH=$HOME/ssl/lib make config eggdrop + ssl-version-11: + name: OpenSSL 1.1 + continue-on-error: true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + repository: openssl/openssl + ref: 'OpenSSL_1_1_1w' + path: 'openssl' + - name: Build OpenSSL + run: | + cd $GITHUB_WORKSPACE/openssl && ./config --prefix=$HOME/ssl && make -j4 && make install_sw + - name: install dependencies + run: sudo apt-get install tcl tcl-dev + - uses: actions/checkout@v4 + with: + path: 'eggdrop' + - name: Build + run: cd $GITHUB_WORKSPACE/eggdrop && ./configure --with-sslinc=$HOME/ssl/include --with-ssllib=$HOME/ssl/lib && LD_LIBRARY_PATH=$HOME/ssl/lib make config eggdrop + ssl-versions-3x: + name: OpenSSL 3.x + strategy: + matrix: + ssl_version: [ '3.0', '3.1', '3.2', '3.3' ] + continue-on-error: true + runs-on: ubuntu-latest + steps: + - uses: oprypin/find-latest-tag@v1 + with: + repository: openssl/openssl + releases-only: true + prefix: 'openssl-' + regex: "${{ matrix.ssl_version }}.[0-9]+" + sort-tags: true + id: openssl + - uses: actions/checkout@v4 + with: + repository: openssl/openssl + ref: ${{ steps.openssl.outputs.tag }} + path: 'openssl' + - name: Build OpenSSL + run: | + cd $GITHUB_WORKSPACE/openssl && ./config --prefix=$HOME/ssl && make -j4 && make install_sw + - uses: actions/checkout@v4 + with: + path: 'eggdrop' + - name: install dependencies + run: sudo apt-get install tcl tcl-dev + - name: Build + run: cd $GITHUB_WORKSPACE/eggdrop && ./configure --with-sslinc=$HOME/ssl/include --with-ssllib=$HOME/ssl/lib64 && LD_LIBRARY_PATH=$HOME/ssl/lib64 make config eggdrop diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml new file mode 100644 index 000000000..e1dc3be6b --- /dev/null +++ b/.github/workflows/make.yml @@ -0,0 +1,39 @@ +name: Eggdrop Compile + +on: + pull_request: + branches: [ develop ] + push: + branches: [ develop ] + +jobs: + default-build: + name: Compile Test + strategy: + matrix: + cc: [ 'gcc', 'clang' ] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: install dependencies + run: sudo apt-get install clang tcl tcl-dev openssl libssl-dev + - name: Build + env: + CC: ${{ matrix.cc }} + run: ./configure && make config && make -j4 && make install + feature-test: + name: Features + continue-on-error: true + needs: default-build + strategy: + matrix: + conf_tls: [ '', '--disable-tls' ] + conf_ipv6: [ '', '--disable-ipv6' ] + conf_tdns: [ '', '--disable-tdns' ] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: install dependencies + run: sudo apt-get install tcl tcl-dev openssl libssl-dev + - name: Build + run: ./configure ${{ matrix.conf_tls }} ${{ matrix.conf_ipv6 }} ${{ matrix.conf_tdns }} && make config && make -j4 diff --git a/.github/workflows/misc.yml b/.github/workflows/misc.yml new file mode 100644 index 000000000..b6a894b30 --- /dev/null +++ b/.github/workflows/misc.yml @@ -0,0 +1,45 @@ +name: Check autotools/makedepend + +on: + pull_request: + branches: [ develop ] + push: + branches: [ develop ] + +jobs: + autotools-check: + name: Check if misc/runautotools needs to be run + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: install dependencies + run: sudo apt-get install build-essential autoconf + - name: Stage configure with revision removed + run: | + for i in `find . -name configure`; do sed -i 's/From configure.ac .*//' $i; git add $i; done + - name: Run autotools + run: misc/runautotools + - name: Remove configure revision again + run: | + for i in `find . -name configure`; do sed -i 's/From configure.ac .*//' $i; done + - name: Check diff + run: | + git diff | tee .gitdiff + if [ -s .gitdiff ]; then + exit 1 + fi + makedepend-check: + name: Check if misc/makedepend needs to be run + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: install dependencies + run: sudo apt-get install build-essential autoconf tcl-dev tcl openssl libssl-dev + - name: Run makedepend + run: misc/makedepend + - name: Check diff + run: | + git diff | tee .gitdiff + if [ -s .gitdiff ]; then + exit 1 + fi diff --git a/INSTALL b/INSTALL index 81e2a5184..1db949afb 100644 --- a/INSTALL +++ b/INSTALL @@ -158,5 +158,5 @@ the README file. If not, then READ IT!&@#%@! Have fun with Eggdrop! - Copyright (C) 1997 Robey Pointer Copyright (C) 1999 - 2023 Eggheads + Copyright (C) 1997 Robey Pointer Copyright (C) 1999 - 2024 Eggheads Development Team diff --git a/README b/README index 2d74900ca..468549297 100644 --- a/README +++ b/README @@ -216,5 +216,5 @@ OBTAINING HELP - Don't ask to ask- just state your question, along with any relevant details and error messages -Copyright (C) 1997 Robey Pointer Copyright (C) 1999 - 2023 Eggheads +Copyright (C) 1997 Robey Pointer Copyright (C) 1999 - 2024 Eggheads Development Team diff --git a/config.h.in b/config.h.in index 30cc2b7da..22e26d5c8 100644 --- a/config.h.in +++ b/config.h.in @@ -287,6 +287,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_TIME_H + /* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use `HAVE_STRUCT_TM_TM_ZONE' instead. */ #undef HAVE_TM_ZONE diff --git a/configure b/configure index 2a6387317..a59374034 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac 98f8972a. +# From configure.ac 9068a673. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for Eggdrop 1.9.5. # @@ -2789,7 +2789,6 @@ as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" as_fn_append ac_header_c_list " wchar.h wchar_h HAVE_WCHAR_H" as_fn_append ac_header_c_list " minix/config.h minix_config_h HAVE_MINIX_CONFIG_H" -as_fn_append ac_header_c_list " sys/time.h sys_time_h HAVE_SYS_TIME_H" as_fn_append ac_header_c_list " sys/select.h sys_select_h HAVE_SYS_SELECT_H" as_fn_append ac_header_c_list " sys/socket.h sys_socket_h HAVE_SYS_SOCKET_H" as_fn_append ac_header_c_list " sys/param.h sys_param_h HAVE_SYS_PARAM_H" @@ -6855,8 +6854,6 @@ fi fi - - ac_fn_c_check_header_compile "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default" if test "x$ac_cv_header_arpa_inet_h" = xyes then : @@ -6940,6 +6937,12 @@ if test "x$ac_cv_header_sys_time_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h +fi +ac_fn_c_check_header_compile "$LINENO" "time.h" "ac_cv_header_time_h" "$ac_includes_default" +if test "x$ac_cv_header_time_h" = xyes +then : + printf "%s\n" "#define HAVE_TIME_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes @@ -10635,7 +10638,6 @@ printf "%s\n" "#define EGG_TDNS 1" >>confdefs.h # Check for Python -EGG_PYTHON_ENABLE # Check whether --with-python-config was given. diff --git a/configure.ac b/configure.ac index 2a1188989..06d4708ae 100644 --- a/configure.ac +++ b/configure.ac @@ -91,9 +91,8 @@ EGG_CHECK_OS # Checks for header files. EGG_HEADER_STDC AC_HEADER_DIRENT -AC_CHECK_HEADERS_ONCE([sys/time.h]) -AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h locale.h netdb.h netinet/in.h stdio.h stdarg.h stddef.h sys/file.h sys/param.h sys/select.h sys/socket.h sys/time.h unistd.h wchar.h]) +AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h locale.h netdb.h netinet/in.h stdio.h stdarg.h stddef.h sys/file.h sys/param.h sys/select.h sys/socket.h sys/time.h time.h unistd.h wchar.h]) # Checks for typedefs, structures, and compiler characteristics. @@ -165,7 +164,6 @@ EGG_TLS_DETECT EGG_TDNS_ENABLE # Check for Python -EGG_PYTHON_ENABLE EGG_PYTHON_WITHCONFIG diff --git a/doc/sphinx_source/modules/mod/python.rst b/doc/sphinx_source/modules/mod/python.rst index 55307eb6f..5e06a45b2 100644 --- a/doc/sphinx_source/modules/mod/python.rst +++ b/doc/sphinx_source/modules/mod/python.rst @@ -8,6 +8,11 @@ Python Module This module adds a Python interpreter to Eggdrop, allowing you to run Python scripts. +------------------- +System Requirements +------------------- +This module requires Python version 3.8 or higher in order to run. Similar to Tcl requirements, Eggdrop requires both python and python development libraries to be installed on the host machine. On Debian/Ubuntu machines, this means the packages ``python``, ``python-dev`` AND ``python-is-python3`` to be installed. The python-is-python3 updates symlinks on the host system that allow Eggdrop to find it. + -------------- Loading Python -------------- @@ -50,105 +55,3 @@ pysource ^^^^^^^^^^^^^^^^^^^^^^^ The ``pysource`` command is analogous to the Tcl ``source`` command, except that it loads a Python script into Eggdrop instead of a Tcl script. - ------------------------ -Eggdrop Python Commands ------------------------ - -The Python module is built to use the existing core Tcl commands integrated into Eggdrop via the ``eggdrop.tcl`` module. To call an existing Tcl command from Python, you can either load the entire catalog by running ``import eggdrop.tcl``, or be more specific by ``from eggdrop.tcl import putserv, putlog, chanlist``, etc. - -Arguments to the Tcl functions are automatically converted as follows: - -* ``None`` is converted to an empty Tcl object (the empty string, ``""``) -* ``List`` and ``Tuple`` is converted to a ``Tcl list`` -* ``Dict`` is converted to a ``Tcl dictionary`` -* Everything else is converted to a string using the str() method - -Return values from Tcl functions must be manually converted: - -* ``""`` the empty string is automatically converted to None -* everything else is returned as string -* ``Tcl list`` as string can be converted to a Python ``List`` using ``parse_tcl_list`` -* ``Tcl dictionary`` as string can be converted to a Python ``Dict`` using ``parse_tcl_list`` - -Additionally, a few extra python commands have been created for use without these conversions: - -^^^^^^^^^^^^^^^^ -bind -^^^^^^^^^^^^^^^^ - -The python version of the bind command is used to create a bind that triggers a python function. The python bind takes the same arguments as the Tcl binds, but here each argument is passed individually. For example, a bind that would look like ``bind pub * !foo myproc`` in Tcl is written as ``bind("pub", "*", "!foo", myproc)``. For more information on Eggsrop bind argument syntax please see :ref:`bind_types`. The eggdrop.tcl.bind command should not be used as it will attempt to call a Tcl proc. - -^^^^^^^^^^^^^^^^^^^^^^^ -parse_tcl_list -^^^^^^^^^^^^^^^^^^^^^^^ - -When a python script calls a Tcl command that returns a list via the eggdrop.tcl module, the return value will be a Tcl-formatted list- also simply known as a string. The ``parse_tcl_list`` command will convert the Tcl-formatted list into a Python list, which can then freely be used within the Python script. - -^^^^^^^^^^^^^^^^^^^^^^^ -parse_tcl_dict -^^^^^^^^^^^^^^^^^^^^^^^ - -When a python script calls a Tcl command that returns a dict via the eggdrop.tcl module, the return value will be a Tcl-formatted dict- also simply known as a string. The ``parse_tcl_dict`` command will c -onvert the Tcl-formatted dict into a Python list, which can then freely be used within the Python script. - ----------------- -Config variables ----------------- - -There are also some variables you can set in your config file: - - set allow-resync 0 - When two bots get disconnected, this setting allows them to create a - resync buffer which saves all changes done to the userfile during - the disconnect. When they reconnect, they will not have to transfer - the complete user file, but, instead, just send the resync buffer. - --------------------------------- -Writing an Eggdrop Python script --------------------------------- - -This is how to write a python script for Eggdrop. - -You can view examples of Python scripts in the exampleScripts folder included with this module. - -.. glossary:: - - bestfriend.py - This example script demonstrates how to use the parse_tcl_list() python command to convert a list returned by a Tcl command into a list that is usable by Python. - - greet.py - This is a very basic script that demonstrates how a Python script with binds can be run by Eggdrop. - - imdb.py - This script shows how to use an existing third-party module to extend a Python script, in this case retrieving information from imdb.com. - - listtls.py - This script demonstrates how to use parse-tcl_list() and parse_tcl_dict() to convert a list of dicts provided by Tcl into something that is usable by Python. - - urltitle.py - This script shows how to use an existing third-party module to extend a Python script, in this case using an http parser to collect title information from a provided web page. - - -^^^^^^^^^^^^^^ -Header section -^^^^^^^^^^^^^^ - -An Eggdrop python script requires you to import X Y and Z, in this format. - -^^^^^^^^^^^^ -Code Section -^^^^^^^^^^^^ - -Normal python code works here. To run a command from the Eggdrop Tcl library, use this format. - -Use this format all over. - -------------------------------------- -Writing a module for use with Eggdrop -------------------------------------- - -This is how you import a module for use with an egg python script. - - -Copyright (C) 2000 - 2024 Eggheads Development Team diff --git a/doc/sphinx_source/using/python.rst b/doc/sphinx_source/using/python.rst new file mode 100644 index 000000000..520aa1810 --- /dev/null +++ b/doc/sphinx_source/using/python.rst @@ -0,0 +1,113 @@ +======================= +Using the Python Module +======================= + +In Eggdrop 1.10.0, Eggdrop was shipped with a Python module that, similar to the existing core Tcl capability, allows Eggdrop to run python scripts. + +------------------- +System Requirements +------------------- +Similar to Tcl requirements, Eggdrop requires both python and python development libraries to be installed on the host machine. On Debian/Ubuntu machines, this requires the packages python-dev AND python-is-python3 to be installed. The python-is-python3 updates symlinks on the host system that allow Eggdrop to find it. + +-------------- +Loading Python +-------------- + +Put this line into your Eggdrop configuration file to load the python module:: + + loadmodule python + +To load a python script from your config file, place the .py file in the scripts/ folder and add the following line to your config:: + + pysource scripts/myscript.py + +----------------------- +Eggdrop Python Commands +----------------------- + +The Python module is built to use the existing core Tcl commands integrated into Eggdrop via the ``eggdrop.tcl`` module. To call an existing Tcl command from Python, you can either load the entire catalog by running ``import eggdrop.tcl``, or be more specific by ``from eggdrop.tcl import putserv, putlog, chanlist``, etc. + +Arguments to the Tcl functions are automatically converted as follows: + +* ``None`` is converted to an empty Tcl object (the empty string, ``""``) +* ``List`` and ``Tuple`` is converted to a ``Tcl list`` +* ``Dict`` is converted to a ``Tcl dictionary`` +* Everything else is converted to a string using the str() method + +Return values from Tcl functions must be manually converted: + +* ``""`` the empty string is automatically converted to None +* everything else is returned as string +* ``Tcl list`` as string can be converted to a Python ``List`` using ``parse_tcl_list`` +* ``Tcl dictionary`` as string can be converted to a Python ``Dict`` using ``parse_tcl_list`` + +^^^^^^^^^^^^^^^^ +bind +^^^^^^^^^^^^^^^^ + +An important difference to note is that Eggdrop Python has its own ``bind`` command implemented. You will generally want to create binds using the Python ``bind`` command and not import bind from eggdrop.tcl because a Python bind will call a Python function, whereas using the Tcl bind will call a Tcl function (not one from the script you are writing). + +The python version of the bind command is used to create a bind that triggers a python function. The python bind takes the same arguments as the Tcl binds, but here each argument is passed individually. For example, a bind that would look like ``bind pub * !foo myproc`` in Tcl is written as ``bind("pub", "*", "!foo", myproc)``. For more information on Eggsrop bind argument syntax please see :ref:`bind_types`. The eggdrop.tcl.bind command should not be used as it will attempt to call a Tcl proc. + +^^^^^^^^^^^^^^^^^^^^^^^ +parse_tcl_list +^^^^^^^^^^^^^^^^^^^^^^^ + +When a python script calls a Tcl command that returns a list via the eggdrop.tcl module, the return value will be a Tcl-formatted list- also simply known as a string. The ``parse_tcl_list`` command will convert the Tcl-formatted list into a Python list, which can then freely be used within the Python script. + +^^^^^^^^^^^^^^^^^^^^^^^ +parse_tcl_dict +^^^^^^^^^^^^^^^^^^^^^^^ + +When a python script calls a Tcl command that returns a dict via the eggdrop.tcl module, the return value will be a Tcl-formatted dict- also simply known as a string. The ``parse_tcl_dict`` command will convert the Tcl-formatted dict into a Python list, which can then freely be used within the Python script. + +-------------------------------- +Writing an Eggdrop Python script +-------------------------------- + +Some example scripts, complete with documentation, are included with the Python module that ships with Eggdrop (src/mod/python.mod/scripts). These scripts are included to help demonstrate script formatting and usage. The scripts are: + + +.. glossary:: + + bestfriend.py + This example script demonstrates how to use the parse_tcl_list() python command to convert a list returned by a Tcl command into a list that is usable by Python. + + greet.py + This is a very basic script that demonstrates how a Python script with binds can be run by Eggdrop. + + imdb.py + This script shows how to use an existing third-party module to extend a Python script, in this case retrieving information from imdb.com. + + listtls.py + This script demonstrates how to use parse-tcl_list() and parse_tcl_dict() to convert a list of dicts provided by Tcl into something that is usable by Python. + + urltitle.py + This script shows how to use an existing third-party module to extend a Python script, in this case using an http parser to collect title information from a provided web page. + + +^^^^^^^^^^^^^^ +Header section +^^^^^^^^^^^^^^ + +Python is able to call any Tcl command by importing the ``eggdrop`` module. For example, to use the ``putlog`` command in a python script, you would import it as:: + + from eggdrop.tcl import putlog + +and then call it using:: + + putlog("This is a logged message") + + +An important difference to note is that Eggdrop Python has its own ``bind`` command implemented. You will generally want to create binds using the Python ``bind`` command and not import bind from eggdrop.tcl because a Python bind will call a Python function, whereas using the Tcl bind will call a Tcl function (not one from the script you are writing). + +Where does python print go? + +------------------------------------- +Writing a module for use with Eggdrop +------------------------------------- + +This is how you import a module for use with an egg python script. + +Copyright (C) 2000 - 2024 Eggheads Development Team + diff --git a/doc/sphinx_source/using/tcl-commands.rst b/doc/sphinx_source/using/tcl-commands.rst index 7953dccbd..6a662052c 100644 --- a/doc/sphinx_source/using/tcl-commands.rst +++ b/doc/sphinx_source/using/tcl-commands.rst @@ -1136,7 +1136,7 @@ nick2hand [channel] Module: irc ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -account2nicks [channel] +account2nicks [channel] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Returns: a de-duplicated Tcl list of the nickname(s) on the specified channel (if one is specified) whose nickname matches the given account; "" is returned if no match is found. This command will only work if a server supports (and Eggdrop has enabled) the account-notify and extended-join capabilities, and the server understands WHOX requests (also known as raw 354 responses). If no channel is specified, all channels are checked. diff --git a/eggdrop-basic.conf b/eggdrop-basic.conf index d14753d0e..849575610 100755 --- a/eggdrop-basic.conf +++ b/eggdrop-basic.conf @@ -300,9 +300,8 @@ set ssl-capath "/etc/ssl/" ## Eggdrop, things change. ## This path specifies the path were Eggdrop should look for its modules. -## If you run the bot from the compilation directory, you will want to set -## this to "". If you use 'make install' (like all good kiddies do ;), this -## is a fine default. Otherwise, use your head :) +## If you use 'make install' (like all good kiddies do ;), this is a fine +## default. Otherwise, use your head :) set mod-path "modules/" #### CHANNELS MODULE #### @@ -416,10 +415,7 @@ if {[file exists aclocal.m4]} { die {You are attempting to run Eggdrop from the if {[info exists net-type]} { switch -- ${net-type} { - "EFnet" { - # EFnet - source scripts/quotepong.tcl - } + "EFnet" - "0" { # EFnet source scripts/quotepong.tcl diff --git a/eggdrop.conf b/eggdrop.conf index 86ac99e64..852758286 100755 --- a/eggdrop.conf +++ b/eggdrop.conf @@ -605,9 +605,8 @@ die "Please make sure you edit your config file completely." # Eggdrop, things change. # This path specifies the path were Eggdrop should look for its modules. -# If you run the bot from the compilation directory, you will want to set -# this to "". If you use 'make install' (like all good kiddies do ;), this -# is a fine default. Otherwise, use your head :) +# If you use 'make install' (like all good kiddies do ;), this is a fine +# default. Otherwise, use your head :) set mod-path "modules/" @@ -656,6 +655,7 @@ loadmodule pbkdf2 # This setting is planned to be enabled by default in Eggdrop 2.0. #set remove-pass 0 + #### BLOWFISH MODULE #### # # This module is planned to be removed in Eggdrop 2.0 @@ -676,21 +676,14 @@ loadmodule blowfish set blowfish-use-mode cbc -#### DNS MODULE (Deprecated) #### - -## This module provided asynchronous dns support, but as of v1.9.2, this -## functionality was moved into the core code. If you are having issues with the -## new DNS functionality, or just want to continue using this module, compile -## Eggdrop with the --disable-tdns flag (./configure --disdable-tdns). +#### PYTHON MODULE ##### # -## You really probably don't want to uncomment this!!!! -# -#loadmodule dns -#set dns-servers "8.8.8.8 1.1.1.1 185.222.222.222" -#set dns-cache 86400 -#set dns-negcache 600 -#set dns-maxsends 4 -#set dns-retrydelay 3 +# This module gives Eggdrop the ability to run python scripts. if loaded, +# Python scripts can be loaded at the end of the config file using the pysouce +# command to tell Eggdrop where the file is loaded. The module requires Python +# version 3.8 or higher to run. To load the python module, uncomment it below. +#loadmodule python + #### CHANNELS MODULE #### @@ -1448,6 +1441,7 @@ set xfer-timeout 30 # be v1.9.0 or higher). #set sharefail-unlink 1 + #### SHARE MODULE #### # This module provides userfile sharing support between two directly @@ -1710,10 +1704,7 @@ loadhelp userinfo.help if {[info exists net-type]} { switch -- ${net-type} { - "EFnet" { - # EFnet - source scripts/quotepong.tcl - } + "EFnet" - "0" { # EFnet source scripts/quotepong.tcl diff --git a/misc/modconfig b/misc/modconfig index 0fd07b063..a22acd9dd 100755 --- a/misc/modconfig +++ b/misc/modconfig @@ -274,7 +274,7 @@ xdetect-modules) mc_new_mod_state=enabled fi fi - if test "${mc_new_mod_state}" = enabled; then + if test "${mc_new_mod_state}" = enabled && test -n "`find $mc_mod_bin_dir/${mc_mod}.mod -name \*.c`"; then ${mc_self_call} -q add ${mc_mod} else ${mc_self_call} -q del ${mc_mod} diff --git a/misc/updatecopyright b/misc/updatecopyright index a17b5edaf..a220e45d0 100755 --- a/misc/updatecopyright +++ b/misc/updatecopyright @@ -49,8 +49,8 @@ update_copyright() { mv ${i}_ $i fi # Cats and Dogs - sed -i '/Eggdrop v%s (C) 1997 Robey Pointer/c\ "Eggdrop v%s (C) 1997 Robey Pointer (C) 2010-'$YEAR' Eggheads",' src/main.c - sed -i '/Eggdrop v%s+%s (C) 1997 Robey Pointer/c\ "Eggdrop v%s+%s (C) 1997 Robey Pointer (C) 2010-'$YEAR' Eggheads",' src/main.c + sed -i '/Eggdrop v" EGG_STRINGVER " (C) 1997 Robey Pointer (C) 1999-/c\ "Eggdrop v" EGG_STRINGVER " (C) 1997 Robey Pointer (C) 1999-'$YEAR' Eggheads Development Team",' src/main.c + sed -i '/Eggdrop v" EGG_STRINGVER "+" EGG_PATCH " (C) 1997 Robey Pointer (C) 1999-/c\ "Eggdrop v" EGG_STRINGVER "+" EGG_PATCH " (C) 1997 Robey Pointer (C) 1999-'$YEAR' Eggheads Development Team",' src/main.c } diff --git a/src/Makefile.in b/src/Makefile.in index 6c6be3ac1..21e359131 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -6,6 +6,7 @@ srcdir = @srcdir@ VPATH = @srcdir@ @SET_MAKE@ +EGGEXEC = @EGGEXEC@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ @@ -18,6 +19,8 @@ CFLAGS = @CFLAGS@ -I.. -I$(top_srcdir) @SSL_INCLUDES@ @DEFS@ $(CFLGS) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ +XLIBS = @SSL_LIBS@ @TCL_LIB_SPEC@ @LIBS@ + eggdrop_objs = bg.o botcmd.o botmsg.o botnet.o chanprog.o cmds.o dcc.o \ dccutil.o dns.o flags.o language.o match.o main.o mem.o misc.o misc_file.o \ modules.o net.o rfc1459.o tcl.o tcldcc.o tclhash.o tclmisc.o tcluser.o \ @@ -173,7 +176,8 @@ modules.o: modules.c main.h ../config.h ../eggint.h ../lush.h lang.h \ net.o: net.c main.h ../config.h ../eggint.h ../lush.h lang.h eggdrop.h \ compat/in6.h flags.h proto.h misc_file.h cmdt.h tclegg.h tclhash.h \ chan.h users.h compat/compat.h compat/base64.h compat/inet_aton.h \ - ../src/main.h compat/snprintf.h compat/explicit_bzero.h compat/strlcpy.h + ../src/main.h compat/snprintf.h compat/explicit_bzero.h compat/strlcpy.h \ + modules.h mod/modvals.h rfc1459.o: rfc1459.c main.h ../config.h ../eggint.h ../lush.h lang.h \ eggdrop.h compat/in6.h flags.h proto.h misc_file.h cmdt.h tclegg.h \ tclhash.h chan.h users.h compat/compat.h compat/base64.h \ diff --git a/src/chan.h b/src/chan.h index 19a56e5a1..31b639834 100644 --- a/src/chan.h +++ b/src/chan.h @@ -50,8 +50,8 @@ typedef struct memstruct { time_t split; /* in case they were just netsplit */ time_t last; /* for measuring idle time */ time_t delay; /* for delayed autoop */ - struct userrec *user; - int tried_getuser; + struct userrec *user; /* cached user lookup */ + int tried_getuser; /* negative user lookup cache */ struct memstruct *next; } memberlist; diff --git a/src/chanprog.c b/src/chanprog.c index e8205f17b..f589593fb 100644 --- a/src/chanprog.c +++ b/src/chanprog.c @@ -116,34 +116,13 @@ struct chanset_t *findchan_by_dname(const char *name) return NULL; } - -/* - * "caching" functions - */ - -/* Shortcut for get_user_by_host -- might have user record in one - * of the channel caches. - */ -struct userrec *check_chanlist(const char *host) -{ - char *nick, *uhost, buf[UHOSTLEN]; - memberlist *m; - struct chanset_t *chan; - - strlcpy(buf, host, sizeof buf); - uhost = buf; - nick = splitnick(&uhost); - for (chan = chanset; chan; chan = chan->next) - for (m = chan->channel.member; m && m->nick[0]; m = m->next) - if (!rfc_casecmp(nick, m->nick) && !strcasecmp(uhost, m->userhost)) - return m->user; - return NULL; -} - /* Clear the user pointers in the chanlists. * - * Necessary when a hostmask is added/removed, a user is added or a new - * userfile is loaded. + * Necessary when: + * - a hostmask is added/removed + * - an account is added/removed + * - a user is added + * - new userfile is loaded */ void clear_chanlist(void) { @@ -159,8 +138,9 @@ void clear_chanlist(void) /* Clear the user pointer of a specific nick in the chanlists. * - * Necessary when a hostmask is added/removed, a nick changes, etc. - * Does not completely invalidate the channel cache like clear_chanlist(). + * Necessary when: + * - their hostmask changed (chghost) + * - their account changed */ void clear_chanlist_member(const char *nick) { @@ -176,23 +156,6 @@ void clear_chanlist_member(const char *nick) } } -/* If this user@host is in a channel, set it (it was null) - */ -void set_chanlist(const char *host, struct userrec *rec) -{ - char *nick, *uhost, buf[UHOSTLEN]; - memberlist *m; - struct chanset_t *chan; - - strlcpy(buf, host, sizeof buf); - uhost = buf; - nick = splitnick(&uhost); - for (chan = chanset; chan; chan = chan->next) - for (m = chan->channel.member; m && m->nick[0]; m = m->next) - if (!rfc_casecmp(nick, m->nick) && !strcasecmp(uhost, m->userhost)) - m->user = rec; -} - /* Calculate the memory we should be using */ int expmem_chanprog() diff --git a/src/cmds.c b/src/cmds.c index e1730507a..507c69687 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -1908,11 +1908,11 @@ static int add_to_handle(struct userrec *u, int idx, char *handle, char *host, i } } if ( !type && !glob_botmast(fr) && !chan_master(fr) && get_user_by_host(host)) { - dprintf(idx, "You cannot add %s matching another user!\n", - type ? "an account" : "a host"); + dprintf(idx, "You cannot add a host matching another user!\n"); return 1; } if (type) { + // host-variable contains account u2 = get_user_by_account(host); if (u2) { dprintf(idx, "That account already exists for user %s\n", u2->handle); @@ -1920,6 +1920,7 @@ static int add_to_handle(struct userrec *u, int idx, char *handle, char *host, i } addaccount_by_handle(handle, host); } else { + // host for (q = get_user(&USERENTRY_HOSTS, u); q; q = q->next) { if (!strcasecmp(q->extra, host)) { dprintf(idx, "That %s is already there.\n", diff --git a/src/eggdrop.h b/src/eggdrop.h index cca60c09a..c91ae91e2 100644 --- a/src/eggdrop.h +++ b/src/eggdrop.h @@ -183,12 +183,8 @@ #endif /* Almost every module needs some sort of time thingy, so... */ -#ifdef HAVE_SYS_TIME_H -# include -#else -# include -#endif - +#include /* gettimeofday() POSIX 2001 */ +#include /* POSIX 2001 */ /* Yikes...who would have thought finding a usable random() would be so much * trouble? diff --git a/src/main.c b/src/main.c index 8d2874f62..0b321d025 100644 --- a/src/main.c +++ b/src/main.c @@ -53,12 +53,6 @@ #include #include -#ifdef HAVE_SYS_TIME_H -# include -#else -# include -#endif - #ifdef STOP_UAC /* OSF/1 complains a lot */ # include # define UAC_NOPRINT 0x00000001 /* Don't report unaligned fixups */ @@ -129,7 +123,7 @@ int make_userfile = 0; /* Using bot in userfile-creation mode? */ int save_users_at = 0; /* Minutes past the hour to save the userfile? */ int notify_users_at = 0; /* Minutes past the hour to notify users of notes? */ -char version[81]; /* Version info (long form) */ +char version[128]; /* Version info (long form) */ char ver[41]; /* Version info (short form) */ volatile sig_atomic_t do_restart = 0; /* .restart has been called, restart ASAP */ @@ -722,7 +716,8 @@ int init_userent(); int init_misc(); int init_bots(); int init_modules(); -void init_tcl(int, char **); +void init_tcl0(int, char **); +void init_tcl1(int, char **); void init_language(int); #ifdef TLS int ssl_init(); @@ -893,7 +888,7 @@ static void mainloop(int toplevel) } kill_tcl(); - init_tcl(argc, argv); + init_tcl1(argc, argv); init_language(0); /* this resets our modules which we didn't unload (encryption and uptime) */ @@ -981,15 +976,15 @@ int main(int arg_c, char **arg_v) #ifdef EGG_PATCH egg_snprintf(egg_version, sizeof egg_version, "%s+%s %u", EGG_STRINGVER, EGG_PATCH, egg_numver); egg_snprintf(ver, sizeof ver, "eggdrop v%s+%s", EGG_STRINGVER, EGG_PATCH); - egg_snprintf(version, sizeof version, - "Eggdrop v%s+%s (C) 1997 Robey Pointer (C) 2010-2024 Eggheads", - EGG_STRINGVER, EGG_PATCH); + strlcpy(version, + "Eggdrop v" EGG_STRINGVER "+" EGG_PATCH " (C) 1997 Robey Pointer (C) 1999-2024 Eggheads Development Team", + sizeof version); #else egg_snprintf(egg_version, sizeof egg_version, "%s %u", EGG_STRINGVER, egg_numver); egg_snprintf(ver, sizeof ver, "eggdrop v%s", EGG_STRINGVER); - egg_snprintf(version, sizeof version, - "Eggdrop v%s (C) 1997 Robey Pointer (C) 2010-2024 Eggheads", - EGG_STRINGVER); + strlcpy(version, + "Eggdrop v" EGG_STRINGVER " (C) 1997 Robey Pointer (C) 1999-2024 Eggheads Development Team", + sizeof version); #endif /* For OSF/1 */ @@ -1028,6 +1023,10 @@ int main(int arg_c, char **arg_v) sigaction(SIGILL, &sv, NULL); sv.sa_handler = got_alarm; sigaction(SIGALRM, &sv, NULL); + // Added for python.mod because the _signal handler otherwise overwrites it + // see https://discuss.python.org/t/asyncio-skipping-signal-handling-setup-during-import-for-python-embedded-context/37054/6 + sv.sa_handler = got_term; + sigaction(SIGINT, &sv, NULL); /* Initialize variables and stuff */ now = time(NULL); @@ -1037,6 +1036,7 @@ int main(int arg_c, char **arg_v) init_mem(); if (argc > 1) do_arg(); + init_tcl0(argc, argv); init_language(1); printf("\n%s\n", version); @@ -1056,7 +1056,7 @@ int main(int arg_c, char **arg_v) init_modules(); if (backgrd) bg_prepare_split(); - init_tcl(argc, argv); + init_tcl1(argc, argv); init_language(0); #ifdef STATIC link_statics(); diff --git a/src/main.h b/src/main.h index f8f2b5032..79d388492 100644 --- a/src/main.h +++ b/src/main.h @@ -41,15 +41,18 @@ #include "eggint.h" #include "lush.h" +#ifndef TCL_SIZE_MAX + typedef int Tcl_Size; +# define Tcl_GetSizeIntFromObj Tcl_GetIntFromObj +# define TCL_SIZE_MAX INT_MAX +# define TCL_SIZE_MODIFIER "" +#endif + #ifndef TCL_PATCH_LEVEL # define TCL_PATCH_LEVEL "*unknown*" #endif -#ifdef CONST -# define EGG_CONST CONST -#else -# define EGG_CONST -#endif +#define EGG_CONST const #ifdef CONST86 # define TCL_CONST86 CONST86 diff --git a/src/mod/channels.mod/channels.c b/src/mod/channels.mod/channels.c index 95fed762b..d5d849879 100644 --- a/src/mod/channels.mod/channels.c +++ b/src/mod/channels.mod/channels.c @@ -737,7 +737,7 @@ static char *traced_globchanset(ClientData cdata, Tcl_Interp *irp, EGG_CONST char *name1, EGG_CONST char *name2, int flags) { - int i, items; + Tcl_Size i, items; char *t, *s; EGG_CONST char **item, *s2; diff --git a/src/mod/channels.mod/cmdschan.c b/src/mod/channels.mod/cmdschan.c index 4d96630a7..d613f43a9 100644 --- a/src/mod/channels.mod/cmdschan.c +++ b/src/mod/channels.mod/cmdschan.c @@ -1191,7 +1191,7 @@ static void cmd_mns_chrec(struct userrec *u, int idx, char *par) static void cmd_pls_chan(struct userrec *u, int idx, char *par) { - int i, argc; + Tcl_Size i, argc; EGG_CONST char **argv; char *chname; struct chanset_t *chan; diff --git a/src/mod/channels.mod/tclchan.c b/src/mod/channels.mod/tclchan.c index 512702703..f40f9f8d2 100644 --- a/src/mod/channels.mod/tclchan.c +++ b/src/mod/channels.mod/tclchan.c @@ -1013,7 +1013,7 @@ static int tcl_channel_getlist(Tcl_Interp *irp, struct chanset_t *chan) { char s[121], *str; EGG_CONST char **argv = NULL; - int argc = 0; + Tcl_Size argc = 0; struct udef_struct *ul; /* String values first */ @@ -1133,7 +1133,7 @@ static int tcl_channel_get(Tcl_Interp *irp, struct chanset_t *chan, { char s[121], *str = NULL; EGG_CONST char **argv = NULL; - int argc = 0; + Tcl_Size argc = 0; struct udef_struct *ul; if (!strcmp(setting, "chanmode")) @@ -1998,17 +1998,17 @@ static void init_masklist(masklist *m) static void init_channel(struct chanset_t *chan, int reset) { int flags = reset ? reset : CHAN_RESETALL; + memberlist *m, *m1; if (flags & CHAN_RESETWHO) { - if (chan->channel.member) { - nfree(chan->channel.member); + for (m = chan->channel.member; m; m = m1) { + m1 = m->next; + nfree(m); } chan->channel.members = 0; chan->channel.member = nmalloc(sizeof *chan->channel.member); /* Since we don't have channel_malloc, manually bzero */ egg_bzero(chan->channel.member, sizeof *chan->channel.member); - chan->channel.member->nick[0] = 0; - chan->channel.member->next = NULL; } if (flags & CHAN_RESETMODES) { @@ -2089,7 +2089,7 @@ static void clear_channel(struct chanset_t *chan, int reset) */ static int tcl_channel_add(Tcl_Interp *irp, char *newname, char *options) { - int items; + Tcl_Size items; int ret = TCL_OK; int join = 0; char buf[2048], buf2[256]; diff --git a/src/mod/channels.mod/userchan.c b/src/mod/channels.mod/userchan.c index 12d5c3202..2bac2ac3a 100644 --- a/src/mod/channels.mod/userchan.c +++ b/src/mod/channels.mod/userchan.c @@ -1270,12 +1270,7 @@ static int expired_mask(struct chanset_t *chan, char *who) * present in the channel and has op. */ - if (m->user) - u = m->user; - else { - simple_sprintf(buf, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(buf); - } + u = get_user_from_member(m); /* Do not expire masks set by bots. */ if (u && u->flags & USER_BOT) return 0; diff --git a/src/mod/compress.mod/configure b/src/mod/compress.mod/configure index 2c3f4c0cc..2d3dc6c26 100755 --- a/src/mod/compress.mod/configure +++ b/src/mod/compress.mod/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac 98f8972a. +# From configure.ac 9068a673. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for Eggdrop Compress Module 1.9.5. # diff --git a/src/mod/dns.mod/configure b/src/mod/dns.mod/configure index 07c7b3b57..7a99e8b4f 100755 --- a/src/mod/dns.mod/configure +++ b/src/mod/dns.mod/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac 98f8972a. +# From configure.ac 9068a673. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for Eggdrop DNS Module 1.9.5. # diff --git a/src/mod/filesys.mod/filesys.c b/src/mod/filesys.mod/filesys.c index 1c12721ba..dcaafef76 100644 --- a/src/mod/filesys.mod/filesys.c +++ b/src/mod/filesys.mod/filesys.c @@ -48,12 +48,6 @@ # endif #endif -#ifdef HAVE_SYS_TIME_H -# include -#else -# include -#endif - #include "filedb3.h" #include "filesys.h" #include "src/tandem.h" diff --git a/src/mod/irc.mod/chan.c b/src/mod/irc.mod/chan.c index 0a80927e9..9124d428c 100644 --- a/src/mod/irc.mod/chan.c +++ b/src/mod/irc.mod/chan.c @@ -110,12 +110,14 @@ static void setaccount(char *nick, char *account) } else { putlog(LOG_MODES, chan->dname, "%s!%s logged in to their account %s", nick, m->userhost, account); } - check_tcl_account(m->nick, m->userhost, m->user, chan->dname, account); + check_tcl_account(m->nick, m->userhost, get_user_from_member(m), chan->dname, account); } strlcpy(m->account, account, sizeof m->account); } } } + /* Username for nick could be different after account change, invalidate cache */ + clear_chanlist_member(nick); } /* Returns the current channel mode. @@ -207,9 +209,11 @@ static void do_mask(struct chanset_t *chan, masklist *m, char *mask, char mode) /* This is a clone of detect_flood, but works for channel specificity now * and handles kick & deop as well. + * + * victim for flood-deop, account for flood-join */ static int detect_chan_flood(char *floodnick, char *floodhost, char *from, - struct chanset_t *chan, int which, char *victim) + struct chanset_t *chan, int which, char *victim_or_account) { char h[NICKMAX+UHOSTLEN+1], ftype[12], *p; struct userrec *u; @@ -236,7 +240,8 @@ static int detect_chan_flood(char *floodnick, char *floodhost, char *from, if (!m && (which != FLOOD_JOIN)) return 0; - get_user_flagrec(get_user_by_host(from), &fr, chan->dname); + u = lookup_user_record(m, victim_or_account, from); + get_user_flagrec(u, &fr, chan->dname); if (glob_bot(fr) || ((which == FLOOD_DEOP) && (glob_master(fr) || chan_master(fr)) && (glob_friend(fr) || chan_friend(fr))) || ((which == FLOOD_KICK) && (glob_master(fr) || chan_master(fr)) && @@ -307,10 +312,10 @@ static int detect_chan_flood(char *floodnick, char *floodhost, char *from, } /* Deop'n the same person, sillyness ;) - so just ignore it */ if (which == FLOOD_DEOP) { - if (!rfc_casecmp(chan->deopd, victim)) + if (!rfc_casecmp(chan->deopd, victim_or_account)) return 0; else - strlcpy(chan->deopd, victim, sizeof chan->deopd); + strlcpy(chan->deopd, victim_or_account, sizeof chan->deopd); } chan->floodnum[which]++; if (chan->floodnum[which] >= thr) { /* FLOOD */ @@ -320,7 +325,6 @@ static int detect_chan_flood(char *floodnick, char *floodhost, char *from, chan->floodwho[which][0] = 0; if (which == FLOOD_DEOP) chan->deopd[0] = 0; - u = get_user_by_host(from); if (check_tcl_flud(floodnick, floodhost, u, ftype, chan->dname)) return 0; switch (which) { @@ -425,8 +429,7 @@ static void kick_all(struct chanset_t *chan, char *hostmask, char *comment, flushed = 0; kicknick[0] = 0; for (m = chan->channel.member; m && m->nick[0]; m = m->next) { - sprintf(s, "%s!%s", m->nick, m->userhost); - get_user_flagrec(m->user ? m->user : get_user_by_host(s), &fr, chan->dname); + get_user_flagrec(get_user_from_member(m), &fr, chan->dname); if ((me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) && match_addr(hostmask, s) && !chan_sentkick(m) && !match_my_nick(m->nick) && !chan_issplit(m) && @@ -474,10 +477,7 @@ static void refresh_ban_kick(struct chanset_t *chan, char *user, char *nick) if (match_addr(b->mask, user)) { struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; char c[512]; /* The ban comment. */ - char s[NICKMAX+UHOSTLEN+1]; - - sprintf(s, "%s!%s", m->nick, m->userhost); - get_user_flagrec(m->user ? m->user : get_user_by_host(s), &fr, + get_user_flagrec(get_user_from_member(m), &fr, chan->dname); if (!glob_friend(fr) && !chan_friend(fr)) { add_mode(chan, '-', 'o', nick); /* Guess it can't hurt. */ @@ -869,7 +869,7 @@ static void check_this_member(struct chanset_t *chan, char *nick, (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) { check_exemptlist(chan, s); quickban(chan, m->userhost); - p = get_user(&USERENTRY_COMMENT, m->user); + p = get_user(&USERENTRY_COMMENT, get_user_from_member(m)); dprintf(DP_SERVER, "KICK %s %s :%s\n", chan->name, m->nick, p ? p : IRC_POLITEKICK); m->flags |= SENTKICK; @@ -888,8 +888,7 @@ static void check_this_user(char *hand, int delete, char *host) for (chan = chanset; chan; chan = chan->next) for (m = chan->channel.member; m && m->nick[0]; m = m->next) { - sprintf(s, "%s!%s", m->nick, m->userhost); - u = m->user ? m->user : get_user_by_host(s); + u = get_user_from_member(m); if ((u && !strcasecmp(u->handle, hand) && delete < 2) || (!u && delete == 2 && match_addr(host, s))) { u = delete ? NULL : u; @@ -904,8 +903,8 @@ static void check_this_user(char *hand, int delete, char *host) static void recheck_channel(struct chanset_t *chan, int dobans) { memberlist *m; - char s[NICKMAX+UHOSTLEN+1]; struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; + struct userrec *u; static int stacking = 0; int stop_reset = 0; @@ -915,12 +914,8 @@ static void recheck_channel(struct chanset_t *chan, int dobans) stacking++; /* Okay, sort through who needs to be deopped. */ for (m = chan->channel.member; m && m->nick[0]; m = m->next) { - sprintf(s, "%s!%s", m->nick, m->userhost); - if (!m->user && !m->tried_getuser) { - m->tried_getuser = 1; - m->user = get_user_by_host(s); - } - get_user_flagrec(m->user, &fr, chan->dname); + u = get_user_from_member(m); + get_user_flagrec(u, &fr, chan->dname); if (glob_bot(fr) && chan_hasop(m) && !match_my_nick(m->nick)) stop_reset = 1; /* Perhaps we were halfop and tried to halfop/kick the user earlier but @@ -1084,7 +1079,6 @@ static int got352or4(struct chanset_t *chan, char *user, char *host, simple_sprintf(m->userhost, "%s@%s", user, host); simple_sprintf(userhost, "%s!%s", nick, m->userhost); /* Combine n!u@h */ - m->user = NULL; /* No handle match (yet) */ if (match_my_nick(nick)) /* Is it me? */ strcpy(botuserhost, m->userhost); /* Yes, save my own userhost */ m->flags |= WHO_SYNCED; @@ -1115,7 +1109,6 @@ static int got352or4(struct chanset_t *chan, char *user, char *host, if (chan->need_op[0]) do_tcl("need-op", chan->need_op); } - m->user = get_user_by_host(userhost); /* Update accountname in channel records, 0 means logged out */ /* A 0 is not a change from "" */ @@ -1214,13 +1207,13 @@ static int got354(char *from, char *msg) } return 0; } - + /* React to IRCv3 CHGHOST command. CHGHOST changes the hostname and/or * ident of the user. Format: * :geo!awesome@eggdrop.com CHGHOST tehgeo foo.io * changes user hostmask to tehgeo@foo.io */ -static int gotchghost(char *from, char *msg){ +static int gotchghost(char *from, char *msg) { struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; struct userrec *u; struct chanset_t *chan; @@ -1234,20 +1227,21 @@ static int gotchghost(char *from, char *msg){ if (match_my_nick(nick)) { snprintf(botuserhost, UHOSTMAX, "%s@%s", ident, msg); } - u = get_user_by_host(from); /* Run the bind for each channel the user is on */ for (chan = chanset; chan; chan = chan->next) { chname = chan->dname; m = ismember(chan, nick); if (m) { + u = get_user_from_member(m); snprintf(m->userhost, sizeof m->userhost, "%s@%s", ident, msg); snprintf(mask, sizeof mask, "%s %s!%s@%s", chname, nick, ident, msg); check_tcl_chghost(nick, from, mask, u, chname, ident, msg); - get_user_flagrec(m->user ? m->user : get_user_by_host(s1), &fr, - chan->dname); + get_user_flagrec(u, &fr, chan->dname); check_this_member(chan, m->nick, &fr); } } + /* Username for nick could be different after host change, invalidate cache */ + clear_chanlist_member(nick); return 0; } @@ -1309,7 +1303,7 @@ static int got353(char *from, char *msg) } return 0; } - + /* React to 396 numeric (HOSTHIDDEN), sent when user mode +x (hostmasking) was * successfully set. Format: * :barjavel.freenode.net 396 BeerBot unaffiliated/geo/bot/beerbot :is now your hidden host (set by services.) @@ -1400,12 +1394,12 @@ static int gotaway(char *from, char *msg) strlcpy(s1, from, sizeof buf); nick = splitnick(&s1); - u = get_user_by_host(from); /* Run the bind for each channel the user is on */ for (chan = chanset; chan; chan = chan->next) { chname = chan->dname; m = ismember(chan, nick); if (m) { + u = get_user_from_member(m); snprintf(mask, sizeof mask, "%s %s", chname, from); check_tcl_ircaway(nick, from, mask, u, chname, msg); if (strlen(msg)) { @@ -1831,7 +1825,6 @@ static int gottopic(char *from, char *msg) chname = newsplit(&msg); fixcolon(msg); - u = get_user_by_host(from); nick = splitnick(&from); chan = findchan(chname); if (chan) { @@ -1841,6 +1834,7 @@ static int gottopic(char *from, char *msg) if (m != NULL) m->last = now; set_topic(chan, msg); + u = lookup_user_record(m, NULL, from); // TODO: get account from msgtags check_tcl_topc(nick, from, u, chan->dname, msg); } return 0; @@ -1942,28 +1936,27 @@ static void set_delay(struct chanset_t *chan, char *nick) */ static int gotjoin(char *from, char *channame) { - char *nick, *p, buf[UHOSTLEN], *uhost = buf, *chname; + char *nick, *p, buf[UHOSTLEN], *uhost = buf, *chname, *account = NULL; char *ch_dname = NULL; - int extjoin = 0; struct chanset_t *chan; memberlist *m; masklist *b; - struct capability *current; + int extjoin = 0; + struct capability *captmp; struct userrec *u; struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; - /* Check if extended-join CAP is enabled */ - current = cap; - while (current != NULL) { - if (!strcasecmp("extended-join", current->name)) { - extjoin = current->enabled ? 1 : 0; - } - current = current->next; - } + captmp = find_capability("extended-join"); + extjoin = captmp && captmp->enabled; + strlcpy(uhost, from, sizeof buf); nick = splitnick(&uhost); chname = newsplit(&channame); - if (!extjoin) { + if (extjoin) { + // :nick!user@host JOIN #chan account :realname + account = newsplit(&channame); + } else { + // :nick!user@host JOIN :#chan fixcolon(chname); } chan = findchan_by_dname(chname); @@ -2014,7 +2007,8 @@ static int gotjoin(char *from, char *channame) } } else if (!channel_pending(chan)) { chan->status &= ~CHAN_STOP_CYCLE; - detect_chan_flood(nick, uhost, from, chan, FLOOD_JOIN, NULL); + + detect_chan_flood(nick, uhost, from, chan, FLOOD_JOIN, extjoin ? account : NULL); chan = findchan(chname); if (!chan) { @@ -2027,9 +2021,6 @@ static int gotjoin(char *from, char *channame) /* The channel doesn't exist anymore, so get out of here. */ goto exit; - /* Grab last time joined before we update it */ - u = get_user_by_host(from); - get_user_flagrec(u, &fr, chan->dname); /* Lam: fix to work with !channels */ if (!channel_active(chan) && !match_my_nick(nick)) { /* uh, what?! i'm on the channel?! */ putlog(LOG_MISC, chan->dname, @@ -2041,6 +2032,8 @@ static int gotjoin(char *from, char *channame) } else { m = ismember(chan, nick); if (m && m->split && !strcasecmp(m->userhost, uhost)) { + u = get_user_from_member(m); + get_user_flagrec(u, &fr, chan->dname); check_tcl_rejn(nick, uhost, u, chan->dname); chan = findchan(chname); @@ -2055,12 +2048,11 @@ static int gotjoin(char *from, char *channame) goto exit; /* The tcl binding might have deleted the current user. Recheck. */ - u = get_user_by_host(from); + u = get_user_from_member(m); m->split = 0; m->last = now; m->delay = 0L; m->flags = (chan_hasop(m) ? WASOP : 0) | (chan_hashalfop(m) ? WASHALFOP : 0); - m->user = u; set_handle_laston(chan->dname, u, now); m->flags |= STOPWHO; putlog(LOG_JOIN, chan->dname, "%s (%s) returned to %s.", nick, uhost, @@ -2076,19 +2068,20 @@ static int gotjoin(char *from, char *channame) m->delay = 0L; strlcpy(m->nick, nick, sizeof m->nick); strlcpy(m->userhost, uhost, sizeof m->userhost); - m->user = u; m->flags |= STOPWHO; if (extjoin) { + u = lookup_user_record(m, account, from); /* calls check_tcl_account which can delete the channel */ - setaccount(nick, newsplit(&channame)); - + setaccount(nick, account); + if (!(chan = findchan(chname)) && !(chan = findchan_by_dname(ch_dname ? ch_dname : chname))) { /* The channel doesn't exist anymore, so get out of here. */ goto exit; } + } else { + u = lookup_user_record(find_member_from_nick(nick), NULL, from); // TODO: get account from msgtags } - check_tcl_join(nick, uhost, u, chan->dname); if (!(chan = findchan(chname)) && !(chan = findchan_by_dname(ch_dname ? ch_dname : chname))) { @@ -2098,7 +2091,6 @@ static int gotjoin(char *from, char *channame) /* The record saved in the channel record always gets updated, * so we can use that. */ - u = m->user; if (match_my_nick(nick)) { /* It was me joining! Need to update the channel record with the @@ -2129,9 +2121,9 @@ static int gotjoin(char *from, char *channame) if (u) { struct laston_info *li = 0; - cr = get_chanrec(m->user, chan->dname); + cr = get_chanrec(u, chan->dname); if (!cr && no_chanrec_info) - li = get_user(&USERENTRY_LASTON, m->user); + li = get_user(&USERENTRY_LASTON, u); if (channel_greet(chan) && use_info && ((cr && now - cr->laston > wait_info) || (no_chanrec_info && (!li || now - li->laston > wait_info)))) { @@ -2189,7 +2181,7 @@ static int gotjoin(char *from, char *channame) (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) { check_exemptlist(chan, from); quickban(chan, from); - p = get_user(&USERENTRY_COMMENT, m->user); + p = get_user(&USERENTRY_COMMENT, get_user_from_member(m)); dprintf(DP_MODE, "KICK %s %s :%s\n", chname, nick, (p && (p[0] != '@')) ? p : IRC_COMMENTKICK); m->flags |= SENTKICK; @@ -2249,6 +2241,7 @@ static int gotpart(char *from, char *msg) char *nick, *chname, *key; struct chanset_t *chan; struct userrec *u; + memberlist *m; chname = newsplit(&msg); fixcolon(chname); @@ -2260,8 +2253,9 @@ static int gotpart(char *from, char *msg) return 0; } if (chan && !channel_pending(chan)) { - u = get_user_by_host(from); nick = splitnick(&from); + m = ismember(chan, nick); + u = get_user_from_member(m); if (!channel_active(chan)) { /* whoa! */ putlog(LOG_MISC, chan->dname, @@ -2341,7 +2335,6 @@ static int gotkick(char *from, char *origmsg) } if (channel_active(chan)) { fixcolon(msg); - u = get_user_by_host(from); strlcpy(buf, from, sizeof buf); uhost = buf; whodid = splitnick(&uhost); @@ -2352,6 +2345,7 @@ static int gotkick(char *from, char *origmsg) return 0; m = ismember(chan, whodid); + u = lookup_user_record(m, NULL, from); // TODO: get account from msgtags if (m) m->last = now; /* This _needs_ to use chan->dname */ @@ -2368,7 +2362,7 @@ static int gotkick(char *from, char *origmsg) struct userrec *u2; simple_sprintf(s1, "%s!%s", m->nick, m->userhost); - u2 = get_user_by_host(s1); + u2 = get_user_from_member(m); set_handle_laston(chan->dname, u2, now); maybe_revenge(chan, from, s1, REVENGE_KICK); } @@ -2451,12 +2445,11 @@ static int gotnick(char *from, char *msg) m->flags &= ~(SENTKICK | SENTDEOP | SENTOP | SENTDEHALFOP | SENTHALFOP | SENTVOICE | SENTDEVOICE); /* nick-ban or nick is +k or something? */ - get_user_flagrec(m->user ? m->user : get_user_by_host(s1), &fr, - chan->dname); + u = get_user_from_member(m); + get_user_flagrec(u, &fr, chan->dname); check_this_member(chan, m->nick, &fr); /* Make sure this is in the loop, someone could have changed the record * in an earlier iteration of the loop. */ - u = get_user_by_host(from); found = 1; check_tcl_nick(nick, uhost, u, chan->dname, msg); @@ -2467,10 +2460,9 @@ static int gotnick(char *from, char *msg) } } if (!found) { - u = get_user_by_host(from); s1[0] = '*'; s1[1] = 0; - check_tcl_nick(nick, uhost, u, s1, msg); + check_tcl_nick(nick, uhost, NULL, s1, msg); } return 0; } @@ -2514,7 +2506,7 @@ static int gotquit(char *from, char *msg) chname = chan->dname; m = ismember(chan, nick); if (m) { - u = get_user_by_host(from2); + u = get_user_from_member(m); if (u) /* If you remove this, the bot will crash when the user record in * question is removed/modified during the tcl binds below, and the @@ -2612,7 +2604,7 @@ static int gotmsg(char *from, char *msg) ctcp_count++; if (ctcp[0] != ' ') { code = newsplit(&ctcp); - u = get_user_by_host(from); + u = lookup_user_record(find_member_from_nick(nick), NULL, from); // TODO: get account from msgtags if (!ignoring || trigger_on_ignore) { if (!check_tcl_ctcp(nick, uhost, u, to, code, ctcp)) { chan = findchan(realto); @@ -2704,8 +2696,7 @@ static int gotnotice(char *from, char *msg) fixcolon(msg); strlcpy(uhost, from, sizeof buf); nick = splitnick(&uhost); - u = get_user_by_host(from); - + u = lookup_user_record(find_member_from_nick(nick), NULL, from); // TODO: get account from msgtags /* Check for CTCP: */ p = strchr(msg, 1); while (p && *p) { diff --git a/src/mod/irc.mod/cmdsirc.c b/src/mod/irc.mod/cmdsirc.c index 1caefe53e..c9bf58ab1 100644 --- a/src/mod/irc.mod/cmdsirc.c +++ b/src/mod/irc.mod/cmdsirc.c @@ -68,13 +68,11 @@ static int has_oporhalfop(int idx, struct chanset_t *chan) */ static char *getnick(char *handle, struct chanset_t *chan) { - char s[UHOSTLEN]; struct userrec *u; memberlist *m; for (m = chan->channel.member; m && m->nick[0]; m = m->next) { - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - if ((u = get_user_by_host(s)) && !strcasecmp(u->handle, handle)) + if ((u = get_user_from_member(m)) && !strcasecmp(u->handle, handle)) return m->nick; } return NULL; @@ -163,8 +161,8 @@ static void cmd_kickban(struct userrec *u, int idx, char *par) struct chanset_t *chan; char *chname, *nick, *s1; memberlist *m; - char s[UHOSTLEN]; char bantype = 0; + char s[UHOSTLEN]; if (!par[0]) { dprintf(idx, "Usage: kickban [channel] [-|@] [reason]\n"); @@ -208,7 +206,7 @@ static void cmd_kickban(struct userrec *u, int idx, char *par) return; } egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s); + u = get_user_from_member(m); get_user_flagrec(u, &victim, chan->dname); if ((chan_op(victim) || (glob_op(victim) && !chan_deop(victim))) && !(chan_master(user) || glob_master(user))) { @@ -265,7 +263,6 @@ static void cmd_op(struct userrec *u, int idx, char *par) struct chanset_t *chan; char *nick; memberlist *m; - char s[UHOSTLEN]; nick = newsplit(&par); chan = get_channel(idx, par); @@ -294,8 +291,7 @@ static void cmd_op(struct userrec *u, int idx, char *par) dprintf(idx, "%s is not on %s.\n", nick, chan->dname); return; } - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s); + u = get_user_from_member(m); get_user_flagrec(u, &victim, chan->dname); if (chan_deop(victim) || (glob_deop(victim) && !glob_op(victim))) { dprintf(idx, "%s is currently being auto-deopped.\n", m->nick); @@ -315,7 +311,6 @@ static void cmd_deop(struct userrec *u, int idx, char *par) struct chanset_t *chan; char *nick; memberlist *m; - char s[UHOSTLEN]; nick = newsplit(&par); chan = get_channel(idx, par); @@ -348,8 +343,7 @@ static void cmd_deop(struct userrec *u, int idx, char *par) dprintf(idx, "I'm not going to deop myself.\n"); return; } - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s); + u = get_user_from_member(m); get_user_flagrec(u, &victim, chan->dname); if ((chan_master(victim) || glob_master(victim)) && !(chan_owner(user) || glob_owner(user))) { @@ -371,7 +365,6 @@ static void cmd_halfop(struct userrec *u, int idx, char *par) struct userrec *u2; char *nick; memberlist *m; - char s[UHOSTLEN]; nick = newsplit(&par); chan = get_channel(idx, par); @@ -386,8 +379,7 @@ static void cmd_halfop(struct userrec *u, int idx, char *par) get_user_flagrec(dcc[idx].user, &user, chan->dname); m = ismember(chan, nick); if (m && !chan_op(user) && (!glob_op(user) || chan_deop(user))) { - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u2 = m->user ? m->user : get_user_by_host(s); + u2 = get_user_from_member(m); if (!u2 || strcasecmp(u2->handle, dcc[idx].nick) || (!chan_halfop(user) && (!glob_halfop(user) || chan_dehalfop(user)))) { @@ -414,8 +406,7 @@ static void cmd_halfop(struct userrec *u, int idx, char *par) dprintf(idx, "%s is not on %s.\n", nick, chan->dname); return; } - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s); + u = get_user_from_member(m); get_user_flagrec(u, &victim, chan->dname); if (chan_dehalfop(victim) || (glob_dehalfop(victim) && !glob_halfop(victim))) { dprintf(idx, "%s is currently being auto-dehalfopped.\n", m->nick); @@ -437,7 +428,6 @@ static void cmd_dehalfop(struct userrec *u, int idx, char *par) struct userrec *u2; char *nick; memberlist *m; - char s[UHOSTLEN]; nick = newsplit(&par); chan = get_channel(idx, par); @@ -452,9 +442,7 @@ static void cmd_dehalfop(struct userrec *u, int idx, char *par) get_user_flagrec(dcc[idx].user, &user, chan->dname); m = ismember(chan, nick); if (m && !chan_op(user) && (!glob_op(user) || chan_deop(user))) { - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u2 = m->user ? m->user : get_user_by_host(s); - + u2 = get_user_from_member(m); if (!u2 || strcasecmp(u2->handle, dcc[idx].nick) || (!chan_halfop(user) && (!glob_halfop(user) || chan_dehalfop(user)))) { dprintf(idx, "You are not a channel op on %s.\n", chan->dname); @@ -484,8 +472,7 @@ static void cmd_dehalfop(struct userrec *u, int idx, char *par) dprintf(idx, "I'm not going to dehalfop myself.\n"); return; } - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s); + u = get_user_from_member(m); get_user_flagrec(u, &victim, chan->dname); if ((chan_master(victim) || glob_master(victim)) && !(chan_owner(user) || glob_owner(user))) { @@ -512,7 +499,6 @@ static void cmd_voice(struct userrec *u, int idx, char *par) struct userrec *u2; char *nick; memberlist *m; - char s[UHOSTLEN]; nick = newsplit(&par); chan = get_channel(idx, par); @@ -533,8 +519,7 @@ static void cmd_voice(struct userrec *u, int idx, char *par) * - stdarg */ if (m && !(chan_op(user) || chan_halfop(user) || (glob_op(user) && !chan_deop(user)) || (glob_halfop(user) && !chan_dehalfop(user)))) { - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u2 = m->user ? m->user : get_user_by_host(s); + u2 = get_user_from_member(m); if (!u2 || strcasecmp(u2->handle, dcc[idx].nick) || (!chan_voice(user) && (!glob_voice(user) || chan_quiet(user)))) { @@ -570,7 +555,6 @@ static void cmd_devoice(struct userrec *u, int idx, char *par) struct userrec *u2; char *nick; memberlist *m; - char s[UHOSTLEN]; nick = newsplit(&par); chan = get_channel(idx, par); @@ -586,8 +570,7 @@ static void cmd_devoice(struct userrec *u, int idx, char *par) m = ismember(chan, nick); if (m && !(chan_op(user) || chan_halfop(user) || (glob_op(user) && !chan_deop(user)) || (glob_halfop(user) && !chan_dehalfop(user)))) { - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u2 = m->user ? m->user : get_user_by_host(s); + u2 = get_user_from_member(m); if (!u2 || strcasecmp(u2->handle, dcc[idx].nick) || (!chan_voice(user) && (!glob_voice(user) || chan_quiet(user)))) { @@ -623,7 +606,6 @@ static void cmd_kick(struct userrec *u, int idx, char *par) struct chanset_t *chan; char *chname, *nick; memberlist *m; - char s[UHOSTLEN]; if (!par[0]) { dprintf(idx, "Usage: kick [channel] [reason]\n"); @@ -663,8 +645,7 @@ static void cmd_kick(struct userrec *u, int idx, char *par) chan->dname); return; } - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s); + u = get_user_from_member(m); get_user_flagrec(u, &victim, chan->dname); if ((chan_op(victim) || (glob_op(victim) && !chan_deop(victim))) && !(chan_master(user) || glob_master(user))) { @@ -748,8 +729,9 @@ static void cmd_channel(struct userrec *u, int idx, char *par) for (m = chan->channel.member; m && m->nick[0]; m = m->next) { if (strlen(m->nick) > maxnicklen) maxnicklen = strlen(m->nick); - if ((m->user) && (strlen(m->user->handle) > maxhandlen)) - maxhandlen = strlen(m->user->handle); + u = get_user_from_member(m); + if (u && (strlen(u->handle) > maxhandlen)) + maxhandlen = strlen(u->handle); } if (maxnicklen < 9) maxnicklen = 9; @@ -768,15 +750,13 @@ static void cmd_channel(struct userrec *u, int idx, char *par) strftime(s, 6, "%H:%M", localtime(&(m->joined))); } else strlcpy(s, " --- ", sizeof s); - if (m->user == NULL) { - egg_snprintf(s1, sizeof s1, "%s!%s", m->nick, m->userhost); - m->user = get_user_by_host(s1); - } - if (m->user == NULL) + egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); + u = get_user_from_member(m); + if (u == NULL) strlcpy(handle, "*", sizeof handle); else - strlcpy(handle, m->user->handle, sizeof handle); - get_user_flagrec(m->user, &user, chan->dname); + strlcpy(handle, u->handle, sizeof handle); + get_user_flagrec(u, &user, chan->dname); /* Determine status char to use */ if (glob_bot(user) && (glob_op(user) || chan_op(user))) atrflag = 'B'; @@ -1022,7 +1002,7 @@ static void cmd_adduser(struct userrec *u, int idx, char *par) if (strlen(hand) > HANDLEN) hand[HANDLEN] = 0; egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s); + u = get_user_from_member(m); if (u) { dprintf(idx, "%s is already known as %s.\n", nick, u->handle); return; @@ -1059,7 +1039,7 @@ static void cmd_adduser(struct userrec *u, int idx, char *par) static void cmd_deluser(struct userrec *u, int idx, char *par) { - char *nick, s[UHOSTLEN]; + char *nick; struct chanset_t *chan; memberlist *m = NULL; struct flag_record victim = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 }; @@ -1080,8 +1060,7 @@ static void cmd_deluser(struct userrec *u, int idx, char *par) return; } get_user_flagrec(u, &user, chan->dname); - egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s); + u = get_user_from_member(m); if (!u) { dprintf(idx, "%s is not a valid user.\n", nick); return; diff --git a/src/mod/irc.mod/irc.c b/src/mod/irc.mod/irc.c index 8cce81776..bc3f578e4 100644 --- a/src/mod/irc.mod/irc.c +++ b/src/mod/irc.mod/irc.c @@ -142,7 +142,6 @@ static void punish_badguy(struct chanset_t *chan, char *whobad, /* Set the offender +d */ if ((chan->revenge_mode > 0) && !(chan_deop(fr) || glob_deop(fr))) { char s[UHOSTLEN], s1[UHOSTLEN]; - memberlist *mx = NULL; /* Removing op */ if (chan_op(fr) || (glob_op(fr) && !chan_deop(fr))) { @@ -186,8 +185,6 @@ static void punish_badguy(struct chanset_t *chan, char *whobad, fr.chan = USER_DEOP; fr.udef_chan = 0; u = get_user_by_handle(userlist, s1); - if ((mx = ismember(chan, badnick))) - mx->user = u; set_user_flagrec(u, &fr, chan->dname); simple_sprintf(s, "(%s) %s (%s)", ct, reason, whobad); set_user(&USERENTRY_COMMENT, u, (void *) s); @@ -227,20 +224,25 @@ static void punish_badguy(struct chanset_t *chan, char *whobad, static void maybe_revenge(struct chanset_t *chan, char *whobad, char *whovictim, int type) { - char *badnick, *victim; + char *badnick, *victim, buf[NICKLEN + UHOSTLEN]; int mevictim; struct userrec *u, *u2; + memberlist *m; if (!chan || (type < 0)) return; /* Get info about offender */ - u = get_user_by_host(whobad); + strlcpy(buf, whobad, sizeof buf); badnick = splitnick(&whobad); + m = ismember(chan, badnick); + u = lookup_user_record(m, NULL, buf); // TODO: get account from msgtags /* Get info about victim */ - u2 = get_user_by_host(whovictim); + strlcpy(buf, whovictim, sizeof buf); victim = splitnick(&whovictim); + m = ismember(chan, victim); + u2 = lookup_user_record(m, NULL, buf); // TODO: get account from msgtags mevictim = match_my_nick(victim); /* Do we want to revenge? */ @@ -264,12 +266,10 @@ static void set_key(struct chanset_t *chan, char *k) static int hand_on_chan(struct chanset_t *chan, struct userrec *u) { - char s[NICKMAX+UHOSTLEN+1]; memberlist *m; for (m = chan->channel.member; m && m->nick[0]; m = m->next) { - sprintf(s, "%s!%s", m->nick, m->userhost); - if (u == get_user_by_host(s)) + if (u == get_user_from_member(m)) return 1; } return 0; @@ -531,7 +531,6 @@ static void status_log() static void check_lonely_channel(struct chanset_t *chan) { memberlist *m; - char s[NICKMAX+UHOSTLEN+1]; int i = 0; if (channel_pending(chan) || !channel_active(chan) || me_op(chan) || @@ -576,8 +575,7 @@ static void check_lonely_channel(struct chanset_t *chan) chan->status |= CHAN_WHINED; } for (m = chan->channel.member; m && m->nick[0]; m = m->next) { - sprintf(s, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s); + u = get_user_from_member(m); if (!match_my_nick(m->nick) && (!u || !(u->flags & USER_BOT))) { ok = 0; break; @@ -601,7 +599,7 @@ static void check_expired_chanstuff() { masklist *b, *e; memberlist *m, *n; - char *key, s[NICKMAX+UHOSTLEN+1]; + char *key; struct chanset_t *chan; struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; @@ -670,9 +668,7 @@ static void check_expired_chanstuff() for (m = chan->channel.member; m && m->nick[0]; m = m->next) if (now - m->last >= chan->idle_kick * 60 && !match_my_nick(m->nick) && !chan_issplit(m)) { - sprintf(s, "%s!%s", m->nick, m->userhost); - get_user_flagrec(m->user ? m->user : get_user_by_host(s), - &fr, chan->dname); + get_user_flagrec(get_user_from_member(m), &fr, chan->dname); if ((!(glob_bot(fr) || glob_friend(fr) || (glob_op(fr) && !chan_deop(fr)) || chan_friend(fr) || chan_op(fr))) && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) { @@ -685,9 +681,7 @@ static void check_expired_chanstuff() for (m = chan->channel.member; m && m->nick[0]; m = n) { n = m->next; if (m->split && now - m->split > wait_split) { - sprintf(s, "%s!%s", m->nick, m->userhost); - check_tcl_sign(m->nick, m->userhost, - m->user ? m->user : get_user_by_host(s), + check_tcl_sign(m->nick, m->userhost, get_user_from_member(m), chan->dname, "lost in the netsplit"); putlog(LOG_JOIN, chan->dname, "%s (%s) got lost in the net-split.", m->nick, m->userhost); @@ -915,12 +909,16 @@ static int check_tcl_pub(char *nick, char *from, char *chname, char *msg) struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; int x; char buf[512], *args = buf, *cmd, host[161], *hand; - struct userrec *u; + struct chanset_t *chan; + struct userrec *u = NULL; + memberlist *m; strlcpy(buf, msg, sizeof buf); cmd = newsplit(&args); simple_sprintf(host, "%s!%s", nick, from); - u = get_user_by_host(host); + chan = findchan(chname); + m = ismember(chan, nick); + u = lookup_user_record(m ? m : find_member_from_nick(nick), NULL, from); // TODO: get account from msgtags hand = u ? u->handle : "*"; get_user_flagrec(u, &fr, chname); Tcl_SetVar(interp, "_pub1", nick, 0); @@ -943,10 +941,14 @@ static int check_tcl_pubm(char *nick, char *from, char *chname, char *msg) int x; char buf[1024], host[161]; struct userrec *u; + struct chanset_t *chan; + memberlist *m; simple_sprintf(buf, "%s %s", chname, msg); simple_sprintf(host, "%s!%s", nick, from); - u = get_user_by_host(host); + chan = findchan(chname); + m = ismember(chan, nick); + u = lookup_user_record(m ? m : find_member_from_nick(nick), NULL, from); // TODO: get account from msgtags get_user_flagrec(u, &fr, chname); Tcl_SetVar(interp, "_pubm1", nick, 0); Tcl_SetVar(interp, "_pubm2", from, 0); diff --git a/src/mod/irc.mod/mode.c b/src/mod/irc.mod/mode.c index 327844c3b..5350fafd7 100644 --- a/src/mod/irc.mod/mode.c +++ b/src/mod/irc.mod/mode.c @@ -52,11 +52,11 @@ static struct chanset_t *modebind_refresh(char *chname, if (!chname || !(chan = findchan(chname))) return NULL; if (usrhost) { - u = get_user_by_host(usrhost); + u = lookup_user_record(NULL, NULL, usrhost); // TODO: get account from somewhere get_user_flagrec(u, usr, chan->dname); } if (vcrhost) { - u = get_user_by_host(vcrhost); + u = lookup_user_record(NULL, NULL, vcrhost); // TODO: get account from somewhere get_user_flagrec(u, vcr, chan->dname); } return chan; @@ -421,11 +421,7 @@ static void got_op(struct chanset_t *chan, char *nick, char *from, check_chan = 1; strcpy(ch, chan->name); - simple_sprintf(s, "%s!%s", m->nick, m->userhost); - if (!m->user) - u = get_user_by_host(s); - else - u = m->user; + u = get_user_from_member(m); get_user_flagrec(u, &victim, chan->dname); /* Flags need to be set correctly right from the beginning now, so that @@ -519,11 +515,7 @@ static void got_halfop(struct chanset_t *chan, char *nick, char *from, check_chan = 1; strcpy(ch, chan->name); - simple_sprintf(s, "%s!%s", m->nick, m->userhost); - if (!m->user) - u = get_user_by_host(s); - else - u = m->user; + u = get_user_from_member(m); get_user_flagrec(u, &victim, chan->dname); /* Flags need to be set correctly right from the beginning now, so that @@ -612,7 +604,7 @@ static void got_deop(struct chanset_t *chan, char *nick, char *from, strcpy(ch, chan->name); simple_sprintf(s, "%s!%s", m->nick, m->userhost); simple_sprintf(s1, "%s!%s", nick, from); - u = get_user_by_host(s); + u = get_user_from_member(m); get_user_flagrec(u, &victim, chan->dname); had_halfop = chan_hasop(m); @@ -703,9 +695,8 @@ static void got_dehalfop(struct chanset_t *chan, char *nick, char *from, } strcpy(ch, chan->name); - simple_sprintf(s, "%s!%s", m->nick, m->userhost); simple_sprintf(s1, "%s!%s", nick, from); - u = get_user_by_host(s); + u = get_user_from_member(m); get_user_flagrec(u, &victim, chan->dname); had_halfop = chan_hasop(m); @@ -784,7 +775,7 @@ static void got_ban(struct chanset_t *chan, char *nick, char *from, char *who, for (m = chan->channel.member; m && m->nick[0]; m = m->next) { egg_snprintf(s1, sizeof s1, "%s!%s", m->nick, m->userhost); if (match_addr(who, s1)) { - targ = get_user_by_host(s1); + targ = get_user_from_member(m); if (targ) { get_user_flagrec(targ, &victim, chan->dname); if ((glob_friend(victim) || (glob_op(victim) && !chan_deop(victim)) || @@ -1025,12 +1016,15 @@ static int gotmode(char *from, char *origmsg) msg[z] = 0; putlog(LOG_MODES, chan->dname, "%s: mode change '%s %s' by %s", ch, chg, msg, from); - u = get_user_by_host(from); - get_user_flagrec(u, &user, ch); nick = splitnick(&from); m = ismember(chan, nick); - if (m) + if (m) { + u = get_user_from_member(m); + get_user_flagrec(u, &user, ch); m->last = now; + } else { + u = NULL; + } if (m && channel_active(chan) && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) && !(glob_friend(user) || chan_friend(user) || (channel_dontkickops(chan) && (chan_op(user) || (glob_op(user) && @@ -1249,8 +1243,7 @@ static int gotmode(char *from, char *origmsg) refresh_who_chan(chan->name); } else { simple_sprintf(s, "%s!%s", m->nick, m->userhost); - get_user_flagrec(m->user ? m->user : get_user_by_host(s), - &victim, chan->dname); + get_user_flagrec(get_user_from_member(m), &victim, chan->dname); if (ms2[0] == '+') { m->flags &= ~SENTVOICE; m->flags |= CHANVOICE; diff --git a/src/mod/irc.mod/msgcmds.c b/src/mod/irc.mod/msgcmds.c index d179ceac9..1c8a45f6b 100644 --- a/src/mod/irc.mod/msgcmds.c +++ b/src/mod/irc.mod/msgcmds.c @@ -383,7 +383,8 @@ static int msg_who(char *nick, char *host, struct userrec *u, char *par) struct userrec *u; egg_snprintf(s, sizeof s, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s); + /* Don't use s for host here, b/c if we don't have m, we won't have s */ + u = get_user_from_member(m); info = get_user(&USERENTRY_INFO, u); if (u && (u->flags & USER_BOT)) info = 0; @@ -431,7 +432,7 @@ static int msg_who(char *nick, char *host, struct userrec *u, char *par) static int msg_whois(char *nick, char *host, struct userrec *u, char *par) { - char s[UHOSTLEN + 1], s1[143], *s2, stime[14]; + char s1[143], *s2, stime[14], uhost[NICKLEN + UHOSTLEN]; int ok; struct chanset_t *chan; memberlist *m; @@ -454,7 +455,8 @@ static int msg_whois(char *nick, char *host, struct userrec *u, char *par) } if (strlen(par) > NICKMAX) par[NICKMAX] = 0; - putlog(LOG_CMDS, "*", "(%s!%s) !%s! WHOIS %s", nick, host, u->handle, par); + egg_snprintf(uhost, sizeof uhost, "%s!%s", nick, host); + putlog(LOG_CMDS, "*", "(%s) !%s! WHOIS %s", uhost, u->handle, par); u2 = get_user_by_handle(userlist, par); if (!u2) { /* No such handle -- maybe it's a nickname of someone on a chan? */ @@ -462,8 +464,7 @@ static int msg_whois(char *nick, char *host, struct userrec *u, char *par) for (chan = chanset; chan && !ok; chan = chan->next) { m = ismember(chan, par); if (m) { - egg_snprintf(s, sizeof s, "%s!%s", par, m->userhost); - u2 = get_user_by_host(s); + u2 = get_user_from_member(m); if (u2) { ok = 1; dprintf(DP_HELP, "NOTICE %s :[%s] AKA '%s':\n", nick, diff --git a/src/mod/irc.mod/tclirc.c b/src/mod/irc.mod/tclirc.c index 36b485a2a..2e27744a8 100644 --- a/src/mod/irc.mod/tclirc.c +++ b/src/mod/irc.mod/tclirc.c @@ -24,10 +24,10 @@ */ static int tcl_chanlist STDVAR { - char nuh[1024]; int f; memberlist *m; struct chanset_t *chan; + struct userrec *u; struct flag_record plus = { FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0 }, minus = { FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0}, user = { FR_CHAN | FR_GLOBAL | FR_BOT, 0, 0, 0, 0, 0 }; @@ -55,11 +55,8 @@ static int tcl_chanlist STDVAR minus.match = plus.match ^ (FR_AND | FR_OR); for (m = chan->channel.member; m && m->nick[0]; m = m->next) { - if (!m->user) { - egg_snprintf(nuh, sizeof nuh, "%s!%s", m->nick, m->userhost); - m->user = get_user_by_host(nuh); - } - get_user_flagrec(m->user, &user, argv[1]); + u = get_user_from_member(m); + get_user_flagrec(u, &user, argv[1]); user.match = plus.match; if (flagrec_eq(&plus, &user)) { if (!f || !flagrec_eq(&minus, &user)) @@ -347,8 +344,8 @@ static int tcl_onchan STDVAR static int tcl_handonchan STDVAR { - char nuh[1024]; struct chanset_t *chan, *thechan = NULL; + struct userrec *u; memberlist *m; BADARGS(2, 3, " handle ?channel?"); @@ -365,11 +362,8 @@ static int tcl_handonchan STDVAR while (chan && (thechan == NULL || thechan == chan)) { for (m = chan->channel.member; m && m->nick[0]; m = m->next) { - if (!m->user) { - egg_snprintf(nuh, sizeof nuh, "%s!%s", m->nick, m->userhost); - m->user = get_user_by_host(nuh); - } - if (m->user && !strcasecmp(m->user->handle, argv[1])) { + u = get_user_from_member(m); + if (u && !strcasecmp(u->handle, argv[1])) { Tcl_AppendResult(irp, "1", NULL); return TCL_OK; } @@ -986,7 +980,8 @@ static int tcl_account2nicks STDVAR struct chanset_t *chan, *thechan = NULL; Tcl_Obj *nicks; Tcl_Obj **nicksv = NULL; - int nicksc = 0, i, found; + Tcl_Size nicksc = 0, i; + int found; BADARGS(2, 3, " account ?channel?"); @@ -1027,12 +1022,13 @@ static int tcl_account2nicks STDVAR static int tcl_hand2nicks STDVAR { - char nuh[1024]; memberlist *m; struct chanset_t *chan, *thechan = NULL; + struct userrec *u; Tcl_Obj *nicks; Tcl_Obj **nicksv = NULL; - int nicksc = 0, i, found; + Tcl_Size nicksc = 0, i; + int found; BADARGS(2, 3, " handle ?channel?"); @@ -1050,13 +1046,8 @@ static int tcl_hand2nicks STDVAR while (chan && (thechan == NULL || thechan == chan)) { for (m = chan->channel.member; m && m->nick[0]; m = m->next) { found = 0; - /* Does this user have the account we're looking for? */ - if (!m->user && !m->tried_getuser) { - egg_snprintf(nuh, sizeof nuh, "%s!%s", m->nick, m->userhost); - m->tried_getuser = 1; - m->user = get_user_by_host(nuh); - } - if (m->user && !strcasecmp(m->user->handle, argv[1])) { + u = get_user_from_member(m); + if (u && !strcasecmp(u->handle, argv[1])) { /* Is the nick of the user already in the list? */ Tcl_ListObjGetElements(irp, nicks, &nicksc, &nicksv); for (i = 0; i < nicksc; i++) { @@ -1078,9 +1069,9 @@ static int tcl_hand2nicks STDVAR static int tcl_hand2nick STDVAR { - char nuh[1024]; memberlist *m; struct chanset_t *chan, *thechan = NULL; + struct userrec *u; BADARGS(2, 3, " handle ?channel?"); @@ -1096,12 +1087,8 @@ static int tcl_hand2nick STDVAR while (chan && (thechan == NULL || thechan == chan)) { for (m = chan->channel.member; m && m->nick[0]; m = m->next) { - if (!m->user && !m->tried_getuser) { - egg_snprintf(nuh, sizeof nuh, "%s!%s", m->nick, m->userhost); - m->tried_getuser = 1; - m->user = get_user_by_host(nuh); - } - if (m->user && !strcasecmp(m->user->handle, argv[1])) { + u = get_user_from_member(m); + if (u && !strcasecmp(u->handle, argv[1])) { Tcl_AppendResult(irp, m->nick, NULL); return TCL_OK; } @@ -1113,9 +1100,9 @@ static int tcl_hand2nick STDVAR static int tcl_nick2hand STDVAR { - char nuh[1024]; memberlist *m; struct chanset_t *chan, *thechan = NULL; + struct userrec *u; BADARGS(2, 3, " nick ?channel?"); @@ -1132,11 +1119,8 @@ static int tcl_nick2hand STDVAR while (chan && (thechan == NULL || thechan == chan)) { m = ismember(chan, argv[1]); if (m) { - if (!m->user) { - egg_snprintf(nuh, sizeof nuh, "%s!%s", m->nick, m->userhost); - m->user = get_user_by_host(nuh); - } - Tcl_AppendResult(irp, m->user ? m->user->handle : "*", NULL); + u = get_user_from_member(m); + Tcl_AppendResult(irp, u ? u->handle : "*", NULL); return TCL_OK; } chan = chan->next; diff --git a/src/mod/module.h b/src/mod/module.h index 1a67a0268..271ad4ba2 100644 --- a/src/mod/module.h +++ b/src/mod/module.h @@ -199,7 +199,7 @@ typedef void (*chanout_butfunc)(int, int, const char *, ...) ATTRIBUTE_FORMAT(pr #define open_telnet ((int (*) (int, char *, int))global[87]) /* 88 - 91 */ #define check_tcl_event ((void (*) (const char *))global[88]) -/* was my_memcpy -- use memcpy() instead */ +/* was my_memcpy() -- use memcpy() instead */ #define my_atoul ((IP(*)(char *))global[90]) #define my_strcpy ((int (*)(char *, const char *))global[91]) /* 92 - 95 */ @@ -422,11 +422,11 @@ typedef void (*chanout_butfunc)(int, int, const char *, ...) ATTRIBUTE_FORMAT(pr #define egg_inet_aton ((int (*)(const char *cp, struct in_addr *addr))global[251]) /* 252 - 255 */ #define egg_snprintf (global[252]) -/* was egg_vsnprintf -- use vsnprintf() instead */ -/* was egg_memset -- use memset() instead */ -/* was egg_strcasecmp -- use strcasecmp instead */ +/* was egg_vsnprintf() -- use vsnprintf() instead */ +/* was egg_memset() -- use memset() instead */ +/* was egg_strcasecmp() -- use strcasecmp() instead */ /* 256 - 259 */ -/* was egg_strncasecmp -- use strncasecmp instead */ +/* was egg_strncasecmp() -- use strncasecmp() instead */ #define is_file ((int (*)(const char *))global[257]) #define must_be_owner (*(int *)(global[258])) #define tandbot (*(tand_t **)(global[259])) @@ -494,7 +494,7 @@ typedef void (*chanout_butfunc)(int, int, const char *, ...) ATTRIBUTE_FORMAT(pr # define strlcpy ((size_t (*) (char *, const char *, size_t))global[303]) #endif /* 304 - 307 */ -#define strncpyz ((size_t (*) (char *, const char *, size_t))global[304]) +#define strncpyz strlcpy /* strncpyz() is deprecated, use strlcpy() instead */ #ifndef HAVE_BASE64 # define b64_ntop ((int (*) (uint8_t const *, size_t, char *, size_t))global[305]) # define b64_pton ((int (*) (const char *, uint8_t *, size_t))global[306]) @@ -521,7 +521,10 @@ typedef void (*chanout_butfunc)(int, int, const char *, ...) ATTRIBUTE_FORMAT(pr #define bind_bind_entry ((int(*)(tcl_bind_list_t *, const char *, const char *, const char *))global[320]) #define unbind_bind_entry ((int(*)(tcl_bind_list_t *, const char *, const char *, const char *))global[321]) #define argv0 ((char *)global[322]) - +#define lookup_user_record ((struct userrec * (*)(memberlist *, char *, char *))global[323]) +/* 324 - 327 */ +#define find_member_from_nick ((memberlist * (*) (char *))global[324]) +#define get_user_from_member ((struct userrec * (*) (memberlist *))global[325]) /* hostmasking */ diff --git a/src/mod/modvals.h b/src/mod/modvals.h index 6b955cad3..a840e09cf 100644 --- a/src/mod/modvals.h +++ b/src/mod/modvals.h @@ -39,7 +39,11 @@ #define HOOK_LOADED 13 #define HOOK_BACKUP 14 #define HOOK_DIE 15 -#define REAL_HOOKS 16 +#define HOOK_PRE_SELECT 16 +#define HOOK_POST_SELECT 17 + +#define REAL_HOOKS 18 + #define HOOK_SHAREOUT 105 #define HOOK_SHAREIN 106 #define HOOK_ENCRYPT_PASS 107 diff --git a/src/mod/notes.mod/notes.c b/src/mod/notes.mod/notes.c index 5c5d47aa8..ee9a9b3e5 100644 --- a/src/mod/notes.mod/notes.c +++ b/src/mod/notes.mod/notes.c @@ -834,13 +834,11 @@ static void notes_hourly() memberlist *m; int k; int l; - char s1[NICKMAX+UHOSTLEN+1]; struct userrec *u; for (chan = chanset; chan; chan = chan->next) { for (m = chan->channel.member; m && m->nick[0]; m = m->next) { - sprintf(s1, "%s!%s", m->nick, m->userhost); - u = get_user_by_host(s1); + u = get_user_from_member(m); if (u) { k = num_notes(u->handle); for (l = 0; l < dcc_total; l++) diff --git a/src/mod/python.mod/configure b/src/mod/python.mod/configure index eadf4ed9c..6b0a130f5 100755 --- a/src/mod/python.mod/configure +++ b/src/mod/python.mod/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac 98f8972a. +# From configure.ac 9068a673. # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for Eggdrop Python Module 1.10.0. # diff --git a/src/mod/python.mod/python.c b/src/mod/python.mod/python.c index 7a4ed7fce..b2521661e 100644 --- a/src/mod/python.mod/python.c +++ b/src/mod/python.mod/python.c @@ -31,7 +31,6 @@ #undef interp #define tclinterp (*(Tcl_Interp **)(global[128])) #undef days -#include #include #include #include "src/mod/irc.mod/irc.h" @@ -43,6 +42,7 @@ static PyObject *pirp, *pglobals; #undef global static Function *global = NULL, *irc_funcs = NULL; +static PyThreadState *_pythreadsave; #include "src/mod/python.mod/pycmds.c" #include "src/mod/python.mod/tclpython.c" @@ -53,42 +53,43 @@ static int python_expmem() return 0; // TODO } -// TODO: Do we really have to exit eggdrop on module load failure? -static void init_python() { +static int python_gil_unlock() { + _pythreadsave = PyEval_SaveThread(); + return 0; +} + +static int python_gil_lock() { + PyEval_RestoreThread(_pythreadsave); + return 0; +} + +static char *init_python() { PyObject *pmodule; PyStatus status; PyConfig config; - if (PY_VERSION_HEX < 0x0308) { - putlog(LOG_MISC, "*", "Python: Python version %d is lower than 3.8, not loading Python module", PY_VERSION_HEX); - return; - } PyConfig_InitPythonConfig(&config); config.install_signal_handlers = 0; config.parse_argv = 0; status = PyConfig_SetBytesString(&config, &config.program_name, argv0); if (PyStatus_Exception(status)) { PyConfig_Clear(&config); - putlog(LOG_MISC, "*", "Python: Fatal error: Could not set program base path"); - Py_ExitStatusException(status); + return "Python: Fatal error: Could not set program base path"; } if (PyImport_AppendInittab("eggdrop", &PyInit_eggdrop) == -1) { - putlog(LOG_MISC, "*", "Python: Error: could not extend in-built modules table"); - exit(1); + PyConfig_Clear(&config); + return "Python: Error: could not extend in-built modules table"; } status = Py_InitializeFromConfig(&config); if (PyStatus_Exception(status)) { PyConfig_Clear(&config); - putlog(LOG_MISC, "*", "Python: Fatal error: Could not initialize config"); - fatal(1); + return "Python: Fatal error: Could not initialize config"; } PyConfig_Clear(&config); PyDateTime_IMPORT; pmodule = PyImport_ImportModule("eggdrop"); if (!pmodule) { - PyErr_Print(); - putlog(LOG_MISC, "*", "Error: could not import module 'eggdrop'"); - fatal(1); + return "Error: could not import module 'eggdrop'"; } pirp = PyImport_AddModule("__main__"); @@ -100,7 +101,7 @@ static void init_python() { PyRun_SimpleString("import eggdrop"); PyRun_SimpleString("sys.displayhook = eggdrop.__displayhook__"); - return; + return NULL; } static void kill_python() { @@ -119,6 +120,8 @@ static void python_report(int idx, int details) static char *python_close() { Context; + del_hook(HOOK_PRE_SELECT, (Function)python_gil_unlock); + del_hook(HOOK_POST_SELECT, (Function)python_gil_lock); kill_python(); rem_builtins(H_dcc, mydcc); rem_tcl_commands(my_tcl_cmds); @@ -135,6 +138,7 @@ static Function python_table[] = { char *python_start(Function *global_funcs) { + char *s; /* Assign the core function table. After this point you use all normal * functions defined in src/mod/modules.h */ @@ -155,10 +159,14 @@ char *python_start(Function *global_funcs) } // irc.mod depends on server.mod and channels.mod, so those were implicitely loaded - init_python(); + if ((s = init_python())) + return s; /* Add command table to bind list */ add_builtins(H_dcc, mydcc); add_tcl_commands(my_tcl_cmds); + add_hook(HOOK_PRE_SELECT, (Function)python_gil_unlock); + add_hook(HOOK_POST_SELECT, (Function)python_gil_lock); + return NULL; } diff --git a/src/mod/python.mod/scripts/urlTitle.py b/src/mod/python.mod/scripts/urlTitle.py index f8b498226..b2d35899a 100644 --- a/src/mod/python.mod/scripts/urlTitle.py +++ b/src/mod/python.mod/scripts/urlTitle.py @@ -17,6 +17,7 @@ def pubGetTitle(nick, host, handle, channel, text, **kwargs): try: reqs = requests.get(text) soup = BeautifulSoup(reqs.text, 'html.parser') + putlog("Found title for "+text) putmsg(channel, "The title of the webpage is: "+soup.find_all('title')[0].get_text()) except Exception as e: putmsg(channel, "Error: " + str(e)) diff --git a/src/mod/seen.mod/seen.c b/src/mod/seen.mod/seen.c index 41cea68d2..63ddd0593 100644 --- a/src/mod/seen.mod/seen.c +++ b/src/mod/seen.mod/seen.c @@ -73,12 +73,6 @@ #include "src/mod/module.h" -#ifdef HAVE_SYS_TIME_H -# include -#else -# include -#endif - #include "src/users.h" #include "src/chan.h" #include "channels.mod/channels.h" @@ -148,7 +142,7 @@ static int dcc_seen(struct userrec *u, int idx, char *par) static void do_seen(int idx, char *prefix, char *nick, char *hand, char *channel, char *text) { - char stuff[512], word1[512], word2[512], whotarget[128], object[128], + char word1[512], word2[512], whotarget[128], object[128], whoredirect[512], *oix, *lastonplace = 0; struct userrec *urec; struct chanset_t *chan; @@ -194,8 +188,7 @@ static void do_seen(int idx, char *prefix, char *nick, char *hand, m = ismember(chan, object); if (m) { onchan = 1; - snprintf(stuff, sizeof stuff, "%s!%s", object, m->userhost); - urec = get_user_by_host(stuff); + urec = get_user_from_member(m); if (!urec || !strcasecmp(object, urec->handle)) break; strcat(whoredirect, object); @@ -342,7 +335,7 @@ static void do_seen(int idx, char *prefix, char *nick, char *hand, if (m) { onchan = 1; snprintf(word1, sizeof word1, "%s!%s", whotarget, m->userhost); - urec = get_user_by_host(word1); + urec = get_user_from_member(m); if (!urec || !strcasecmp(whotarget, urec->handle)) break; strcat(whoredirect, whotarget); @@ -359,8 +352,7 @@ static void do_seen(int idx, char *prefix, char *nick, char *hand, while (chan) { m = chan->channel.member; while (m && m->nick[0]) { - snprintf(word2, sizeof word2, "%s!%s", m->nick, m->userhost); - urec = get_user_by_host(word2); + urec = get_user_from_member(m); if (urec && !strcasecmp(urec->handle, whotarget)) { strcat(whoredirect, whotarget); strcat(whoredirect, " is "); diff --git a/src/mod/server.mod/cmdsserv.c b/src/mod/server.mod/cmdsserv.c index ab580d208..ceb79e436 100644 --- a/src/mod/server.mod/cmdsserv.c +++ b/src/mod/server.mod/cmdsserv.c @@ -20,7 +20,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include static void cmd_servers(struct userrec *u, int idx, char *par) { diff --git a/src/mod/server.mod/server.c b/src/mod/server.mod/server.c index 80d0ad5f1..6aff0e488 100644 --- a/src/mod/server.mod/server.c +++ b/src/mod/server.mod/server.c @@ -1413,7 +1413,7 @@ static int server_raw STDVAR static int server_rawt STDVAR { - int unused; + Tcl_Size unused; Tcl_Obj *tagdict; Function F = (Function) cd; @@ -1809,7 +1809,8 @@ static char *tcl_eggserver(ClientData cdata, Tcl_Interp *irp, EGG_CONST char *name1, EGG_CONST char *name2, int flags) { - int lc, code, i; + Tcl_Size lc, i; + int code; char x[1024]; EGG_CONST char **list, *slist; struct server_list *q; diff --git a/src/mod/server.mod/servmsg.c b/src/mod/server.mod/servmsg.c index 85baed7cf..91a50e2e9 100644 --- a/src/mod/server.mod/servmsg.c +++ b/src/mod/server.mod/servmsg.c @@ -493,7 +493,7 @@ static int detect_flood(char *floodnick, char *floodhost, char *from, int which) if (!strcasecmp(floodhost, botuserhost)) return 0; - u = get_user_by_host(from); + u = lookup_user_record(NULL, NULL, from); // TODO: get account somehow atr = u ? u->flags : 0; if (atr & (USER_BOT | USER_FRIEND)) return 0; @@ -539,7 +539,7 @@ static int detect_flood(char *floodnick, char *floodhost, char *from, int which) lastmsgs[which] = 0; lastmsgtime[which] = 0; lastmsghost[which][0] = 0; - u = get_user_by_host(from); + u = lookup_user_record(NULL, NULL, from); // TODO: get account somehow if (check_tcl_flud(floodnick, floodhost, u, ftype, "*")) return 0; /* Private msg */ @@ -607,7 +607,7 @@ static int gotmsg(char *from, char *msg) putlog(LOG_PUBLIC, to, "CTCP %s: %s from %s (%s) to %s", code, ctcp, nick, uhost, to); } else { - u = get_user_by_host(from); + u = lookup_user_record(find_member_from_nick(nick), NULL, from); // TODO: get account from msgtags if (!ignoring || trigger_on_ignore) { if (!check_tcl_ctcp(nick, uhost, u, to, code, ctcp) && !ignoring) { if ((lowercase_ctcp && !strcasecmp(code, "DCC")) || @@ -670,7 +670,7 @@ static int gotmsg(char *from, char *msg) } detect_flood(nick, uhost, from, FLOOD_PRIVMSG); - u = get_user_by_host(from); + u = lookup_user_record(find_member_from_nick(nick), NULL, from); // TODO: get account from msgtags code = newsplit(&msg); rmspace(msg); @@ -730,7 +730,7 @@ static int gotnotice(char *from, char *msg) "CTCP reply %s: %s from %s (%s) to %s", code, ctcp, nick, uhost, to); } else { - u = get_user_by_host(from); + u = lookup_user_record(find_member_from_nick(nick), NULL, from); // TODO: get account from msgtags if (!ignoring || trigger_on_ignore) { check_tcl_ctcr(nick, uhost, u, to, code, ctcp); if (!ignoring) @@ -766,7 +766,7 @@ static int gotnotice(char *from, char *msg) } detect_flood(nick, uhost, from, FLOOD_NOTICE); - u = get_user_by_host(from); + u = lookup_user_record(find_member_from_nick(nick), NULL, from); // TODO: get account from msgtags if (!ignoring || trigger_on_ignore) if (check_tcl_notc(nick, uhost, u, botname, msg) == 2) @@ -2001,6 +2001,54 @@ static int got730or1(char *from, char *msg, int code) return 0; } +/* Got IRCv3 standard-reply + * [...] + */ +static int gotstdreply(char *from, char *msgtype, char *msg) +{ + char *cmd, *code, *text; + char context[MSGMAX] = ""; + int len; + + cmd = newsplit(&msg); + code = newsplit(&msg); +/* TODO: Once this feature is better implemented, consider how to handle + * one-word descriptions that aren't technically required to have a : + */ + text = strstr(msg, " :"); + if (text) { + text++; + if (text != msg) { + len = text - msg; + snprintf(context, sizeof context, "%.*s", len, msg); + } + fixcolon(text); + } + putlog(LOG_SERV, "*", "%s: %s: Received a %s message from %s: %s", cmd, code, msgtype, from, text); + return 0; +} + +/* Got IRCv3 FAIL standard-reply */ +static int gotstdfail(char *from, char *msg) +{ + gotstdreply(from, "FAIL", msg); + return 0; +} + +/* Got IRCv3 NOTE standard-reply */ +static int gotstdnote(char *from, char *msg) +{ + gotstdreply(from, "NOTE", msg); + return 0; +} + +/* Got IRCv3 WARN standard-reply */ +static int gotstdwarn(char *from, char *msg) +{ + gotstdreply(from, "WARN", msg); + return 0; +} + /* Got 730/RPL_MONONLINE * : 730 :target[!user@host][,target[!user@host]]* */ @@ -2097,6 +2145,9 @@ static cmd_t my_raw_binds[] = { {"PING", "", (IntFunc) gotping, NULL}, {"PONG", "", (IntFunc) gotpong, NULL}, {"WALLOPS", "", (IntFunc) gotwall, NULL}, + {"FAIL", "", (IntFunc) gotstdfail, NULL}, + {"NOTE", "", (IntFunc) gotstdnote, NULL}, + {"WARN", "", (IntFunc) gotstdwarn, NULL}, {"001", "", (IntFunc) got001, NULL}, {"005", "", (IntFunc) got005, NULL}, {"303", "", (IntFunc) got303, NULL}, diff --git a/src/mod/server.mod/tclisupport.c b/src/mod/server.mod/tclisupport.c index 6ac22d7b3..66fa72aae 100644 --- a/src/mod/server.mod/tclisupport.c +++ b/src/mod/server.mod/tclisupport.c @@ -67,7 +67,7 @@ int tcl_isupport STDOBJVAR static int tcl_isupport_get STDOBJVAR { - int keylen; + Tcl_Size keylen; const char *key, *value; Tcl_Obj *tclres; @@ -95,7 +95,7 @@ static int tcl_isupport_get STDOBJVAR static int tcl_isupport_isset STDOBJVAR { - int keylen; + Tcl_Size keylen; const char *key, *value; BADOBJARGS(3, 3, 2, "setting"); @@ -109,7 +109,7 @@ static int tcl_isupport_isset STDOBJVAR /* not exposed for now */ static int tcl_isupport_set STDOBJVAR { - int keylen, valuelen; + Tcl_Size keylen, valuelen; const char *key, *value; /* First one to check for type validity only */ @@ -126,7 +126,7 @@ static int tcl_isupport_set STDOBJVAR static int tcl_isupport_unset STDOBJVAR { struct isupport *data; - int keylen; + Tcl_Size keylen; const char *key; BADOBJARGS(3, 3, 2, "setting"); @@ -170,7 +170,7 @@ char *traced_isupport(ClientData cdata, Tcl_Interp *irp, } /* remove trailing space */ if (Tcl_DStringLength(&ds)) - Tcl_DStringTrunc(&ds, Tcl_DStringLength(&ds) - 1); + Tcl_DStringSetLength(&ds, Tcl_DStringLength(&ds) - 1); Tcl_SetVar2(interp, name1, name2, Tcl_DStringValue(&ds), TCL_GLOBAL_ONLY); Tcl_DStringFree(&ds); diff --git a/src/modules.c b/src/modules.c index 708252b04..297e17ef7 100644 --- a/src/modules.c +++ b/src/modules.c @@ -23,6 +23,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include #include "main.h" #include "modules.h" @@ -60,16 +61,10 @@ # ifndef RTLD_NOW # define RTLD_NOW 1 # endif -# ifdef RTLD_LAZY -# define DLFLAGS RTLD_LAZY|RTLD_GLOBAL -# else -# define DLFLAGS RTLD_NOW|RTLD_GLOBAL -# endif +# define DLFLAGS RTLD_NOW|RTLD_GLOBAL # endif /* MOD_USE_DL */ #endif /* !STATIC */ -#define strncpyz strlcpy - extern struct dcc_t *dcc; extern struct userrec *userlist, *lastuser; extern struct chanset_t *chanset; @@ -301,7 +296,7 @@ Function global_table[] = { (Function) open_telnet, /* 88 - 91 */ (Function) check_tcl_event, - (Function) 0, /* was egg_memcpy -- use memcpy() instead */ + (Function) memcpy, /* was egg_memcpy -- use memcpy() instead */ (Function) my_atoul, (Function) my_strcpy, /* 92 - 95 */ @@ -524,10 +519,10 @@ Function global_table[] = { /* 252 - 255 */ (Function) egg_snprintf, (Function) vsnprintf, /* was egg_vsnprintf -- use vsnprintf instead */ - (Function) 0, /* was egg_memset -- use memset() or egg_bzero() instead */ - (Function) 0, /* was egg_strcasecmp -- use strcasecmp() instead */ + (Function) memset, /* was egg_memset -- use memset() or egg_bzero() instead */ + (Function) strcasecmp, /* was egg_strcasecmp -- use strcasecmp() instead */ /* 256 - 259 */ - (Function) 0, /* was egg_strncasecmp -- use strncasecmp() instead */ + (Function) strncasecmp, /* was egg_strncasecmp -- use strncasecmp() instead */ (Function) is_file, (Function) & must_be_owner, /* int */ (Function) & tandbot, /* tand_t * */ @@ -595,7 +590,7 @@ Function global_table[] = { (Function) 0, #endif /* 304 - 307 */ - (Function) strncpyz, + (Function) strlcpy, /* was strncpyz() -- use strlcpy() instead */ #ifndef HAVE_BASE64 (Function) b64_ntop, (Function) b64_pton, @@ -626,7 +621,11 @@ Function global_table[] = { /* 320 - 323 */ (Function) bind_bind_entry, (Function) unbind_bind_entry, - (Function) & argv0 + (Function) & argv0, + (Function) lookup_user_record, +/* 324 - 327 */ + (Function) find_member_from_nick, + (Function) get_user_from_member, }; void init_modules(void) @@ -696,6 +695,7 @@ int module_register(char *name, Function *funcs, int major, int minor) const char *module_load(char *name) { + size_t len; module_entry *p; char *e; Function f; @@ -704,7 +704,7 @@ const char *module_load(char *name) #endif #ifndef STATIC - char workbuf[1024]; + char workbuf[PATH_MAX]; # ifdef MOD_USE_SHL shl_t hand; # endif @@ -730,11 +730,14 @@ const char *module_load(char *name) #ifndef STATIC if (moddir[0] != '/') { - if (getcwd(workbuf, 1024) == NULL) + if (getcwd(workbuf, sizeof workbuf) == NULL) { + debug1("modules: getcwd(): %s\n", strerror(errno)); return MOD_BADCWD; - sprintf(&(workbuf[strlen(workbuf)]), "/%s%s." EGG_MOD_EXT, moddir, name); + } + len = strlen(workbuf); + snprintf(workbuf + len, (sizeof workbuf) - len, "/%s%s." EGG_MOD_EXT, moddir, name); } else { - sprintf(workbuf, "%s%s." EGG_MOD_EXT, moddir, name); + snprintf(workbuf, sizeof workbuf, "%s%s." EGG_MOD_EXT, moddir, name); } # ifdef MOD_USE_SHL diff --git a/src/net.c b/src/net.c index 3e23acb97..5a63d5808 100644 --- a/src/net.c +++ b/src/net.c @@ -27,6 +27,7 @@ #include #include "main.h" +#include "modules.h" #include #include #include @@ -924,11 +925,13 @@ int sockread(char *s, int *len, sock_list *slist, int slistmax, int tclonly) t.tv_sec = td->blocktime.tv_sec; t.tv_usec = td->blocktime.tv_usec; + call_hook(HOOK_PRE_SELECT); x = select((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 (maxfd_r >= 0 ? &fdr : NULL), SELECT_TYPE_ARG234 (maxfd_w >= 0 ? &fdw : NULL), SELECT_TYPE_ARG234 (maxfd_e >= 0 ? &fde : NULL), SELECT_TYPE_ARG5 &t); + call_hook(HOOK_POST_SELECT); if (x == -1) return -2; /* socket error */ if (x == 0) @@ -973,7 +976,12 @@ int sockread(char *s, int *len, sock_list *slist, int slistmax, int tclonly) { if (slist[i].ssl) { x = SSL_read(slist[i].ssl, s, grab); - if (x < 0) { + if (!x && (SSL_get_shutdown(slist[i].ssl) == SSL_RECEIVED_SHUTDOWN)) { + *len = slist[i].sock; + slist[i].flags &= ~SOCK_CONNECT; + debug1("net: SSL_read(): received shutdown sock %i", slist[i].sock); + return -1; + } else if (x < 0) { int err = SSL_get_error(slist[i].ssl, x); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) errno = EAGAIN; @@ -1216,9 +1224,10 @@ int sockgets(char *s, int *len) /* Might be necessary to prepend stored-up data! */ if (socklist[ret].handler.sock.inbuf != NULL) { p = socklist[ret].handler.sock.inbuf; - socklist[ret].handler.sock.inbuf = nmalloc(strlen(p) + strlen(xx) + 1); - strcpy(socklist[ret].handler.sock.inbuf, p); - strcat(socklist[ret].handler.sock.inbuf, xx); + len2 = strlen(p); + socklist[ret].handler.sock.inbuf = nmalloc(len2 + strlen(xx) + 1); + memcpy(socklist[ret].handler.sock.inbuf, p, len2); + strcpy(socklist[ret].handler.sock.inbuf + len2, xx); nfree(p); if (strlen(socklist[ret].handler.sock.inbuf) < READMAX + 2) { strcpy(xx, socklist[ret].handler.sock.inbuf); @@ -1269,10 +1278,11 @@ int sockgets(char *s, int *len) /* Prepend old data back */ if (socklist[ret].handler.sock.inbuf != NULL) { p = socklist[ret].handler.sock.inbuf; - socklist[ret].handler.sock.inbuflen = strlen(p) + strlen(xx); + len2 = strlen(xx); + socklist[ret].handler.sock.inbuflen = len2 + strlen(p); socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1); - strcpy(socklist[ret].handler.sock.inbuf, xx); - strcat(socklist[ret].handler.sock.inbuf, p); + memcpy(socklist[ret].handler.sock.inbuf, xx, len2); + strcpy(socklist[ret].handler.sock.inbuf + len2, p); nfree(p); } else { socklist[ret].handler.sock.inbuflen = strlen(xx); diff --git a/src/tcl.c b/src/tcl.c index 5015fd5b5..64409ee25 100644 --- a/src/tcl.c +++ b/src/tcl.c @@ -767,6 +767,7 @@ Tcl_Obj *egg_string_unicodesup_desurrogate(const char *oldstr, int len) { int stridx = 0, bufidx = 0; char *buf = nmalloc(len); + Tcl_Obj *o; while (stridx < len) { uint32_t low, high; @@ -787,7 +788,10 @@ Tcl_Obj *egg_string_unicodesup_desurrogate(const char *oldstr, int len) } } } - return Tcl_NewStringObj(buf, bufidx); + + o = Tcl_NewStringObj(buf, bufidx); + nfree(buf); + return o; } /* C function called for ::egg_tcl_tolower/toupper/totitle @@ -901,17 +905,10 @@ void init_unicodesup(void) } #endif /* TCL_WORKAROUND_UNICODESUP */ -/* Not going through Tcl's crazy main() system (what on earth was he - * smoking?!) so we gotta initialize the Tcl interpreter - */ -void init_tcl(int argc, char **argv) +void init_tcl0(int argc, char **argv) { Tcl_NotifierProcs notifierprocs; - - const char *encoding; - int i, j; - char *langEnv, pver[1024] = ""; - + egg_bzero(¬ifierprocs, sizeof(notifierprocs)); notifierprocs.initNotifierProc = tickle_InitNotifier; notifierprocs.createFileHandlerProc = tickle_CreateFileHandler; @@ -923,8 +920,8 @@ void init_tcl(int argc, char **argv) notifierprocs.serviceModeHookProc = tickle_ServiceModeHook; Tcl_SetNotifier(¬ifierprocs); - -/* This must be done *BEFORE* Tcl_SetSystemEncoding(), + + /* This must be done *BEFORE* Tcl_SetSystemEncoding(), * or Tcl_SetSystemEncoding() will cause a segfault. */ /* This is used for 'info nameofexecutable'. @@ -932,6 +929,19 @@ void init_tcl(int argc, char **argv) * the environment variable PATH for it to register anything. */ Tcl_FindExecutable(argv[0]); +#if TCL_MAJOR_VERSION >= 9 + Tcl_InitSubsystems(); +#endif +} + +/* Not going through Tcl's crazy main() system (what on earth was he + * smoking?!) so we gotta initialize the Tcl interpreter + */ +void init_tcl1(int argc, char **argv) +{ + const char *encoding; + int i, j; + char *langEnv, pver[1024] = ""; /* Initialize the interpreter */ interp = Tcl_CreateInterp(); diff --git a/src/tclmisc.c b/src/tclmisc.c index c5db7090c..bbfdb5299 100644 --- a/src/tclmisc.c +++ b/src/tclmisc.c @@ -25,13 +25,6 @@ #include "main.h" #include "modules.h" #include "md5/md5.h" - -#ifdef HAVE_SYS_TIME_H -# include -#else -# include -#endif - #include #include diff --git a/src/tls.c b/src/tls.c index 180af6b37..d3af0c6ea 100644 --- a/src/tls.c +++ b/src/tls.c @@ -531,6 +531,12 @@ static char *ssl_printname(X509_NAME *name) /* X509_NAME_oneline() is easier and shorter, but is deprecated and the manual discourages it's usage, so let's not be lazy ;) */ + if (!bio) { + debug0("TLS: ssl_printname(): BIO_new(): error"); + buf = nmalloc(1); + *buf = 0; + return buf; + } if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_ONELINE & ~XN_FLAG_SPC_EQ)) { len = BIO_get_mem_data(bio, &data); if (len > 0) { @@ -564,6 +570,12 @@ static char *ssl_printtime(ASN1_UTCTIME *t) char *data, *buf; BIO *bio = BIO_new(BIO_s_mem()); + if (!bio) { + debug0("TLS: ssl_printtime(): BIO_new(): error"); + buf = nmalloc(1); + *buf = 0; + return buf; + } ASN1_UTCTIME_print(bio, t); len = BIO_get_mem_data(bio, &data); if (len > 0) { @@ -591,6 +603,12 @@ static char *ssl_printnum(ASN1_INTEGER *i) char *data, *buf; BIO *bio = BIO_new(BIO_s_mem()); + if (!bio) { + debug0("TLS: ssl_printnum(): BIO_new(): error"); + buf = nmalloc(1); + *buf = 0; + return buf; + } i2a_ASN1_INTEGER(bio, i); len = BIO_get_mem_data(bio, &data); if (len > 0) { @@ -712,7 +730,7 @@ int ssl_verify(int ok, X509_STORE_CTX *ctx) !(data->verify & TLS_VERIFYFROM)) || ((err == X509_V_ERR_CERT_HAS_EXPIRED) && !(data->verify & TLS_VERIFYTO))) { - debug1("TLS: peer certificate warning: %s", + putlog(data->loglevel, "*", "TLS: peer certificate warning: %s", X509_verify_cert_error_string(err)); ok = 1; } @@ -799,7 +817,7 @@ static void ssl_info(const SSL *ssl, int where, int ret) SSL_alert_desc_string_long(ret)); } else { /* Ignore close notify warnings */ - debug1("Received close notify warning during %s", + debug1("TLS: Received close notify during %s", (where & SSL_CB_READ) ? "read" : "write"); } } else if (where & SSL_CB_EXIT) { @@ -819,10 +837,16 @@ static void ssl_info(const SSL *ssl, int where, int ret) SSL_state_string_long(ssl)); } } - } else { - /* Display the state of the engine for debugging purposes */ - debug1("TLS: state change: %s", SSL_state_string_long(ssl)); } + /* Display the state of the engine for debugging purposes */ + else if (where == SSL_CB_HANDSHAKE_START) + debug1("TLS: handshake start: %s", SSL_state_string_long(ssl)); + else if (where == SSL_CB_CONNECT_LOOP) + debug1("TLS: connect loop: %s", SSL_state_string_long(ssl)); + else if (where == SSL_CB_ACCEPT_LOOP) + debug1("TLS: accept loop: %s", SSL_state_string_long(ssl)); + else + debug1("TLS: state change: %s", SSL_state_string_long(ssl)); } /* Switch a socket to SSL communication @@ -902,9 +926,9 @@ int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host, SSL_set_mode(td->socklist[i].ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); if (data->flags & TLS_CONNECT) { - struct timespec req = { 0, 1000000L }; SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify); /* Introduce 1ms lag so an unpatched hub has time to setup the ssl handshake */ + const struct timespec req = { 0, 1000000L }; nanosleep(&req, NULL); #ifdef SSL_set_tlsext_host_name if (*data->host) diff --git a/src/userent.c b/src/userent.c index 3fde1f20a..a070995fd 100644 --- a/src/userent.c +++ b/src/userent.c @@ -1036,7 +1036,8 @@ static int xtra_pack(struct userrec *u, struct user_entry *e) static void xtra_display(int idx, struct user_entry *e) { - int code, lc, j; + int code; + Tcl_Size lc, j; EGG_CONST char **list; struct xtra_key *xk; diff --git a/src/userrec.c b/src/userrec.c index da5da6b42..66bb8f16c 100644 --- a/src/userrec.c +++ b/src/userrec.c @@ -171,18 +171,21 @@ static struct userrec *check_dcclist_hand(char *handle) return NULL; } -/* Shortcut for get_user_by_handle -- might have user record in channels +/* Search every channel record for the provided nickname. Used in cases where + * we are searching for a user record but don't have a memberlist to start from */ -static struct userrec *check_chanlist_hand(const char *hand) -{ +memberlist *find_member_from_nick(char *nick) { struct chanset_t *chan; - memberlist *m; + memberlist *m = NULL; - for (chan = chanset; chan; chan = chan->next) - for (m = chan->channel.member; m && m->nick[0]; m = m->next) - if (m->user && !strcasecmp(m->user->handle, hand)) - return m->user; - return NULL; + for (chan = chanset; chan; chan = chan->next) { + for (m = chan->channel.member; m && m->nick[0]; m = m->next) { + if (!rfc_casecmp(m->nick, nick)) { + return m; + } + } + } + return m; } /* Search userlist for a provided account name @@ -193,12 +196,11 @@ struct userrec *get_user_by_account(char *acct) struct userrec *u; struct list_type *q; - if (acct == NULL) + if (!acct || !acct[0] || !strcmp(acct, "*")) return NULL; for (u = userlist; u; u = u->next) { - q = get_user(&USERENTRY_ACCOUNT, u); - for (; q; q = q->next) { - if(q && !strcasecmp(q->extra, acct)) { + for (q = get_user(&USERENTRY_ACCOUNT, u); q; q = q->next) { + if (!rfc_casecmp(q->extra, acct)) { return u; } } @@ -226,11 +228,6 @@ struct userrec *get_user_by_handle(struct userrec *bu, char *handle) cache_hit++; return ret; } - ret = check_chanlist_hand(handle); - if (ret) { - cache_hit++; - return ret; - } cache_miss++; } for (u = bu; u; u = u->next) @@ -242,6 +239,76 @@ struct userrec *get_user_by_handle(struct userrec *bu, char *handle) return NULL; } +struct userrec *get_user_from_member(memberlist *m) +{ + struct userrec *ret = NULL; + + /* Check positive/negative cache first */ + if (m->user || m->tried_getuser) { + return m->user; + } + + /* Check if there is a user with a matching account if one is provided */ + if (m->account[0] != '*') { + ret = get_user_by_account(m->account); + if (ret) { + goto getuser_done; + } + } + + /* Check if there is a user with a matching hostmask if one is provided */ + if ((m->userhost[0] != '\0') && (m->nick[0] != '\0')) { + char s[NICKMAX+UHOSTLEN+1]; + sprintf(s, "%s!%s", m->nick, m->userhost); + ret = get_user_by_host(s); + if (ret) { + goto getuser_done; + } + } + +getuser_done: + m->user = ret; + m->tried_getuser = 1; + return NULL; +} + +/* Wrapper function to find an Eggdrop user record based on either a provided + * channel memberlist record, host, or account. This function will first check + * a provided memberlist and return the result. If no user record is found (or + * the memberlist itself was NULL), this function will try again based on a + * provided account, and then again on a provided host. + * + * When calling this function it is best to provide all available independent + * variables- ie, if you provide 'm' for the memberlist, don't provide + * 'm->account' for the account, use the independent source variable 'account' + * if available. This allows redundant checking in case of unexpected NULLs + */ +struct userrec *lookup_user_record(memberlist *m, char *host, char *account) +{ + struct userrec *u = NULL; + +/* First check for a user record tied to a memberlist */ + if (m) { + u = get_user_from_member(m); + if (u) { + return u; + } + } +/* Next check for a user record tied to an account */ + if (account && account[0]) { + u = get_user_by_account(account); + if (u) { + return u; + } + } +/* Last check for a user record tied to a hostmask */ + if (host && host[0]) { + u = get_user_by_host(host); + return u; + } + return NULL; +} + /* Fix capitalization, etc */ void correct_handle(char *handle) @@ -265,8 +332,6 @@ void clear_masks(maskrec *m) temp = m->next; if (m->mask) nfree(m->mask); - if (m->user) - nfree(m->user); if (m->desc) nfree(m->desc); nfree(m); @@ -311,12 +376,10 @@ void clear_userlist(struct userrec *bu) /* Find CLOSEST host match * (if "*!*@*" and "*!*@*clemson.edu" both match, use the latter!) - * - * Checks the chanlist first, to possibly avoid needless search. */ struct userrec *get_user_by_host(char *host) { - struct userrec *u, *ret; + struct userrec *u, *ret = NULL; struct list_type *q; int cnt, i; char host2[UHOSTLEN]; @@ -326,12 +389,7 @@ struct userrec *get_user_by_host(char *host) rmspace(host); if (!host[0]) return NULL; - ret = check_chanlist(host); cnt = 0; - if (ret != NULL) { - cache_hit++; - return ret; - } cache_miss++; strlcpy(host2, host, sizeof host2); for (u = userlist; u; u = u->next) { @@ -346,7 +404,6 @@ struct userrec *get_user_by_host(char *host) } if (ret != NULL) { lastuser = ret; - set_chanlist(host2, ret); } return ret; } diff --git a/src/users.c b/src/users.c index d5c48f234..928f85ae9 100644 --- a/src/users.c +++ b/src/users.c @@ -523,8 +523,6 @@ void tell_user_ident(int idx, char *id) struct userrec *u; u = get_user_by_handle(userlist, id); - if (u == NULL) - u = get_user_by_host(id); if (u == NULL) { dprintf(idx, "%s.\n", USERF_NOMATCH); return; diff --git a/src/users.h b/src/users.h index e9a451418..6bc27c1ce 100644 --- a/src/users.h +++ b/src/users.h @@ -184,7 +184,10 @@ struct userrec *get_user_by_handle(struct userrec *, char *); struct userrec *get_user_by_host(char *); struct userrec *get_user_by_account(char *); struct userrec *get_user_by_nick(char *); +struct userrec *get_user_from_member(memberlist *); +struct userrec *lookup_user_record(memberlist *, char *, char *); struct userrec *check_chanlist(const char *); +memberlist *find_member_from_nick(char *); /* All the default userentry stuff, for code re-use */ diff --git a/src/version.h b/src/version.h index 63e9d3316..64e4e4698 100644 --- a/src/version.h +++ b/src/version.h @@ -27,5 +27,5 @@ */ #define EGG_STRINGVER "1.9.5" -#define EGG_NUMVER 1090505 -#define EGG_PATCH "python" +#define EGG_NUMVER 1090506 +#define EGG_PATCH "accounttracking"