diff options
author | Márcio Silva <coadde at hyperbola dot info> | 2017-06-02 15:44:54 -0300 |
---|---|---|
committer | Márcio Silva <coadde at hyperbola dot info> | 2017-06-02 15:44:54 -0300 |
commit | b4830e97ae51396ccaa9ca2acb469aef80094ae8 (patch) | |
tree | c069b1ef6f9189848726121afa8d815e4e56d138 /lib/commands.sh | |
download | hyperbot-b4830e97ae51396ccaa9ca2acb469aef80094ae8.tar.lz hyperbot-b4830e97ae51396ccaa9ca2acb469aef80094ae8.tar.xz hyperbot-b4830e97ae51396ccaa9ca2acb469aef80094ae8.zip |
Add initial files from envbot v0.1-beta1
Diffstat (limited to 'lib/commands.sh')
-rw-r--r-- | lib/commands.sh | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/lib/commands.sh b/lib/commands.sh new file mode 100644 index 0000000..b914a58 --- /dev/null +++ b/lib/commands.sh @@ -0,0 +1,265 @@ +#!/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 +} |