1*906afcb8SAndy Fiddaman#!/usr/bin/ksh93 2*906afcb8SAndy Fiddaman 3*906afcb8SAndy Fiddaman# 4*906afcb8SAndy Fiddaman# CDDL HEADER START 5*906afcb8SAndy Fiddaman# 6*906afcb8SAndy Fiddaman# The contents of this file are subject to the terms of the 7*906afcb8SAndy Fiddaman# Common Development and Distribution License (the "License"). 8*906afcb8SAndy Fiddaman# You may not use this file except in compliance with the License. 9*906afcb8SAndy Fiddaman# 10*906afcb8SAndy Fiddaman# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11*906afcb8SAndy Fiddaman# or http://www.opensolaris.org/os/licensing. 12*906afcb8SAndy Fiddaman# See the License for the specific language governing permissions 13*906afcb8SAndy Fiddaman# and limitations under the License. 14*906afcb8SAndy Fiddaman# 15*906afcb8SAndy Fiddaman# When distributing Covered Code, include this CDDL HEADER in each 16*906afcb8SAndy Fiddaman# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17*906afcb8SAndy Fiddaman# If applicable, add the following below this CDDL HEADER, with the 18*906afcb8SAndy Fiddaman# fields enclosed by brackets "[]" replaced with your own identifying 19*906afcb8SAndy Fiddaman# information: Portions Copyright [yyyy] [name of copyright owner] 20*906afcb8SAndy Fiddaman# 21*906afcb8SAndy Fiddaman# CDDL HEADER END 22*906afcb8SAndy Fiddaman# 23*906afcb8SAndy Fiddaman 24*906afcb8SAndy Fiddaman# 25*906afcb8SAndy Fiddaman# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 26*906afcb8SAndy Fiddaman# 27*906afcb8SAndy Fiddaman 28*906afcb8SAndy Fiddaman# 29*906afcb8SAndy Fiddaman# shircbot - a simple IRC client/bot demo 30*906afcb8SAndy Fiddaman# 31*906afcb8SAndy Fiddaman 32*906afcb8SAndy Fiddaman# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant 33*906afcb8SAndy Fiddamanexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin 34*906afcb8SAndy Fiddaman 35*906afcb8SAndy Fiddaman# Make sure all math stuff runs in the "C" locale to avoid problems 36*906afcb8SAndy Fiddaman# with alternative # radix point representations (e.g. ',' instead of 37*906afcb8SAndy Fiddaman# '.' in de_DE.*-locales). This needs to be set _before_ any 38*906afcb8SAndy Fiddaman# floating-point constants are defined in this script). 39*906afcb8SAndy Fiddamanif [[ "${LC_ALL}" != "" ]] ; then 40*906afcb8SAndy Fiddaman export \ 41*906afcb8SAndy Fiddaman LC_MONETARY="${LC_ALL}" \ 42*906afcb8SAndy Fiddaman LC_MESSAGES="${LC_ALL}" \ 43*906afcb8SAndy Fiddaman LC_COLLATE="${LC_ALL}" \ 44*906afcb8SAndy Fiddaman LC_CTYPE="${LC_ALL}" 45*906afcb8SAndy Fiddaman unset LC_ALL 46*906afcb8SAndy Fiddamanfi 47*906afcb8SAndy Fiddamanexport LC_NUMERIC=C 48*906afcb8SAndy Fiddaman 49*906afcb8SAndy Fiddamanfunction fatal_error 50*906afcb8SAndy Fiddaman{ 51*906afcb8SAndy Fiddaman print -u2 "${progname}: $*" 52*906afcb8SAndy Fiddaman exit 1 53*906afcb8SAndy Fiddaman} 54*906afcb8SAndy Fiddaman 55*906afcb8SAndy Fiddaman# Definition for a IRC session class 56*906afcb8SAndy Fiddamantypeset -T ircsession_t=( 57*906afcb8SAndy Fiddaman compound server=( 58*906afcb8SAndy Fiddaman typeset name 59*906afcb8SAndy Fiddaman integer port 60*906afcb8SAndy Fiddaman ) 61*906afcb8SAndy Fiddaman 62*906afcb8SAndy Fiddaman typeset nick="ksh93irc" 63*906afcb8SAndy Fiddaman 64*906afcb8SAndy Fiddaman typeset running=true 65*906afcb8SAndy Fiddaman 66*906afcb8SAndy Fiddaman integer fd=-1 67*906afcb8SAndy Fiddaman 68*906afcb8SAndy Fiddaman function createsession 69*906afcb8SAndy Fiddaman { 70*906afcb8SAndy Fiddaman set -o xtrace 71*906afcb8SAndy Fiddaman 72*906afcb8SAndy Fiddaman _.server.name=$1 73*906afcb8SAndy Fiddaman _.server.port=$2 74*906afcb8SAndy Fiddaman _.nick=$3 75*906afcb8SAndy Fiddaman 76*906afcb8SAndy Fiddaman redirect {_.fd}<> "/dev/tcp/${_.server.name}/${_.server.port}" 77*906afcb8SAndy Fiddaman (( $? == 0 )) || { print -n2 $"Could not open server connection." ; return 1 ; } 78*906afcb8SAndy Fiddaman 79*906afcb8SAndy Fiddaman printf "fd=%d\n" _.fd 80*906afcb8SAndy Fiddaman 81*906afcb8SAndy Fiddaman return 0 82*906afcb8SAndy Fiddaman } 83*906afcb8SAndy Fiddaman 84*906afcb8SAndy Fiddaman function login 85*906afcb8SAndy Fiddaman { 86*906afcb8SAndy Fiddaman { 87*906afcb8SAndy Fiddaman printf "USER %s %s %s %s\n" "${_.nick}" "${_.nick}" "${_.nick}" "${_.nick}" 88*906afcb8SAndy Fiddaman printf "NICK %s\n" "${_.nick}" 89*906afcb8SAndy Fiddaman } >&${_.fd} 90*906afcb8SAndy Fiddaman 91*906afcb8SAndy Fiddaman return 0 92*906afcb8SAndy Fiddaman } 93*906afcb8SAndy Fiddaman 94*906afcb8SAndy Fiddaman function join_channel 95*906afcb8SAndy Fiddaman { 96*906afcb8SAndy Fiddaman printf "JOIN %s\n" "$1" >&${_.fd} 97*906afcb8SAndy Fiddaman 98*906afcb8SAndy Fiddaman return 0 99*906afcb8SAndy Fiddaman } 100*906afcb8SAndy Fiddaman 101*906afcb8SAndy Fiddaman function mainloop 102*906afcb8SAndy Fiddaman { 103*906afcb8SAndy Fiddaman typeset line 104*906afcb8SAndy Fiddaman float -S last_tick=0 105*906afcb8SAndy Fiddaman # We use the linebuf_t class here since network traffic 106*906afcb8SAndy Fiddaman # isn't guranteed to fit a single $'\n'-terminated line 107*906afcb8SAndy Fiddaman # into one TCP package. linebuf_t buffers characters 108*906afcb8SAndy Fiddaman # until it has one complete line. This avoids the need for 109*906afcb8SAndy Fiddaman # async I/O normally used by IRC clients 110*906afcb8SAndy Fiddaman linebuf_t serverbuf 111*906afcb8SAndy Fiddaman linebuf_t clientbuf 112*906afcb8SAndy Fiddaman integer fd=${_.fd} 113*906afcb8SAndy Fiddaman 114*906afcb8SAndy Fiddaman _.login 115*906afcb8SAndy Fiddaman 116*906afcb8SAndy Fiddaman while ${_.running} ; do 117*906afcb8SAndy Fiddaman while serverbuf.readbuf line <&${fd} ; do 118*906afcb8SAndy Fiddaman _.dispatch_serverevent "$line" 119*906afcb8SAndy Fiddaman done 120*906afcb8SAndy Fiddaman 121*906afcb8SAndy Fiddaman while clientbuf.readbuf line </dev/stdin ; do 122*906afcb8SAndy Fiddaman printf "client: %q\n" "${line}" 123*906afcb8SAndy Fiddaman printf "%s\n" "${line}" >&${fd} 124*906afcb8SAndy Fiddaman done 125*906afcb8SAndy Fiddaman 126*906afcb8SAndy Fiddaman # call mainloop_tick function in intervals to handle 127*906afcb8SAndy Fiddaman # async events (e.g. automatic /join etc.) 128*906afcb8SAndy Fiddaman if (( (SECONDS-last_tick) > 5. )) ; then 129*906afcb8SAndy Fiddaman (( last_tick=SECONDS )) 130*906afcb8SAndy Fiddaman _.mainloop_tick 131*906afcb8SAndy Fiddaman fi 132*906afcb8SAndy Fiddaman done 133*906afcb8SAndy Fiddaman 134*906afcb8SAndy Fiddaman return 0 135*906afcb8SAndy Fiddaman } 136*906afcb8SAndy Fiddaman 137*906afcb8SAndy Fiddaman function mainloop_tick 138*906afcb8SAndy Fiddaman { 139*906afcb8SAndy Fiddaman return 0 140*906afcb8SAndy Fiddaman } 141*906afcb8SAndy Fiddaman 142*906afcb8SAndy Fiddaman function dispatch_serverevent 143*906afcb8SAndy Fiddaman { 144*906afcb8SAndy Fiddaman typeset line="$1" 145*906afcb8SAndy Fiddaman 146*906afcb8SAndy Fiddaman case "${line}" in 147*906afcb8SAndy Fiddaman ~(El)PING) 148*906afcb8SAndy Fiddaman compound ping_args=( 149*906afcb8SAndy Fiddaman line="$line" 150*906afcb8SAndy Fiddaman ) 151*906afcb8SAndy Fiddaman _.serverevent_ping "ping_args" 152*906afcb8SAndy Fiddaman ;; 153*906afcb8SAndy Fiddaman ~(El):.*\ PRIVMSG) 154*906afcb8SAndy Fiddaman compound privmsg_args=( 155*906afcb8SAndy Fiddaman typeset line="$line" 156*906afcb8SAndy Fiddaman typeset msguser="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\1}" 157*906afcb8SAndy Fiddaman typeset msgchannel="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\3}" 158*906afcb8SAndy Fiddaman typeset msg="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\4}" 159*906afcb8SAndy Fiddaman ) 160*906afcb8SAndy Fiddaman _.serverevent_privmsg "privmsg_args" 161*906afcb8SAndy Fiddaman ;; 162*906afcb8SAndy Fiddaman ~(El):.*\ INVITE) 163*906afcb8SAndy Fiddaman compound invite_args=( 164*906afcb8SAndy Fiddaman typeset line="$line" 165*906afcb8SAndy Fiddaman typeset inviteuser="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\1}" 166*906afcb8SAndy Fiddaman typeset invitenick="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\3}" 167*906afcb8SAndy Fiddaman typeset invitechannel="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\4}" 168*906afcb8SAndy Fiddaman ) 169*906afcb8SAndy Fiddaman _.serverevent_invite "invite_args" 170*906afcb8SAndy Fiddaman ;; 171*906afcb8SAndy Fiddaman *) 172*906afcb8SAndy Fiddaman printf "server: %q\n" "${line}" 173*906afcb8SAndy Fiddaman ;; 174*906afcb8SAndy Fiddaman esac 175*906afcb8SAndy Fiddaman 176*906afcb8SAndy Fiddaman return 0 177*906afcb8SAndy Fiddaman } 178*906afcb8SAndy Fiddaman 179*906afcb8SAndy Fiddaman function serverevent_privmsg 180*906afcb8SAndy Fiddaman { 181*906afcb8SAndy Fiddaman nameref args=$1 182*906afcb8SAndy Fiddaman typeset msguser="${args.msguser}" 183*906afcb8SAndy Fiddaman typeset msgchannel="${args.msgchannel}" 184*906afcb8SAndy Fiddaman typeset msg="${args.msg}" 185*906afcb8SAndy Fiddaman 186*906afcb8SAndy Fiddaman printf "#privms: user=%q, channel=%q, msg=%q\n" "$msguser" "$msgchannel" "$msg" 187*906afcb8SAndy Fiddaman 188*906afcb8SAndy Fiddaman return 0 189*906afcb8SAndy Fiddaman } 190*906afcb8SAndy Fiddaman 191*906afcb8SAndy Fiddaman function serverevent_invite 192*906afcb8SAndy Fiddaman { 193*906afcb8SAndy Fiddaman nameref args=$1 194*906afcb8SAndy Fiddaman 195*906afcb8SAndy Fiddaman printf "JOIN %s\n" "${args.invitechannel/:/}" >&${_.fd} 196*906afcb8SAndy Fiddaman 197*906afcb8SAndy Fiddaman return 0 198*906afcb8SAndy Fiddaman } 199*906afcb8SAndy Fiddaman 200*906afcb8SAndy Fiddaman function send_privmsg 201*906afcb8SAndy Fiddaman { 202*906afcb8SAndy Fiddaman typeset channel="$1" 203*906afcb8SAndy Fiddaman typeset msg="$2" 204*906afcb8SAndy Fiddaman 205*906afcb8SAndy Fiddaman # Do we have to escape any characters in "msg" ? 206*906afcb8SAndy Fiddaman printf "PRIVMSG %s :%s\n" "${channel}" "${msg}" >&${_.fd} 207*906afcb8SAndy Fiddaman 208*906afcb8SAndy Fiddaman return 0 209*906afcb8SAndy Fiddaman } 210*906afcb8SAndy Fiddaman 211*906afcb8SAndy Fiddaman function serverevent_ping 212*906afcb8SAndy Fiddaman { 213*906afcb8SAndy Fiddaman nameref args=$1 214*906afcb8SAndy Fiddaman 215*906afcb8SAndy Fiddaman printf "PONG %s\n" "${args.line/~(Elr)([^ ]+) ([^ ]+).*/\2}" >&${_.fd} 216*906afcb8SAndy Fiddaman 217*906afcb8SAndy Fiddaman return 0 218*906afcb8SAndy Fiddaman } 219*906afcb8SAndy Fiddaman) 220*906afcb8SAndy Fiddaman 221*906afcb8SAndy Fiddaman# line buffer class 222*906afcb8SAndy Fiddaman# The buffer class tries to read characters from the given <fd> until 223*906afcb8SAndy Fiddaman# it has read a whole line. 224*906afcb8SAndy Fiddamantypeset -T linebuf_t=( 225*906afcb8SAndy Fiddaman typeset buf 226*906afcb8SAndy Fiddaman 227*906afcb8SAndy Fiddaman function reset 228*906afcb8SAndy Fiddaman { 229*906afcb8SAndy Fiddaman _.buf="" 230*906afcb8SAndy Fiddaman return 0 231*906afcb8SAndy Fiddaman } 232*906afcb8SAndy Fiddaman 233*906afcb8SAndy Fiddaman function readbuf 234*906afcb8SAndy Fiddaman { 235*906afcb8SAndy Fiddaman nameref var=$1 236*906afcb8SAndy Fiddaman typeset ch 237*906afcb8SAndy Fiddaman 238*906afcb8SAndy Fiddaman while IFS='' read -t 0.2 -N 1 ch ; do 239*906afcb8SAndy Fiddaman [[ "$ch" == $'\r' ]] && continue 240*906afcb8SAndy Fiddaman 241*906afcb8SAndy Fiddaman if [[ "$ch" == $'\n' ]] ; then 242*906afcb8SAndy Fiddaman var="${_.buf}" 243*906afcb8SAndy Fiddaman _.reset 244*906afcb8SAndy Fiddaman return 0 245*906afcb8SAndy Fiddaman fi 246*906afcb8SAndy Fiddaman 247*906afcb8SAndy Fiddaman _.buf+="$ch" 248*906afcb8SAndy Fiddaman done 249*906afcb8SAndy Fiddaman 250*906afcb8SAndy Fiddaman return 1 251*906afcb8SAndy Fiddaman } 252*906afcb8SAndy Fiddaman) 253*906afcb8SAndy Fiddaman 254*906afcb8SAndy Fiddamanfunction usage 255*906afcb8SAndy Fiddaman{ 256*906afcb8SAndy Fiddaman OPTIND=0 257*906afcb8SAndy Fiddaman getopts -a "${progname}" "${shircbot_usage}" OPT '-?' 258*906afcb8SAndy Fiddaman exit 2 259*906afcb8SAndy Fiddaman} 260*906afcb8SAndy Fiddaman 261*906afcb8SAndy Fiddaman# program start 262*906afcb8SAndy Fiddaman# (be carefull with builtins here - they are unconditionally available 263*906afcb8SAndy Fiddaman# in the shell's "restricted" mode) 264*906afcb8SAndy Fiddamanbuiltin basename 265*906afcb8SAndy Fiddamanbuiltin sum 266*906afcb8SAndy Fiddaman 267*906afcb8SAndy Fiddamantypeset progname="${ basename "${0}" ; }" 268*906afcb8SAndy Fiddaman 269*906afcb8SAndy Fiddamantypeset -r shircbot_usage=$'+ 270*906afcb8SAndy Fiddaman[-?\n@(#)\$Id: shircbot (Roland Mainz) 2009-09-09 \$\n] 271*906afcb8SAndy Fiddaman[-author?Roland Mainz <roland.mainz@sun.com>] 272*906afcb8SAndy Fiddaman[-author?Roland Mainz <roland.mainz@nrubsig.org>] 273*906afcb8SAndy Fiddaman[+NAME?shircbot - simple IRC bot demo] 274*906afcb8SAndy Fiddaman[+DESCRIPTION?\bshircbot\b is a small demo IRC bot which provides 275*906afcb8SAndy Fiddaman a simple IRC bot with several subcommands.] 276*906afcb8SAndy Fiddaman[n:nickname?IRC nickname for this bot.]:[nick] 277*906afcb8SAndy Fiddaman[s:ircserver?IRC servername.]:[servername] 278*906afcb8SAndy Fiddaman[j:joinchannel?IRC servername.]:[channelname] 279*906afcb8SAndy Fiddaman[+SEE ALSO?\bksh93\b(1)] 280*906afcb8SAndy Fiddaman' 281*906afcb8SAndy Fiddaman 282*906afcb8SAndy Fiddamancompound config=( 283*906afcb8SAndy Fiddaman typeset nickname="${LOGNAME}bot" 284*906afcb8SAndy Fiddaman typeset servername="irc.freenode.net" 285*906afcb8SAndy Fiddaman integer port=6667 286*906afcb8SAndy Fiddaman typeset -a join_channels 287*906afcb8SAndy Fiddaman) 288*906afcb8SAndy Fiddaman 289*906afcb8SAndy Fiddamanwhile getopts -a "${progname}" "${shircbot_usage}" OPT ; do 290*906afcb8SAndy Fiddaman# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" 291*906afcb8SAndy Fiddaman case ${OPT} in 292*906afcb8SAndy Fiddaman n) config.nickname="${OPTARG}" ;; 293*906afcb8SAndy Fiddaman s) config.servername="${OPTARG}" ;; 294*906afcb8SAndy Fiddaman j) config.join_channels+=( "${OPTARG}" ) ;; 295*906afcb8SAndy Fiddaman *) usage ;; 296*906afcb8SAndy Fiddaman esac 297*906afcb8SAndy Fiddamandone 298*906afcb8SAndy Fiddamanshift $((OPTIND-1)) 299*906afcb8SAndy Fiddaman 300*906afcb8SAndy Fiddaman# if no channel was provided we join a predefined set of channels 301*906afcb8SAndy Fiddamanif (( ${#config.join_channels[@]} == 0 )) ; then 302*906afcb8SAndy Fiddaman if [[ "${config.servername}" == "irc.freenode.net" ]] ; then 303*906afcb8SAndy Fiddaman config.join_channels+=( "#opensolaris" ) 304*906afcb8SAndy Fiddaman config.join_channels+=( "#opensolaris-dev" ) 305*906afcb8SAndy Fiddaman config.join_channels+=( "#opensolaris-arc" ) 306*906afcb8SAndy Fiddaman config.join_channels+=( "#opensolaris-meeting" ) 307*906afcb8SAndy Fiddaman config.join_channels+=( "#ospkg" ) 308*906afcb8SAndy Fiddaman config.join_channels+=( "#ksh" ) 309*906afcb8SAndy Fiddaman elif [[ "${config.servername}" == ~(E)irc.(sfbay|sweden) ]] ; then 310*906afcb8SAndy Fiddaman config.join_channels+=( "#onnv" ) 311*906afcb8SAndy Fiddaman fi 312*906afcb8SAndy Fiddamanfi 313*906afcb8SAndy Fiddaman 314*906afcb8SAndy Fiddamanprint "## Start." 315*906afcb8SAndy Fiddaman 316*906afcb8SAndy Fiddamanircsession_t mybot 317*906afcb8SAndy Fiddaman 318*906afcb8SAndy Fiddaman# override ircsession_t::serverevent_privmsg with a new method for our bot 319*906afcb8SAndy Fiddamanfunction mybot.serverevent_privmsg 320*906afcb8SAndy Fiddaman{ 321*906afcb8SAndy Fiddaman nameref args=$1 322*906afcb8SAndy Fiddaman typeset msguser="${args.msguser}" 323*906afcb8SAndy Fiddaman typeset msgchannel="${args.msgchannel}" 324*906afcb8SAndy Fiddaman typeset msg="${args.msg}" 325*906afcb8SAndy Fiddaman 326*906afcb8SAndy Fiddaman printf "#message: user=%q, channel=%q, msg=%q\n" "$msguser" "$msgchannel" "$msg" 327*906afcb8SAndy Fiddaman 328*906afcb8SAndy Fiddaman # Check if we get a private message 329*906afcb8SAndy Fiddaman if [[ "${msgchannel}" == "${_.nick}" ]] ; then 330*906afcb8SAndy Fiddaman # ${msgchannel} point to our own nick if we got a private message, 331*906afcb8SAndy Fiddaman # we need to extract the sender's nickname from ${msguser} and put 332*906afcb8SAndy Fiddaman # it into msgchannel 333*906afcb8SAndy Fiddaman msgchannel="${msguser/~(El):(.*)!.*/\1}" 334*906afcb8SAndy Fiddaman else 335*906afcb8SAndy Fiddaman # check if this is a command for this bot 336*906afcb8SAndy Fiddaman [[ "$msg" != ~(Eli):${_.nick}:[[:space:]] ]] && return 0 337*906afcb8SAndy Fiddaman fi 338*906afcb8SAndy Fiddaman 339*906afcb8SAndy Fiddaman # strip beginning (e.g. ":<nick>:" or ":") plus extra spaces 340*906afcb8SAndy Fiddaman msg="${msg/~(Eli)(:${_.nick})*:[[:space:]]*/}" 341*906afcb8SAndy Fiddaman 342*906afcb8SAndy Fiddaman printf "botmsg=%q\n" "$msg" 343*906afcb8SAndy Fiddaman 344*906afcb8SAndy Fiddaman case "$msg" in 345*906afcb8SAndy Fiddaman ~(Eli)date) 346*906afcb8SAndy Fiddaman _.send_privmsg "$msgchannel" "${ 347*906afcb8SAndy Fiddaman printf "%(%Y-%m-%d, %Th/%Z)T\n" 348*906afcb8SAndy Fiddaman }" 349*906afcb8SAndy Fiddaman ;; 350*906afcb8SAndy Fiddaman ~(Eli)echo) 351*906afcb8SAndy Fiddaman _.send_privmsg "$msgchannel" "${msg#*echo}" 352*906afcb8SAndy Fiddaman ;; 353*906afcb8SAndy Fiddaman ~(Eli)exitbot) 354*906afcb8SAndy Fiddaman typeset exitkey="$(print "$msguser" | sum -x sha1)" # this is unwise&&insecure 355*906afcb8SAndy Fiddaman if [[ "$msg" == *${exitkey}* ]] ; then 356*906afcb8SAndy Fiddaman _.running=false 357*906afcb8SAndy Fiddaman fi 358*906afcb8SAndy Fiddaman ;; 359*906afcb8SAndy Fiddaman ~(Eli)help) 360*906afcb8SAndy Fiddaman _.send_privmsg "$msgchannel" "${ 361*906afcb8SAndy Fiddaman printf "Hello, this is shircbot, written in ksh93 (%s). " "${.sh.version}" 362*906afcb8SAndy Fiddaman printf "Subcommands are 'say hello', 'math <math-expr>', 'stocks', 'uuid', 'date' and 'echo'." 363*906afcb8SAndy Fiddaman }" 364*906afcb8SAndy Fiddaman ;; 365*906afcb8SAndy Fiddaman ~(Eli)math) 366*906afcb8SAndy Fiddaman if [[ "${msg}" == ~(E)[\`\$] ]] ; then 367*906afcb8SAndy Fiddaman # "restricted" shell mode would prevent any damage but we try to be carefull... 368*906afcb8SAndy Fiddaman _.send_privmsg "$msgchannel" "Syntax error." 369*906afcb8SAndy Fiddaman else 370*906afcb8SAndy Fiddaman typeset mathexpr="${msg#*math}" 371*906afcb8SAndy Fiddaman 372*906afcb8SAndy Fiddaman printf "Calculating '%s'\n" "${mathexpr}" 373*906afcb8SAndy Fiddaman _.send_privmsg "$msgchannel" "${ 374*906afcb8SAndy Fiddaman ( printf 'export PATH=/usr/${RANDOM}/$$/${RANDOM}/foo ; set -o restricted ; printf "%%s = %%.40g\n" "%s" $(( %s ))\n' "${mathexpr}" "${mathexpr}" | source /dev/stdin 2>&1 ) 375*906afcb8SAndy Fiddaman }" 376*906afcb8SAndy Fiddaman fi 377*906afcb8SAndy Fiddaman ;; 378*906afcb8SAndy Fiddaman ~(Eli)say\ hello) 379*906afcb8SAndy Fiddaman _.send_privmsg "$msgchannel" "Hello, this is a bot." 380*906afcb8SAndy Fiddaman ;; 381*906afcb8SAndy Fiddaman ~(Eli)stocks) 382*906afcb8SAndy Fiddaman typeset stockmsg tickersymbol 383*906afcb8SAndy Fiddaman for tickersymbol in "JAVA" "ORCL" "IBM" "AAPL" "HPQ" ; do 384*906afcb8SAndy Fiddaman stockmsg="$( /usr/sfw/bin/wget -q -O /dev/stdout "http://quote.yahoo.com/d/quotes.csv?f=sl1d1t1c1ohgv&e=.csv&s=${tickersymbol}" 2>&1 )" 385*906afcb8SAndy Fiddaman _.send_privmsg "$msgchannel" "${tickersymbol}: ${stockmsg//,/ }" 386*906afcb8SAndy Fiddaman done 387*906afcb8SAndy Fiddaman ;; 388*906afcb8SAndy Fiddaman ~(Eli)uuid) 389*906afcb8SAndy Fiddaman _.send_privmsg "$msgchannel" "${ 390*906afcb8SAndy Fiddaman print "%(%Y%M%D%S%N)T$((RANDOM))%s\n" "${msguser}" | sum -x sha256 391*906afcb8SAndy Fiddaman }" 392*906afcb8SAndy Fiddaman ;; 393*906afcb8SAndy Fiddaman esac 394*906afcb8SAndy Fiddaman 395*906afcb8SAndy Fiddaman return 0 396*906afcb8SAndy Fiddaman} 397*906afcb8SAndy Fiddaman 398*906afcb8SAndy Fiddaman# Automatically join the list of channels listed in |config.join_channels| 399*906afcb8SAndy Fiddaman# after the client is connected to the server for some time 400*906afcb8SAndy Fiddamanfunction mybot.mainloop_tick 401*906afcb8SAndy Fiddaman{ 402*906afcb8SAndy Fiddaman integer -S autojoin_done=2 403*906afcb8SAndy Fiddaman integer i 404*906afcb8SAndy Fiddaman 405*906afcb8SAndy Fiddaman if (( autojoin_done-- == 0 && ${#config.join_channels[@]} > 0 )) ; then 406*906afcb8SAndy Fiddaman print "# Autojoin channels..." 407*906afcb8SAndy Fiddaman 408*906afcb8SAndy Fiddaman for ((i=0 ; i < ${#config.join_channels[@]} ; i++ )) ; do 409*906afcb8SAndy Fiddaman mybot.join_channel "${config.join_channels[i]}" 410*906afcb8SAndy Fiddaman done 411*906afcb8SAndy Fiddaman fi 412*906afcb8SAndy Fiddaman 413*906afcb8SAndy Fiddaman return 0 414*906afcb8SAndy Fiddaman} 415*906afcb8SAndy Fiddaman 416*906afcb8SAndy Fiddamanmybot.createsession "${config.servername}" ${config.port} "${config.nickname}" 417*906afcb8SAndy Fiddaman 418*906afcb8SAndy Fiddaman# This is a network-facing application - once we've set eveything up 419*906afcb8SAndy Fiddaman# we set PATH to a random value and switch to the shell's restricted 420*906afcb8SAndy Fiddaman# mode to make sure noone can escape the jail. 421*906afcb8SAndy Fiddaman#export PATH=/usr/$RANDOM/foo 422*906afcb8SAndy Fiddaman#set -o restricted 423*906afcb8SAndy Fiddaman 424*906afcb8SAndy Fiddamanmybot.mainloop 425*906afcb8SAndy Fiddaman 426*906afcb8SAndy Fiddamanprint "## End." 427*906afcb8SAndy Fiddaman 428*906afcb8SAndy Fiddamanexit 0 429