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