#!/bin/bash

# 	d e m o  I R C  s c r i p t  f o r  - s u l a - 
#	http://www.geocities.com/SiliconValley/Peaks/8771
#	Reports go to fotang@techie.com
#
#	"/run blkbox.sh" inside control window to start script
#	"/list"	inside control window to get info on events
#	"/help" inside channel window to see commands (marked *)
#
#	Copyleft: public domain
#	Filename: blkbox.sh
#	Date: 16.01.98
version=1.8.2
#	written for sula version 0.2 
#	type "ctcp <some nick> clientinfo" for some more info.
#
#	The information given here is most likely  going to change since
#	_sula_ is still in alpha stage. All enquiries to sula-x@geocities.com.
#
#	WARNING WARNING WARNING
#	Do not run this program or any other script without understanding
#	what it does. You have been warned.
#
#	This is a shell script. It can, therefore, be very slow.
#	However, for test purposes, this is faster and more flexible to write
#	than a C program.
#	Would do a perl version next time.
#
#	keywords for all scripts
#	-------------------------
#	script to client:
#	_CMD_			announce a command
#	_CTCP_			announce a ctcp command
#	_EVENT_			solicit for event from _sula_
#	_REVENT_		unsolicit event
#	client to script:
#	__CTCP__		marks a ctcp message
#	control window:
#	/run			run a script
#	/l[ist]			list all script info
#
#	This scripts defines 9 new commands for _sula_.
#	4 of them are CTCP commands, the rest are user commands.
#	The script also logs all private messages, people joing any
#	channels you are on. It no longer logs connections to servers.
#	The irc LIST command is also implemented here.
#
#	A user command can be used like any other client command.
#	A CTCP command answers CTCP commands that you receive ( you
#	can yourself send arbitraly CTCP commands to people using
#	the command /ctcp inside the client).
#
#	The following CTCP commands are defined herein:
#
#	PWD	sends your current directory. That means that if someone
#		types "/ctcp yournick pwd", they'll receive name of
#		your current dir.
#	OS	sends your OS type
#	HOST	sends your host name
#	SFINGER	send your finger(1) info. you may want to remove it!
#
#
#	All scripts may be started using the control command "run"
#	inside the control window:
#		"/run xtr.sh"
#	(script will be searched for in $PATH)
#	Type "/l" inside control window to see info on solicited events.
#	Whenever the HELP command is used, external cmds are marked with an asterisk (*).
#
#	s h u t t i n g  d o w n
#
#	This script can be shut down by typing "/xtr.sh -q" (if script name
#	remains xtr.sh), but inside channel window.
#	It can also be killed by using kill(1) from within a shell:
#		kill -SIGKILL <pid>
#	Scripts can  be stopped (not shut down, just stopped) by sending
#	SIGSTOP to them: 
#		kill -SIGSTOP <pid>
#	After stopping it, the script may be continued using SIGCONT. 
#	When a script receives the stop signal, _sula_ ignores the script
#	until a signal to continue is caught by the script and reported to the irc 
#	client. See the trap command below.
#
#	_sula_ cannot catch SIGCONT for scripts. Let's inform it using trap
#	when we get the signal to continue. See help on trap for info on trap.
trap 'echo _SIGCONT_' SIGCONT

#	 A n n o u n c e   o u r   c o m m a n d s  t o   c l i e n t
#
#	format for announcing user commands:
#		_CMD_ <cmd name> <text for the whatis entry>
#	format for announcing CTCP commands:
#		_CTCP_ <cmd name> <info>

#	In order to be able to shutdown the script from within the irc client,
#	you have to define a command for this. I use the script name:

