Skip to content

Instantly share code, notes, and snippets.

@justjanne
Forked from maxaudron/ircmsg.sh
Created February 5, 2020 11:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justjanne/baa4eca94c8063288941e70b96096a10 to your computer and use it in GitHub Desktop.
Save justjanne/baa4eca94c8063288941e70b96096a10 to your computer and use it in GitHub Desktop.
#!/bin/bash
declare -A tags
clear_message() {
start=0
source=""
fragment=""
tags=()
prefix=""
command=""
params=()
}
extract_fragment() {
local end=${1:-"-1"}
local prefix=${2:-""}
# Try to set find the end of the space-delimited fragment
if [ "$end" == "-1" ]; then
local tmp=${source:$start}
local tmp=${tmp%% *}
end=$(($start + ${#tmp}))
fi
# If no space comes after this point, use the remainder of the string
if [ "$end" == "-1" ]; then
end=${#source}
fi
fragment=""
# If a prefix is set
if [ "$prefix" != "" ]; then
# And the fragment starts with the prefix
if [ "$start" -lt "${#source}" ] && [ "${source:$start:1}" == "$prefix" ]; then
# return the fragment without the prefix, advancing the string
fragment=${source:$(($start + 1)):$(($end - $start - 1))}
start=$end
fi
else
# otherwise return the entire fragment
fragment=${source:$start:$(($end - $start))}
start=$end
fi
}
skip_empty_parts() {
while [ "$start" -lt "${#source}" ] && [ "${source:$start:1}" == " " ]; do
start=$((start + 1))
done
}
parse_tag_value() {
local value=${1}
local result=""
local escaped=0
for (( i=0; i<${#value}; i++ )); do
c=${value:$i:1}
if [ $escaped -ne 0 ]; then
if [ "$c" == "\\" ]; then
result+="\\"
elif [ "$c" == "s" ]; then
result+=" "
elif [ "$c" == ":" ]; then
result+=";"
elif [ "$c" == "r" ]; then
result+="\r"
elif [ "$c" == "n" ]; then
result+="\n"
else
result+="$c"
fi
escaped=0
elif [ $c == "\\" ]; then
escaped=1
else
result+="$c"
fi
done
echo $result
}
parse_tags() {
extract_fragment "-1" "@"
local raw_tag_str=$fragment
# Tags are delimited with ; according to spec
local IFS=";"
for raw_tag in $raw_tag_str; do
if [ "$raw_tag" != "" ]; then
local raw_key=${raw_tag%%=*}
local raw_value=${raw_tag:$((${#raw_key}+1))}
tags[$raw_key]=$(parse_tag_value $raw_value)
fi
done
}
parse_prefix() {
extract_fragment "-1" ":"
prefix=$fragment
}
parse_command() {
extract_fragment "-1"
command=$fragment
}
parse_parameter() {
if [ $start -lt ${#source} ] && [ ${source:$start:1} == ':' ]; then
start=$(($start + 1))
extract_fragment ${#source}
else
extract_fragment
fi
params+=( "$fragment" )
}
parse_message() {
clear_message
source=${1}
parse_tags
skip_empty_parts
parse_prefix
skip_empty_parts
parse_command
skip_empty_parts
unset params
while [ $start -lt ${#source} ]; do
parse_parameter
skip_empty_parts
done
}
print_message() {
echo "tags: "
for i in "${!tags[@]}"
do
echo " ${i}=${tags[$i]}"
done
echo "prefix: $prefix"
echo "command: $command"
echo "params: "
for i in "${params[@]}"
do
echo " ${i}"
done
}
parse_message "@a=b;c=32;k;rt=ql7 :source PRIVMSG #channel :test a thing"
print_message
echo "---"
parse_message ":coolguy!ag@net\x035w\x03ork.admin PRIVMSG foo :bar baz"
print_message
echo "---"
parse_message "@tag1=value\\\\ntest COMMAND"
print_message
echo "---"
parse_message "@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 COMMAND param1 param2 :param3 param3"
print_message
echo "---"
parse_message ":gravel.mozilla.org 432 #momo :Erroneous Nickname: Illegal characters"
print_message
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment