aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/modules
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/modules')
-rw-r--r--contrib/modules/m_bugzilla.sh231
-rw-r--r--contrib/modules/m_calc.sh74
-rw-r--r--contrib/modules/m_convert.sh117
-rw-r--r--contrib/modules/m_eix.sh101
-rw-r--r--contrib/modules/m_eval.sh55
-rw-r--r--contrib/modules/m_helloworld.sh193
-rw-r--r--contrib/modules/m_perl/__main__.sh74
-rw-r--r--contrib/modules/m_perl/safe_eval.pl25
8 files changed, 870 insertions, 0 deletions
diff --git a/contrib/modules/m_bugzilla.sh b/contrib/modules/m_bugzilla.sh
new file mode 100644
index 0000000..c428cdc
--- /dev/null
+++ b/contrib/modules/m_bugzilla.sh
@@ -0,0 +1,231 @@
+#!/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/>. #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Check bugs using the program bugz and return output from it.
+## @pybugz bugz is a tool to search Gentoo bug reports (or other bugzillas)<br />
+## @pybugz From eix pybugz:<br />
+## @pybugz Description: Command line interface to (Gentoo) Bugzilla
+## @Dependencies This module therefore depends on:<br />
+## @Dependencies pybugz
+## @Config_variables To set bugzilla to use something like this in config:<br />
+## @Config_variables <pre>config_module_bugzilla_tracker_name[0]='gentoo'
+## @Config_variables config_module_bugzilla_tracker_url[0]='https://bugs.gentoo.org/'</pre>
+## @Config_variables Must end in trailing slash! Also the first entry will be the default.<br />
+## @Config_variables You also need to specify flood limiting<br />
+## @Config_variables (how often in seconds)<br />
+## @Config_variables <tt>config_module_bugzilla_rate='10'</tt>
+#---------------------------------------------------------------------
+
+module_bugzilla_INIT() {
+ modinit_API='2'
+ modinit_HOOKS='after_load'
+ commands_register "$1" 'bugs_search' 'bugs search' || return 1
+ commands_register "$1" 'bug' || return 1
+ helpentry_module_bugzilla_description="Search in bugzilla bug trackers."
+
+ helpentry_bugzilla_bugs_search_syntax='[-t <tracker>] [-(all|closed)] <pattern>'
+ helpentry_bugzilla_bugs_search_description='Search for <pattern> in <tracker> (or the default tracker).'
+
+ helpentry_bugzilla_bug_syntax='[-t <tracker>] <id>'
+ helpentry_bugzilla_bug_description='Look up the bug with <id> in <tracker> (or the default tracker).'
+}
+
+module_bugzilla_UNLOAD() {
+ unset module_bugzilla_last_query module_bugzilla_default_bugtracker
+ unset module_bugzilla_parse_config module_bugzilla_find_tracker
+ hash_reset 'bugzilla_tracker'
+}
+
+module_bugzilla_REHASH() {
+ module_bugzilla_parse_config
+}
+
+#---------------------------------------------------------------------
+## Initialize the hash of name -> url mapping
+## @Type Private
+#---------------------------------------------------------------------
+module_bugzilla_parse_config() {
+ hash_reset 'bugzilla_tracker'
+ local index
+ for index in "${!config_module_bugzilla_tracker_name[@]}"; do
+ hash_set 'bugzilla_tracker' \
+ "${config_module_bugzilla_tracker_name[index]}" \
+ "${config_module_bugzilla_tracker_url[index]}"
+ done
+ module_bugzilla_default_bugtracker="${config_module_bugzilla_tracker_url[0]}"
+}
+
+#---------------------------------------------------------------------
+## Find what tracker to use from the parameters.
+## @param Name of parameter variable.
+## @param Name of bugtracker variable.
+## @Type Private
+#---------------------------------------------------------------------
+module_bugzilla_find_tracker() {
+ if [[ "${!1}" =~ ^(-(tracker|t)\ +([A-Za-z0-9]+)\ +)(.+) ]]; then
+ local tindex="${BASH_REMATCH[3]}"
+ # Store result back in variable.
+ printf -v "$1" '%s' "${BASH_REMATCH[4]}"
+ local turl
+ hash_get 'bugzilla_tracker' "$tindex" 'turl'
+ if [[ $turl ]]; then
+ printf -v "$2" '%s' "$turl"
+ else
+ feedback_generic_error "$sendernick" "bugs search" "No such bug tracker found."
+ fi
+ else
+ printf -v "$2" '%s' "${module_bugzilla_default_bugtracker}"
+ fi
+}
+
+# Called after module has loaded.
+# Check for bugz
+module_bugzilla_after_load() {
+ if ! hash bugz > /dev/null 2>&1; then
+ log_error "Couldn't find bugz command line tool. The bugzilla module depend on that tool (emerge pybugz to get it on Gentoo)."
+ return 1
+ fi
+ if [[ -z ${config_module_bugzilla_tracker_url[0]} ]]; then
+ log_error "Please set at least config_module_bugzilla_url[0] in config."
+ return 1
+ fi
+ if [[ -z ${config_module_bugzilla_tracker_name[0]} ]]; then
+ log_error "Please set at least config_module_bugzilla_name[0] in config."
+ return 1
+ fi
+ if [[ -z $config_module_bugzilla_rate ]]; then
+ log_error "Please set config_module_bugzilla_rate in config."
+ return 1
+ fi
+ module_bugzilla_parse_config
+ unset module_bugzilla_last_query
+ module_bugzilla_last_query='0'
+}
+
+module_bugzilla_handler_bugs_search() {
+ # Accept this anywhere, unless someone can give a good reason not to.
+ local sender="$1"
+ local channel="$2"
+ local sendernick=
+ parse_hostmask_nick "$sender" 'sendernick'
+ # If it isn't in a channel send message back to person who send it,
+ # otherwise send in channel
+ if ! [[ $2 =~ ^# ]]; then
+ channel="$sendernick"
+ fi
+ local parameters="$3"
+ local bugtracker
+ module_bugzilla_find_tracker 'parameters' 'bugtracker'
+ if [[ "$parameters" =~ ^(-(all|closed)\ +)?(.+) ]]; then
+ local mode="${BASH_REMATCH[2]}"
+ local pattern="${BASH_REMATCH[@]: -1}"
+ # Simple flood limiting
+ if time_check_interval "$module_bugzilla_last_query" "$config_module_bugzilla_rate"; then
+ time_get_current 'module_bugzilla_last_query'
+ local bugs_parameters=""
+ if [[ $mode = "all" ]]; then
+ bugs_parameters="-s all"
+ elif [[ $mode = "closed" ]]; then
+ bugs_parameters="-s CLOSED -s RESOLVED"
+ fi
+ log_info_file bugzilla.log "$sender made the bot run pybugz search on \"$pattern\""
+ # We unset TERM because otherwise bugz output some control codes
+ local result="$(unset TERM; ulimit -t 4; bugz -fqb "$bugtracker" search $bugs_parameters "$pattern")"
+ local lines="$(wc -l <<< "$result")"
+ local header footer
+ # Some odd formatting chars are always returned (in some versions of pybugz), so we can't check for empty string.
+ if [[ ${#result} -le 10 ]]; then
+ header="No bugs matching \"$pattern\" found"
+ elif [[ $lines -gt 1 ]]; then
+ header="First bug matching \"$pattern\": "
+ footer=" ($lines more bugs found)"
+ else
+ header="One bug matching \"$pattern\" found: "
+ fi
+ if [[ $(head -n 1 <<< "$result") =~ \ ([0-9]+)\ +([^ ]+)\ +(.*)$ ]]; then
+ local pretty_result="${format_bold}${bugtracker}${BASH_REMATCH[1]}${format_bold} ${format_bold}Description${format_bold}: ${BASH_REMATCH[3]} ${format_bold}Assigned To${format_bold}: ${BASH_REMATCH[2]}"
+ fi
+ send_msg "$channel" "${header}${pretty_result}${footer}"
+ else
+ log_error_file bugzilla.log "FLOOD DETECTED in bugzilla module"
+ fi
+ else
+ feedback_bad_syntax "$sendernick" "bugs search" "[-t tracker] [-(all|closed)] <pattern>"
+ fi
+}
+
+module_bugzilla_handler_bug() {
+ # Accept this anywhere, unless someone can give a good reason not to.
+ local sender="$1"
+ local channel="$2"
+ local sendernick=
+ parse_hostmask_nick "$sender" 'sendernick'
+ # If it isn't in a channel send message back to person who send it,
+ # otherwise send in channel
+ if ! [[ $2 =~ ^# ]]; then
+ channel="$sendernick"
+ fi
+ local parameters="$3"
+ local bugtracker
+ module_bugzilla_find_tracker 'parameters' 'bugtracker'
+ # Extract bug ID
+ if [[ "$parameters" =~ ^([0-9]+) ]]; then
+ local id="${BASH_REMATCH[1]}"
+ # Simple flood limiting
+ if time_check_interval "$module_bugzilla_last_query" "$config_module_bugzilla_rate"; then
+ time_get_current 'module_bugzilla_last_query'
+ log_info_file bugzilla.log "$sender made the bot check with pybugz for bug \"$id\""
+ # We unset TERM because otherwise bugz output some control codes
+ local result="$(unset TERM; ulimit -t 4; bugz -fqb "$bugtracker" get -n "$id" | grep -E 'Title|Status|Resolution')"
+ local resultread pretty_result
+ local title status resolution
+ # Read the data out of the multiline result.
+ while read -r resultread; do
+ if [[ $resultread =~ ^Title[\ :]+([^ ].*) ]]; then
+ title="${BASH_REMATCH[1]}"
+ elif [[ $resultread =~ ^Status[\ :]+([^ ].*) ]]; then
+ status="${BASH_REMATCH[1]}"
+ elif [[ $resultread =~ ^Resolution[\ :]+([^ ].*) ]]; then
+ resolution="${BASH_REMATCH[1]}"
+ fi
+ done <<< "$result"
+ # Yes this is a bit of a mess
+ if [[ "$title" ]]; then
+ # This info is always here
+ pretty_result="${format_bold}Bug $id${format_bold} (${format_bold}Status${format_bold} $status"
+ # The resolution may not exist, add it if it does.
+ if [[ $resolution ]]; then
+ pretty_result+=", ${format_bold}Resolution${format_bold} $resolution"
+ fi
+ # And add the title in. Does not depend on if resolution exist.
+ pretty_result+="): $title (${bugtracker}${id})"
+ else
+ pretty_result="Bug $id not found"
+ fi
+ send_msg "$channel" "${pretty_result}"
+ else
+ log_error_file bugzilla.log "FLOOD DETECTED in bugzilla module"
+ fi
+ else
+ feedback_bad_syntax "$sendernick" "bug" "[-t tracker] <id>"
+ fi
+}
diff --git a/contrib/modules/m_calc.sh b/contrib/modules/m_calc.sh
new file mode 100644
index 0000000..fa1d98d
--- /dev/null
+++ b/contrib/modules/m_calc.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+# -*- coding: utf-8 -*-
+###########################################################################
+# #
+# envbot - an IRC bot in bash #
+# Copyright (C) 2007-2008 EmErgE <halt.system@gmail.com> #
+# 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/>. #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Calculate with bc
+## @Dependencies This module depends on bc
+## @Dependencies (http://www.gnu.org/software/bc/bc.html)
+#---------------------------------------------------------------------
+
+module_calc_INIT() {
+ modinit_API='2'
+ modinit_HOOKS=''
+ if ! hash bc > /dev/null 2>&1; then
+ log_error "Couldn't find \"bc\" command line tool. The calc module depend on that tool."
+ return 1
+ fi
+ commands_register "$1" 'calc' || return 1
+ helpentry_module_calc_description="Simple calculator module."
+ helpentry_calc_calc_syntax='<expression>'
+ helpentry_calc_calc_description='Try to calculate <expression> using bc.'
+}
+
+module_calc_UNLOAD() {
+ return 0
+}
+
+module_calc_REHASH() {
+ return 0
+}
+
+module_calc_handler_calc() {
+ local sender="$1"
+ local channel="$2"
+ local sendernick=
+ parse_hostmask_nick "$sender" 'sendernick'
+ # If it isn't in a channel send message back to person who send it,
+ # otherwise send in channel
+ if ! [[ $2 =~ ^# ]]; then
+ channel="$sendernick"
+ fi
+ local parameters="$3"
+
+ # Sanity check on parameters
+ parameters="$(tr -d '\n\r\t' <<< "$parameters")"
+ if grep -Eq "scale=|read|while|if|for|break|continue|print|return|define|[e|j] *\(" <<< "$parameters"; then
+ send_msg "$channel" "${sendernick}: Can't calculate that, it contains a potential unsafe/very slow function."
+ elif [[ $parameters =~ \^[0-9]{4,} ]]; then
+ send_msg "$channel" "${sendernick}: Some too large numbers."
+ else
+ # Force some security guards
+ local myresult="$(ulimit -t 4; echo "$parameters" | bc -l 2>&1 | head -n 1)"
+ send_msg "$channel" "${sendernick}: $myresult"
+ fi
+
+}
diff --git a/contrib/modules/m_convert.sh b/contrib/modules/m_convert.sh
new file mode 100644
index 0000000..3910379
--- /dev/null
+++ b/contrib/modules/m_convert.sh
@@ -0,0 +1,117 @@
+#!/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/>. #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Convert values with units
+## @Dependencies This module depends on units
+## @Dependencies (http://www.gnu.org/software/units/units.html)
+#---------------------------------------------------------------------
+
+module_convert_INIT() {
+ modinit_API='2'
+ modinit_HOOKS=''
+ if ! hash units > /dev/null 2>&1; then
+ log_error "Couldn't find \"units\" command line tool. The convert module depend on that tool."
+ return 1
+ fi
+ # Is it GNU units?
+ if units --help > /dev/null 2>&1; then
+ module_convert_gnu=1
+ else
+ module_convert_gnu=0
+ fi
+ commands_register "$1" 'convert' || return 1
+ helpentry_module_convert_description="Convert between different units."
+ helpentry_convert_convert_syntax='<value> <unit> [to] <unit>'
+ helpentry_convert_convert_description='Convert the value from one unit to another.'
+}
+
+module_convert_UNLOAD() {
+ return 0
+}
+
+module_convert_REHASH() {
+ return 0
+}
+
+module_convert_handler_convert() {
+ local sender="$1"
+ local channel="$2"
+ local sendernick=
+ parse_hostmask_nick "$sender" 'sendernick'
+ # If it isn't in a channel send message back to person who send it,
+ # otherwise send in channel
+ if ! [[ $2 =~ ^# ]]; then
+ channel="$sendernick"
+ fi
+ local parameters="$3"
+ # Format: convert <value> <in unit> <out unit>
+ if [[ "$parameters" =~ ^([-0-9.]+)\ +([a-zA-Z0-9^/*]+)\ +(to\ +)?([a-zA-Z0-9^/*]+) ]]; then
+ local value="${BASH_REMATCH[1]}"
+ local inunit="${BASH_REMATCH[2]}"
+ local outunit="${BASH_REMATCH[@]: -1}"
+ # Construct expression of value and inunit,
+ # needed because of temperature
+ case $inunit in
+ C|F|K)
+ # This only work on GNU units.
+ if [[ $module_convert_gnu = 1 ]]; then
+ local inexpr="temp${inunit}($value)"
+ else
+ local inexpr="$value deg${inunit}"
+ fi
+ ;;
+ *)
+ local inexpr="$value $inunit"
+ ;;
+ esac
+ # Out: Temperature
+ case $outunit in
+ C|F|K)
+ # This only work on GNU units
+ if [[ $module_convert_gnu = 1 ]]; then
+ local outexpr="temp${outunit}"
+ else
+ local outexpr="deg${outunit}"
+ fi
+ local outunit="degrees $outunit"
+ ;;
+ *)
+ local outexpr="$outunit"
+ ;;
+ esac
+
+ # Need to do the local separately or return code will be messed up.
+ local myresult
+ # Force some security guards
+ # We can't use -t, that doesn't work on *BSD units...
+ # so we use awk to get interesting lines.
+ # Then check pipestatus to give nice return code
+ myresult="$(ulimit -t 4; units -q "$inexpr" "$outexpr" 2>&1 | awk '/^\t[0-9]+/ {print $1} /\*/ {print $2} /[Ee]rror|[Uu]nknown/'; [[ ${PIPESTATUS[0]} -eq 0 ]] || exit 1)"
+ if [[ $? -eq 0 ]]; then
+ send_msg "$channel" "${sendernick}: $myresult $outunit"
+ else
+ send_msg "$channel" "${sendernick}: Error: $myresult"
+ fi
+ else
+ feedback_bad_syntax "$sendernick" "convert" "<value> <in unit> [to] <out unit>"
+ fi
+}
diff --git a/contrib/modules/m_eix.sh b/contrib/modules/m_eix.sh
new file mode 100644
index 0000000..46ba964
--- /dev/null
+++ b/contrib/modules/m_eix.sh
@@ -0,0 +1,101 @@
+#!/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/>. #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Check eix and return output from it.
+## @eix eix is a tool to search Gentoo packages<br />
+## @eix From eix eix:<br />
+## @eix <tt> Description: Small utility for searching ebuilds with indexing for fast results</tt>
+## @Dependencies This module therefore depends on:<br />
+## @Dependencies Gentoo<br />
+## @Dependencies eix<br />
+## @Config_variables You need to specify flood limiting in config.<br />
+## @Config_variables (how often in seconds)<br />
+## @Config_variables <tt>config_module_eix_rate='5'</tt><br />
+#---------------------------------------------------------------------
+
+module_eix_INIT() {
+ modinit_API='2'
+ modinit_HOOKS='after_load'
+ commands_register "$1" 'eix' || return 1
+ helpentry_module_eix_description="Search in Gentoo package database."
+
+ helpentry_eix_eix_syntax='<pattern>'
+ helpentry_eix_eix_description='Search for wildcard pattern in the local copy of the Gentoo package database.'
+}
+
+module_eix_UNLOAD() {
+ unset module_eix_format_string module_eix_last_query
+}
+
+module_eix_REHASH() {
+ return 0
+}
+
+# Called after module has loaded.
+# Check for eix and config being sane.
+module_eix_after_load() {
+ # Check (silently) for eix
+ if ! hash eix >/dev/null 2>&1; then
+ log_error "Couldn't find \"eix\" command line tool. The eix module depend on that tool."
+ return 1
+ fi
+ if [[ -z $config_module_eix_rate ]]; then
+ log_error_file eix.log "YOU MUST SET config_module_eix_rate IN YOUR CONFIG IN ORDER TO USE THE EIX MODULE"
+ return 1
+ fi
+ # Flood limiting.
+ unset module_eix_last_query
+ module_eix_last_query='0'
+}
+
+#---------------------------------------------------------------------
+## eix format string.
+## @Type Private
+#---------------------------------------------------------------------
+module_eix_format_string="<category>/${format_bold}<name>${format_bold} \(<availableversionsshort>\) \(${format_bold}<homepage>${format_bold}\): <description>"
+
+module_eix_handler_eix() {
+ # Accept this anywhere, unless someone can give a good reason not to.
+ local sender="$1"
+ local channel="$2"
+ # If it isn't in a channel send message back to person who send it,
+ # otherwise send in channel
+ if ! [[ $2 =~ ^# ]]; then
+ parse_hostmask_nick "$sender" 'channel'
+ fi
+ local parameters="$3"
+ if [[ "$parameters" =~ ^(.+) ]]; then
+ local pattern="${BASH_REMATCH[1]}"
+ # Simple flood limiting
+ if time_check_interval "$module_eix_last_query" "$config_module_eix_rate"; then
+ time_get_current 'module_eix_last_query'
+ log_info_file eix.log "$sender made the bot run eix on \"$pattern\""
+ send_msg "$channel" "$(ulimit -t 4; EIX_PRINT_IUSE='false' eix -pSCxs --format "$module_eix_format_string" "$pattern" | head -n 1)"
+ else
+ log_error_file eix.log "FLOOD DETECTED in eix module"
+ fi
+ else
+ local sendernick
+ parse_hostmask_nick "$sender" 'sendernick'
+ feedback_bad_syntax "$sendernick" "eix" "<pattern>"
+ fi
+}
diff --git a/contrib/modules/m_eval.sh b/contrib/modules/m_eval.sh
new file mode 100644
index 0000000..c3a03c4
--- /dev/null
+++ b/contrib/modules/m_eval.sh
@@ -0,0 +1,55 @@
+#!/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/>. #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Allow owners to make the bot eval any code<br />
+## THIS IS FOR DEBUGGING ONLY!!!! Don't use it in other cases
+#---------------------------------------------------------------------
+
+module_eval_INIT() {
+ modinit_API='2'
+ modinit_HOOKS=''
+ commands_register "$1" 'eval' || return 1
+ helpentry_module_eval_description="Eval command for developers debugging the bot. Don't use if you don't know what you are doing."
+
+ helpentry_eval_eval_syntax='<expression>'
+ helpentry_eval_eval_description='Evaluate <expression> in global scope.'
+}
+
+module_eval_UNLOAD() {
+ return 0
+}
+
+module_eval_REHASH() {
+ return 0
+}
+
+module_eval_handler_eval() {
+ # Accept anywhere
+ local sender="$1"
+ if access_check_owner "$sender"; then
+ local parameters="$3"
+ access_log_action "$sender" "did eval with: $parameters"
+ eval "$parameters"
+ else
+ access_fail "$sender" "eval a command" "owner"
+ fi
+}
diff --git a/contrib/modules/m_helloworld.sh b/contrib/modules/m_helloworld.sh
new file mode 100644
index 0000000..25b6a10
--- /dev/null
+++ b/contrib/modules/m_helloworld.sh
@@ -0,0 +1,193 @@
+#!/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/>. #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Example module meant to help people who want to make modules for envbot
+#---------------------------------------------------------------------
+
+#---------------------------------------------------------------------
+## This is called to get a list of hooks that the module provides.
+## Use the hook after_load to do other things
+## @Type Module hook
+## @Stdout A list of hooks.
+#---------------------------------------------------------------------
+module_helloworld_INIT() {
+ modinit_API='2'
+ # Set modinit_HOOKS to the hooks we have.
+ modinit_HOOKS='after_load'
+ # Register commands, each command handler will have a name like:
+ # module_modulename_handler_function
+ # Example: module_helloworld_handler_hi
+ # If command name and function name are the same you can skip
+ # command name.
+ commands_register "$1" 'hi' || return 1
+ # Here the function name and command name can't be the same,
+ # as the command name got space in it. Note that a command can
+ # be at most two words.
+ commands_register "$1" 'hello_world' 'hello world' || return 1
+ helpentry_module_helloworld_description="This is an example module."
+
+ helpentry_helloworld_hi_syntax='<target> <message>'
+ helpentry_helloworld_hi_description='Send a greeting to <target> (nick or channel) with the <message>.'
+
+ helpentry_helloworld_helloworld_syntax='<message>'
+ helpentry_helloworld_helloworld_description='Send a greeting to the current scope with the one word <message>.'
+}
+
+#---------------------------------------------------------------------
+## Here we do anything needed to unload the module.
+## @Type Module hook
+## @return 0 Unloaded correctly
+## @return 1 Failed to unload. On this the bot will quit.
+## @Note This function is NOT called when the bot is exiting. To check for that
+## @Note use the FINALISE hook!
+#---------------------------------------------------------------------
+module_helloworld_UNLOAD() {
+ # Here we unset any functions and variables that we have defined
+ # except the hook functions.
+ unset module_helloworld_variable module_helloworld_function
+}
+
+#---------------------------------------------------------------------
+## Here do anything needed at rehash
+## @Type Module hook
+## @return 0 Rehashed correctly
+## @return 1 Non fatal error for the bot itself. The bot will call UNLOAD on the module.
+## @return 2 Fatal error of some kind. On this the bot will quit.
+#---------------------------------------------------------------------
+module_helloworld_REHASH() {
+ # We don't have anything to do here.
+ return 0
+}
+
+#---------------------------------------------------------------------
+## Called after all the hooks are added for the module.
+## @Type Module hook
+## @return 0 Unloaded correctly
+## @return 1 Failed. On this the bot will call unload on the module.
+#---------------------------------------------------------------------
+module_helloworld_after_load() {
+ # Set a global variable, this can't be done in INIT.
+ # Remember to unset all global variables on UNLOAD!
+ module_helloworld_variable="world!"
+}
+
+#---------------------------------------------------------------------
+## This logs "hello world" as an informative level log item
+## when called
+## @Type Private
+## @Note Note that this is a custom function used by
+## @Note some other part of the script
+#---------------------------------------------------------------------
+module_helloworld_function() {
+ # Lets use the variable defined above!
+ log_info "Hello $module_helloworld_variable"
+}
+
+#---------------------------------------------------------------------
+## Called on the command "hello world"
+## @Type Function handler
+## @param From who (n!u@h)
+## @param To who (channel or botnick)
+## @param The parameters to the command
+#---------------------------------------------------------------------
+module_helloworld_handler_hello_world() {
+ local sender="$1"
+ local target
+ # If it isn't in a channel send message back to person who send it,
+ # otherwise send in channel
+ if [[ $2 =~ ^# ]]; then
+ target="$2"
+ else
+ # parse_hostmask_nick gets the nick from a hostmask.
+ parse_hostmask_nick "$sender" 'target'
+ fi
+
+ local parameters="$3"
+ # Check if the syntax for the parameters is correct!
+ # Lets check for one parameter without spaces
+ if [[ "$parameters" =~ ^([^ ]+) ]]; then
+ # Store the bit in the first group of the regex into
+ # the variable message
+ local message="${BASH_REMATCH[1]}"
+ # Send a hello world message:
+ send_msg "$target" "Hello world! I had the parameter $message"
+ else
+ # So the regex for matching parameters didn't work, lets provide
+ # the user with some feedback!
+ local sendernick
+ parse_hostmask_nick "$sender" 'sendernick'
+ feedback_bad_syntax "$sendernick" "hello world" "<message> # Where message is one word!"
+ fi
+}
+
+#---------------------------------------------------------------------
+## Called on the command "hi"
+## @Type Function handler
+## @param From who (n!u@h)
+## @param To who (channel or botnick)
+## @param The parameters to the command
+#---------------------------------------------------------------------
+module_helloworld_handler_hi() {
+ local sender="$1"
+
+ local parameters="$3"
+ # Two parameters, one is single word, the other matches to
+ # end of line.
+ if [[ "$parameters" =~ ^([^ ]+)\ (.+) ]]; then
+ # Store the groups in some variables.
+ local target_channel="${BASH_REMATCH[1]}"
+ local message="${BASH_REMATCH[2]}"
+ # This is used for the access check below.
+ # Check if target is a channel or nick.
+ local scope
+ if [[ $target_channel =~ ^# ]]; then
+ scope="$target_channel"
+ else
+ scope="MSG"
+ fi
+
+ # Lets check for access.
+ # First variable is capability to check for
+ # Second variable is the hostmask of the sender of the message
+ # Third variable is the scope, that we set above.
+ if access_check_capab "hi" "$sender" "$scope"; then
+ # Such important events for security as a "hi" should
+ # really get logged even if it fails! ;)
+ access_log_action "$sender" "made the hi channel \"$message\" in/to \"$target_channel\""
+ local sendernick
+ parse_hostmask_nick "$sender" 'sendernick'
+ send_msg "${target_channel}" "Hi $target_channel! $sendernick wants you to know ${message}"
+ # As an example also call our function.
+ module_helloworld_function
+ else
+ # Lets tell the sender they lack access!
+ # access_fail will send a PRIVMSG to the sender saying permission denied
+ # and also log the failed attempt.
+ access_fail "$sender" "make the bot hi" "hi"
+ fi
+ else
+ # As above, provide feedback about bad syntax.
+ local sendernick
+ parse_hostmask_nick "$sender" 'sendernick'
+ feedback_bad_syntax "$sendernick" "hi" "<target> <message> # Where target is a nick or channel"
+ fi
+}
diff --git a/contrib/modules/m_perl/__main__.sh b/contrib/modules/m_perl/__main__.sh
new file mode 100644
index 0000000..36906a5
--- /dev/null
+++ b/contrib/modules/m_perl/__main__.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+# -*- coding: utf-8 -*-
+###########################################################################
+# #
+# envbot - an IRC bot in bash #
+# Copyright (C) 2007-2008 EmErgE <halt.system@gmail.com> #
+# Copyright (C) 2007-2008 Vsevolod Kozlov #
+# 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/>. #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Evaluate with perl
+## @Dependencies This module depends on perl
+## @Dependencies (http://www.perl.org/about.html)
+## @Note This may not be safe!
+#---------------------------------------------------------------------
+
+module_perl_INIT() {
+ modinit_API='2'
+ modinit_HOOKS=''
+ if ! hash perl > /dev/null 2>&1; then
+ log_error "Couldn't find \"perl\" binary. The perl module depends on it."
+ return 1
+ fi
+ module_perl_working_dir="$MODULE_BASE_PATH"
+ commands_register "$1" 'perl' || return 1
+ helpentry_module_perl_description="Execute perl code."
+
+ helpentry_perl_perl_syntax='<code>'
+ helpentry_perl_perl_description='Execute perl code.'
+}
+
+module_perl_UNLOAD() {
+ unset module_perl_working_dir
+ unset module_perl_handler_perl
+ return 0
+}
+
+module_perl_REHASH() {
+ return 0
+}
+
+module_perl_handler_perl() {
+ local sender="$1"
+ local channel="$2"
+ local sendernick=
+ parse_hostmask_nick "$sender" 'sendernick'
+ if access_check_capab "perl_eval" "$sender" "$channel"; then
+ # If it isn't in a channel send message back to person who send it,
+ # otherwise send in channel
+ if ! [[ $2 =~ ^# ]]; then
+ channel="$sendernick"
+ fi
+ local parameters="$3"
+ # Extremely Safe Perl Evaluation
+ local myresult="$(perl "${module_perl_working_dir}/safe_eval.pl" "$parameters")"
+ send_msg "$channel" "${sendernick}: $myresult"
+ else
+ access_fail "$sender" "make the bot evalute perl expressions" "perl_eval"
+ fi
+}
diff --git a/contrib/modules/m_perl/safe_eval.pl b/contrib/modules/m_perl/safe_eval.pl
new file mode 100644
index 0000000..1e6489f
--- /dev/null
+++ b/contrib/modules/m_perl/safe_eval.pl
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+use strict;
+use Safe;
+
+my $expr = shift;
+
+my $cpt = new Safe;
+
+#Basic variable IO and traversal
+
+$cpt->permit(':base_core');
+
+$SIG{ALRM} = sub {
+ die "Alarm";
+};
+
+alarm(4);
+
+my $ret = $cpt->reval($expr);
+
+if ($@) {
+ print $@;
+} else {
+ print $ret;
+}