18462SApril.Chin@Sun.COM#!/usr/bin/ksh93 28462SApril.Chin@Sun.COM 38462SApril.Chin@Sun.COM# 48462SApril.Chin@Sun.COM# CDDL HEADER START 58462SApril.Chin@Sun.COM# 68462SApril.Chin@Sun.COM# The contents of this file are subject to the terms of the 78462SApril.Chin@Sun.COM# Common Development and Distribution License (the "License"). 88462SApril.Chin@Sun.COM# You may not use this file except in compliance with the License. 98462SApril.Chin@Sun.COM# 108462SApril.Chin@Sun.COM# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 118462SApril.Chin@Sun.COM# or http://www.opensolaris.org/os/licensing. 128462SApril.Chin@Sun.COM# See the License for the specific language governing permissions 138462SApril.Chin@Sun.COM# and limitations under the License. 148462SApril.Chin@Sun.COM# 158462SApril.Chin@Sun.COM# When distributing Covered Code, include this CDDL HEADER in each 168462SApril.Chin@Sun.COM# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 178462SApril.Chin@Sun.COM# If applicable, add the following below this CDDL HEADER, with the 188462SApril.Chin@Sun.COM# fields enclosed by brackets "[]" replaced with your own identifying 198462SApril.Chin@Sun.COM# information: Portions Copyright [yyyy] [name of copyright owner] 208462SApril.Chin@Sun.COM# 218462SApril.Chin@Sun.COM# CDDL HEADER END 228462SApril.Chin@Sun.COM# 238462SApril.Chin@Sun.COM 248462SApril.Chin@Sun.COM# 25*12068SRoger.Faulkner@Oracle.COM# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 268462SApril.Chin@Sun.COM# 278462SApril.Chin@Sun.COM 288462SApril.Chin@Sun.COM# 298462SApril.Chin@Sun.COM# shircbot - a simple IRC client/bot demo 308462SApril.Chin@Sun.COM# 318462SApril.Chin@Sun.COM 328462SApril.Chin@Sun.COM# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant 338462SApril.Chin@Sun.COMexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin 348462SApril.Chin@Sun.COM 358462SApril.Chin@Sun.COM# Make sure all math stuff runs in the "C" locale to avoid problems 368462SApril.Chin@Sun.COM# with alternative # radix point representations (e.g. ',' instead of 378462SApril.Chin@Sun.COM# '.' in de_DE.*-locales). This needs to be set _before_ any 388462SApril.Chin@Sun.COM# floating-point constants are defined in this script). 398462SApril.Chin@Sun.COMif [[ "${LC_ALL}" != "" ]] ; then 408462SApril.Chin@Sun.COM export \ 418462SApril.Chin@Sun.COM LC_MONETARY="${LC_ALL}" \ 428462SApril.Chin@Sun.COM LC_MESSAGES="${LC_ALL}" \ 438462SApril.Chin@Sun.COM LC_COLLATE="${LC_ALL}" \ 448462SApril.Chin@Sun.COM LC_CTYPE="${LC_ALL}" 458462SApril.Chin@Sun.COM unset LC_ALL 468462SApril.Chin@Sun.COMfi 478462SApril.Chin@Sun.COMexport LC_NUMERIC=C 488462SApril.Chin@Sun.COM 498462SApril.Chin@Sun.COMfunction fatal_error 508462SApril.Chin@Sun.COM{ 518462SApril.Chin@Sun.COM print -u2 "${progname}: $*" 528462SApril.Chin@Sun.COM exit 1 538462SApril.Chin@Sun.COM} 548462SApril.Chin@Sun.COM 558462SApril.Chin@Sun.COM# Definition for a IRC session class 568462SApril.Chin@Sun.COMtypeset -T ircsession_t=( 5710898Sroland.mainz@nrubsig.org compound server=( 588462SApril.Chin@Sun.COM typeset name 598462SApril.Chin@Sun.COM integer port 608462SApril.Chin@Sun.COM ) 618462SApril.Chin@Sun.COM 628462SApril.Chin@Sun.COM typeset nick="ksh93irc" 638462SApril.Chin@Sun.COM 648462SApril.Chin@Sun.COM typeset running=true 658462SApril.Chin@Sun.COM 668462SApril.Chin@Sun.COM integer fd=-1 678462SApril.Chin@Sun.COM 688462SApril.Chin@Sun.COM function createsession 698462SApril.Chin@Sun.COM { 708462SApril.Chin@Sun.COM set -o xtrace 718462SApril.Chin@Sun.COM 728462SApril.Chin@Sun.COM _.server.name=$1 738462SApril.Chin@Sun.COM _.server.port=$2 748462SApril.Chin@Sun.COM _.nick=$3 758462SApril.Chin@Sun.COM 7610898Sroland.mainz@nrubsig.org redirect {_.fd}<> "/dev/tcp/${_.server.name}/${_.server.port}" 778462SApril.Chin@Sun.COM (( $? == 0 )) || { print -n2 $"Could not open server connection." ; return 1 ; } 788462SApril.Chin@Sun.COM 798462SApril.Chin@Sun.COM printf "fd=%d\n" _.fd 808462SApril.Chin@Sun.COM 818462SApril.Chin@Sun.COM return 0 828462SApril.Chin@Sun.COM } 838462SApril.Chin@Sun.COM 848462SApril.Chin@Sun.COM function login 858462SApril.Chin@Sun.COM { 868462SApril.Chin@Sun.COM { 878462SApril.Chin@Sun.COM printf "USER %s %s %s %s\n" "${_.nick}" "${_.nick}" "${_.nick}" "${_.nick}" 888462SApril.Chin@Sun.COM printf "NICK %s\n" "${_.nick}" 898462SApril.Chin@Sun.COM } >&${_.fd} 908462SApril.Chin@Sun.COM 918462SApril.Chin@Sun.COM return 0 928462SApril.Chin@Sun.COM } 938462SApril.Chin@Sun.COM 948462SApril.Chin@Sun.COM function join_channel 958462SApril.Chin@Sun.COM { 968462SApril.Chin@Sun.COM printf "JOIN %s\n" "$1" >&${_.fd} 978462SApril.Chin@Sun.COM 988462SApril.Chin@Sun.COM return 0 998462SApril.Chin@Sun.COM } 1008462SApril.Chin@Sun.COM 1018462SApril.Chin@Sun.COM function mainloop 1028462SApril.Chin@Sun.COM { 1038462SApril.Chin@Sun.COM typeset line 1048462SApril.Chin@Sun.COM float -S last_tick=0 1058462SApril.Chin@Sun.COM # We use the linebuf_t class here since network traffic 1068462SApril.Chin@Sun.COM # isn't guranteed to fit a single $'\n'-terminated line 1078462SApril.Chin@Sun.COM # into one TCP package. linebuf_t buffers characters 1088462SApril.Chin@Sun.COM # until it has one complete line. This avoids the need for 1098462SApril.Chin@Sun.COM # async I/O normally used by IRC clients 1108462SApril.Chin@Sun.COM linebuf_t serverbuf 1118462SApril.Chin@Sun.COM linebuf_t clientbuf 1128462SApril.Chin@Sun.COM integer fd=${_.fd} 11310898Sroland.mainz@nrubsig.org 1148462SApril.Chin@Sun.COM _.login 1158462SApril.Chin@Sun.COM 1168462SApril.Chin@Sun.COM while ${_.running} ; do 1178462SApril.Chin@Sun.COM while serverbuf.readbuf line <&${fd} ; do 1188462SApril.Chin@Sun.COM _.dispatch_serverevent "$line" 1198462SApril.Chin@Sun.COM done 1208462SApril.Chin@Sun.COM 1218462SApril.Chin@Sun.COM while clientbuf.readbuf line </dev/stdin ; do 1228462SApril.Chin@Sun.COM printf "client: %q\n" "${line}" 1238462SApril.Chin@Sun.COM printf "%s\n" "${line}" >&${fd} 1248462SApril.Chin@Sun.COM done 1258462SApril.Chin@Sun.COM 1268462SApril.Chin@Sun.COM # call mainloop_tick function in intervals to handle 1278462SApril.Chin@Sun.COM # async events (e.g. automatic /join etc.) 1288462SApril.Chin@Sun.COM if (( (SECONDS-last_tick) > 5. )) ; then 1298462SApril.Chin@Sun.COM (( last_tick=SECONDS )) 1308462SApril.Chin@Sun.COM _.mainloop_tick 1318462SApril.Chin@Sun.COM fi 1328462SApril.Chin@Sun.COM done 1338462SApril.Chin@Sun.COM 1348462SApril.Chin@Sun.COM return 0 1358462SApril.Chin@Sun.COM } 1368462SApril.Chin@Sun.COM 1378462SApril.Chin@Sun.COM function mainloop_tick 1388462SApril.Chin@Sun.COM { 1398462SApril.Chin@Sun.COM return 0 1408462SApril.Chin@Sun.COM } 1418462SApril.Chin@Sun.COM 1428462SApril.Chin@Sun.COM function dispatch_serverevent 1438462SApril.Chin@Sun.COM { 1448462SApril.Chin@Sun.COM typeset line="$1" 1458462SApril.Chin@Sun.COM 1468462SApril.Chin@Sun.COM case "${line}" in 1478462SApril.Chin@Sun.COM ~(El)PING) 14810898Sroland.mainz@nrubsig.org compound ping_args=( 1498462SApril.Chin@Sun.COM line="$line" 1508462SApril.Chin@Sun.COM ) 1518462SApril.Chin@Sun.COM _.serverevent_ping "ping_args" 1528462SApril.Chin@Sun.COM ;; 1538462SApril.Chin@Sun.COM ~(El):.*\ PRIVMSG) 15410898Sroland.mainz@nrubsig.org compound privmsg_args=( 1558462SApril.Chin@Sun.COM typeset line="$line" 1568462SApril.Chin@Sun.COM typeset msguser="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\1}" 1578462SApril.Chin@Sun.COM typeset msgchannel="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\3}" 1588462SApril.Chin@Sun.COM typeset msg="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\4}" 1598462SApril.Chin@Sun.COM ) 1608462SApril.Chin@Sun.COM _.serverevent_privmsg "privmsg_args" 1618462SApril.Chin@Sun.COM ;; 1628462SApril.Chin@Sun.COM ~(El):.*\ INVITE) 16310898Sroland.mainz@nrubsig.org compound invite_args=( 1648462SApril.Chin@Sun.COM typeset line="$line" 1658462SApril.Chin@Sun.COM typeset inviteuser="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\1}" 1668462SApril.Chin@Sun.COM typeset invitenick="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\3}" 1678462SApril.Chin@Sun.COM typeset invitechannel="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\4}" 1688462SApril.Chin@Sun.COM ) 1698462SApril.Chin@Sun.COM _.serverevent_invite "invite_args" 1708462SApril.Chin@Sun.COM ;; 1718462SApril.Chin@Sun.COM *) 1728462SApril.Chin@Sun.COM printf "server: %q\n" "${line}" 1738462SApril.Chin@Sun.COM ;; 1748462SApril.Chin@Sun.COM esac 1758462SApril.Chin@Sun.COM 1768462SApril.Chin@Sun.COM return 0 1778462SApril.Chin@Sun.COM } 1788462SApril.Chin@Sun.COM 1798462SApril.Chin@Sun.COM function serverevent_privmsg 1808462SApril.Chin@Sun.COM { 1818462SApril.Chin@Sun.COM nameref args=$1 1828462SApril.Chin@Sun.COM typeset msguser="${args.msguser}" 1838462SApril.Chin@Sun.COM typeset msgchannel="${args.msgchannel}" 1848462SApril.Chin@Sun.COM typeset msg="${args.msg}" 1858462SApril.Chin@Sun.COM 1868462SApril.Chin@Sun.COM printf "#privms: user=%q, channel=%q, msg=%q\n" "$msguser" "$msgchannel" "$msg" 1878462SApril.Chin@Sun.COM 1888462SApril.Chin@Sun.COM return 0 1898462SApril.Chin@Sun.COM } 1908462SApril.Chin@Sun.COM 1918462SApril.Chin@Sun.COM function serverevent_invite 1928462SApril.Chin@Sun.COM { 1938462SApril.Chin@Sun.COM nameref args=$1 1948462SApril.Chin@Sun.COM 1958462SApril.Chin@Sun.COM printf "JOIN %s\n" "${args.invitechannel/:/}" >&${_.fd} 1968462SApril.Chin@Sun.COM 1978462SApril.Chin@Sun.COM return 0 1988462SApril.Chin@Sun.COM } 1998462SApril.Chin@Sun.COM 2008462SApril.Chin@Sun.COM function send_privmsg 2018462SApril.Chin@Sun.COM { 2028462SApril.Chin@Sun.COM typeset channel="$1" 2038462SApril.Chin@Sun.COM typeset msg="$2" 2048462SApril.Chin@Sun.COM 2058462SApril.Chin@Sun.COM # Do we have to escape any characters in "msg" ? 2068462SApril.Chin@Sun.COM printf "PRIVMSG %s :%s\n" "${channel}" "${msg}" >&${_.fd} 2078462SApril.Chin@Sun.COM 2088462SApril.Chin@Sun.COM return 0 2098462SApril.Chin@Sun.COM } 2108462SApril.Chin@Sun.COM 2118462SApril.Chin@Sun.COM function serverevent_ping 2128462SApril.Chin@Sun.COM { 2138462SApril.Chin@Sun.COM nameref args=$1 2148462SApril.Chin@Sun.COM 2158462SApril.Chin@Sun.COM printf "PONG %s\n" "${args.line/~(Elr)([^ ]+) ([^ ]+).*/\2}" >&${_.fd} 2168462SApril.Chin@Sun.COM 2178462SApril.Chin@Sun.COM return 0 2188462SApril.Chin@Sun.COM } 2198462SApril.Chin@Sun.COM) 2208462SApril.Chin@Sun.COM 2218462SApril.Chin@Sun.COM# line buffer class 2228462SApril.Chin@Sun.COM# The buffer class tries to read characters from the given <fd> until 2238462SApril.Chin@Sun.COM# it has read a whole line. 2248462SApril.Chin@Sun.COMtypeset -T linebuf_t=( 2258462SApril.Chin@Sun.COM typeset buf 2268462SApril.Chin@Sun.COM 2278462SApril.Chin@Sun.COM function reset 2288462SApril.Chin@Sun.COM { 2298462SApril.Chin@Sun.COM _.buf="" 2308462SApril.Chin@Sun.COM return 0 2318462SApril.Chin@Sun.COM } 2328462SApril.Chin@Sun.COM 2338462SApril.Chin@Sun.COM function readbuf 2348462SApril.Chin@Sun.COM { 2358462SApril.Chin@Sun.COM nameref var=$1 2368462SApril.Chin@Sun.COM typeset ch 2378462SApril.Chin@Sun.COM 2388462SApril.Chin@Sun.COM while IFS='' read -t 0.2 -N 1 ch ; do 2398462SApril.Chin@Sun.COM [[ "$ch" == $'\r' ]] && continue 2408462SApril.Chin@Sun.COM 2418462SApril.Chin@Sun.COM if [[ "$ch" == $'\n' ]] ; then 2428462SApril.Chin@Sun.COM var="${_.buf}" 2438462SApril.Chin@Sun.COM _.reset 2448462SApril.Chin@Sun.COM return 0 2458462SApril.Chin@Sun.COM fi 2468462SApril.Chin@Sun.COM 2478462SApril.Chin@Sun.COM _.buf+="$ch" 2488462SApril.Chin@Sun.COM done 2498462SApril.Chin@Sun.COM 2508462SApril.Chin@Sun.COM return 1 2518462SApril.Chin@Sun.COM } 2528462SApril.Chin@Sun.COM) 2538462SApril.Chin@Sun.COM 2548462SApril.Chin@Sun.COMfunction usage 2558462SApril.Chin@Sun.COM{ 2568462SApril.Chin@Sun.COM OPTIND=0 2578462SApril.Chin@Sun.COM getopts -a "${progname}" "${shircbot_usage}" OPT '-?' 2588462SApril.Chin@Sun.COM exit 2 2598462SApril.Chin@Sun.COM} 2608462SApril.Chin@Sun.COM 2618462SApril.Chin@Sun.COM# program start 2628462SApril.Chin@Sun.COM# (be carefull with builtins here - they are unconditionally available 2638462SApril.Chin@Sun.COM# in the shell's "restricted" mode) 2648462SApril.Chin@Sun.COMbuiltin basename 2658462SApril.Chin@Sun.COMbuiltin sum 2668462SApril.Chin@Sun.COM 2678462SApril.Chin@Sun.COMtypeset progname="${ basename "${0}" ; }" 2688462SApril.Chin@Sun.COM 2698462SApril.Chin@Sun.COMtypeset -r shircbot_usage=$'+ 27010898Sroland.mainz@nrubsig.org[-?\n@(#)\$Id: shircbot (Roland Mainz) 2009-09-09 \$\n] 2718462SApril.Chin@Sun.COM[-author?Roland Mainz <roland.mainz@sun.com>] 2728462SApril.Chin@Sun.COM[-author?Roland Mainz <roland.mainz@nrubsig.org>] 2738462SApril.Chin@Sun.COM[+NAME?shircbot - simple IRC bot demo] 2748462SApril.Chin@Sun.COM[+DESCRIPTION?\bshircbot\b is a small demo IRC bot which provides 2758462SApril.Chin@Sun.COM a simple IRC bot with several subcommands.] 2768462SApril.Chin@Sun.COM[n:nickname?IRC nickname for this bot.]:[nick] 2778462SApril.Chin@Sun.COM[s:ircserver?IRC servername.]:[servername] 2788462SApril.Chin@Sun.COM[j:joinchannel?IRC servername.]:[channelname] 2798462SApril.Chin@Sun.COM[+SEE ALSO?\bksh93\b(1)] 2808462SApril.Chin@Sun.COM' 2818462SApril.Chin@Sun.COM 28210898Sroland.mainz@nrubsig.orgcompound config=( 2838462SApril.Chin@Sun.COM typeset nickname="${LOGNAME}bot" 2848462SApril.Chin@Sun.COM typeset servername="irc.freenode.net" 2858462SApril.Chin@Sun.COM integer port=6667 2868462SApril.Chin@Sun.COM typeset -a join_channels 2878462SApril.Chin@Sun.COM) 2888462SApril.Chin@Sun.COM 2898462SApril.Chin@Sun.COMwhile getopts -a "${progname}" "${shircbot_usage}" OPT ; do 2908462SApril.Chin@Sun.COM# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|" 2918462SApril.Chin@Sun.COM case ${OPT} in 2928462SApril.Chin@Sun.COM n) config.nickname="${OPTARG}" ;; 2938462SApril.Chin@Sun.COM s) config.servername="${OPTARG}" ;; 2948462SApril.Chin@Sun.COM j) config.join_channels+=( "${OPTARG}" ) ;; 2958462SApril.Chin@Sun.COM *) usage ;; 2968462SApril.Chin@Sun.COM esac 2978462SApril.Chin@Sun.COMdone 2988462SApril.Chin@Sun.COMshift $((OPTIND-1)) 2998462SApril.Chin@Sun.COM 3008462SApril.Chin@Sun.COM# if no channel was provided we join a predefined set of channels 3018462SApril.Chin@Sun.COMif (( ${#config.join_channels[@]} == 0 )) ; then 3028462SApril.Chin@Sun.COM if [[ "${config.servername}" == "irc.freenode.net" ]] ; then 3038462SApril.Chin@Sun.COM config.join_channels+=( "#opensolaris" ) 3048462SApril.Chin@Sun.COM config.join_channels+=( "#opensolaris-dev" ) 3058462SApril.Chin@Sun.COM config.join_channels+=( "#opensolaris-arc" ) 30610898Sroland.mainz@nrubsig.org config.join_channels+=( "#opensolaris-meeting" ) 30710898Sroland.mainz@nrubsig.org config.join_channels+=( "#ospkg" ) 3088462SApril.Chin@Sun.COM config.join_channels+=( "#ksh" ) 3098462SApril.Chin@Sun.COM elif [[ "${config.servername}" == ~(E)irc.(sfbay|sweden) ]] ; then 3108462SApril.Chin@Sun.COM config.join_channels+=( "#onnv" ) 3118462SApril.Chin@Sun.COM fi 3128462SApril.Chin@Sun.COMfi 3138462SApril.Chin@Sun.COM 3148462SApril.Chin@Sun.COMprint "## Start." 3158462SApril.Chin@Sun.COM 3168462SApril.Chin@Sun.COMircsession_t mybot 3178462SApril.Chin@Sun.COM 3188462SApril.Chin@Sun.COM# override ircsession_t::serverevent_privmsg with a new method for our bot 3198462SApril.Chin@Sun.COMfunction mybot.serverevent_privmsg 3208462SApril.Chin@Sun.COM{ 3218462SApril.Chin@Sun.COM nameref args=$1 3228462SApril.Chin@Sun.COM typeset msguser="${args.msguser}" 3238462SApril.Chin@Sun.COM typeset msgchannel="${args.msgchannel}" 3248462SApril.Chin@Sun.COM typeset msg="${args.msg}" 3258462SApril.Chin@Sun.COM 3268462SApril.Chin@Sun.COM printf "#message: user=%q, channel=%q, msg=%q\n" "$msguser" "$msgchannel" "$msg" 3278462SApril.Chin@Sun.COM 3288462SApril.Chin@Sun.COM # Check if we get a private message 3298462SApril.Chin@Sun.COM if [[ "${msgchannel}" == "${_.nick}" ]] ; then 3308462SApril.Chin@Sun.COM # ${msgchannel} point to our own nick if we got a private message, 3318462SApril.Chin@Sun.COM # we need to extract the sender's nickname from ${msguser} and put 3328462SApril.Chin@Sun.COM # it into msgchannel 3338462SApril.Chin@Sun.COM msgchannel="${msguser/~(El):(.*)!.*/\1}" 3348462SApril.Chin@Sun.COM else 3358462SApril.Chin@Sun.COM # check if this is a command for this bot 3368462SApril.Chin@Sun.COM [[ "$msg" != ~(Eli):${_.nick}:[[:space:]] ]] && return 0 3378462SApril.Chin@Sun.COM fi 3388462SApril.Chin@Sun.COM 3398462SApril.Chin@Sun.COM # strip beginning (e.g. ":<nick>:" or ":") plus extra spaces 3408462SApril.Chin@Sun.COM msg="${msg/~(Eli)(:${_.nick})*:[[:space:]]*/}" 3418462SApril.Chin@Sun.COM 3428462SApril.Chin@Sun.COM printf "botmsg=%q\n" "$msg" 3438462SApril.Chin@Sun.COM 3448462SApril.Chin@Sun.COM case "$msg" in 3458462SApril.Chin@Sun.COM ~(Eli)date) 34610898Sroland.mainz@nrubsig.org _.send_privmsg "$msgchannel" "${ 34710898Sroland.mainz@nrubsig.org printf "%(%Y-%m-%d, %Th/%Z)T\n" 34810898Sroland.mainz@nrubsig.org }" 3498462SApril.Chin@Sun.COM ;; 3508462SApril.Chin@Sun.COM ~(Eli)echo) 3518462SApril.Chin@Sun.COM _.send_privmsg "$msgchannel" "${msg#*echo}" 3528462SApril.Chin@Sun.COM ;; 3538462SApril.Chin@Sun.COM ~(Eli)exitbot) 3548462SApril.Chin@Sun.COM typeset exitkey="$(print "$msguser" | sum -x sha1)" # this is unwise&&insecure 3558462SApril.Chin@Sun.COM if [[ "$msg" == *${exitkey}* ]] ; then 3568462SApril.Chin@Sun.COM _.running=false 3578462SApril.Chin@Sun.COM fi 3588462SApril.Chin@Sun.COM ;; 3598462SApril.Chin@Sun.COM ~(Eli)help) 36010898Sroland.mainz@nrubsig.org _.send_privmsg "$msgchannel" "${ 3618462SApril.Chin@Sun.COM printf "Hello, this is shircbot, written in ksh93 (%s). " "${.sh.version}" 3628462SApril.Chin@Sun.COM printf "Subcommands are 'say hello', 'math <math-expr>', 'stocks', 'uuid', 'date' and 'echo'." 36310898Sroland.mainz@nrubsig.org }" 3648462SApril.Chin@Sun.COM ;; 3658462SApril.Chin@Sun.COM ~(Eli)math) 3668462SApril.Chin@Sun.COM if [[ "${msg}" == ~(E)[\`\$] ]] ; then 3678462SApril.Chin@Sun.COM # "restricted" shell mode would prevent any damage but we try to be carefull... 3688462SApril.Chin@Sun.COM _.send_privmsg "$msgchannel" "Syntax error." 3698462SApril.Chin@Sun.COM else 3708462SApril.Chin@Sun.COM typeset mathexpr="${msg#*math}" 3718462SApril.Chin@Sun.COM 3728462SApril.Chin@Sun.COM printf "Calculating '%s'\n" "${mathexpr}" 37310898Sroland.mainz@nrubsig.org _.send_privmsg "$msgchannel" "${ 37410898Sroland.mainz@nrubsig.org ( printf 'export PATH=/usr/${RANDOM}/$$/${RANDOM}/foo ; set -o restricted ; printf "%%s = %%.40g\n" "%s" $(( %s ))\n' "${mathexpr}" "${mathexpr}" | source /dev/stdin 2>&1 ) 37510898Sroland.mainz@nrubsig.org }" 3768462SApril.Chin@Sun.COM fi 3778462SApril.Chin@Sun.COM ;; 3788462SApril.Chin@Sun.COM ~(Eli)say\ hello) 3798462SApril.Chin@Sun.COM _.send_privmsg "$msgchannel" "Hello, this is a bot." 3808462SApril.Chin@Sun.COM ;; 3818462SApril.Chin@Sun.COM ~(Eli)stocks) 3828462SApril.Chin@Sun.COM typeset stockmsg tickersymbol 38310898Sroland.mainz@nrubsig.org for tickersymbol in "JAVA" "ORCL" "IBM" "AAPL" "HPQ" ; do 3848462SApril.Chin@Sun.COM stockmsg="$( /usr/sfw/bin/wget -q -O /dev/stdout "http://quote.yahoo.com/d/quotes.csv?f=sl1d1t1c1ohgv&e=.csv&s=${tickersymbol}" 2>&1 )" 3858462SApril.Chin@Sun.COM _.send_privmsg "$msgchannel" "${tickersymbol}: ${stockmsg//,/ }" 3868462SApril.Chin@Sun.COM done 3878462SApril.Chin@Sun.COM ;; 3888462SApril.Chin@Sun.COM ~(Eli)uuid) 38910898Sroland.mainz@nrubsig.org _.send_privmsg "$msgchannel" "${ 39010898Sroland.mainz@nrubsig.org print "%(%Y%M%D%S%N)T$((RANDOM))%s\n" "${msguser}" | sum -x sha256 39110898Sroland.mainz@nrubsig.org }" 3928462SApril.Chin@Sun.COM ;; 3938462SApril.Chin@Sun.COM esac 3948462SApril.Chin@Sun.COM 3958462SApril.Chin@Sun.COM return 0 3968462SApril.Chin@Sun.COM} 3978462SApril.Chin@Sun.COM 3988462SApril.Chin@Sun.COM# Automatically join the list of channels listed in |config.join_channels| 3998462SApril.Chin@Sun.COM# after the client is connected to the server for some time 4008462SApril.Chin@Sun.COMfunction mybot.mainloop_tick 4018462SApril.Chin@Sun.COM{ 4028462SApril.Chin@Sun.COM integer -S autojoin_done=2 4038462SApril.Chin@Sun.COM integer i 4048462SApril.Chin@Sun.COM 4058462SApril.Chin@Sun.COM if (( autojoin_done-- == 0 && ${#config.join_channels[@]} > 0 )) ; then 4068462SApril.Chin@Sun.COM print "# Autojoin channels..." 4078462SApril.Chin@Sun.COM 4088462SApril.Chin@Sun.COM for ((i=0 ; i < ${#config.join_channels[@]} ; i++ )) ; do 4098462SApril.Chin@Sun.COM mybot.join_channel "${config.join_channels[i]}" 4108462SApril.Chin@Sun.COM done 4118462SApril.Chin@Sun.COM fi 4128462SApril.Chin@Sun.COM 4138462SApril.Chin@Sun.COM return 0 4148462SApril.Chin@Sun.COM} 4158462SApril.Chin@Sun.COM 4168462SApril.Chin@Sun.COMmybot.createsession "${config.servername}" ${config.port} "${config.nickname}" 4178462SApril.Chin@Sun.COM 4188462SApril.Chin@Sun.COM# This is a network-facing application - once we've set eveything up 4198462SApril.Chin@Sun.COM# we set PATH to a random value and switch to the shell's restricted 4208462SApril.Chin@Sun.COM# mode to make sure noone can escape the jail. 4218462SApril.Chin@Sun.COM#export PATH=/usr/$RANDOM/foo 4228462SApril.Chin@Sun.COM#set -o restricted 4238462SApril.Chin@Sun.COM 4248462SApril.Chin@Sun.COMmybot.mainloop 4258462SApril.Chin@Sun.COM 4268462SApril.Chin@Sun.COMprint "## End." 4278462SApril.Chin@Sun.COM 4288462SApril.Chin@Sun.COMexit 0 429