aboutsummaryrefslogtreecommitdiffstats
path: root/modules/m_nicktracking.sh
diff options
context:
space:
mode:
Diffstat (limited to 'modules/m_nicktracking.sh')
-rw-r--r--modules/m_nicktracking.sh316
1 files changed, 316 insertions, 0 deletions
diff --git a/modules/m_nicktracking.sh b/modules/m_nicktracking.sh
new file mode 100644
index 0000000..34b6873
--- /dev/null
+++ b/modules/m_nicktracking.sh
@@ -0,0 +1,316 @@
+#!/bin/bash
+# -*- coding: utf-8 -*-
+###########################################################################
+# #
+# envbot - an IRC bot in bash #
+# Copyright (C) 2007-2008 Arvid Norlander #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Provides nick tracking API for other modules.
+#---------------------------------------------------------------------
+
+module_nicktracking_INIT() {
+ modinit_API='2'
+ modinit_HOOKS='after_load before_connect on_numeric on_NICK on_QUIT on_KICK on_PART on_JOIN'
+ helpentry_module_nicktracking_description="Provides nicktracking backend for other modules."
+}
+
+module_nicktracking_UNLOAD() {
+ unset module_nicktracking_channels
+ hash_reset module_nicktracking_channels_nicks
+ hash_reset module_nicktracking_nicks
+ # Private functions
+ unset module_nicktracking_clear_nick module_nicktracking_clear_chan
+ unset module_nicktracking_parse_names
+ unset module_nicktracking_add_channel_nick
+ unset module_nicktracking_remove_channel_nick
+ # API functions
+ unset module_nicktracking_get_hostmask_by_nick
+ unset module_nicktracking_get_channel_nicks
+ return 0
+}
+
+module_nicktracking_REHASH() {
+ return 0
+}
+
+
+#################
+# API functions #
+#################
+
+#---------------------------------------------------------------------
+## Return hostmask of a nick
+## @Type API
+## @param Nick to find hostmask for
+## @param Variable to return hostmask in
+## @Note If no nick is found (or data about the nick
+## @Note is missing currently), the return variable will be empty.
+#---------------------------------------------------------------------
+module_nicktracking_get_hostmask_by_nick() {
+ hash_get 'module_nicktracking_nicks' "$(tr '[:upper:]' '[:lower:]' <<< "$1")" "$2"
+}
+
+#---------------------------------------------------------------------
+## Return list of nicks on a channel
+## @Type API
+## @param Channel to check
+## @param Variable to return space separated list in
+## @return 0 Channel data exists.
+## @return 1 We don't track this channel.
+#---------------------------------------------------------------------
+module_nicktracking_get_channel_nicks() {
+ if list_contains 'module_nicktracking_channels' "$1"; then
+ hash_get 'module_nicktracking_channels_nicks' "$1" "$2"
+ return 0
+ else
+ return 1
+ fi
+}
+
+
+#####################
+# Private functions #
+#####################
+
+#---------------------------------------------------------------------
+## Check if a nick should be removed
+## @Type Private
+## @param Nick to check
+#---------------------------------------------------------------------
+module_nicktracking_clear_nick() {
+ # If not on a channel any more, remove knowledge about nick.
+ if ! hash_search 'module_nicktracking_channels_nicks' "$1"; then
+ hash_unset 'module_nicktracking_nicks' "$1"
+ fi
+}
+
+#---------------------------------------------------------------------
+## Clear a channel (if we part it or such)
+## @Type Private
+## @param Channel name
+#---------------------------------------------------------------------
+module_nicktracking_clear_chan() {
+ list_remove 'module_nicktracking_channels' "$1" 'module_nicktracking_channels'
+ # Get list and then unset it.
+ local nicks=
+ hash_get 'module_nicktracking_channels_nicks' "$1" 'nicks'
+ hash_unset 'module_nicktracking_channels_nicks' "$1"
+ # Sigh, this isn't fast I know...
+ local nick
+ for nick in $nicks; do
+ module_nicktracking_clear_nick "$nick"
+ done
+}
+
+#---------------------------------------------------------------------
+## Parse RPL_NAMREPLY data.
+## @Type Private
+## @param NAMES data
+#---------------------------------------------------------------------
+module_nicktracking_parse_names() {
+ if [[ $1 =~ ^[=*@]?\ *(#[^ ]+)\ +:(.+) ]]; then
+ local channel="${BASH_REMATCH[1]}"
+ local nicks="${BASH_REMATCH[2]}"
+ local entry nick realnick
+ # Loop through the entries
+ for entry in $nicks; do
+ # This will work both with and without NAMESX
+ if [[ $entry =~ [$server_PREFIX_prefixes]*([^ ]+) ]]; then
+ nick="${BASH_REMATCH[1]}"
+ # Is UHNAMES enabled?
+ # If yes lets take care of hostmask.
+ if [[ $server_UHNAMES -eq 1 ]]; then
+ parse_hostmask_nick "$nick" 'realnick'
+ realnick="$(tr '[:upper:]' '[:lower:]' <<< "$realnick")"
+ hash_set 'module_nicktracking_nicks' "$realnick" "$nick"
+ # Add to nick list of channel if not in list
+ hash_contains 'module_nicktracking_channels_nicks' "$channel" "$realnick" || \
+ hash_append 'module_nicktracking_channels_nicks' "$channel" "$realnick"
+ else
+ realnick="$(tr '[:upper:]' '[:lower:]' <<< "$nick")"
+ # Add to nick list of channel if not in list
+ hash_contains 'module_nicktracking_channels_nicks' "$channel" "$realnick" || \
+ hash_append 'module_nicktracking_channels_nicks' "$channel" "$realnick"
+ fi
+ else
+ log_error_file unknown_data.log "module_nicktracking_parse_names: Uh uh, regex for inner loop is bad, couldn't parse: $nick"
+ log_error_file unknown_data.log "module_nicktracking_parse_names: Please report a bug with the above message"
+ fi
+ done
+ else
+ log_error_file unknown_data.log "module_nicktracking_parse_names: Uh uh, outer regex is bad, couldn't parse: $1"
+ log_error_file unknown_data.log "module_nicktracking_parse_names: Please report a bug with the above message"
+ fi
+ return 0
+}
+
+#---------------------------------------------------------------------
+## Parse RPL_WHOREPLY data.
+## @Type Private
+## @param WHO data
+#---------------------------------------------------------------------
+module_nicktracking_parse_who() {
+ # Read the who data into an array then extract the data from the array.
+ local whodata
+ read -ra whodata <<< "$1"
+ local channel="${whodata[0]}"
+ local ident="${whodata[1]}"
+ local host="${whodata[2]}"
+ local nick="${whodata[4]}"
+ local lowernick="$(tr '[:upper:]' '[:lower:]' <<< "$nick")"
+ # Set the hash tables
+ hash_set 'module_nicktracking_nicks' "$lowernick" "${nick}!${ident}@${host}"
+ # We don't want to add twice
+ hash_contains 'module_nicktracking_channels_nicks' "$channel" "$lowernick" || \
+ hash_append 'module_nicktracking_channels_nicks' "$channel" "$lowernick"
+}
+
+
+#---------------------------------------------------------------------
+## Add a nick to a channel
+## @Type Private
+## @param Channel
+## @param Hostmask
+## @param Nick
+#---------------------------------------------------------------------
+module_nicktracking_add_channel_nick() {
+ local nick="$(tr '[:upper:]' '[:lower:]' <<< "$3")"
+ hash_append 'module_nicktracking_channels_nicks' "$1" "$nick"
+ hash_set 'module_nicktracking_nicks' "$nick" "$2"
+}
+
+#---------------------------------------------------------------------
+## Remove a nick from a channel
+## @Type Private
+## @param Channel
+## @param Nick
+#---------------------------------------------------------------------
+module_nicktracking_remove_channel_nick() {
+ local nick="$(tr '[:upper:]' '[:lower:]' <<< "$2")"
+ hash_substract 'module_nicktracking_channels_nicks' "$1" "$nick"
+ module_nicktracking_clear_nick "$nick"
+}
+
+
+#########
+# Hooks #
+#########
+
+module_nicktracking_after_load() {
+ # Handle case of loading while bot is running
+ if [[ $server_connected -eq 1 ]]; then
+ module_nicktracking_channels="$channels_current"
+ local channel
+ for channel in $module_nicktracking_channels; do
+ send_raw "NAMES $channel"
+ # We have to send a WHO #channel if servers doesn't support UHNAMES.
+ if [[ $server_UHNAMES -eq 0 ]]; then
+ send_raw "WHO $channel"
+ fi
+ done
+ fi
+}
+
+module_nicktracking_before_connect() {
+ # Reset state.
+ unset module_nicktracking_channels
+ hash_reset module_nicktracking_channels_nicks
+ hash_reset module_nicktracking_nicks
+ return 0
+}
+
+
+##########################
+# Message handling hooks #
+##########################
+
+module_nicktracking_on_numeric() {
+ case $1 in
+ "$numeric_RPL_NAMREPLY")
+ # TODO: Parse NAMES
+ module_nicktracking_parse_names "$2"
+ ;;
+ "$numeric_RPL_WHOREPLY")
+ module_nicktracking_parse_who "$2"
+ ;;
+ esac
+}
+
+module_nicktracking_on_NICK() {
+ local oldnick oldident oldhost oldentry
+ parse_hostmask "$1" 'oldnick' 'oldident' 'oldhost'
+ local oldlowercase="$(tr '[:upper:]' '[:lower:]' <<< "$oldnick")"
+ local newlowercase="$(tr '[:upper:]' '[:lower:]' <<< "$2")"
+ # Remove old and add new.
+ hash_get 'module_nicktracking_nicks' "$oldlowercase" 'oldentry'
+ hash_unset 'module_nicktracking_nicks' "$oldlowercase"
+ hash_set 'module_nicktracking_nicks' "$newlowercase" "${2}!${oldident}@${oldhost}"
+ local channel
+ # Loop through the channels
+ for channel in $module_nicktracking_channels; do
+ hash_replace 'module_nicktracking_channels_nicks' "$channel" "$oldnick" "$newlowercase"
+ done
+ return 0
+}
+
+module_nicktracking_on_QUIT() {
+ local whoquit=
+ parse_hostmask_nick "$1" 'whoquit'
+ local nick="$(tr '[:upper:]' '[:lower:]' <<< "$whoquit")"
+ hash_unset 'module_nicktracking_nicks' "$nick"
+ local channel
+ # Remove from channel
+ for channel in $module_nicktracking_channels; do
+ hash_substract 'module_nicktracking_channels_nicks' "$channel" "$nick"
+ done
+}
+
+module_nicktracking_on_KICK() {
+ local whogotkicked="$3"
+ if [[ $whogotkicked == $server_nick_current ]]; then
+ module_nicktracking_clear_chan "$2"
+ else
+ module_nicktracking_remove_channel_nick "$2" "$whogotkicked"
+ fi
+}
+
+module_nicktracking_on_PART() {
+ # Check if it was us
+ local whoparted=
+ parse_hostmask_nick "$1" 'whoparted'
+ if [[ $whoparted == $server_nick_current ]]; then
+ module_nicktracking_clear_chan "$2"
+ else
+ module_nicktracking_remove_channel_nick "$2" "$whoparted"
+ fi
+}
+
+module_nicktracking_on_JOIN() {
+ local whojoined=
+ parse_hostmask_nick "$1" 'whojoined'
+ if [[ $whojoined == $server_nick_current ]]; then
+ module_nicktracking_channels+=" $2"
+ hash_set 'module_nicktracking_channels_nicks' "$2" "$server_nick_current"
+ # We have to send a WHO #channel if servers doesn't support UHNAMES.
+ if [[ $server_UHNAMES -eq 0 ]]; then
+ send_raw "WHO $2"
+ fi
+ else
+ module_nicktracking_add_channel_nick "$2" "$1" "$whojoined"
+ fi
+}