marvvin

[archived] IRC bot
git clone https://hhvn.uk/marvvin
git clone git://hhvn.uk/marvvin
Log | Files | Refs | README | LICENSE

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 }