#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README pec
# Wrapped by tetherow@cse on Tue May 10 23:12:55 1994
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(4416 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis is the Perl Empire Client.
X
XHISTORY:
X  This client was originally written by Sean Eddy(sre@mrc-lmb.cam.ac.uk), aka
Xthe Elven King of Mirkwood, as a quick hack for those occassions when you don't
Xhave empclient/eif.  It was then hacked by Michael Feuell
X(elf@twain.ucs.umass.edu), aka the elf of Krikkit, to add in the ability to kill
Xa hung session (or your co-ruler when he won't let you on to read those witty
XMurk-o-Vision updates.)  At this point I picked up the code thinking it would
Xbe great to have a portable and small client (and it would give me an chance to
Xlearn perl.
X
XREQUIREMENTS:
X  Perl 4.016 or greater (I hope) with getopts.pl and fcntl.ph.  If you don't
Xhave any of these hound your sysadmin, they're free.
X
XINVOCATION:
X  The Perl Empire Client can be invoked in several ways.  If you run it with 
Xno command line arguments it will prompt you for the needed information.  If you
Xhave the environment variables, EMPIREHOST EMPIREPORT COUNTRY and PLAYER, set
Xthen it will use these values.  You can also use the command line switches,
X-h {host} -p {port} {country player} to give the client the proper information.
XOr you can use the -g {game} switch to get the information from the .pecrc file.
X  You may also specify the -k switch which will log onto the server and kill the
Xcurrent session.
X
X.pecrc FILE:
X  The pecrc file should be located in your home directory.  It contains game
Xinformation and some default commands that will be executed once you are 
Xconnected to the server.  The file format is:
X
Xgame EMPIREHOST EMPIREPORT COUNTRY PLAYER
X
XThe default commands are on lines that begin with a tab character.  If the
Xline appears before any game declarations then it is performed for every
Xconnection.  If the line appears after a game declaration than it only pertains
Xto the game immediately above it.  This is useful for alias and getting initial
Xinfo when you connect.
X
XPIPING and REDIRECTION:
X  The Perl Empire Client allows full piping and output redirection.  You can
Xredirect the output from a command to a file with the > and >> characters.  You
Xcan redierect a file to the server with the < character.  And you can pipe the
Xoutput of a command to some other command with the | character.  The output of
Xa command is anything that is sent to the client from the server after the
Xcommand has been issued, upto, but not including the command prompt.
X  While not actually being a function of piping, I have added in the idea of
Xsecondary commands from eif.  Any line that begins with an & will only be sent
Xto the server if at a secondary prompt (ie a prompt for more information from
Xthe player)  This should help in the writting of scripts.
X
XHISTORY FUNCTION:
X  The Perl Empire Client supplies a rudimentary history package which will keep
Xtrack of the last 20 commands entered by the user.  These commands can be
Xaccessed via !{text}.  `!' by itself will reissue the last command entered, if
X{text} is supplied, without the curly brackets, the client will reissue the last
Xcommand that began with {text}.  You can get a full list of the history stack
Xwith the `hist' command.
X
XALIASES:
X  The Perl Empire Client also supplies a simple aliasing package.  To create an
Xalias use the alias command:
X  alias value replacement arguments
Xvalue is the word you want to alias, replacement is the word you want to replace
Xit with, and arguments, optional, are the words from the original command you
Xwant to use.  ex:
X  alias mpa map $1
X  mpa #1				// Will send map #1
X  mpa #1 ?type=)			// Will still only send map #1
XIf you give no arguments only the value will be replaced with the replacement
Xand the rest of the command line will stay the same.  You can get a full list
Xof all defined alias by entering alias with no arguments.  You can remove an
Xalias with the unalias command.
X
XBUGS, SUGGESTIONS, COMPLAINTS:
X  Please send me any feedback you feel would help improve this client.  I will
Xtry to fix any bugs you find, and will consider all recomendations for 
Xmodification.  I don't want this client to become a `super-client' and would
Xlike to keep the code to a minimum (I have already doubled it's size).  But if
Xyou have a suggestion I would be more than happy to consider it.  Also if you
Xmake changes to the code, please let me know what and why, I may include it in
Xthe next release.
X
X
X
XSam "Drazz'zt" Tetherow
XRuler of Khazad'ur
Xucpl079@unlvm.unl.edu
Xtetherow@cse.unl.edu
END_OF_FILE
if test 4416 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'pec' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pec'\"
else
echo shar: Extracting \"'pec'\" \(8502 characters\)
sed "s/^X//" >'pec' <<'END_OF_FILE'
X#! /usr/local/bin/perl
X#usage: pec -g <game> -h <host> -p <port> -k [<coun> <rep>]
X#
X# perl empire client
X# version 1 by Sean "Elven King" Eddy (Mirkwood)
X#   patch 1 by Michael "the Elf" Feuell (Krikkit/Carnage Deity)
X#   patch 2 by Sam "Drazz'zt" Tetherow (Khazad'ur)
X# version 2 by Sam "Drazz'zt" Tetherow (Khazad'ur)
X 
Xrequire "getopts.pl";
Xrequire "fcntl.ph";
X 
X&Getopts("g:h:p:k");
Xif ($opt_g) {
X  open(RC, "/$ENV{'HOME'}/.pecrc");
X  for(;;) {
X    $_=<RC>;
X    if (!$_) { last; }
X    if (/^\t/) { push(@inputstack, $'); }
X    else { last; }
X  } 
X  do {
X    if (/$opt_g\s+(\S+)\s+(\d+)\s+(\S+)\s+(.*)/) {
X      $opt_h=$1; $opt_p=$2; $COUNTRY=$3; $PLAYER=$4;
X      for(;;) {
X	$_=<RC>; if (!$_) { last; }
X	if (/^\t/) { push(@inputstack, $'); }
X	else { last; }
X      }
X    }
X  } until(!($_=<RC>));
X  close(RC);
X}
X
X$EMPIREHOST = ($opt_h || $ENV{'EMPIREHOST'} || &ask_user("Host: "));
X$EMPIREPORT = ($opt_p || $ENV{'EMPIREPORT'} || &ask_user("Port: "));
X$COUNTRY = ($COUNTRY || shift || $ENV{'COUNTRY'} || &ask_user("Country: "));
X$PLAYER =  ($PLAYER || shift || $ENV{'PLAYER'} || &ask_user("Player: "));
X
Xsub ask_user {
X  print @_;
X  local($answer);
X  chop($answer = <STDIN>);
X  $answer;
X}
X
X 
X 
X                                # Empire server return codes.
X$C_CMDOK   = "0";
X$C_DATA    = "1"; $C_INIT    = "2"; $C_EXIT    = 3; $C_FLUSH   = 4; $C_NOECHO  = 5;
X$C_PROMPT  = 6; $C_ABORT   = 7; $C_REDIR   = 8; $C_PIPE    = 9; $C_CMDERR  ="a";
X$C_BADCMD  ="b"; $C_EXECUTE ="c";
X$Redirect  = 0;			# Are we redirecting the output?
X 
X                                # get our IP address and the Empire host's
Xchop($hostname = `hostname`);
X($name,$aliases,$proto)                 = getprotobyname('tcp');
X($name,$aliases,$type,$len,$thisaddr)   = gethostbyname($hostname);
X($name,$aliases,$type,$len,$EMPIREHOST) = gethostbyname($EMPIREHOST);
X 
X                                # pack IP addresses into socket addresses
X$sockaddr = 'S n a4 x8';        # pack format (unsigned short, network order
X				# short, ascii string length 4, 8 null bytes
X$AF_INET = 2;                   # Assume this is to say we are INET
X$SOCK_STREAM = 1;               # Stream socket as opposed to UDP or RAW
X$us   = pack($sockaddr, $AF_INET, 0, $thisaddr);
X$them = pack($sockaddr, $AF_INET, $EMPIREPORT, $EMPIREHOST);
X 
X                                # make the connection
Xsocket(S, $AF_INET, $SOCK_STREAM, $proto) || die $!;
Xbind(S, $us)      || die $!;
Xconnect(S, $them) || die $!;
Xfcntl(S, 4, 'FNDELAY') || die $!;	# Non-blocking socket
Xselect(S);      $| = 1;
Xselect(STDOUT); $| = 1;
X$SIG{'INT'}='abort_handler';		#working but needs <CR> enter afterwards
X$SIG{'PIPE'}='brknpipe';		#catch broken pipes.
X&login;
Xfor(;;) {
X  if ($#inputstack>=0 && $waiting==0) { &proc_input(shift(@inputstack)); }
X  vec($rin, fileno(S), 1)=1;
X  vec($rin, fileno(STDIN), 1)=1;
X  if ($waiting==1 || $#inputstack<0) {
X    select($rout=$rin, undef, undef, undef); 
X    select((select(STDIN), $|=1)[$[]);
X    select((select(S), $|=1)[$[]);
X  }
X  if (vec($rout, fileno(S), 1)) { &socket(&getline); }
X  if (vec($rout, fileno(STDIN), 1)) { &keyboard; }
X}
Xexit; 					# never reached
X 
Xsub login {
X  push(@inputstack, "coun $COUNTRY\n");
X  push(@inputstack, "pass $PLAYER\n");
X  push(@inputstack, "user $ENV{'USER'}\n");
X  if ( $opt_k ) { push(@inputstack, "kill\n"); }
X  push(@inputstack, "play\n");
X}
X
Xsub keyboard {			# read from the keyboard.  Should be only one
X  sysread(STDIN, $input, 2048);
X  if (length($input)==1) { return; }
X  if ($input =~ /"[^"]*;[^"]*"/ || ($code==$C_FLUSH && $output=~ /left/)) {
X    push(@inputstack, $input);
X  } else {
X    $input =~ s/;/\n;/g;
X    push(@inputstack, split(/;/, $input));
X  }
X  $input='';
X  return;
X}
X
Xsub proc_input {
X  local($x, $y, @cmd);
X  local($input)=@_;
X  if ($input =~ /^alias/o) {
X    if ($input=~ /\S+\s+(\S+)\s*(.*)/o) {
X      $key=$1; $value=$2;
X      if ($value =~ /"[^"]*;[^"]*"/) { $value =~ s/\"//g; }
X      $alias{$key}=$value;
X      print "Set.\n";
X      print $prompt;
X    } else {
X      print "Aliases:\n";
X      foreach $key (keys %alias) {
X	print "  $key=$alias{$key}\n";
X      }
X      print $prompt;
X    }
X  } elsif ($input=~ /^:/o) { system $'; print $prompt; }
X  elsif ($input=~ /^!/o) { &history($'); }
X  elsif ($input=~ /^&/o) {
X    if ($code==$C_FLUSH) {
X      if (!($output =~ /left/o)) { &proc_input($'); }
X      else { print S $input; }
X    }
X  }
X  elsif ($input=~ /^</o) {
X    open(READFILE,$');	
X    while(<READFILE>) { push(@inputstack, $_); }
X    close(READFILE);
X    print $prompt;
X  } elsif ($input=~ /^hist/o) {		# history listing
X    print "History:\n";
X    for($y=$#hist; $y>=0; $y--) { print "  $hist[$y]\n"; }
X    print $prompt;
X  } elsif ($input =~ /^unalias\s+(\S+)*/o) { # unalias
X    delete $alias{$1};
X    print "Removed.\n";
X    print $prompt;
X  } else {
X    ($tmp, $rest) = ($input =~ /(^\S+)\s*(.*)/o);
X    if ($alias{$tmp}) {
X       &proc_input(&alias($rest, $alias{$tmp}));
X    } else {
X      if ($code==$C_PROMPT || ($code==$C_FLUSH && !$output =~ /\d+ left/)) {
X	push(@hist, $input);
X	while ($#hist>19) { shift(@hist); }
X	print S "$input";
X      } else { print S "$input"; }
X      $waiting=1;
X    }
X  }
X}
X
Xsub socket {
X  local($input)=@_;
X  ($code, $output) = ($input =~ /^(\w+) (.*)/o);
X  if (!($code cmp $C_CMDOK) || !($code cmp $C_INIT)) { $waiting=0; next; }
X  elsif (!($code cmp $C_DATA)) { 
X    if ($Redirect) { print REDIRECT_TO $output, "\n"; }
X    else { print $output, "\n"; }
X  }
X  elsif ($code == $C_EXIT) {
X    print $output, "\n";
X    &exit_clean;
X  }
X  elsif ($code == $C_FLUSH) {
X                                # prompt, but not a command line one.
X    $output =~ /(\d+) (\d+)/o;
X    print STDOUT "$output";
X    $waiting=0;
X  }
X  elsif ($code == $C_PROMPT) {
X    if ($Redirect) { 
X      $Redirect=0; 
X      close REDIRECT_TO;
X    }
X    $waiting=0;
X                                # get BTU and time usage, print a prompt
X    $output =~ /(\d+) (\d+)/o;
X    print "\n";
X    if ($opt_g) { $prompt="[$opt_g $1:$2] Command:"; }
X    else { $prompt="[$1:$2] Command:"; }
X    print "$prompt";
X  }
X  elsif ($code == $C_REDIR || $code == $C_PIPE) {
X    $Redirect=1;
X    open(REDIRECT_TO, $output);	# Open the output descriptor
X  }
X  elsif (!($code cmp $C_CMDERR) || !($code cmp $C_BADCMD)) {
X    print "$output\n";
X    print S "quit\n";
X  }
X  elsif ($code == $C_ABORT || $code == $C_EXECUTE) {
X    print $output; 
X  } else { die "Unrecognized output from server\n"; }
X return;
X}
X
Xsub getline {				# get a line from the socket
X  local($string)='';
X  local($char);
X  while(sysread(S, $char, 1)!=0) {
X    $string=$string . $char;
X    if (!($char cmp "\n")) { return $string; }
X  }
X  local($code)= ($string =~ /^(\d+)\s*/o);	# If not \n deliminated
X  if ($code!=C_PROMPT && $code!=C_FLUSH) {	# and not a prompt
X    return $string . &getline; 			# then it is a packet break
X  }
X  return $string;
X} 
X
Xsub alias {
X  local($cmdline, $template) = @_;
X  local(@cmd)=split(/ /, $cmdline); 
X  local(@temp)=split(/ /, $template);
X  if ($#temp==0 || !($temp[1] cmp '$0')) {
X    return join(' ', $temp[0], @cmd);
X  } else {
X    $template =~ s/(\$(\d+))/$cmd[\2-1]/ge;
X    return "$template";
X  }
X}
X
Xsub history {					# handle unix-like (?) history
X  local($match)=@_;
X  chop($match);
X  for($x=$#hist;$x>-1;$x--) {
X    if ($hist[$x] =~ /^$match/) {
X      print S "$hist[$x]\n";
X      $waiting=1;
X      return;
X    }
X  }
X  print "Event not found.\n";
X  return;
X}
X
Xsub exit_clean {
X    shutdown(S,2);
X    exit;
X}
X
Xsub abort_handler {
X  if ($waiting==0 && $code==$C_FLUSH) { print S "aborted\n"; }
X  $waiting=0;
X  while($#inputstack>=0) { shift(@inputstack); }
X  $SIG{'INT'}='abort_handler';		#working but needs <CR> enter afterwards
X  return;
X}
X
Xsub brknpipe {
X  $waiting=0;
X  print "Broken pipe.\n";
X  return;
X}
X 
X#############################################################################
X#
X# A skeletal Perl Empire client.
X#
X# Sean Eddy (Mirkwood)
X# sre@mrc-lmb.cam.ac.uk
X# December 1993
X#
X#############################################################################
X#
X# I've added environment variable acceptance, and command line options.
X# note option '-k' kill before playing.
X#
X# Michael Feuell (Krikkit/Carnage Deity)
X# elf@twain.ucs.umass.edu
X# December 1993
X#
X#############################################################################
X#
X# Additions are documented in the README file that should have come with this.
X#
X# Sam "Drazz'zt" Tetherow
X# stetherow@unl.edu
X#
X#############################################################################
END_OF_FILE
if test 8502 -ne `wc -c <'pec'`; then
    echo shar: \"'pec'\" unpacked with wrong size!
fi
chmod +x 'pec'
# end of 'pec'
fi
echo shar: End of shell archive.
exit 0
