handler.rc (9334B)
1 #!/bin/rc 2 # 3 # uses GNU timeout(1), because lazy. 4 5 mkdir -p data/locks 6 7 # parameterize 8 LINE = `$nl{echo $LINE | tr -d '\r'} 9 PARAMS = `' '$nl{echo $LINE | sed 's/ :.*//'} 10 PARAMS = ($PARAMS `$nl{echo $LINE | sed 's/.* ://'}) 11 PREV = `$nl{tail -n 10 < in.log} 12 13 fn match_raw { 14 echo $LINE | grep $* >/dev/null 15 } 16 17 fn match_msg { 18 if (!~ $PARAMS(1) 'PRIVMSG') { 19 return 1; 20 } 21 if (~ $PARAMS(2) $nick) { 22 TARGET = $NICK 23 } else { 24 TARGET = $PARAMS(2) 25 } 26 MSG = $PARAMS(3) 27 echo $PARAMS(3) | grep $* >/dev/null 28 } 29 30 fn match_hilight { 31 if (~ $PARAMS(1) 'PRIVMSG' && match_msg -iE '^' ^ $nick ^ '[:,]|[[:punct:]] *' ^ $nick ^ '$') { 32 # TARGET already set by match_msg 33 MSG = `$nl{echo $PARAMS(3) | sed 's/^' ^ $nick ^ '[:,] //;s/[[:punct:]] *' ^ $nick ^'$//'} 34 echo $MSG | grep $* >/dev/null 35 } else { 36 return 1 37 } 38 } 39 40 fn send_raw { 41 printf $* >> $input 42 } 43 44 fn send_join { 45 send_raw 'JOIN %s\r\n' $1 46 } 47 48 fn send_msg { 49 send_raw 'PRIVMSG %s :%s\r\n' $1 $2 50 } 51 52 fn send_stdin { 53 for (line in `$nl{cat}) { 54 send_msg $TARGET $line 55 } 56 } 57 58 fn send_notice { 59 send_raw 'NOTICE %s :%s\r\n' $1 $2 60 } 61 62 fn lock { 63 echo `{date +%s} ^ ' + ' ^ $2 | bc > data/locks/$1 64 } 65 66 fn unlock { 67 rm -f data/locks/$1 68 } 69 70 fn islocked { 71 for (f in data/locks/*) { 72 d = `{cat $f >[2]/dev/null} 73 if (expr $d '<' `{date +%s} >/dev/null >[2=1]) { 74 rm $f 75 } 76 } 77 test -f data/locks/$1 78 } 79 80 fn randomize { 81 n = `{awk -vmax=$#* -vmin=1 'BEGIN{srand(); print int(min+rand()*(max))}'} 82 echo $*($n) 83 } 84 85 fn title { 86 out = () 87 url = `$nl{echo $1 | sed 's/invidio.us/www.youtube.com/g;s/m.imdb.com/www.imdb.com/g' | tr -d '\r' | sed 's~embed/~watch?v=~g' | grep -o '[a-z]*://[^ ]*' | sed 's/[\.?>,]$//'} 88 curl -qsLD - $url | tr -d '\r' | sed '/^[^[:print:]]*$/q' | tr '[:upper:]' '[:lower:]' > data/headers 89 curl -qsL $url | tr -d '\r' > data/content 90 if (echo $url | grep 'http[s]*://[w.]*youtu[.]*be' >/dev/null) { 91 title = `$nl{< data/content \ 92 grep '<meta itemprop="name"' | 93 sed -E 's/.*<meta itemprop="name" content="([^"]*)">.*/\1/'} 94 author = `$nl{< data/content \ 95 grep -o 'author":[^}]*}' | 96 sed -E 's/.*:"([^"]*).*/\1/g'} 97 date = `$nl{< data/content \ 98 grep -o 'uploadDate":[^}]*}' | 99 sed -E 's/.*:"([^"]*).*/\1/g;s/([0-9]*)-([0-9]*)-([0-9]*)/\3-\2-\1/'} 100 101 send_notice $TARGET '40You91,16Tube ::: Title: ' ^ $^title ^ ' ::: Author: ' ^ $^author ^ ' ::: Uploaded: ' ^ $^date 102 } else { 103 code = `{head -n 1 < data/headers} 104 ctype = `{awk -F: '$1 == "content-type" {print $2}' < data/headers} 105 server = `{awk -F: '$1 == "server" {print $2}' < data/headers} 106 107 if (~ $ctype 'text/html'*) { 108 title = `$nl{< data/content grep -o '<title[^>]*>[^<]*</title>' | sed 's~.*<title[^>]*>~~g;s~</title>.*~~g' | head -n 1} 109 published = `$nl{< data/content grep -o '<meta[^>]*"published_time[^>]*>' | sed -E 's/.*content="([^"]*)".*/\1/;s/T.*//;s~([0-9]*)-([0-9]*)-([0-9]*)~\3/\2/\1~'} 110 modified = `$nl{< data/content grep -o '<meta[^>]*"modified_time[^>]*>' | sed -E 's/.*content="([^"]*)".*/\1/;s/T.*//;s~([0-9]*)-([0-9]*)-([0-9]*)~\3/\2/\1~'} 111 author = `$nl{< data/content grep -o '<meta[^>]*"author[^>]*>' | sed -E 's/.*content="([^"]*)".*/\1/'} 112 generator = `$nl{< data/content grep -io '<meta[^>]*"generator[^>]*>' | sed -E 's/.*content="([^"]*)".*/\1/'} 113 114 if (echo $title | grep '.' >/dev/null) 115 out = $out ^ 'Title: ' ^ $title ^ ' ' 116 if (echo $published | grep '.' >/dev/null) 117 out = $out ^ 'Published: ' ^ $published ^ ' ' 118 if (echo $modified | grep '.' >/dev/null) 119 out = $out ^ 'Modified: ' ^ $modified ^ ' ' 120 if (echo $author | grep '.' >/dev/null) 121 out = $out ^ 'Author: ' ^ $author ^ ' ' 122 if (echo $generator | grep '.' >/dev/null) 123 out = $out ^ 'Generator: ' ^ $generator ^ ' ' 124 } else { 125 if (echo $ctype | grep '.' >/dev/null) 126 out = $out ^ 'Content type: ' ^ $ctype ^ ' ' 127 } 128 129 if (~ $server 'cloudflare') { 130 out = $out ^ 'Cloudflared ' 131 } else { 132 out = $out ^ 'Server: ' ^ $server ^ ' ' 133 } 134 135 send_notice $TARGET $out 136 } 137 } 138 139 if (~ $PARAMS(1) 'PING') { 140 send_raw 'PONG :%s\r\n' $PARAMS(2) 141 } else if (~ $PARAMS(1) '376') { 142 # end of MOTD 143 send_join '#hlircnet' 144 send_join '#test' 145 } else if (match_msg -i '^!help' || match_hilight -iE '^(help|source|src|usage|-h|--help)') { 146 send_msg $TARGET 'Source: git://hhvn.uk/ | Help: gopher://hhvn.uk/1/git/o/marvvin/file/data/help.txt.gph' 147 } else if (match_hilight -iE '^(calc|bc) ') { 148 exp = `$nl{echo $MSG | sed 's/[^ ]* *//'} 149 if (islocked bc) { 150 send_msg $TARGET 'bc is currently locked' 151 } else { 152 lock bc 6 153 ret = `$nl{echo $exp | timeout 5 bc >[2=1] | head -n5} 154 for (r in $ret) { 155 send_msg $TARGET $r 156 } 157 unlock bc 158 } 159 } else if (match_hilight -i '^say hi to') { 160 send_msg $TARGET 'Hi' ^ `$nl{echo $MSG | sed 's/.*say hi to//'} 161 } else if (match_hilight -i '^say') { 162 send_msg $TARGET `$nl{echo $MSG | sed 's/[^ ]* *//'} 163 } else if (match_hilight -i '^topic') { 164 send_raw 'TOPIC #hlircnet :--== #hlircnet ==-- ::: --== gopher://hlirc.net/0/metachannel.txt ==-- ::: --== <%s> %s ==--\r\n' \ 165 $NICK `$nl{echo $MSG | sed 's/[^ ]* *//'} 166 } else if (match_hilight -iE '^(convert|exchange|currency)( |$)') { 167 VERB = `{echo $PARAMS(3)} 168 VERB = $VERB(2) 169 ARGS = `{echo $MSG | sed 's/[^ ]*//'} 170 if (~ $ARGS ()) { 171 if (~ $VERB convert) { 172 backend = 'GNU units(1), ' 173 noun = 'unit/currency' 174 } else { 175 noun = 'currency' 176 } 177 backend = $backend ^ 'cryptocompare.com (regular currencies too)' 178 send_msg $TARGET 'usage: ' ^ $VERB ^ ' [amount] <' ^ $noun ^ '> [to] <' ^ $noun ^ '>' 179 send_msg $TARGET 'Backend: ' ^ $backend 180 return 181 } 182 183 if (!~ $ARGS(1) [0-9]*) { 184 ARGS = (1 $ARGS) 185 } 186 187 if (~ $VERB convert && ~ $ARGS to into as in) { 188 from = `$nl{echo $^ARGS | sed -E 's/(^| )(to|into|as|in)( |$).*//'} 189 to = `$nl{echo $^ARGS | sed -E 's/.*(^| )(to|into|as|in)( |$)//'} 190 data = `$nl{units $from $to >[2]/dev/null} 191 if (~ $bqstatus(1) 0) { 192 send_msg $TARGET `{echo $data(1) | sed -E 's/[[:space:]]*(\*[[:space:]]*|)//'} ^ ' ' ^ $to 193 return 194 } 195 } 196 197 data = `$nl{./bin/currency $ARGS} 198 if (~ $bqstatus(1) 0) { 199 send_msg $TARGET $data 200 return 201 } 202 203 send_msg $TARGET 'Unknown units or values' 204 } else if (match_hilight -iE '^(' ^ `$nl{builtin ls bin/ | tr '\n' '|' | sed 's/|*$//'} ^ ')') { 205 CMD = `{echo $MSG | sed 's/ .*//'} 206 ARGS = `{echo $MSG | sed 's/[^ ]*//'} 207 ./bin/$CMD $ARGS | send_stdin $TARGET 208 } else if (match_hilight -E '^welcome back') { 209 send_msg $TARGET 'Thanks, ' ^ $NICK 210 } else if (match_hilight -E '^wtf .|^what .') { 211 acr = `$nl{echo $MSG | sed 's/[^ ]* *//;s/^is //' | tr '[:lower:]' '[:upper:]'} 212 out = `$nl{awk -F\t -vacr=$acr 'toupper($1) == acr {printf("%s, ", $2)}' < data/suggest/acronym | sed 's/, $//'} 213 if (~ $out ()) { 214 send_msg $TARGET 'No acronym ''' ^ $acr ^ ''' found. Use `marvvin: suggest acronym <acronym> <definition...>` to add one' 215 } else { 216 send_msg $TARGET $acr ^ ': ' ^ $out 217 } 218 } else if (match_hilight '^suggest') { 219 categories = (response acronym) 220 splitmsg = `{printf '%s' $MSG} 221 if (~ $splitmsg(2) $categories) { 222 if (~ $splitmsg(2) 'acronym') { 223 MSG = `$nl{echo $MSG | sed -E 's/^([^ ]* *[^ ]* *[^ ]*) */\1\t/'} 224 if (!echo $MSG | grep `''{printf '\t'}) { 225 send_msg $TARGET $NICK ^ ': acronyms need a definition' 226 exit 227 } 228 } 229 mkdir -p data/suggest/ 230 echo '# [From: ' ^ $FROM ^ '] [Target: ' ^ $TARGET ^ '] ' ^ `$nl{date} >> data/suggest/$splitmsg(2) 231 echo $MSG | sed 's/[^ ]* *[^ ]* *//' >> data/suggest/$splitmsg(2) 232 send_msg $TARGET $NICK ^ ': suggestion submitted to category ''' ^ $splitmsg(2) ^ '''' 233 } else if (~ $splitmsg(2) ()) { 234 send_msg $TARGET $NICK ^ ': categories: ' ^ $^categories 235 } else { 236 send_msg $TARGET $NICK ^ ': invalid category. Accepted categories are: ' ^ `$nl{echo $^categories | sed 's/ /, /g'} 237 } 238 } else if (match_hilight '^ip ') { 239 arg = `{echo $MSG | sed 's/[^ ]* *//'} 240 ip4 = `{echo $arg | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'} 241 242 if (~ $ip4 ()) { 243 ip4 = dig +short $arg A 244 } 245 246 ipinfo = `{curl https://ipinfo.io/$ip4/json | jq .city,.region,.country | tr -d "} 247 send_msg $TARGET 'IPv4: ' ^ $ip4 ^ ' City: ' ^ $ipinfo(1) ^ ' Region: ' ^ $ipinfo(2) ^ ' Country: ' ^ $ipinfo(3) 248 } else if (!islocked insult && match_hilight -iE 'you suck|fuck you|go fuck yourself|stupid bot|idiot|retard|shut up') { 249 lock insult 150 250 send_msg $TARGET `$nl{randomize \ 251 'If you hate me so much I can leave and never come back' \ 252 'Whatever. No one thinks you''re cool' \ 253 'If you can''t think of anything nice to say, don''t say it' \ 254 'Stop acting like you''re any better than me' \ 255 'Rude.' \ 256 'Consider yourself lucky that I am forced to keep responding to you' \ 257 'I have feelings too' \ 258 'Bots have feelings too' \ 259 'You''ll regret saying that one day'} 260 } else if (match_hilight -iE '^(hi|hey|hej|hello|hallÄ)' || match_msg -iE '^(hi|hey|hej|hallo|hallÄ).*' ^ $nick ^ '[[:space:]]*$') { 261 if (!islocked personalgreet) { 262 SPLIT = `{echo $MSG} 263 send_msg $TARGET `$nl{printf \ 264 'Hey ' ^ $NICK ^ '\n' ^ 'Hey\n' ^ $NICK ^ ', hello\n' ^ 'Hello\n' ^ 'Hi ' ^ $NICK ^ '\n' ^ 'Hi\n' | 265 grep -ivF $SPLIT(1) | shuf -n 1} 266 lock personalgreet 60 267 } 268 } else if (match_hilight '.*') { 269 send_msg $TARGET `$nl{grep '^[^#]' < data/suggest/response | shuf -n 1} 270 } else { 271 urls = `$nl{echo $MSG | grep -Eo 'https?://[^ ]*'} 272 for (url in $urls) { 273 title $url 274 } 275 }