Reorganization to hopefully prevent git conflicts.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,7 @@
|
||||
response/error.txt
|
||||
response/exit.txt
|
||||
triggers/greet/greetings.txt
|
||||
triggers/keywords/keywords.cfg
|
||||
log.txt
|
||||
.*
|
||||
bot.cfg
|
||||
|
||||
48
bot.sh
48
bot.sh
@@ -18,6 +18,47 @@ if [[ ! -f "bot.cfg" ]]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check and initialize customizable configuration files
|
||||
check_config_files() {
|
||||
local configFiles=(
|
||||
"response/error.txt:response/error.txt.example"
|
||||
"response/exit.txt:response/exit.txt.example"
|
||||
"triggers/greet/greetings.txt:triggers/greet/greetings.txt.example"
|
||||
"triggers/keywords/keywords.cfg:triggers/keywords/keywords.cfg.example"
|
||||
)
|
||||
|
||||
for entry in "${configFiles[@]}"; do
|
||||
local target="${entry%:*}"
|
||||
local example="${entry#*:}"
|
||||
|
||||
if [[ ! -f "$target" ]]; then
|
||||
if [[ -f "$example" ]]; then
|
||||
cp "$example" "$target"
|
||||
echo "Created $target from $example"
|
||||
else
|
||||
# Hardcoded fallback for critical files if example is missing
|
||||
case "$target" in
|
||||
"response/error.txt")
|
||||
mkdir -p "$(dirname "$target")"
|
||||
printf "I don't understand\nI'm not sure how to help you with that.\n" > "$target"
|
||||
echo "Warning: $example not found. Created $target with default content."
|
||||
;;
|
||||
"response/exit.txt")
|
||||
mkdir -p "$(dirname "$target")"
|
||||
printf "Ta ta for now.\nbye.\n" > "$target"
|
||||
echo "Warning: $example not found. Created $target with default content."
|
||||
;;
|
||||
*)
|
||||
echo "Warning: Missing $example and no hardcoded fallback available."
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
check_config_files
|
||||
|
||||
# Load required files.
|
||||
for i in "bot.cfg" "functions.sh" ; do
|
||||
if [[ -f "$i" ]]; then
|
||||
@@ -231,6 +272,13 @@ while true; do
|
||||
from="${result#*#}"
|
||||
from="${from%% *}"
|
||||
from="#${from:-${channels[0]}}"
|
||||
|
||||
# Validate channel name format (IRC RFC 2812: must start with #, contain only valid chars)
|
||||
if [[ ! "$from" =~ ^#[a-zA-Z0-9_-]+$ ]]; then
|
||||
# Invalid channel, use default
|
||||
from="#${channels[0]}"
|
||||
fi
|
||||
|
||||
# Trigger stuff happens here.
|
||||
# Call link trigger if msg contains a link:
|
||||
if [[ "$result" =~ .*http://|https://|www\..* ]]; then
|
||||
|
||||
@@ -14,4 +14,11 @@ if ! check_dependencies "${dependencies[@]}"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
msg "$chan" "$(units -v ${*#* } | head -n1 | tr -d '[:space:]')"
|
||||
# Validate input
|
||||
if [[ -z "$*" ]]; then
|
||||
msg "$chan" "Please provide a unit conversion (e.g., '10 meters to feet')."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Quote variables to prevent command injection
|
||||
msg "$chan" "$(units -v "${*#* }" | head -n1 | tr -d '[:space:]')"
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
dependencies=("fortune")
|
||||
|
||||
target="${3#fortune}"
|
||||
# Trim leading/trailing whitespace
|
||||
target="${target#"${target%%[![:space:]]*}"}"
|
||||
target="${target%"${target##*[![:space:]]}"}"
|
||||
|
||||
# Check dependencies before running
|
||||
if ! check_dependencies "${dependencies[@]}"; then
|
||||
@@ -12,6 +15,7 @@ if ! check_dependencies "${dependencies[@]}"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fortuneText="$(fortune -a -e -s -n 512 $target || echo "No fortunes found.")"
|
||||
# Quote target to prevent command injection
|
||||
fortuneText="$(fortune -a -e -s -n 512 "$target" || echo "No fortunes found.")"
|
||||
fortuneText="$(echo "$fortuneText" | tr '[:space:]' ' ' | sed -e 's/"/\"/g')"
|
||||
msg "$2" "$fortuneText"
|
||||
|
||||
@@ -4,8 +4,35 @@
|
||||
user=$1
|
||||
shift
|
||||
shift
|
||||
if [[ "$user" =~ $allowList ]]; then
|
||||
./modules/do/do.sh "$1" "#$channel" "does a magical gesture and turns into ${1}!"
|
||||
nick $1
|
||||
sed -i bot.cfg -e "s/nick=.*/nick=\"$1\"/"
|
||||
|
||||
newNick="$1"
|
||||
|
||||
# Validate that user is authorized
|
||||
if [[ ! "$user" =~ $allowList ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Validate IRC nickname format (RFC 2812)
|
||||
# Nicknames can contain: a-z A-Z 0-9 _ - [ ] { } \ | ^
|
||||
if [[ -z "$newNick" ]]; then
|
||||
msg "#$channel" "$user: Please provide a nickname."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! [[ "$newNick" =~ ^[a-zA-Z0-9_\[\]\{\}\\|\^-]+$ ]]; then
|
||||
msg "#$channel" "$user: Invalid nickname format. Only alphanumeric and _-[]{}\\|^ allowed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ ${#newNick} -gt 30 ]]; then
|
||||
msg "#$channel" "$user: Nickname too long (max 30 characters)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Change the nick
|
||||
./modules/do/do.sh "$newNick" "#$channel" "does a magical gesture and turns into ${newNick}!"
|
||||
nick "$newNick"
|
||||
|
||||
# Safely update config file - escape forward slashes for sed
|
||||
escapedNick="${newNick//\//\\/}"
|
||||
sed -i "s/^nick=.*/nick=\"${escapedNick}\"/" bot.cfg
|
||||
|
||||
@@ -13,15 +13,15 @@ if ! check_dependencies "${dependencies[@]}"; then
|
||||
msg "$chan" "$1: This module requires: ${dependencies[*]}"
|
||||
exit 1
|
||||
fi
|
||||
#get the lyric text into a variable
|
||||
lyricText="$(clyrics $@ | tr '[:space:]' ' ' | tr -s ' ' | fold -s -w 384)"
|
||||
# Get the lyric text into a variable (quote $@ to prevent command injection)
|
||||
lyricText="$(clyrics "$@" | tr '[:space:]' ' ' | tr -s ' ' | fold -s -w 384)"
|
||||
i=$(echo "$lyricText" | wc -l)
|
||||
i=$(($RANDOM % $i + 1))
|
||||
i=$((RANDOM % i + 1))
|
||||
lyricText="$(echo "$lyricText" | tail +$i | head -1 | rev | cut -d '.' -f2- | rev)"
|
||||
#Display the lyric text
|
||||
if [ ${#lyricText} -gt 15 ] ; then
|
||||
msg "$chan" "${lyricText}"
|
||||
exit 0
|
||||
fi
|
||||
msg "$chan" "no lyrics found for $@."
|
||||
msg "$chan" "no lyrics found for $*."
|
||||
exit 0
|
||||
|
||||
@@ -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
|
||||
|
||||
4
triggers/greet/greetings.txt.example
Normal file
4
triggers/greet/greetings.txt.example
Normal file
@@ -0,0 +1,4 @@
|
||||
Greetings
|
||||
Howdy, welcome to {channel}!
|
||||
Wazzup Moe Fugger!
|
||||
Welcome to {channel}!
|
||||
26
triggers/keywords/keywords.cfg.example
Normal file
26
triggers/keywords/keywords.cfg.example
Normal 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}!"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user