266 lines
11 KiB
Bash
266 lines
11 KiB
Bash
#!/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/>. #
|
|
# #
|
|
###########################################################################
|
|
#---------------------------------------------------------------------
|
|
## Handle registering of commands
|
|
#---------------------------------------------------------------------
|
|
|
|
#---------------------------------------------------------------------
|
|
## List of commands (maps to function for the command), a hash
|
|
## @Note Dummy variable to document the fact that it is a hash.
|
|
## @Type Private
|
|
#---------------------------------------------------------------------
|
|
commands_list=''
|
|
|
|
#---------------------------------------------------------------------
|
|
## List of functions (by module), a hash
|
|
## @Note Dummy variable to document the fact that it is a hash.
|
|
## @Type Private
|
|
#---------------------------------------------------------------------
|
|
commands_modules_functions=''
|
|
|
|
#---------------------------------------------------------------------
|
|
## List of commands (by function), a hash
|
|
## @Note Dummy variable to document the fact that it is a hash.
|
|
## @Type Private
|
|
#---------------------------------------------------------------------
|
|
commands_function_commands=''
|
|
|
|
#---------------------------------------------------------------------
|
|
## List of commands (by module)
|
|
## @Note Dummy variable to document the fact that it is a hash.
|
|
## @Type Private
|
|
#---------------------------------------------------------------------
|
|
commands_module_commands=''
|
|
|
|
#---------------------------------------------------------------------
|
|
## List of modules (by command)
|
|
## @Note Dummy variable to document the fact that it is a hash.
|
|
## @Type Private
|
|
#---------------------------------------------------------------------
|
|
commands_commands_module=''
|
|
|
|
#---------------------------------------------------------------------
|
|
## Comma separated list of all commands
|
|
## @Type Semi-private
|
|
#---------------------------------------------------------------------
|
|
commands_commands=''
|
|
|
|
# Just unset dummy variables.
|
|
unset commands_list commands_modules_functions commands_function_commands commands_module_commands commands_module_commands
|
|
|
|
#---------------------------------------------------------------------
|
|
## Register a command.
|
|
## @Type API
|
|
## @param Module name
|
|
## @param Function name (Part after module_modulename_handler_)
|
|
## @param Command name (on IRC, may contain spaces) (optional, defaults to same as function name, that is $2)
|
|
## @return 0 If successful
|
|
## @return 1 If failed for other reason
|
|
## @return 2 If invalid command name
|
|
## @return 3 If the command already exists (maybe from some other module)
|
|
## @return 4 If the function already exists for other command.
|
|
## @return 5 If the function in question is not declared.
|
|
#---------------------------------------------------------------------
|
|
commands_register() {
|
|
# Speed isn't that important here, it is only called at module load after all.
|
|
local module="$1"
|
|
local function_name="$2"
|
|
local command_name="$3"
|
|
# Command name is optional
|
|
if [[ -z $command_name ]]; then
|
|
command_name="$function_name"
|
|
fi
|
|
# Check for valid command name
|
|
if ! [[ $command_name =~ ^[a-zA-Z0-9] ]]; then
|
|
log_error "commands_register_command: Module \"$module\" gave invalid command name \"$command_name\". First char of command must be alphanumeric."
|
|
return 2
|
|
fi
|
|
if ! [[ $command_name =~ ^[a-zA-Z0-9][^\ ,]*( [^, ]+)?$ ]]; then
|
|
log_error "commands_register_command: Module \"$module\" gave invalid command name \"$command_name\". A command can be at most 2 words and should have no trailing white space and may not contain a \",\" (comma)."
|
|
return 2
|
|
fi
|
|
# Bail out if command is already registered.
|
|
if hash_exists 'commands_list' "$command_name"; then
|
|
log_error "commands_register_command: Failed to register command from \"$module\": a command with the name \"$command_name\" already exists."
|
|
return 3
|
|
fi
|
|
# Bail out if the function already is mapped to some other command
|
|
if hash_exists 'commands_function_commands' "$function_name"; then
|
|
log_error "commands_register_command: Failed to register command from \"$module\": the function is already registered under another command name."
|
|
return 4
|
|
fi
|
|
|
|
# Does the function itself exist?
|
|
local full_function_name="module_${module}_handler_${function_name}"
|
|
if ! declare -F | grep -qe "^declare -f ${full_function_name}$"; then
|
|
log_error "commands_register_command: Failed to register command from \"$module\": the function $full_function_name does not exist"
|
|
return 5
|
|
fi
|
|
# So it was valid. Lets add it then.
|
|
|
|
# Store in module -> function mapping.
|
|
hash_append 'commands_modules_functions' "$module" "$function_name" || {
|
|
log_error "commands_register_command: module -> commands mapping failed: mod=\"$module\" func=\"$function_name\"."
|
|
return 1
|
|
}
|
|
# Store in command -> function mapping
|
|
hash_set 'commands_list' "$command_name" "$full_function_name" || {
|
|
log_error "commands_register_command: command -> function mapping failed: cmd=\"$command_name\" full_func=\"$full_function_name\"."
|
|
return 1
|
|
}
|
|
# Store in function -> command mapping
|
|
hash_set 'commands_function_commands' "$function_name" "$command_name" || {
|
|
log_error "commands_register_command: function -> command mapping failed: func=\"$function_name\" cmd=\"$command_name\"."
|
|
return 1
|
|
}
|
|
# Store in command -> module mapping
|
|
hash_set 'commands_commands_module' "$command_name" "$module" || {
|
|
log_error "commands_register_command: command -> module mapping failed: cmd=\"$command_name\" mod=\"$module\"."
|
|
return 1
|
|
}
|
|
# Store in module -> commands mapping (ick!)
|
|
hash_append 'commands_module_commands' "$module" "$command_name" ',' || {
|
|
log_error "commands_register_command: module -> command mapping failed: mod=\"$module\" cmd=\"$command_name\"."
|
|
}
|
|
# Store in comma-separated command list
|
|
if [[ $commands_commands ]]; then
|
|
commands_commands+=",$command_name" || return 1
|
|
else
|
|
commands_commands="$command_name" || return 1
|
|
fi
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
## Get what module provides a command.
|
|
## @param Command to find.
|
|
## @param Variable to return in
|
|
## @Type Semi-private
|
|
#---------------------------------------------------------------------
|
|
commands_provides() {
|
|
hash_get "commands_commands_module" "$1" "$2"
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
## Get what commands exist in a module.
|
|
## @param Command to find.
|
|
## @param Variable to return comma separated list in
|
|
## @Type Semi-private
|
|
#---------------------------------------------------------------------
|
|
commands_in_module() {
|
|
hash_get "commands_module_commands" "$1" "$2"
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
## Will remove all commands from a module and unset the functions in question.
|
|
## @Type Private
|
|
## @param Module
|
|
## @return 0 If successful (or no commands exist for module)
|
|
## @return 1 If error
|
|
## @return 2 If fatal error
|
|
#---------------------------------------------------------------------
|
|
commands_unregister() {
|
|
local module="$1"
|
|
# Are there any commands for the module?
|
|
hash_exists 'commands_modules_functions' "$module" || {
|
|
return 0
|
|
}
|
|
local function_name full_function_name command_name functions
|
|
# Get list of functions
|
|
hash_get 'commands_modules_functions' "$module" 'functions' || return 2
|
|
# Iterate through the functions
|
|
for function_name in $functions; do
|
|
# Get command name
|
|
hash_get 'commands_function_commands' "$function_name" 'command_name' || return 2
|
|
# Unset from function -> command hash
|
|
hash_unset 'commands_function_commands' "$function_name" || return 2
|
|
# Unset from command -> function hash
|
|
hash_unset 'commands_list' "$command_name" || return 2
|
|
# Unset from command -> module mapping
|
|
hash_unset 'commands_commands_module' "$command_name" || return 2
|
|
# Remove from command list.
|
|
list_remove 'commands_commands' "$command_name" 'commands_commands' "," || return 1
|
|
# Unset help strings (if any):
|
|
unset helpentry_${module}_${function_name}_syntax
|
|
unset helpentry_${module}_${function_name}_description
|
|
# Unset function itself.
|
|
full_function_name="module_${module}_handler_${function_name}"
|
|
unset "$full_function_name" || return 2
|
|
done
|
|
# Unset the module -> commands mapping.
|
|
hash_unset 'commands_module_commands' "$module" || return 2
|
|
# Finally unset module -> functions mapping.
|
|
hash_unset 'commands_modules_functions' "$module" || return 2
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
## Process a line finding what command it would be
|
|
## @Type Private
|
|
## @param Sender
|
|
## @param Target
|
|
## @param Query
|
|
## @return 0 If not a command
|
|
## @return 1 If it indeed was a command that we therefore handled.
|
|
## @return 2 A command but that didn't exist.
|
|
#---------------------------------------------------------------------
|
|
commands_call_command() {
|
|
local regex="${config_commands_listenregex}"
|
|
# Not on a channel?
|
|
if [[ ! $2 =~ ^# ]]; then
|
|
# Should we treat it as a command anyway?
|
|
if [[ $config_commands_private_always == 1 ]]; then
|
|
local regex="(${config_commands_listenregex})?"
|
|
fi
|
|
fi
|
|
# Check if it is a command.
|
|
# (${config_commands_listenregex}, followed by an alphanumeric char.)
|
|
if [[ "$3" =~ ^${regex}([a-zA-Z0-9].*) ]]; then
|
|
local data="${BASH_REMATCH[@]: -1}"
|
|
# Right, get the parts of the command
|
|
if [[ $data =~ ^([a-zA-Z0-9][^ ]*)( [^, ]+)?( .*)? ]]; then
|
|
local firstword="${BASH_REMATCH[1]}"
|
|
local secondword="${BASH_REMATCH[2]}"
|
|
local parameters="${BASH_REMATCH[3]}"
|
|
|
|
local function=
|
|
# Check for two word commands first.
|
|
hash_get 'commands_list' "${firstword}${secondword}" 'function'
|
|
if [[ -z "$function" ]]; then
|
|
# Maybe one word then?
|
|
hash_get 'commands_list' "$firstword" 'function'
|
|
if [[ "$function" ]]; then
|
|
parameters="${secondword}${parameters}"
|
|
# No, not that either
|
|
else
|
|
return 2
|
|
fi
|
|
fi
|
|
|
|
# So we got a command, now lets run it
|
|
# (strip leading white spaces) from parameters.
|
|
"$function" "$1" "$2" "${parameters## }"
|
|
return 1
|
|
fi
|
|
return 2
|
|
fi
|
|
return 0
|
|
}
|