aboutsummaryrefslogtreecommitdiffstats
path: root/modules/m_factoids.sh
diff options
context:
space:
mode:
Diffstat (limited to 'modules/m_factoids.sh')
-rw-r--r--modules/m_factoids.sh461
1 files changed, 461 insertions, 0 deletions
diff --git a/modules/m_factoids.sh b/modules/m_factoids.sh
new file mode 100644
index 0000000..ba164ed
--- /dev/null
+++ b/modules/m_factoids.sh
@@ -0,0 +1,461 @@
+#!/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/>. #
+# #
+###########################################################################
+#---------------------------------------------------------------------
+## Simple factoids module using SQLite3
+#---------------------------------------------------------------------
+
+module_factoids_INIT() {
+ modinit_API='2'
+ modinit_HOOKS='after_load on_PRIVMSG'
+ commands_register "$1" 'learn' || return 1
+ commands_register "$1" 'forget' || return 1
+ commands_register "$1" 'lock_factoid' 'lock factoid' || return 1
+ commands_register "$1" 'unlock_factoid' 'unlock factoid' || return 1
+ commands_register "$1" 'whatis' || return 1
+ commands_register "$1" 'factoid_stats' 'factoid stats' || return 1
+ helpentry_module_factoids_description="Provides a factoid database."
+
+ helpentry_factoids_learn_syntax='<key> (as|is|are|=) <value>'
+ helpentry_factoids_learn_description='Teach the bot a new factoid.'
+
+ helpentry_factoids_forget_syntax='<key>'
+ helpentry_factoids_forget_description='Make the bot forget the factoid <key>.'
+
+ helpentry_factoids_lock_factoid_syntax='<key>'
+ helpentry_factoids_lock_factoid_description='Prevent normal users from changing the factoid <key>.'
+
+ helpentry_factoids_unlock_factoid_syntax='<key>'
+ helpentry_factoids_unlock_factoid_description='Allow changes to a previously locked factoid <key>.'
+
+ helpentry_factoids_whatis_syntax='<key>'
+ helpentry_factoids_whatis_description='Look up the factoid <key>.'
+
+ helpentry_factoids_factoid_stats_syntax=''
+ helpentry_factoids_factoid_stats_description='Report some statistics on the factoid database.'
+}
+
+
+module_factoids_UNLOAD() {
+ # Ok this is a LOT. I hope I got all...
+ unset module_factoids_set module_factoids_remove module_factoids_parse_assignment
+ unset module_factoids_parse_key module_factoids_parse_value
+ unset module_factoids_set_INSERT_or_UPDATE module_factoids_send_factoid
+ unset module_factoids_get_count module_factoids_get_locked_count
+ unset module_factoids_is_locked module_factoids_lock module_factoids_unlock
+ unset module_factoids_SELECT module_factoids_INSERT module_factoids_UPDATE module_factoids_DELETE
+}
+
+
+module_factoids_REHASH() {
+ return 0
+}
+
+
+# Called after module has loaded.
+module_factoids_after_load() {
+ modules_depends_register "factoids" "sqlite3" || {
+ # This error reporting is hackish, will fix later.
+ if ! list_contains "modules_loaded" "sqlite3"; then
+ log_error "The factoids module depends upon the SQLite3 module being loaded."
+ fi
+ return 1
+ }
+ if [[ -z $config_module_factoids_table ]]; then
+ log_error "Factiods table (config_module_factoids_table) must be set in config if you want to use factoids module."
+ return 1
+ fi
+ if ! module_sqlite3_table_exists "$config_module_factoids_table"; then
+ log_error "factoids module: $config_module_factoids_table does not exist in the database file."
+ log_error "factoids module: See comment in doc/factoids.sql for how to create the table."
+ fi
+}
+
+
+#---------------------------------------------------------------------
+## Get an item from DB
+## @Type Private
+## @param Key
+## @Stdout The result of the database query.
+#---------------------------------------------------------------------
+module_factoids_SELECT() {
+ #$ sqlite3 -list data/factoids.sqlite "SELECT value from factoids WHERE name='factoids';"
+ #A system that stores useful bits of information
+ module_sqlite3_exec_sql "SELECT value FROM $config_module_factoids_table WHERE name='$(module_sqlite3_clean_string "$1")';"
+}
+
+
+#---------------------------------------------------------------------
+## Insert a new item into DB
+## @Type Private
+## @param key
+## @param value
+## @param hostmask of person who added it
+#---------------------------------------------------------------------
+module_factoids_INSERT() {
+ module_sqlite3_exec_sql \
+ "INSERT INTO $config_module_factoids_table (name, value, who) VALUES('$(module_sqlite3_clean_string "$1")', '$(module_sqlite3_clean_string "$2")', '$(module_sqlite3_clean_string "$3")');"
+}
+
+
+#---------------------------------------------------------------------
+## Change the item in DB
+## @Type Private
+## @param key
+## @param new value
+## @param hostmask of person who changed it
+#---------------------------------------------------------------------
+module_factoids_UPDATE() {
+ module_sqlite3_exec_sql \
+ "UPDATE $config_module_factoids_table SET value='$(module_sqlite3_clean_string "$2")', who='$(module_sqlite3_clean_string "$3")' WHERE name='$(module_sqlite3_clean_string "$1")';"
+}
+
+
+#---------------------------------------------------------------------
+## Remove an item
+## @Type Private
+## @param key
+#---------------------------------------------------------------------
+module_factoids_DELETE() {
+ module_sqlite3_exec_sql "DELETE FROM $config_module_factoids_table WHERE name='$(module_sqlite3_clean_string "$1")';"
+}
+
+
+#---------------------------------------------------------------------
+## How many factoids are there
+## @Type Private
+## @Stdout Count of factoids.
+#---------------------------------------------------------------------
+module_factoids_get_count() {
+ module_sqlite3_exec_sql "SELECT COUNT(name) FROM $config_module_factoids_table;"
+}
+
+
+#---------------------------------------------------------------------
+## How many locked factoids are there
+## @Type Private
+## @Stdout Count of locked factoids.
+#---------------------------------------------------------------------
+module_factoids_get_locked_count() {
+ module_sqlite3_exec_sql "SELECT COUNT(name) FROM $config_module_factoids_table WHERE is_locked='1';"
+}
+
+
+#---------------------------------------------------------------------
+## Check if factoid is locked or not.
+## @Type Private
+## @param key
+## @return 0 locked
+## @return 1 not locked
+#---------------------------------------------------------------------
+module_factoids_is_locked() {
+ local lock="$(module_sqlite3_exec_sql "SELECT is_locked FROM $config_module_factoids_table WHERE name='$(module_sqlite3_clean_string "$1")';")"
+ if [[ $lock == "1" ]]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+
+#---------------------------------------------------------------------
+## Lock a factoid against changes from non-owners
+## @Type Private
+## @param key
+#---------------------------------------------------------------------
+module_factoids_lock() {
+ module_sqlite3_exec_sql "UPDATE $config_module_factoids_table SET is_locked='1' WHERE name='$(module_sqlite3_clean_string "$1")';"
+}
+
+
+#---------------------------------------------------------------------
+## Unlock a factoid from protection against non-owners
+## @Type Private
+## @param key
+#---------------------------------------------------------------------
+module_factoids_unlock() {
+ module_sqlite3_exec_sql "UPDATE $config_module_factoids_table SET is_locked='0' WHERE name='$(module_sqlite3_clean_string "$1")';"
+}
+
+
+#---------------------------------------------------------------------
+## Wrapper, call either INSERT or UPDATE
+## @Type Private
+## @param key
+## @param value
+## @param hostmask of person set it
+#---------------------------------------------------------------------
+module_factoids_set_INSERT_or_UPDATE() {
+ if [[ $(module_factoids_SELECT "$1") ]]; then
+ module_factoids_UPDATE "$1" "$2" "$3"
+ else
+ module_factoids_INSERT "$1" "$2" "$3"
+ fi
+}
+
+
+#---------------------------------------------------------------------
+## Wrapper, call either INSERT or UPDATE
+## @Type Private
+## @param key
+## @param value
+## @param sender
+## @param channel
+#---------------------------------------------------------------------
+module_factoids_set() {
+ local key="$1"
+ local value="$2"
+ local sender="$3"
+ local channel="$4"
+ local sendernick
+ parse_hostmask_nick "$sender" 'sendernick'
+ if module_factoids_is_locked "$key"; then
+ if access_check_capab "factoid_admin" "$sender" "GLOBAL"; then
+ module_factoids_set_INSERT_or_UPDATE "$key" "$value" "$sender"
+ send_msg "$channel" "Ok ${sendernick}, I will remember, $key is $value"
+ else
+ access_fail "$sender" "change a locked factoid" "factoid_admin"
+ fi
+ else
+ module_factoids_set_INSERT_or_UPDATE "$key" "$value" "$sender"
+ send_msg "$channel" "Ok ${sendernick}, I will remember, $key is $value"
+ fi
+}
+
+
+#---------------------------------------------------------------------
+## Wrapper, check access
+## @Type Private
+## @param key
+## @param sender
+## @param channel
+#---------------------------------------------------------------------
+module_factoids_remove() {
+ local key="$1"
+ local sender="$2"
+ local channel="$3"
+ local value="$(module_factoids_SELECT "$(tr '[:upper:]' '[:lower:]' <<< "$key")")"
+ if [[ "$value" ]]; then
+ if module_factoids_is_locked "$key"; then
+ if access_check_capab "factoid_admin" "$sender" "GLOBAL"; then
+ module_factoids_DELETE "$key"
+ send_msg "$channel" "I forgot $key"
+ else
+ access_fail "$sender" "remove a locked factoid" "factoid_admin"
+ fi
+ else
+ module_factoids_DELETE "$key"
+ send_msg "$channel" "I forgot $key"
+ fi
+ else
+ send_msg "$channel" "I didn't have a factoid matching \"$key\""
+ fi
+}
+
+
+#---------------------------------------------------------------------
+## Send the factoid:
+## @Type Private
+## @param To where (channel or nick)
+## @param What factoid.
+#---------------------------------------------------------------------
+module_factoids_send_factoid() {
+ local channel="$1"
+ local key="$2"
+ local value="$(module_factoids_SELECT "$(tr '[:upper:]' '[:lower:]' <<< "$key")")"
+ if [[ "$value" ]]; then
+ if [[ $value =~ ^\<REPLY\>\ *(.*) ]]; then
+ send_msg "$channel" "${BASH_REMATCH[1]}"
+ elif [[ $value =~ ^\<ACTION\>\ *(.*) ]]; then
+ send_ctcp "$channel" "ACTION ${BASH_REMATCH[1]}"
+ else
+ send_msg "$channel" "$key is $value"
+ fi
+ else
+ send_msg "$channel" "I don't know what \"$key\" is."
+ fi
+}
+
+
+#---------------------------------------------------------------------
+## Parse assignment:
+## @Type Private
+## @param String to parse
+## @Note Will return using Global variables
+## @Globals $module_factoids_parse_key $module_factoids_parse_value
+#---------------------------------------------------------------------
+module_factoids_parse_assignment() {
+ local word key value
+ # Have we hit a separator yet?
+ local state=0
+ while read -rd ' ' word; do
+ case "$state" in
+ 0)
+ # If state is 1 the rest is value
+ if [[ "$word" =~ ^(as|is|are|=)$ ]]; then
+ state=1
+ else
+ key+=" $word"
+ fi
+ ;;
+ 1)
+ value+=" $word"
+ ;;
+ esac
+ # Extra space at end is intended, to make read work correctly.
+ done <<< "$1 "
+ # And clean spaces, fastest way
+ read -ra module_factoids_parse_key <<< "$key"
+ read -ra module_factoids_parse_value <<< "$value"
+}
+
+
+module_factoids_handler_learn() {
+ local sender="$1"
+ local sendernick
+ parse_hostmask_nick "$sender" 'sendernick'
+ local channel="$2"
+ if ! [[ $2 =~ ^# ]]; then
+ channel="$sendernick"
+ fi
+ local parameters="$3"
+ if [[ "$parameters" =~ ^(.+)\ (as|is|are|=)\ (.+) ]]; then
+ # Do the actual parsing elsewhere:
+ module_factoids_parse_assignment "$parameters"
+ local key="${module_factoids_parse_key[*]}"
+ local value="${module_factoids_parse_value[*]}"
+ unset module_factoids_parse_key module_factoids_parse_value
+ module_factoids_set "$(tr '[:upper:]' '[:lower:]' <<< "$key")" "$value" "$sender" "$channel"
+ else
+ feedback_bad_syntax "$sendernick" "learn" "<key> (as|is|are|=) <value>"
+ fi
+ return 1
+}
+
+module_factoids_handler_forget() {
+ local sender="$1"
+ local sendernick
+ parse_hostmask_nick "$sender" 'sendernick'
+ local channel="$2"
+ if ! [[ $2 =~ ^# ]]; then
+ channel="$sendernick"
+ fi
+ local parameters="$3"
+ if [[ "$parameters" =~ ^(.+) ]]; then
+ local key="${BASH_REMATCH[1]}"
+ module_factoids_remove "$(tr '[:upper:]' '[:lower:]' <<< "$key")" "$sender" "$channel"
+ else
+ feedback_bad_syntax "$sendernick" "forget" "<key>"
+ fi
+}
+
+module_factoids_handler_lock_factoid() {
+ local sender="$1"
+ if access_check_capab "factoid_admin" "$sender" "GLOBAL"; then
+ local sendernick
+ parse_hostmask_nick "$sender" 'sendernick'
+ local channel="$2"
+ if ! [[ $2 =~ ^# ]]; then
+ channel="$sendernick"
+ fi
+ local parameters="$3"
+ if [[ "$parameters" =~ ^(.+) ]]; then
+ local key="${BASH_REMATCH[1]}"
+ module_factoids_lock "$(tr '[:upper:]' '[:lower:]' <<< "$key")"
+ send_msg "$channel" "Ok ${sendernick}, the factoid \"$key\" is now protected from changes"
+ else
+ feedback_bad_syntax "$sendernick" "lock" "<key>"
+ fi
+ else
+ access_fail "$sender" "lock a factoid" "factoid_admin"
+ fi
+}
+
+module_factoids_handler_unlock_factoid() {
+ local sender="$1"
+ if access_check_capab "factoid_admin" "$sender" "GLOBAL"; then
+ local sendernick
+ parse_hostmask_nick "$sender" 'sendernick'
+ local channel="$2"
+ if ! [[ $2 =~ ^# ]]; then
+ channel="$sendernick"
+ fi
+ local parameters="$3"
+ if [[ "$parameters" =~ ^(.+) ]]; then
+ local key="${BASH_REMATCH[1]}"
+ module_factoids_unlock "$(tr '[:upper:]' '[:lower:]' <<< "$key")"
+ send_msg "$channel" "Ok ${sendernick}, the factoid \"$key\" is no longer protected from changes"
+ else
+ feedback_bad_syntax "$sendernick" "lock" "<key>"
+ fi
+ else
+ access_fail "$sender" "lock a factoid" "factoid_admin"
+ fi
+}
+
+module_factoids_handler_whatis() {
+ local sender="$1"
+ local sendernick
+ parse_hostmask_nick "$sender" 'sendernick'
+ local channel="$2"
+ if ! [[ $2 =~ ^# ]]; then
+ channel="$sendernick"
+ fi
+ local parameters="$3"
+ if [[ "$parameters" =~ ^(.+) ]]; then
+ local key="${BASH_REMATCH[1]}"
+ module_factoids_send_factoid "$channel" "$key"
+ else
+ feedback_bad_syntax "$sendernick" "whatis" "<key>"
+ fi
+}
+
+module_factoids_handler_factoid_stats() {
+ local sender="$1"
+ local channel="$2"
+ if ! [[ $2 =~ ^# ]]; then
+ parse_hostmask_nick "$sender" 'channel'
+ fi
+ local count="$(module_factoids_get_count)"
+ local lockedcount="$(module_factoids_get_locked_count)"
+ if [[ "$count" ]]; then
+ send_msg "$channel" "There are $count items in my factoid database. $lockedcount of the factoids are locked."
+ fi
+}
+
+module_factoids_on_PRIVMSG() {
+ local sender="$1"
+ local channel="$2"
+ if ! [[ $2 =~ ^# ]]; then
+ parse_hostmask_nick "$sender" 'channel'
+ fi
+ local query="$3"
+ # Answer question in channel if we got a factoid.
+ if [[ "$query" =~ ^((what|where|who|why|how)\ )?((is|are|were|was|to|can I find)\ )?([^\?]+)\?? ]]; then
+ local key="${BASH_REMATCH[@]: -1}"
+ local value="$(module_factoids_SELECT "$(tr '[:upper:]' '[:lower:]' <<< "$key")")"
+ if [[ "$value" ]]; then
+ module_factoids_send_factoid "$channel" "$key"
+ return 1
+ fi
+ fi
+ return 0
+}