Reorganization to hopefully prevent git conflicts.

This commit is contained in:
Storm Dragon
2025-10-25 01:30:02 -04:00
parent f6990bcc81
commit d684623974
13 changed files with 296 additions and 77 deletions

View File

@@ -1,16 +1,26 @@
#!/usr/bin/env bash
[ -f functions.sh ] && source functions.sh
greetingsFile="triggers/greet/greetings.txt"
# All names to match are completely lowercase.
case "${1,,}" in
storm_dragon)
msg "$2" "my lord, $1: how may I serve you?"
;;
*)
greeting=(
Greetings
"Howdy, welcome to $2!"
"Wazzup Moe Fugger!"
"Welcome to $2!"
)
msg "$2" "$1: ${greeting[$(($RANDOM % ${#greeting[@]}))]}"
# Read greetings from file into array
if [[ -f "$greetingsFile" ]]; then
mapfile -t greeting < "$greetingsFile"
else
# Fallback if file doesn't exist
greeting=("Greetings" "Welcome!")
fi
# Replace {channel} placeholder with actual channel name
selectedGreeting="${greeting[$((RANDOM % ${#greeting[@]}))]}"
selectedGreeting="${selectedGreeting//\{channel\}/$2}"
msg "$2" "$1: $selectedGreeting"
;;
esac

View File

@@ -0,0 +1,4 @@
Greetings
Howdy, welcome to {channel}!
Wazzup Moe Fugger!
Welcome to {channel}!

View File

@@ -0,0 +1,26 @@
# Keywords Configuration
# Format: keyword|action|percentage (percentage is optional, defaults to 100%)
# Available variables: $chan (channel), $who (user nickname)
# Use {random:option1|option2|option3} for random selection in messages
#
# Examples:
# word|msg "$chan" "Hello there!"|50%
# test|act "$chan" "does something cool"
linux|msg "$chan" "Linux is {random:awesome|God|great|lovely|fantastic|amazing|wonderful}!"|25%
windows|msg "$chan" "{random:Failure is not an option, it comes bundled with Windows!|Apple got all pissed off because I farted in their store. It's not my falt they don't have Windows...|Windows is dumb!|Did you know that Micro Soft is Linda's pet name for Bill Gates?|A computer without Windows is like a chocolate cake without the mustard.|Windows is stupid|In a world without walls and fences - who needs windows and gates?|Windows, plug and pray.|Windows - Just another pain in the glass.|Windows, it's not pretty, it's not ugly, but it's pretty ugly.}!"|25%
emacs|msg "$chan" "$who, Real men of genius use vim!"|50%
jaws|msg "$chan" "${who}: watch out for sharks!"
emacspeak|msg "$chan" "$who, Real men of genius use vim!"
nano|msg "$chan" "$who, Real men of genius use vim!"
pidgin|msg "$chan" "$who, Real men of genius use irssi!"
weechat|msg "$chan" "$who, Real men of genius use irssi!"
thunderbird|msg "$chan" "$who, Real dogs use mutt, real men of genius use cat on a mailbox file!"
gedit|msg "$chan" "$who, Real men of genius use vim!"
pluma|msg "$chan" "$who, Real men of genius use vim!"
dragonforce|msg "$chan" "$who: I love DragonForce!!!"
vim|msg "$chan" "{random:Praise vim! HA|In times of trouble, just ask yourself, 'What would Bram Moolenaar do?'.|Vim is like a Ferrari, if you're a beginner, it handles like a bitch, but once you get the hang of it, it's small, powerful and FAST!|VIM is like a new model Ferrari, and sounds like one too - 'VIIIIIIMMM!'|Only through vim can you be saved! HA}"
# Multi-word triggers (match anywhere in message, spaces removed)
# Format: ~phrase|action|percentage
~nowplaying:|act "$chan" "{random:cranks the volume up to 11|got soooo high at that show|boogies down to the sound of the band}!"

View File

@@ -4,67 +4,142 @@
who="${1%!*}"
who="${who//:}"
shift
# shellcheck disable=SC2034 # Used in action strings via execute_action
chan="$1"
shift
# each word is stored in an associative array, with the actions to be taken as the array's contents.
# the variable $chan contains the channel that caused the trigger.
# the variable $who contains the nick that caused the trigger.
# Optional: Add a percentage (e.g., "50%") as the last element to respond only that percent of the time.
declare -A keywords
keywords[linux]="msg \"$chan\" \"Linux is $(shuf -n1 -e awesome God great lovely fantastic amazing wonderful)!\" 25%"
keywords[windows]="msg \"$chan\" \"$(shuf -n1 -e\
"Failure is not an option, it comes bundled with Windows!"\
"Apple got all pissed off because I farted in their store. It's not my falt they don't have Windows..."\
"Windows is dumb!"\
"Did you know that Micro Soft is Linda's pet name for Bill Gates?"\
"A computer without Windows is like a chocolate cake without the mustard."\
"Windows is stupid"\
"In a world without walls and fences - who needs windows and gates?"\
"Windows, plug and pray."\
"Windows - Just another pain in the glass."\
"Windows, it's not pretty, it's not ugly, but it's pretty ugly.")!\" 25%"
keywords[emacs]="msg \"$chan\" \"$who, Real men of genius use vim!\" 50%"
keywords[jaws]="msg \"$chan\" \"${who}: watch out for sharks!\""
keywords[emacspeak]="msg \"$chan\" \"$who, Real men of genius use vim!\""
keywords[nano]="msg \"$chan\" \"$who, Real men of genius use vim!\""
keywords[pidgin]="msg \"$chan\" \"$who, Real men of genius use irssi!\""
keywords[weechat]="msg \"$chan\" \"$who, Real men of genius use irssi!\""
keywords[thunderbird]="msg \"$chan\" \"$who, Real dogs use mutt, real men of genius use cat on a mailbox file!\""
keywords[gedit]="msg \"$chan\" \"$who, Real men of genius use vim!\""
keywords[pluma]="msg \"$chan\" \"$who, Real men of genius use vim!\""
keywords[dragonforce]="msg \"$chan\" \"$who: I love DragonForce!!!\""
keywords[vim]="msg \"$chan\" \"$(shuf -n1 -e \
"Praise vim! HA"\
"In times of trouble, just ask yourself, 'What would Bram Moolenaar do?'."\
"Vim is like a Ferrari, if you're a beginner, it handles like a bitch, but once you get the hang of it, it's small, powerful and FAST!"\
"VIM is like a new model Ferrari, and sounds like one too - 'VIIIIIIMMM!'"\
"Only through vim can you be saved! HA")\""
keywordsFile="triggers/keywords/keywords.cfg"
# Function to process random selection syntax: {random:opt1|opt2|opt3}
process_random() {
local text="$1"
while [[ "$text" =~ \{random:([^}]+)\} ]]; do
local options="${BASH_REMATCH[1]}"
IFS='|' read -ra optArray <<< "$options"
local selected="${optArray[$((RANDOM % ${#optArray[@]}))]}"
text="${text/\{random:$options\}/$selected}"
done
echo "$text"
}
# Safe execution function - only allows predefined IRC functions
execute_action() {
local action="$1"
# Parse the action to extract function name and arguments
if [[ "$action" =~ ^msg[[:space:]]+(\"[^\"]+\"|[^[:space:]]+)[[:space:]]+(.+)$ ]]; then
local target="${BASH_REMATCH[1]}"
local message="${BASH_REMATCH[2]}"
# Remove quotes from target and message if present
target="${target//\"/}"
# Safely expand only $chan and $who variables - NO EVAL
message="${message//\"\$chan\"/$chan}"
message="${message//\$chan/$chan}"
message="${message//\"\$who\"/$who}"
message="${message//\$who/$who}"
message="${message//\$\{chan\}/$chan}"
message="${message//\$\{who\}/$who}"
message="$(process_random "$message")"
msg "$target" "$message"
elif [[ "$action" =~ ^act[[:space:]]+(\"[^\"]+\"|[^[:space:]]+)[[:space:]]+(.+)$ ]]; then
local target="${BASH_REMATCH[1]}"
local message="${BASH_REMATCH[2]}"
# Remove quotes from target and message if present
target="${target//\"/}"
# Safely expand only $chan and $who variables - NO EVAL
message="${message//\"\$chan\"/$chan}"
message="${message//\$chan/$chan}"
message="${message//\"\$who\"/$who}"
message="${message//\$who/$who}"
message="${message//\$\{chan\}/$chan}"
message="${message//\$\{who\}/$who}"
message="$(process_random "$message")"
act "$target" "$message"
elif [[ "$action" =~ ^reply[[:space:]]+(\"[^\"]+\"|[^[:space:]]+)[[:space:]]+(.+)$ ]]; then
local target="${BASH_REMATCH[1]}"
local message="${BASH_REMATCH[2]}"
# Remove quotes from target and message if present
target="${target//\"/}"
# Safely expand only $chan and $who variables - NO EVAL
message="${message//\"\$chan\"/$chan}"
message="${message//\$chan/$chan}"
message="${message//\"\$who\"/$who}"
message="${message//\$who/$who}"
message="${message//\$\{chan\}/$chan}"
message="${message//\$\{who\}/$who}"
message="$(process_random "$message")"
reply "$target" "$message"
fi
}
# Load keywords from config file into associative array
declare -A keywords
if [[ -f "$keywordsFile" ]]; then
while IFS='|' read -r keyword action percentage || [[ -n "$keyword" ]]; do
# Skip comments and empty lines
[[ "$keyword" =~ ^[[:space:]]*# ]] && continue
[[ -z "$keyword" ]] && continue
# Trim whitespace
keyword="${keyword#"${keyword%%[![:space:]]*}"}"
keyword="${keyword%"${keyword##*[![:space:]]}"}"
action="${action#"${action%%[![:space:]]*}"}"
action="${action%"${action##*[![:space:]]}"}"
percentage="${percentage#"${percentage%%[![:space:]]*}"}"
percentage="${percentage%"${percentage##*[![:space:]]}"}"
# Store in array (key includes ~ prefix for multi-word triggers)
if [[ -n "$percentage" ]]; then
keywords["$keyword"]="$action $percentage"
else
keywords["$keyword"]="$action"
fi
done < "$keywordsFile"
fi
# Process single-word triggers
wordList="$(echo "${@,,}" | tr '[:space:]' $'\n' | sort -u)"
for w in ${wordList//[[:punct:]]/} ; do
if [[ -n "${keywords[${w,,}]}" && "$lastWordMatch" != "${keywords[${w,,}]}" ]]; then
keywordAction="${keywords[${w,,}]}"
# Check if the last element is a percentage
if [[ "$keywordAction" =~ (.*)\ ([0-9]+)%$ ]]; then
command="${BASH_REMATCH[1]}"
percentage="${BASH_REMATCH[2]}"
# Generate random number between 1-100 and only respond if within percentage
randomNum=$((RANDOM % 100 + 1))
if [[ $randomNum -le $percentage ]]; then
eval "$command"
fi
else
# No percentage specified, always respond
eval "$keywordAction"
fi
lastWordMatch="${keywords[${w,,}]}"
fi
if [[ -n "${keywords[${w,,}]}" && "$lastWordMatch" != "${keywords[${w,,}]}" ]]; then
keywordAction="${keywords[${w,,}]}"
# Check if the last element is a percentage
if [[ "$keywordAction" =~ (.*)\ ([0-9]+)%$ ]]; then
command="${BASH_REMATCH[1]}"
percentage="${BASH_REMATCH[2]}"
# Generate random number between 1-100 and only respond if within percentage
randomNum=$((RANDOM % 100 + 1))
if [[ $randomNum -le $percentage ]]; then
execute_action "$command"
fi
else
# No percentage specified, always respond
execute_action "$keywordAction"
fi
lastWordMatch="${keywords[${w,,}]}"
fi
done
# Example of dealing with multi word triggers.
# Reset wordList without sorting it and with spaces removed.
# Process multi-word triggers (those starting with ~)
wordList="$(echo "${@,,}" | tr -d '[:space:]')"
if [[ "${wordList,,}" =~ .*nowplaying:.* ]]; then
act "$chan" "$(shuf -n1 -e "cranks the volume up to 11" "got soooo high at that show" "boogies down to the sound of the band")!"
fi
for trigger in "${!keywords[@]}"; do
if [[ "$trigger" =~ ^~ ]]; then
# Remove the ~ prefix for matching
triggerPattern="${trigger#\~}"
if [[ "${wordList,,}" =~ .*${triggerPattern}.* ]]; then
keywordAction="${keywords[$trigger]}"
# Check if the last element is a percentage
if [[ "$keywordAction" =~ (.*)\ ([0-9]+)%$ ]]; then
command="${BASH_REMATCH[1]}"
percentage="${BASH_REMATCH[2]}"
# Generate random number between 1-100 and only respond if within percentage
randomNum=$((RANDOM % 100 + 1))
if [[ $randomNum -le $percentage ]]; then
execute_action "$command"
fi
else
# No percentage specified, always respond
execute_action "$keywordAction"
fi
fi
fi
done

View File

@@ -12,10 +12,25 @@ fi
for l in $3 ; do
text="${l#:}"
if [[ "${text}" =~ http://|https://|www\..* ]]; then
pageTitle="$(curl -L -s --connect-timeout 5 "$text" | sed -n -e 'H;${x;s!.*<head[^>]*>\(.*\)</head>.*!\1!;T;s!.*<title>\(.*\)</title>.*!\1!p}' | w3m -dump -T text/html | tr '[:space:]' ' ')"
pageTitle="$(echo "$pageTitle" | tr -cd '[:print:]')"
if [[ ${#pageTitle} -gt 1 ]]; then
msg "$2" "$pageTitle"
fi
# Security: Only allow http:// and https:// protocols
if [[ ! "$text" =~ ^https?:// ]]; then
# Convert www. to http://www.
if [[ "$text" =~ ^www\. ]]; then
text="http://$text"
else
# Skip unknown protocols
continue
fi
fi
# Remove potentially dangerous shell metacharacters from URL
text="${text//[;&|]/}"
# Fetch page title with timeout and security limits
pageTitle="$(curl -L -s --connect-timeout 5 --max-time 10 "$text" | sed -n -e 'H;${x;s!.*<head[^>]*>\(.*\)</head>.*!\1!;T;s!.*<title>\(.*\)</title>.*!\1!p}' | w3m -dump -T text/html | tr '[:space:]' ' ')"
pageTitle="$(echo "$pageTitle" | tr -cd '[:print:]')"
if [[ ${#pageTitle} -gt 1 ]]; then
msg "$2" "$pageTitle"
fi
fi
done