summaryrefslogtreecommitdiff
path: root/gnu/libexec/uucp/contrib
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /gnu/libexec/uucp/contrib
initial import of NetBSD tree
Diffstat (limited to 'gnu/libexec/uucp/contrib')
-rw-r--r--gnu/libexec/uucp/contrib/Dial.Hayes108
-rw-r--r--gnu/libexec/uucp/contrib/Hangup.Hayes57
-rw-r--r--gnu/libexec/uucp/contrib/Login.LAT137
-rw-r--r--gnu/libexec/uucp/contrib/Login.PortSel133
-rw-r--r--gnu/libexec/uucp/contrib/Login.VMS96
-rw-r--r--gnu/libexec/uucp/contrib/Makefile.uurt40
-rw-r--r--gnu/libexec/uucp/contrib/Makefile.xchat31
-rw-r--r--gnu/libexec/uucp/contrib/README82
-rw-r--r--gnu/libexec/uucp/contrib/README-UURATE21
-rw-r--r--gnu/libexec/uucp/contrib/README-XCHAT42
-rw-r--r--gnu/libexec/uucp/contrib/amiga.c43
-rw-r--r--gnu/libexec/uucp/contrib/dialHDB.c187
-rw-r--r--gnu/libexec/uucp/contrib/savelog.man130
-rw-r--r--gnu/libexec/uucp/contrib/savelog.sh247
-rw-r--r--gnu/libexec/uucp/contrib/stats.sh27
-rw-r--r--gnu/libexec/uucp/contrib/tstout.c158
-rw-r--r--gnu/libexec/uucp/contrib/uuclean25
-rw-r--r--gnu/libexec/uucp/contrib/uucomp.shar552
-rw-r--r--gnu/libexec/uucp/contrib/uudemon.shar82
-rw-r--r--gnu/libexec/uucp/contrib/uupoll.shar2705
-rw-r--r--gnu/libexec/uucp/contrib/uuq.sh125
-rw-r--r--gnu/libexec/uucp/contrib/uurate.c1860
-rw-r--r--gnu/libexec/uucp/contrib/uurate.man280
-rw-r--r--gnu/libexec/uucp/contrib/uureroute.perl91
-rw-r--r--gnu/libexec/uucp/contrib/uusnap.c321
-rw-r--r--gnu/libexec/uucp/contrib/uutraf210
-rw-r--r--gnu/libexec/uucp/contrib/uutry43
-rw-r--r--gnu/libexec/uucp/contrib/uuxconv50
-rw-r--r--gnu/libexec/uucp/contrib/xc-conf.h-dist38
-rw-r--r--gnu/libexec/uucp/contrib/xchat.c1473
-rw-r--r--gnu/libexec/uucp/contrib/xchat.man628
31 files changed, 10022 insertions, 0 deletions
diff --git a/gnu/libexec/uucp/contrib/Dial.Hayes b/gnu/libexec/uucp/contrib/Dial.Hayes
new file mode 100644
index 00000000000..32eef82d347
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Dial.Hayes
@@ -0,0 +1,108 @@
+#!xchat
+# @(#) dial.hayes V1.1 Tue Sep 1 13:59:58 1992 (Bob Denny)
+#
+# xchat script for dialing a vanilla Hayes modem
+#
+# Usage:
+# xchat dial.hayes telno
+#
+# where telno is the telephone number, subject to pause and wait
+# character modification.
+#
+# Uncomment the first two lines after "start:" to get debugging
+# in file "Dial.Log"
+#
+# Flush input, zero counter, set telephone number if supplied,
+# else fail if no telephone number given.
+#
+start:
+### dbgfile Dial.Log
+### dbgset 15
+ zero
+ flush
+ ifnstr notelno 0
+ telno 0
+ goto initmodem
+#
+# Missing telephone number.
+#
+notelno:
+ logerr No telephone number given
+ failed
+#
+# Reset the modem to nonvolatile profile.
+# Allow 3 sec. for response, as some modems are slow to reset.
+#
+initmodem:
+ count
+ ifgtr cantinit 4
+ send ATZ\r
+ timeout initmodem 3000
+ expect setupmodem OK
+#
+# No response from modem
+#
+cantinit:
+ logerr Can't wake modem
+ failed
+#
+# Send the stuff needed to initialize the modem to the modes
+# needed for the particular modem flavor. The string below
+# is provided as a vanilla example. Allow 2 sec. for the
+# modem to respond to this command.
+#
+setupmodem:
+ sleep 1000
+ send ATM0S7=90S11=120\r
+ timeout setupfail 2000
+ expect setupfail ERROR
+ expect dialnumber OK
+#
+# Modem barfed or died on setup command.
+#
+setupfail:
+ logerr Error in modem setup string
+ failed
+#
+# Dial the supplied number. Handle the various errors that
+# can come back from the modem by logging the error.
+#
+dialnumber:
+ sleep 1000
+ send ATDT
+ dial
+ send \r
+ flush
+ timeout timeout 90000
+ expect connected CONNECT
+ expect busy BUSY
+ expect nocarrier NO CARRIER
+ expect noanswer NO ANSWER
+ expect nodialtone NO DIALTONE
+#
+# Success!
+#
+connected:
+ success
+#
+# Handle modem dial failures
+#
+timeout:
+ logerr Modem or carrier timeout.
+ failed
+busy:
+ logerr BUSY
+ failed
+nocarrier:
+ logerr NO CARRIER
+ failed
+noanswer:
+ logerr NO ANSWER
+ failed
+nodialtone:
+ logerr NO DIALTONE
+ failed
+#
+# end
+#
+
diff --git a/gnu/libexec/uucp/contrib/Hangup.Hayes b/gnu/libexec/uucp/contrib/Hangup.Hayes
new file mode 100644
index 00000000000..c111c00fcae
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Hangup.Hayes
@@ -0,0 +1,57 @@
+#!xchat
+# @(#) Hangup.Hayes V1.1 Tue Sep 1 14:04:25 1992 (Bob Denny)
+#
+# xchat script for hanging up a Hayes-type modem. When used with Taylor
+# UUCP, this script should be run as the dialer-complete and dialer-abort
+# script with xchat.
+#
+# Usage:
+# xchat Hangup.Hayes [ x ]
+#
+# where 'x' is any string. If it is present, this script will log the
+# modem reset as an ABORT reset, otherwise it will not log anything.
+#
+# Uncomment the lines starting with '###' to get debugging log.
+#
+start:
+### dbgfile Hangup.Log
+### dbgset 15
+ zero
+ sleep 2000 # Wait for trailing garbage
+ flush # Toss it out
+ ifnstr wakemodem 0 # No abort indicator
+ log Hangup on abort
+#
+# Get modem's attention via Hayes 'escape' protocol.
+#
+wakemodem:
+ sleep 4000
+ send +++
+ sleep 4000
+ send \r
+ timeout reset 2000
+ expect reset OK
+#
+# We're (probably) in command mode. Use ATZ (reset) to hang up
+# as some modems don't behave well with ATH0 command.
+#
+reset:
+ send ATZ\r
+ timeout silent 5000
+ expect done OK
+#
+# Finished, modem is back in initial state.
+#
+done:
+ success
+#
+# No response to escape protocol. Log the error and force DTR low
+# in an attempt to get control of the modem. Then send ATZ just to
+# make sure.
+#
+silent:
+ logerr Hangup: no response from modem
+ hangup # Force DTR low as last gasp
+ send ATZ\r
+ sleep 5000
+ failed
diff --git a/gnu/libexec/uucp/contrib/Login.LAT b/gnu/libexec/uucp/contrib/Login.LAT
new file mode 100644
index 00000000000..d557f97e219
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Login.LAT
@@ -0,0 +1,137 @@
+#!xchat
+# @(#) login.LAT V1.2 Tue Sep 1 13:25:28 1992
+#
+# xchat script for logging into a VMS system through a LAT
+# terminal server port. If no VMS password parameter supplied,
+# skips password phase of VMS login. If LAT-password supplied,
+# will log into LAT server using that password. NOTE: does not
+# handle the situation where a LAT password is needed but no
+# VMS password is needed.
+#
+# Usage:
+# xchat login.LAT sysname username [ password [ LAT-password ] ]
+#
+# History:
+# rbd Fri Aug 14 13:37:06 1992
+# Changes for Lantronix ETS-16. It says "type help at the Local>
+# prompt..." then it gives the prompt for real! Prompt may need
+# to be something other than "Local>". We match the real Local>
+# prompt by matching the leading newline!
+#
+# rbd Tue Sep 1 13:04:32 1992
+# Remove absolute path name from log file. Now defaults per config.
+#
+start:
+ dbgfile Login.Log
+ dbgset 15
+ sleep 2000 # Wait 2 seconds
+ flush # Flush typeahead
+ ifnstr svrstart 3 # Skip server password if not given
+#
+# Starting point if server password supplied. Handle situation
+# where the server line may have been left waiting for username
+# or at local> prompt.
+#
+getsvrpwp:
+ zero
+l0:
+ count # Get server's password prompt
+ ifgtr deadmux 5 # die if 5 cr's don't do it
+ send \r
+ timeout l0 1000 # Wait and try again
+ expect dosvrpw ssword>
+ expect svrlogin ername>
+ expect connect \nLocal>
+#
+# Send server's password. Fail if don't get Username
+# or Local> prompt.
+#
+dosvrpw:
+ zero
+l2:
+ sendstr 3
+ send \r
+ timeout badsvrpw 5000 # Die if invalid
+ expect svrlogin ername>
+ expect connect \nLocal>
+#
+# Starting point if NO server password supplied. Handle situation
+# where the server line may have been left at local> prompt.
+#
+svrstart:
+ zero
+l1:
+ count # Get username> or local> prompt
+ ifgtr deadmux 5 # Die if 5 cr's don't do it
+ send \r
+ timeout l1 1000 # Wait and try again
+ expect svrlogin ername>
+ expect connect \nLocal>
+#
+# Server asked for a username. Just give 'uucp'.
+#
+svrlogin:
+ send uucp\r
+ timeout deadmux 2000
+ expect connect \nLocal>
+#
+# At this point, we have the Local> prompt. Send the connect
+# command for the specified LAT host service name, and wait for
+# VMS "Username:" prompt. Die after 10 seconds.
+#
+connect:
+ send c\s
+ sendstr 0
+ send \r
+ timeout nologin 10000
+ expect gotlogin ername:
+#
+# Got VMS "Username:" prompt. Send the username. If a password
+# was given, wait for the "Password:" prompt. Die after 10 seconds.
+# if no password was given, we're done!
+#
+gotlogin:
+ sendstr 1
+ send \r
+ ifnstr done 2
+ timeout nopasswd 10000
+ expect gotpasswd ssword:
+#
+# Got VMS "Password:" prompt. Send the password and we're done!
+#
+gotpasswd:
+ sendstr 2
+ send \r
+#
+# Success!
+#
+done:
+ success
+#
+# ERROR HANDLERS
+#
+#
+# LAT server appears dead. Fail.
+#
+deadmux:
+ logerr No response from LAT server
+ failed
+#
+# The server password was bad. Fail.
+#
+badsvrpw:
+ logerr Invalid LAT server password
+ failed
+#
+# VMS system appears to be dead. Fail.
+#
+nologin:
+ logerr No VMS Username: prompt
+ failed
+#
+# Failed to get "Password:" prompt. Fail.
+#
+nopasswd:
+ logerr No VMS Password: prompt. Invalid password?
+ failed
+
diff --git a/gnu/libexec/uucp/contrib/Login.PortSel b/gnu/libexec/uucp/contrib/Login.PortSel
new file mode 100644
index 00000000000..d8c3a6643a6
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Login.PortSel
@@ -0,0 +1,133 @@
+#!xchat
+# @(#) Login.PortSelUnix V1.0 Tue Sep 1 14:57:05 1992 (Bob Denny)
+#
+# NOTE: Untested with xchat V1.1. Taken from DECUS UUCP.
+#
+# From: "Kent C. Brodie" <moocow!brodie@CSD4.MILW.WISC.EDU>
+# uucp: {uunet!marque,csd4.milw.wisc.edu}!moocow!brodie
+# special script for "uwmcsd4", have to go through a port selector (and then
+# log in via standard Unix procedures).
+#
+# Also included is the ability to wait in the port selector queue.
+# Be forwarned that the debug log can get pretty big depending on
+# how many times you "wait" in the queue.
+# (C) 1989 Kent C. Brodie - Medical College of Wisconsin
+
+# P0 is systemname , P1 is username, P2 is password.
+
+ zero
+
+# send a CR to get the selector's attention. Sleep a little bit
+# due to large login text of selector. It sends "Which System?"
+# when it's ready.
+
+getprtslct:
+ count
+ ifgtr noprtslct 6
+ break
+ send \r
+ sleep 2000
+ flush
+ expect prtslctok ystem?
+ timeout getprtslct 15000
+
+noprtslct:
+ logerr Sent cr, no "Which System?" from port selector
+ failed
+
+# Send the system name. We either get "OK" (connected), or we
+# get "No ports available, would you like to wait?" (wait in queue)
+
+prtslctok:
+ zero
+ sendstr 0
+ send \r
+ expect connected OK
+ expect prtslctwait wait?
+ timeout noconnect 10000
+
+# Usually we get "nn Your place in queue" messages. JUST in case we
+# get a free port right away, check for 'Are you ready?' as well.
+
+prtslctwait:
+ zero
+ send Y\r
+ expect prtslctque queue
+ expect prtslctrdy ready?
+ timeout prtwaitbad 70000
+
+prtwaitbad:
+ logerr Sent "Y" to wait in queue, did not get valid response.
+ failed
+
+# Here's where we wait in the queue. The port selector sends us a status
+# message about once a minute. We either get "nn Your place in queue"
+# or we get "System Available. Are you Ready?".
+# If something goes wrong, we time out waiting for either response.
+# The reason we don't sleep for 40-50 seconds is because as SOON as the
+# port is ready, it informs us. If we wait too long, it drops us.
+# This setup is laid out for a maximum of 20 "tries" which is ABOUT
+# 20 minutes. Note: This constant retrying can make log files
+# kind of big....
+
+prtslctque:
+ count
+ ifgtr prtslcttry 20
+ expect prtslctque queue
+ expect prtslctrdy ready?
+ timeout noportwait 70000
+
+prtslcttry:
+ logerr Too many (20) wait/retries -- queue too busy.
+ failed
+
+prtslctrdy:
+ send Y\r
+ expect connected OK
+ timeout noconnect 20000
+
+
+noportwait:
+ logerr Timed out awaiting place in port queue
+ failed
+
+noconnect:
+ logerr Sent system name, no "OK" from selector
+ failed
+
+# standard Unix login stuff. Send cr, expect "ogin:", if no, send a break
+# (which tells Unix to try the next bit rate) and try again.
+
+connected:
+ send \r
+ zero
+ goto waitlogin
+
+sendbreak:
+ count
+ ifgtr nolgi 6
+ flush
+ break
+
+waitlogin:
+ expect gotlogin ogin:
+ timeout sendbreak 5000
+
+nolgi:
+ logerr No login: prompt
+ failed
+
+gotlogin:
+ sendstr 1
+ send \r
+ expect gotword word:
+ timeout nopwd 10000
+
+nopwd:
+ logerr No password: prompt
+ failed
+
+gotword:
+ sendstr 2
+ send \r
+ success
diff --git a/gnu/libexec/uucp/contrib/Login.VMS b/gnu/libexec/uucp/contrib/Login.VMS
new file mode 100644
index 00000000000..d6196cb2aa6
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Login.VMS
@@ -0,0 +1,96 @@
+#!xchat
+# @(#) Login.VMS V1.1 Tue Sep 1 13:24:54 1992 (Bob Denny)
+#
+#
+# xchat script for logging into a VMS system. If no VMS password
+# parameter supplied, skips password phase of VMS login. If syspass
+# parameter given, will go through steps needed to log into a VMS
+# system where a "system password" was set on the port.
+#
+# Cannot handle situation where system password is required but
+# no password needed.
+#
+#
+# Usage:
+# xchat Login.VMS username [ password [ syspass ] ]
+#
+# Uncomment the lines starting with "###" to get debug logging.
+#
+start:
+### dbgfile Login.Log
+### dbgset 15
+ sleep 2000 # Wait 2 seconds
+ zero
+ flush # Flush typeahead
+ ifnstr login 2 # Skip sys passwd if not given
+#
+# Need system password. Send <CR> to get bell.
+# Try 5 times at 2 sec. intervals. Skip to do
+# username if we see "Username:".
+#
+syspass:
+ count
+ ifgtr nobell 5 # Fail after 5 tries
+ send \r
+ timeout syspass 2000 # Wait 2 sec. and try again
+ expect gotbell \007
+ expect gotlogin Username:
+#
+# Got the bell. Send the system password. Repeat 5 times
+# at 2 sec. intervals. Fail if we don't get Username:
+#
+gotbell:
+ zero
+ sleep 2000
+l1:
+ count
+ ifgtr nologin 5 # Fail after 5 tries
+ sendstr 2
+ send \r
+ timeout l1 2000 # Wait 2 sec. and try again
+ expect gotlogin Username:
+#
+# Start here if no system password supplied.
+# Send <CR> until we get Username: Try 5 times at 2 sec. intervals.
+#
+login:
+ count
+ ifgtr nologin 5 # Fail after 5 tries
+ send \r
+ timeout login 2000 # Wait 2 sec. and try again
+ expect gotlogin Username:
+#
+# Got VMS "Username:" prompt. Send the username. If a password
+# was given, wait for the "Password:" prompt. Die after 10 seconds.
+# if no password was given, we're done!
+#
+gotlogin:
+ sendstr 0
+ send \r
+ ifnstr done 1
+ timeout nopasswd 10000
+ expect gotpasswd Password:
+#
+# Got VMS "Password:" prompt. Send the password and we're done!
+#
+gotpasswd:
+ sendstr 1
+ send \r
+#
+# Success!
+#
+done:
+ success
+#
+# ERROR HANDLERS
+#
+nobell:
+ logerr No VMS system password prompt (bell)
+ failed
+nologin:
+ logerr No VMS Username: prompt
+ failed
+nopasswd:
+ logerr No VMS Password: prompt.
+ failed
+
diff --git a/gnu/libexec/uucp/contrib/Makefile.uurt b/gnu/libexec/uucp/contrib/Makefile.uurt
new file mode 100644
index 00000000000..8088539f6e5
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Makefile.uurt
@@ -0,0 +1,40 @@
+# $Id: Makefile.uurt,v 1.1 1995/10/18 08:38:23 deraadt Exp $
+# Makefile for uurate 1.10
+#
+
+# Prefix directory for installation directories.
+prefix = /usr/local
+
+# Directory where the needed .h files are installed (uucp.h ...).
+uucpsrcs = ../
+
+# Where uurate is installed
+BIN=$(prefix)/bin
+# Where uurate's man is installed
+MAN=$(prefix)/man/man1
+
+# The directory to look in for Taylor style configuration files
+newconfigdir = $(prefix)/conf/uucp
+
+# Flags to use when compiling uurate
+CC=gcc -O2
+CFLAGS=-I.. -Wall
+LDFLAGS=-s
+
+SHELL=/bin/sh
+PROGS=uurate
+
+#-----------
+MORECFLAGS= -I. -I$(uucpsrcs) -DNEWCONFIGLIB=\"$(newconfigdir)\"
+
+all: $(PROGS)
+
+uurate: uurate.c
+ $(CC) $(CFLAGS) $(MORECFLAGS) $@.c -o $@ $(LDFLAGS)
+
+install: $(PROGS)
+ cp $(PROGS) $(BIN)
+ cp uurate.man $(MAN)/uurate.1
+
+clean:
+ rm -f $(PROGS) core
diff --git a/gnu/libexec/uucp/contrib/Makefile.xchat b/gnu/libexec/uucp/contrib/Makefile.xchat
new file mode 100644
index 00000000000..5e9aaa8ffed
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/Makefile.xchat
@@ -0,0 +1,31 @@
+#
+# Makefile for xchat 1.1
+#
+# Bob Denny - Tue Sep 1 15:58:22 1992
+#
+CC=cc
+SHELL=/bin/sh
+BIN=/usr/local/lib/uucp
+PROGS=xchat
+
+#-----------
+
+all: $(PROGS)
+
+install: $(PROGS)
+ @for i in $(PROGS) ; do \
+ echo "Install $$i into $(BIN)..." ; \
+ cp $$i $(BIN) ; \
+ echo "Set ownership and protection..." ; \
+ /bin/chmod 0555 $(BIN)/$$i ; \
+ /bin/chown bin $(BIN)/$$i ; \
+ /bin/chgrp bin $(BIN)/$$i ; \
+ done
+
+clean:
+ rm -f $(PROGS) core
+
+
+
+
+
diff --git a/gnu/libexec/uucp/contrib/README b/gnu/libexec/uucp/contrib/README
new file mode 100644
index 00000000000..8e4651a9bbd
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/README
@@ -0,0 +1,82 @@
+This is the README file for the Taylor UUCP contrib directory.
+
+This directory contains contributed shell scripts and programs that
+you may find useful.
+
+Not actually included here, but nonetheless useful, is the TUA program
+distributed by Lele Gaifax <lele@nautilus.sublink.org>. It can do
+various sorts of analysis of any type of UUCP log file. It should be
+available from most FTP sites.
+
+xchat.c, xchat.man, README-XCHAT, xc-conf.h-dist, Makefile.xchat:
+ A program by Bob Denny that may be invoked by the ``chat-program''
+ command for any of the various types of chat scripts. It is
+ driven by scripts which are written in its own little language.
+ It is a powerful program that can add a lot of flexibility to your
+ chat scripts.
+
+Dial.Hayes, Hangup.Hayes, Login.LAT, Login.PortSel, Login.VMS:
+ Sample scripts for xchat.
+
+uucomp.shar
+ A set of programs which automatically compresses outgoing data in
+ the spool directory. The remote system must cooperate when using
+ this. It can cut down on phone usage when applicable.
+ Contributed by Ed Carp.
+
+uurate.c, uurate.man, README-UURATE, Makefile.uurt:
+ A nifty little program by Bob Denny which analyzes the Log and
+ Stats file and prints various sorts of reports. This version was
+ tweaked by Stephan Niemz and Klaus Dahlenburg.
+
+uutraf:
+ Another program to produce neat reports from your log files, this
+ one a perl script by Johan Vromans.
+
+savelog.sh, savelog.man:
+ A handy shell script to rename a log file and cycle old versions
+ through a set of names, throwing away the oldest one. It will
+ also optionally compress the old log files. I believe that this
+ is originally from smail. It was written by Ronald S. Karr and
+ Landon Curt Noll, and was given to me by Bob Denny.
+
+uureroute.perl:
+ A perl script to reroute all mail queued up for one host to
+ another. Written by Bill Campbell and contributed by Francois
+ Pinard.
+
+stats.sh:
+ A gawk script by Zacharias Beckman which reads the Stats file and
+ prints the last 80 lines as a nicely formatted table.
+
+uuq.sh:
+ A uuq workalike shell script by Zacharias Beckman.
+
+uupoll.shar:
+ uupoll and autopoll programs contributed by Klaus Dahlenburg.
+ uupoll can be used to automatically poll all systems, or a list of
+ systems; autopoll will poll and then retry failed calls.
+
+uudemon.shar:
+ An implementation of the HDB uudemon.poll script by Donald Burr.
+
+uuxconv:
+ A program by Richard E. Nickle to help convert SPOOLDIR_HDB spool
+ directories to SPOOLDIR_TAYLOR spool directories (note that it is
+ not necessary to convert your spool directories at all; the
+ SPOOLDIR_TAYLOR approach may be slightly more efficient).
+
+dialHDB.c:
+ A program by Daniel Hagerty which permits using HDB dialer
+ programs as chat programs.
+
+amiga.c:
+ A wrapper program to run uucico from a cron table under Amiga
+ SVR4 (apparently a wrapper is required). This was contributed by
+ Lawrence E. Rosenman.
+
+tstout.c:
+ A program to remove a user from utmp and wtmp, essentially logging
+ them out. I put this together from BSD code. I need it to use
+ tstuu with the system UUCP on Ultrix 4.0, for reasons that escape
+ me. Most people will have little use for this.
diff --git a/gnu/libexec/uucp/contrib/README-UURATE b/gnu/libexec/uucp/contrib/README-UURATE
new file mode 100644
index 00000000000..0ef637514a5
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/README-UURATE
@@ -0,0 +1,21 @@
+uurate V1.10 - Gather and display Taylor UUCP traffic statistics
+
+Bob Denny (denny@alisa.com) - Thu Sep 3 19:47:41 1992 (V1.2.1)
+Klaus Dahlenburg (kdburg@incoahe.hanse.de) - Tue Sep 28 18:11:34 CET 1993
+
+See the man page for documentation.
+
+Installation:
+------------
+
+(1) Copy or sym-link Makefile.uurt to Makefile.
+
+(2) Edit Makefile: set BIN where you want uurate to be installed,
+ MAN where the man page should go to, and set CFLAGS to point
+ to the directory containing the UUCP sources (this is .. by
+ default). Don't forget to set newconfigdir= to point to the
+ directory where the (Taylor-uucp)config is stored.
+
+(3) Type ``make'' to compile the program.
+
+(4) Type ``make install'' to install the program.
diff --git a/gnu/libexec/uucp/contrib/README-XCHAT b/gnu/libexec/uucp/contrib/README-XCHAT
new file mode 100644
index 00000000000..5f93a284bda
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/README-XCHAT
@@ -0,0 +1,42 @@
+This is xchat V1.1 (Tue Sep 1 15:50:56 1992)
+
+Introduction:
+------------
+
+Xchat is a general-purpose dialing and login program designed for use
+with Taylor UUCP as a "chat-program", taking the place (or augmenting)
+the built-in chat scripting facility. It provides the ability to
+closely control timeouts, multiple simultaneous expect strings with
+separate actions, extended terminal control, modem command character
+pacing, and more.
+
+When used in conjunction with Taylor UUCP's configuration features,
+xchat can provide you the ability to manage the most intricate login,
+dial and hangup needs. The scripts are written in a shell-like (well,
+sort-of) style with labels, commands, and parameters, easing the task
+of writing procedures for complex terminal communications situations.
+
+Installation:
+------------
+
+(1) Copy xc-conf.h-dist to xc-conf.h, then edit xc-conf.h to reflect
+ your condifuration. A description of the settings is in that file.
+
+(2) Copy Makefile.xchat to Makefile and edit it to set BIN to where
+ you want xchat installed.
+
+(2) Do a 'make' to build xchat.
+
+(3) Do a 'make install' to install it.
+
+(4) Format and print xchat.8, and install it if you want.
+
+(5) Print out copies of the scripts in the ./scripts subdirectory.
+
+(6) Read xchat.8 and the scripts together.
+
+
+Author:
+------
+
+Robert B. Denny (denny@alisa.com)
diff --git a/gnu/libexec/uucp/contrib/amiga.c b/gnu/libexec/uucp/contrib/amiga.c
new file mode 100644
index 00000000000..d982364cfd5
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/amiga.c
@@ -0,0 +1,43 @@
+/* Wrapper code for Taylor UUCP on Amiga Unix (SVR4) for cron invoked UUCP */
+/* processes. */
+
+/* The problem: Cron is not a "licensed" process. any process that grabs a
+ controlling terminal needs to be licensed. Taylor UUCP needs controlling
+ terminals. Taylor UUCP does relinquish the controlling terminal before
+ fork(), so the "UUCP" license is appropriate.
+ This simple program does the "right" thing, but *MUST* be SETUID ROOT */
+
+/* Written by: Lawrence E. Rosenman <ler@lerami.lerctr.org> */
+
+#include <sys/sysm68k.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pwd.h>
+
+int main(int argc,char *argv[],char *envp)
+{
+ struct passwd *pw;
+ char name[256];
+
+ strcpy(name,"/usr/local/lib/uucp/uucico");
+ if (sysm68k(_m68k_LIMUSER,EUA_GET_LIC) == 0 ) { /* are we unlicensed? */
+ if (sysm68k(_m68k_LIMUSER,EUA_UUCP) == -1) { /* yes, get a "uucp" license */
+ fprintf(stderr,"sysm68k failed, errno=%d\n",errno); /* we didn't? crab it */
+ exit(errno);
+ }
+ }
+
+ pw = getpwnam("uucp"); /* get the Password Entry for uucp */
+ if (pw == NULL)
+ {
+ fprintf(stderr,"User ID \"uucp\" doesn't exist.\n");
+ exit(1);
+ }
+ setgid(pw->pw_gid); /* set gid to uucp */
+ setuid(pw->pw_uid); /* set uid to uucp */
+ argv[0]=name; /* have PS not lie... */
+ execv("/usr/local/lib/uucp/uucico",argv); /* go to the real program */
+ exit(errno);
+}
diff --git a/gnu/libexec/uucp/contrib/dialHDB.c b/gnu/libexec/uucp/contrib/dialHDB.c
new file mode 100644
index 00000000000..cb2662134af
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/dialHDB.c
@@ -0,0 +1,187 @@
+/*
+# File: dialHDB.c
+# Author: Daniel Hagerty , hag@eddie.mit.edu
+# Copyright (C) 1993
+# Date: Fri Nov 26 19:22:31 1993
+# Description: Program for using HDB dialers for dialing modems, exiting
+ with 0 on success, else failure.
+# Version: 1.0
+# Revision History:
+######
+### 11/26/93 Hag - File creation
+######
+### 1/5/94 Hag - Finally got around to finishing this damn thing.
+######
+*/
+/* Basic theory behind this program-
+ dialHDB forks into two processes, a monitor parent, and a child
+ that does the exec of the dialer. Child pretty much just execs the
+ dialer program, unless there's an exec problem, in which case the
+ child sends the parent a SIGUSR1 to indicate failed execution.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#define kUsage "Usage:\n\t%s dialerPath device number speed\n\
+%s dialer -h device speed\n"
+
+#define kExitErrFlag 0x80 /* & in with exit code to determine error */
+#define kErrorMask 0x0f /* Mask to determine error code */
+
+/* Error code defines as lifted from an HDB dialer */
+#define RCE_NULL 0 /* general purpose or unknown error code */
+#define RCE_INUSE 1 /* line in use */
+#define RCE_SIG 2 /* signal aborted dialer */
+#define RCE_ARGS 3 /* invalid arguments */
+#define RCE_PHNO 4 /* invalid phone number */
+#define RCE_SPEED 5 /* invalid baud rate -or- bad connect baud */
+#define RCE_OPEN 6 /* can't open line */
+#define RCE_IOCTL 7 /* ioctl error */
+#define RCE_TIMOUT 8 /* timeout */
+#define RCE_NOTONE 9 /* no dial tone */
+#define RCE_BUSY 13 /* phone is busy */
+#define RCE_NOCARR 14 /* no carrier */
+#define RCE_ANSWER 15 /* no answer */
+
+/* Structure definition to map error codes to strings */
+typedef struct
+{
+ int errNum;
+ char *errString;
+} errTable;
+
+const errTable errors[]=
+{
+ { RCE_NULL, "Unknown Error" },
+ { RCE_INUSE, "Line is being used" },
+ { RCE_SIG, "Recieved fatal signal" },
+ { RCE_ARGS, "Bad arguments" },
+ { RCE_PHNO, "Invalid phone number" },
+ { RCE_SPEED, "Invalid baud rate or bad connection" },
+ { RCE_OPEN, "Unable to open line" },
+ { RCE_IOCTL, "ioctl error" },
+ { RCE_TIMOUT, "Timed out" },
+ { RCE_NOTONE, "No dialtone" },
+ { RCE_BUSY, "Phone number is busy" },
+ { RCE_NOCARR, "No carrier" },
+ { RCE_ANSWER, "No answer" },
+ { 0,NULL}
+};
+
+/* Function Prototypes */
+int figureStat(int stat);
+char *findInTable(int error);
+void badExec(void);
+
+char *dialerName; /* basename of our dialer program */
+char *dialerPath; /* full path of dialer program */
+
+main(int argc,char *argv[])
+{
+ int parent; /* pid of parent process */
+ int child; /* pid of child process */
+ int stat; /* exit status of child process */
+ char *temp; /* used to get basename of dialer */
+
+ if(argc!=5)
+ {
+ fprintf(stderr,kUsage,argv[0],argv[0]);
+ exit(1);
+ }
+
+ dialerPath=argv[1];
+ dialerName= (temp=strrchr(argv[1],'/'))!=NULL ? temp+1 : argv[1];
+
+ parent=getpid();
+
+ signal(SIGUSR1,badExec); /* set up for possible failed exec */
+
+ if((child=fork())<0)
+ {
+ perror("fork");
+ exit(2);
+ }
+ if(child>0) /* We're parent, wait for child to exit */
+ {
+ /* Set up to ignore signals so we can report them on stderror */
+ signal(SIGHUP,SIG_IGN);
+ signal(SIGINT,SIG_IGN);
+ signal(SIGTERM,SIG_IGN);
+
+ wait(&stat); /* wait for child to exit */
+ exit(figureStat(stat)); /* figure out our exit code and die */
+ }
+ else /* child process */
+ {
+ close(0); /* close of modem file desc, since HDB */
+ close(1); /* doesn't use them */
+ dup2(2,1); /* and remap stdout to stderr, just in case */
+ if(execvp(argv[1],argv+1)<0) /* exec program with argv shifted by 1 */
+ { /* if exec fails, send SIGUSR1 to parent */
+ kill(parent,SIGUSR1);
+ exit(0);
+ }
+ }
+ exit(0);
+}
+
+/* Figure out whether or not dialer ran succesfully, and return
+with 0 if it worked, otherwise error */
+int figureStat(int stat)
+{
+ int exit;
+ int errFlag;
+ int error;
+
+ if(WIFSIGNALED(stat)) /* determine if exit was from signal or what */
+ {
+ fprintf(stderr,"Error: Dialer %s recieved signal %d.\n",dialerName,
+ WTERMSIG(stat));
+ return(1);
+ }
+ if(WIFSTOPPED(stat))
+ {
+ fprintf(stderr,"Error: Dialer %s recieved signal %d.\n",dialerName,
+ WSTOPSIG(stat));
+ return(1);
+ }
+ exit=WEXITSTATUS(stat);
+
+ errFlag=exit&kExitErrFlag; /* Is the error flag set? */
+ if(errFlag)
+ {
+ char *errString;
+
+ error=exit&kErrorMask;
+ errString=findInTable(error); /* find it's string, print it on stderr */
+ fprintf(stderr,"Error: %s - %s.\n",dialerName,errString); /* and return */
+ return(1);
+ }
+ return(0);
+}
+
+/* Support routine, look up exit code in error table, and return pointer
+to proper string */
+char *findInTable(int error)
+{
+ int i=0;
+
+ for(i=0;errors[i].errString!=NULL;i++)
+ {
+ if(errors[i].errNum==error)
+ return(errors[i].errString);
+ }
+ /* Still here, return the top entry, for unknown error */
+ return(errors[0].errString);
+}
+
+/* Called by signal if we recieve SIGUSR 1 */
+void badExec(void)
+{
+ fprintf(stderr,"Error: %s - Execution problem.\n",dialerPath);
+ exit(1);
+}
diff --git a/gnu/libexec/uucp/contrib/savelog.man b/gnu/libexec/uucp/contrib/savelog.man
new file mode 100644
index 00000000000..919b94f4ec1
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/savelog.man
@@ -0,0 +1,130 @@
+.\" @(#)man/man8/savelog.an 1.2 24 Oct 1990 05:18:46
+.de pP
+.if n .sp 1
+.if t .sp .4
+..
+.de tP
+.pP
+.ta \\n(pDu
+.ti -\\n(pDu
+..
+.TH SAVELOG X_MAN8_EXT_X "31 January 1988" "Local"
+.SH NAME
+savelog \- cycle and truncate log files
+.SH SYNOPSIS
+.na
+.B X_UTIL_BIN_DIR_X/savelog
+[
+.B \-m
+.I mode
+] [
+.B \-u
+.I user
+] [
+.B \-g
+.I group
+] [
+.B \-c
+.I cycle
+] [
+.B \-t
+] [
+.B \-l
+]
+.I logfile
+.br
+.ad
+.SH DESCRIPTION
+The
+.I savelog
+command renames and optionally compresses a log file and cycles it
+through a set of names based on the original log file, removing the
+last name in the cycle.
+.SH OPTIONS
+The
+.I savelog
+command accepts the following options:
+.TP
+\fB\-m\fP \fImode\fP
+Change the permissions mode for renamed log files to
+.IR mode .
+By default the mode is unchanged.
+.TP
+\fB\-u\fP \fIuser\fP
+Change the owner for renamed log files to
+.IR user .
+By default the owner is unchanged.
+.TP
+\fB\-g\fP \fIgroup\fP
+Change the group for renamed log files to
+.IR group .
+By default the group is unchanged.
+.TP
+\fB\-c\fP \fIcycle\fP
+Save
+.I cycle
+versions of the logfile, where
+.I cycle
+is a decimal number. The default value is 7.
+.TP
+.B \-l
+Do not compress log files. By default, a compression program is used,
+if one is available.
+.TP
+.B \-t
+Ensure that a new logfile exists when the savelog operation is
+complete. Use of
+.BR \-m ,
+.BR \-u
+or
+.BR \-g
+imply this, ensuring that the logfile will have the designated mode.
+.SH "OPERATION"
+The given logfile is cycled through files named:
+.RS
+
+OLD/\fIfile\fP.\fInumber\fP
+
+.RE
+where
+.I file
+is the basename for the logfile and where
+.I number
+ranges from 0 to one less then the
+.I cycle
+count specified for the command.
+The
+.I OLD
+dirctory is created, as necessary, and is under the same directory as
+the logfile itself.
+.PP
+This cycle operation is accomplished by renaming the file numbered
+.IR cycle -2
+to a file numbered
+.IR cycle -1
+and so on until the file numbered 0 is renamed to the file numbered 1.
+If compression is being used, the first cycle file is compressed after
+being renamed to cycle 1. After the cycle files are moved through the
+various names, the filefile itself is moved to the cycle 0 file.
+This cycle normally occurs once every time
+.I savelog
+is executed.
+If the log file does not exist, savelog ignores it and does
+not cycle the OLD files.
+.PP
+If compression is being used, then compressed log files will have an
+additional suffix appropriate for the compression program that is
+used.
+.SH "SEE ALSO"
+.IR smail (X_MAN5_EXT_X)
+and
+.IR smail (X_MAN8_EXT_X).
+.SH COPYRIGHT
+Copyright(C)1987, 1988 Ronald S. Karr and Landon Curt Noll
+.br
+See a file COPYING,
+distributed with the source code,
+or type
+.I "smail \-bc"
+for distribution rights and restrictions
+associated with this software.
diff --git a/gnu/libexec/uucp/contrib/savelog.sh b/gnu/libexec/uucp/contrib/savelog.sh
new file mode 100644
index 00000000000..64c989f292b
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/savelog.sh
@@ -0,0 +1,247 @@
+#! /bin/sh
+# @(#)util/savelog.sh 1.4 26 Oct 1991 22:49:39
+#
+# savelog - save a log file
+#
+# Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
+#
+# See the file COPYING, distributed with smail, for restriction
+# and warranty information.
+#
+# usage: savelog [-m mode] [-u user] [-g group] [-t] [-c cycle] [-l] file...
+#
+# -m mode - chmod log files to mode
+# -u user - chown log files to user
+# -g group - chgrp log files to group
+# -c cycle - save cycle versions of the logfile (default: 7)
+# -t - touch file
+# -l - don't compress any log files (default: compress)
+# file - log file names
+#
+# The savelog command saves and optionally compresses old copies of files
+# into an 'dir'/OLD sub-directory. The 'dir' directory is determined from
+# the directory of each 'file'.
+#
+# Older version of 'file' are named:
+#
+# OLD/'file'.<number><compress_suffix>
+#
+# where <number> is the version number, 0 being the newest. By default,
+# version numbers > 0 are compressed (unless -l prevents it). The
+# version number 0 is never compressed on the off chance that a process
+# still has 'file' opened for I/O.
+#
+# If the 'file' does not exist or if it is zero length, no further processing
+# is performed. However if -t was also given, it will be created.
+#
+# For files that do exist and have lengths greater than zero, the following
+# actions are performed.
+#
+# 1) Version numered files are cycled. That is version 6 is moved to
+# version 7, version is moved to becomes version 6, ... and finally
+# version 0 is moved to version 1. Both compressed names and
+# uncompressed names are cycled, regardless of -t. Missing version
+# files are ignored.
+#
+# 2) The new OLD/file.1 is compressed and is changed subject to
+# the -m, -u and -g flags. This step is skipped if the -t flag
+# was given.
+#
+# 3) The main file is moved to OLD/file.0.
+#
+# 4) If the -m, -u, -g or -t flags are given, then file is created
+# (as an empty file) subject to the given flags.
+#
+# 5) The new OLD/file.0 is chanegd subject to the -m, -u and -g flags.
+#
+# Note: If the OLD sub-directory does not exist, it will be created
+# with mode 0755.
+#
+# Note: If no -m, -u or -g flag is given, then the primary log file is
+# not created.
+#
+# Note: Since the version numbers start with 0, version number <cycle>
+# is never formed. The <cycle> count must be at least 2.
+#
+# Bugs: If a process is still writing to the file.0 and savelog
+# moved it to file.1 and compresses it, data could be lost.
+# Smail does not have this problem in general because it
+# restats files often.
+
+# common location
+PATH="X_UTIL_PATH_X:X_SECURE_PATH_X"; export PATH
+COMPRESS="X_COMPRESS_X"
+COMP_FLAG="X_COMP_FLAG_X"
+DOT_Z="X_DOT_Z_X"
+CHOWN="X_CHOWN_X"
+GETOPT="X_UTIL_BIN_DIR_X/getopt"
+
+# parse args
+exitcode=0 # no problems to far
+prog=$0
+mode=
+user=
+group=
+touch=
+count=7
+set -- `$GETOPT m:u:g:c:lt $*`
+if [ $# -eq 0 -o $? -ne 0 ]; then
+ echo "usage: $prog [-m mode][-u user][-g group][-t][-c cycle][-l] file ..." 1>&2
+ exit 1
+fi
+for i in $*; do
+ case $i in
+ -m) mode=$2; shift 2;;
+ -u) user=$2; shift 2;;
+ -g) group=$2; shift 2;;
+ -c) count=$2; shift 2;;
+ -t) touch=1; shift;;
+ -l) COMPRESS=""; shift;;
+ --) shift; break;;
+ esac
+done
+if [ "$count" -lt 2 ]; then
+ echo "$prog: count must be at least 2" 1>&2
+ exit 2
+fi
+
+# cycle thru filenames
+while [ $# -gt 0 ]; do
+
+ # get the filename
+ filename=$1
+ shift
+
+ # catch bogus files
+ if [ -b "$filename" -o -c "$filename" -o -d "$filename" ]; then
+ echo "$prog: $filename is not a regular file" 1>&2
+ exitcode=3
+ continue
+ fi
+
+ # if not a file or empty, do nothing major
+ if [ ! -s $filename ]; then
+ # if -t was given and it does not exist, create it
+ if [ ! -z "$touch" -a ! -f $filename ]; then
+ touch $filename
+ if [ "$?" -ne 0 ]; then
+ echo "$prog: could not touch $filename" 1>&2
+ exitcode=4
+ continue
+ fi
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $filename
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $filename
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $filename
+ fi
+ fi
+ continue
+ fi
+
+ # be sure that the savedir exists and is writable
+ savedir=`expr "$filename" : '\(.*\)/'`
+ if [ -z "$savedir" ]; then
+ savedir=./OLD
+ else
+ savedir=$savedir/OLD
+ fi
+ if [ ! -s $savedir ]; then
+ mkdir $savedir
+ if [ "$?" -ne 0 ]; then
+ echo "$prog: could not mkdir $savedir" 1>&2
+ exitcode=5
+ continue
+ fi
+ chmod 0755 $savedir
+ fi
+ if [ ! -d $savedir ]; then
+ echo "$prog: $savedir is not a directory" 1>&2
+ exitcode=6
+ continue
+ fi
+ if [ ! -w $savedir ]; then
+ echo "$prog: directory $savedir is not writable" 1>&2
+ exitcode=7
+ continue
+ fi
+
+ # deterine our uncompressed file names
+ newname=`expr "$filename" : '.*/\(.*\)'`
+ if [ -z "$newname" ]; then
+ newname=$savedir/$filename
+ else
+ newname=$savedir/$newname
+ fi
+
+ # cycle the old compressed log files
+ cycle=`expr $count - 1`
+ rm -f $newname.$cycle $newname.$cycle$DOT_Z
+ while [ "$cycle" -gt 1 ]; do
+ # --cycle
+ oldcycle=$cycle
+ cycle=`expr $cycle - 1`
+ # cycle log
+ if [ -f $newname.$cycle$DOT_Z ]; then
+ mv -f $newname.$cycle$DOT_Z $newname.$oldcycle$DOT_Z
+ fi
+ if [ -f $newname.$cycle ]; then
+ # file was not compressed for some reason move it anyway
+ mv -f $newname.$cycle $newname.$oldcycle
+ fi
+ done
+
+ # compress the old uncompressed log if needed
+ if [ -f $newname.0 ]; then
+ if [ -z "$COMPRESS" ]; then
+ newfile=$newname.1
+ mv $newname.0 $newfile
+ else
+ newfile=$newname.1$DOT_Z
+ $COMPRESS $COMP_FLAG < $newname.0 > $newfile
+ rm -f $newname.0
+ fi
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $newfile
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $newfile
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $newfile
+ fi
+ fi
+
+ # move the file into the file.0 holding place
+ mv -f $filename $newname.0
+
+ # replace file if needed
+ if [ ! -z "$touch" -o ! -z "$user" -o \
+ ! -z "$group" -o ! -z "$mode" ]; then
+ touch $filename
+ fi
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $filename
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $filename
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $filename
+ fi
+
+ # fix the permissions on the holding place file.0 file
+ if [ ! -z "$user" ]; then
+ $CHOWN $user $newname.0
+ fi
+ if [ ! -z "$group" ]; then
+ chgrp $group $newname.0
+ fi
+ if [ ! -z "$mode" ]; then
+ chmod $mode $newname.0
+ fi
+done
+exit $exitcode
diff --git a/gnu/libexec/uucp/contrib/stats.sh b/gnu/libexec/uucp/contrib/stats.sh
new file mode 100644
index 00000000000..ac1d0f556ee
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/stats.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# uuspeed - a script to parse a Taylor UUCP Stats file into pretty results.
+# Zacharias J. Beckman.
+
+grep bytes /usr/spool/uucp/Stats | grep -v 'bytes 0.00 secs' | grep -v 'failed after' | tail -80 | \
+gawk '
+ BEGIN {
+ printf(" UUCP transmission history:\n");
+ format=" %8d bytes %8s(%8s) in %7.2f sec = %5.0f baud, %4.1fK / min\n";
+ average=0.01;
+ samples=0;
+ }
+
+ {
+ if ($6 > 100) {
+ printf (format, $6, $5, $2, $9, $6/$9*10, ($6/$9*60)/1000);
+
+ average += ($6/$9*10);
+ samples += 1;
+ }
+ }
+
+ END {
+ printf (" average speed %d baud\n", average/samples);
+ }
+'
diff --git a/gnu/libexec/uucp/contrib/tstout.c b/gnu/libexec/uucp/contrib/tstout.c
new file mode 100644
index 00000000000..dd82633c7a0
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/tstout.c
@@ -0,0 +1,158 @@
+/* tstout.c
+ Put together by Ian Lance Taylor <ian@airs.com>
+
+ This program is used to logout a program run by the tstuu program.
+ I needed this because on Ultrix 4.0 I can't get the uucp program
+ to run without invoking it via /bin/login and having it start up
+ as a shell. If I don't do it this way, it gets a SIGSEGV trap
+ for some reason. Most systems probably don't need to do things
+ this way. It will only work on BSD systems anyhow, I suspect.
+
+ The code for this comes from "UNIX Network Programming" by W.
+ Richard Stevens, Prentice-Hall 1990. Most of it is from 4.3BSD, as
+ noted in the comments.
+
+ This program must run suid to root.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <utmp.h>
+
+static int logout P((const char *zdev));
+static void logwtmp P((const char *zdev, const char *zname,
+ const char *zhost));
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *z;
+
+ if (argc != 2
+ || strncmp (argv[1], "/dev/", sizeof "/dev/" - 1) != 0)
+ {
+ fprintf (stderr, "Usage: tstout device\n");
+ exit (EXIT_FAILURE);
+ }
+
+ z = argv[1] + 5;
+
+ if (logout (z))
+ logwtmp (z, "", "");
+
+ chmod (argv[1], 0666);
+ chown (argv[1], 0, 0);
+
+ *z = 'p';
+ chmod (argv[1], 0666);
+ chown (argv[1], 0, 0);
+
+ exit (EXIT_SUCCESS);
+}
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)logout.c 5.2 (Berkeley) 2/17/89";
+#endif /* LIBC_SCCS and not lint */
+
+#define UTMPFILE "/etc/utmp"
+
+/* 0 on failure, 1 on success */
+
+static int
+logout(line)
+ register const char *line;
+{
+ register FILE *fp;
+ struct utmp ut;
+ int rval;
+ time_t time();
+
+ if (!(fp = fopen(UTMPFILE, "r+")))
+ return(0);
+ rval = 0;
+ while (fread((char *)&ut, sizeof(struct utmp), 1, fp) == 1) {
+ if (!ut.ut_name[0] ||
+ strncmp(ut.ut_line, line, sizeof(ut.ut_line)))
+ continue;
+ bzero(ut.ut_name, sizeof(ut.ut_name));
+ bzero(ut.ut_host, sizeof(ut.ut_host));
+ (void)time((time_t *)&ut.ut_time);
+ (void)fseek(fp, (long)-sizeof(struct utmp), L_INCR);
+ (void)fwrite((char *)&ut, sizeof(struct utmp), 1, fp);
+ (void)fseek(fp, (long)0, L_INCR);
+ rval = 1;
+ }
+ (void)fclose(fp);
+ return(rval);
+}
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)logwtmp.c 5.2 (Berkeley) 9/20/88";
+#endif /* LIBC_SCCS and not lint */
+
+#define WTMPFILE "/usr/adm/wtmp"
+
+static void
+logwtmp(line, name, host)
+ const char *line, *name, *host;
+{
+ struct utmp ut;
+ struct stat buf;
+ int fd;
+ time_t time();
+ char *strncpy();
+
+ if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (!fstat(fd, &buf)) {
+ (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+ (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+ (void)time((time_t *)&ut.ut_time);
+ if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
+ sizeof(struct utmp))
+ (void)ftruncate(fd, buf.st_size);
+ }
+ (void)close(fd);
+}
diff --git a/gnu/libexec/uucp/contrib/uuclean b/gnu/libexec/uucp/contrib/uuclean
new file mode 100644
index 00000000000..1cfb6332bfb
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uuclean
@@ -0,0 +1,25 @@
+# This is a sample uuclean shell script
+# Copyright (C) 1992 Ian Lance Taylor
+# Do whatever you like with this script.
+#
+# Set some variables
+bindir=/usr/local/bin
+spooldir=/usr/spool/uucp
+#
+# Warn about all mail over two days old
+$(bindir)/uustat -c rmail -o 48 -N -Q -W"Unable to deliver; will try up to one week"
+# Return all mail over a week old
+$(bindir)/uustat -c rmail -o 168 -K -M -N -Q -W"Could not be delivered for over one week"
+# Throw away other requests over a week old
+$(bindir)/uustat -o 168 -K -M -N -Q -W"Over one week old"
+# Throw away any executions over three days old
+$(bindir)/uustat -o 72 -M -N -Q -W"Unable to execute for three days"
+#
+# Now delete any old spool files
+find $(spooldir) -ctime +8 -name '[CDX].*' -print -exec rm -f \{\} \;
+# Delete any old temporary files
+find $(spooldir) -atime +1 -ctime +1 -name 'TM.*' -print -exec rm -f \{\} \;
+# Delete any old preserved files
+find $(spooldir)/.Preserve -atime +14 -ctime +14 -print -exec rm -f \{\} \;
+# Delete any old failed execution files
+find $(spooldir)/.Failed -atime +14 -ctime +14 -print -exec rm -f \{\} \;
diff --git a/gnu/libexec/uucp/contrib/uucomp.shar b/gnu/libexec/uucp/contrib/uucomp.shar
new file mode 100644
index 00000000000..da131d048c5
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uucomp.shar
@@ -0,0 +1,552 @@
+#! /bin/sh
+#
+# Created by shar, version 0.5 - 04/10/91
+#
+# This is a shell archive, meaning:
+# 1. Remove everything about the #! /bin/sh line.
+# 2. Save the resulting text in a file.
+# 3. Execute the file with /bin/sh to create:
+#
+# length name
+# ------ -------------------------------------
+# 128 uucomp-1.1/Compress
+# 264 uucomp-1.1/Copyright
+# 410 uucomp-1.1/INTERNALS
+# 1069 uucomp-1.1/Makefile
+# 3528 uucomp-1.1/README
+# 632 uucomp-1.1/crmail.c
+# 632 uucomp-1.1/crnews.c
+# 108 uucomp-1.1/tags
+# 3506 uucomp-1.1/uucomp.c
+# 383 uucomp-1.1/uucomp.h
+#
+
+if test ! -d uucomp-1.1 ; then
+ mkdir uucomp-1.1
+fi
+#
+# Archive number 1
+# This archive created Tue Sep 28 20:21:14 1993
+#
+
+echo "shar: extracting uucomp-1.1/Compress - (128 characters)"
+if test -f 'uucomp-1.1/Compress' ; then
+ echo shar: will not over-write existing file uucomp-1.1/Compress
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/Compress'
+Xfor i in $*
+Xdo
+X if [ -d /usr/spool/uucp/$i ]
+X then
+X# echo Looking at $i
+X cd /usr/spool/uucp/$i
+X /usr/bin/uucomp C.*
+X fi
+Xdone
+SHAR_EOF
+if test 128 -ne "`wc -c < 'uucomp-1.1/Compress'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/Compress (should have been 128 characters, but was "`wc -c < 'uucomp-1.1/Compress'`" characters) *****"
+fi
+fi
+
+touch 0715110393 uucomp-1.1/Compress
+chmod 0700 uucomp-1.1/Compress
+
+echo "shar: extracting uucomp-1.1/Copyright - (264 characters)"
+if test -f 'uucomp-1.1/Copyright' ; then
+ echo shar: will not over-write existing file uucomp-1.1/Copyright
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/Copyright'
+X
+X/*
+X *
+X * Copyright 1993 by Ed Carp (erc@apple.com) All rights reserved.
+X *
+X * Permission is hereby granted for any non-commercial use of this
+X * program, as long as this copyright notice remains intact. Commercial
+X * users may contact me - I'm easy.
+X *
+X */
+X
+SHAR_EOF
+if test 264 -ne "`wc -c < 'uucomp-1.1/Copyright'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/Copyright (should have been 264 characters, but was "`wc -c < 'uucomp-1.1/Copyright'`" characters) *****"
+fi
+fi
+
+touch 0715174993 uucomp-1.1/Copyright
+chmod 0600 uucomp-1.1/Copyright
+
+echo "shar: extracting uucomp-1.1/INTERNALS - (410 characters)"
+if test -f 'uucomp-1.1/INTERNALS' ; then
+ echo shar: will not over-write existing file uucomp-1.1/INTERNALS
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/INTERNALS'
+XThis is the basic workflow for uucomp:
+X
+Xfor (every argv)
+Xdo
+X if not "C." file skip
+X if open fail, skip
+X read 1 line from C. file
+X grab second and 10th field (second is data file name,
+X 10th is command name)
+X if open fail on second field, skip
+X if 10th field isn't "rmail" or "rnews", skip
+X execute "gzip -9" on second field
+X change "rmail" and "rnews" to "crmail" and "crnews", respectively
+X in C. file
+Xdone
+SHAR_EOF
+if test 410 -ne "`wc -c < 'uucomp-1.1/INTERNALS'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/INTERNALS (should have been 410 characters, but was "`wc -c < 'uucomp-1.1/INTERNALS'`" characters) *****"
+fi
+fi
+
+touch 0715174693 uucomp-1.1/INTERNALS
+chmod 0600 uucomp-1.1/INTERNALS
+
+echo "shar: extracting uucomp-1.1/Makefile - (1069 characters)"
+if test -f 'uucomp-1.1/Makefile' ; then
+ echo shar: will not over-write existing file uucomp-1.1/Makefile
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/Makefile'
+X#
+X# Makefile generated with genmake - version 1.1 08/22/92
+X#
+X# genmake is Copyright 1991 by Edwin R. Carp
+X#
+X# GENMAKE -B/usr/bin -tsp [files]
+X#
+X
+XCC = gcc -O6
+XCFLAGS = $(INCLUDE)
+XSOURCES = crmail.c crnews.c uucomp.c
+XOBJECTS = crmail.o crnews.o uucomp.o
+XPROGRAMS = /usr/bin/crmail /usr/bin/crnews /usr/bin/uucomp
+X
+Xall: $(PROGRAMS) tags
+X
+X/usr/bin/crmail: crmail.o
+X $(CC) $(CFLAGS) -o crmail crmail.o $(LDFLAGS) -O
+X strip crmail
+X chmod 755 crmail
+X mv crmail /usr/bin
+X
+X/usr/bin/crnews: crnews.o
+X $(CC) $(CFLAGS) -o crnews crnews.o $(LDFLAGS) -O
+X strip crnews
+X chmod 755 crnews
+X mv crnews /usr/bin
+X
+X/usr/bin/uucomp: uucomp.o
+X $(CC) $(CFLAGS) -o uucomp uucomp.o $(LDFLAGS) -O
+X strip uucomp
+X chmod 755 uucomp
+X mv uucomp /usr/bin
+X
+Xclean:
+X /bin/rm -f $(OBJECTS) MAKELOG eddep makedep
+X
+Xclobber:
+X /bin/rm -f $(OBJECTS) $(PROGRAMS) MAKELOG eddep makedep *~ *.bak *.BAK
+X /bin/rm -f tags
+X
+Xhidden:
+X echo "make all > MAKELOG 2>&1 &"|/bin/sh
+X
+Xmakefile:
+X genmake -B/usr/bin -tsp $(SOURCES) &
+X
+Xmakeall:
+X genmake -B/usr/bin -tsp *.c &
+X
+Xtags: $(SOURCES)
+X ctags $(SOURCES) > tags
+X
+SHAR_EOF
+if test 1069 -ne "`wc -c < 'uucomp-1.1/Makefile'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/Makefile (should have been 1069 characters, but was "`wc -c < 'uucomp-1.1/Makefile'`" characters) *****"
+fi
+fi
+
+touch 0714235093 uucomp-1.1/Makefile
+chmod 0600 uucomp-1.1/Makefile
+
+echo "shar: extracting uucomp-1.1/README - (3528 characters)"
+if test -f 'uucomp-1.1/README' ; then
+ echo shar: will not over-write existing file uucomp-1.1/README
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/README'
+XLike most people these days, I'm looking for ways to make my computing
+Xenvironment more efficient. This environment consists of a 486, a 386,
+Xand a 386SL laptop, all of which run Taylor uucp under Linux. The 386
+Xlaptop gets used a lot, since it goes wherever I go and I answer a lot
+Xof news and email every day. Often, I must use other people's facilities
+X(phone lines and such) to send out replies and post news if I'm not at home.
+XSince it's not fair to the client for them to pay for my zone calls back
+Xto my home in Fremont, I place the calls on my phone card. Unfortunately,
+XPacBell is very proud of the services they offer, especially in regards
+Xto this convenience of automatically charging calls to my house wherever I
+Xmay be. Considering that this can be very expensive to do, I searched for
+Xa way to cut my phone bill down to something I could afford to pay each
+Xmonth without fainting every time I saw the bill.
+X
+XThe first thing I did was to go out and plunk $195 for a 14.4KB modem.
+XThat helped, but C-News is very slow on my laptop, and batching articles
+Xis even slower, and email (of course) isn't batched at all. Even with
+XMNP5 compression turned on, this doesn't make for a very efficient setup,
+Xeven at high speeds.
+X
+XPlaying around with uucp told me that the line turnaround wasn't that much
+Xoverhead, nor was sending the C./X. files (the execute files) - the real
+Xoverhead was sending out uncompressed news and especially email, since
+XI subscribe to several mailing lists and digests can run quite large.
+X
+XI looked at uubatch, but the most current version I could find (1.05) was
+Xnot compatible with Taylor uucp (and I had no other alternative), so I
+Xdecided to write my own. Experiments with "gzip -9" convinced me that
+Xthat was the way to go, since gzip gives email and news 60 to 75 percent
+Xcompression, which would tend to cut one's phone bill significantly.
+X
+XYou hold in your mailbox (or news reader) the end result of that effort.
+XBear in mind that (1) this is a "first cut" and while it is unlikely that
+Xthere are very many bugs, there are certainly places where the programs could
+Xbe improved and tuned. Suggestions and comments are welcome!
+X
+XTo install:
+X
+X 1. Feed this to shar.
+X 2. Look at the Makefile. Make sure that the paths for
+X things are set up correctly.
+X 3. Look at uucomp.h and make sure that the path and
+X options for COMPRESS/UNCOMPRESS are set up properly.
+X 3. Type "make". This will make uucomp, crmail, and crnews
+X and will place them in /usr/bin. Move Compress into
+X /usr/lib/uucp.
+X 4. Make an entry in crontab to do
+X /usr/lib/uucp/Compress site1 site2 site3...
+X occasionally. It is suggested that this be done fairly
+X frequently. Alternately, you could set up a login shell
+X for selected sites to run uucomp every time that site
+X logged in.
+X 5. Don't forget to add /usr/bin/crmail and /usr/bin/crnews
+X to the list of programs allowed to be executed in your
+X Permissions file (if running HDB UUCP), or whatever is
+X appropriate for your version of uucp.
+X
+XEnjoy! Any questions or comments can be sent to erc@apple.com.
+X
+XNote: This is tuned for Taylor uucp, but would not be particularly
+Xdifficult to adapt to other version of uucp. See the file INTERNALS for
+Xdetails of how this works.
+X
+XJuly 15, 1993
+XEd Carp
+Xerc@apple.com
+X------------------------------------------------------------------------------
+XChanges since 1.0:
+X
+X Version Date Description
+X
+X 1.1 08/04/93 Added sanity check in C. file (check that
+X 'E' is first char in file, otherwise skip)
+SHAR_EOF
+if test 3528 -ne "`wc -c < 'uucomp-1.1/README'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/README (should have been 3528 characters, but was "`wc -c < 'uucomp-1.1/README'`" characters) *****"
+fi
+fi
+
+touch 0804224993 uucomp-1.1/README
+chmod 0600 uucomp-1.1/README
+
+echo "shar: extracting uucomp-1.1/crmail.c - (632 characters)"
+if test -f 'uucomp-1.1/crmail.c' ; then
+ echo shar: will not over-write existing file uucomp-1.1/crmail.c
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/crmail.c'
+X/*
+X * crmail - get compressed mail from host, uncompress
+X * WARNING: This may be insecure!
+X */
+X
+X/*
+X *
+X * Copyright 1993 by Ed Carp (erc@apple.com) All rights reserved.
+X *
+X * Permission is hereby granted for any non-commercial use of this
+X * program, as long as this copyright notice remains intact. Commercial
+X * users may contact me - I'm easy.
+X *
+X */
+X
+X#include <stdio.h>
+X#include "uucomp.h"
+Xmain (argc, argv)
+Xint argc;
+Xchar **argv;
+X{
+X char cmd[1024];
+X int i;
+X
+X sprintf (cmd, "%s|%s ", UNCOMPRESS, RMAIL);
+X for (i = 1; i < argc; i++)
+X {
+X strcat (cmd, argv[i]);
+X strcat (cmd, " ");
+X }
+X system (cmd);
+X exit (0);
+X}
+SHAR_EOF
+if test 632 -ne "`wc -c < 'uucomp-1.1/crmail.c'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/crmail.c (should have been 632 characters, but was "`wc -c < 'uucomp-1.1/crmail.c'`" characters) *****"
+fi
+fi
+
+touch 0715195493 uucomp-1.1/crmail.c
+chmod 0600 uucomp-1.1/crmail.c
+
+echo "shar: extracting uucomp-1.1/crnews.c - (632 characters)"
+if test -f 'uucomp-1.1/crnews.c' ; then
+ echo shar: will not over-write existing file uucomp-1.1/crnews.c
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/crnews.c'
+X/*
+X * crnews - get compressed news from host, uncompress
+X * WARNING: This may be insecure!
+X */
+X
+X/*
+X *
+X * Copyright 1993 by Ed Carp (erc@apple.com) All rights reserved.
+X *
+X * Permission is hereby granted for any non-commercial use of this
+X * program, as long as this copyright notice remains intact. Commercial
+X * users may contact me - I'm easy.
+X *
+X */
+X
+X#include <stdio.h>
+X#include "uucomp.h"
+Xmain (argc, argv)
+Xint argc;
+Xchar **argv;
+X{
+X char cmd[1024];
+X int i;
+X
+X sprintf (cmd, "%s|%s ", UNCOMPRESS, RNEWS);
+X for (i = 1; i < argc; i++)
+X {
+X strcat (cmd, argv[i]);
+X strcat (cmd, " ");
+X }
+X system (cmd);
+X exit (0);
+X}
+SHAR_EOF
+if test 632 -ne "`wc -c < 'uucomp-1.1/crnews.c'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/crnews.c (should have been 632 characters, but was "`wc -c < 'uucomp-1.1/crnews.c'`" characters) *****"
+fi
+fi
+
+touch 0715195593 uucomp-1.1/crnews.c
+chmod 0600 uucomp-1.1/crnews.c
+
+echo "shar: extracting uucomp-1.1/tags - (108 characters)"
+if test -f 'uucomp-1.1/tags' ; then
+ echo shar: will not over-write existing file uucomp-1.1/tags
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/tags'
+Xmain crmail.c /^main (argc, argv)$/
+Xmain crnews.c /^main (argc, argv)$/
+Xmain uucomp.c /^main (argc, argv)$/
+SHAR_EOF
+if test 108 -ne "`wc -c < 'uucomp-1.1/tags'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/tags (should have been 108 characters, but was "`wc -c < 'uucomp-1.1/tags'`" characters) *****"
+fi
+fi
+
+touch 0804224993 uucomp-1.1/tags
+chmod 0600 uucomp-1.1/tags
+
+echo "shar: extracting uucomp-1.1/uucomp.c - (3506 characters)"
+if test -f 'uucomp-1.1/uucomp.c' ; then
+ echo shar: will not over-write existing file uucomp-1.1/uucomp.c
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/uucomp.c'
+X/*
+X * uucomp - compress outgoing news/mail
+X *
+X * usage: uucomp C.*
+X *
+X * This works for Taylor uucp (available from prep.ai.mit.edu:/pub/gnu/uucp*),
+X * but I don't promise it works for anyone else's uucp package. Basically, this
+X * is a quick-n-dirty hack to get compressed mail and news to a uucp site. This
+X * becomes important when you're on the other end of a 1200 baud packet radio
+X * link, where the throughput can be 60 CPS (or lower). It also tends to hide
+X * any nasties that people might want to say to you, since the packets *are*
+X * public readable. Yes, I looked at uubatch, but it was too complicated for
+X * me to figure out <grin>, and it didn't work with Taylor-uucp. This is almost
+X * too simple to work...
+X *
+X * To use this little guy, do something like this in the .bashrc or .profile
+X * or .cshrc of the uucp's login shell:
+X *
+X * cd /usr/spool/uucp/<wherever the C. and D. files are kept>
+X * /usr/bin/uucomp C.*
+X * exec /usr/lib/uucp/uucico
+X *
+X * This program was written by Ed Carp (erc@apple.com). It can be used for any
+X * non-commercial purpose. This software is freely redistributable.
+X */
+X
+X/*
+X *
+X * Copyright 1993 by Ed Carp (erc@apple.com) All rights reserved.
+X *
+X * Permission is hereby granted for any non-commercial use of this
+X * program, as long as this copyright notice remains intact. Commercial
+X * users may contact me - I'm easy.
+X *
+X */
+X
+X#include <stdio.h>
+X#include "uucomp.h"
+X#undef NULL
+X#define NULL (0)
+Xmain (argc, argv)
+Xint argc;
+Xchar **argv;
+X{
+X int i, j, sw, ctr = 0, errflag = 0, mctr = 0, nctr = 0, skipctr = 0;
+X char scr[64], rcmd[10], line[1024], lineout[1024];
+X char *strtok (), *ptr, *lineptr, compfile[32];
+X FILE *in;
+X
+X printf ("uucomp 1.1 08/04/93 ... by erc@apple.com\nscanning %d files.", argc - 1);
+X for (i = 1; i < argc; i++)
+X {
+X if (strncmp (argv[i], "C.", 2) != 0)
+X {
+X skipctr++;
+X continue;
+X }
+X if ((in = fopen (argv[i], "r+")) == (FILE *) NULL)
+X {
+X skipctr++;
+X continue;
+X }
+X fgets (line, 1022, in);
+X if(*line != 'E')
+X {
+X skipctr++;
+X continue;
+X }
+X line[strlen (line) - 1] = NULL;
+X rewind (in);
+X *lineout = NULL;
+X lineptr = line;
+X sw = errflag = 0;
+X printf (".");
+X fflush (stdout);
+X for (j = 0;; j++)
+X {
+X ptr = strtok (lineptr, " ");
+X if (ptr == NULL)
+X break;
+X lineptr = NULL;
+X if (j == 1)
+X {
+X if (access (ptr, 4) == EOF)
+X {
+X#ifdef DEBUG
+X printf ("skip: file '%s' doesn't exist\n", ptr);
+X#endif
+X errflag = 1;
+X break; /*
+X * skip it if the data file isn't
+X * there yet
+X */
+X }
+X strcpy (compfile, ptr);
+X }
+X if (j == 9)
+X {
+X if (strcmp (ptr, "rmail") != 0 && strcmp (ptr, "rnews") != 0)
+X {
+X#ifdef DEBUG
+X printf ("skip: '%s' wrong command\n", ptr);
+X#endif
+X errflag = 1;
+X break;
+X }
+X if (strcmp (ptr, "rmail") == 0)
+X mctr++;
+X if (strcmp (ptr, "rnews") == 0)
+X nctr++;
+X sw = 1;
+X strcat (lineout, "c");
+X }
+X strcat (lineout, ptr);
+X strcat (lineout, " ");
+X }
+X if (errflag == 1)
+X {
+X skipctr++;
+X fclose (in);
+X continue;
+X }
+X fprintf (in, "%s\n", lineout);
+X fclose (in);
+X sprintf (line,
+X "%s -fc > /tmp/uucomp.%d < %s;cp /tmp/uucomp.%d %s",
+X COMPRESS, getpid (), compfile, getpid (), compfile);
+X system (line);
+X ctr++;
+X }
+X sprintf (line, "/tmp/uucomp.%d", getpid ());
+X unlink (line);
+X printf ("\n%d skipped, %d compressed (%d mail, %d news).\n",
+X skipctr, ctr, mctr, nctr);
+X exit (0);
+X}
+SHAR_EOF
+if test 3506 -ne "`wc -c < 'uucomp-1.1/uucomp.c'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/uucomp.c (should have been 3506 characters, but was "`wc -c < 'uucomp-1.1/uucomp.c'`" characters) *****"
+fi
+fi
+
+touch 0804224693 uucomp-1.1/uucomp.c
+chmod 0600 uucomp-1.1/uucomp.c
+
+echo "shar: extracting uucomp-1.1/uucomp.h - (383 characters)"
+if test -f 'uucomp-1.1/uucomp.h' ; then
+ echo shar: will not over-write existing file uucomp-1.1/uucomp.h
+else
+sed 's/^X//' << \SHAR_EOF > 'uucomp-1.1/uucomp.h'
+X/*
+X *
+X * Copyright 1993 by Ed Carp (erc@apple.com) All rights reserved.
+X *
+X * Permission is hereby granted for any non-commercial use of this
+X * program, as long as this copyright notice remains intact. Commercial
+X * users may contact me - I'm easy.
+X *
+X */
+X
+X#define COMPRESS "/usr/bin/gzip -9c"
+X#define UNCOMPRESS "/usr/bin/gzip -dc"
+X#define RMAIL "rmail"
+X#define RNEWS "rnews"
+SHAR_EOF
+if test 383 -ne "`wc -c < 'uucomp-1.1/uucomp.h'`" ; then
+ echo "shar: ***** error transmitting file uucomp-1.1/uucomp.h (should have been 383 characters, but was "`wc -c < 'uucomp-1.1/uucomp.h'`" characters) *****"
+fi
+fi
+
+touch 0715190293 uucomp-1.1/uucomp.h
+chmod 0600 uucomp-1.1/uucomp.h
+echo End of all shell archives
+exit 0
diff --git a/gnu/libexec/uucp/contrib/uudemon.shar b/gnu/libexec/uucp/contrib/uudemon.shar
new file mode 100644
index 00000000000..31a8fa60707
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uudemon.shar
@@ -0,0 +1,82 @@
+#! /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: Poll uudemon.poll
+# Wrapped by dburr@sbanet on Fri Jul 23 20:15:18 1993
+PATH=/bin:/usr/bin:/usr/ucb ; export PATH
+if test -f 'Poll' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'Poll'\"
+else
+echo shar: Extracting \"'Poll'\" \(244 characters\)
+sed "s/^X//" >'Poll' <<'END_OF_FILE'
+X# HDB-ish poll file
+X#
+X# Format: <site><tab><hour1> <hour2> ...
+X# ONLY ONE TAB BETWEEN FIELDS... more may work, but I have absolutely no
+X# idea if it will work at all.
+X#
+X# comment lines (begin with `#') are ignored.
+X
+Xdschub 20 21 22
+Xgd 20 21 22
+END_OF_FILE
+if test 244 -ne `wc -c <'Poll'`; then
+ echo shar: \"'Poll'\" unpacked with wrong size!
+fi
+# end of 'Poll'
+fi
+if test -f 'uudemon.poll' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'uudemon.poll'\"
+else
+echo shar: Extracting \"'uudemon.poll'\" \(941 characters\)
+sed "s/^X//" >'uudemon.poll' <<'END_OF_FILE'
+X#!/bin/sh
+X#
+X# This is my impersonation of the HDB uudemon.poll script.
+X# Yes, I know, this is very clumsy and clunky... ahh well, I've always
+X# been better at C/pascal/etc than Shell programming... :(
+X
+X# change LIBDIR to where UUCP library/conf. files are
+X# change SPOOLDIR to the UUCP spool directory. It must be HDB-ish.
+XLIBDIR=/usr/lib/uucp; export LIBDIR
+XSPOOLDIR=/usr/spool/uucp; export SPOOLDIR
+X
+X### no changes needed past here ###
+X
+XHOUR=`date +%H`; export HOUR
+X
+Xif [ -f ${LIBDIR}/Poll ]; then
+X for SYS in `uuname`
+X do
+X CHOICES="`grep "^$SYS[ ]" ${LIBDIR}/Poll | awk -F' ' \
+X '{ print $2 }'`"
+X DOIT="no"
+X for H in $CHOICES
+X do
+X if [ "$HOUR" = "$H" ]; then
+X DOIT="yes"
+X fi
+X done
+X if [ "$DOIT" = "yes" ]; then
+X if [ ! -d ${SPOOLDIR}/${SYS} ]; then
+X mkdir ${SPOOLDIR}/${SYS}
+X fi
+X chmod 755 ${SPOOLDIR}/${SYS}
+X touch ${SPOOLDIR}/${SYS}/C.${SYS}n0000
+X chmod 644 ${SPOOLDIR}/${SYS}/C.${SYS}n0000
+X fi
+X done
+Xfi
+END_OF_FILE
+if test 941 -ne `wc -c <'uudemon.poll'`; then
+ echo shar: \"'uudemon.poll'\" unpacked with wrong size!
+fi
+chmod +x 'uudemon.poll'
+# end of 'uudemon.poll'
+fi
+echo shar: End of shell archive.
+exit 0
diff --git a/gnu/libexec/uucp/contrib/uupoll.shar b/gnu/libexec/uucp/contrib/uupoll.shar
new file mode 100644
index 00000000000..84a95e04e88
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uupoll.shar
@@ -0,0 +1,2705 @@
+#!/bin/sh
+# This is a shell archive (produced by shar 3.49)
+# To extract the files from this archive, save it to a file, remove
+# everything above the "!/bin/sh" line above, and type "sh file_name".
+#
+# made 04/17/1994 02:21 UTC by ian@comton.airs.com
+# Source directory /disk4/ian
+#
+# existing files will NOT be overwritten unless -c is specified
+#
+# This shar contains:
+# length mode name
+# ------ ---------- ------------------------------------------
+# 2602 -r--r--r-- uupoll/Makefile
+# 3636 -r--r--r-- uupoll/README
+# 4718 -r--r--r-- uupoll/autopoll.8c
+# 44031 -r--r--r-- uupoll/autopoll.c
+# 3884 -r--r--r-- uupoll/conf.h
+# 4787 -r--r--r-- uupoll/uupoll.8c
+# 27587 -r--r--r-- uupoll/uupoll.c
+#
+# ============= uupoll/Makefile ==============
+if test ! -d 'uupoll'; then
+ echo 'x - creating directory uupoll'
+ mkdir 'uupoll'
+fi
+if test -f 'uupoll/Makefile' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/Makefile (File already exists)'
+else
+echo 'x - extracting uupoll/Makefile (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/Makefile' &&
+# This is the Makefile for uupoll and autopoll
+# borrowed and hacked from Taylor UUCP 1.04
+X
+# Prefix directory for installation directories.
+prefix = /usr/local
+X
+# The user name/group that should own the resulting executables.
+# Both should run suid.
+owner = uucp.daemon
+X
+# Which mode should the resulting executables have.
+emode = 4111
+X
+# Where to install autopoll. This definition requires $(prefix)/lib to exist.
+lbindir = $(prefix)/lib/uucp
+X
+# Where are the sources from uucp-Taylor uucp.h, uuconf.h, policy.h.
+# the following assumes that our sources are in uucp-1.05/contrib/uupoll
+# and the required .h files are in main directory for uucp-1.05
+uucpsrcs = ../../
+X
+# Where to install uupoll
+bbindir = $(prefix)/bin
+X
+# Where to install man pages. Section 8 for daemons.
+man8dir = $(prefix)/man/man8
+man8ext = .8c
+X
+# Define programs and flags
+CC = gcc
+CFLAGS = -O2
+LDFLAGS = -s
+LIBS =
+X
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL) -m 644
+X
+#
+# Nothing else to configure
+#
+X
+SHELL = /bin/sh
+X
+VERSION = 1.00
+X
+MORECFLAGS = -I. -I$(uucpsrcs) -Wall
+X
+PROGRAMS = uupoll autopoll
+X
+UUPOLLOBJS = uupoll.o
+AUTOOBJS = autopoll.o
+X
+ALLOBJS = uupoll.o autopoll.o
+X
+all: $(PROGRAMS)
+X
+install: $(PROGRAMS)
+X if test -d $(lbindir); then true; else mkdir $(lbindir); fi
+X if test -d $(bbindir); then true; else mkdir $(bbindir); fi
+X -if test -f $(lbindir)/autopoll.old; then rm -f $(lbindir)/autopoll; else mv $(lbindir)/autopoll $(lbindir)/autopoll.old; fi
+X -if test -f $(bbindir)/uupoll.old; then rm -f $(bbindir)/uupoll; else mv $(bbindir)/uupoll $(bbindir)/uupoll.old; fi
+X $(INSTALL_PROGRAM) autopoll $(lbindir)/autopoll
+X $(INSTALL_PROGRAM) uupoll $(bbindir)/uupoll
+X chown $(owner) $(lbindir)/autopoll $(bbindir)/uupoll
+X chmod $(emode) $(lbindir)/autopoll $(bbindir)/uupoll
+X $(INSTALL_DATA) uupoll.8c $(man8dir)/uupoll$(man8ext)
+X $(INSTALL_DATA) autopoll.8c $(man8dir)/autopoll$(man8ext)
+X
+uninstall:
+X rm -f $(lbindir)/autopoll $(bbindir)/uupoll
+X rm -f $(man8dir)/autopoll$(man8ext) $(man8dir)/uupoll$(man8ext)
+X -cp $(lbindir)/autopoll.old $(lbindir)/autopoll
+X -cp $(bbindir)/uupoll.old $(bbindir)/uupoll
+X -chown $(owner) $(lbindir)/autopoll $(bbindir)/uupoll
+X -chmod $(emode) $(lbindir)/autopoll $(bbindir)/uupoll
+X
+uupoll: $(UUPOLLOBJS)
+X $(CC) $(LDFLAGS) -o uupoll $(UUPOLLOBJS) $(LIBS)
+X
+autopoll: $(AUTOOBJS)
+X $(CC) $(LDFLAGS) -o autopoll $(AUTOOBJS) $(LIBS)
+X
+.c.o:
+X $(CC) -c $(CFLAGS) $(MORECFLAGS) $<
+X
+X
+clean:
+X rm -f $(ALLOBJS) $(PROGRAMS)
+X
+mostlyclean: clean
+X
+TAGS:
+X etags *.h *.c
+X
+# Header file dependencies. These are maintained by hand.
+X
+$(ALLOBJS): conf.h
+X
+.NOEXPORT:
+SHAR_EOF
+chmod 0444 uupoll/Makefile ||
+echo 'restore of uupoll/Makefile failed'
+Wc_c="`wc -c < 'uupoll/Makefile'`"
+test 2602 -eq "$Wc_c" ||
+ echo 'uupoll/Makefile: original size 2602, current size' "$Wc_c"
+fi
+# ============= uupoll/README ==============
+if test -f 'uupoll/README' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/README (File already exists)'
+else
+echo 'x - extracting uupoll/README (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/README' &&
+X
+The package consists of the following files:
+X
+X - autopoll.c
+X - autopoll.8c
+X - conf.h
+X - Makefile
+X - README
+X - uupoll.c
+X - uupoll.8c
+X
+CAVEAT:
+uupoll as well as autopoll are created, tested and run on
+a NeXT running NeXTstep 2.1+ only! Autopoll will take the same arguments
+as uucico and may well work with them the same way uucico works but it
+has only been tested to call uucico with the options:
+X
+X -s<site> -S<site> -f -r1 -C -D (as well as the long form of these options)
+X
+so far. All options given to autopoll will be passed verbatim to uucico.
+X
+DESCRIPTION:
+The program uupoll was created to be a full replacement for the vendor
+supplied one on a NeXT computer. That uupoll checked any site name against
+the "hardwired" L.sys and did end with a "Bus error" if the site could not
+be found. There was no source available to modify so it had to be created
+from scratch.
+The program autopoll has no equivalent an the NeXT. The intentions behind
+it was to automate the task of rescheduling any failed call. It may be
+started by an entry in the crontab tables in just the same way uucico is
+started (it will start uucico):
+X
+05 5 * * * uucp /usr/local/lib/uucp/autopoll -r1 >>/tmp/poll.log 2>&1
+X
+Any messages go to stderr or a file (if compiled with that option); in case
+the file could not be opened it will use stdout to tell you just that and quit.
+To catch any output one may place the string
+X
+X >>/tmp/poll.log 2>&1
+X
+into the command line as well. Uupoll as well as autopoll will place only
+a start message into the logfiles in case they are invoked manually from
+the shell.
+If the call fails autopoll will reschedule uucico for a later time by means
+of an AT job.
+The messages given by uupoll and autopoll carry an indicator to inform about
+the nature of an error; they are:
+X
+- (I) informal message; such as ".. started" ".. ended".
+- (W) there might be an error but the program decided to go ahead.
+X The exit code will be at least 4.
+- (E) a severe error was encountered that either aborts the whole run or
+X only the task for one site will be aborted.
+X The exit code will be at least 8.
+- (C) a catastrophic error has been found such as unable to fork. The run
+X is aborted.
+X The exit code will be at least 16.
+The final message will show the exit code the programm has terminated with.
+X
+For more information see the man pages or look into the source.
+X
+INSTALLATION:
+all files should be placed in one folder. Then examine and change the files
+Makefile and conf.h to meet your needs. To compile uupoll some files of
+uucp must be available (see Makefile: uucpsrcs)
+If not already there change to the directory which contain the files and type:
+X
+make
+X
+this should compile UUPOLL and AUTOPOLL. There should only be a warning
+that rcsid is defined but not used.
+Before actually installing you should test the programs to be working as
+desired.
+Then check the Makefile for the final placement of the modules and the man
+pages. Make sure the ownership and setuid is what you need on your machine
+to run the program(s).
+Then su to root and type:
+X
+make install
+X
+which should install the above programs and the man pages in the appropriate
+directories.
+Some word on the coding: have mercy! This is my second project in 'C'; any
+suggestions that may improve the style/coding are welcome however.
+X
+In case of any problems that can't be solved feel free to contact the
+author at:
+X
+Klaus Dahlenburg Timezone : GMT + 2
+P.O.Box 1267 email : kdburg@incoahe.hanse.de
+D-21249 Tostedt Fax : +49 4287 676
+X Germany Voice : +49 4287 681
+X
+Have fun!
+SHAR_EOF
+chmod 0444 uupoll/README ||
+echo 'restore of uupoll/README failed'
+Wc_c="`wc -c < 'uupoll/README'`"
+test 3636 -eq "$Wc_c" ||
+ echo 'uupoll/README: original size 3636, current size' "$Wc_c"
+fi
+# ============= uupoll/autopoll.8c ==============
+if test -f 'uupoll/autopoll.8c' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/autopoll.8c (File already exists)'
+else
+echo 'x - extracting uupoll/autopoll.8c (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/autopoll.8c' &&
+.\"
+.\" @(#)autopoll.8c 1.4 (incoahe) 5/09/1993
+.\"
+.TH AUTOPOLL 8C "May 09, 1993"
+.UC 6
+.SH NAME
+autopoll \- automatic \s-1UUCP\s+1 file transfer supervisor
+.SH SYNOPSIS
+.B autopoll
+[
+.BI options
+]
+.SH DESCRIPTION
+file transfer requests placed by
+.IR uucp (1)
+or
+.IR uux (1)
+are handled by
+.IR uucico (8C).
+.IR uucico
+will be invoked immediately by the above programs unless the \-r
+option is given which queues the request for later processing. This
+is typically done by entries in the
+.IR crontab
+table(s) which will invoke
+.IR uucico.
+.IR uucico
+can also be invoked by
+.IR uupoll (8C).
+All methods have in common that there is no automatic retry by
+.IR uucico
+itself in case the call failed for some reason.
+Either manual
+intervention or some sort of scripts must be used to overcome this
+limitation.
+.PP
+.IR Autopoll
+can be used to automate up to a certain degree the task of rescheduling
+a call. None of the standard programs already mentioned need to be
+modified to get this working. Also not recommended (see BUGS section)
+.IR uucico
+may be an alias to
+.IR autopoll
+as all arguments passed to
+.IR autopoll
+will be copied verbatim to
+.IR uucico.
+In case this is done by link or other means the original
+.I uucio
+must still be available in a directory outside of the normal search path
+otherwise
+.I autopoll
+can't do what it's intended to do and will form a loop.
+.PP
+When
+.IR autopoll
+is called thre will be a check on the \-s, \-S and \-f option to
+see whether this
+is a specific call or not. Also the \-S and the \-f option must be checked
+to determine the type of call: honor any imposed wait for a site or not.
+Any call to ourself or to an unknown site will be refused. The known sites
+will be obtained by a call to
+.IR uuname(1).
+All other options will not be checked in any way. Next to this
+.IR uucico
+is called and the exit code is checked for a `1' which indicates that the call
+failed for some reason whatsoever. A `0' exit code will be interpreted as
+a success and
+.IR autopoll
+ends immediate. If the call seems to be unsuccessful a new call is scheduled
+for any site whose .Status files have a retry period greater than 0. The
+retry will be scheduled by means of placing an
+.IR at
+job at the time of the failing call plus any wait time given. For those
+sites that have been called with either the \-f or \-S option the retry
+time will be the time of the failing call plus 120 seconds.
+.PP
+In case the time calculated from the values found in a \.Status file is
+lower than the current time, the current time plus 60 seconds will be taken
+as the retry time.
+.PP
+A site will
+.IR not
+be automatically called again if one of the following
+conditions is met:
+.PP
+\-
+.IR uucico
+is terminated by a signal
+.PP
+\- either fork() or exec() failed
+.PP
+\- the
+.IR at
+command failed for any reasons.
+.PP
+\- if no wait should be honored and the retry time is found to be zero.
+(this may indicate a `Wrong time to call' condition.
+.PP
+There are other circumstances that may lead to not reschedule a call or
+not to call
+.IR uucico
+at all, all of which should be accompanied by (a) self explanatory message(s).
+.SH BUGS
+\- invalid options will make
+.IR uucico
+fail. The exit code for this type is the same as for any other failure; this
+can reschedule the call over and over again or never.
+.PP
+\-
+.IR autopoll
+may not work as expected when called with options other than \-r1, \-s,
+\-S or \-f.
+.PP
+\- a rescheduled call may fail with `wrong time to call' the second time
+but will be rescheduled again. The times to call won't be checked by
+.IR autopoll
+and the .Status file may not indicate this in case the \-c option is given.
+.PP
+\- in case the ..._DIR points to an invalid file a `Bus error' my pop up
+during the `exec' call.
+.PP
+\- the `chat-timeout' value may have to be increased when using
+.IR autopoll.
+An indication to do that is that the call fails short after `CONNECT'
+has been received with `Time out in chat script'.
+.PP
+\- the site names given will be checked aginst the output of
+.I uuname
+without any alias expansion done.
+.PP
+\- the text strings whithin the \.Status files will not be used to detect
+a failing call.
+.SH FILES
+.nf
+/usr/local/lib/uucp UUCP internal utilities
+/usr/lib/uucp
+/usr/local/bin UUCP internal utilities
+/usr/bin
+/usr/spool/uucp/.Status/ Status files for each site
+/usr/spool/uucp/ UUCP spool area. one of its sub-
+X directories will hold the null jobs.
+/tmp/poll.log This file is present only if autopoll
+X has been compiled to place the messages
+X into a file. Otherwise all messages will
+X go to stderr. The directory as well as
+X the name may be different.
+.fi
+.SH SEE ALSO
+uucp(1C), uux(1C), uucico(8C), uupoll(8C), uuname(1C), sort(1), uniq(1),
+at(1)
+SHAR_EOF
+chmod 0444 uupoll/autopoll.8c ||
+echo 'restore of uupoll/autopoll.8c failed'
+Wc_c="`wc -c < 'uupoll/autopoll.8c'`"
+test 4718 -eq "$Wc_c" ||
+ echo 'uupoll/autopoll.8c: original size 4718, current size' "$Wc_c"
+fi
+# ============= uupoll/autopoll.c ==============
+if test -f 'uupoll/autopoll.c' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/autopoll.c (File already exists)'
+else
+echo 'x - extracting uupoll/autopoll.c (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/autopoll.c' &&
+/* ---------------------------------------------------------------------------*
+X
+X Name: autopoll
+X
+X Author: Klaus Dahlenburg <kdburg@incoahe.hanse.de>
+X
+X Status: Public domain
+X
+X Copyright: none; claiming it to be your work will adversly affect
+X your image to be a good programmer.
+X
+X Function: Autopoll may be called just as uucico is called. The difference
+X is that autopoll will call uucico and if the return code is
+X not zero a check is made on the status files to see which site's
+X call failed. Those sites will be called again at that time found
+X in the status file plus any imposed wait. The next call will be
+X scheduled via an at job which in turn is handled by cron.
+X Atrun depends on the scheduling granularity of cron so the
+X actual times may be later than planned.
+X Autopoll will check the options -f and -s (-S) as well as the name
+X of the site passed. All other options will be passed unchecked.
+X The -f and -S options will indicate to autopoll that any wait
+X to call a site should be ignored; if the call fails the next
+X call to those sites will be at the current time plus 120 secs.
+X When the time found plus any wait evaluates to a time that
+X passed already the next call will be the current time plus 60
+X secs. The name of the site if given must be a valid one and not
+X the host itself otherwise it will be ignored.
+X
+X Call: autopoll [ options ]
+X
+X all option that apply to uucico may be given and
+X will be passed verbatim. See man uucico(8).
+X
+X Environment: NeXT 2.1+, Taylor UUCP-1.04+
+X
+X I/O: stdin: unused.
+X stdout: used only when ALOG_DIR is defined and the file
+X can't be opened. It will be a single message to tell
+X just that and the run is aborted.
+X stderr: all messages go here.
+X If ALOG_DIR is defined (see conf.h) all messages will
+X be appended to a file autopoll.msglog in that
+X directory; the file will be created automatically if
+X necessary; a redirection is then no longer possible.
+X Needs access to .Status files (see Comments later on).
+X
+X Called Programs: sort, uniq, uucico, uuname, at
+X
+X Compile: no special options are needed. Compiled with gcc 2.3.3 -O2.
+X Compile with the supplied cc might produce erroneous code
+X for the check options switch case 's' code: the break inside
+X the first if (..) {... break} is ignored.
+X
+X Comments: - should run setuid UUCP or whatever userid is necessary to
+X access (RDONLY) the .Status files and to run the programs
+X named under "Called Programs" above.
+X - No alias expansion is done on the given names for the
+X check against uuname's output..
+X - Invalid arguments will yield in an exit code > 0 as do
+X "normal" failures. It may therefore happen that a site
+X is called at the intervals with the same invalid arguments.
+X - "Wrong time to call" is not handled properly and may
+X call the site at the intervals until the time ban is lifted.
+X - human action is necessary as we can't distinguish between
+X "normal" failures and "errors" such as wrong password,
+X number to dial etc. The logs should be checked periodically.
+X - if CICO_DIR points to a non existent program the run may
+X end with signal 10: Bus Error.
+X - is has been observed that uucico will time out with "Dial
+X failed" when called via autopoll; setting chat-timeout to
+X value of 40 cured that problem.
+X - no rescheduling is done in case uucico fails and this
+X is not reported in the .Status file, one should check
+X the uucico log; this is to the fact that autopoll will
+X not scan the uucico log.
+*/
+X
+X
+#if !defined(lint)
+static char rcsid[] = "$Id: uupoll.shar,v 1.1 1995/10/18 08:38:24 deraadt Exp $";
+#endif /* not lint */
+X
+/* $Log: uupoll.shar,v $
+/* Revision 1.1 1995/10/18 08:38:24 deraadt
+/* Initial revision
+/*
+/* Revision 1.2 1995/08/24 05:19:19 jtc
+/* Upgraded to Taylor UUCP 1.06.1 (Thanks to John Kohl).
+/*
+X * Revision 2.8 1994/04/14 17:22:54 kdburg
+X * corrected misspelled AT_OPTION
+X *
+X * Revision 2.7 1994/04/11 20:15:48 kdburg
+X * major rework done; honor now some of the new option taht came with
+X * uucp-1.05
+X *
+X * Revision 2.6 1994/03/26 17:40:30 kdburg
+X * added support for UNAME_DIR; cleanup of some code; adjusted code after
+X * obtaining sitenames via popen()
+X *
+X * Revision 2.5 1993/07/07 16:49:02 kdburg
+X * when used interactivly only the start msg is put into the msg-log
+X * so far defined (UULOG)
+X *
+X * Revision 2.4 1993/06/26 16:17:51 kdburg
+X * the -S option wasn't propagated to the command passed to the at pgm
+X *
+X * Revision 2.3 1993/05/25 12:05:01 kdburg
+X * added error check on gettimeofday; added comment in the note section;
+X * minor changes not affection code
+X *
+X * Revision 2.2 1993/05/17 20:47:05 kdburg
+X * execution of at cmd also ok always said failed...
+X *
+X * Revision 2.1 1993/05/16 21:49:13 kdburg
+X * changed exit() to _exit() in case the exec fails within child
+X *
+X * Revision 2.0 1993/05/16 14:12:05 kdburg
+X * initial revision
+X * */
+X
+#define CAT 16
+#define SEVERE 8
+#define WARNING 4
+#define OK 0
+/* Boolean types */
+typedef int bool;
+#undef TRUE
+#undef FALSE
+#define TRUE (1)
+#define FALSE (0)
+X
+#include "conf.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+X
+#ifdef ALOG_FILE
+X static char Msg_Log[] = ALOG_FILE; /* name of msglog filename */
+#endif
+X
+#ifdef UNAME_DIR
+X static char subcmd[] = " | sort | uniq"; /* pipe that follows uuname */
+#else /* ! UNAME_DIR */
+X static char Sort[] = "uuname | sort | uniq"; /* default to obtain site names */
+#endif /*UNAME_DIR */
+X
+#ifdef AT_OPTION
+X static char at_opt[] = AT_OPTION;
+#else
+X static char at_opt[] = "-mc";
+#endif /* AT_OPTION */
+X
+static char at_cmd[] = "at";
+static char cGrade[] = DEF_GRADE; /* grade as defined in conf.h */
+static char dGrade[] = "A"; /* use this if DEF_GRADE is invalid */
+static char Auto_Dir[] = AUTO_DIR; /* we live here */
+static char Cico_Dir[] = CICO_DIR; /* here lives cico */
+X
+struct Sites {
+X char name[MAXHOSTNAMELEN+1]; /* name of site as supplied by uuname */
+X char grade[1]; /* as passed or defaulted */
+X bool flag; /* TRUE: call this site only */
+X bool force; /* TRUE: -S or -f option given */
+X int stat_code;
+X int stat_retries;
+X long stat_lastcall;
+X long stat_delay;
+X char *stat_errtext;
+};
+X struct Common_Stor {
+X int maxtab; /* high-water-mark for site tab */
+X int Single_Site_Tab; /* entry into site tab for a site */
+X /* passed via -s or -S option */
+X bool force_any; /* TRUE: -f option without site */
+X bool one_site; /* TRUE: call for a specific site */
+X bool nodetach; /* TRUE: -D or --nodetach found */
+X bool ifwork; /* TRUE: -C or --ifwork found */
+X char *Grade; /* use this as grade for calls */
+X char *Poll_Pgm; /* our name without path */
+X char *called_as; /* but called by this name */
+X int our_pid; /* our process-id */
+X char *Uucico; /* cico's name without path */
+X char This_Site[MAXHOSTNAMELEN+1]; /* our site name */
+X char Single_Site[MAXHOSTNAMELEN+1]; /* name of site found as arg */
+X union wait *W_Stat;
+X char *Usort; /* will hold uuname + subcmd */
+X struct passwd *pwd;
+X struct timeval tp;
+X struct timezone tzp;
+X struct Sites Sitetab[SITE_MAX];
+X char mon[3];
+X int day, hh, mm, ss;
+X char oname[24];
+X char jname[20];
+X char tstr[20];
+X char ctag[2];
+X char workf[300];
+X char call_args[300];
+X };
+X
+/* copied from taylor uucp "uudefs.h"
+X *
+X **/
+X
+/* The tstatus_type enumeration holds the kinds of status information
+X we put in the status file. The order of entries here corresponds
+X to the order of entries in the azStatus array. */
+enum tstatus_type
+{
+X /* Conversation complete. */
+X STATUS_COMPLETE,
+X /* Port unavailable. */
+X STATUS_PORT_FAILED,
+X /* Dial failed. */
+X STATUS_DIAL_FAILED,
+X /* Login failed. */
+X STATUS_LOGIN_FAILED,
+X /* Handshake failed. */
+X STATUS_HANDSHAKE_FAILED,
+X /* Failed after logging in. */
+X STATUS_FAILED,
+X /* Talking to remote system. */
+X STATUS_TALKING,
+X /* Wrong time to call. */
+X STATUS_WRONG_TIME,
+X /* Number of status values. */
+X STATUS_VALUES
+};
+X
+/* ----end-- copied from taylor uucp "uudefs.h" */
+X
+X
+/* define the prototypes
+X * */
+X
+int set_mlog(FILE **seclog, struct Common_Stor *);
+int get_sites(struct Common_Stor *);
+int Call_Cico(int argc, char *argv[], struct Common_Stor *);
+int get_args(int argc, char *argv[], struct Common_Stor *);
+int Housekeeping(int argc, char *argv[], struct Common_Stor *);
+int Chk_Status(int argc, char *argv[],
+X struct timeval tcc,
+X struct timezone tzcc,
+X struct Common_Stor *);
+int Check_Site(struct Common_Stor *);
+int start_at(char *name, struct Common_Stor *);
+void *storage(unsigned count, char *errloc, int *Rc, struct Common_Stor *);
+X
+extern int gethostname(char *name, int namelen);
+extern int system(char *cmd);
+extern int fork();
+extern int unlink(char *path);
+extern void *malloc(size_t byteSize);
+extern int execve(char *name, char *argv[], char *envp[]);
+extern int execlp(char *name, char *arg0, ...);
+extern int chmod(char *path, int mode);
+extern int getuid();
+extern int getpid();
+extern int isatty(int);
+extern char *ttyname(int);
+extern void free(void *ptr);
+#ifdef __STRICT_ANSI__
+extern FILE *popen(char *command, char *type);
+extern int pclose(FILE *stream);
+extern void _exit(int status);
+#endif /* __STRICT_ANSI__ */
+#ifdef __STRICT_BSD__
+extern int fprintf(FILE *stream, const char *format, ...);
+extern int fclose(FILE *stream);
+extern char *strerror(int errnum);
+extern int fflush(FILE *stream);
+extern void exit(int status);
+extern int fscanf(FILE *stream, const char *format, ...);
+extern int sscanf(char *s, const char *format, ...);
+#endif /* __STRICT_BSD__ */
+X
+/* --------------------------------------------------------------------------*/
+/* Main */
+/* --------------------------------------------------------------------------*/
+X
+int main(int argc, char *argv[])
+{
+X
+X struct Common_Stor *sCom_Sto;
+X int Maxrc = OK; /* Max err-code encountered so far */
+X int k = 0;
+X
+X if ( NULL == (sCom_Sto = malloc(sizeof(struct Common_Stor))) ) {
+X fprintf(stderr,"%s: (C) malloc failed (%s). Reason: %i (%s)\n",
+X AUTO_DIR,"Common_Stor",errno,strerror(errno));
+X exit (CAT);
+X }
+X
+X Maxrc = Housekeeping(argc, argv, sCom_Sto);
+X
+/* If any errors popped up so far they are of such a nature that it is very
+X * questionable to continue; so we better bail out in this case.
+X */
+X if (Maxrc <= WARNING) {
+X if ((sCom_Sto->W_Stat = (union wait *)storage (sizeof(union wait),
+X "W_Stat",&Maxrc,sCom_Sto)) != NULL) {
+X k = Call_Cico(argc, argv, sCom_Sto);
+X Maxrc = Maxrc >= k ? Maxrc:k;
+X free(sCom_Sto->W_Stat);
+X sCom_Sto->W_Stat = NULL;
+X }
+X }
+X k = gettimeofday(&sCom_Sto->tp, &sCom_Sto->tzp);
+X fprintf(stderr,"%s: (I) ended with rc = %i on %s\n",
+X sCom_Sto->called_as,
+X Maxrc,k!=0 ? "time unavailable":ctime(&sCom_Sto->tp.tv_sec));
+X fclose(stderr);
+X free(sCom_Sto);
+X sCom_Sto = NULL;
+X exit (Maxrc);
+}
+X
+/* --------------------------------------------------------------------------*/
+/* Functions */
+/* --------------------------------------------------------------------------*/
+X
+/* --------------------------------------------------------------------
+X * housekeeping
+X */
+X
+int Housekeeping(argc, argv, sCom_Sto)
+X int argc;
+X char *argv[];
+X struct Common_Stor *sCom_Sto; {
+X
+X FILE *seclog = NULL;
+X int Rc = OK;
+X int Rci = OK; /* intermediate rc as returnd by functions */
+X
+X sCom_Sto->our_pid = getpid();
+X
+/*
+X * get our name sans path
+X * */
+X
+X sCom_Sto->called_as = argv[0] + strlen(*argv);
+X for(;sCom_Sto->called_as >= argv[0] && *--sCom_Sto->called_as != '/';)
+X ;
+X sCom_Sto->called_as++;
+X
+/* if defined set up the name of the message log file otherwise
+X * stderr will be used. Setup the cmd string to obtain all known sitenames
+X * which will be sorted in ascending order with duplicates removed
+X * */
+X
+X Rc = set_mlog(&seclog, sCom_Sto);
+X if (Rc > WARNING)
+X return (Rc);
+X
+/* put out the started message including the time and the userid.
+X * */
+X
+X sCom_Sto->pwd = getpwuid(getuid());
+X
+X if ((gettimeofday(&sCom_Sto->tp, &sCom_Sto->tzp)) != 0) { /* unacceptable error */
+X fprintf(stderr,"%s: (C) gettimeofday() failed. Reason: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X
+X if (seclog != NULL) {
+X fprintf(seclog,"\n%s: (I) started by `%s' (%s) on %s",
+X sCom_Sto->called_as,
+X (sCom_Sto->pwd==NULL) ? "???":sCom_Sto->pwd->pw_name,
+X ttyname(0),
+X ctime(&sCom_Sto->tp.tv_sec));
+X fclose(seclog);
+X }
+X fprintf(stderr,"\n%s: (I) started by `%s' on %s",
+X sCom_Sto->called_as,
+X (sCom_Sto->pwd==NULL) ? "???":sCom_Sto->pwd->pw_name,
+X ctime(&sCom_Sto->tp.tv_sec));
+X
+/* set up the default grade
+X * */
+X
+X sCom_Sto->Grade = dGrade; /* set default for now */
+X if (strlen(cGrade) != 1) {
+X fprintf(stderr,"%s: (W) grade %s invalid; default `%s' used\n",
+X sCom_Sto->called_as,cGrade,sCom_Sto->Grade);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else
+X sCom_Sto->Grade = cGrade; /* Ok, take the one from conf.h */
+X
+/* get the program to actually call the site. This is normally UUCICO.
+X * */
+X
+X sCom_Sto->Uucico = Cico_Dir + strlen(Cico_Dir);
+X for(;sCom_Sto->Uucico >= Cico_Dir && *--sCom_Sto->Uucico != '/';)
+X ;
+X sCom_Sto->Uucico++;
+X
+/* get the path to ourself.
+X * */
+X
+X sCom_Sto->Poll_Pgm = Auto_Dir + strlen(Auto_Dir);
+X for(;sCom_Sto->Poll_Pgm >= Auto_Dir && *--(sCom_Sto->Poll_Pgm) != '/';)
+X ;
+X sCom_Sto->Poll_Pgm++;
+X
+/* obtain our sitename
+X * */
+X
+X if ((gethostname(sCom_Sto->This_Site,MAXHOSTNAMELEN+1)) != 0) {
+X fprintf(stderr,"%s: (W) hostname could not be obtained\n",
+X sCom_Sto->called_as);
+X Rc = (Rc >= WARNING) ? Rc:WARNING;
+X }
+X
+/* obtain all known sitenames
+X * */
+X
+X Rci = get_sites(sCom_Sto);
+X Rc = Rci > Rc ? Rci:Rc;
+X
+/* check the arguments that we are called with
+X * */
+X
+X Rci = get_args(argc, argv, sCom_Sto);
+X Rc = Rci > Rc ? Rci:Rc;
+X
+X return (Rc);
+}
+X
+/* --------------------------------------------------------------------
+X * check all relevant arguments that have been passed to us. Those args
+X * that may be needed for a recall will be copied to a workfield.
+X * */
+X
+int get_args(int argc, char *argv[], struct Common_Stor *sCom_Sto) {
+X
+X int j = 0;
+X int Rc = OK;
+X int Rci = OK;
+X
+X strcpy(sCom_Sto->Single_Site,"");
+X sCom_Sto->force_any = FALSE;
+X sCom_Sto->one_site = FALSE;
+X sCom_Sto->nodetach = FALSE;
+X
+X strcpy(sCom_Sto->call_args,AUTO_DIR); /* specify complete path to us */
+X strcat(sCom_Sto->call_args," "); /* and separate by one space */
+X for (j=1;j<argc;j++) {
+X if (strcmp(argv[j],"--nodetach") == 0 ||
+X strcmp(argv[j],"-D") == 0) {
+X sCom_Sto->nodetach = TRUE;
+X strcat(sCom_Sto->call_args,"-D ");
+X continue;
+X }
+X if (strcmp(argv[j],"--force") == 0 ||
+X strcmp(argv[j],"-f") == 0) {
+X strcat(sCom_Sto->call_args,"-f ");
+X sCom_Sto->force_any = TRUE;
+X continue;
+X }
+X if (strcmp(argv[j],"--ifwork") == 0 ||
+X strcmp(argv[j],"-C") == 0) {
+X sCom_Sto->ifwork = TRUE;
+X continue;
+X }
+X if ( strncmp(argv[j],"-s",2) == 0 ||
+X strncmp(argv[j],"-S",2) == 0 ||
+X strcmp(argv[j],"--system") == 0) {
+X if (strncmp(argv[j],"-S",2) == 0)
+X sCom_Sto->force_any = TRUE;
+X
+X if (strlen(argv[j]) == 2 || strcmp(argv[j],"--system") == 0) {
+X j++;
+X if (j>=argc) {
+X fprintf(stderr,"%s: (E) System to call is missing\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X else {
+X strcpy(sCom_Sto->Single_Site,argv[j]);
+X Rci = Check_Site(sCom_Sto);
+X if (! Rci) {
+X sCom_Sto->one_site = TRUE; /* specific call */
+X strcat(sCom_Sto->call_args,argv[j-1]);
+X strcat(sCom_Sto->call_args," ");
+X strcat(sCom_Sto->call_args,argv[j]);
+X strcat(sCom_Sto->call_args," ");
+X }
+X }
+X Rc = Rci <= Rc ? Rc:Rci;
+X }
+X else {
+X strcpy(sCom_Sto->Single_Site,argv[j]+2);
+X Rci = Check_Site(sCom_Sto);
+X if (! Rci) {
+X sCom_Sto->one_site = TRUE; /* specific call */
+X strcat(sCom_Sto->call_args,argv[j]);
+X strcat(sCom_Sto->call_args," ");
+X }
+X Rc = Rci <= Rc ? Rc:Rci;
+X }
+X continue;
+X }
+X strcat(sCom_Sto->call_args,argv[j]);
+X strcat(sCom_Sto->call_args," ");
+X } /* end copy all arguments */
+X
+X if (sCom_Sto->ifwork) {
+X if (sCom_Sto->one_site) {
+X strcat(sCom_Sto->call_args,"-C ");
+X }
+X else {
+X fprintf(stderr,"%s: (W) no site given, '-C' option is ignored\n",
+X sCom_Sto->called_as);
+X sCom_Sto->ifwork = FALSE;
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X }
+X
+X if (! sCom_Sto->nodetach) {
+X strcat(sCom_Sto->call_args,"-D ");
+X }
+X
+X return (Rc);
+}
+X
+/* --------------------------------------------------------------------
+X * call uucico or whatever programm is necessary to get connected
+X */
+X
+/* Start uucico and wait for completion. In case the return code is '0'
+X * we're finished; otherwise we'll have to check the status files for any
+X * non successful calls (retry time > 0).
+X * Any such site will be called again at the current time plus any wait
+X * Note:
+X * If the '-D' or '--nodetach' option is missing, uucico will
+X * detach immediate. The return-code is 0 in this case and therefore
+X * we can't check whether the call is successful or not. No recall
+X * is scheduled for such an invocation. If we however get control
+X * to schedule a recall we silently add the '-D' option. To add
+X * the '-D' option in any case may be undesirable for a specific
+X * type of run.
+X */
+X
+int Call_Cico(int argc, char *argv[], struct Common_Stor *sCom_Sto) {
+X
+X int W_Ret = 0;
+X int pid = 0;
+X int Rc = OK;
+X struct timeval tcc;
+X struct timezone tzcc;
+X
+X if ((gettimeofday(&tcc, &tzcc)) != 0) { /* unacceptable error */
+X fprintf(stderr,"%s: (C) gettimeofday() failed. Reason: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X Rc = Rc >= CAT ? Rc:CAT;
+X }
+X
+X if (Rc > WARNING) {
+X return (Rc);
+X }
+X
+X fflush(stderr);
+X switch(pid = fork()) {
+X case -1:
+X fprintf(stderr,"%s: (C) could not fork(). Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X return (CAT);
+X case 0:
+X if ((argv[0] = (char *)storage(strlen(sCom_Sto->Uucico)+1,"argv[0]",
+X &Rc,sCom_Sto)) == NULL) {
+X _exit (CAT);
+X }
+X strcpy(argv[0],sCom_Sto->Uucico); /* change name to be uucico */
+X execve(Cico_Dir, argv, NULL);
+X fprintf(stderr,"%s: (C) could not start %s. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,errno,strerror(errno));
+X _exit (CAT); /* child: bail out */
+X default:
+X fprintf(stderr,"%s: (I) starting %s [%d]\n\n",
+X sCom_Sto->called_as,sCom_Sto->Uucico,pid);
+X fflush(stderr); /* maybe we come behind uucico's output */
+X /* if any; it's a race condition */
+X W_Ret = wait(sCom_Sto->W_Stat);
+X if (sCom_Sto->W_Stat->w_termsig == 0) {
+X if (sCom_Sto->W_Stat->w_retcode == 0) {
+X fprintf(stderr,"%s: (I) %s [%d] ended normally\n",
+X sCom_Sto->called_as,sCom_Sto->Uucico,pid);
+X return (OK);
+X }
+X if (sCom_Sto->W_Stat->w_retcode != CAT) {
+X fprintf(stderr,"%s: (I) %s's log may contain further information !\n",
+X sCom_Sto->called_as,sCom_Sto->Uucico);
+X fprintf(stderr,"\n%s: (W) %s [%d] ended with rc = %i\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,pid,
+X sCom_Sto->W_Stat->w_retcode);
+X return (Chk_Status(argc, argv,
+X tcc, tzcc, sCom_Sto));
+X }
+X else
+X return (CAT); /* we where unable to exec */
+X }
+X else {
+X fprintf(stderr,"\n%s: (E) %s [%d] terminated by signal %i\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,
+X pid,
+X sCom_Sto->W_Stat->w_termsig);
+X return (SEVERE);
+X }
+X } /* switch (pid = fork()) */
+X return (OK); /* Never reached: silence the compiler */
+}
+X
+X
+/* --------------------------------------------------------------------
+X * check the status after the call has completed and the return code
+X * is > zero. The status is checked for all sites found via uuname or
+X * for one site only (option -s, -S or --system given on call)
+X */
+X
+int Chk_Status(int argc, char *argv[],
+X struct timeval tcc,
+X struct timezone tzcc,
+X struct Common_Stor *sCom_Sto) {
+X
+/*
+X * For all sites found in Site_Tab their status files will be checked.
+X * The table scan will be bypassed for a call to a specific site.
+X * If the call failed the wait period is > 0. We will schedule an at-job
+X * to be run at the time found + the delta. In case we find an old entry
+X * where the time + delta is lower than the current time we'll advance
+X * the current time by 60 secs. and use that value instead.
+X * In case we are invoked to call a specific site and either the -f option or
+X * the site was given as -S... indicating to disregard any wait, we'll
+X * use the time found in the status file increased by 120 secs.
+*/
+X
+X FILE *infile;
+X long secs, retries = 0;
+X long add = 0;
+X int errind = 0;
+X int i = 0;
+X int ecnt = 0;
+X int recall_cnt = 0;
+X char curr_site[MAXHOSTNAMELEN+11] = ""; /* keyword + sitename */
+X bool schedule = TRUE; /* FALSE: no more rescheduling: unspec. + force */
+X int Rc = WARNING; /* uucico got rc = 1 otherwise we were not here */
+X int Rs = 0; /* uucico' reason code from .Status file */
+X
+/*
+X * Note
+X * We have to increase the sum of time and wait by at least one minute.
+X * That is because this time denotes the earliest point *after* which
+X * we may call again.
+X * When a site is called at the wrong time the follwing actions are
+X * taken: wait = 0 && ! force --> no further action (indicator: see log)
+X * wait = 0 && force --> (W) message generated; no further action
+X * wait > 0 && ! force --> normal scheduling at time + wait
+X * wait > 0 && force --> normal scheduling at time+120 secs
+X * We can't depend on the string "Wrong time to call" because the .Status
+X * file may not be updated due to the -c switch. This may lead to a
+X * situation where the site will be called over and over again while it's
+X * still the wrong time. (No we don't want to go fishing for a message in
+X * the uucp LOG!)
+X * In case the -s, -S or --system option was given we will only
+X * check that site and schedule a recall for it so far the
+X * conditions are met.
+X * In case the -C or --ifwork switch is given without naming a site a
+X * the option is dropped and only an unspecific call is scheduled.
+X * */
+X
+X if (sCom_Sto->one_site) {
+X i = sCom_Sto->Single_Site_Tab;
+X if (strncmp(sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Single_Site,
+X sizeof(sCom_Sto->Single_Site)) != 0) {
+X fprintf(stderr,"%s: (C) internal index-error (%d): %s found: %s\n",
+X sCom_Sto->called_as,
+X i,
+X sCom_Sto->Single_Site,
+X sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= CAT ? Rc:CAT;
+X return (Rc); /* break unconditionally */
+X }
+X }
+X
+X for (i = sCom_Sto->Single_Site_Tab; i <= sCom_Sto->maxtab; i++) {
+X sprintf(sCom_Sto->workf,"%s%s",STATUS_DIR,sCom_Sto->Sitetab[i].name);
+X if ((infile=fopen(sCom_Sto->workf,"r")) == NULL) {
+X ecnt++;
+X fprintf(stderr,"%s: (W) no access to status file for: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X if (sCom_Sto->one_site) {
+X break;
+X }
+X else {
+X continue;
+X }
+X }
+X
+X fscanf(infile,"%d %d %ld %ld",&errind,&retries,&secs,&add);
+X fclose(infile);
+X
+X /*
+X * in case the .Status file is not updated and we have a call to
+X * a specific site we try to give some clues of what went wrong
+X * (we won't succeed in any case!)
+X */
+X
+X if (sCom_Sto->Sitetab[i].stat_lastcall == secs && sCom_Sto->one_site) {
+X
+X if (errind == 0 && retries == 0 && add == 0)
+X break;
+X
+X if (errind > 0) {
+X if (tcc.tv_sec <= (secs+add) && ! sCom_Sto->Sitetab[i].force) {
+X fprintf(stderr,"%s: (W) retry time not reached for site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else {
+X fprintf(stderr,"%s: (E) maybe port/site unavailable site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X }
+X else {
+X if (sCom_Sto->one_site) {
+X fprintf(stderr,"%s: (E) unknown error for call to site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X }
+X fprintf(stderr,"%s: (W) no recall scheduled for site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X break; /* bail out completely */
+X }
+X
+X if (sCom_Sto->Sitetab[i].stat_lastcall == secs) {
+X if (sCom_Sto->one_site)
+X break;
+X else
+X continue;
+X }
+X
+X Rs = OK; /* if Rs is > WARNING we won't schedule a recall */
+X switch(errind) {
+X case STATUS_COMPLETE:
+X if (add != 0 || retries != 0) {
+X fprintf(stderr,"%s: (E) unknown error for call to site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rs = Rs >= SEVERE ? Rs:SEVERE;
+X }
+X break;
+X case STATUS_PORT_FAILED:
+X fprintf(stderr,"%s: (E) port was unavailable site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X break;
+X case STATUS_DIAL_FAILED:
+X fprintf(stderr,"%s: (E) dail failed for site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X break;
+X case STATUS_LOGIN_FAILED:
+X fprintf(stderr,"%s: (E) login for site: %s failed\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rs = Rs >= SEVERE ? Rs:SEVERE;
+X break;
+X case STATUS_HANDSHAKE_FAILED:
+X fprintf(stderr,"%s: (E) handshake failed site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X break;
+X case STATUS_FAILED:
+X fprintf(stderr,"%s: (E) invalid status after login site: %s \n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X break;
+X case STATUS_TALKING:
+X break;
+X case STATUS_WRONG_TIME:
+X fprintf(stderr,"%s: (W) it's the wrong time to call site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rs = Rs >= SEVERE ? Rs:SEVERE;
+X break;
+X default:
+X fprintf(stderr,"%s: (E) unknown error for call to site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rs = Rs >= SEVERE ? Rs:SEVERE;
+X break;
+X }
+X Rc = Rs > Rc ? Rs:Rc;
+X if (Rs > WARNING) { /* schedule a recall ? */
+X fprintf(stderr,"%s: (W) no recall scheduled for site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X if (sCom_Sto->one_site)
+X break;
+X else
+X continue;
+X }
+X
+X if (add == 0) {
+X fprintf(stderr,"%s: (W) no delay found for site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X
+X
+X if (! schedule) {
+X recall_cnt += 1;
+X continue; /* scheduling already done: unspec. + force */
+X }
+X if ((gettimeofday(&sCom_Sto->tp, &sCom_Sto->tzp)) != 0) {
+X fprintf(stderr,"%s: (C) gettimeofday() failed. Reason: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X fclose(infile);
+X Rc = Rc >= CAT ? Rc:CAT;
+X break; /* break unconditionally */
+X }
+X
+X if (sCom_Sto->force_any || sCom_Sto->Sitetab[i].force) {
+X add = secs + 120; /* shorten the wait */
+X }
+X else { /* ! force */
+X
+/*
+X * check for an already scheduled recall. For we don't keep
+X * a file of already scheduled recalls the only way to recognize
+X * this, is to check the current time against that of the .Stats file.
+X * In case the current time is >= the .Stats-time + n-secs fuzz value
+X * we assume (99.99% correctness) that we have already scheduled a recall
+X * for this site. If this assumption is incorrect a call will be
+X * scheduled on the next unspecific failing call. This check can't
+X * be done for forced call because the .Stats will be updated.
+X */
+X if (sCom_Sto->tp.tv_sec >= secs+2) {
+X fprintf(stderr,"%s: (W) Retry time not reached for site: %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X if (sCom_Sto->one_site)
+X break;
+X else
+X continue;
+X }
+X add += secs + 60; /* if not force then take the full wait */
+X } /* force */
+X
+X if (sCom_Sto->tp.tv_sec >= add) {
+X add = sCom_Sto->tp.tv_sec + 60; /* time < current time */
+X }
+X
+X sscanf(ctime(&add),"%*s %s %d %d:%d:%d",sCom_Sto->mon,
+X &sCom_Sto->day,
+X &sCom_Sto->hh,
+X &sCom_Sto->mm,
+X &sCom_Sto->ss);
+X
+X sprintf(sCom_Sto->oname,"/tmp/at.%d.%02d%02d%02d",sCom_Sto->our_pid,
+X sCom_Sto->hh,
+X sCom_Sto->mm,
+X sCom_Sto->ss);
+X if (! sCom_Sto->one_site) {
+X strcpy(curr_site,"-s");
+X strcat(curr_site,sCom_Sto->Sitetab[i].name);
+X }
+X
+X /*
+X * If 'onesite' is FALSE and 'force' is TRUE
+X * we will reschedule one unspecific call an let UUCICO decide
+X * which site should be called (is there any work?)
+X */
+X
+X if ( ! sCom_Sto->one_site && sCom_Sto->force_any) {
+X recall_cnt += 1;
+X schedule = FALSE;
+X continue;
+X }
+X strcat(sCom_Sto->call_args,curr_site);
+X Rs = start_at(sCom_Sto->Sitetab[i].name, sCom_Sto);
+X Rc = Rs >= Rc ? Rs:Rc;
+X unlink(sCom_Sto->oname);
+X if (Rc > SEVERE || sCom_Sto->one_site)
+X break;
+X } /* for (i = Single_Site_Tab; ...) */
+X
+X if (ecnt > sCom_Sto->maxtab) {
+X fprintf(stderr,"%s: (E) no access to status files; no scheduling done\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X else {
+X if (! schedule) {
+X if (recall_cnt == 1) {
+X strcat(sCom_Sto->call_args,curr_site);
+X }
+X Rs = start_at("any site", sCom_Sto);
+X Rc = Rs >= Rc ? Rs:Rc;
+X unlink(sCom_Sto->oname);
+X }
+X }
+X return (Rc);
+}
+X
+X /*
+X *
+X */
+X
+int start_at(char *site, struct Common_Stor *sCom_Sto) {
+X
+FILE *outfile;
+int W_Ret = 0;
+int Rc = OK;
+int pid = 0;
+X
+/*
+X * if we can't open the workfile to be passed to AT we'll abandon
+X * this site and set the rc accordingly
+X * */
+X
+X if ((outfile=fopen(sCom_Sto->oname,"w")) == NULL) {
+X fprintf(stderr,"%s: (E) could not open workfile %s. No scheduling for: %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->oname,
+X site);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X fclose(outfile);
+X unlink(sCom_Sto->oname);
+X return (Rc); /* bail out here */
+X }
+X sprintf(sCom_Sto->jname,"at.%d.%02d%02d%02d",sCom_Sto->our_pid,
+X sCom_Sto->hh,
+X sCom_Sto->mm,
+X sCom_Sto->ss);
+X fprintf(outfile,"%s \n",sCom_Sto->call_args);
+X sprintf(sCom_Sto->tstr,"%02d%02d",sCom_Sto->hh,
+X sCom_Sto->mm);
+X sprintf(sCom_Sto->ctag,"%d",sCom_Sto->day);
+X fclose(outfile);
+X if ((chmod(sCom_Sto->oname,00644)) != 0) {
+X fprintf(stderr,"%s: (W) chmod to %s failed. Reason_code: %i (%s)\n",
+X sCom_Sto->called_as,
+X sCom_Sto->oname,
+X errno,
+X strerror(errno));
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X
+X switch (pid = fork()) {
+X case -1:
+X fprintf(stderr,"%s: (C) could not fork(). Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X return (Rc >= CAT ? Rc:CAT);
+X case 0:
+X if (*at_opt == '\0')
+X execlp(at_cmd, at_cmd, sCom_Sto->tstr,
+X sCom_Sto->mon, sCom_Sto->ctag,
+X sCom_Sto->oname, 0);
+X else
+X execlp(at_cmd, at_cmd, at_opt, sCom_Sto->tstr,
+X sCom_Sto->mon, sCom_Sto->ctag,
+X sCom_Sto->oname, 0);
+X
+X fprintf(stderr,"%s: (C) could not start AT-cmd. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,
+X errno,strerror(errno));
+X _exit (CAT); /* child: bail out */
+X default:
+X fprintf(stderr,"%s: (I) at [%d] started. Job name: %s\n",
+X sCom_Sto->called_as,
+X pid,
+X sCom_Sto->jname);
+X W_Ret = wait(sCom_Sto->W_Stat);
+X if (sCom_Sto->W_Stat->w_termsig == 0) {
+X if (sCom_Sto->W_Stat->w_retcode != 0) {
+X if (sCom_Sto->W_Stat->w_retcode != CAT) {
+X fprintf(stderr,"%s: (E) at-cmd failed for some reason\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X else {
+X Rc = Rc >= CAT ? Rc:CAT;
+X }
+X
+X fprintf(stderr,"%s: (I) at [%d] ended with rc = %i\n",
+X sCom_Sto->called_as,
+X pid,
+X sCom_Sto->W_Stat->w_retcode);
+X /* bail out in case wait returned > SEVERE */
+X if (Rc > SEVERE) {
+X return (Rc);
+X }
+X }
+X else {
+X fprintf(stderr,"%s: (I) at-cmd [%d] ended normally\n",
+X sCom_Sto->called_as,
+X pid);
+X }
+X }
+X else {
+X fprintf(stderr,"%s: (E) at [%d] terminated by signal %i\n",
+X sCom_Sto->called_as,
+X pid,
+X sCom_Sto->W_Stat->w_termsig);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X } /* switch (pid = fork()) */
+X return (Rc);
+}
+/* -----------------------------------------------------------------
+X * check the site passed via -s or -S option to be a valid one and
+X * not to be our hostname.
+X * */
+X
+int Check_Site(struct Common_Stor *sCom_Sto) {
+X
+X int i,j = 0;
+X sCom_Sto->Single_Site_Tab = 0;
+X if (strcmp(sCom_Sto->Single_Site,sCom_Sto->This_Site) == 0) {
+X fprintf(stderr,"%s: (E) won't call *ourself* %s\n",
+X sCom_Sto->called_as,sCom_Sto->Single_Site);
+X return(SEVERE);
+X }
+X for(i=0;i<=sCom_Sto->maxtab;i++) {
+X if ((j=strcmp(sCom_Sto->Sitetab[i].name,sCom_Sto->Single_Site)) >= 0) {
+X break;
+X }
+X }
+X if (j != 0) {
+X fprintf(stderr,"%s: (E) unknown site: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Single_Site);
+X return(SEVERE);
+X }
+X sCom_Sto->Single_Site_Tab = i;
+X sCom_Sto->Sitetab[i].flag = TRUE;
+X if (sCom_Sto->force_any) {
+X sCom_Sto->Sitetab[i].force = TRUE;
+X sCom_Sto->force_any = FALSE;
+X }
+X return(OK);
+}
+X
+X /* ------------------------------------------------------------------
+X * storage - get some memory
+X */
+X
+void *storage(unsigned count,
+X char *location,
+X int *Rc,
+X struct Common_Stor *sCom_Sto)
+{
+X void *p;
+X
+X if( NULL == (p= malloc(count)) ) {
+X fprintf(stderr,"%s: (C) malloc failed (%s). Reason: %i (%s)\n",
+X sCom_Sto->called_as,location,errno,strerror(errno));
+X *Rc = *Rc >= CAT ? *Rc:CAT;
+X }
+X return p;
+}
+X
+/* ------------------------------------------------------------------
+X * if defined open the message log file otherwise all mesages will go
+X * to stderr. If UNAME_DIR is defined construct the command to be
+X * passed to popen(); if undefined the deafult will be used
+X * */
+X
+int set_mlog(FILE **seclog, struct Common_Stor *sCom_Sto) {
+X
+X int Rc = 0;
+X
+#ifdef ALOG_FILE
+X if (!isatty(0)) {
+X if ((freopen(Msg_Log,"a",stderr)) == NULL) {
+X fprintf(stdout,"%s: (C) Could not open msglog: %s\n",
+X sCom_Sto->called_as,Msg_Log);
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X }
+X else {
+X if ((*seclog = fopen(Msg_Log,"a")) == NULL) {
+X fprintf(stderr,"%s: (C) Could not open msglog: %s\n",
+X sCom_Sto->called_as,Msg_Log);
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X }
+#endif /* ALOG_FILE */
+X
+/* set up the pipe together with the complete path to uuname */
+X
+#ifdef UNAME_DIR
+X if ((sCom_Sto->Usort = (char *)storage (sizeof(UNAME_DIR)+sizeof(subcmd),
+X "Sort",&Rc, sCom_Sto)) != NULL) {
+X strncpy(sCom_Sto->Usort,UNAME_DIR,strlen(UNAME_DIR)); /* paste in the path */
+X strcat(sCom_Sto->Usort,subcmd); /* chain the pipe to it */
+X }
+#else /* ! UNAME_DIR */
+X sCom_Sto->Usort = &Sort; /* set pointer to uuname + sort */
+#endif /* UNAME_DIR */
+X
+X return (Rc);
+}
+X
+/* ------------------------------------------------------------------
+X * obtain all active sitenames
+X * */
+X
+int get_sites(struct Common_Stor *sCom_Sto) {
+X
+X int i = 0;
+X int n;
+X int Rc = 0;
+X FILE *infile, *statsfile;
+X
+X if ((infile=popen(sCom_Sto->Usort,"r")) != NULL) {
+X while(fgets(sCom_Sto->Sitetab[i].name,MAXHOSTNAMELEN+1,infile)) {
+X if (i > SITE_MAX) { /* let'm run so that we can give */
+X i++; /* the user some guidance */
+X continue; /* we'll tell the user later on */
+X }
+X n = strlen(sCom_Sto->Sitetab[i].name)-1; /* offset: next to last char */
+X sCom_Sto->Sitetab[i].name[n] = '\0'; /* strip trailing newline */
+X sCom_Sto->Sitetab[i].flag = FALSE; /* TRUE: poll this site only*/
+X sCom_Sto->Sitetab[i].force = FALSE; /* TRUE: force call */
+X strcpy(sCom_Sto->Sitetab[i].grade,sCom_Sto->Grade);
+X sprintf(sCom_Sto->workf,"%s%s",STATUS_DIR,sCom_Sto->Sitetab[i].name);
+X if ((statsfile=fopen(sCom_Sto->workf,"r")) == NULL) {
+X fprintf(stderr,"%s: (W) no access to status file for: %s\n",
+X sCom_Sto->called_as,sCom_Sto->Sitetab[i].name);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else {
+X fscanf(statsfile,"%d %d %ld %ld %s",
+X &sCom_Sto->Sitetab[i].stat_code,
+X &sCom_Sto->Sitetab[i].stat_retries,
+X &sCom_Sto->Sitetab[i].stat_lastcall,
+X &sCom_Sto->Sitetab[i].stat_delay,
+X sCom_Sto->workf);
+X
+X fclose(statsfile);
+X if ((sCom_Sto->Sitetab[i].stat_errtext =
+X (char *)storage (sizeof(sCom_Sto->workf),
+X "stat_errtext",&Rc, sCom_Sto)) == NULL) {
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else
+X strcpy(sCom_Sto->Sitetab[i].stat_errtext,sCom_Sto->workf);
+X }
+X sCom_Sto->maxtab = i++; /* set high-water-mark */
+X }
+X if (ferror(infile) != 0) {
+X fprintf(stderr,"%s: (E) fgets() for sitenames failed reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X pclose(infile);
+X
+X /*
+X * check for an empty table (strange but possible)
+X */
+X
+X if (sCom_Sto->maxtab == 0) {
+X fprintf(stderr,"%s: (E) could not obtain sitenames.\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X else {
+X
+X /* in case the internal table overflows we'll now give notice and tell
+X * the user by which amount the table has to be increased to hold all
+X * site-names
+X */
+X
+X if (i > SITE_MAX) {
+X fprintf(stderr,"%s: (E) number of sites > internal tab\n",
+X sCom_Sto->called_as);
+X fprintf(stderr,"%s: (E) increase SITE_MAX to >= %d and recompile\n",
+X sCom_Sto->called_as,i);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X } /* sCom_Sto->maxtab == 0 */
+X
+X }
+X else /* infile == NULL */
+X {
+X fprintf(stderr,"%s: (E) could not sort sitenames. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X
+X } /* if ((infile=popen(sCom_Sto->Usort,"r")) ... */
+X
+X return (Rc);
+}
+SHAR_EOF
+chmod 0444 uupoll/autopoll.c ||
+echo 'restore of uupoll/autopoll.c failed'
+Wc_c="`wc -c < 'uupoll/autopoll.c'`"
+test 44031 -eq "$Wc_c" ||
+ echo 'uupoll/autopoll.c: original size 44031, current size' "$Wc_c"
+fi
+# ============= uupoll/conf.h ==============
+if test -f 'uupoll/conf.h' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/conf.h (File already exists)'
+else
+echo 'x - extracting uupoll/conf.h (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/conf.h' &&
+#ifndef CONF
+X #define CONF
+X
+/* $Id: uupoll.shar,v 1.1 1995/10/18 08:38:24 deraadt Exp $ */
+/* $Log: uupoll.shar,v $
+/* Revision 1.1 1995/10/18 08:38:24 deraadt
+/* Initial revision
+/*
+/* Revision 1.2 1995/08/24 05:19:19 jtc
+/* Upgraded to Taylor UUCP 1.06.1 (Thanks to John Kohl).
+/*
+X * Revision 1.9 1994/04/14 17:24:58 kdburg
+X * added comment to the AT_OPTION
+X *
+X * Revision 1.8 1994/03/26 17:41:06 kdburg
+X * the location of uuname can now be specified. This was added due to
+X * the fact that cron (NeXT 3.2 and +) now obeys the path that was active
+X * during boot (either /.path or set within /etc/rc) so autopoll/uupoll
+X * always got the wrong uuname when called direct fron cron. This is
+X * not true when called via a script that does a 'su - user -c ...'
+X *
+X * Revision 1.7 1993/06/26 16:21:47 kdburg
+X * default location for logfiles changed
+X *
+X * Revision 1.6 1993/05/14 22:32:05 kdburg
+X * change to HAVE_SPOOLDIR_TAYLOR
+X *
+X * Revision 1.5 1993/05/09 13:16:53 kdburg
+X * make have-autopoll the default
+X *
+X * Revision 1.4 1993/05/08 23:17:34 kdburg
+X * cleanup and to reflect changes made to autopoll/uupoll
+X *
+X * Revision 1.3 1993/04/29 10:46:34 kdburg
+X * added def for STATUS_DIR
+X *
+X * Revision 1.2 1993/04/27 15:31:47 kdburg
+X * rearranged the defs; changed LOG_DIR to ALOG_DIR in case uupoll
+X * will have one too; we need then eventually 2 different dirs.
+X *
+X * Revision 1.1 1993/04/26 21:20:12 kdburg
+X * Initial revision
+X * */
+X
+/* --------- combined config file for uupoll and autopoll */
+/* --------- change the following defines to meet your needs */
+X
+/* define the default grade to be inserted into the pollfile name */
+#define DEF_GRADE "A"
+X
+/* Define the complete path to the uuname program.
+X * If undefined we'll use just the name 'uuname' to call it
+X * */
+#define UNAME_DIR "/usr/local/bin/uuname"
+X
+/* define the path to the directory which does contain uucico */
+#define CICO_DIR "/usr/local/lib/uucp/uucico"
+X
+/* define the path to the directory which holds all the uucp files.
+X * We'll place the poll file in one of it's subdirectories
+X * */
+#define SPOOL_DIR "/usr/spool/uucp"
+X
+/* at least one of the follwing must be defined To use the second or
+X * third set of definitions, change the ``#if 1'' to ``#if 0''
+X * and change the appropriate ``#if 0'' to ``#if 1''.
+X * */
+#if 0
+#define HAVE_SPOOLDIR_BSD
+#endif
+#if 0
+#define HAVE_SPOOLDIR_HDB
+#endif
+#if 1
+#define HAVE_SPOOLDIR_TAYLOR
+#endif
+X
+/* define the maximum number of sites in your config or L.sys */
+#define SITE_MAX 100
+X
+/* define the path to the directory which is to contain the
+X * message log created by uupoll and the file name itself.
+X * change the ``#if 1'' to ``#if 0'' to have the messages on stderr
+X * */
+#if 1
+#define ULOG_FILE "/Logfiles/poll.log"
+#endif
+X
+/* change if to 0 if you don't have autopoll installed. */
+#if 1
+#define AUTO_POLL
+#endif
+X
+/* The following defs are irrelevant if you don't have autopoll */
+X
+/* define the options to be given to the at cmd (-s -c -m). The default
+X * is shown (use csh and send mail after execution) if AT_OPTION is
+X * undefined
+X * */
+#define AT_OPTION "-mc"
+X
+/* Define the complete path to the autopoll program.
+X * This will assure that we get the one we want
+X * The path must be the same as given in Makefile (lbindir)
+X * */
+#define AUTO_DIR "/usr/local/lib/uucp/autopoll"
+X
+/* define the path to the directory which is to contain the
+X * message log created by autopoll and the file name itself.
+X * change the ``#if 1'' to ``#if 0'' to have the messages on stderr
+X * */
+#if 1
+#define ALOG_FILE "/Logfiles/poll.log"
+#endif
+X
+/* define the full path to the directory which holds the status files
+X * The name should be given *except* the sitename. A trailing `/' if any
+X * must be given.
+X * Example: /usr/spool/uucp/.Status/sys.sitename
+X * then specify STATUS_DIR as
+X * "/usr/spool/uucp/.Status/sys."
+X * */
+#define STATUS_DIR "/usr/spool/uucp/.Status/"
+#endif
+SHAR_EOF
+chmod 0444 uupoll/conf.h ||
+echo 'restore of uupoll/conf.h failed'
+Wc_c="`wc -c < 'uupoll/conf.h'`"
+test 3884 -eq "$Wc_c" ||
+ echo 'uupoll/conf.h: original size 3884, current size' "$Wc_c"
+fi
+# ============= uupoll/uupoll.8c ==============
+if test -f 'uupoll/uupoll.8c' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/uupoll.8c (File already exists)'
+else
+echo 'x - extracting uupoll/uupoll.8c (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/uupoll.8c' &&
+.\" Copyright (c) 1986 Regents of the University of California.
+.\" All rights reserved. The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\" @(#)uupoll.8c 6.1 (Berkeley) 4/24/86
+.\" @(#)uupoll.8c 1.11 (incoahe) 5/09/1993
+.\"
+.TH UUPOLL 8C "Mai 09, 1993"
+.UC 6
+.SH NAME
+uupoll \- poll a remote \s-1UUCP\s+1 site
+.SH SYNOPSIS
+.B uupoll
+[
+.BI \-g grade
+] [
+.B \-n
+] [
+.B \-x
+]
+.I system ... ...
+.SH SUMMARY
+This version of
+.IR uupoll
+can be used to fully replace the vendor supplied
+.IR uupoll
+that comes with the NeXTStep OS. The original version (up to 3.1) had a
+X bug in that
+X an unknown site given as argument would yield in a `Bus error' condition.
+Using any other type of UUCP like Taylor-UUCP with the option of having
+a different file structure as well as a different L.sys will therefore
+make it necessary to do maintenance to the (unused) L.sys as well to keep
+.IR uupoll
+going. This one has been programmed from scratch due to the fact that no
+source code was available. Some enhancements have been incorporated into
+this version:
+.PP
+\- the default grade may now be compiled different from `A'.
+.PP
+\- the options may now be given in any order and the \-g option may be given
+more than once. Any option will be used immediately when encountered and
+will stay in effect unless reset; this does not apply to the \-x and \-n
+option which can't be reset. The processing of options is guaranteed to be
+from left to right so that some grouping may be achieved (see below).
+.PP
+\-
+.IR uupoll
+may be used to call any program instead of
+.IR uucico
+namely
+.IR autopoll
+to ease the task of rescheduling a failed call.
+.SH DESCRIPTION
+.I Uupoll
+is used to force a poll of a remote system. It queues a null job for the
+remote system, unless the \-x option has been given, and then invokes
+either
+.IR uucico (8C)
+or
+.IR autopoll (8C)
+or any other program depending on how
+.IR uupoll
+is customized. If used in conjunction with
+.IR autopoll
+the latter will then invoke
+.IR uucico.
+.SH OPTIONS
+The following options are available:
+.TP 8
+.BI \-g grade
+Only send jobs of grade
+.I grade
+or higher on this call. The
+.I grade
+stays in effect until it is changed by a different \-g option.
+.TP 8
+.B \-n
+Queue the null job, but do not invoke the program that actually calls
+the named site(s).
+The \-n option once given will apply to all sites following to the
+.IR right
+of it.
+.TP 8
+.B \-x
+Do not place a null job for all following sites. This option must be given
+before the \-n option. The \-n option will nullify this. Any grade in effect
+will not be honored because
+.I uucico (Taylor)
+does not carry the \-g option at the moment.
+.PP
+.I Uupoll
+is usually run by
+.IR cron (5)
+or by a user who wants to hurry a job along. A typical entry in
+.I crontab
+could be:
+.PP
+.nf
+X 0 0,8,16 * * * uucp /usr/bin/uupoll ihnp4
+X 0 4,12,20 * * * uucp /usr/bin/uupoll ucbvax
+.fi
+This will poll
+.B ihnp4
+at midnight, 0800, and 1600, and
+.B ucbvax
+at 0400, noon, and 2000.
+.PP
+If the local machine is already running
+.I uucico
+every
+hour and has a limited number of outgoing modems, a better approach
+might be:
+.PP
+.nf
+X 0 0,8,16 * * * uucp /usr/bin/uupoll -n ihnp4
+X 0 4,12,20 * * * uucp /usr/bin/uupoll -n ucbvax
+X 5 * * * * uucp /usr/lib/uucp/uucico -r1 -D -C
+.fi
+This will queue null jobs for the remote sites at the top of the hour; they
+will be processed by
+.I uucico
+when it runs five minutes later (the -C option apply to Taylor
+uucp-1.05 only, the -D option applies to Talor uucp-1.04 and up)
+.SH EXTENDED options
+An example of the options and how they interact is given below. The working
+order while processing the options is left to right:
+.nf
+X uupoll -gC site1 -gB site2 -x site3 -n -gA site4 site5
+.fi
+.PP
+this poll will:
+.PP
+- call immediate site1 with grade C or higher and will place a null job
+.PP
+- call immediate site2 with grade B or higher and will place a null job
+.PP
+- call immediate site3 with grade B or higher without placing a null job
+.PP
+- just placing a null job for site4 and site5 with grade A or higher. These
+sites will be called at the next regular schedule.
+.SH BUGS
+When more than one site is given on the command line and no \-n option is
+given there will be an immediate invocation of
+.IR uucico
+or
+.IR autopoll
+for
+.IR all
+sites given. That may lead to a `No port available' condition.
+.SH FILES
+.ta \w'/usr/spool/uucp/ 'u
+.nf
+/etc/uucp/ UUCP internal files/utilities
+/usr/spool/uucp/ Spool directory
+/tmp/poll.log This file is present only if uupoll has been
+X compiled to place the messages into a file.
+X Otherwise all messages will go to stderr.
+X The directory as well as the name may be
+X different. The name may be defined at compile time.
+.fi
+.SH SEE ALSO
+uucp(1C), uux(1C), uucico(8C), autopoll(8C)
+SHAR_EOF
+chmod 0444 uupoll/uupoll.8c ||
+echo 'restore of uupoll/uupoll.8c failed'
+Wc_c="`wc -c < 'uupoll/uupoll.8c'`"
+test 4787 -eq "$Wc_c" ||
+ echo 'uupoll/uupoll.8c: original size 4787, current size' "$Wc_c"
+fi
+# ============= uupoll/uupoll.c ==============
+if test -f 'uupoll/uupoll.c' -a X"$1" != X"-c"; then
+ echo 'x - skipping uupoll/uupoll.c (File already exists)'
+else
+echo 'x - extracting uupoll/uupoll.c (Text)'
+sed 's/^X//' << 'SHAR_EOF' > 'uupoll/uupoll.c' &&
+/* ---------------------------------------------------------------------------*
+X
+X Name: uupoll
+X
+X Author: Klaus Dahlenburg <kdburg@incoahe.hanse.de>
+X
+X Status: Public domain
+X
+X Copyright: none
+X
+X Funktion: The main intention behind this program was to get a full
+X replacement of the uupoll supplied by NeXT when using an
+X UUCP or a file structure that is different from that hardwired
+X config in NeXT's uupoll. The lack of source made it impossible
+X to modify the supplied uupoll.
+X
+X Call: uupoll [-n] [-x] [-g[A | 0-9,A-Z,a-z]] site ...
+X
+X -n just place a poll file but do not call uucico;
+X This option can be given only once.
+X -x meaningful only for sites not affected by the -n
+X option. It prevents the creation of a poll file;
+X the default is to place one. In case the poll fails
+X there will be no attempt to poll those sites on
+X the next general (unspecific) poll. If using
+X autopoll the site will be called at the next + 1
+X run of autopoll.
+X -g any grade may be given to meet the criteria for
+X a successful poll. The default being specified
+X in conf.h (A).
+X This option may be given individually for each
+X site to call.
+X site the name of the site to be called. As many sites
+X as necessary may be specified separated by at least
+X one blank.
+X Note: any site will be called with the options currently in
+X effect. The working order is left to right. Example:
+X uupoll -gQ site1 site2 -gZ site3 -n site4
+X site1 and site2 will be called immediate with grade Q
+X site3 will be called immediate with grade Z. Site4 will
+X have a poll file created with grade Z.
+X
+X Environment: NeXT 2.1
+X
+X Called Programs: sort, uniq, uucico (or autopoll), uuname
+X
+X Compile: no special options are needed
+X
+X Comments: - should run setuid UUCP or whatever userid is necessary to
+X write to the spool directory with the proper ownership of
+X the files and to run uucico.
+X - No alias expansion is done on the given names.
+*/
+X
+#if !defined(lint)
+static char rcsid[] = "$Id: uupoll.shar,v 1.1 1995/10/18 08:38:24 deraadt Exp $";
+#endif /* not lint */
+X
+/* $Log: uupoll.shar,v $
+/* Revision 1.1 1995/10/18 08:38:24 deraadt
+/* Initial revision
+/*
+/* Revision 1.2 1995/08/24 05:19:19 jtc
+/* Upgraded to Taylor UUCP 1.06.1 (Thanks to John Kohl).
+/*
+X * Revision 2.7 1994/04/14 17:22:04 kdburg
+X * major rework done
+X *
+X * Revision 2.6 1994/03/26 17:38:41 kdburg
+X * added support for UNAME_DIR; cleanup of some code; adjusted code after
+X * obtaining sitenames via popen()
+X *
+X * Revision 2.5 1994/03/24 19:01:24 kdburg
+X * some minor changes; some calls had their rc not checked
+X *
+X * Revision 2.4 1993/07/08 07:56:26 kdburg
+X * befor invoking autopoll stdin is now closed to avoid blocking of
+X * terminal
+X *
+X * Revision 2.3 1993/07/05 19:43:00 kdburg
+X * when used interactivly only the start msg is put into the msg-log
+X * so far defined (UULOG)
+X *
+X * Revision 2.2 1993/05/20 18:50:52 kdburg
+X * no execute permission to the poll-pgm (uucico/autopoll) was not
+X * reflected in the log; when to start message was not given when -x
+X * option was present
+X *
+X * Revision 2.1 1993/05/16 21:48:15 kdburg
+X * changed exit() to _exit() in case the exec fails within child
+X *
+X * Revision 2.0 1993/05/16 14:11:04 kdburg
+X * initial revision
+X * */
+X
+#define CAT 16
+#define SEVERE 8
+#define WARNING 4
+#define OK 0
+#define P_MODE 00647 /* file-mode for poll-file */
+/* Boolean types */
+typedef int bool;
+#undef TRUE
+#undef FALSE
+#define TRUE (1)
+#define FALSE (0)
+X
+#include "conf.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include <sys/time.h>
+X
+#define X_OK 1 /* access: executable ? */
+X
+#ifdef ALOG_FILE
+X static char Msg_Log[] = ALOG_FILE; /* name of msglog filename */
+#endif
+X
+#ifdef UNAME_DIR
+X static char subcmd[] = " | sort | uniq"; /* pipe that follows uuname */
+#else /* ! UNAME_DIR */
+X static char Sort[] = "uuname | sort | uniq"; /* default to obtain site names */
+#endif /*UNAME_DIR */
+X
+static char cGrade[] = DEF_GRADE; /* grade as defined in conf.h */
+static char dGrade[] = "A"; /* use this if DEF_GRADE is invalid */
+#ifdef AUTO_POLL
+X static char Auto_Dir[] = AUTO_DIR; /* autopoll lives here */
+#else
+X static char Cico_Dir[] = CICO_DIR; /* and here lives cico */
+#endif /* AUTO_POLL */
+X
+struct Sites {
+X char name[MAXHOSTNAMELEN+1]; /* name of site as supplied by uuname */
+X char grade[1]; /* as passed or defaulted */
+X bool flag; /* TRUE this site should be polled */
+X int asap; /* 1 without -n; 2 with -x option */
+};
+X struct Common_Stor {
+X int maxtab; /* high-water-mark for site tab */
+X char *Grade; /* use this as grade for calls */
+X char *Poll_Pgm; /* our name without path */
+X char *called_as; /* but called by this name */
+X int our_pid; /* our process-id */
+X char *Uucico; /* cico's name without path */
+X char This_Site[MAXHOSTNAMELEN+1]; /* our site name */
+X char System[MAXHOSTNAMELEN+1]; /* intermediate to hold sitename */
+X char *Usort; /* will hold uuname + subcmd */
+X struct passwd *pwd;
+X struct timeval tp;
+X struct timezone tzp;
+X struct Sites Sitetab[SITE_MAX];
+X char workf[300];
+X };
+X
+/* define the prototypes
+X * */
+X
+int set_mlog(FILE **seclog, struct Common_Stor *);
+int get_sites(struct Common_Stor *);
+int Check_Args(int argc, char *argv[], struct Common_Stor *);
+int Housekeeping(int argc, char *argv[], struct Common_Stor *);
+int Call_Site(struct Common_Stor *);
+void *storage(unsigned count, char *errloc, int *Rc, struct Common_Stor *);
+X
+extern int getpid();
+extern void free(void *ptr);
+extern int access(char *path, int mode);
+extern int gethostname(char *name, int namelen);
+extern int system(char *cmd);
+extern int fork();
+extern int execlp(char *name, char *arg0, ...);
+extern void *malloc(size_t byteSize);
+extern int getuid();
+extern int isatty(int);
+extern char *ttyname(int);
+extern int open(char *path, int flags, int mode);
+extern int close(int fd);
+#ifdef __STRICT_ANSI__
+extern FILE *popen(char *command, char *type);
+extern int pclose(FILE *stream);
+extern void _exit(int status);
+#endif /* __STRICT_ANSI__ */
+#ifdef __STRICT_BSD__
+extern int fprintf(FILE *stream, const char *format, ...);
+extern int fclose(FILE *stream);
+extern char *strerror(int errnum);
+extern int fflush(FILE *stream);
+extern void exit(int status);
+#endif /* __STRICT_BSD__ */
+X
+/* --------------------------------------------------------------------------*/
+/* Main */
+/* --------------------------------------------------------------------------*/
+X
+int main(int argc, char *argv[])
+{
+X
+X struct Common_Stor *sCom_Sto;
+X int Maxrc = OK; /* Max err-code encountered so far */
+X int k = 0;
+X
+X if ( NULL == (sCom_Sto = malloc(sizeof(struct Common_Stor))) ) {
+X fprintf(stderr,"%s: (C) malloc failed (%s). Reason: %i (%s)\n",
+X argv[0],"Common_Stor",errno,strerror(errno));
+X exit (CAT);
+X }
+X
+X Maxrc = Housekeeping(argc, argv, sCom_Sto);
+X
+/* If any errors popped up so far they are of such a nature that it is very
+X * questionable to continue; so we better bail out in this case.
+X */
+X if (Maxrc <= WARNING) {
+X k = Call_Site(sCom_Sto);
+X Maxrc = Maxrc >= k ? Maxrc:k;
+X }
+X k = gettimeofday(&sCom_Sto->tp, &sCom_Sto->tzp);
+X fprintf(stderr,"%s: (I) ended with rc = %i on %s\n",
+X sCom_Sto->called_as,
+X Maxrc,k!=0 ? "time unavailable":ctime(&sCom_Sto->tp.tv_sec));
+X fclose(stderr);
+X free(sCom_Sto);
+X sCom_Sto = NULL;
+X exit (Maxrc);
+}
+X
+/* --------------------------------------------------------------------------*/
+/* Functions */
+/* --------------------------------------------------------------------------*/
+X
+/* --------------------------------------------------------------------
+X * housekeeping
+X */
+X
+int Housekeeping(argc, argv, sCom_Sto)
+X int argc;
+X char *argv[];
+X struct Common_Stor *sCom_Sto; {
+X
+X FILE *seclog = NULL;
+X int Rc = OK;
+X int Rci = OK; /* intermediate rc as returnd by functions */
+X
+X sCom_Sto->our_pid = getpid();
+X
+/*
+X * get our name sans path
+X * */
+X
+X sCom_Sto->called_as = argv[0] + strlen(*argv);
+X for(;sCom_Sto->called_as >= argv[0] && *--sCom_Sto->called_as != '/';)
+X ;
+X sCom_Sto->called_as++;
+X
+/* if defined set up the name of the message log file otherwise
+X * stderr will be used. Setup the cmd string to obtain all known sitenames
+X * which will be sorted in ascending order with duplicates removed
+X * */
+X
+X Rc = set_mlog(&seclog, sCom_Sto);
+X if (Rc > WARNING)
+X return (Rc);
+X
+/* put out the started message including the time and the userid.
+X * */
+X
+X sCom_Sto->pwd = getpwuid(getuid());
+X
+X if ((gettimeofday(&sCom_Sto->tp, &sCom_Sto->tzp)) != 0) { /* unacceptable error */
+X fprintf(stderr,"%s: (C) gettimeofday() failed. Reason: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X
+X if (seclog != NULL) {
+X fprintf(seclog,"\n%s: (I) started by `%s' (%s) on %s",
+X sCom_Sto->called_as,
+X (sCom_Sto->pwd==NULL) ? "???":sCom_Sto->pwd->pw_name,
+X ttyname(0),
+X ctime(&sCom_Sto->tp.tv_sec));
+X fclose(seclog);
+X }
+X fprintf(stderr,"\n%s: (I) started by `%s' on %s",
+X sCom_Sto->called_as,
+X (sCom_Sto->pwd==NULL) ? "???":sCom_Sto->pwd->pw_name,
+X ctime(&sCom_Sto->tp.tv_sec));
+X
+/* set up the default grade
+X * */
+X
+X sCom_Sto->Grade = dGrade; /* set default for now */
+X if (strlen(cGrade) != 1) {
+X fprintf(stderr,"%s: (W) grade %s invalid; default `%s' used\n",
+X sCom_Sto->called_as,cGrade,sCom_Sto->Grade);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else
+X sCom_Sto->Grade = cGrade; /* Ok, take the one from conf.h */
+X
+/* get the program to actually call the site. This is either UUCICO
+X * or AUTOPOLL or something completely different.
+X * */
+X
+#ifdef AUTO_POLL
+X sCom_Sto->Uucico = Auto_Dir + strlen(Auto_Dir);
+X for(;sCom_Sto->Uucico >= Auto_Dir && *--sCom_Sto->Uucico != '/';)
+X ;
+X sCom_Sto->Uucico++;
+#else /* ! AUTO_POLL */
+X sCom_Sto->Uucico = Cico_Dir + strlen(Cico_Dir);
+X for(;sCom_Sto->Uucico >= Cico_Dir && *--sCom_Sto->Uucico != '/';)
+X ;
+X sCom_Sto->Uucico++;
+#endif /* AUTO_POLL */
+X
+/* get the path to ourself.
+X * */
+X
+X sCom_Sto->Poll_Pgm = argv[0] + strlen(argv[0]);
+X for(;sCom_Sto->Poll_Pgm >= argv[0] && *--(sCom_Sto->Poll_Pgm) != '/';)
+X ;
+X sCom_Sto->Poll_Pgm++;
+X
+/* obtain our sitename
+X * */
+X
+X if ((gethostname(sCom_Sto->This_Site,MAXHOSTNAMELEN+1)) != 0) {
+X fprintf(stderr,"%s: (W) hostname could not be obtained\n",
+X sCom_Sto->called_as);
+X Rc = (Rc >= WARNING) ? Rc:WARNING;
+X }
+X
+/* obtain all known sitenames
+X * */
+X
+X Rci = get_sites(sCom_Sto);
+X Rc = Rci > Rc ? Rci:Rc;
+X
+/* check the arguments that we are called with
+X * */
+X
+X Rci = Check_Args(argc, argv, sCom_Sto);
+X Rc = Rci > Rc ? Rci:Rc;
+X
+X return (Rc);
+}
+X
+/* --------------------------------------------------------------------
+X * check all relevant arguments that have been passed to us. Those args
+X * that may be needed for a recall will be copied to a workfield.
+X * */
+X
+int Check_Args(int argc, char *argv[], struct Common_Stor *sCom_Sto) {
+X int i,s,k,n = 0;
+X int Rc = OK;
+X int One_Site = 0; /* TRUE: found at least one valid site to call */
+X int poll_file = 1; /* FALSE: after -x option given */
+X int def_flag = 0; /* TRUE: when option -n was encountered */
+X
+X /* --------------------------------------------------------------*/
+X /* check the arguments passed to us */
+X /* */
+X /* These are: -n -> place a POLL file but do not start uucico */
+X /* -x -> do not place a poll file (immed. poll only) */
+X /* -g? -> specify a grade with the POLL file. The ? */
+X /* may be: 0-9, A-Z, a-z */
+X /* (validity not checked!) */
+X /* site name of the site to call. There many be as */
+X /* many as necessary separated by at least one */
+X /* blank */
+X /* Note: all options will stay in effect as long as they are'nt */
+X /* changed by a new setting. The options -n and -x can't */
+X /* be negated once given; that means place all sites */
+X /* that should be immediately polled to the left of the */
+X /* -n option; the same applies to the -x option which must */
+X /* be left of the -n option to come into effect! */
+X /* The working order is left to right! */
+X /* --------------------------------------------------------------*/
+X
+X for (i = 1, s = 0; i < argc; i++) {
+X k = strlen(argv[i]);
+X switch (*argv[i]) {
+X
+X /* ----> handle the options */
+X
+X case '-':
+X n = 1;
+X switch (*(argv[i]+n)) {
+X case 'n':
+X if (k > 2) {
+X fprintf(stderr,"%s: (E) invalid specification %s\n",
+X sCom_Sto->called_as,argv[i]);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X def_flag = 1;
+X break;
+X case 'x':
+X if (k > 2) {
+X fprintf(stderr,"%s: (E) invalid specification %s\n",
+X sCom_Sto->called_as,argv[i]);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X if (def_flag) {
+X fprintf(stderr,"%s: (W) -x after -n has no effect\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X else {
+X poll_file = 0;
+X }
+X break;
+X case 'g':
+X if (k > 3) {
+X fprintf(stderr,"%s: (E) invalid specification %s\n",
+X sCom_Sto->called_as,argv[i]);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X if (*(argv[i]+n+1) == '\0') {
+X fprintf(stderr,"%s: (E) missing grade\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X if (isalnum(*(argv[i]+n+1)) == 0) {
+X fprintf(stderr,"%s: (E) invalid grade %s\n",
+X sCom_Sto->called_as,argv[i]);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X break;
+X }
+X strcpy(sCom_Sto->Grade,(argv[i]+n+1));
+X break;
+X default:
+X fprintf(stderr,"%s: (W) missing/unknown option `-%s' ignored\n",
+X sCom_Sto->called_as,argv[i]+n);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X break;
+X } /* end of switch (*(argv[i]+n)) */
+X break;
+X
+X /* ----> handle the sitenames */
+X
+X default:
+X if (strcmp(argv[i],sCom_Sto->This_Site) == 0) {
+X fprintf(stderr,"%s: (W) ignoring to call *ourself* %s\n",
+X sCom_Sto->called_as,argv[i]);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X break;
+X }
+X strcpy(sCom_Sto->System,argv[i]);
+X for(s=0;s<=sCom_Sto->maxtab;s++) {
+X if ((n=strcmp(sCom_Sto->Sitetab[s].name,sCom_Sto->System)) >= 0) {
+X break;
+X }
+X }
+X if (n != 0) {
+X fprintf(stderr,"%s: (W) unknown site (ignored): %s\n",
+X sCom_Sto->called_as,sCom_Sto->System);
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X break;
+X }
+X
+X /* ----> if there was no error we arrive here to save the data */
+X
+X strcpy(sCom_Sto->Sitetab[s].grade,sCom_Sto->Grade);
+X One_Site = sCom_Sto->Sitetab[s].flag = 1; /* poll this site */
+X if (def_flag)
+X sCom_Sto->Sitetab[s].asap = 0; /* poll on next schedule */
+X else {
+X sCom_Sto->Sitetab[s].asap = 1; /* poll immediately */
+X if (! poll_file)
+X sCom_Sto->Sitetab[s].asap++; /* and do not place a poll file */
+X }
+X s++;
+X break;
+X } /* end of switch (*argv[i]) */
+X } /* end of for(...) */
+X
+/* now let's check what we've gotten so far. If no valid data has been */
+/* entered we will indicate that to prevent further processing */
+X
+X if (! One_Site) {
+X fprintf(stderr,"%s: (E) found no site to call\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X
+return (Rc);
+}
+X
+int Call_Site(struct Common_Stor *sCom_Sto) {
+X
+/* For all sites that carry the -n flag we will place */
+/* a poll file into the appropriate directory. For all others there will */
+/* be an immediate call to uucico (or autopoll) */
+/* Those sites that have been named on the command have the corresponding */
+/* flag byte set to one. */
+X
+X int fdpoll; /* fildes for the poll file */
+X int mode = P_MODE; /* mode for poll file */
+X int i = 0;
+X int Rc = OK;
+X int pid = 0; /* process-id after fork() */
+X
+X for(i=0;(i<=sCom_Sto->maxtab);i++) {
+X if (sCom_Sto->Sitetab[i].flag == 0) /* should we trigger this one ? */
+X continue; /* nope */
+X
+/* processing done for delayed polls only */
+X
+X if (sCom_Sto->Sitetab[i].asap <= 1) { /* do not place a poll file */
+X /* for sites that will be polled */
+X /* immediate and carry the -x option */
+#ifdef HAVE_SPOOLDIR_TAYLOR
+X sprintf(sCom_Sto->workf,"%s/%s/C./C.%sPOLL",
+X SPOOL_DIR,
+X sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Sitetab[i].grade);
+#endif
+#ifdef HAVE_SPOOLDIR_HDB
+X sprintf(sCom_Sto->workf,"%s/%s/C.%s%sPOLL",
+X SPOOL_DIR,
+X sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Sitetab[i].grade);
+#endif
+#ifdef HAVE_SPOOLDIR_BSD
+X sprintf(sCom_Sto->workf,"%s/C./C.%s%sPOLL",
+X SPOOL_DIR,
+X sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Sitetab[i].grade);
+#endif
+X
+X fflush(stderr);
+X if ((fdpoll=open(sCom_Sto->workf,O_CREAT,mode)) <= 0) {
+X fprintf(stderr,"%s: (E) couldn't place poll file for system: %s. Reason: %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Sitetab[i].name,
+X strerror(errno));
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X else {
+X if (close(fdpoll) != 0) {
+X fprintf(stderr,"%s: (W) close failed for poll file; system: %s. Reason: %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Sitetab[i].name,
+X strerror(errno));
+X Rc = Rc >= WARNING ? Rc:WARNING;
+X }
+X }
+X }
+X
+/* the following processing is done for immediate polls only
+X * there is no wait for the completion of the called program that actually
+X * calls the site
+X * */
+X
+X fflush(stderr);
+X if (Rc <= WARNING) {
+X fprintf(stderr,"%s: (I) site %s will be called %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Sitetab[i].name,
+X sCom_Sto->Sitetab[i].asap == 0 ?
+X "upon next poll":"immediately");
+X if (sCom_Sto->Sitetab[i].asap >= 1)
+X {
+#ifdef AUTO_DIR
+X if ( access(Auto_Dir,X_OK) != 0) /* do we have xecute permission ? */
+#else /* ! AUTO_DIR */
+X if ( access(Cico_Dir,X_OK) != 0) /* do we have xecute permission ? */
+#endif /* AUTO_DIR */
+X {
+X fprintf(stderr,"%s: (C) could not start %s. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,
+X errno,strerror(errno));
+X return (Rc >= CAT ? Rc:CAT); /* abandon the run */
+X }
+X switch (pid = fork())
+X {
+X case -1:
+X fprintf(stderr,"%s: (C) could not fork() Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,
+X errno,strerror(errno));
+X return (Rc >= CAT ? Rc:CAT);
+X case 0:
+X if (isatty(0))
+X close(0); /* don't block the terminal by autopoll */
+#ifdef AUTO_DIR
+X execlp(Auto_Dir,
+#else /* ! AUTO_DIR */
+X execlp(Cico_Dir,
+#endif /*AUTO_DIR */
+X sCom_Sto->Uucico,
+X "-D", "-r1", "-s",
+X sCom_Sto->Sitetab[i].name,0);
+X fprintf(stderr,"%s: (C) could not start %s. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,
+X errno,strerror(errno));
+X _exit (CAT); /* child: bail out */
+X default:
+X fflush(stderr);
+X fprintf(stderr,"%s: (I) %s [%d] started; site: %s\n",
+X sCom_Sto->called_as,
+X sCom_Sto->Uucico,
+X pid,
+X sCom_Sto->Sitetab[i].name);
+X } /* switch (pid = fork()) */
+X } /* if (Sitetab ...) */
+X } /* if (Rc ...) */
+X } /* for(i=0;(i<= ...)) */
+X return (Rc);
+}
+X
+X /* ------------------------------------------------------------------
+X * storage - get some memory
+X */
+X
+void *storage(unsigned count,
+X char *location,
+X int *Rc,
+X struct Common_Stor *sCom_Sto)
+{
+X void *p;
+X
+X if( NULL == (p= malloc(count)) ) {
+X fprintf(stderr,"%s: (C) malloc failed (%s). Reason: %i (%s)\n",
+X sCom_Sto->called_as,location,errno,strerror(errno));
+X *Rc = *Rc >= CAT ? *Rc:CAT;
+X }
+X return p;
+}
+X
+/* ------------------------------------------------------------------
+X * if defined open the message log file otherwise all mesages will go
+X * to stderr. If UNAME_DIR is defined construct the command to be
+X * passed to popen(); if undefined the default will be used
+X * */
+X
+int set_mlog(FILE **seclog, struct Common_Stor *sCom_Sto) {
+X
+X int Rc = 0;
+X
+#ifdef ALOG_FILE
+X if (!isatty(0)) {
+X if ((freopen(Msg_Log,"a",stderr)) == NULL) {
+X fprintf(stdout,"%s: (C) Could not open msglog: %s\n",
+X sCom_Sto->called_as,Msg_Log);
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X }
+X else {
+X if ((*seclog = fopen(Msg_Log,"a")) == NULL) {
+X fprintf(stderr,"%s: (C) Could not open msglog: %s\n",
+X sCom_Sto->called_as,Msg_Log);
+X return (Rc >= CAT ? Rc:CAT);
+X }
+X }
+#endif /* ALOG_FILE */
+X
+/* set up the pipe together with the complete path to uuname */
+X
+#ifdef UNAME_DIR
+X if ((sCom_Sto->Usort = (char *)storage (sizeof(UNAME_DIR)+sizeof(subcmd),
+X "Sort",&Rc, sCom_Sto)) != NULL) {
+X strncpy(sCom_Sto->Usort,UNAME_DIR,strlen(UNAME_DIR)); /* paste in the path */
+X strcat(sCom_Sto->Usort,subcmd); /* chain the pipe to it */
+X }
+#else /* ! UNAME_DIR */
+X sCom_Sto->Usort = &Sort; /* set pointer to uuname + sort */
+#endif /* UNAME_DIR */
+X
+X return (Rc);
+}
+X
+/* ------------------------------------------------------------------
+X * obtain all active sitenames
+X * */
+X
+int get_sites(struct Common_Stor *sCom_Sto) {
+X
+X int i = 0;
+X int n;
+X int Rc = 0;
+X FILE *infile;
+X
+X if ((infile=popen(sCom_Sto->Usort,"r")) != NULL) {
+X while(fgets(sCom_Sto->Sitetab[i].name,MAXHOSTNAMELEN+1,infile)) {
+X if (i > SITE_MAX) { /* let'm run so that we can give */
+X i++; /* the user some guidance */
+X continue; /* we'll tell the user later on */
+X }
+X n = strlen(sCom_Sto->Sitetab[i].name)-1; /* offset: next to last char */
+X sCom_Sto->Sitetab[i].name[n] = '\0'; /* strip trailing newline */
+X sCom_Sto->Sitetab[i].flag = FALSE; /* TRUE: poll this site */
+X sCom_Sto->Sitetab[i].asap = FALSE; /* TRUE: immediate poll */
+X strcpy(sCom_Sto->Sitetab[i].grade,sCom_Sto->Grade);
+X sprintf(sCom_Sto->workf,"%s%s",STATUS_DIR,sCom_Sto->Sitetab[i].name);
+X sCom_Sto->maxtab = i++; /* set high-water-mark */
+X }
+X if (ferror(infile) != 0) {
+X fprintf(stderr,"%s: (E) fgets() for sitenames failed reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X pclose(infile);
+X
+X /*
+X * check for an empty table (strange but possible)
+X */
+X
+X if (sCom_Sto->maxtab == 0) {
+X fprintf(stderr,"%s: (E) could not obtain sitenames.\n",
+X sCom_Sto->called_as);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X else {
+X
+X /* in case the internal table overflows we'll now give notice and tell
+X * the user by which amount the table has to be increased to hold all
+X * site-names
+X */
+X
+X if (i > SITE_MAX) {
+X fprintf(stderr,"%s: (E) number of sites > internal tab\n",
+X sCom_Sto->called_as);
+X fprintf(stderr,"%s: (E) increase SITE_MAX to >= %d and recompile\n",
+X sCom_Sto->called_as,i);
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X }
+X } /* sCom_Sto->maxtab == 0 */
+X
+X }
+X else /* infile == NULL */
+X {
+X fprintf(stderr,"%s: (E) could not sort sitenames. Reason-code: %i (%s)\n",
+X sCom_Sto->called_as,errno,strerror(errno));
+X Rc = Rc >= SEVERE ? Rc:SEVERE;
+X
+X } /* if ((infile=popen(sCom_Sto->Usort,"r")) ... */
+X
+X return (Rc);
+}
+SHAR_EOF
+chmod 0444 uupoll/uupoll.c ||
+echo 'restore of uupoll/uupoll.c failed'
+Wc_c="`wc -c < 'uupoll/uupoll.c'`"
+test 27587 -eq "$Wc_c" ||
+ echo 'uupoll/uupoll.c: original size 27587, current size' "$Wc_c"
+fi
+exit 0
diff --git a/gnu/libexec/uucp/contrib/uuq.sh b/gnu/libexec/uucp/contrib/uuq.sh
new file mode 100644
index 00000000000..a5d88e95223
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uuq.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+#
+# uuq - a script to examine and display the Taylor spool directory contents.
+# note - uses the uuname script or similar functionality.
+# Zacharias Beckman
+
+SPOOLDIR="/usr/spool/uucp"
+SYSTEMS=`uuname`
+TMPFILE="/tmp/uuq.tmp"
+FORSYSTEM=""
+DELETE=""
+LONG=0
+SINGLE=0
+
+while [ "$1" != "" ]
+do
+ case $1 in
+ -l) LONG=1
+ shift
+ ;;
+ -s) shift
+ SYSTEMS=$argv[1]
+ SINGLE=1
+ shift
+ ;;
+ -d) shift
+ DELETE=$argv[1]
+ shift
+ ;;
+ -h) echo "uuq: usage uuq [options]"
+ echo " -l long listing (may take a while)"
+ echo " -s n run uuq only for system n"
+ echo " -d n delete item n from the queue (required -s)"
+ exit 1
+ ;;
+ *) echo "uuq: invalid option"
+ exit 1
+ ;;
+ esac
+done
+
+if [ "${DELETE}" != "" ] && [ ${SINGLE} != 1 ] ; then
+ echo "uuq: you must specify a system to delete the job from:"
+ echo " uuq -s wizard -d D.0004"
+ exit 1
+fi
+
+cd ${SPOOLDIR}
+
+# if we are deleting a job, then do that first and exit without showing
+# any other queue information
+
+if [ "${DELETE}" != "" ] ; then
+ if [ -d ${SYSTEMS}/D. ] ; then
+ cd ${SYSTEMS}/C.
+ PACKET=${DELETE}
+ if [ -f ${PACKET} ] ; then
+ EXFILE=../D.X/`awk '{if (NR == 2) print $2}' ${PACKET}`
+ DFILE=../D./`awk '{if (NR == 1) print $2}' ${PACKET}`
+ echo "deleting job ${PACKET}"
+ rm ${PACKET}
+ rm ${EXFILE}
+ rm ${DFILE}
+ else
+ echo "uuq: job ${PACKET} not found"
+ exit 1
+ fi
+ else
+ echo "uuq: system ${SYSTEMS} not found"
+ fi
+
+ exit 1
+fi
+
+# use the 'uuname' script to obtain a list of systems for the 'sys' file,
+# then step through each directory looking for appropriate information.
+
+if [ ${LONG} -gt 0 ] ; then
+ echo "system"
+ echo -n "job# act size command"
+fi
+
+for DESTSYSTEM in ${SYSTEMS} ; do
+ # if there is an existing directory for the named system, cd into it and
+ # "do the right thing."
+
+ if [ -d ${DESTSYSTEM} ] ; then
+ cd ${DESTSYSTEM}/C.
+
+ PACKET=`ls`
+
+ if [ "${PACKET}" != "" ] ; then
+ # if a long listing has been required, extra information is printed
+
+ echo ""
+ echo "${DESTSYSTEM}:"
+
+ # now each packet must be examined and appropriate information is
+ # printed for this system
+
+ if [ ${LONG} -gt 0 ] ; then
+ for PACKET in * ; do
+ EXFILE=../D.X/`awk '{if (NR == 2) print $2}' ${PACKET}`
+ DFILE=../D./`awk '{if (NR == 1) print $2}' ${PACKET}`
+ echo -n "${PACKET} " > ${TMPFILE}
+ gawk '{if (NR == 2) printf(" %s ", $1);}' ${PACKET} >> ${TMPFILE}
+ ls -l ${DFILE}|awk '{printf("%-10d ", $4)}' >> ${TMPFILE}
+ if [ -f ${EXFILE} ] ; then
+ gawk '/U / {printf("(%s)", $2);}\
+ /C / {print substr($0,2,length($0));}' ${EXFILE} >> ${TMPFILE}
+ else
+ echo "---" >> ${TMPFILE}
+ fi
+
+ cat ${TMPFILE}
+ done
+ cat ${SPOOLDIR}/.Status/${DESTSYSTEM}
+ else
+ ls
+ fi
+ fi
+ fi
+
+ cd ${SPOOLDIR}
+done
diff --git a/gnu/libexec/uucp/contrib/uurate.c b/gnu/libexec/uucp/contrib/uurate.c
new file mode 100644
index 00000000000..bcefc7b5732
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uurate.c
@@ -0,0 +1,1860 @@
+/*
+ * @(#)uurate.c 1.2 - Thu Sep 3 18:32:46 1992
+ *
+ * This program digests log and stats files in the "Taylor" format
+ * and outputs various statistical data to standard out.
+ *
+ * Author:
+ * Bob Denny (denny@alisa.com)
+ * Fri Feb 7 13:38:36 1992
+ *
+ * Original author:
+ * Mark Pizzolato mark@infopiz.UUCP
+ *
+ * Edits:
+ * Bob Denny - Fri Feb 7 15:04:54 1992
+ * Heavy rework for Taylor UUCP. This was the (very old) uurate from
+ * DECUS UUCP, which had a single logfile for activity and stats.
+ * Personally, I would have done things differently, with tables
+ * and case statements, but in the interest of time, I preserved
+ * Mark Pizzolato's techniques and style.
+ *
+ * Bob Denny - Sun Aug 30 14:18:50 1992
+ * Changes to report format suggested by Francois Pinard and others.
+ * Add summary report, format from uutraf.pl (perl script), again
+ * thanks to Francois. Integrate and checkout with 1.03 of Taylor UUCP.
+ *
+ * Stephan Niemz <stephan@sunlab.ka.sub.org> - Fri Apr 9 1993
+ * - Print totals in summary report,
+ * - show all commands in execution report,
+ * - count incoming calls correctly,
+ * - suppress empty tables,
+ * - don't divide by zero in efficiency report,
+ * - limit the efficiency to 100% (could be more with the i-protocol),
+ * - suppress some zeros to improve readability,
+ * - check for failure of calloc,
+ * - -h option changed to -s for consistency with all other uucp commands
+ * (but -h was left in for comptibility).
+ *
+ * Scott Boyd <scott@futures.com> - Thu Aug 26 13:21:34 PDT 1993
+ * - Changed hosts linked-list insertion routine so that hosts
+ * are always listed in alphabetical order on reports.
+ *
+ * Klaus Dahlenburg <kdburg@incoahe.hanse.de> - Fri Jun 18 1993 (1.2.2)
+ * - redesigned the printed layout (sticked to those 80 column tubes).
+ * - 'Retry time not ...' and ' ERROR: All matching ports ...' will now be
+ * counted as calls and will raise the failed-call counter.
+ * - times now shown as hh:mm:ss; the fields may hold up to 999 hrs
+ * (a month equals 744 hrs at max). Printing will be as follows:
+ *
+ * hrs > 0 hh:mm:ss
+ * min > 0 mm:ss
+ * sec > 0 ss
+ * leading zeroes are suppressed.
+ *
+ * - the bytes xfered will be given in thousands only (we're counting
+ * so 1K is 1000 bytes!). Sums up to 9,999,999.9 thousand can be shown.
+ * - dropped the fractions of a byte in columns: bytes/second (avg cps).
+ * - File statistic changed to display in/out in one row instead of 2
+ * separate reports.
+ * - eliminated the goto in command report and tightened the code; also
+ * the 'goto usage' has been replaced by a call to void usage() with no
+ * return (exit 1).
+ * - a totaling is done for all reports now; the total values are held
+ * within the structure; after finishing read there will be an alloc
+ * for a site named 'Total' so that the totals line will be printed
+ * more or less automatically.
+ * - option -t implemented: that is every possible report will be given.
+ * - the start and end date/time of the input files are printed; can be
+ * dropped by the -q option at run time.
+ * - it is now possible to use Log/Stats files from V2_LOGGING configs.
+ * They must however not be mixed together (with each other).
+ * - the Log/Stats files are taken from config which is passed via
+ * Makefile at compile time. Variable to set is: newconfigdir. If the
+ * default config can't be read the default values are used
+ * (the config is optional!).
+ * Note: keyword/filename must be on the same line (no continuation).
+ * - -I option implemented to run with a different config file. In case
+ * the file can't be opened the run is aborted!
+ * - -q option implemented to run without environment report (default is
+ * FALSE: print the report).
+ * - -p option added to print protocol statistics: one for the packets
+ * and one for the errors encountered
+ * - reapplied patch by Scott Boyd <scott@futures.com> that I did not
+ * get knowledge of
+ */
+/* $Log: uurate.c,v $
+/* Revision 1.1 1995/10/18 08:38:24 deraadt
+/* Initial revision
+/*
+/* Revision 1.3 1995/08/24 05:19:21 jtc
+/* Upgraded to Taylor UUCP 1.06.1 (Thanks to John Kohl).
+/*
+ * Revision 1.15 1994/04/07 21:47:11 kdburg
+ * printed 'no data avail' while there was data; layout chnaged
+ * (cosmetic only)
+ *
+ * Revision 1.14 1994/04/07 21:16:32 kdburg
+ * the layout of the protocol-used line within the LOGFILE changed
+ * from 1.04 to 1.05; both formats may be used together; output
+ * changed for packet report (columns adjusted)
+ *
+ * Revision 1.13 1994/04/04 10:04:35 kdburg
+ * cosmetic change to the packet-report (separator lines)
+ *
+ * Revision 1.12 1994/03/30 19:52:04 kdburg
+ * incorporated patch by Scott Boyd which was missing from this version
+ * of uurate.c. Left the comment in cronological order.
+ *
+ * Revision 1.11 1994/03/28 18:53:22 kdburg
+ * config not checked properly for 'logfile/statsfile' overwrites, bail-out
+ * possible; wrong file name written to log for statsfile when found
+ *
+ * Revision 1.10 1993/09/28 16:46:51 kdburg
+ * transmission failures denoted by: failed after ... in stats file
+ * have not been counted at all.
+ *
+ * Revision 1.9 1993/08/17 23:38:36 kdburg
+ * sometimes a line(site) was missing from the protocol stats due
+ * to a missing +; added option -d and -v reassing option -h to print
+ * the help; a zero was returned instead of a null-pointer by
+ * prot_sum
+ *
+ * Revision 1.8 1993/07/03 06:58:55 kdburg
+ * empty input not handled properly; assigned some buffer to input; msg
+ * not displayed when no protocol data was available
+ *
+ * Revision 1.7 1993/06/27 10:31:53 kdburg
+ * rindex was replaced by strchr must be strrchr
+ *
+ * Revision 1.6 1993/06/26 06:59:18 kdburg
+ * switch hdr_done not reset at beginning of protocol report
+ *
+ * Revision 1.5 1993/06/25 22:22:30 kdburg
+ * changed rindex to strchr; if there is no NEWCONFIG defined take
+ * appropriate action
+ *
+ * Revision 1.4 1993/06/25 20:04:07 kdburg
+ * added comment about -p option; inserted proto for rindex
+ *
+ * Revision 1.3 1993/06/25 19:31:14 kdburg
+ * major rework done; added protocol reports (normal/errors)
+ *
+ * Revision 1.2 1993/06/21 19:53:54 kdburg
+ * init
+ * */
+
+char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2.2";
+static char rcsid[] = "$Id: uurate.c,v 1.1 1995/10/18 08:38:24 deraadt Exp $";
+#include <ctype.h> /* Character Classification */
+#include <math.h>
+#include "uucp.h"
+/* uucp.h includes string.h or strings.h, no include here. */
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#define _DEBUG_ 0
+
+/*
+ * Direction of Calling and Data Transmission
+ */
+
+#define IN 0 /* Inbound */
+#define OUT 1 /* Outbound */
+
+/*
+ * define some limits
+ */
+#define MAXCOLS 8 /* report has this # of columns incl. 'name' */
+#define MAXREP 6 /* number of reports available */
+#define MAXFNAME 64 /* max input file name length incl. path*/
+#define MAXDNAME 8 /* max display (Hostname) name length */
+
+/*
+ * Data structures used to collect information
+ */
+struct File_Stats
+ {
+ int files; /* Files Transferred */
+ unsigned long bytes; /* Data Size Transferred*/
+ double time; /* Transmission Time */
+ };
+
+struct Phone_Call
+ {
+ int calls; /* Call Count */
+ int succs; /* Successful calls */
+ double connect_time; /* Connect Time Spent */
+ struct File_Stats flow[2]; /* Rcvd & Sent Data */
+ };
+
+struct Execution_Command
+ {
+ struct Execution_Command *next;
+ char Commandname[64];
+ int count;
+ };
+
+struct Protocol_Summary
+ {
+ struct Protocol_Summary *next;
+ char type[3];
+ long int pr_cnt;
+ long int pr_psent;
+ long int pr_present;
+ long int pr_preceived;
+ long int pr_eheader;
+ long int pr_echksum;
+ long int pr_eorder;
+ long int pr_ereject;
+ long int pr_pwinmin;
+ long int pr_pwinmax;
+ long int pr_psizemin;
+ long int pr_psizemax;
+ };
+
+struct Host_entry
+ {
+ struct Host_entry *next;
+ char Hostname[32];
+ struct Execution_Command *cmds; /* Local Activities */
+ struct Phone_Call call[2]; /* In & Out Activities */
+ struct Protocol_Summary *proto;
+ };
+
+ struct Host_entry *hosts = NULL;
+ struct Host_entry *tot = NULL;
+ struct Host_entry *cur = NULL;
+ struct Execution_Command *cmd, *t_cmds = NULL;
+ struct Protocol_Summary *prot, *t_prot, *s_prot, *ss_prot = NULL;
+/*
+ * Stuff for getopt()
+ */
+
+extern int optind; /* GETOPT : Option Index */
+extern char *optarg; /* GETOPT : Option Value */
+#if ! HAVE_STDLIB_H
+ extern pointer *calloc();
+#endif /* HAVE_STDLIB_H */
+/*
+ * Default files to read. Taken from Taylor compile-time configuration.
+ * def_logs must look like an argvec, hence the dummy argv[0].
+ * Maybe later modified by scanning the config
+ */
+
+static char *def_logs[3] = { NULL, NULL, NULL};
+char *I_conf = NULL; /* points to config lib given by -I option */
+char *D_conf = NULL; /* points to config lib from makefile */
+char *Tlog = NULL; /* points to Log-file */
+char *Tstat = NULL; /* points to Stats-file */
+char Pgm_name[64]; /* our pgm-name */
+char logline[BUFSIZ+1]; /* input area */
+char noConf[] = "- not defined -";
+char buff[16*BUFSIZ];
+char sbuff[2*BUFSIZ];
+
+/*
+ * Boolean switches for various decisions
+ */
+
+ int p_done = FALSE; /* TRUE: start date/time of file printed */
+ int hdr_done = FALSE; /* TRUE: report header printed */
+ int show_files = FALSE; /* TRUE: -f option given */
+ int show_calls = FALSE; /* TRUE: -c option given */
+ int show_commands = FALSE; /* TRUE: -x option given */
+ int show_efficiency = FALSE; /* TRUE: -e option given */
+ int show_all = FALSE; /* TRUE: -t option given */
+ int show_proto = FALSE; /* TRUE: -p option given */
+ int use_stdin = FALSE; /* TRUE: -i option given */
+ int be_quiet = FALSE; /* TRUE: -q option given */
+ int have_files[2]; /* TRUE: [IN] or [OUT] files found */
+ int have_calls = FALSE; /* TRUE: in/out calls found */
+ int have_commands = FALSE; /* TRUE: found uuxqt records */
+ int have_proto = FALSE; /* TRUE: protocol data found */
+ int no_records = TRUE; /* FALSE: got one record from file */
+
+/*
+ * protos
+ */
+
+static pointer *getmem(unsigned n);
+static void inc_cmd(struct Execution_Command **, char *name);
+static void fmtime(double sec, char *buf);
+static void fmbytes(unsigned long n, char *buf);
+static void usage();
+static int chk_config(char *conf, int n, int type);
+static void hdrprt(char c, int bot);
+struct Protocol_Summary *prot_sum(struct Protocol_Summary **, char *, int);
+
+/*
+ * BEGIN EXECUTION
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ FILE *Log = NULL;
+ int c;
+ char *p, *s, *stt, *flq = NULL;
+ char Hostname[MAXHOSTNAMELEN]; /* def taken from <sys/param.h> */
+ char Filename[15]; /* filename to be printed */
+ char in_date[14]; /* holds the date info of record read*/
+ char in_time[14]; /* holds the time info of record read */
+ char dt_info[31]; /* holds the date info from the last record read */
+ char *logmsg;
+ int sent, called = IN;
+ int report = 0; /* if <= 0 give msg that no report was avail. */
+ int junk;
+
+ /* --------------------------------------------------------------------
+ * P r o l o g
+ * --------------------------------------------------------------------
+ */
+
+ Hostname[0] = '\0';
+ have_files[IN]= have_files[OUT]= FALSE;
+ setvbuf(stdout,sbuff,_IOFBF,sizeof(sbuff));
+
+ /*
+ * get how we've been called isolate the name from the path
+ */
+
+ if ((stt = strrchr(argv[0],'/')) != NULL)
+ strcpy(Pgm_name,++stt);
+ else
+ strcpy(Pgm_name,argv[0]);
+ def_logs[0] = Pgm_name;
+
+ /*
+ * I wish the compiler had the #error directive!
+ */
+
+#if !HAVE_TAYLOR_LOGGING && !HAVE_V2_LOGGING
+ fprintf(stderr,"\a%s: (E) %s\n",Pgm_name,"Your config of Taylor UUCP is not yet supported.");
+ fprintf(stderr,"%s: (E) %s\n",Pgm_name,"Current support is for V2 or TAYLOR logging only.");
+ puts(" Run aborted due to errors\n")
+ exit(1);
+#endif
+
+ /*
+ * get some mem to store the default config name (def's are in
+ * policy.h )
+ */
+
+ if (sizeof(NEWCONFIGLIB) > 1) /* defined at compile time */
+ {
+ D_conf = (char *)getmem((sizeof(NEWCONFIGLIB) + sizeof("/config")));
+ strcpy(D_conf,NEWCONFIGLIB); /* passed by makefile */
+ strcat(D_conf,"/config");
+ }
+ Tlog = (char *)getmem(sizeof(LOGFILE));
+ Tstat = (char *)getmem(sizeof(STATFILE));
+ Tlog = LOGFILE;
+ Tstat = STATFILE;
+
+ /*
+ * Process the command line arguments
+ */
+
+ while((c = getopt(argc, argv, "I:s:cfdexaitphv")) != EOF)
+ {
+ switch(c)
+ {
+ case 'h':
+ (void) usage();
+ case 's':
+ strcpy(Hostname, optarg);
+ break;
+ case 'c':
+ show_calls = TRUE;
+ ++report;
+ break;
+ case 'd':
+ printf("%s: (I) config-file default: %s\n",Pgm_name,D_conf);
+ exit (0);
+ break;
+ case 'f':
+ show_files = TRUE;
+ ++report;
+ break;
+ case 'x':
+ show_commands = TRUE;
+ ++report;
+ break;
+ case 'e':
+ show_efficiency = TRUE;
+ ++report;
+ break;
+ case 'a':
+ show_calls = show_files = show_commands = show_efficiency = TRUE;
+ report = 4;
+ break;
+ case 'i':
+ use_stdin = TRUE;
+ break;
+ case 't':
+ show_all = TRUE;
+ report = MAXREP;
+ break;
+ case 'p':
+ show_proto = TRUE;
+ ++report;
+ break;
+ case 'I':
+ I_conf = (char *)getmem(sizeof(optarg));
+ I_conf = optarg;
+ break;
+ case 'q':
+ be_quiet = TRUE;
+ break;
+ case 'v':
+ printf("%s\n",rcsid);
+ exit (0);
+ default :
+ (void) usage();
+ }
+ }
+ if (report == 0) /* no options given */
+ ++report; /* at least summary can be printed */
+ if (! be_quiet)
+ hdrprt('i',0); /* print header for environment info */
+
+ /*
+ * Adjust argv and argc to account for the args processed above.
+ */
+
+ argc -= (optind - 1);
+ argv += (optind - 1);
+
+ /*
+ * If further args present, Assume rest are logfiles for us to process
+ * which should be given in pairs (log plus stat) otherwise the results may
+ * not come out as expected! If no further args are present take input from
+ * Log and Stat files provided in the compilation environment of Taylor UUCP.
+ * If -i was given, Log already points to stdin and no file args are accepted.
+ */
+
+ if (use_stdin) /* If -i, read from stdin */
+ {
+ if (argc != 1) /* No file arguments allowed */
+ {
+ fprintf(stderr,"\a%s: (E) %s\n",Pgm_name,
+ "it's not posssible to give file args with '-i'");
+ (void) usage();
+ }
+ else
+ {
+ argc = 2;
+ Log = stdin;
+ if (! be_quiet)
+ puts(" Input from stdin; no other files will be used\n");
+ }
+ }
+ else
+ {
+ if (argc != 1) /* file arguments are present */
+ {
+ if (! be_quiet)
+ puts(" No defaults used; will use passed file arguments\n");
+ }
+ else /* Read from current logs */
+ {
+ def_logs[1] = Tlog; /* prime the */
+ def_logs[2] = Tstat; /* file names */
+ if (! be_quiet)
+ printf(" Config for this run: ");
+
+ if (I_conf != NULL)
+ {
+ junk = 0;
+ if (! be_quiet)
+ printf("%s\n",I_conf);
+ if (0 != (chk_config(I_conf,be_quiet,junk)))
+ return (8);
+ }
+ else
+ {
+ if (D_conf != NULL)
+ {
+ junk = 1; /* indicate default (compiled) config */
+ if (! be_quiet)
+ printf("%s\n",D_conf);
+ chk_config(D_conf,be_quiet,junk);
+ }
+ else
+ if (! be_quiet)
+ printf("%s\n",noConf);
+ }
+ def_logs[1] = Tlog; /* final setting of */
+ def_logs[2] = Tstat; /* file names */
+ argv = def_logs; /* Bash argvec to log/stat files */
+ argc = sizeof(def_logs) / sizeof(def_logs[0]);
+ }
+ }
+
+ /* --------------------------------------------------------------------
+ * MAIN LOGFILE PROCESSING LOOP
+ * --------------------------------------------------------------------
+ */
+
+ if (!use_stdin)
+ {
+ if (argc < 3 && ! be_quiet)
+ {
+ puts(" (W) there is only one input file!");
+ puts(" (W) some reports may not be printed");
+ }
+ if (! be_quiet)
+ hdrprt('d',0); /* give subheaderline */
+ }
+
+ while (argc > 1)
+ {
+ if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL)
+ {
+ perror(argv[1]);
+ exit (8);
+ }
+ setvbuf(Log,buff,_IOFBF,sizeof(buff));
+ if ((flq = strrchr(argv[1], '/')) == NULL)
+ strncpy(Filename,argv[1],sizeof(Filename)-1);
+ else
+ strncpy(Filename,++flq,sizeof(Filename)-1);
+
+ strcpy(in_date," n/a");
+ strcpy(in_time," n/a");
+ p_done = FALSE; /* no info printed yet */
+ no_records = TRUE; /* not read any record yet */
+
+ /*
+ * Read each line of the logfile and collect information
+ */
+
+ while (fgets(logline, sizeof(logline), Log))
+ {
+ /*
+ * The host name of the other end of the connection is
+ * always the second field of the log line, whether we
+ * are reading a Log file or a Stats file. Set 'p' to
+ * point to the second field, null-terminated. Skip
+ * the line if something is funny. V2 and Taylor ar identical
+ * up to this part. Put out the start/end date of the files read;
+ */
+
+ if (NULL == (p = strchr(logline, ' ')))
+ continue;
+ no_records = FALSE; /* got one (usable) record at least */
+ ++p;
+
+ if (NULL != (stt = strchr(p, '(')))
+ {
+ if (! p_done && ! use_stdin && ! be_quiet)
+ {
+
+#if HAVE_TAYLOR_LOGGING
+ sscanf(++stt,"%s%*c%[^.]",in_date,in_time);
+#endif /* HAVE_TAYLOR_LOGGING */
+
+#if HAVE_V2_LOGGING
+ sscanf(++stt,"%[^-]%*c%[1234567890:]",in_date,in_time);
+#endif /* HAVE_V2_LOGGING */
+
+ printf(" %-14s %10s %8s",Filename, in_date, in_time);
+ strcpy(in_date," n/a"); /* reset to default */
+ strcpy(in_time," n/a");
+ p_done = TRUE;
+ }
+ else
+ {
+ if (! use_stdin && ! be_quiet) /* save for last time stamp prt. */
+ strncpy(dt_info,++stt,sizeof(dt_info)-1);
+ }
+ }
+
+ if (NULL != (s = strchr(p, ' ')))
+ *s = '\0';
+ for (s = p; *s; ++s)
+ if (isupper(*s))
+ *s = tolower(*s);
+
+ /*
+ * Skip this line if we got -s <host> and
+ * this line does not contain that host name.
+ * Don't skip the `incoming call' line with the system name `-'.
+ */
+
+ if (Hostname[0] != '\0')
+ if ( (p[0] != '-' || p[1] != '\0') && 0 != strcmp(p, Hostname) )
+ continue;
+
+ /*
+ * We are within a call block now. If this line is a file
+ * transfer record, determine the direction. If not then
+ * skip the line if it is not interesting.
+ */
+
+ if ((s = strchr(++s, ')')) == NULL)
+ continue;
+
+#if ! HAVE_TAYLOR_LOGGING
+#if HAVE_V2_LOGGING
+ if ((strncmp(s,") (",3)) == 0) /* are we in stats file ?) */
+ if ((s = strchr(++s, ')')) == NULL)
+ continue; /* yes but strange layout */
+#endif /* HAVE_V2_LOGGING */
+#endif /* ! HAVE_TAYLOR_LOGGING */
+
+ logmsg = s + 2; /* Message is 2 characters after ')' */
+ if ((0 != strncmp(logmsg, "Call complete", 13)) &&
+ (0 != strncmp(logmsg, "Calling system", 14)) &&
+ (0 != strncmp(logmsg, "Incoming call", 13)) &&
+ (0 != strncmp(logmsg, "Handshake successful", 20)) &&
+ (0 != strncmp(logmsg, "Retry time not", 14)) &&
+ (0 != strncmp(logmsg, "ERROR: All matching ports", 25)) &&
+ (0 != strncmp(logmsg, "Executing", 9)) &&
+ (0 != strncmp(logmsg, "Protocol ", 9)) &&
+ (0 != strncmp(logmsg, "sent ", 5)) &&
+ (0 != strncmp(logmsg, "received ", 9)) &&
+ (0 != strncmp(logmsg, "failed after ", 13)) &&
+ (0 != strncmp(logmsg, "Errors: ", 8)))
+ continue;
+
+ /*
+ * Find the Host_entry for this host, or create a new
+ * one and link it on to the list.
+ */
+
+ if ((cur == NULL) || (0 != strcmp(p, cur->Hostname)))
+ {
+ struct Host_entry *e, *last;
+
+ for (e= cur= hosts; cur != NULL ; e= cur, cur= cur->next)
+ if (0 == strcmp(cur->Hostname, p))
+ break;
+ if (cur == NULL)
+ {
+ cur= (struct Host_entry *)getmem(sizeof(*hosts));
+ strcpy(cur->Hostname, p);
+ if (hosts == NULL)
+ e= hosts= cur;
+ else {
+ e = hosts;
+ last = NULL;
+ while (e != NULL) {
+ if (strcmp(e->Hostname, cur->Hostname) <= 0) {
+ if (e->next == NULL) {
+ e->next = cur;
+ break;
+ }
+ last = e;
+ e = e->next;
+ }
+ else {
+ cur->next = e;
+ if (last == NULL)
+ hosts = cur;
+ else
+ last->next = cur;
+ break;
+ }
+ } /* while (e != NULL) */
+ } /* hosts == NULL */
+ } /* cur == NULL */
+ }
+
+ /*
+ * OK, if this is a uuxqt record, find the Execution_Command
+ * structure for the command being executed, or create a new
+ * one. Then count an execution of this command.
+ * (Log file only)
+ */
+
+ if (0 == strncmp(logmsg, "Executing", 9))
+ {
+ if (NULL == (p = strchr(logmsg, '(')))
+ continue;
+ if ((s = strpbrk(++p, " )")) == NULL)
+ continue;
+ *s = '\0';
+ inc_cmd(&cur->cmds, p);
+ inc_cmd(&t_cmds, p);
+ have_commands = TRUE;
+ continue;
+ }
+
+ /*
+ * Count start of outgoing call.
+ */
+
+ if ((0 == strncmp(logmsg, "Calling system", 14)) ||
+ (0 == strncmp(logmsg, "Retry time not", 14)) ||
+ (0 == strncmp(logmsg, "ERROR: All matching ports", 25)))
+ {
+ called = OUT;
+ cur->call[OUT].calls++;
+ have_calls = TRUE;
+ s_prot = NULL; /* destroy pointer to protocol */
+ continue;
+ }
+
+ /*
+ * Count start of incoming call.
+ */
+
+ if (0 == strncmp(logmsg, "Incoming call", 13))
+ {
+ called = IN;
+ s_prot = NULL; /* destroy pointer to protocol */
+ continue;
+ }
+
+ /*
+ * On an incoming call, get system name from the second line.
+ * Get protocol type and size/window too
+ */
+
+ if (0 == strncmp(logmsg, "Handshake successful", 20))
+ {
+ if ( called==IN )
+ cur->call[IN].calls++;
+ have_calls = TRUE;
+ s_prot = NULL; /* destroy pointer to protocol */
+ if (NULL == (p = strchr(logmsg, '(')))
+ continue;
+ if (0 == strncmp(p, "(protocol ", 10))
+ {
+ if (NULL == (p = strchr(p, '\'')))
+ continue;
+ ss_prot = prot_sum(&cur->proto, ++p, 1);
+ s_prot = prot_sum(&t_prot, p, 1);
+ continue;
+ }
+ }
+
+ /*
+ * check protocol type and get stats
+ *
+ */
+
+ if (0 == strncmp(logmsg, "Protocol ", 9))
+ {
+ s_prot = NULL; /* destroy pointer to protocol */
+ if (NULL == (p = strchr(logmsg, '\'')))
+ continue;
+ ss_prot = prot_sum(&cur->proto, ++p, 2);
+ s_prot = prot_sum(&t_prot, p, 2);
+ continue;
+ }
+
+ /*
+ * check protocol errors. Unfortunately the line does not contain
+ * the used protocol, so if any previous line did contain that
+ * information and we did process that line we will save the pointer
+ * to that particular segment into s_prot. If this pointer is not set
+ * the error info is lost for we don't know where to store.
+ *
+ */
+
+ if ((0 == strncmp(logmsg, "Errors: header", 14)) && s_prot != NULL)
+ {
+ int i1,i2,i3,i4 = 0;
+ sscanf(logmsg,"%*s %*s %d%*c%*s %d%*c%*s %d%*c%*s %*s%*c %d",&i1,&i2,&i3,&i4);
+ ss_prot->pr_eheader += i1;
+ ss_prot->pr_echksum += i2;
+ ss_prot->pr_eorder += i3;
+ ss_prot->pr_ereject += i4;
+ s_prot->pr_eheader += i1;
+ s_prot->pr_echksum += i2;
+ s_prot->pr_eorder += i3;
+ s_prot->pr_ereject += i4;
+ s_prot = NULL;
+ continue;
+ }
+
+ /*
+ * Handle end of call. Pick up the connect time.
+ * position is on the closing paren of date/time info
+ * i.e: ) text....
+ */
+
+ if (0 == strncmp(logmsg, "Call complete", 13))
+ {
+ cur->call[called].succs++;
+ s_prot = NULL; /* destroy pointer to protocol */
+ if (NULL == (s = strchr(logmsg, '(')))
+ continue;
+ cur->call[called].connect_time += atof(s+1);
+ continue;
+ }
+
+ /*
+ * We are definitely in a Stats file now.
+ * If we reached here, this must have been a file transfer
+ * record. Count it in the field corresponding to the
+ * direction of the transfer. Count bytes transferred and
+ * the time to transfer as well.
+ * Position within the record is at the word 'received' or 'sent'
+ * depending on the direction.
+ */
+
+ sent = IN; /* give it an initial value */
+ if (0 == strncmp(logmsg, "failed after ",13))
+ logmsg += 13; /* the transmission failed for any reason */
+ /* so advance pointer */
+ if (0 == strncmp(logmsg, "sent", 4))
+ sent = OUT;
+ else if (0 == strncmp(logmsg, "received", 8))
+ sent = IN;
+ have_files[sent] = TRUE;
+ cur->call[called].flow[sent].files++;
+ if (NULL == (s = strchr(logmsg, ' '))) /* point past keyword */
+ continue; /* nothing follows */
+ /* we should be at the bytes column now*/
+#if HAVE_TAYLOR_LOGGING
+ cur->call[called].flow[sent].bytes += atol(++s);
+#endif /* HAVE_TAYLOR_LOGGING */
+#if HAVE_V2_LOGGING
+ if (NULL == (s = strpbrk(s, "0123456789"))) /* point to # bytes */
+ continue;
+ cur->call[called].flow[sent].bytes += atol(s);
+#endif /* HAVE_V2_LOGGING */
+ if (NULL == (s = strchr(s, ' '))) /* point past # of bytes */
+ continue;
+ if (NULL == (s = strpbrk(s, "0123456789"))) /* point to # of seconds */
+ continue;
+ cur->call[called].flow[sent].time += atof(s);
+
+ } /* end of while (fgets(logline...)) */
+
+ if (stt != NULL && ! use_stdin && ! be_quiet && ! no_records)
+ {
+
+#if HAVE_TAYLOR_LOGGING
+ sscanf(dt_info,"%s%*c%[^.]",in_date,in_time);
+#endif /* HAVE_TAYLOR_LOGGING */
+
+#if HAVE_V2_LOGGING
+ sscanf(dt_info,"%[^-]%*c%[1234567890:]",in_date,in_time);
+#endif /* HAVE_V2_LOGGING */
+
+ printf(" %10s %8s\n",in_date, in_time);
+ p_done = FALSE;
+ }
+ if (Log != stdin)
+ {
+ if (0 != ferror(Log))
+ {
+ if (! be_quiet)
+ printf(" %-14s data is incomplete; read error"," ");
+ else
+ fprintf(stderr,"%s (W) data is incomplete; read error on %s\n",
+ Pgm_name,argv[1]);
+ }
+ else
+ {
+ if (! be_quiet && no_records)
+ printf(" %-14s %10s\n",Filename, " is empty ");
+ }
+ }
+ fclose(Log);
+
+ argc--;
+ argv++;
+ } /* end of while (for (argv ....) */
+
+ /*
+ * do we have *any* data ?
+ */
+
+ if (cur == NULL)
+ {
+ puts("\n(I) Sorry! No data is available for any requested report\n");
+ exit(0);
+ }
+
+ /*
+ * truncate hostname, alloc the structure holding the totals and
+ * collect the totals data
+ */
+
+ for (cur = hosts; cur != NULL;cur = cur->next)
+ {
+ cur->Hostname[MAXDNAME] = '\0';
+ if (cur->next == NULL) /* last so will have to alloc totals */
+ {
+ cur->next = (struct Host_entry *)getmem(sizeof(*hosts));
+ strcpy(cur->next->Hostname,"Totals");
+ tot = cur->next;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ if (cur->next != NULL) /* don't count totals to totals */
+ {
+ tot->call[IN].flow[IN].bytes += cur->call[IN].flow[IN].bytes;
+ tot->call[OUT].flow[IN].bytes += cur->call[OUT].flow[IN].bytes;
+ tot->call[IN].flow[OUT].bytes += cur->call[IN].flow[OUT].bytes;
+ tot->call[OUT].flow[OUT].bytes += cur->call[OUT].flow[OUT].bytes;
+ tot->call[IN].flow[IN].time += cur->call[IN].flow[IN].time;
+ tot->call[OUT].flow[IN].time += cur->call[OUT].flow[IN].time;
+ tot->call[IN].flow[OUT].time += cur->call[IN].flow[OUT].time;
+ tot->call[OUT].flow[OUT].time += cur->call[OUT].flow[OUT].time;
+ tot->call[IN].flow[IN].files += cur->call[IN].flow[IN].files;
+ tot->call[OUT].flow[IN].files += cur->call[OUT].flow[IN].files;
+ tot->call[IN].flow[OUT].files += cur->call[IN].flow[OUT].files;
+ tot->call[OUT].flow[OUT].files += cur->call[OUT].flow[OUT].files;
+ tot->call[OUT].succs += cur->call[OUT].succs;
+ tot->call[OUT].calls += cur->call[OUT].calls;
+ tot->call[OUT].connect_time += cur->call[OUT].connect_time;
+ tot->call[IN].succs += cur->call[IN].succs;
+ tot->call[IN].calls += cur->call[IN].calls;
+ tot->call[IN].connect_time += cur->call[IN].connect_time;
+ }
+ }
+ break; /* totals is last in Host_Entry */
+ }
+ }
+
+ /*
+ * ***********
+ * * REPORTS *
+ * ***********
+ */
+
+#if _DEBUG_
+ putchar('\n');
+#endif
+
+ /* ------------------------------------------------------------------
+ *
+ * Summary report only when no other report except option -t is given
+ *
+ * I know, this code could be tightened (rbd)...
+ * ------------------------------------------------------------------
+ */
+
+ if ( !(show_calls || show_files ||
+ show_efficiency || show_commands || show_proto) || show_all)
+ {
+ if (have_calls || have_files[IN] || have_files[OUT])
+ {
+ char t1[32], t2[32], t3[32], t4[32], t5[32];
+ long ib, ob, b, rf, sf;
+ double it, ot, ir, or;
+
+ hdr_done = FALSE;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ ib = (cur->call[IN].flow[IN].bytes +
+ cur->call[OUT].flow[IN].bytes);
+ fmbytes(ib, t1);
+
+ ob = (cur->call[IN].flow[OUT].bytes +
+ cur->call[OUT].flow[OUT].bytes);
+ fmbytes(ob, t2);
+
+ /* Don't print null-lines. */
+ if (( b= ib+ob ) == 0 )
+ continue;
+ /* Don't print the header twice. */
+ if (! hdr_done)
+ {
+ hdrprt('s',0); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+
+ fmbytes(b, t3);
+
+ it = cur->call[IN].flow[IN].time +
+ cur->call[OUT].flow[IN].time;
+ fmtime(it, t4);
+
+ ot = cur->call[IN].flow[OUT].time +
+ cur->call[OUT].flow[OUT].time;
+ fmtime(ot, t5);
+
+ rf = cur->call[IN].flow[IN].files +
+ cur->call[OUT].flow[IN].files;
+
+ sf = cur->call[IN].flow[OUT].files +
+ cur->call[OUT].flow[OUT].files;
+
+ ir = (it == 0.0) ? 0.0 : (ib / it);
+ or = (ot == 0.0) ? 0.0 : (ob / ot);
+
+ if (cur->next == NULL) /* totals line reached ? */
+ hdrprt('s',1); /* print the separator line */
+
+ printf("%-8s %4d %4d %9s %9s %9s %9s %9s %5.0f %5.0f\n",
+ cur->Hostname, rf, sf,
+ t1, t2, t3, t4, t5,
+ ir, or);
+ }
+ if (! hdr_done)
+ {
+ puts("\n(I) No data found to print Compact summary report");
+ }
+ }
+ else
+ {
+ puts("\n(I) No data available for Compact summary report");
+ --report;
+ }
+ }
+
+ /* ------------------------------------------------------------------
+ * Protocol statistics report
+ * ------------------------------------------------------------------
+ */
+
+ if (show_proto || show_all)
+ {
+ if (have_proto)
+ {
+ /* --------------------- */
+ /* protocol packet report */
+ /* --------------------- */
+
+ char *type = NULL;
+ hdr_done = FALSE;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ type = cur->Hostname;
+ if (cur->next == NULL)
+ {
+ if (hdr_done)
+ puts("-------------------------------------------------------------------");
+ cur->proto = t_prot;
+ }
+ for (prot = cur->proto; prot != NULL; prot = prot->next)
+ {
+ if (! hdr_done)
+ {
+ hdrprt('p',0); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+ printf("%-8s %3s %4d %4d %5d %4d %10d %7d %10d\n",
+ type == NULL ? " ":cur->Hostname,
+ prot->type,
+ prot->pr_psizemin,
+ prot->pr_psizemax,
+ prot->pr_pwinmin,
+ prot->pr_pwinmax,
+ prot->pr_psent,
+ prot->pr_present,
+ prot->pr_preceived);
+ type = NULL;
+ }
+ }
+ if (! hdr_done)
+ puts("\n(I) No data found to print Protocol packet report");
+
+ /* --------------------- */
+ /* protocol error report */
+ /* --------------------- */
+
+ type = NULL;
+ hdr_done = FALSE;
+ if (t_prot != NULL)
+ {
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ type = cur->Hostname;
+ if (cur->next == NULL)
+ {
+ if (hdr_done)
+ puts("--------------------------------------------------------------");
+ cur->proto = t_prot;
+ }
+
+ for (prot = cur->proto; prot != NULL; prot = prot->next)
+ {
+ if ((prot->pr_eheader + prot->pr_echksum +
+ prot->pr_eorder + prot->pr_ereject) != 0)
+ {
+ if (! hdr_done)
+ {
+ hdrprt('p',1); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+ printf("%-8s %3s %11d %11d %11d %11d\n",
+ type == NULL ? " ":cur->Hostname,
+ prot->type,
+ prot->pr_eheader,
+ prot->pr_echksum,
+ prot->pr_eorder,
+ prot->pr_ereject);
+ type = NULL;
+ }
+ }
+ }
+ }
+ if (! hdr_done)
+ puts("\n(I) No data found to print Protocol error report");
+ }
+ else
+ {
+ puts("\n(I) No data available for Protocol reports");
+ --report;
+ }
+ }
+
+ /* ------------------------------------------------------------------
+ * Call statistics report
+ * ------------------------------------------------------------------
+ */
+
+ if (show_calls || show_all)
+ {
+ if (have_calls)
+ {
+ char t1[32], t2[32];
+
+ hdr_done = FALSE;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ if (cur->next == NULL)
+ {
+ if (hdr_done)
+ hdrprt('c',1); /* print the separator line */
+ }
+ else
+ {
+ /* Don't print null-lines on deatail lines */
+ if ( cur->call[OUT].calls + cur->call[IN].calls == 0 )
+ continue;
+
+ /* Don't print the header twice. */
+ if (! hdr_done)
+ {
+ hdrprt('c',0); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+ }
+ if ( cur->call[OUT].calls > 0 || cur->next == NULL)
+ {
+ fmtime(cur->call[OUT].connect_time, t1);
+ printf( " %-8s %7d %7d %7d %9s",
+ cur->Hostname,
+ cur->call[OUT].succs,
+ cur->call[OUT].calls - cur->call[OUT].succs,
+ cur->call[OUT].calls,
+ t1 );
+ }
+ else
+ {
+ printf( " %-42s", cur->Hostname );
+ }
+ if ( cur->call[IN].calls > 0 || cur->next == NULL )
+ {
+ fmtime(cur->call[IN].connect_time, t2);
+ printf( " %7d %7d %7d %9s",
+ cur->call[IN].succs,
+ cur->call[IN].calls - cur->call[IN].succs,
+ cur->call[IN].calls,
+ t2 );
+ }
+ putchar('\n');
+ }
+ if (! hdr_done)
+ {
+ puts("\n(I) No data found to print Call statistics report");
+ }
+ }
+ else
+ {
+ puts("\n(I) No data available for Call statistics report");
+ --report;
+ }
+ }
+
+ /* ------------------------------------------------------------------
+ * File statistics report
+ * ------------------------------------------------------------------
+ */
+
+ if (show_files || show_all)
+ {
+ if (have_files[IN] || have_files[OUT])
+ {
+ char t1[32], t2[32];
+ double rate = 0, time = 0;
+ int b = 0;
+ int lineOut = 0;
+
+ hdr_done = FALSE;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ lineOut = 0;
+ for (sent= IN; sent <= OUT; ++sent)
+ {
+ b = cur->call[IN].flow[sent].bytes +
+ cur->call[OUT].flow[sent].bytes;
+ time = cur->call[IN].flow[sent].time +
+ cur->call[OUT].flow[sent].time;
+
+ /* Don't print null-lines on detail lines. */
+ if ( (b != 0 && time != 0.0) || cur->next == NULL)
+ {
+ /* Don't print the header twice. */
+ if (! hdr_done)
+ {
+ hdrprt('f',0); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+ fmbytes(b, t1);
+ rate = (cur->call[IN].flow[sent].bytes +
+ cur->call[OUT].flow[sent].bytes) / time;
+ fmtime((cur->call[IN].flow[sent].time +
+ cur->call[OUT].flow[sent].time), t2);
+
+ if (lineOut == 0) /* first half not printed yet ? */
+ {
+ if (cur->next == NULL) /* totals line ? */
+ hdrprt('f',1); /* print the separator line */
+ printf(" %-8s", cur->Hostname);
+ if (sent == OUT) /* can't happen whith totals line */
+ printf("%34s", " ");
+ }
+
+ printf(" %5d %11s %9s %5.0f",
+ cur->call[IN].flow[sent].files +
+ cur->call[OUT].flow[sent].files,
+ t1, t2, rate);
+ lineOut = 1;
+ }
+ } /* end: for (sent ... ) */
+ if (lineOut)
+ printf("\n");
+ } /* end: for (cur= ... ) */
+ if (! hdr_done)
+ {
+ puts("\n(I) No data found to print File statistics report");
+ }
+ }
+ else
+ {
+ puts("\n(I) No data available for File statistics report");
+ --report;
+ }
+ }
+
+ /* ------------------------------------------------------------------
+ * Efficiency report
+ * ------------------------------------------------------------------
+ */
+
+ if (show_efficiency || show_all)
+ {
+ if (have_files[IN] || have_files[OUT])
+ {
+ char t1[32], t2[32], t3[32];
+ double total, flow;
+
+ hdr_done = FALSE;
+ for (cur = hosts; cur != NULL; cur = cur->next)
+ {
+ /* Don't print null-lines. */
+ if ( 0 == cur->call[IN].flow[IN].files +
+ cur->call[IN].flow[OUT].files +
+ cur->call[OUT].flow[IN].files +
+ cur->call[OUT].flow[OUT].files ||
+ 0.0 == (total= cur->call[IN].connect_time +
+ cur->call[OUT].connect_time))
+ {
+ continue;
+ }
+
+ if (! hdr_done)
+ {
+ hdrprt('e',0); /* print the header line(s) */
+ hdr_done = TRUE;
+ }
+
+ flow = cur->call[IN].flow[IN].time +
+ cur->call[IN].flow[OUT].time +
+ cur->call[OUT].flow[IN].time +
+ cur->call[OUT].flow[OUT].time;
+ fmtime(total, t1);
+ fmtime(flow, t2);
+ fmtime(total-flow, t3);
+
+ if (cur->next == NULL)
+ hdrprt('e',1); /* print the separator line */
+
+ printf(" %-8s %10s %10s %10s %7.2f\n",
+ cur->Hostname, t1, t2, t3,
+ flow >= total ? 100.0: flow*100.0/total);
+ } /* end: for (cur= .. */
+ if (! hdr_done)
+ {
+ puts("\n(I) No data found to print Efficiency report");
+ }
+ }
+ else
+ {
+ puts("\n(I) No data available for Efficiency report");
+ --report;
+ }
+ }
+
+ /* ------------------------------------------------------------------
+ * Command execution report
+ * ------------------------------------------------------------------
+ */
+
+ if (show_commands || show_all)
+ {
+ if (have_commands)
+ {
+ int ncmds, i, match;
+
+ /*
+ * layout the header line. The column's header is the command name
+ */
+
+ hdr_done = FALSE;
+ for (ncmds= 0, cmd= t_cmds;
+ cmd != NULL && ncmds <= MAXCOLS-1;
+ ncmds++, cmd= cmd->next)
+ {
+ if (! hdr_done)
+ {
+ puts("\nCommand executions:");
+ puts("-------------------");
+ puts(" Name of ");
+ fputs(" site ", stdout);
+ hdr_done = TRUE;
+ }
+ printf(" %7s", cmd->Commandname);
+ }
+ if (! hdr_done)
+ {
+ puts("\n(I) No data found to print Command execution report");
+ }
+ else
+ {
+ fputs("\n --------", stdout);
+ for (i= 0; i<ncmds; i++)
+ fputs(" ------", stdout);
+ putchar('\n');
+
+ /*
+ * print out the number of executions for each host/command
+ */
+
+ for (cur= hosts; cur != NULL; cur= cur->next)
+ {
+ if (cur->next == NULL)
+ break;
+
+ /* Don't print null-lines. */
+
+ if (cur->cmds == NULL)
+ continue;
+
+ printf(" %-8s", cur->Hostname);
+ for (cmd= t_cmds; cmd != NULL; cmd= cmd->next)
+ {
+ struct Execution_Command *ec;
+ match = FALSE;
+ for(ec= cur->cmds; ec != NULL; ec= ec->next)
+ {
+ if ( 0 == strcmp(cmd->Commandname, ec->Commandname) )
+ {
+ printf(" %7d", ec->count);
+ match = TRUE;
+ break;
+ }
+ }
+ if (! match)
+ printf("%8s"," "); /* blank out column */
+ }
+ putchar('\n');
+ }
+
+ /*
+ * print the totals line
+ */
+
+ fputs(" --------", stdout);
+ for (i= 0; i<ncmds; i++)
+ fputs("--------", stdout);
+ printf("\n %-8s", cur->Hostname);
+ for (cmd= t_cmds; cmd != NULL; cmd= cmd->next)
+ {
+ printf(" %7d", cmd->count);
+ }
+ putchar('\n');
+ }
+ }
+ else
+ {
+ puts("\n(I) No data available for Command execution report");
+ --report;
+ }
+ }
+ if (report <= 0 ) /* any reports ? */
+ {
+ puts("\n(I) Sorry! No data is available for any requested report\n");
+ exit(1);
+ }
+
+ puts("\n(I) End of reports\n");
+ exit (0);
+} /* end of main */
+
+ /* ------------------------------------------------------------------
+ * * Functions *
+ * ------------------------------------------------------------------
+ */
+
+ /* ------------------------------------------------------------------
+ * display the help
+ * ------------------------------------------------------------------
+ */
+
+void usage()
+{
+ fprintf(stderr,"Usage uurate [-acdefhiptvx] [-s hostname] [-I config file] [logfile(s) ... logfile(s)]\n");
+ fprintf(stderr,"where:\t-a\tPrint reports c,e,f,x\n");
+ fprintf(stderr,"\t-c\tReport call statistics\n");
+ fprintf(stderr,"\t-d\tPrint the name of the default config file\n");
+ fprintf(stderr,"\t-e\tReport efficiency statistics\n");
+ fprintf(stderr,"\t-f\tReport file transfer statistics\n");
+ fprintf(stderr,"\t-h\tPrint this help\n");
+ fprintf(stderr,"\t-i\tRead log info from standard input\n");
+ fprintf(stderr,"\t-p\tReport protocol statistics\n");
+ fprintf(stderr,"\t-t\tAll available reports plus compact summary report\n");
+ fprintf(stderr,"\t-v\tPrint version number\n");
+ fprintf(stderr,"\t-x\tReport command execution statistics\n");
+ fprintf(stderr,"\t-s host\tReport activities involving HOST only\n");
+ fprintf(stderr,"\t-I config Use config instead of standard config file\n");
+ fprintf(stderr,"If no report options given, a compact summary report is printed.\n");
+ fprintf(stderr,"log files should be given as pairs that is Log/Stats ... .\n");
+ fprintf(stderr,"If neither -i nor logfiles given, those names found in config will be used\n");
+
+ exit (1);
+}
+
+ /* ------------------------------------------------------------------
+ * getmem - get some memory
+ * ------------------------------------------------------------------
+ */
+
+static pointer *getmem(n)
+ unsigned n;
+{
+ pointer *p;
+
+ if( NULL== (p= calloc(1, n)) )
+ {
+ fprintf(stderr,"\a%s (C) %s\n",Pgm_name, "out of memory\n");
+ exit (8);
+ }
+ return p;
+}
+
+ /* ------------------------------------------------------------------
+ * inc_cmd - increment command count
+ * ------------------------------------------------------------------
+ */
+
+static void inc_cmd(cmds, name)
+ struct Execution_Command **cmds;
+ char *name;
+{
+ int cnt = 0;
+ struct Execution_Command *cmd, *ec;
+
+ for (ec = cmd = *cmds; cmd != NULL; ec= cmd, cmd= cmd->next, cnt++)
+ if ( (0 == strcmp(cmd->Commandname, name)) ||
+ (0 == strcmp(cmd->Commandname, "Misc.")) )
+ break;
+ if (cmd == NULL)
+ {
+ cmd= (struct Execution_Command *)getmem(sizeof(*cmd));
+ if (cnt <= MAXCOLS-1) /* first col prints site name therefore < max-1 */
+ {
+ strcpy(cmd->Commandname, name);
+ if (*cmds == NULL)
+ ec = *cmds = cmd;
+ else
+ ec->next= cmd;
+ }
+ else
+ {
+ strcpy(ec->Commandname, "Misc."); /* reached high-water-mark */
+ cmd = ec; /* backtrack */
+ }
+ }
+ cmd->count++;
+}
+
+
+ /* ------------------------------------------------------------------
+ * prot_sum - collect protocol data
+ * ------------------------------------------------------------------
+ */
+
+ struct Protocol_Summary *
+ prot_sum(proto, ptype, ind)
+ struct Protocol_Summary **proto;
+ char *ptype;
+ int ind;
+{
+ int cnt = 0;
+ int i1, i2, i3 = 0;
+ struct Protocol_Summary *cur, *first;
+
+ for (first = cur = *proto; cur != NULL; first= cur, cur= cur->next, cnt++)
+ {
+ if ( (0 == strncmp(cur->type, ptype,strlen(cur->type))))
+ break;
+ }
+ if (cur == NULL)
+ {
+ cur= (struct Protocol_Summary *)getmem(sizeof(*cur));
+ sscanf(ptype,"%[^\' ]3",cur->type);
+ if (*proto == NULL)
+ first = *proto = cur;
+ else
+ first->next= cur;
+ }
+ if (NULL == (ptype = strchr(ptype, ' ')))
+ return (NULL);
+ cur->pr_cnt++;
+ have_proto = TRUE;
+ ++ptype;
+ switch(ind)
+ {
+ case 1: /* used protocol line */
+ /*
+ * uucp-1.04 format: .... packet size ssss window ww)
+ * uucp-1.05 format: .... remote packet/window ssss/ww local ssss/ww)
+ * (the remote packet/window will be used!)
+ */
+
+ i1 = i2 = 0; /* reset */
+
+ if (NULL == (strchr(ptype, '/')))
+ sscanf(ptype,"%*s %*s %d %*s %d",&i1,&i2);
+ else
+ sscanf(ptype,"%*s %*s %d/%d",&i1,&i2);
+
+ if (i1 > cur->pr_psizemax)
+ cur->pr_psizemax = i1;
+ if (i1 < cur->pr_psizemin || cur->pr_psizemin == 0)
+ cur->pr_psizemin = i1;
+
+ if (i2 > cur->pr_pwinmax)
+ cur->pr_pwinmax = i2;
+ if (i2 < cur->pr_pwinmin || cur->pr_pwinmin == 0)
+ cur->pr_pwinmin = i2;
+ break;
+ case 2: /* protocol statistics line */
+ i1 = i2 = i3 = 0; /* reset */
+ sscanf(ptype,"%*s %*s %d%*c %*s %d%*c %*s %d",&i1,&i2,&i3);
+ cur->pr_psent += i1;
+ cur->pr_present += i2;
+ cur->pr_preceived += i3;
+ break;
+ default:
+ break;
+ }
+ return (cur);
+}
+ /* ------------------------------------------------------------------
+ * fmtime() - Format time in hours & minutes & seconds;
+ * ------------------------------------------------------------------
+ */
+
+static void fmtime(dsec, buf)
+ double dsec;
+ char *buf;
+{
+ long hrs, min, lsec;
+
+ if( dsec <= 0 )
+ {
+ strcpy(buf, "0" );
+ return;
+ }
+ lsec = fmod(dsec+0.5, 60L); /* round to the next full second */
+ hrs = dsec / 3600L;
+ min = ((long)dsec / 60L) % 60L;
+ if (hrs == 0)
+ if (min == 0)
+ sprintf(buf,"%6s%2ld"," ",lsec);
+ else
+ sprintf(buf,"%3s%2ld:%02ld"," ",min,lsec);
+ else
+ sprintf(buf,"%2ld:%02ld:%02ld",hrs,min,lsec);
+
+}
+
+ /* ------------------------------------------------------------------
+ * fmbytes - Format size in bytes
+ * ------------------------------------------------------------------
+ */
+
+static void fmbytes(n, buf)
+ unsigned long n;
+ char *buf;
+{
+ if ( n == 0 )
+ {
+ strcpy( buf, "0.0" );
+ return;
+ }
+ sprintf(buf, "%.1f", (double)n / 1000.0); /* Display in Kilobytes */
+}
+
+
+ /* ------------------------------------------------------------------
+ * chk_config - Read the config file
+ * check on keywords: logfile and statfile. When found override
+ * the corresponding default
+ * ------------------------------------------------------------------
+ */
+
+int chk_config(char *T_conf,int be_quiet, int type)
+{
+ FILE *Conf;
+ char keywrd[9];
+ char name[MAXPATHLEN+1];
+ char *pos1, *pos2;
+ int i = 0;
+ int logf = FALSE;
+ int statf = FALSE;
+
+ if ((Conf = fopen(T_conf, "r")) == NULL)
+ {
+ if (! be_quiet)
+ {
+ puts(" Could not open config");
+ if (type == 0)
+ {
+ puts(" The run will be aborted\n");
+ return (8);
+ }
+ }
+ else
+ {
+ fprintf(stderr,"%s (E) %s %s \n",Pgm_name,
+ "could not open config:",
+ T_conf);
+ if (type != 0)
+ fprintf(stderr,"%s (W) defaults used for all files\n",
+ Pgm_name);
+ else
+ {
+ fprintf(stderr,"%s (C) ended due to errors\n",
+ Pgm_name);
+ return (8);
+ }
+ }
+ }
+ else
+ {
+ while (fgets(logline, sizeof(logline), Conf))
+ {
+ if (logline[0] == '#')
+ continue;
+ sscanf(logline,"%8s %s",keywrd,name);
+ if (0 == strncmp(keywrd,"logfile",7))
+ {
+ pos1 = pos2 = name;
+ for (i=0;(i<=MAXPATHLEN && *pos1 != '\0');pos1++,pos2++,i++)
+ {
+ if (*pos1 == '#') /* name immed followed by comment */
+ break;
+ if (*pos1 == '\\') /* quoted comment (filename has #) */
+ {
+ ++pos1; /* skip escape char */
+ if (*pos1 != '#') /* continuation ? */
+ {
+ puts(" Config error:");
+ puts(" Found filename continuation; bailing out\n");
+ exit (8);
+ }
+ }
+ *pos2 = *pos1; /* move char */
+ }
+ *pos2 = '\0'; /* terminate string */
+ Tlog = (char *)getmem(strlen(name)+1);
+ strcpy(Tlog,name);
+ if (! be_quiet)
+ printf(" logfile used: %s\n",Tlog);
+ logf = TRUE;
+ if (statf) /* statsfile still to come ? */
+ break; /* no finished */
+ continue;
+ }
+
+ if (0 == strncmp(keywrd,"statfile",8))
+ {
+ pos1 = pos2 = name;
+ for (i=0;(i<=MAXPATHLEN && *pos1 != '\0');pos1++,pos2++,i++)
+ {
+ if (*pos1 == '#') /* name immed followed by comment */
+ break;
+ if (*pos1 == '\\') /* quoted comment (filename has #) */
+ {
+ ++pos1; /* skip escape char */
+ if (*pos1 != '#') /* continuation ? */
+ {
+ puts(" Config error:");
+ puts(" Found filename continuation; bailing out\n");
+ exit (8);
+ }
+ }
+ *pos2 = *pos1; /* move char */
+ }
+ *pos2 = '\0'; /* terminate string */
+ Tstat = (char *)getmem(strlen(name)+1);
+ strcpy(Tstat,name);
+ if (! be_quiet)
+ printf(" statfile used: %s\n",Tstat);
+ statf = TRUE;
+ if (logf) /* logfile still to come ? */
+ break; /* no finished */
+ continue;
+ }
+ }
+ fclose(Conf);
+ }
+
+ if (! be_quiet)
+ {
+ if (! logf)
+ puts(" logfile used: - default -");
+ if (! statf)
+ puts(" statfile used: - default -");
+ }
+
+return 0;
+}
+
+
+ /* ------------------------------------------------------------------
+ * hdrprt - Print Header/Trailer lines (constant data)
+ * ------------------------------------------------------------------
+ */
+
+static void hdrprt(char head, int bot)
+{
+ switch(head)
+ {
+ case('s'): /* standard summary report */
+ if (bot == 0)
+ {
+ puts("\nCompact summary:");
+ puts("----------------");
+ puts("\
+Name of + Files + +------- Bytes/1000 --------+ +------ Time -----+ + Avg CPS +\n\
+site in out inbound outbound total inbound outbound in out\n\
+-------- ---- ---- --------- --------- --------- --------- --------- ----- -----");
+ }
+ else
+ puts("\
+--------------------------------------------------------------------------------");
+ break;
+
+
+ case('f'): /* file statistic report */
+ if (bot == 0)
+ {
+ puts("\nFile statistics:");
+ puts("----------------");
+ puts(" Name of +----------- Inbound -----------+ +---------- Outbound -----------+");
+ puts(" site files Bytes/1000 xfr time B/sec files Bytes/1000 xfr time B/sec");
+ puts(" -------- ----- ----------- --------- ----- ----- ----------- --------- -----");
+ }
+ else
+ puts("\
+ ----------------------------------------------------------------------------");
+ break;
+
+
+ case('c'): /* calls statistic report */
+ if (bot == 0)
+ {
+ puts("\nCall statistics:");
+ puts("----------------");
+ puts(" Name of +------- Outbound Calls -------+ +-------- Inbound Calls ------+");
+ puts(" site succ. failed total time succ. failed total time");
+ puts(" -------- ------ ------ ------ --------- ------ ------ ------ ---------");
+ }
+ else
+ puts("\
+ ----------------------------------------------------------------------------");
+ break;
+
+
+ case('e'): /* efficiency statistic report */
+ if (bot == 0)
+ {
+ puts("\nEfficiency:");
+ puts("-----------");
+ puts(" Name of +------ Times inbound/outbound -------+");
+ puts(" site connected xfr time overhead eff. %");
+ puts(" -------- --------- --------- --------- ------");
+ }
+ else
+ puts(" -------------------------------------------------");
+ break;
+
+ case('i'): /* Environment information */
+ if (bot == 0)
+ {
+ puts("\nEnvironment Information:");
+ puts("------------------------");
+ printf(" Default config: %s\n",D_conf == NULL ?
+ noConf:D_conf);
+ printf(" Default logfile: %s\n",Tlog);
+ printf(" Default statfile: %s\n\n",Tstat);
+ }
+ break;
+
+ case('d'): /* Date/time coverage */
+ if (bot == 0)
+ {
+ puts("\n Date coverage of input files:");
+ puts(" Name of +----- Start -----+ +------ End ------+");
+ puts(" file date time date time");
+ puts(" -------- ---------- -------- ---------- --------");
+ }
+ break;
+
+ case('p'): /* Protocol stats */
+ if (bot == 0)
+ {
+ puts("\nProtocol packet report:");
+ puts("-----------------------");
+ puts(" +------- protocol -----+ +--------- Packets ----------+");
+ puts("Name of packet window ");
+ puts("site typ min max min max sent resent received");
+ puts("-------- --- ---- ---- ---- ---- ----------- ------- ----------");
+ }
+ else
+ {
+ puts("\nProtocol error report:");
+ puts("----------------------");
+ puts("Name of +----------------- Error Types --------------------+");
+ puts("site typ header checksum order rem-reject");
+ puts("-------- --- ----------- ---------- ----------- ----------");
+ }
+ break;
+
+ default:
+ if (bot == 0)
+ {
+ puts("\nNo header for this report defined:");
+ }
+ else
+ puts(" ");
+ break;
+ }
+}
diff --git a/gnu/libexec/uucp/contrib/uurate.man b/gnu/libexec/uucp/contrib/uurate.man
new file mode 100644
index 00000000000..13f79a313fa
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uurate.man
@@ -0,0 +1,280 @@
+''' $Id: uurate.man,v 1.1 1995/10/18 08:38:25 deraadt Exp $
+.TH uurate 1
+.SH NAME
+uurate \- Report Taylor UUCP statistics
+.SH SYNOPSIS
+.BR uurate " [ " "\-acdefhipqtvx" " ] [ " "\-s "
+.I host
+.RI " ] [ " "\-I "
+.I config
+.RI " ][ " "logfile..." " ] "
+.PP
+or simply,
+.PP
+.B uurate
+.PP
+for a traffic summary report.
+.SH DESCRIPTION
+The
+.I uurate
+command provides tabular summary reports on the operation of the
+Taylor UUCP system. Data is taken from the currently active log
+files, standard input, or from a list of log files given on the
+command line. Output is in the form of tabular reports summarizing
+call, file transfer, and command execution
+.RI "(" "uuxqt" ")"
+activity.
+.PP
+The log and stats files given to
+.I uurate
+must be in the ``Taylor'' or ``V2'' format. Also, note that call and file
+transfer activities are logged in separate files, nominally called
+.I Log
+and
+.I Stats,
+respectively. For reports to be meaningful, the
+.I Log
+and
+.I Stats
+files should be given to
+.I uurate
+together, and cover the same time period.
+.PP
+If neither the
+.B \-i
+or
+.B \-I
+option nor any
+.I logfile
+options are given,
+.I uurate
+defaults to taking its input from the current Taylor
+.I Log
+and
+.I Stats
+files. The names are either as defined at compilation time, in case
+there is no config file, or taken from the arguments of the keywords
+.I logfile
+and
+.I statfile
+when encountered in the config file.
+This is the normal mode of operation.
+.PP
+The reporting options described below can be used to select
+the set of reports desired. If no options are given, a summary
+report is displayed. If there is no relevant data for a particular
+report or host, that report or host will be suppressed.
+.SH OPTIONS
+The following options may be given to
+.I uurate:
+.TP 5
+.B \-a
+All reports. Identical to
+.B \-cfexp.
+.TP 5
+.B \-c
+Report on call statistics. Requires data from a
+.I Log
+file.
+.TP 5
+.B \-d
+will print the default config file to be used.
+.TP 5
+.B \-e
+Report on efficiency (total connect time versus time spent transferring
+files). Requires data from both a
+.I Log
+and a
+.I Stats
+file, and they must span the same time period.
+.TP 5
+.B \-f
+Report on file transfer statistics. Requires data from a
+.I Stats
+file.
+.TP 5
+.B \-h
+will print a short help information.
+.TP 5
+.B \-i
+tells uurate to read any logfile information from standard input.
+.TP 5
+.B \-p
+report on protocol errors and packets sent/received
+.TP 5
+.B \-q
+do not print the Environment information,
+.TP 5
+.B \-t
+All reports. Identical to
+.B \-cfexp.
+plus the
+.B Compact summary.
+.TP 5
+.B \-v
+will print the version id string
+.TP 5
+.B \-x
+Report on remote execution requests (e.g.,
+.IR rmail ")."
+Requires data from a
+.I Log
+file.
+.TP 5
+.BI "\-s " "host"
+Restrict report output to
+.I host.
+.TP 5
+.BI "\-I " "config file"
+an alternate config file may be passed by this option.
+.SH "DESCRIPTION OF REPORTS"
+There are four reports available: the call, file transfer, efficiency,
+and remote execution reports. Each may be selected by a command line
+option. All reports may be selected via the options
+.B \-a
+or
+.B \-t.
+If no report selection options are given,
+.I uurate
+displays a compact traffic summary report (see below).
+.SS "Summary report"
+If no report options are given,
+.I uurate
+displays a traffic summary report. This is particularly useful in daily
+.I cron
+jobs which report on errors and the like. Traffic statistics for each
+active system is reported on a single line. If more than one system was
+active, a 'totals' line is included at the end of the report.
+.SS "Protocol packet report"
+The protocol report gives statistics on min/max packet and window sizes
+used during transmission. Further on data is collected for packets
+transferred. The data is collected for each host/protocol type.
+The fields are described below:
+.PP
+.br
+.nf
+.in +.3i
+.ta 1.0i
+.BR "site " "UUCP node name of neighbor host system,"
+.BR "typ " "Type of protocol used"
+.BR "Min " "minimum packet/window size"
+.BR "Max " "maximum packet/window size"
+.BR "sent " "packets sent"
+.BR "resent " "packets resent"
+.BR "received " "packets received"
+.in -.3
+.SS "Protocol error report"
+The protocol report gives statistics on packet errors
+during transmission. The data is collected for each host/protocol type.
+The fields are described below:
+.PP
+.br
+.nf
+.in +.3i
+.ta 1.5i
+.BR "site " "UUCP node name of neighbor host system,"
+.BR "typ " "Type of protocol used"
+.BR "header " "number of errors in header"
+.BR "checksum " "number of checksum errors"
+.BR "order " "number of order errors"
+.BR "resent " "number packets resent"
+.BR "rem-reject " "packets that the remote site rejected"
+.in -.3
+.SS "Call report"
+The call report gives statistics on inbound and outbound calls for
+each active host system. The fields are described below:
+.PP
+.br
+.nf
+.in +.3i
+.ta 1.0i
+.BR "site " "UUCP node name of neighbor host system,"
+.BR "succ. " "Successful calls attempted to/by that system,"
+.BR "failed " "Failed calls to/by that system,"
+.BR "total " "Total calls to/by that system,"
+.BR "time " "Collected connect time (hh:mm:ss) for all calls,"
+.in -.3
+.SS "File transfer reports"
+The file transfer reports give statistics on inbound and
+outbound file transfers (regardless of which end initiated the transfer)
+for each active host system. There are two reports, one for files
+sent to the remote system and one for files received from the remote
+system. The fields in each report are described below:
+.PP
+.br
+.nf
+.in +.3i
+.ta 1.0i
+.BR "site " "UUCP node name of neighbor host system"
+.BR "files " "Number of files transferred"
+.BR "Bytes/1000 " "Total size of files transferred given in thousands"
+.BR "xfr time " "Total time (hh:mm:ss) spent on transfer the files,"
+.BR "B/sec " "Average transfer rate (bytes/sec)."
+.in -.3
+.SS "Efficiency report"
+The efficiency report describes the utilization of the links
+to each active remote system, giving the ratio of total connect time
+to the time spent actually transferring files.
+The fields are described below:
+.PP
+.br
+.nf
+.in +.3i
+.ta 1.0i
+.BR "site " "UUCP node name of neighbor host system"
+.BR "connected " "Total connect time for that system (turn-around)"
+.BR "xfr time " "Total file transfer time for that system"
+.BR "overhead " "Connect time not used to transfer files,"
+.BR "eff. % " "Ratio of connect time to transfer time (xfer*100/conn)"
+.in -.3
+.SS "Command executions report"
+The remote execution report describes remotely
+requested command executions from each active host system, like
+.I rmail
+and
+.IR rnews "."
+Up to eight command names are displayed. If there are more, the
+rest will be put together in an `Misc.' column.
+The fields are described below:
+.PP
+.br
+.nf
+.in +.3i
+.ta 1.0i
+.BR "site " "UUCP node name of neighbor host system,"
+.BR "(command) " "Number of requests of this command,"
+.BR "Misc. " "Number of other requests, if more than eight."
+.in -.3i
+.SS FILES
+The file names below may be changed at compilation time or by the
+configuration file, so these are only approximations.
+.br
+.nf
+.in +.3in
+.ta 2.2i
+.IR "/usr/spool/uucp/Log " "V2/Taylor format call/execution log,"
+.IR "/usr/spool/uucp/Stats " "V2/Taylor format file transfer log."
+.SS "SEE ALSO"
+.IR uucico "(8)"
+.SS BUGS
+Does not understand other than V2/TAYLOR logging formats. Anyone care to
+volunteer to add the not mentioned?
+.PP
+Scanning the arguments of logfile and statfile keywords
+in config should handle lines continued with the backslash as well.
+.PP
+The
+.B failfm
+field in the call statistics table is always zero, unless
+something really serious happens, e.g. uucico got SIGQUIT or
+the whole system crashed.
+.SS AUTHOR
+Robert B. Denny (denny@alisa.com).
+.br
+Loosely based on the DECUS UUCP program
+.I uurate
+by Mark Pizzolato.
+.br
+Modified by Stephan Niemz (stephan@sunlab.ka.sub.org).
+.br
+Modified by Klaus Dahlenburg (kdburg@incoahe.hanse.de).
diff --git a/gnu/libexec/uucp/contrib/uureroute.perl b/gnu/libexec/uucp/contrib/uureroute.perl
new file mode 100644
index 00000000000..3eeb654e1e2
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uureroute.perl
@@ -0,0 +1,91 @@
+#!/usr/local/bin/perl
+eval ' exec /usr/local/bin/perl $0 "$@" '
+ if $running_under_some_shell;
+
+# From a script by <Bill.Campbell@celestial.com>
+# Newsgroups: comp.sources.misc
+# Subject: v28i073: uureroute - Reroute HDB queued mail, Part01/01
+# Date: 26 Feb 92 02:28:37 GMT
+#
+# This is a Honey DanBer specific routine written in perl to reroute all
+# mail queued up for a specific host. It needs to be run as "root" since
+# uucp will not allow itself to remove others requests.
+#
+# Revision *** 92/21/09: Francois Pinard <pinard@iro.umontreal.ca>
+# 1. adapted for Taylor UUCP
+#
+# Revision 1.3 91/10/08 09:01:21 src
+# 1. Rewritten in perl
+# 2. Add -v option for debugging.
+#
+# Revision 1.2 91/10/07 23:57:42 root
+# 1. Fix mail program path.
+# 2. Truncate directory name to 7 characters
+
+($progname = $0) =~ s!.*/!!; # save this very early
+
+$USAGE = "
+# Reroute uucp mail
+#
+# Usage: $progname [-v] host [host...]
+#
+# Options Argument Description
+# -v Verbose (doesn't execute /bin/sh)
+#
+";
+
+$UUSTAT = "/usr/local/bin/uustat";
+$SHELL = "/bin/sh";
+$SMAIL = "/bin/smail";
+
+sub usage
+{
+ die join ("\n", @_) . "\n$USAGE\n";
+}
+
+do "getopts.pl";
+
+&usage ("Invalid Option") unless do Getopts ("vV");
+
+$verbose = ($opt_v ? '-v' : ());
+$suffix = ($verbose ? '' : $$);
+
+&usage ("No system specified") if $#ARGV < 0;
+
+if (!$verbose)
+{
+ open (SHELL, "| $SHELL");
+ select SHELL;
+}
+
+while ($system = shift)
+{
+ $sysprefix = substr ($system, 0, 7);
+ $directory = "/usr/spool/uucp/$sysprefix";
+ open (UUSTAT, "$UUSTAT -s $system -c rmail |");
+ print "set -ex\n";
+ while (<UUSTAT>)
+ {
+ ($jobid, ) = split;
+ ($cfile) = substr ($jobid, length ($jobid) - 5);
+ $cfilename = "$directory/C./C.$cfile";
+ open (CFILE, $cfilename) || die "Cannot open $cfilename\n";
+ $_ = <CFILE>;
+ close CFILE;
+ if (/^E D\.(....) [^ ]+ [^ ]+ -CR D\.\1 0666 [^ ]+ 0 rmail (.*)/)
+ {
+ $datafile = "$directory/D./D.$1";
+ $address = $2;
+ }
+ else
+ {
+ print STDERR;
+ die "Cannot parse previous line from $cfilename\n";
+ }
+ print "$SMAIL -R $system!$address < $datafile && $UUSTAT -k $jobid\n";
+ }
+ close UUSTAT;
+}
+close SHELL unless $verbose;
+
+exit 0;
diff --git a/gnu/libexec/uucp/contrib/uusnap.c b/gnu/libexec/uucp/contrib/uusnap.c
new file mode 100644
index 00000000000..71092993dc2
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uusnap.c
@@ -0,0 +1,321 @@
+/* uusnap.c
+ (c) 1992 Heiko W.Rupp hwr@pilhuhn.ka.sub.org
+ uusnap is a tool to display the activities of the connected
+ systems.
+
+ Put a file uusnap.systems in NEWCONFIGDIR (see Makefile), in which
+ the systems, you want to monitor are listed, one on a single line.
+ The sequence of the files there determine the sequence of the
+ listing.
+
+ At the moment it only works with taylor config and taylor dirs
+
+ compile it form the Makefile or:
+ cc -c -g -pipe -O -I. -I. -DNEWCONFIGLIB=\"/usr/local/lib/uucp\" uusnap.c
+ cc -o uusnap uusnap.o
+ For this, uusnap.[ch] must be in the same directory as uucp.h and so.
+
+ uusnap must have read access to SPOOLDIR/.Status in order to work.
+*/
+
+#define MAXSYS 30 /* maximum number of systems */
+#define WAIT_NORMAL 10 /* wait period if noone is talking */
+#define WAIT_TALKING 2 /* refresh display every second if */
+ /* someone is talking with us */
+
+#include "uucp.h"
+#if USE_RCS_ID
+char uusnap_rcsid[] = "$Id: uusnap.c,v 1.1 1995/10/18 08:38:25 deraadt Exp $";
+#endif
+
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+
+extern char *ctime(time_t*);
+
+struct sysInfo {
+ char sysname[10]; /* name of the system to watch */
+ char *statfile; /* name of its status file */
+ char *spooldir; /* root of its spooldir */
+ int in; /* number of unprocessed in-files */
+ int out; /* number of files to send them */
+ time_t last; /* last poll time */
+ time_t next; /* time of next poll */
+ time_t lastidir; /* time of last in-spooldir access */
+ time_t lastodir; /* time of last outgoing spd acc */
+ time_t laststat; /* time of last status file access */
+ int status; /* status of the system */
+ int num_retries; /* number of retries */
+};
+
+struct sysInfo Systems[MAXSYS];
+
+
+/* I have extend the system status. If time for the specified system
+ is Never, I say so. To get this to work, one also should extend
+ uucico.c. It is not important to do this. With the normal uucico,
+ one only gets no status.
+*/
+
+const char *azStatus[] = /* Status codes as defined by uucico */
+{ /* listing them here instead of */
+ "Conversation complete", /* including the appropriate file */
+ "Port unavailable", /* reduces the size of the executable */
+ "Dial failed",
+ "Login failed",
+ "Handshake failed",
+ "Call failed",
+ "Talking",
+ "Wrong time to call",
+ "Time to call = Never !"
+};
+
+main()
+{
+ int i;
+ i=get_systems();
+ display_info(i);
+
+ exit(0);
+}
+
+int
+get_systems()
+{
+ char filename[1024];
+ char fn[1024];
+ char line[80];
+ FILE *fp;
+ int i=0;
+ int j;
+ struct stat stbuf;
+ struct sysInfo sys;
+
+ strcpy(filename,NEWCONFIGLIB);
+ strcat(filename,"/uusnap.systems");
+ if ((fp=fopen(filename,"r"))!=NULL) {
+ while (fgets(line,80,fp)!=NULL) {
+ *(rindex(line,'\n'))='\0';
+ strcpy(sys.sysname,line); /* get the name of the system */
+ strcpy(fn,SPOOLDIR); /* get the name of the statusfile */
+ strcat(fn,"/.Status/");
+ strcat(fn,line);
+ sys.statfile=malloc(strlen(fn)+1);
+ strcpy(sys.statfile,fn);
+ strcpy(fn,SPOOLDIR); /* get the name of the spooldir */
+ strcat(fn,"/");
+ strcat(fn,line);
+ sys.spooldir=malloc(strlen(fn)+1);
+ strcpy(sys.spooldir,fn);
+ sys.laststat=0;
+ sys.lastidir=sys.lastodir=0;
+ Systems[i]=sys; /* get_stat_for_system needs it */
+ get_stat_for_system(i); /* now get the system status */
+ get_inq_num(i,TRUE); /* number of unprocessed files */
+ get_outq_num(i,TRUE); /* number of files to send */
+ i++;
+ }
+ fclose(fp);
+ }
+ else {
+ fprintf(stderr,"Can't open %s \n",filename);
+ exit(1);
+ }
+ return i;
+}
+
+
+
+display_info(int numSys)
+{
+ char *filename;
+ int sysnum;
+ FILE *fp;
+ char contentline[80];
+ char isTalking=FALSE;
+ struct stat stbuf;
+ struct sysInfo sys;
+ time_t time;
+
+ filename = (char*)malloc(1024);
+ if (filename == NULL) {
+ fprintf(stderr, "Can't malloc 1024 bytes");
+ exit(1);
+ }
+
+ while(TRUE) {
+ display_headline();
+ for (sysnum=0;sysnum<numSys;sysnum++) {
+ sys = Systems[sysnum];
+ stat(sys.statfile,&stbuf);
+ if ((time=stbuf.st_atime) > sys.laststat) {
+ get_stat_for_system(sysnum);
+ }
+ if(display_status_line(sysnum)==1)
+ isTalking=TRUE;
+ }
+ if (isTalking) {
+ sleep(WAIT_TALKING);
+ isTalking = FALSE;
+ }
+ else
+ sleep(WAIT_NORMAL); /* wait a bit */
+ }
+ return 0;
+}
+
+int
+display_status_line(int sn)
+{
+ char *time_s;
+
+ int sys_stat,num_retries,wait;
+ int i;
+ time_t last_time;
+ time_t next_time;
+
+ struct sysInfo sys;
+
+ sys = Systems[sn];
+
+ printf("%10s ",sys.sysname);
+ get_inq_num(sn);
+ if (sys.in==0)
+ printf(" ");
+ else
+ printf("%3d ",sys.in);
+ get_outq_num(sn);
+ if (sys.out==0)
+ printf(" ");
+ else
+ printf("%3d ",sys.out);
+ time_s = ctime(&sys.last);
+ time_s = time_s + 11;
+ *(time_s+8)='\0';
+ printf("%8s ",time_s); /* time of last poll */
+ time_s = ctime(&sys.next);
+ time_s = time_s + 11;
+ *(time_s+8)='\0';
+ if (sys.last == sys.next)
+ printf(" ");
+ else
+ printf("%8s ",time_s); /* time of next poll */
+ if (sys.num_retries==0)
+ printf(" ");
+ else
+ printf("%2d ",sys.num_retries);
+ if (sys_stat==6) /* system is talking */
+ printf("\E[7m"); /* reverse video on */
+ printf("%s",azStatus[sys.status]);
+ if (sys.status==6) {
+ printf("\E[m\n"); /* reverse video off */
+ return 1;
+ }
+ else {
+ printf("\n");
+ return 0;
+ }
+}
+
+
+display_headline()
+{
+ printf("\E[;H\E[2J"); /* clear screen */
+ printf("\E[7muusnap (press CTRL-C to escape)\E[m \n\n");
+ printf(" System #in #out last next #ret Status\n");
+ return 0;
+}
+
+get_inq_num(int num,char firstTime)
+{
+ int i=0;
+ char filename[1024];
+ struct stat stbuf;
+ DIR *dirp;
+
+ strcpy(filename,Systems[num].spooldir);
+ strcat(filename,"/X./.");
+ stat(filename,&stbuf);
+ if ((stbuf.st_mtime > Systems[num].lastidir) || (firstTime)) {
+ if ((dirp=opendir(filename))!=NULL) {
+ while(readdir(dirp))
+ i++;
+ closedir(dirp);
+ stat(filename,&stbuf);
+ Systems[num].lastidir=stbuf.st_mtime;
+ }
+ else {
+ fprintf(stderr,"Can't open %s \n",filename);
+ exit(1);
+ }
+ if (i>=2)
+ i-=2; /* correct . and .. */
+ Systems[num].in=i;
+ }
+ return 0;
+}
+
+get_outq_num(int sys,char firstTime)
+{
+ int i=0;
+ char filename[1024];
+ struct stat stbuf;
+ DIR *dirp;
+
+ strcpy(filename,Systems[sys].spooldir);
+ strcat(filename,"/C./.");
+ stat(filename,&stbuf);
+ if ((stbuf.st_mtime > Systems[sys].lastodir) || (firstTime)) {
+ if ((dirp=opendir(filename))!=NULL) {
+ while(readdir(dirp))
+ i++;
+ closedir(dirp);
+ stat(filename,&stbuf);
+ Systems[sys].lastodir=stbuf.st_mtime;
+ }
+ else {
+ fprintf(stderr,"Can't open %s \n",filename);
+ exit(1);
+ }
+ if (i>=2)
+ i-=2; /* correct . and .. */
+ Systems[sys].out=i;
+ }
+ return 0;
+}
+
+get_stat_for_system(int i)
+{
+ char fn[80];
+ struct sysInfo sys;
+ struct stat stbuf;
+ FILE *fp;
+ time_t wait;
+
+ sys = Systems[i];
+ stat(sys.statfile,&stbuf);
+ if (stbuf.st_atime > sys.laststat) {
+ if ((fp=fopen(sys.statfile,"r"))!=NULL) {
+ fgets(fn,80,fp);
+ fclose(fp);
+ sscanf(fn,"%d %d %ld %d",
+ &sys.status,
+ &sys.num_retries,
+ &sys.last,
+ &wait);
+ sys.next=sys.last+wait;
+ }
+ else {
+ sys.status=0;
+ sys.num_retries=0;
+ sys.last=0;
+ sys.next=0;
+ }
+ stat(sys.statfile,&stbuf);
+ sys.laststat=stbuf.st_atime;
+ }
+ Systems[i] = sys;
+ return 0;
+}
diff --git a/gnu/libexec/uucp/contrib/uutraf b/gnu/libexec/uucp/contrib/uutraf
new file mode 100644
index 00000000000..00e4b035f72
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uutraf
@@ -0,0 +1,210 @@
+#!/usr/bin/perl
+# uutraf.pl -- UUCP Traffic Analyzer
+# SCCS Status : @(#)@ uutraf 1.8
+# Author : Johan Vromans
+# Created On : ***
+# Last Modified By: Johan Vromans
+# Last Modified On: Mon Aug 30 15:02:22 1993
+# Update Count : 6
+# Status : OK
+# Requires: : Perl V4 or later
+
+# Reads UUCP syslog, and generates a report from it.
+#
+# Created by Johan Vromans <jv@mh.nl>
+# Loosely based on an idea by Greg Hackney (hack@texbell.swbt.com)
+
+# Usage: uutraf [-taylor|-hdb|-bnu|-bsd] [syslog]
+
+# Logfile formats:
+#
+# BSD:
+#
+# jv mhres (2/23-5:18) (698818735) received 135 b 2 secs
+# root mhres (2/23-5:19) (698818742) sent 2365 b 3 secs, Pk: 38, Rxmt: 0
+#
+# HDB:
+#
+# uunet!uucp M (12/10-09:04:22) (C,16390,1) [ttyXX] <- 2371 / 5.000 secs, \
+# 474 bytes/sec
+#
+# Taylor:
+#
+# jv mhres (1992-02-24 20:49:04.06) sent 16234 bytes in 148.780 seconds \
+# (109 bytes/sec)
+# jv mhres (1992-02-24 21:04:05.76) received 449 bytes in 6.550 seconds \
+# (68 bytes/sec)
+
+$uucp_type = "gnu";
+
+%hosts = (); # hosts seen
+%bytes_in = (); # of bytes received from host
+%bytes_out = (); # of bytes sent to host
+%secs_in = (); # of seconds connect for recving
+%secs_out = (); # of seconds connect for sending
+%files_in = (); # of input requests
+%files_out = (); # of output requests
+
+# read info, break the lines and tally
+
+if ( $ARGV[0] =~ /^-/ ) {
+ ($uucp_type = substr (shift (@ARGV), 1)) =~ tr/A-Z/a-z/;
+}
+
+if ( $uucp_type eq "taylor" || $uucp_type eq "gnu" ) {
+ @ARGV = ("/usr/local/spool/uucp/Stats") unless $#ARGV >= 0;
+ $pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/ .]+)\\) " .
+ "(sent|received) (\\d+) bytes in (\\d+)\\.(\\d+) seconds";
+ $uucp_type = 0;
+ $recv = "received";
+}
+elsif ( $uucp_type eq "hdb" || $uucp_type eq "bnu" ) {
+ @ARGV = ("/usr/spool/uucp/.Admin/xferstats") unless $#ARGV >= 0;
+ $pat = "^([^!]+)![^(]+\\(([-0-9:\\/]+)\\).+([<>])-? " .
+ "(\\d+) \\/ (\\d+)\\.(\\d+) secs";
+ $uucp_type = 1;
+ $recv = "<";
+}
+elsif ( $uucp_type eq "bsd" || $uucp_type eq "v7" ) {
+ @ARGV = ("/usr/spool/uucp/SYSLOG") unless $#ARGV >= 0;
+ $pat = "^[^ ]+ ([^ ]+) \\(([-0-9:\\/]+)\\) \\([^)]+\\) " .
+ "(sent|received) (\\d+) b (\\d+) secs";
+ $uucp_type = 2;
+ $recv = "received";
+}
+else {
+ die ("FATAL: Unknown UUCP type: $uucp_type\n");
+}
+
+$garbage = 0;
+
+while ( <> ) {
+ unless ( /$pat/o ) {
+ print STDERR "$_";
+ next if /failed/;
+ if ( $garbage++ > 10 ) {
+ die ("FATAL: Too much garbage; wrong UUCP type?\n");
+ }
+ next;
+ }
+
+ # gather timestamps
+ $last_date = $2;
+ $first_date = $last_date unless defined $first_date;
+
+ # initialize new hosts
+ unless ( defined $hosts{$1} ) {
+ $hosts{$1} = $files_in{$1} = $files_out{$1} =
+ $bytes_in{$1} = $bytes_out{$1} =
+ $secs_in{$1} = $secs_out{$1} = 0;
+ }
+
+ # Taylor and HDB have milliseconds, BSD has not.
+ $secs = ($uucp_type == 2) ? ($5 + ($5 == 0 ? 0.5 : 0)) : ($5 + $6/1000);
+
+ # tally
+ if ( $3 eq $recv ) { # recv
+ $bytes_in{$1} += $4;
+ $files_in{$1}++;
+ $secs_in{$1} += $secs;
+ }
+ else { # xmit
+ $bytes_out{$1} += $4;
+ $files_out{$1}++;
+ $secs_out{$1} += $secs;
+ }
+ $garbage = 0;
+}
+
+@hosts = keys (%hosts);
+die ("No info found, stopped\n") if $#hosts < 0;
+
+################ report section ################
+
+$thishost = &gethostname();
+$thishost = (defined $thishost) ? "on node $thishost" : "report";
+
+if ( $uucp_type eq 0 ) { # Taylor UUCP
+ substr ($first_date, 16) = "";
+ substr ($last_date, 16) = "";
+}
+
+format std_head =
+@|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+"UUCP traffic $thishost from $first_date to $last_date"
+
+Remote -----------K-Bytes----------- ----Hours---- --Avg CPS-- --Files--
+ Host Recv Sent Total Recv Sent Recv Sent Recv Sent
+.
+format std_out =
+@<<<<<<< @>>>>>>>> @>>>>>>>> @>>>>>>>> @>>>>> @>>>>> @>>>> @>>>> @>>> @>>>
+$Zhost, $Zi_bytes, $Zo_bytes, $Zt_bytes, $Zi_hrs, $Zo_hrs, $Zi_acps, $Zo_acps, $Zi_count, $Zo_count
+.
+
+$^ = "std_head";
+$~ = "std_out";
+
+&print_dashes ();
+
+reset "T"; # reset totals
+
+foreach $host (@hosts) {
+ &print_line ($host, $bytes_in{$host}, $bytes_out{$host},
+ $secs_in{$host}, $secs_out{$host},
+ $files_in{$host}, $files_out{$host});
+
+}
+
+&print_dashes ();
+&print_line ("Total", $Ti_bytes, $To_bytes,
+ $Ti_secs, $To_secs, $Ti_count, $To_count);
+
+################ that's it ################
+
+sub print_line {
+ reset "Z"; # reset print fields
+ local ($Zhost,
+ $Zi_bytes, $Zo_bytes,
+ $Zi_secs, $Zo_secs,
+ $Zi_count, $Zo_count) = @_;
+ $Ti_bytes += $Zi_bytes;
+ $To_bytes += $Zo_bytes;
+ $Zt_bytes = $Zi_bytes + $Zo_bytes;
+ $Tt_bytes += $Zt_bytes;
+ $Zi_acps = ($Zi_secs > 0) ? sprintf ("%.0f", $Zi_bytes/$Zi_secs) : "0";
+ $Zo_acps = ($Zo_secs > 0) ? sprintf ("%.0f", $Zo_bytes/$Zo_secs) : "0";
+ $Zi_bytes = sprintf ("%.1f", $Zi_bytes/1000);
+ $Zo_bytes = sprintf ("%.1f", $Zo_bytes/1000);
+ $Zt_bytes = sprintf ("%.1f", $Zt_bytes/1000);
+ $Zi_hrs = sprintf ("%.1f", $Zi_secs/3600);
+ $Zo_hrs = sprintf ("%.1f", $Zo_secs/3600);
+ $Ti_secs += $Zi_secs;
+ $To_secs += $Zo_secs;
+ $Ti_count += $Zi_count;
+ $To_count += $Zo_count;
+ write;
+}
+
+sub print_dashes {
+ $Zhost = $Zi_bytes = $Zo_bytes = $Zt_bytes =
+ $Zi_hrs = $Zo_hrs = $Zi_acps = $Zo_acps = $Zi_count = $Zo_count =
+ "------------";
+ write;
+ # easy, isn't it?
+}
+
+################ missing ################
+
+sub gethostname {
+ $ENV{"SHELL"} = "/bin/sh";
+ $try = `(hostname) 2>/dev/null`;
+ chop $try;
+ return $+ if $try =~ /^[-.\w]+$/;
+ $try = `uname -n 2>/dev/null`;
+ chop $try;
+ return $+ if $try =~ /^[-.\w]+$/;
+ $try = `uuname -l 2>/dev/null`;
+ chop $try;
+ return $+ if $try =~ /^[-.\w]+$/;
+ return undef;
+}
diff --git a/gnu/libexec/uucp/contrib/uutry b/gnu/libexec/uucp/contrib/uutry
new file mode 100644
index 00000000000..258bb302f09
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uutry
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# This script was hacked together by Marc Evans (marc@Synergytics.Com)
+# I claim no copyright to it and don't really care what people do
+# with it, hence, it is public domain. I take no responsibility for
+# for happens if you use this script, providing no warentee. This
+# section of the comments may be removed if you so desire.
+#
+# Usage:
+# uutry [-x#] systemname
+# where '-x#' has the value [0-9], higher values providing more detail
+
+#
+# The following variables should be gropped from the configuration
+# files rather then being hard coded here.
+#
+Spool=/usr/spool/uucp
+Lib=/usr/local/lib/uucp
+Status=$Spool/.Status
+Debug=$Spool/Debug
+Uucico=$Lib/uucico
+#
+# Default option values
+#
+x="-x5"
+s=""
+
+for i in $* ; do
+ case $i in
+ -x*) x="$i" ;;
+ *) s="$i" ;;
+ esac
+done
+
+if [ x$s != x ]; then
+ rm -f $Status/$s
+ $Uucico -r1 $x -s$s &
+ >$Debug
+ tail -f $Debug
+else
+ echo "Usage: uutry systemname"
+ exit 1
+fi
diff --git a/gnu/libexec/uucp/contrib/uuxconv b/gnu/libexec/uucp/contrib/uuxconv
new file mode 100644
index 00000000000..843f9e000fa
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/uuxconv
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# uuxconv
+#
+# After converting to Taylor from SVR4.03 UUCP, I still had a lot of
+# jobs queued up to go out.
+#
+# This script is a one-shot to mass-requeue a site's spool.
+#
+# It doesn't go and do your whole spool, nor even all grades.
+# you need to go into each grade directory for each site and
+# execute this.
+#
+# i.e.: You have a site named 'foo'
+# cd /var/spool/uucp/foo/Z
+# uuxconv foo
+#
+# it does delete the 'D' & 'X' after requeing them, but doesn't remove
+# the 'C' files.
+#
+# I foolishly went and ran this script on all my queued jobs, without
+# adding the improvements to recursively go through the entire UUCP spool,
+# so now I'm out of files to test with. I don't want to add the code
+# to do that since I can't test it, and this worked.
+#
+# I hereby give this (trivial :-)) program to the GNU Project/FSF
+# and Ian Taylor in it's entirety, so that it can be placed in
+# the contrib directory of taylor-uucp, and save others the pain
+# of rewriting it.
+#
+# Richard Nickle (rick@trystro.uucp, rnickle@gnu.ai.mit.edu)
+# May 27, 1993
+#
+if [ $# -eq 0 ]
+then
+ echo "Usage: $0 sitename"
+ exit 1
+fi
+exit 0
+site=$1
+tsite=`echo $site | cut -c1-5`
+find . -name "D.$tsite*" -print |
+while read file
+do
+ control=`egrep "^C" $file | cut -c3-`
+ input=`egrep "^I" $file | cut -c3-`
+ (uux - -r -z $site!$control < $input) && (rm $file $input)
+ echo "$site!$control < $input"
+done
+exit 0
diff --git a/gnu/libexec/uucp/contrib/xc-conf.h-dist b/gnu/libexec/uucp/contrib/xc-conf.h-dist
new file mode 100644
index 00000000000..8810dd78d92
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/xc-conf.h-dist
@@ -0,0 +1,38 @@
+/*
+ * *************
+ * * XC-CONF.H *
+ * *************
+ *
+ * Configuration file for xchat 1.1. Edit this file prior to make-ing
+ * xchat.
+ *
+ * History:
+ * Bob Denny - Tue Sep 1 11:42:54 1992
+ */
+
+/*
+ * Edit this to reflect the relative location of xchat sources to
+ * the main Taylor UUCP source directory. As distributed, xchat
+ * is in the ./contrib sub-directory under the main Taylor UUCP
+ * directory. Therefore, Taylor's conf.h is in our parent directory.
+ */
+#include "../conf.h"
+
+/*
+ * The following definition establishes the default path to the
+ * scripts used by xchat. You may lleave this blank (""), but
+ * the command line given to xchat (e.g., in the 'sys' file entry)
+ * must specify a full (absolute) path name to the script to be
+ * executed. Normally, this is the same place you put your config
+ * and system files for UUCP.
+ */
+#define SCRIPT_DIR "/usr/local/conf/uucp/" /* MUST HAVE TRAILING "/" */
+
+/*
+ * The following definition establishes the default path to the
+ * log files that are produced by the 'dbgfile' statement. Normally
+ * this is the same location you configured Taylor UUCP to put its
+ * log files.
+ */
+#define LOG_DIR "/usr/spool/uucp/" /* MUST HAVE TRAILING "/" */
+
diff --git a/gnu/libexec/uucp/contrib/xchat.c b/gnu/libexec/uucp/contrib/xchat.c
new file mode 100644
index 00000000000..b44549e53ed
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/xchat.c
@@ -0,0 +1,1473 @@
+/*
+ * ***********
+ * * XCHAT.C *
+ * ***********
+ *
+ * Extended chat processor for Taylor UUCP. See accompanying documentation.
+ *
+ * Written by:
+ * Bob Denny (denny@alisa.com)
+ * Based on code in DECUS UUCP (for VAX/VMS)
+ *
+ * Small modification by:
+ * Daniel Hagerty (hag@eddie.mit.edu)
+ *
+ * History:
+ * Version 1.0 shipped with Taylor 1.03. No configuration info inside.
+ *
+ * Bob Denny - Sun Aug 30 18:41:30 1992
+ * V1.1 - long overdue changes for other systems. Rip out interval
+ * timer code, use timer code from Taylor UUCP, use select()
+ * for timed reads. Use Taylor UUCP "conf.h" file to set
+ * configuration for this program. Add defaulting of script
+ * and log file paths.
+ *
+ * Daniel Hagerty - Mon Nov 22 18:17:38 1993
+ * V1.2 - Added a new opcode to xchat. "expectstr" is a cross between
+ * sendstr and expect, looking for a parameter supplied string.
+ * Useful where a prompt could change for different dial in
+ * lines and such.
+ *
+ * Bugs:
+ * Does not support BSD terminal I/O. Anyone care to add it?
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/termio.h>
+
+#include "xc-conf.h"
+
+/*
+ * Pick a timing routine to use, as done in Taylor UUCP.
+ */
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS || HAVE_POLL
+#define USE_SELECT_TIMER 0
+#else
+#define USE_SELECT_TIMER HAVE_SELECT
+#if USE_SELECT_TIMER
+#include <sys/time.h>
+#endif
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP || HAVE_NAPMS
+#undef HAVE_POLL
+#define HAVE_POLL 0
+#endif
+
+#if HAVE_USLEEP || HAVE_NAP
+#undef HAVE_NAPMS
+#define HAVE_NAPMS 0
+#endif
+
+#if HAVE_USLEEP
+#undef HAVE_NAP
+#define HAVE_NAP 0
+#endif
+
+static int ttblind();
+static int ttcd();
+
+/* script entry -- "compiled" form of dial, hangup, or login script */
+
+struct script {
+ struct script *next; /* pointer to next entry, or null */
+ int opcode; /* numeric opcode */
+ char *strprm; /* pointer to string param */
+ long intprm; /* integer parameter */
+ char *newstate; /* new state name */
+};
+
+/* opcode definition array element -- one for each possible opcode */
+
+struct script_opdef {
+ char *opname;
+ int opcode; /* numeric opcode -- same as array index */
+ int prmtype; /* one of SC_NONE, SC_STR, SC_XSTR, SC_INT */
+ int newstate; /* one of SC_NONE, SC_NWST */
+};
+
+ /* values for opcode */
+
+#define SC_LABEL 0 /* "label" (state name) */
+#define SC_CDLY 1 /* set char output delay in msec */
+#define SC_PCHR 2 /* pause char for dial string (from P in input) */
+#define SC_PTIM 3 /* seconds to allow for pause char */
+#define SC_WCHR 4 /* wait char for dial string (from W in input) */
+#define SC_WTIM 5 /* seconds to allow for wait char */
+#define SC_ZERO 6 /* zero counter */
+#define SC_INCR 7 /* increment counter */
+#define SC_IFGT 8 /* change state if counter > int param */
+#define SC_WAIT 9 /* wait for int param seconds */
+#define SC_GOTO 10 /* unconditional change to new state */
+#define SC_SEND 11 /* send strparam (after sprintf substitutions) */
+#define SC_BRK 12 /* send a break */
+#define SC_HANG 13 /* drop DTR */
+#define SC_DIAL 14 /* send telno string (after subst PCHR & WCHR) */
+#define SC_DTIM 15 /* time in msec per digit (for timeout calculations) */
+ /* default = 100 (one tenth second) */
+#define SC_CTIM 16 /* additional time (in seconds) to wait for carrier */
+ /* default = 45 seconds */
+#define SC_EXIT 17 /* script done, success */
+#define SC_FAIL 18 /* script done, failure */
+#define SC_LOG 19 /* write strparam to uucp.log */
+#define SC_LOGE 20 /* write strparam to uucp.log w/error ind */
+#define SC_DBG 21 /* write strparam to debug log if debug lvl = LGI */
+#define SC_DBGE 22 /* write strparam to debug log if debug lvl = LGIE */
+#define SC_DBST 23 /* 'or' intparam into debug mask */
+#define SC_DBCL 24 /* 'bicl' intparam into debug mask */
+#define SC_TIMO 25 /* newstate if no match in intparam secs */
+ /* (uses calculated dial time if intparam is 0) */
+#define SC_XPCT 26 /* wait for strparam, goto _newstate if found */
+#define SC_CARR 27 /* goto _newstate if carrier detected */
+#define SC_FLSH 28 /* flush typeahead buffer */
+#define SC_IFBL 29 /* change state if controller is blind w/o CD */
+#define SC_IFBG 30 /* chg state if ctlr is blind and counter > intprm */
+#define SC_SNDP 31 /* send parameter n */
+#define SC_IF1P 32 /* if parameter n present */
+#define SC_IF0P 33 /* if parameter n absent */
+#define SC_DBOF 34 /* open debugging file */
+#define SC_TELN 35 /* Set telno from parameter n */
+#define SC_7BIT 36 /* Set port to 7-bit stripping */
+#define SC_8BIT 37 /* Set port for 8-bit characters */
+#define SC_PNON 38 /* Set port for 8-bit, no parity */
+#define SC_PEVN 39 /* Set port for 7-bit, even parity */
+#define SC_PODD 40 /* Set port for 7-bit, odd parity */
+#define SC_HUPS 41 /* Change state on HUP signal */
+#define SC_XPST 42 /* Expect a param string */
+#define SC_END 43 /* end of array */
+
+ /* values for prmtype, prm2type */
+
+#define SC_NONE 0 /* no parameter */
+#define SC_STR 1 /* simple string */
+#define SC_INT 2 /* integer */
+#define SC_NWST 3 /* new state name */
+#define SC_XSTR 4 /* translated string */
+
+/* opcode definition table for dial/login/hangup scripts */
+
+static struct script_opdef sc_opdef[] =
+ {
+ {"label", SC_LABEL, SC_NONE, SC_NONE},
+ {"chrdly", SC_CDLY, SC_INT, SC_NONE},
+ {"pchar", SC_PCHR, SC_STR, SC_NONE},
+ {"ptime", SC_PTIM, SC_INT, SC_NONE},
+ {"wchar", SC_WCHR, SC_STR, SC_NONE},
+ {"wtime", SC_WTIM, SC_INT, SC_NONE},
+ {"zero", SC_ZERO, SC_NONE, SC_NONE},
+ {"count", SC_INCR, SC_NONE, SC_NONE},
+ {"ifgtr", SC_IFGT, SC_INT, SC_NWST},
+ {"sleep", SC_WAIT, SC_INT, SC_NONE},
+ {"goto", SC_GOTO, SC_NONE, SC_NWST},
+ {"send", SC_SEND, SC_XSTR, SC_NONE},
+ {"break", SC_BRK, SC_NONE, SC_NONE},
+ {"hangup", SC_HANG, SC_NONE, SC_NONE},
+ {"7bit", SC_7BIT, SC_NONE, SC_NONE},
+ {"8bit", SC_8BIT, SC_NONE, SC_NONE},
+ {"nopar", SC_PNON, SC_NONE, SC_NONE},
+ {"evenpar", SC_PEVN, SC_NONE, SC_NONE},
+ {"oddpar", SC_PODD, SC_NONE, SC_NONE},
+ {"telno", SC_TELN, SC_INT, SC_NONE},
+ {"dial", SC_DIAL, SC_NONE, SC_NONE},
+ {"dgttime", SC_DTIM, SC_INT, SC_NONE},
+ {"ctime", SC_CTIM, SC_INT, SC_NONE},
+ {"success", SC_EXIT, SC_NONE, SC_NONE},
+ {"failed", SC_FAIL, SC_NONE, SC_NONE},
+ {"log", SC_LOG, SC_XSTR, SC_NONE},
+ {"logerr", SC_LOGE, SC_XSTR, SC_NONE},
+ {"debug", SC_DBG, SC_XSTR, SC_NONE},
+ {"debuge", SC_DBGE, SC_XSTR, SC_NONE},
+ {"dbgset", SC_DBST, SC_INT, SC_NONE},
+ {"dbgclr", SC_DBCL, SC_INT, SC_NONE},
+ {"dbgfile", SC_DBOF, SC_XSTR, SC_NONE},
+ {"timeout", SC_TIMO, SC_INT, SC_NWST},
+ {"expect", SC_XPCT, SC_XSTR, SC_NWST},
+ {"ifcarr", SC_CARR, SC_NONE, SC_NWST},
+ {"ifhang", SC_HUPS, SC_NONE, SC_NWST},
+ {"flush", SC_FLSH, SC_NONE, SC_NONE},
+ {"ifblind", SC_IFBL, SC_NONE, SC_NWST},
+ {"ifblgtr", SC_IFBG, SC_INT, SC_NWST},
+ {"sendstr", SC_SNDP, SC_INT, SC_NONE},
+ {"ifstr", SC_IF1P, SC_INT, SC_NWST},
+ {"ifnstr", SC_IF0P, SC_INT, SC_NWST},
+ {"expectstr", SC_XPST, SC_INT, SC_NWST},
+ {"table end", SC_END, SC_NONE, SC_NONE}
+ };
+
+#define SUCCESS 0
+#define FAIL 1
+#define ERROR -1
+#define MAX_SCLINE 255 /* max length of a line in a script file */
+#define MAX_EXPCT 127 /* max length of an expect string */
+#define CTL_DELIM " \t\n\r" /* Delimiters for tokens */
+#define SAME 0 /* if (strcmp(a,b) == SAME) ... */
+#define SLOP 10 /* Slop space on arrays */
+#define MAX_STRING 200 /* Max length string to send/expect */
+
+#define DEBUG_LEVEL(level) \
+ (Debug & (1 << level))
+
+#define DB_LOG 0 /* error messages and a copy of the LOGFILE output */
+#define DB_LGIE 1 /* dial,login,init trace -- errors only */
+#define DB_LGI 2 /* dial,login,init trace -- nonerrors (incl chr I/O) */
+#define DB_LGII 3 /* script processing internals */
+
+#define TRUE 1
+#define FALSE 0
+
+#define NONE 0
+#define EVEN 1
+#define ODD 2
+
+#define logit(m, p1) fprintf(stderr, "%s %s\n", m, p1)
+
+static char **paramv; /* Parameter vector */
+static int paramc; /* Parameter count */
+static char telno[64]; /* Telephone number w/meta-chars */
+static int Debug;
+static int fShangup = FALSE; /* TRUE if HUP signal received */
+static FILE *dbf = NULL;
+static struct termio old, new;
+
+extern int usignal();
+extern int uhup();
+
+static struct siglist
+{
+ int signal;
+ int (*o_catcher) ();
+ int (*n_catcher) ();
+} sigtbl[] = {
+ { SIGHUP, NULL, uhup },
+ { SIGINT, NULL, usignal },
+ { SIGIOT, NULL, usignal },
+ { SIGQUIT, NULL, usignal },
+ { SIGTERM, NULL, usignal },
+ { SIGALRM, NULL, usignal },
+ { 0, NULL, NULL } /* Table end */
+ };
+
+extern struct script *read_script();
+extern void msleep();
+extern char xgetc();
+extern void charlog();
+extern void setup_tty();
+extern void restore_tty();
+extern void ttoslow();
+extern void ttflui();
+extern void tthang();
+extern void ttbreak();
+extern void tt7bit();
+extern void ttpar();
+extern void DEBUG();
+
+extern void *malloc();
+
+
+/*
+ * **********************************
+ * * BEGIN EXECUTION - MAIN PROGRAM *
+ * **********************************
+ *
+ * This program is called by Taylor UUCP with a list of
+ * arguments in argc/argv, and stdin/stdout mapped to the
+ * tty device, and stderr mapped to the Taylor logfile, where
+ * anything written to stdout will be logged as an error.
+ *
+ */
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ int i, stat;
+ FILE *sf;
+ char sfname[256];
+ struct script *script;
+ struct siglist *sigs;
+
+ /*
+ * The following is needed because my cpp does not have the
+ * #error directive...
+ */
+#if ! HAVE_SELECT
+ no_select_sorry(); /* Sad way to fail make */
+#endif
+
+ paramv = &argv[2]; /* Parameters start at 2nd arg */
+ paramc = argc - 2; /* Number of live parameters */
+
+ telno[0] = '\0';
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "%s: no script file supplied\n", argv[0]);
+ exit(FAIL);
+ }
+
+ /*
+ * If the script file argument begins with '/', then we assume
+ * it is an absolute pathname, otherwise, we prepend the
+ * SCRIPT_DIR path.
+ */
+ *sfname = '\0'; /* Empty name string */
+ if(argv[1][0] != '/') /* If relative path */
+ strcat(sfname, SCRIPT_DIR); /* Prepend the default dir. */
+ strcat(sfname, argv[1]); /* Add the script file name */
+
+ /*
+ * Now open the script file.
+ */
+ if ((sf = fopen(sfname, "r")) == NULL)
+ {
+ fprintf(stderr, "%s: Failed to open script %s\n", argv[0], sfname);
+ perror(" ");
+ exit(FAIL);
+ }
+
+ /*
+ * COMPILE SCRIPT
+ */
+ if ((script = read_script(sf)) == NULL)
+ {
+ fprintf(stderr, "%s: script error in \"%s\"\n", argv[0], argv[1]);
+ exit(FAIL);
+ }
+
+ /*
+ * Set up a signal catcher so the line can be returned to
+ * it's current state if something nasty happens.
+ */
+ sigs = &sigtbl[0];
+ while(sigs->signal)
+ {
+ sigs->o_catcher = (int (*) ())signal(sigs->signal, sigs->n_catcher);
+ sigs += 1;
+ }
+
+ /*
+ * Save current tty settings, then set up raw, single
+ * character input processing, with 7-bit stripping.
+ */
+ setup_tty();
+
+ /*
+ * EXECUTE SCRIPT
+ */
+ if ((stat = do_script(script)) != SUCCESS)
+ fprintf(stderr, "%s: script %s failed.\n", argv[0], argv[1]);
+
+ /*
+ * Clean up and exit.
+ */
+ restore_tty();
+#ifdef FIXSIGS
+ sigs = &sigtbl[0];
+ while(sigs->signal)
+ if(sigs->o_catcher != -1)
+ signal(sigs->signal, sigs->o_catcher);
+#endif
+ exit(stat);
+}
+
+/*
+ * deal_script - deallocate a script and all strings it points to
+ */
+int deal_script(loc)
+struct script *loc;
+{
+ /*
+ * If pointer is null, just exit
+ */
+ if (loc == (struct script *)NULL)
+ return SUCCESS;
+
+ /*
+ * Deallocate the rest of the script
+ */
+ deal_script(loc->next);
+
+ /*
+ * Deallocate the string parameter, if any
+ */
+ if (loc->strprm != (char *)NULL)
+ free(loc->strprm);
+
+ /*
+ * Deallocate the new state name parameter, if any
+ */
+ if (loc->newstate != (char *)NULL)
+ free(loc->newstate);
+
+ /*
+ * Deallocate this entry
+ */
+ free(loc);
+
+ return SUCCESS;
+}
+
+
+/*
+ * read_script
+ *
+ * Read & compile a script, return pointer to first entry, or null if bad
+ */
+struct script *read_script(fd)
+ FILE *fd;
+{
+ struct script *this = NULL;
+ struct script *prev = NULL;
+ struct script *first = NULL;
+ long len, i;
+ char inpline[MAX_SCLINE];
+ char inpcopy[MAX_SCLINE];
+ char *c, *cln, *opc, *cp;
+
+ /*
+ * MAIN COMPILATION LOOP
+ */
+ while ((c = fgets(inpline, (sizeof inpline - 1), fd)) != (char *)NULL)
+ {
+ /*
+ * Skip comments and blank lines
+ */
+ if (*c == '#' || *c == '\n')
+ continue;
+
+ /*
+ * Get rid of the trailing newline, and copy the string
+ */
+ inpline[strlen(inpline)-1] = '\0';
+ strcpy(inpcopy, inpline);
+
+ /*
+ * Look for text starting in the first col (a label)
+ */
+ if ((!isspace(inpline[0])) &&
+ (cln = strchr (inpline, ':')) != (char *)NULL) {
+ this = (struct script *)malloc (sizeof (struct script));
+ if (prev != (struct script *)NULL)
+ prev->next = this;
+ prev = this;
+ if (first == (struct script *)NULL)
+ first = this;
+ this->next = (struct script *)NULL;
+ this->opcode = SC_LABEL;
+ len = cln - c;
+ this->strprm = (char *)malloc(len+1);
+ strncpy(this->strprm, c, len);
+ (this->strprm)[len] = '\0';
+ this->intprm = 0;
+ this->newstate = (char *)NULL;
+ c = cln + 1;
+ }
+
+ /*
+ * Now handle the opcode. Fold it to lower case.
+ */
+ opc = strtok(c, CTL_DELIM);
+ if (opc == (char *)NULL) /* If no opcode... */
+ continue; /* ...read the next line */
+ cp = opc;
+ while(*cp)
+ tolower(*cp++);
+
+ /*
+ * If we have an opcode but we haven't seen anything
+ * else (like a label) yet, i.e., this is the first
+ * entry, and there was no label. We need to
+ * cobble up a label so that read_script is happy
+ */
+ if (first == (struct script *)NULL)
+ {
+ this = (struct script *)malloc (sizeof (struct script));
+ prev = this;
+ first = this;
+ this->next = (struct script *)NULL;
+ this->opcode = SC_LABEL;
+ this->strprm = (char *)malloc(2);
+ strcpy(this->strprm, ":");
+ this->intprm = 0;
+ this->newstate = (char *)NULL;
+ }
+
+ /*
+ * Find opcode - ndex through the opcode definition table
+ */
+ for (i=1; sc_opdef[i].opcode != SC_END; i++)
+ if (strcmp(opc, sc_opdef[i].opname) == SAME)
+ break;
+ if ((sc_opdef[i].opcode) == SC_END)
+ {
+ logit ("Bad opcode in script", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+
+ /*
+ * Found opcode. Allocate a new command node and initialize
+ */
+ this = (struct script *)malloc(sizeof (struct script));
+ prev->next = this;
+ prev = this;
+ this->next = (struct script *)NULL;
+ this->opcode = sc_opdef[i].opcode;
+ this->strprm = (char *)NULL;
+ this->intprm = 0;
+ this->newstate = (char *)NULL;
+
+ /*
+ * Pick up new state parameter, if any
+ */
+ if (sc_opdef[i].newstate == SC_NWST)
+ {
+ c = strtok((char *)NULL, CTL_DELIM);
+ if (c == (char *)NULL)
+ {
+ logit("Missing new state", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+ else
+ {
+ this->newstate = (char *)malloc(strlen(c)+1);
+ strcpy(this->newstate, c);
+ }
+ }
+
+ /*
+ * Pick up the string or integer parameter. Handle missing
+ * parameter gracefully.
+ */
+ switch (sc_opdef[i].prmtype)
+ {
+ /*
+ * INT parameter - convert and store in node
+ */
+ case SC_INT:
+ c = strtok((char *)NULL, CTL_DELIM);
+ if (c == (char *)NULL)
+ {
+ logit("Missing script param", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+ /*
+ * If this is the parameter to DBST or DBCL, force
+ * base-10 conversion, else convert per parameter.
+ */
+ if (sc_opdef[i].opcode == SC_DBST ||
+ sc_opdef[i].opcode == SC_DBCL)
+ this->intprm = strtol(c, (char **)NULL, 0);
+ else
+ this->intprm = strtol(c, (char **)NULL, 10);
+ break;
+
+ /*
+ * STR/XSTR strings.
+ */
+ case SC_STR:
+ case SC_XSTR:
+ c = strtok((char *)NULL, CTL_DELIM);
+ if (c == (char *)NULL)
+ {
+ logit("Missing script param", opc);
+ deal_script(first);
+ return (struct script *)NULL;
+ }
+ /*
+ * For XSTR opcode, use c to find out where
+ * the string param begins in the copy of the
+ * input line, and pick up all that's left of
+ * the line (to allow imbedded blanks, etc.).
+ */
+ if (sc_opdef[i].prmtype == SC_XSTR)
+ c = &inpcopy[0] + (c - &inpline[0]);
+
+ /*
+ * Allocate a buffer for the string parameter
+ */
+ this->strprm = (char *)malloc(strlen(c)+1);
+
+ /*
+ * For XSTR, Translate the string and store its
+ * length. Note that, after escape sequences are
+ * compressed, the resulting string may well be a
+ * few bytes shorter than the input string (whose
+ * length was the basis for the malloc above),
+ * but it will never be longer.
+ */
+ if (sc_opdef[i].prmtype == SC_XSTR)
+ {
+ this->intprm = xlat_str(this->strprm, c);
+ this->strprm[this->intprm] = '\0';
+ }
+ else
+ strcpy(this->strprm, c);
+ break;
+
+ }
+ }
+
+ /*
+ * EOF
+ */
+ return first;
+}
+
+
+/*
+ * xlat_str
+ *
+ * Translate embedded escape characters in a "send" or "expect" string.
+ *
+ * Called by read_script(), above.
+ *
+ * Returns the actual length of the resulting string. Note that imbedded
+ * nulls (specified by \000 in the input) ARE allowed in the result.
+ */
+xlat_str(out, in)
+ char *out, *in;
+{
+ register int i = 0, j = 0;
+ int byte, k;
+
+ while (in[i])
+ {
+ if (in[i] != '\\')
+ {
+ out[j++] = in[i++];
+ }
+ else
+ {
+ switch (in[++i])
+ {
+ case 'd': /* EOT */
+ out[j++] = 0x04;
+ break;
+ case 'N': /* null */
+ out[j++] = 0x00;
+ break;
+ case 'n': /* line feed */
+ out[j++] = 0x0a;
+ break;
+ case 'r': /* carriage return */
+ out[j++] = 0x0d;
+ break;
+ case 's': /* space */
+ out[j++] = ' ';
+ break;
+ case 't': /* tab */
+ out[j++] = '\t';
+ break;
+ case '-': /* hyphen */
+ out[j++] = '-';
+ break;
+ case '\\': /* back slash */
+ out[j++] = '\\';
+ break;
+ case '0': /* '\nnn' format */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ byte = in[i] - '0';
+ k = 0;
+
+ while (3 > ++k)
+ if ((in[i+1] < '0') || (in[i+1] > '7'))
+ break;
+ else
+ {
+ byte = (byte<<3) + in[i+1] - '0';
+ ++i;
+ }
+ out[j++] = byte;
+ break;
+ default: /* don't know so skip it */
+ break;
+ }
+ ++i;
+ }
+ }
+ return j;
+}
+
+
+/* find a state within a script */
+
+struct script *
+ find_state(begin, newstate)
+struct script *begin;
+char *newstate;
+{
+ struct script *here;
+
+ for (here=begin; here != (struct script *)NULL; here=here->next) {
+ if (here->opcode == SC_LABEL &&
+ strcmp(here->strprm, newstate) == SAME)
+ return here;
+ }
+ return (struct script *)NULL;
+}
+
+
+/*
+ * do_script() - execute a script
+ */
+int do_script(begin)
+ struct script *begin;
+{
+ struct script *curstate, *newstate, *curscr;
+ int dbgsave;
+ char tempstr[MAX_SCLINE];
+ char dfname[256];
+ char *c, chr;
+ int prmlen;
+ int dbfd;
+
+ time_t sc_carrtime = 45000; /* time to wf carr after dial */
+ time_t sc_chrdly = 100; /* delay time for ttoslow */
+ time_t sc_ptime = 2000; /* time to allow for pause char */
+ time_t sc_wtime = 10000; /* time to allow for wait char */
+ time_t sc_dtime = 100; /* time to allow for each digit */
+ time_t sc_dtmo; /* total time to dial number */
+ int sc_counter; /* random counter */
+ char sc_pchar = ','; /* modem pause character */
+ char sc_wchar = 'W'; /* modem wait-for-dialtone character */
+ time_t sc_begwait; /* time at beg of wait */
+ time_t sc_secs; /* timeout period */
+
+ int expcnt;
+ int expin;
+ static char expbuf[MAX_EXPCT];
+
+ dbgsave = Debug;
+ curstate = begin;
+
+ if (curstate == (struct script *)NULL)
+ return SUCCESS;
+
+ _newstate:
+ /*
+ * do all of curstate's actions. Enter with curstate pointing
+ * to a label entry
+ */
+ expin = 0;
+
+ for (curscr = curstate->next; /* point to 1st scr after label */
+ (curscr != (struct script *)NULL) && /* do until end of scr */
+ (curscr->opcode != SC_LABEL); /* or next label */
+ curscr = curscr->next)
+ {
+ expcnt = 0;
+ switch (curscr->opcode)
+ {
+ case SC_LABEL:
+ logit("Script proc err", curstate->strprm);
+ return FAIL;
+
+ case SC_FLSH:
+ DEBUG(DB_LGII, "Flushing typeahead buffer\n", 0);
+ ttflui();
+ break;
+
+ case SC_CDLY:
+ sc_chrdly = curscr->intprm;
+ DEBUG(DB_LGII, "Set chrdly to %d\n", sc_chrdly);
+ break;
+
+ case SC_PCHR:
+ sc_pchar = *(curscr->strprm);
+ DEBUG(DB_LGII, "Set pause char to %c\n", sc_pchar);
+ break;
+
+ case SC_PTIM:
+ sc_ptime = curscr->intprm;
+ DEBUG(DB_LGII, "Set pause time to %d\n", sc_ptime);
+ break;
+
+ case SC_WCHR:
+ sc_wchar = *(curscr->strprm);
+ DEBUG(DB_LGII, "Set wait char to %c\n", sc_wchar);
+ break;
+
+ case SC_WTIM:
+ sc_wtime = curscr->intprm;
+ DEBUG(DB_LGII, "Set wait time to %d\n", sc_wtime);
+ break;
+
+ case SC_ZERO:
+ sc_counter = 0;
+ DEBUG(DB_LGII, "Set counter to %d\n", sc_counter);
+ break;
+
+ case SC_INCR:
+ sc_counter++;
+ DEBUG(DB_LGII, "Incr counter to %d\n", sc_counter);
+ break;
+
+ case SC_WAIT:
+ DEBUG(DB_LGII, "Sleeping %d tenth-secs\n", curscr->intprm);
+ msleep(curscr->intprm);
+ break;
+
+ case SC_DTIM:
+ sc_dtime = curscr->intprm;
+ DEBUG(DB_LGII, "Digit time is %d\n", sc_dtime);
+ break;
+
+ case SC_CTIM:
+ sc_carrtime = curscr->intprm;
+ DEBUG(DB_LGII, "Carrier time is %d\n", sc_carrtime);
+ break;
+
+ case SC_EXIT:
+ Debug = dbgsave;
+ DEBUG(DB_LGI, "Script ended successfully\n", 0);
+ return SUCCESS;
+
+ case SC_FAIL:
+ Debug = dbgsave;
+ if (DEBUG_LEVEL(DB_LGI) && dbf != NULL)
+ fprintf(dbf, "Script failed\n");
+ else if (expin)
+ charlog(expbuf, expin, DB_LOG,
+ "Script failed. Last received data");
+ return FAIL;
+
+ case SC_LOG:
+ logit(curscr->strprm, "");
+ break;
+
+ case SC_LOGE:
+ logit("ERROR: ", curscr->strprm);
+ break;
+
+ case SC_DBOF:
+ /*
+ * If the debug file name does not begin with "/", then
+ * we prepend the LOG_DIR to the string. Then CREATE the
+ * file. This WIPES OUT previous logs.
+ */
+ *dfname = '\0'; /* Zero name string */
+ if(curscr->strprm[0] != '/')
+ strcat(dfname, LOG_DIR); /* Prepend default directory */
+ strcat(dfname, curscr->strprm); /* Add given string */
+ DEBUG(DB_LGII, "Open debug file %s\n", dfname);
+ if ((dbfd = creat (dfname, 0600)) <= 0)
+ {
+ logit("Failed to create debug log %s", dfname);
+ perror("");
+ return FAIL;
+ }
+ if ((dbf = fdopen(dbfd, "w")) == NULL)
+ {
+ logit("Failed to open debug log fildes.", "");
+ perror("");
+ return FAIL;
+ }
+ break;
+
+ case SC_DBG:
+ DEBUG(DB_LGI, "<%s>\n", curscr->strprm);
+ break;
+
+ case SC_DBGE:
+ DEBUG(DB_LGIE, "ERROR: <%s>\n", curscr->strprm);
+ break;
+
+ case SC_DBST:
+ Debug |= curscr->intprm;
+ DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug);
+ break;
+
+ case SC_DBCL:
+ Debug &= ~(curscr->intprm);
+ DEBUG(DB_LGII, "Debug mask set to %04o (octal)\n", Debug);
+ break;
+
+ case SC_BRK:
+ DEBUG(DB_LGI, "Sending break\n", 0);
+ ttbreak();
+ break;
+
+ case SC_HANG:
+ DEBUG(DB_LGI, "Dropping DTR\n", 0);
+ tthang();
+ break;
+
+ case SC_7BIT:
+ DEBUG(DB_LGI, "Enabling 7-bit stripping\n", 0);
+ tt7bit(TRUE);
+ break;
+
+ case SC_8BIT:
+ DEBUG(DB_LGI, "Disabling 7-bit stripping\n", 0);
+ tt7bit(FALSE);
+ break;
+
+ case SC_PNON:
+ DEBUG(DB_LGI, "Setting 8-bit, no parity\n", 0);
+ ttpar(NONE);
+ break;
+
+ case SC_PEVN:
+ DEBUG(DB_LGI, "Setting 7-bit, even parity\n", 0);
+ ttpar(EVEN);
+ break;
+
+ case SC_PODD:
+ DEBUG(DB_LGI, "Setting 7-bit, odd parity\n", 0);
+ ttpar(ODD);
+ break;
+
+ case SC_IFBL:
+ if (ttblind())
+ {
+ DEBUG(DB_LGI, "Blind mux,\n", 0);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_IFBG:
+ if (ttblind() && sc_counter > curscr->intprm)
+ {
+ DEBUG(DB_LGI, "Blind mux & ctr > %d\n",
+ curscr->intprm);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_IFGT:
+ if (sc_counter > curscr->intprm)
+ {
+ DEBUG(DB_LGI, "Counter > %d\n", curscr->intprm);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_GOTO:
+ _chgstate:
+ DEBUG(DB_LGI, "Changing to state %s\n",
+ curscr->newstate);
+ curstate = find_state(begin, curscr->newstate);
+ if (curstate == NULL)
+ {
+ logit("New state not found",
+ curscr->newstate);
+ return FAIL;
+ }
+ goto _newstate;
+
+ case SC_SEND:
+ ttoslow(curscr->strprm, curscr->intprm, sc_chrdly);
+ break;
+
+ case SC_TELN:
+ if (curscr->intprm > paramc - 1)
+ {
+ sprintf(tempstr, "telno - param #%d", curscr->intprm);
+ logit(tempstr, " not present");
+ return FAIL;
+ }
+ strcpy(telno, paramv[curscr->intprm]);
+ DEBUG(DB_LGII, "telno set to %s\n", telno);
+ break;
+
+ case SC_SNDP:
+ if (curscr->intprm > paramc - 1)
+ {
+ sprintf(tempstr, "sendstr - param #%d", curscr->intprm);
+ logit(tempstr, " not present");
+ return FAIL;
+ }
+ prmlen = xlat_str(tempstr, paramv[curscr->intprm]);
+ ttoslow(tempstr, prmlen, sc_chrdly);
+ break;
+
+ case SC_IF1P:
+ if (curscr->intprm < paramc)
+ goto _chgstate;
+ break;
+
+ case SC_IF0P:
+ if (curscr->intprm >= paramc)
+ goto _chgstate;
+ break;
+
+ case SC_DIAL:
+ if(telno[0] == '\0')
+ {
+ logit("telno not set", "");
+ return(FAIL);
+ }
+ /*
+ * Compute and set a default timeout for the 'timeout'
+ * command. Some parameters in this computation may be
+ * changed by the script. See the man page xchat(8) for
+ * details.
+ */
+ sc_dtmo = (sc_dtime+sc_chrdly)*strlen(telno)
+ + sc_carrtime;
+ c=strcpy(tempstr, telno);
+ for (; *c!='\0'; c++)
+ {
+ if (*c == 'W')
+ {
+ *c = sc_wchar;
+ sc_dtmo += sc_wtime;
+ }
+ else if (*c == 'P')
+ {
+ *c = sc_pchar;
+ sc_dtmo += sc_ptime;
+ }
+ }
+ DEBUG(DB_LGI, "Dialing, default timeout is %d millisecs\n", sc_dtmo);
+ ttoslow(tempstr, 0, sc_chrdly);
+ break;
+
+ case SC_TIMO: /* these are "expects", don't bother */
+ case SC_XPCT: /* with them yet, other than noting that */
+ case SC_CARR: /* they exist */
+ case SC_XPST:
+ expcnt++;
+ break;
+ }
+
+ }
+
+ /* we've done the current state's actions, now do its expects, if any */
+
+ if (expcnt == 0)
+ {
+ if (curscr != (struct script *)NULL &&
+ (curscr->opcode == SC_LABEL))
+ {
+ curstate = curscr;
+ DEBUG(DB_LGI, "Fell through to state %s\n",
+ curstate->strprm);
+ goto _newstate;
+ }
+ else
+ {
+ logit("No way out of state", curstate->strprm);
+ return FAIL;
+ }
+ }
+
+ time(&sc_begwait); /* log time at beg of expect */
+ DEBUG(DB_LGI, "Doing expects for state %s\n", curstate->strprm);
+ charlog((char *)NULL, 0, DB_LGI, "Received");
+
+ while (1)
+ {
+ chr = xgetc(1); /* Returns upon char input or 1 sec. tmo */
+
+ charlog(&chr, 1, DB_LGI, (char *)NULL);
+
+ if (chr != EOF)
+ {
+ if (expin < MAX_EXPCT)
+ {
+ expbuf[expin++] = chr & 0x7f;
+ }
+ else
+ {
+ strncpy(expbuf, &expbuf[1], MAX_EXPCT-1);
+ expbuf[MAX_EXPCT-1] = chr & 0x7f;
+ }
+ }
+
+ /* for each entry in the current state... */
+
+ for (curscr = curstate->next;
+ (curscr != (struct script *)NULL) &&
+ (curscr->opcode != SC_LABEL);
+ curscr = curscr->next)
+ {
+
+ switch (curscr->opcode)
+ {
+ case SC_TIMO:
+ sc_secs = curscr->intprm;
+ if (sc_secs == 0)
+ sc_secs = sc_dtmo;
+ sc_secs /= 1000;
+ if (time(NULL)-sc_begwait > sc_secs)
+ {
+ DEBUG(DB_LGI,
+ "\nTimed out (%d secs)\n", sc_secs);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_CARR:
+ if (ttcd())
+ {
+ DEBUG(DB_LGI, "\nGot carrier\n", 0);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_HUPS:
+ if (fShangup)
+ {
+ DEBUG(DB_LGI, "\nGot data set hangup\n", 0);
+ goto _chgstate;
+ }
+ break;
+
+ case SC_XPCT:
+ if ((expin >= curscr->intprm) &&
+ (strncmp(curscr->strprm,
+ &expbuf[expin - curscr->intprm],
+ curscr->intprm) == SAME))
+ {
+ charlog(curscr->strprm, curscr->intprm,
+ DB_LGI, "Matched");
+ goto _chgstate;
+ }
+ break;
+
+ }
+ }
+ }
+}
+ /* New opcode added by hag@eddie.mit.edu for expecting a
+ parameter supplied string */
+ case SC_XPST:
+ if(curscr->intprm >paramc-1)
+ {
+ sprintf(tempstr,"expectstr - param#%d",curscr->intprm);
+ logit(tempstr, " not present");
+ return(FAIL);
+ }
+ prmlen=xlat_str(tempstr,paramv[curscr->intprm]);
+ if((expin >= prmlen) &&
+ (strncmp(tempstr,&expbuf[expin-prmlen],
+ prmlen) == SAME))
+ {
+ charlog(tempstr,prmlen,DB_LGI, "Matched");
+ goto _chgstate;
+ }
+ break;
+/*
+ * SIGNAL HANDLERS
+ */
+
+/*
+ * usignal - generic signal catcher
+ */
+static int usignal(isig)
+ int isig;
+{
+ DEBUG(DB_LOG, "Caught signal %d. Exiting...\n", isig);
+ restore_tty();
+ exit(FAIL);
+}
+
+/*
+ * uhup - HUP catcher
+ */
+static int uhup(isig)
+ int isig;
+{
+ DEBUG(DB_LOG, "Data set hangup.\n");
+ fShangup = TRUE;
+}
+
+/*
+ * TERMINAL I/O ROUTINES
+ */
+
+/*
+ * xgetc - get a character with timeout
+ *
+ * Assumes that stdin is opened on a terminal or TCP socket
+ * with O_NONBLOCK.
+ */
+static char xgetc(tmo)
+int tmo; /* Timeout, seconds */
+{
+ char c;
+ struct timeval s;
+ int f = 1; /* Select on stdin */
+ int result;
+
+ if(read(0, &c, 1) <= 0) /* If no data available */
+ {
+ s.tv_sec = (long)tmo;
+ s.tv_usec = 0L;
+ if(select (1, &f, (int *) NULL, &f, &s) == 1)
+ read(0, &c, 1);
+ else
+ c = '\377';
+ }
+
+ return(c);
+}
+
+/*
+ * Pause for an interval in milliseconds
+ */
+void msleep(msec)
+long msec;
+{
+
+#if HAVE_USLEEP
+ if(msec == 0) /* Skip all of this if delay = 0 */
+ return;
+ usleep (msec * (long)1000);
+#endif /* HAVE_USLEEP */
+
+#if HAVE_NAPMS
+ if(msec == 0) /* Skip all of this if delay = 0 */
+ return;
+ napms (msec);
+#endif /* HAVE_NAPMS */
+
+#if HAVE_NAP
+ if(msec == 0) /* Skip all of this if delay = 0 */
+ return;
+ nap (msec);
+#endif /* HAVE_NAP */
+
+#if HAVE_POLL
+ struct pollfd sdummy;
+
+ if(msec == 0)
+ return;
+ /*
+ * We need to pass an unused pollfd structure because poll checks
+ * the address before checking the number of elements.
+ */
+ poll (&sdummy, 0, msec);
+#endif /* HAVE_POLL */
+
+#if USE_SELECT_TIMER
+ struct timeval s;
+
+ if(msec == 0)
+ return;
+ s.tv_sec = msec / 1000L;
+ s.tv_usec = (msec % 1000L) * 1000L;
+ select (0, (int *) NULL, (int *) NULL, (int *) NULL, &s);
+#endif /* USE_SELECT_TIMER */
+
+#if ! HAVE_NAPMS && ! HAVE_NAP && ! HAVE_USLEEP && \
+ ! HAVE_POLL && ! USE_SELECT_TIMER
+ if(msec == 0)
+ return;
+ sleep (1); /* Sleep for a whole second (UGH!) */
+#endif /* HAVE_ and USE_ nothing */
+}
+
+/*
+ * Debugging output
+ */
+static void DEBUG(level, msg1, msg2)
+int level;
+char *msg1, *msg2;
+{
+ if ((dbf != NULL) && DEBUG_LEVEL(level))
+ fprintf(dbf, msg1, msg2);
+}
+
+/*
+ * charlog - log a string of characters
+ *
+ * SPECIAL CASE: msg=NULL, len=1 and msg[0]='\377' gets logged
+ * when read does its 1 sec. timeout. Log "<1 sec.>"
+ * so user can see elapsed time
+ */
+static void charlog(buf, len, mask, msg)
+char *buf;
+int len, mask;
+char *msg;
+{
+ char tbuf[256];
+
+ if (DEBUG_LEVEL(mask) && dbf != NULL)
+ {
+ if(msg == (char *)NULL)
+ msg = "";
+ strncpy(tbuf, buf, len);
+ tbuf[len] = '\0';
+ if(len == 1 && tbuf[0] == '\377')
+ strcpy(tbuf, "<1 sec.>");
+ fprintf(dbf, "%s %s\n", msg, tbuf);
+ }
+}
+
+/*
+ * setup_tty()
+ *
+ * Save current tty settings, then set up raw, single
+ * character input processing, with 7-bit stripping.
+ */
+static void setup_tty()
+{
+ register int i;
+
+ ioctl(0, TCGETA, &old);
+
+ new = old;
+
+ for(i = 0; i < 7; i++)
+ new.c_cc[i] = '\0';
+ new.c_cc[VMIN] = 0; /* MIN = 0, use requested count */
+ new.c_cc[VTIME] = 10; /* TIME = 1 sec. */
+ new.c_iflag = ISTRIP; /* Raw mode, 7-bit stripping */
+ new.c_lflag = 0; /* No special line discipline */
+
+ ioctl(0, TCSETA, &new);
+}
+
+/*
+ * restore_tty() - restore signal handlers and tty modes on exit.
+ */
+static void restore_tty(sig)
+int sig;
+{
+ ioctl(0, TCSETA, &old);
+ return;
+}
+
+/*
+ * ttoslow() - Send characters with pacing delays
+ */
+static void ttoslow(s, len, delay)
+ char *s;
+ int len;
+ time_t delay;
+{
+ int i;
+
+ if (len == 0)
+ len = strlen(s);
+
+ charlog (s, len, DB_LGI, "Sending slowly");
+
+ for (i = 0; i < len; i++, s++)
+ {
+ write(1, s, 1);
+ msleep(delay);
+ }
+}
+
+/*
+ * ttflui - flush input buffer
+ */
+static void ttflui()
+{
+ if(isatty(0))
+ (void) ioctl ( 0, TCFLSH, 0);
+}
+
+/*
+ * ttcd - Test if carrier is present
+ *
+ * NOT IMPLEMENTED. I don't know how!!!
+ */
+static int ttcd()
+{
+ return TRUE;
+}
+
+/*
+ * tthang - Force DTR low for 1-2 sec.
+ */
+static void tthang()
+{
+ if(!isatty())
+ return;
+
+#ifdef TCCLRDTR
+ (void) ioctl (1, TCCLRDTR, 0);
+ sleep (2);
+ (void) ioctl (1, TCSETDTR, 0);
+#endif
+
+ return;
+}
+
+/*
+ * ttbreak - Send a "break" on the line
+ */
+static void ttbreak()
+{
+ (void) ioctl (1, TCSBRK, 0);
+}
+
+/*
+ * ttblind - return TRUE if tty is "blind"
+ *
+ * NOT IMPLEMENTED - Don't know how!!!
+ */
+static int ttblind()
+{
+ return FALSE;
+}
+
+/*
+ * tt7bit - enable/disable 7-bit stripping on line
+ */
+static void tt7bit(enable)
+ int enable;
+{
+ if(enable)
+ new.c_iflag |= ISTRIP;
+ else
+ new.c_iflag &= ~ISTRIP;
+
+ ioctl(0, TCSETA, &new);
+}
+
+/*
+ * ttpar - Set parity mode on line. Ignore parity errors on input.
+ */
+static void ttpar(mode)
+ int mode;
+{
+ switch(mode)
+ {
+ case NONE:
+ new.c_iflag &= ~(INPCK | IGNPAR);
+ new.c_cflag &= ~(CSIZE | PARENB | PARODD);
+ new.c_cflag |= CS8;
+ break;
+
+ case EVEN:
+ new.c_iflag |= (INPCK | IGNPAR);
+ new.c_cflag &= ~(CSIZE | PARODD);
+ new.c_cflag |= (CS7 | PARENB);
+
+ break;
+
+ case ODD:
+ new.c_iflag |= (INPCK | IGNPAR);
+ new.c_cflag &= ~(CSIZE);
+ new.c_cflag |= (CS7 | PARENB | PARODD);
+ break;
+ }
+
+ ioctl(0, TCSETA, &new);
+}
+
+
+
+
+
+
+
diff --git a/gnu/libexec/uucp/contrib/xchat.man b/gnu/libexec/uucp/contrib/xchat.man
new file mode 100644
index 00000000000..55537be9072
--- /dev/null
+++ b/gnu/libexec/uucp/contrib/xchat.man
@@ -0,0 +1,628 @@
+.TH xchat 8
+.SH NAME
+xchat - Extended chat processor
+.SH SYNOPSIS
+.BI "xchat " "scriptfile"
+.RI " [ " parameter... " ] "
+.PP
+where
+.I scriptfile
+is the name of a file containing an
+.I xchat
+script. If
+.I scriptfile
+begins with ``/'', then it is assumed to be a full path name for the
+script file. If not, a configuration-dependent default directory path
+(usually
+.B "/usr/local/conf/uucp/"
+) is prepended to the script file name. Normally, the default path
+is the same as that for the Taylor UUCP configuration files.
+.SH DESCRIPTION
+.I Xchat
+is a general-purpose dialing and login program designed for use
+with Taylor UUCP as a ``chat-program'', taking the place (or
+augmenting) the built-in chat scripting facility. It provides the
+ability to closely control timeouts, multiple simultaneous ``expect''
+strings with separate actions, extended terminal control, modem
+command character pacing, and more.
+.PP
+When used in conjunction with Taylor UUCP's
+configuration features,
+.I xchat
+can provide you the ability to manage the most intricate login,
+dial and hangup needs. The scripts are written in a shell-like (well,
+sort-of) style with labels, commands, and parameters, easing the task
+of writing procedures for complex terminal communications situations.
+.PP
+Because
+.I xchat
+assumes that it is connected to the terminal device via stdin/stdout,
+you can easily debug scripts by invoking it from the shell and
+responding to the script from the keyboard. A debug logging facility
+is included, with the debug output going to a separate user-specified
+file. This makes it easy to debug connection problems without wading
+through large
+.I uucico
+log and debug files.
+.PP
+Formally, a script describes a state machine;
+.I xchat
+interprets the script and does what the state machine
+tells it to. This section will be much easier to understand
+if you obtain listings of the script files supplied with
+.I xchat.
+.SH "SCRIPT FILE FORMAT"
+Script files are ordinary text files containing comments, labels,
+and statements. Blank lines are ignored.
+Comments are denoted by leading ``#''
+characters. Some statements (those which do not end with an
+``extended string'' argument; see below) can also have trailing
+comments.
+.PP
+.I Labels
+begin in column one and are ended by colons (:). A label
+specifies a state name. All lines between a pair of labels are
+the statements for a single state.
+.PP
+Processing always begins at the head of the script (no leading
+state name is necessary).
+.PP
+.I Statements
+are divided into two categories, ``action'' and ``expect''.
+When a state is entered, all of its actions are performed in the
+order in which they appear in the file.
+.PP
+A
+.I transition
+to another state may occur for any of three reasons:
+.IP (1) 5
+One of the actions may cause a transition to
+another state, in which case the rest of the
+current state's actions are skipped.
+Processing resumes with the first action
+statement of the new state.
+.IP (2) 5
+If none of the actions cause a state
+transition, and there are no expects in the
+state, processing ``falls through'' to the next
+state in the file.
+.IP (3) 5
+If none of the actions cause a state
+transition, but there are expects in the
+state, the state machine pauses until one of
+the expects is ``satisfied''. It then transitions
+to the state named in the expect
+statement.
+.PP
+Finally, there are two action statements which, when executed,
+cause the script to exit.
+.SH "SCRIPT FILE STATEMENTS"
+This section describes all of the statements that may appear in script
+files, except for a few special action statements. Those are described
+in a later section, ``Overriding Defaults''.
+.PP
+Some statements accept one or two arguments, referred to in the
+following descriptions as
+.IR int ", " ns ", " str ", or "
+.IR xstr ", to"
+indicate whether the argument is an integer, a new state name, a
+string, or an ``extended string'' (described in a later section).
+.PP
+For all statements that accept two arguments, the first is the
+name of a new state, and the second specifies a condition or
+reason for changing to the new state.
+.SS "Termination And Informational Statements"
+These statements are used to place entries into the Taylor UUCP
+.I Log
+file, and to cause
+.I xchat
+to exit with successful or failure status. It is also possible to open a
+separate
+.I debug
+log file and control the level of tracing and error reporting that will go
+into that log file. This is very useful in debugging
+.I xchat
+scripts.
+.br
+.ta 1.0i 1.5i 2.0i
+.TP 2.0i
+.B failed
+Exit script with ``failed'' status. This causes
+.I xchat
+to exit with status 0.
+.TP 2.0i
+.B success
+Exit script with ``success'' status. This causes
+.I xchat
+to exit with status 1.
+.TP 2.0i
+.BI "log " xstr
+Send informational message
+.I xstr
+to standard error. When used with Taylor UUCP, this is the
+.I Log
+file for the
+.I uucico
+program.
+.TP 2.0i
+.BI "logerr " xstr
+Send message
+.I xstr
+to standard error, with ``ERROR:'' indicator. When used
+with Taylor UUCP, this is the
+.I Log
+file for the
+.I uucico
+program.
+.TP 2.0i
+.BI "dbgfile " xstr
+Open script debugging file
+.I xstr.
+If
+.I xstr
+begins with ``/'', it is assumed to be an absolute path name for the
+debugging file. If not, then a configuration-dependent default directory
+path (usually
+.B "/usr/spool/uucp"
+) is prepended to
+.I xstr.
+Normally the default path is that of the directory where Taylor UUCP
+puts its log files.
+The debugging file is used to capture a detailed log of the data sent
+and received, errors encountered, and a trace of script execution.
+The various types of logging are controlled by the
+.I "debug mask,"
+described next.
+.B Note:
+A new log file is created each time
+.I xchat
+runs. Use the
+.B log
+and
+.B loge
+commands to log
+continuous information onto standard out, which is connected
+to the Taylor UUCP
+.I Log
+file when
+.I xchat
+is run by the Taylor
+.I uucico.
+.TP 2.0i
+.BI "dbgset " int
+Set the bits specified in
+.I int
+in the debugging mask. The value in
+.I int
+is ``or''ed into the mask. Set bit 0 (value \= 1) for error messages,
+bit 1 (value \= 2) for dial, login and init errors, bit 2 (value \= 4)
+for dial, login and init trace with character I/O, and bit 3 (value \= 8)
+for script processing internals. Normally, you will just turn it all on
+with a value of 15.
+.TP 2.0i
+.BI "dbgclr " int
+Clear the bits specified in
+.I int
+from the debugging mask.
+.TP 2.0i
+.BI "debug " xstr
+Write
+.I
+xstr
+into the debug log. The entry will be enclosed in angle brackets.
+.TP 2.0i
+.BI "debuge " xstr
+Write
+.I xstr
+into the debug log with ``ERROR: '' prepended. The entry will be enclosed
+in angle brackets.
+.SS "Sending Data"
+These statements are used to transmit data to standard out (the tty or TCP
+port when used with Taylor UUCP).
+.I
+No implied carriage returns are sent.
+You must include a \\r if you want a carriage return in the string
+sent by the
+.B send
+command. If you want a return sent after
+.B dial
+or
+.B sendstr,
+you must send it with a separate
+.B send
+command.
+.TP 2.0i
+.B dial
+Send the string previously set by the
+.B telno
+command to the serial port.
+.B W
+and
+.B P
+characters in the phone number are
+converted as described under
+.B
+Dial Strings,
+below. This statement also sets a default
+timeout value, as described under the
+.B timeout
+statement.
+.TP 2.0i
+.BI "send " xstr
+Send the string
+.I xstr
+to the serial port.
+.TP 2.0i
+.BI "sendstr " int
+The argument of this statement is a digit from 0
+through 7. Send the corresponding string
+parameter as passed to
+.I xchat
+following the script file name. The parameter is interpreted
+as an extended string.
+.SS "Special Terminal Control Statements"
+These statements are used to cause the terminal port to perform some special action, or to change the mode of the port.
+.I
+The modes of the port are restored to their original settings
+.I
+by xchat before it exits.
+.TP 2.0i
+.B flush
+Flush the terminal port's input buffer.
+.TP 2.0i
+.B break
+Send a break signal.
+.TP 2.0i
+.B hangup
+Momentarily drop Data Terminal Ready (DTR) on the
+serial port, causing the modem to hang up. (Not
+usually needed, since
+.I uucico
+does this at the end of each call.)
+.TP 2.0i
+.B 7bit
+Change the port to strip incoming characters to 7 bits.
+.I
+This is the default mode.
+This mode
+is implied when the port has parity enabled, since parity characters
+are 7-bits wide.
+.TP 2.0i
+.B 8bit
+Change the port to allow incoming 8-bit characters to be passed
+to the script processor. This mode has no effect if parity is
+enabled, since parity characters are 7-bits wide.
+.TP 2.0i
+.B nopar
+Change the port to 8-bits, no parity.
+.I
+This is the default mode.
+.TP 2.0i
+.B evenpar
+Change the port to 7-bits, even parity.
+.I
+Incoming characters with parity errors are discarded.
+.TP 2.0i
+.B oddpar
+Change the port to 7-bits, odd parity.
+.I
+Incoming characters with parity errors are discarded.
+.SS "Counting, Branching, Timing and Testing Statements"
+These statements are used to control the flow of the
+.I xchat
+script itself, including branching, delays, and counter manipulation.
+.TP 2.0i
+.BI "sleep " int
+Delay for
+.I int
+milliseconds.
+.TP 2.0i
+.B zero
+Clear the counter.
+.TP 2.0i
+.B count
+Add one to the counter.
+.TP 2.0i
+.BI "ifgtr " "ns int"
+Go to state
+.I ns
+if counter greater than
+.I int.
+.TP 2.0i
+.BI "goto " ns
+Go to state
+.I ns
+unconditionally.
+.TP 2.0i
+.BI "ifstr " "ns int"
+Go to state
+.I ns
+if string parameter
+.I int
+is nonempty.
+.TP 2.0i
+.BI "ifnstr " "ns int"
+Go to state
+.I ns
+if string parameter
+.I int
+is empty.
+.TP 2.0i
+.BI "ifblind " ns
+Change to state
+.I ns
+if the port is ``blind'' without carrier (CD) asserted.
+.I
+This is not yet implemented, the test always fails.
+.TP 2.0i
+.BI "ifblgtr " "ns int"
+Change to state
+.I ns
+if the port is ``blind'' without carrier (CD) asserted, and counter
+is greater then
+.I int.
+.I
+This is not yet implemented, the test always fails.
+.SS "Expect Statements"
+Expect statements are usually the last statements that appear in a
+given state, though in fact they can appear anywhere within the
+state. Even if they appear at the beginning, the script processor
+always does all of the action statements first. As a practical
+matter, the order of these statements is not significant; they are
+all interpreted ``in parallel''.
+.TP 2.0i
+.BI "expect " "ns xstr"
+Change to state
+.I ns
+if the string specified by
+.I xstr
+is received from standard input (usually the serial port).
+Case is significant, but high-order bits are not
+checked.
+.TP 2.0i
+.BI "expectstr " "ns int"
+Change to state
+.I ns
+if the string specified in parameter
+.I int
+is received from standard input (usually the serial port).
+.I int
+must be in the range 0 to 7.
+Case is significant, but high-order bits are not
+checked.
+Useful where a prompt can change in different dial-in lines.
+.TP 2.0i
+.BI "ifcarr " ns
+Change to state
+.I ns
+if Carrier Detect (CD) is true.
+.I
+Not currently implemented. Always changes state.
+.TP 2.0i
+.BI "ifhang " ns
+Change to state
+.I ns
+if a data set hangup occurs (SIGHUP signal received).
+.TP 2.0i
+.BI "timeout " "ns int"
+Change to state
+.I ns
+if the time (in milliseconds)
+given by
+.I int
+has elapsed without satisfying any
+expects. If the time specified is 0, a default
+timeout value (calculated from the length and
+other characteristics of the most recent dial
+string) is used.
+.SH "SCRIPT PROCESSING DETAILS"
+.SS "Extended Strings"
+In the statements that accept string arguments, the strings are
+interpreted as
+.I
+extended strings.
+Extended strings begin with
+the first nonblank character and continue, including all imbedded
+and trailing blanks and other whitespace, until (but not
+including) the end of the line in the script file. (There is no
+provision for line continuation.) No trailing spaces should be
+present between the last ``desired'' character of the string and the
+end of the line, as they will be included in the stored string and
+sent or expected, just as they appear in the script file. And,
+obviously, no trailing comments are permitted! They will just be
+stored as part of the string.
+.PP
+Within an extended string, the following ``escape sequences'' will
+be converted as indicated before being sent or expected:
+.br
+.nf
+.in +0.5i
+\fB\\d\fR EOT character (control-D)
+\fB\\N\fR null character
+\fB\\n\fR line feed
+\fB\\r\fR carriage return
+\fB\\s\fR space
+\fB\\t\fR tab
+\fB\\\-\fR hyphen
+\fB\\\\\fR backslash
+\fB\\ooo\fR character with value ooo (in octal)
+.in -0.5i
+.fi
+.PP
+Since extended strings in scripts can include embedded spaces,
+tabs, etc., these escape sequences are only required in strings
+appearing in systems entries, though they may be used in script
+files to improve readability.
+.PP
+The octal-character specification (\\ooo) may have from one to
+three octal digits; it is terminated either after the third digit
+or when a non-octal character is encountered. But if you want to
+specify one of these followed by something that happens to be a
+valid octal character (for example, a control-A followed by a 7)
+make sure to include all three digits after the \\ . So \\0017
+would become a control-A followed by the Ascii character ``7'', but
+\\17 or \\017 would become a control-Y (decimal value 25). \\1S
+would convert to a control-A followed by an ``S''.
+.PP
+Extended strings are stored without a trailing carriage return
+unless one is explicitly present in the string (via \\r).
+.SS "String Parameters"
+The
+.B sendstr
+statement sends (after conversion from extended string
+format) one of the parameters given on the
+.I xchat
+command line following the script file name.
+The parameter is selected by the integer
+argument of the statement.
+.PP
+This allows ``generic'' script files to serve
+for many different systems; the string parameters
+provide the phone number, username, password, etc. Character
+substitutions described under ``extended strings'' above are
+performed on these strings.
+.PP
+The ifstr and ifnstr statements allow further generality in script
+files, by testing whether a particular parameter is present in the
+systems entry. For example, a single script can be
+used both for those systems that require a password and
+those that do not. The password is specified as the last argument
+in the
+.xchat
+command; the script can test for this
+parameter's existence and skip the password sequence if
+the parameter is empty.
+.SS "``Wait'' And ``Pause'' Characters In Dial Strings"
+An additional conversion is performed on dial strings. Dial strings
+are interpreted as extended strings. Then the characters
+.B W
+and
+.B P
+within a dial string are interpreted as ``wait for dial
+tone'' and ``pause'', and may be converted to other characters. By
+default,
+.B W
+is left alone, and
+.B P
+is converted to a comma (,);
+these are appropriate for Hayes-type modems. The script may
+specify other substitutions (see below).
+.PP
+.B NOTE:
+The Taylor UUCP documentation states that the ``wait'' and ``pause''
+characters are ``='' and ``-'', respectively. These are actual characters
+understood by some modems. When using
+.I xchat
+you should put
+.B W
+and
+.B P
+in the dial strings you specify in the Taylor configuration files.
+This way, the
+.I xchat
+processor can make the substitution appropriate for the particular
+modem in use. Make a separate
+.I xchat
+script for each modem type, e.g.,
+.I "dial.hayes"
+and specify the translation there. This way, the phone number strings
+in the Taylor configuration files can be used with a variety of modems.
+.SS "Default Timeouts For Dial Strings"
+When a
+.B dial
+statement is executed, a default timeout value is set.
+This is the timeout value used by a subsequent timeout statement
+if the statement specifies a timeout value of 0.
+.PP
+The default timeout is given by:
+.br
+.nf
+.in +2
+\fIctime\fR + (\fIndigits\fR * \fIdgttime\fR) + (\fInwchar\fR * \fIwtime\fR) + (\fInpchar\fR * \fI ptime\fR)
+.in -2
+.fi
+.PP
+where
+.I
+ndigits, nwchar,
+and
+.I npchar
+are the number of digits, wait characters, and pause characters in
+the dial string, and
+.I ctime, dgttime, wtime,
+and
+.I ptime
+are 45 seconds, 0.1 seconds, 10 seconds, and 2 seconds,
+respectively.
+All of these times may be changed as specified below under
+``Overriding Defaults.''
+.SS "Trailing Carriage Returns Not Assumed"
+In the
+.B dial
+and
+.B sendstr
+statements, the dial string or
+parameter is sent with no trailing carriage return;
+if a carriage return must be sent after one of these, a separate
+send statement must provide it.
+.SH "OVERRIDING DEFAULTS"
+The script processor sets several default values. The following
+statements, which override these defaults, may be useful in
+certain circumstances.
+.TP 2.0i
+.BI "chrdly " int
+Since many modems cannot accept dialing commands
+at full ``computer speed'', the script processor
+sends all strings with a brief inter-character
+delay. This statement specifies the delay time,
+in milliseconds. The default is 100 (0.1 second).
+.TP 2.0i
+.BI "pchar " str
+Specifies the character to which
+.BR P s
+in the
+dial string should be converted. Default is
+``,'', for use with Hayes-type modems.
+.TP 2.0i
+.BI "ptime " int
+Specifies the time, in milliseconds, to allow in
+the default timeout for each pause character in
+the dial string. Default is 2000 (2 seconds).
+.TP 2.0i
+.BI "wchar " str
+Specifies the character to which
+.BR W s
+in the
+dial string should be converted. Default is
+``W'', for Hayes modems.
+.TP 2.0i
+.BI "wtime " int
+Specifies the time, in milliseconds, to allow in
+the default timeout for each wait-for-dialtone
+character in the dial string. Default is 10000
+(10 seconds).
+.TP 2.0i
+.BI "dgttime " int
+Specifies the time, in milliseconds, to allow in
+the default timeout for each digit character in
+the dial string. Default is 100 (0.1 second).
+.TP 2.0i
+.BI "ctime " int
+Specifies the time, in milliseconds, to allow in
+the default timeout for carrier to appear after
+the dial string is sent. Default is 45000 (45
+seconds).
+.SH "SEE ALSO"
+uucico(8) for Taylor UUCP, and documentation for Taylor UUCP.
+.SH AUTHOR
+Robert B. Denny (denny@alisa.com)
+.SH CONTRIBUTORS
+Daniel Hagerty (hag@eddie.mit.edu)
+.SH HISTORY
+This program is an adaptation of the dial/login script processing
+code that is a part of DECUS UUCP for VAX/VMS, written by Jamie
+Hanrahan, et. al.
+.SH BUGS
+This version (1.1) does not support BSD terminal facilities. Anyone
+volunteer to add this?
+