aboutsummaryrefslogtreecommitdiffstats
path: root/lib/commands.sh
diff options
context:
space:
mode:
authorMárcio Silva <coadde at hyperbola dot info>2017-06-02 15:44:54 -0300
committerMárcio Silva <coadde at hyperbola dot info>2017-06-02 15:44:54 -0300
commitb4830e97ae51396ccaa9ca2acb469aef80094ae8 (patch)
treec069b1ef6f9189848726121afa8d815e4e56d138 /lib/commands.sh
downloadhyperbot-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.sh265
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
+}