home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume43
/
ftpmail
/
part02
/
lchat.pl
< prev
next >
Wrap
Perl Script
|
1994-07-07
|
6KB
|
242 lines
# This is little chat. It is based on the chat2 that I did for mirror
# which in turn was based on the Randal Schwartz version.
# This version can only have one outgoing open at a time. This
# avoids returning string filehandles which were a source of memory leaks.
#
# chat.pl: chat with a server
# Based on: V2.01.alpha.7 91/06/16
# Randal L. Schwartz (was <merlyn@iwarp.intel.com>)
# multihome additions by A.Macpherson@bnr.co.uk
# allow for /dev/pts based systems by Joe Doupnik <JRD@CC.USU.EDU>
# $Id: chat2.pl,v 2.3 1994/02/03 13:45:35 lmjm Exp lmjm $
# $Log: chat2.pl,v $
# Revision 2.3 1994/02/03 13:45:35 lmjm
# Correct chat'read (bfriesen@simple.sat.tx.us)
#
# Revision 2.2 1993/12/14 11:09:03 lmjm
# Only include sys/socket.ph if not already there.
# Allow for system 5.
#
# Revision 2.1 1993/06/28 15:11:07 lmjm
# Full 2.1 release
#
package chat;
unless( defined &'PF_INET ){
eval "sub ATT { 0; } sub INTEL { 0; }";
do 'sys/socket.ph';
}
if( defined( &main'PF_INET ) ){
$pf_inet = &main'PF_INET;
$sock_stream = &main'SOCK_STREAM;
local($name, $aliases, $proto) = getprotobyname( 'tcp' );
$tcp_proto = $proto;
}
else {
# XXX hardwired $PF_INET, $SOCK_STREAM, 'tcp'
# but who the heck would change these anyway? (:-)
$pf_inet = 2;
$sock_stream = 1;
$tcp_proto = 6;
}
$sockaddr = 'S n a4 x8';
chop( $thishost = `(hostname || uname -n || uuname -l) 2>/dev/null` );
## &chat'open_port("server.address",$port_number);
## opens a named or numbered TCP server
sub open_port { ## public
local($server, $port) = @_;
local($serveraddr,$serverproc);
# We may be multi-homed, start with 0, fixup once connexion is made
$thisaddr = "\0\0\0\0" ;
$thisproc = pack($sockaddr, 2, 0, $thisaddr);
if ($server =~ /^(\d+)+\.(\d+)\.(\d+)\.(\d+)$/) {
$serveraddr = pack('C4', $1, $2, $3, $4);
} else {
local(@x) = gethostbyname($server);
if( ! @x ){
return undef;
}
$serveraddr = $x[4];
}
$serverproc = pack($sockaddr, 2, $port, $serveraddr);
unless (socket(S, $pf_inet, $sock_stream, $tcp_proto)) {
($!) = ($!, close(S)); # close S while saving $!
return undef;
}
unless (bind(S, $thisproc)) {
($!) = ($!, close(S)); # close S while saving $!
return undef;
}
unless (connect(S, $serverproc)) {
($!) = ($!, close(S)); # close S while saving $!
return undef;
}
# We opened with the local address set to ANY, at this stage we know
# which interface we are using. This is critical if our machine is
# multi-homed, with IP forwarding off, so fix-up.
local($fam,$lport);
($fam,$lport,$thisaddr) = unpack($sockaddr, getsockname(S));
$thisproc = pack($sockaddr, 2, 0, $thisaddr);
# end of post-connect fixup
select((select(S), $| = 1)[0]);
return 1;
}
## $return = &chat'expect($timeout_time,
## $pat1, $body1, $pat2, $body2, ... )
## $timeout_time is the time (either relative to the current time, or
## absolute, ala time(2)) at which a timeout event occurs.
## $pat1, $pat2, and so on are regexs which are matched against the input
## stream. If a match is found, the entire matched string is consumed,
## and the corresponding body eval string is evaled.
##
## Each pat is a regular-expression (probably enclosed in single-quotes
## in the invocation). ^ and $ will work, respecting the current value of $*.
## If pat is 'TIMEOUT', the body is executed if the timeout is exceeded.
## If pat is 'EOF', the body is executed if the process exits before
## the other patterns are seen.
##
## Pats are scanned in the order given, so later pats can contain
## general defaults that won't be examined unless the earlier pats
## have failed.
##
## The result of eval'ing body is returned as the result of
## the invocation. Recursive invocations are not thought
## through, and may work only accidentally. :-)
##
## undef is returned if either a timeout or an eof occurs and no
## corresponding body has been defined.
## I/O errors of any sort are treated as eof.
$nextsubname = "expectloop000000"; # used for subroutines
sub expect { ## public
local($endtime) = shift;
local($timeout,$eof) = (1,1);
local($caller) = caller;
local($rmask, $nfound, $timeleft, $thisbuf);
local($cases, $pattern, $action, $subname);
$endtime += time if $endtime < 600_000_000;
# now see whether we need to create a new sub:
unless ($subname = $expect_subname{$caller,@_}) {
# nope. make a new one:
$expect_subname{$caller,@_} = $subname = $nextsubname++;
$cases .= <<"EDQ"; # header is funny to make everything elsif's
sub $subname {
LOOP: {
if (0) { ; }
EDQ
while (@_) {
($pattern,$action) = splice(@_,0,2);
if ($pattern =~ /^eof$/i) {
$cases .= <<"EDQ";
elsif (\$eof) {
package $caller;
$action;
}
EDQ
$eof = 0;
} elsif ($pattern =~ /^timeout$/i) {
$cases .= <<"EDQ";
elsif (\$timeout) {
package $caller;
$action;
}
EDQ
$timeout = 0;
} else {
$pattern =~ s#/#\\/#g;
$cases .= <<"EDQ";
elsif (\$S =~ /$pattern/) {
\$S = \$';
package $caller;
$action;
}
EDQ
}
}
$cases .= <<"EDQ" if $eof;
elsif (\$eof) {
undef;
}
EDQ
$cases .= <<"EDQ" if $timeout;
elsif (\$timeout) {
undef;
}
EDQ
$cases .= <<'ESQ';
else {
$rmask = "";
vec($rmask,fileno(S),1) = 1;
($nfound, $rmask) =
select($rmask, undef, undef, $endtime - time);
if ($nfound) {
$nread = sysread(S, $thisbuf, 1024);
if( $chat'debug ){
print STDERR "sysread $nread ";
print STDERR ">>$thisbuf<<\n";
}
if ($nread > 0) {
$S .= $thisbuf;
} else {
$eof++, redo LOOP; # any error is also eof
}
} else {
$timeout++, redo LOOP; # timeout
}
redo LOOP;
}
}
}
ESQ
eval $cases; die "$cases:\n$@" if $@;
}
$eof = $timeout = 0;
do $subname();
}
## &chat'print(@data)
sub print { ## public
print S @_;
if( $chat'debug ){
print STDERR "printed:";
print STDERR @_;
}
}
## &chat'close()
sub close { ## public
close(S);
}
# &chat'read(*buf, $ntoread )
# blocking read. returns no. of bytes read and puts data in $buf.
# If called with ntoread < 0 then just do the accept and return 0.
sub read { ## public
local(*chatreadbuf) = shift;
$chatreadn = shift;
if( $chatreadn > 0 ){
return sysread(S, $chatreadbuf, $chatreadn );
}
}
1;