shircbot.sh revision 34f9b3eef6fdadbda0a846aa4d68691ac40eace5
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# CDDL HEADER START
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# The contents of this file are subject to the terms of the
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Common Development and Distribution License (the "License").
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# You may not use this file except in compliance with the License.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# See the License for the specific language governing permissions
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# and limitations under the License.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# When distributing Covered Code, include this CDDL HEADER in each
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# If applicable, add the following below this CDDL HEADER, with the
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# fields enclosed by brackets "[]" replaced with your own identifying
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# information: Portions Copyright [yyyy] [name of copyright owner]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# CDDL HEADER END
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Use is subject to license terms.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# shircbot - a simple IRC client/bot demo
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Make sure all math stuff runs in the "C" locale to avoid problems
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# with alternative # radix point representations (e.g. ',' instead of
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# '.' in de_DE.*-locales). This needs to be set _before_ any
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# floating-point constants are defined in this script).
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Definition for a IRC session class
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz redirect {_.fd}<> "/dev/tcp/${_.server.name}/${_.server.port}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin (( $? == 0 )) || { print -n2 $"Could not open server connection." ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function login
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "USER %s %s %s %s\n" "${_.nick}" "${_.nick}" "${_.nick}" "${_.nick}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # We use the linebuf_t class here since network traffic
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # isn't guranteed to fit a single $'\n'-terminated line
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # into one TCP package. linebuf_t buffers characters
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # until it has one complete line. This avoids the need for
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while ${_.running} ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while serverbuf.readbuf line <&${fd} ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # call mainloop_tick function in intervals to handle
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msguser="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\1}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msgchannel="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\3}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msg="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\4}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset inviteuser="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\1}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset invitenick="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\3}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset invitechannel="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\4}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "#privms: user=%q, channel=%q, msg=%q\n" "$msguser" "$msgchannel" "$msg"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "JOIN %s\n" "${args.invitechannel/:/}" >&${_.fd}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "PRIVMSG %s :%s\n" "${channel}" "${msg}" >&${_.fd}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "PONG %s\n" "${args.line/~(Elr)([^ ]+) ([^ ]+).*/\2}" >&${_.fd}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# line buffer class
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# The buffer class tries to read characters from the given <fd> until
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# it has read a whole line.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin getopts -a "${progname}" "${shircbot_usage}" OPT '-?'
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# program start
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# (be carefull with builtins here - they are unconditionally available
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# in the shell's "restricted" mode)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz[-?\n@(#)\$Id: shircbot (Roland Mainz) 2009-09-09 \$\n]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[-author?Roland Mainz <roland.mainz@sun.com>]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[-author?Roland Mainz <roland.mainz@nrubsig.org>]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[+NAME?shircbot - simple IRC bot demo]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[+DESCRIPTION?\bshircbot\b is a small demo IRC bot which provides
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin a simple IRC bot with several subcommands.]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[n:nickname?IRC nickname for this bot.]:[nick]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[s:ircserver?IRC servername.]:[servername]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[j:joinchannel?IRC servername.]:[channelname]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin[+SEE ALSO?\bksh93\b(1)]
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin integer port=6667
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinwhile getopts -a "${progname}" "${shircbot_usage}" OPT ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# if no channel was provided we join a predefined set of channels
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if [[ "${config.servername}" == "irc.freenode.net" ]] ; then
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz config.join_channels+=( "#opensolaris-meeting" )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin elif [[ "${config.servername}" == ~(E)irc.(sfbay|sweden) ]] ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# override ircsession_t::serverevent_privmsg with a new method for our bot
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "#message: user=%q, channel=%q, msg=%q\n" "$msguser" "$msgchannel" "$msg"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # ${msgchannel} point to our own nick if we got a private message,
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # we need to extract the sender's nickname from ${msguser} and put
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin [[ "$msg" != ~(Eli):${_.nick}:[[:space:]] ]] && return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # strip beginning (e.g. ":<nick>:" or ":") plus extra spaces
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset exitkey="$(print "$msguser" | sum -x sha1)" # this is unwise&&insecure
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "Hello, this is shircbot, written in ksh93 (%s). " "${.sh.version}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "Subcommands are 'say hello', 'math <math-expr>', 'stocks', 'uuid', 'date' and 'echo'."
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # "restricted" shell mode would prevent any damage but we try to be carefull...
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz ( printf 'export PATH=/usr/${RANDOM}/$$/${RANDOM}/foo ; set -o restricted ; printf "%%s = %%.40g\n" "%s" $(( %s ))\n' "${mathexpr}" "${mathexpr}" | source /dev/stdin 2>&1 )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.send_privmsg "$msgchannel" "Hello, this is a bot."
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz for tickersymbol in "JAVA" "ORCL" "IBM" "AAPL" "HPQ" ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin stockmsg="$( /usr/sfw/bin/wget -q -O /dev/stdout "http://quote.yahoo.com/d/quotes.csv?f=sl1d1t1c1ohgv&e=.csv&s=${tickersymbol}" 2>&1 )"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.send_privmsg "$msgchannel" "${tickersymbol}: ${stockmsg//,/ }"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print "%(%Y%M%D%S%N)T$((RANDOM))%s\n" "${msguser}" | sum -x sha256
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Automatically join the list of channels listed in |config.join_channels|
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# after the client is connected to the server for some time
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if (( autojoin_done-- == 0 && ${#config.join_channels[@]} > 0 )) ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin for ((i=0 ; i < ${#config.join_channels[@]} ; i++ )) ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinmybot.createsession "${config.servername}" ${config.port} "${config.nickname}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# This is a network-facing application - once we've set eveything up
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# we set PATH to a random value and switch to the shell's restricted
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# mode to make sure noone can escape the jail.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#export PATH=/usr/$RANDOM/foo
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#set -o restricted