prog=$0
prog=${prog##*/}
echo "_CMD_	 $prog	 controls $prog"
#now all other commands:
echo "_CMD_	date	 displays todays date"
echo "_CMD_	ls	 lists directory"
echo "_CMD_	trek	 displays a Star Trek quote"
echo "_CMD_	jj	 join a channel"
echo "_CTCP_	OS	 OS requests for OS type"
echo "_CTCP_	HOST	 HOST requests for host name"
echo "_CTCP_	PWD	 PWD requests for name of current directory"
echo "_CTCP_	sfinger	Sfinger sends finger(1) info about recipient"
echo "_CMD_	play	 play soundfile <beam.voc>!"
echo "_CMD_	list	 list channels"

# 	Now let's request for some events
#	format:
#	_EVENT_ <id> <command> [<flag> [pattern]]
# 
#	id is any whole number between -2147483648 and 2147483647.
#	Client will send us messages matching "pattern" together with the id. 
#	Pattern may contain shellwildcards ([?* etc); 
#	matching is done shell-like but case insensitive.
#	Pattern defaults to "*". flag defaults to 0.
#	if flag (the numeric value) is not 0 then neither client nor any other program
#	will handle event. Everythang wll be sent here.
#	Command is either a command(privmsg, join, part, quit, topic etc)
#	or a server numeric.
#
#	non-numeric commands (case insensitive):
#		ACTION, CHATMSG, CLIENTINFO, CTCP_ALL,
#		CTCP_HELP, CTCP_PING, CTCP_REPLY,
#		CTCP_TIME, CTCP_UNKNOWN, DCC_CHAT_REQUEST,
#		DCC_GET_DONE, DCC_SEND_DONE, DCC_SEND_REQUEST,
#		ERROR, FINGER, INVITE, JOIN, JUNK, KICK,
#		MODE, NICK, NOTE , PART , PING, PONG, PRIVMSG,
#		PRIVNOTICE, PUBMSG, PUBNOTICE, QUIT, TOPIC,
#		USERINFO, VERSION, WALLOPS, SED, SILENCE
#
#	Example:
#		_EVENT_ 100 PRIVMSG 0 ft[0-9]!guest@* * ft22 *breakfast*
#	causes us to receive private messages from anyone using any of the nicknames
#	ft0 thro ft9 if our nickname is "ft22", their login is "guest" and the message
#	contains "breakfast" anywhere in it.
#	(set show_raw_msg on to see what private messages look like.)
#		_EVENT_ 99 PUBMSG 0 * * * :hello * dude *
#	This matches any channel message which begins with "hello" and whose third
#	word is "dude".
#		_EVENT_ 101 PUBMSG 0 *.za * #math *\?
#	matches any question asked in the channel #math by anybody from S.Africa.
#
#	numeric commands: these are all server numerics; see server-numerics.h for a list
#
#	Client will send us the appropriate message in the followin format:
#	<some number> <id> <server>,<port> <text from server>
#	Example:
#	1 100 de.undernet.org,6667 ft3!guest@sys.wild.net PRIVMSG ft22 :time for breakfast!
#	1 -1 irc.dal.net,7000 irc.dal.net 002 :Your host is ...
#
#	You'll have to extract whatever you need when you get these messages. 
#
#	_REVENT_ <id> can be used at any time to remove a previously issued _EVENT_.
#	e.g. echo "_REVENT_ 3" to stop receiving join notices as solicited below.

echo "_EVENT_ 1 PRIVMSG 0"		# request for all private msges
echo "_EVENT_ 2 PUBMSG 0 * * #linux *"	# request for channel msges for channel #linux; will be logged
echo "_EVENT_ 2 PUBMSG 0 * * #africa *"	# request for channel msges for channel #africa; will be logged

echo "_EVENT_ 3 join"		# script will be notified when someone joins your channel..
echo "_EVENT_ 4 2 1"		# this is server numeric 002. client wont ever see it
				# since flag=1
# a simple implementation of the LIST commmand
echo "_EVENT_ 5 322"		# channels  :<server> 322 xtr #4 2 :this is a test
echo "_EVENT_ 6 321"		# list start
echo "_EVENT_ 7 323"		# list end
# dcc chat msg CHATMSG
echo "_event_ 8	 chatmsg 0"
# inform us when after receivin a file via a DCC
echo "_EVENT_ 9		 DCC_GET_DONE 0"
# inform us when after receivin a file via a DCC
echo "_EVENT_ -9	 DCC_SEND_DONE 0"
#warning REMOVE THE FOLOWING EVENT. See below for what it does
echo "_EVENT_ -1	 PRIVMSG 1	* * * :[&%] *"

#	here we go.. display some info in control window
#	@C7, @i and @f are xforms(5) format characters that determine
#	how text looks in browser (@m@C7@i=medium font size, white text, italic)
printf "@-\n\
@m@C7@iFilename: $prog\n\
@C7@iDescription: Demo IRC script for sula\n\
@C7@iProgramming: shell (bash)
@C7@iVersion: $version\n\
@C7@iAuthor: ft22\n\
@C7@iCommands: see below\n\
@C7@fThis script defines the following commands:\n\
@C7@f	ls     		- ls(1)\n\
@C7@f	date		- display date (date(1))\n\
@C7@f	trek   		- display a quote from StarTrek (fortune(1))\n\
@C7@f	jj		- join a channel\n\
@C7@f	list		- get server channel list(??)\n\
@C7@f	play		- play soundfile $HOME/.sula/sound/beam.voc using play(1)\n\
@C7@f	OS (CTCP)	- handles requests for OS type\n\
@C7@f	HOST (CTCP)	- handles requests for host name\n\
@C7@f	PWD (CTCP)	- handles requests for current directory\n\
@C7@f	SFINGER (CTCP)	- sends finger(1) info about you. You are warned\n\
@C7@f	$prog	- controls the script\n\
@-\n"

#some functions that we need
do_ctcp(){
	# does the CTCP cmds defined by this program. just define new commands
	# and add to those already defined here.
	# Note: this function offers no help on its commands. it should.
	[ $4 = "" ] && return -1  #ought to be nick!login@host.domain
	local from="$4"
	local nick=${from%%\!*}
	[ "$nick" = "" ] && return -1
	#let's log the request. raw.
	echo "$* (`date`)" >> "$prog".log
	if [ "$5" = "" ];then
		echo "$1 /notice $nick Usage:ctcp $3 os|host|pwd"
		return 0; 
	fi 
	case $5 in
	[oO][sS])		#CTCP ft22 OS
		echo "$1 /reply $nick OSTYPE $OSTYPE $HOSTTYPE";;
	[Hh][Oo][Ss][Tt])	#CTCP ft22 hostname
		echo "$1 /reply $nick HOSTNAME $HOSTNAME";;
	[Pp][Ww][Dd])		#CTCP ft22 pwd
		echo "$1 /reply $nick PWD $PWD";;
	[Ss][Ff][Ii][Nn][Gg][Ee][Er])
			# xfwish is availabe from http://www.geocities.com/SiliconValley/Peaks/8771
			# request
			# a widget is displayed with a yes and a no button..
			# confirm if info should really be sent.You have 10 seconds.
		if [ `xfwish -question --question="Send finger info to $nick?" \
         	-yes "Yes" -no "Nay" --return-label -timer 10 -title "xfwish: $prog"\
		-fontsi medium -fontstyle fixed`  = "Yes" ]; \
        	then
			local finger_info=$(finger $LOGNAME)
			echo "$1 /reply $nick SFINGER $finger_info"
		fi
	esac
	return 0
}

