7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#!/usr/bin/ksh93
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# CDDL HEADER START
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#
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#
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# or http://www.opensolaris.org/os/licensing.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# See the License for the specific language governing permissions
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# and limitations under the License.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#
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#
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# CDDL HEADER END
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# shircbot - a simple IRC client/bot demo
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
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
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 Chinif [[ "${LC_ALL}" != "" ]] ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin export \
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin LC_MONETARY="${LC_ALL}" \
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin LC_MESSAGES="${LC_ALL}" \
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin LC_COLLATE="${LC_ALL}" \
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin LC_CTYPE="${LC_ALL}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin unset LC_ALL
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinfi
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinexport LC_NUMERIC=C
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinfunction fatal_error
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin{
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin print -u2 "${progname}: $*"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin exit 1
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# Definition for a IRC session class
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chintypeset -T ircsession_t=(
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz compound server=(
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset name
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin integer port
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset nick="ksh93irc"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset running=true
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin integer fd=-1
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function createsession
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin set -o xtrace
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.server.name=$1
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.server.port=$2
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.nick=$3
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz redirect {_.fd}<> "/dev/tcp/${_.server.name}/${_.server.port}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin (( $? == 0 )) || { print -n2 $"Could not open server connection." ; return 1 ; }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "fd=%d\n" _.fd
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function login
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "USER %s %s %s %s\n" "${_.nick}" "${_.nick}" "${_.nick}" "${_.nick}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "NICK %s\n" "${_.nick}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin } >&${_.fd}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function join_channel
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "JOIN %s\n" "$1" >&${_.fd}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function mainloop
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset line
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin float -S last_tick=0
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 # async I/O normally used by IRC clients
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin linebuf_t serverbuf
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin linebuf_t clientbuf
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin integer fd=${_.fd}
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.login
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while ${_.running} ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while serverbuf.readbuf line <&${fd} ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.dispatch_serverevent "$line"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin done
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while clientbuf.readbuf line </dev/stdin ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "client: %q\n" "${line}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "%s\n" "${line}" >&${fd}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin done
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # call mainloop_tick function in intervals to handle
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # async events (e.g. automatic /join etc.)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if (( (SECONDS-last_tick) > 5. )) ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin (( last_tick=SECONDS ))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.mainloop_tick
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fi
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin done
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function mainloop_tick
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function dispatch_serverevent
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset line="$1"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin case "${line}" in
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(El)PING)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz compound ping_args=(
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin line="$line"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.serverevent_ping "ping_args"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(El):.*\ PRIVMSG)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz compound privmsg_args=(
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset line="$line"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msguser="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\1}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msgchannel="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\3}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msg="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\4}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.serverevent_privmsg "privmsg_args"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(El):.*\ INVITE)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz compound invite_args=(
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset line="$line"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset inviteuser="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\1}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset invitenick="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\3}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset invitechannel="${line/~(Elr)([^ ]+) ([^ ]+) ([^ ]+) (.*)/\4}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.serverevent_invite "invite_args"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin *)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "server: %q\n" "${line}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin esac
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function serverevent_privmsg
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin nameref args=$1
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msguser="${args.msguser}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msgchannel="${args.msgchannel}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msg="${args.msg}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "#privms: user=%q, channel=%q, msg=%q\n" "$msguser" "$msgchannel" "$msg"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function serverevent_invite
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin nameref args=$1
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "JOIN %s\n" "${args.invitechannel/:/}" >&${_.fd}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function send_privmsg
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset channel="$1"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msg="$2"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # Do we have to escape any characters in "msg" ?
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "PRIVMSG %s :%s\n" "${channel}" "${msg}" >&${_.fd}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function serverevent_ping
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin nameref args=$1
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "PONG %s\n" "${args.line/~(Elr)([^ ]+) ([^ ]+).*/\2}" >&${_.fd}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
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 Chintypeset -T linebuf_t=(
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset buf
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function reset
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.buf=""
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin function readbuf
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin nameref var=$1
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset ch
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin while IFS='' read -t 0.2 -N 1 ch ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin [[ "$ch" == $'\r' ]] && continue
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if [[ "$ch" == $'\n' ]] ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin var="${_.buf}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.reset
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fi
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.buf+="$ch"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin done
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 1
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinfunction usage
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin{
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin OPTIND=0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin getopts -a "${progname}" "${shircbot_usage}" OPT '-?'
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin exit 2
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# program start
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# (be carefull with builtins here - they are unconditionally available
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# in the shell's "restricted" mode)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinbuiltin basename
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinbuiltin sum
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chintypeset progname="${ basename "${0}" ; }"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chintypeset -r shircbot_usage=$'+
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'
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainzcompound config=(
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset nickname="${LOGNAME}bot"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset servername="irc.freenode.net"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin integer port=6667
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset -a join_channels
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinwhile getopts -a "${progname}" "${shircbot_usage}" OPT ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin case ${OPT} in
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin n) config.nickname="${OPTARG}" ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin s) config.servername="${OPTARG}" ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin j) config.join_channels+=( "${OPTARG}" ) ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin *) usage ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin esac
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chindone
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinshift $((OPTIND-1))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# if no channel was provided we join a predefined set of channels
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinif (( ${#config.join_channels[@]} == 0 )) ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if [[ "${config.servername}" == "irc.freenode.net" ]] ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin config.join_channels+=( "#opensolaris" )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin config.join_channels+=( "#opensolaris-dev" )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin config.join_channels+=( "#opensolaris-arc" )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz config.join_channels+=( "#opensolaris-meeting" )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz config.join_channels+=( "#ospkg" )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin config.join_channels+=( "#ksh" )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin elif [[ "${config.servername}" == ~(E)irc.(sfbay|sweden) ]] ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin config.join_channels+=( "#onnv" )
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fi
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinfi
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinprint "## Start."
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinircsession_t mybot
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# override ircsession_t::serverevent_privmsg with a new method for our bot
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinfunction mybot.serverevent_privmsg
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin{
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin nameref args=$1
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msguser="${args.msguser}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msgchannel="${args.msgchannel}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset msg="${args.msg}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "#message: user=%q, channel=%q, msg=%q\n" "$msguser" "$msgchannel" "$msg"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # Check if we get a private message
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if [[ "${msgchannel}" == "${_.nick}" ]] ; then
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 # it into msgchannel
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin msgchannel="${msguser/~(El):(.*)!.*/\1}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin else
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # check if this is a command for this bot
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin [[ "$msg" != ~(Eli):${_.nick}:[[:space:]] ]] && return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fi
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # strip beginning (e.g. ":<nick>:" or ":") plus extra spaces
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin msg="${msg/~(Eli)(:${_.nick})*:[[:space:]]*/}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "botmsg=%q\n" "$msg"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin case "$msg" in
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(Eli)date)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz _.send_privmsg "$msgchannel" "${
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz printf "%(%Y-%m-%d, %Th/%Z)T\n"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(Eli)echo)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.send_privmsg "$msgchannel" "${msg#*echo}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(Eli)exitbot)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset exitkey="$(print "$msguser" | sum -x sha1)" # this is unwise&&insecure
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if [[ "$msg" == *${exitkey}* ]] ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.running=false
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fi
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(Eli)help)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz _.send_privmsg "$msgchannel" "${
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'."
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(Eli)math)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if [[ "${msg}" == ~(E)[\`\$] ]] ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin # "restricted" shell mode would prevent any damage but we try to be carefull...
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.send_privmsg "$msgchannel" "Syntax error."
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin else
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset mathexpr="${msg#*math}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin printf "Calculating '%s'\n" "${mathexpr}"
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz _.send_privmsg "$msgchannel" "${
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 )
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fi
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(Eli)say\ hello)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin _.send_privmsg "$msgchannel" "Hello, this is a bot."
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(Eli)stocks)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin typeset stockmsg tickersymbol
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//,/ }"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin done
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ~(Eli)uuid)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz _.send_privmsg "$msgchannel" "${
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz print "%(%Y%M%D%S%N)T$((RANDOM))%s\n" "${msguser}" | sum -x sha256
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz }"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin ;;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin esac
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
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 Chinfunction mybot.mainloop_tick
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin{
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin integer -S autojoin_done=2
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin integer i
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if (( autojoin_done-- == 0 && ${#config.join_channels[@]} > 0 )) ; then
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin print "# Autojoin channels..."
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin for ((i=0 ; i < ${#config.join_channels[@]} ; i++ )) ; do
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin mybot.join_channel "${config.join_channels[i]}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin done
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fi
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return 0
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinmybot.createsession "${config.servername}" ${config.port} "${config.nickname}"
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
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
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinmybot.mainloop
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinprint "## End."
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinexit 0