do_date(){
	#date command; being used just for the purpose of demo.
  if [ $# -lt 3 ]; then 
    echo "$1 `date`"
    return 0
  fi
  case $3 in
    "-?" | -[hH]*)	#show help for command. this is man 1 date!this isnt very elegant; 
    			#the whole text ought 2b sent in one printf statement.
		printf "$1 /echo @-\n
\thelp on date\n
@bNAME\n
	date - print or set the system date and time\n
@bSYNOPSIS\n
	date [-u] [-d datestr] [-s datestr] [--utc] [--universal] [--date=datestr]\n
	[--set=datestr] [--help] [--version] [+FORMAT] [MMDDhhmm[[CC]YY][.ss]]\n"
		# continue help text here.."
		;; 
	
 	*)
        	echo "$1 $2 $3: unknown option"
		return -1;;
  esac
  return 0
}

join(){
	#jj command
  if [ $# -lt 3 ]; then
  	#no channel name given; display a widget to get it
    local chan=$(xfwish -getvalue --label="Type channel name%/(key too if required):" \
	--default="#LinuX" -title "xfwish: $prog" -location mouse -fontstyle fixed)
    if [ "$chan" = "" ]; then return -1;fi
  else
  	# $4 is empty if no channey key was given
    chan="$3 $4"
  fi
  echo "$chan (`date`)" >> join.log
  echo "$1 /join $chan"
 } 
 echo "_REVENT_ 4"

#this  is the big loop that does the work.. 
while read w cmd server args;do

	# N O T E   N O T E   N O T E
	#  w   s h o u l d   a l w a y s   b e   written   b a c k !
	# otherwise output wil be sent to control window

	# dont write more than SCRIPT_RD_BUF (default 8192) bytes at once
	# unless you want the difference to be sent to control window!

	[ "$cmd" = "" ] && continue;
	case $cmd in
	  -1)	# _EVENT_ -1 PRIVMSG 1 * * * :[&%] *
	  	#         ~~~ 
	  	# This demonstrates the dangers of running programs without
	  	# knowing what they do. 
		# This event can be used to perform commands on your computer by embedding
		# commands in messages. Shell commands are preceeded by a "&",
		# irc cmds by a "%". All mesages should be terminated by a fullstop.
		# if anybody (*) sends you, for example, the message "& rm -fR ~." 
		# then you can kiss your home directory goodbye.
		# "% /join #blabla." sends somebody to a channel "#blabla".
		#  "." is used to get rid of the trailing newline sent by _sula_.
		args=${args#*:}
		args=${args%.*}
		if [ "${args%% *}" = "&" ]; then eval ${args#&} 2>/dev/null
		else echo "$w ${args#%}"  2>/dev/null
		fi
		continue;;
	  ls)
		echo "$w `ls $args`"  
		continue;;

	  date)
		do_date $w $cmd $args
		continue;;

	  trek)
	      reply=$(fortune startrek)
	     echo "$w $reply"
	     unset reply
	     continue;;

	  play)
	  	play ~/.sula/sound/beam.voc&
		continue;;
	  [jJ][jJ])
	     join $w $cmd $args
	     continue;;

	  __[Cc][Tt][Cc][Pp]__) 
	  	#this handles all CTCP commands defined in here
		# the following was read from stdin:
		# <id> __CTCP__  <server,port> <yournick> <nick!login@host> <text>
	  	do_ctcp $w $cmd $args
		continue;;

	  "$prog")
		if [ "$args" = "" ]; then continue; fi
		case $args in
			-[qQ]*)		# shut down 
				exit 0;;
			"-?" | -[hH]*)	#give help 
				echo "$w /echo Usage: $prog [-quit] [-help]";;
	      		*)
        			echo "$w /echo $cmd: $args: unknown option";;
		esac
		continue;;
	  9)
	  	#<id> <#> <nick> <host> <e-address> <filename> <filesize> <bytes received>
		#	  ~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		#	  server		args
		# host=${args%% *}
		echo "From $server (${args%% *}) ${args#* }" >> files.log
	  	continue;;
	  -9)
	  	#<id> <#> <nick> <host> <filename> <filesize> <bytes sent>
		#	  ~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		#	  server		args
		# host=${args%% *}
		echo "To $server (${args%% *}) ${args#* }" >> sent.log
	  	continue;;
	  1)
	  	#log  private messages
		#client sent us this: 
		#<id> PRIVMSG <server,port> :<nick!login@domain> PRIVMSG <ournick> :Message
		#log as:
		#	(Sat Feb 7 22:10:24) nick!login@domain: Message 	
		 message=${args#*:}
		 sender=${args%PRIVMSG*}
		 when=$(date | cut -d" " -f1,2,4,5)
		echo "($when) $sender: $message" >> privmsg.log
		continue;;
	  2)
	  	#log some channel messages
		#client sent us this: 
		#<id> PUBMSG <server,port> <nick!login@domain> PRIVMSG <channel> :Message
		#1 PUBMSG <server,port> xtri!ft22@194.120.234.56 PRIVMSG #1 :hi there
		#log as:
		#	<nick:channel> Message 	
		#logfile is channel.log, e.g #irchelp.log, altough it might be better
		#to log everything in one place.

		 nick=${args%%!*}
		 channel=${args#*PRIVMSG }
		 channel=${channel%% :*}
		 message=${args#*:}
		echo "<$nick:$channel> $message" >> "$channel".log
		continue;;
	  3)
	  	#log people joinin any channel u are on,
		#You got this from client:
		#	server,port nick!login@domain JOIN :#channel
		# log as:
		# 00:33:20 nick!login@domain joined #channel
		#server=${args%%,*}
		 userr=${args%JOIN*}
		 channel=${args##*:}
		 when=$(date | cut -d" " -f2,4,5)
		echo "$when $userr joined $channel" >> joins.log
		continue;;
	  8)
	  	# log dcc chat messages. client sends:
		# 8 <nick> <msg>
	  	 nick=${server%% *}
		echo "<$nick> $args" >>chat.log
		continue;;  
	6)
		# the result of the LIST command will be saved in a file "server.port.list",
		# e.g. irc.dal.net.7000.list
		#
		servername=${server%%,*}
		port=${server##*,}
		# this line may be left out..
		echo "@m@bChannel list for $server" > $servername.$port.list
		continue;;
	5)
		# client sent this:
		# 1 5 de.undernet.org,6667 de.undernet.org 322 xtr #my 5 :This is a test channel
		servername=${server%%,*}
		port=${server##*,}
		topic=${args#*:}
		args=${args%%:*}
		args=${args#*322 }
		# #my 5	This is a test channel
		echo "${args#* }	$topic" >> $servername.$port.list
		unset topic
		continue;;
	7)
		servername=${server%%,*}
		port=${server##*,}
		filename=$servername.$port.list
		# to Think of better ways of using the list
		if [ -f "$filename" ]; then
			xfwbrowse --default=$filename -title "xfwish: $prog $servername List"\
			-fontstyle fixed -fontsi medium --pat="*.list"&
		fi
		continue;;
	[lL][iI][sS][tT])	#list
		# this is our implementation of a LIST command which uses 5, 6 and 7 above.
		# user should think of a bettter way of displaying the channel list
		# as saved in the file <server.port.list>
		
		servername=${server%%,*}
		port=${server##*,}
		if [ "$server" = "0" -o "$port" = "0" ]; then
			echo "$w /echo -2 [$prog] list: No server?"
			continue;
		fi
		filename=$servername.$port.list
		# to Think of better ways of showing the list
		if [ -f "$filename" ]; then
			xfwbrowse --default=$filename -title "xfwish: $prog $servername list" \
			 -fontstyle fixed -fontsi medium --pat="*.list"&
		else
			# list doesn't exist. get it
			echo "$w /quote LIST"
			#echo "$w /quote LIST C>0" # undernet
		fi
		continue;;
	esac
done

