diff options
author | J.T. Conklin <jtc@FreeBSD.org> | 1993-08-05 18:28:27 +0000 |
---|---|---|
committer | J.T. Conklin <jtc@FreeBSD.org> | 1993-08-05 18:28:27 +0000 |
commit | a5ebd84e62c76a7ed0d157016ca3745583181a8e (patch) | |
tree | 64cb2831b24d3f5002a9a9ec1426e82c6d6bb5d4 /gnu/libexec/uucp/contrib | |
parent | 4ff3cd9d3ddeda602fd8b7717b2a6e4445852c69 (diff) | |
download | src-a5ebd84e62c76a7ed0d157016ca3745583181a8e.tar.gz src-a5ebd84e62c76a7ed0d157016ca3745583181a8e.zip |
Taylor UUCP 1.04
Notes
Notes:
svn path=/head/; revision=242
Diffstat (limited to 'gnu/libexec/uucp/contrib')
25 files changed, 5038 insertions, 0 deletions
diff --git a/gnu/libexec/uucp/contrib/Dial.Hayes b/gnu/libexec/uucp/contrib/Dial.Hayes new file mode 100644 index 000000000000..32eef82d347b --- /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 000000000000..c111c00fcaef --- /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 000000000000..d557f97e2195 --- /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 000000000000..d8c3a6643a66 --- /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 000000000000..d6196cb2aa64 --- /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 000000000000..235fcca889f8 --- /dev/null +++ b/gnu/libexec/uucp/contrib/Makefile.uurt @@ -0,0 +1,30 @@ +# +# Makefile for uurate 1.0 +# + +# Where uurate is installed +BIN=/usr/local/bin + +# Flags to use when compiling uurate +CFLAGS=-I.. + +CC=cc +SHELL=/bin/sh +PROGS=uurate + +#----------- + +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/Makefile.xchat b/gnu/libexec/uucp/contrib/Makefile.xchat new file mode 100644 index 000000000000..5e9aaa8ffedb --- /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 000000000000..c4105ed03868 --- /dev/null +++ b/gnu/libexec/uucp/contrib/README @@ -0,0 +1,46 @@ +This is the README file for the Taylor UUCP contrib directory. + +This directory contains contributed shell scripts and programs that +you may find useful. + +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. + +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. + +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: + A perl script 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. + +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 000000000000..2cc361ce26fb --- /dev/null +++ b/gnu/libexec/uucp/contrib/README-UURATE @@ -0,0 +1,20 @@ +uurate V1.2 - Gather and display Taylor UUCP traffic statistics + +Bob Denny (denny@alisa.com) - Thu Sep 3 19:47:41 1992 + +See the man page for documentation. + +Installation: +------------ + +(1) Copy Makefile.uurt to Makefile. + +(2) Edit Makefile: set BIN where you want uurate to be installed, and + set CFLAGS to point to the directory containing the UUCP sources + (this is .. by default). + +(3) Type ``make'' to compile the program. + +(4) Type ``make install'' to install the program. + +(5) Install the man page if you want. I didn't put that into the Makefile. diff --git a/gnu/libexec/uucp/contrib/README-XCHAT b/gnu/libexec/uucp/contrib/README-XCHAT new file mode 100644 index 000000000000..5f93a284bda6 --- /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/savelog.man b/gnu/libexec/uucp/contrib/savelog.man new file mode 100644 index 000000000000..919b94f4ec11 --- /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 100755 index 000000000000..64c989f292b2 --- /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 100755 index 000000000000..ac1d0f556ee9 --- /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 000000000000..dd82633c7a0f --- /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 000000000000..e9c631c86c3e --- /dev/null +++ b/gnu/libexec/uucp/contrib/uuclean @@ -0,0 +1,23 @@ +# 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 \{\} \; diff --git a/gnu/libexec/uucp/contrib/uuq.sh b/gnu/libexec/uucp/contrib/uuq.sh new file mode 100755 index 000000000000..a5d88e952230 --- /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 000000000000..ceab41c53bfd --- /dev/null +++ b/gnu/libexec/uucp/contrib/uurate.c @@ -0,0 +1,657 @@ +/* + * @(#)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. + */ + +char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2"; + +#include <ctype.h> /* Character Classification */ +#include <string.h> +#include <math.h> + +#include "uucp.h" + + +#define _DEBUG_ 0 + +/* + * Direction of Calling and Data Transmission + */ +#define IN 0 /* Inbound */ +#define OUT 1 /* Outbound */ + +/* + * 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 Host_entry + { + struct Host_entry *next; + char Hostname[32]; + struct Execution_Command *cmds; /* Local Activities */ + struct Phone_Call call[2]; /* In & Out Activities */ + }; + +/* + * Stuff for getopt() + */ +extern int optind; /* GETOPT : Option Index */ +extern char *optarg; /* GETOPT : Option Value */ +extern void *calloc(); + +static void fmtime(); +static void fmbytes(); + +/* + * Default files to read. Taken from Taylor compile-time configuration. + * Must look like an argvec, hence the dummy argv[0]. + */ +static char *(def_logs[3]) = { "", LOGFILE, STATFILE }; + +/* + * Misc. strings for reports + */ +static char *(file_hdr[2]) = { "\nReceived file statistics:\n", + "\nSent file statistics\n" }; + +/* + * BEGIN EXECUTION + */ +main(argc, argv) +int argc; +char *argv[]; +{ + char c; + char *p, *s; + struct Host_entry *hosts = NULL; + struct Host_entry *cur = NULL; + struct Host_entry *e; + struct Execution_Command *cmd; + struct Execution_Command *ec; + char Hostname[64]; + FILE *Log = NULL; + char logline[1024]; + char *logmsg; + int sent; + int called; + int show_files = 0; /* I prefer boolean, but... */ + int show_calls = 0; + int show_commands = 0; + int show_efficiency = 0; + int show_summary = 0; + int have_files = 0; + int have_calls = 0; + int have_commands = 0; + int use_stdin = 0; + Hostname[0] = '\0'; + + /* + * I wish the compiler had the #error directive! + */ +#if !HAVE_TAYLOR_LOGGING + fprintf(stderr, "uurate cannot be used with your configuration of\n"); + fprintf(stderr, "Taylor UUCP. To use uurate you must be using the\n"); + fprintf(stderr, "TAYLOR_LOGGING configuration.\n"); + exit(1); +#endif + + /* + * Process the command line arguments + */ + while((c = getopt(argc, argv, "h:cfexai")) != EOF) + { + switch(c) + { + case 'h': + strcpy(Hostname, optarg); + break; + case 'c': + show_calls = 1; + break; + case 'f': + show_files = 1; + break; + case 'x': + show_commands = 1; + break; + case 'e': + show_efficiency = 1; + break; + case 'a': + show_calls = show_files = show_commands = show_efficiency = 1; + break; + case 'i': + use_stdin = 1; + break; + default : + goto usage; + } + } + + /* + * If no report switches given, show summary report. + */ + if (show_calls == 0 && show_files == 0 + && show_efficiency == 0 && show_commands == 0) + show_summary = 1; + + /* + * 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, + * otherwise, 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(argc == 1) /* No file arguments */ + { + if (use_stdin) /* If -i, read from stdin */ + { + argc = 2; + Log = stdin; + } + else /* Read from current logs */ + { + argc = 3; /* Bash argvec to default log/stat files */ + argv = &def_logs[0]; + } + } + else if (use_stdin) /* File args with -i is an error */ + { + fprintf(stderr, "uurate (error): file args given with '-i'\n"); + goto usage; + } + +#if _DEBUG_ + printf("\n"); +#endif + + /* + * MAIN LOGFILE PROCESSING LOOP + */ + while (argc > 1) + { + + if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL) + { + perror(argv[1]); + return; + } + +#if _DEBUG_ + printf("Reading %s...\n", (use_stdin ? "stdin" : argv[1])); +#endif + + /* + * 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. + */ + if (NULL == (p = strchr(logline, ' '))) + continue; + ++p; + if (NULL != (s = strchr(p, ' '))) + *s = '\0'; + for (s = p; *s; ++s) + if (isupper(*s)) + *s = tolower(*s); + /* + * Skip this line if we got -h <host> and + * this line does not contain that host name. + */ + if (Hostname[0] != '\0') + if (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; + logmsg = s + 2; /* Message is 2 characters after ')' */ + if (0 == strncmp(logmsg, "sent", 4)) + sent = OUT; + else + if (0 == strncmp(logmsg, "received", 8)) + sent = IN; + else + if ((0 != strncmp(logmsg, "Call complete", 13)) && + (0 != strncmp(logmsg, "Calling system", 14)) && + (0 != strncmp(logmsg, "Incoming call", 13)) && + (0 != strncmp(logmsg, "Executing", 9))) + 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))) + { + for (cur = hosts; cur != NULL ; cur = cur->next) + if (0 == strcmp(cur->Hostname, p)) + break; + if (cur == NULL) + { + cur = (struct Host_entry *)calloc(1, sizeof(*hosts)); + strcpy(cur->Hostname, p); + if (hosts == NULL) + hosts = cur; + else + { + for (e = hosts; e->next != NULL; e = e->next); + e->next = cur; + } + } + } + /* + * 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. + */ + if (0 == strncmp(logmsg, "Executing", 9)) + { + if (NULL == (p = strchr(logmsg, '('))) + continue; + if ((s = strpbrk(++p, " )")) == NULL) + continue; + *s = '\0'; + for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next) + if (0 == strcmp(cmd->Commandname, p)) + break; + if (cmd == NULL) + { + cmd = (struct Execution_Command *)calloc(1, sizeof(*cmd)); + strcpy(cmd->Commandname, p); + if (cur->cmds == NULL) + cur->cmds = cmd; + else + { + for (ec = cur->cmds; ec->next != NULL; ec = ec->next); + ec->next = cmd; + } + } + ++cmd->count; + have_commands = 1; + continue; + } + /* + * Count start of outgoing call. + */ + if (0 == strncmp(logmsg, "Calling system", 14)) + { + called = OUT; + cur->call[called].calls += 1; + have_calls = 1; + continue; + } + /* + * Count start of incoming call. + */ + if (0 == strncmp(logmsg, "Incoming call", 13)) + { + called = IN; + cur->call[called].calls += 1; + have_calls = 1; + continue; + } + /* + * Handle end of call. Pick up the connect time. + */ + if (0 == strncmp(logmsg, "Call complete", 13)) + { + cur->call[called].succs += 1; + if (NULL == (s = strchr(logmsg, '('))) + continue; + cur->call[called].connect_time += atof(s+1); + continue; + } + /* + * 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. + */ + have_files = 1; + cur->call[called].flow[sent].files += 1; + if (NULL == (s = strchr(logmsg, ' '))) + continue; + cur->call[called].flow[sent].bytes += atol(++s); + if (NULL == (s = strchr(s, ' '))) + continue; + if (NULL == (s = strpbrk(s, "0123456789"))) + continue; + cur->call[called].flow[sent].time += atof(s); + } + argc -= 1; + argv += 1; + if(Log != stdin) + fclose(Log); + } + + /* + * *********** + * * REPORTS * + * *********** + */ + + /* + * Truncate the Hostnames to 8 characters at most. + */ + for (cur = hosts; cur != NULL; cur = cur->next) + cur->Hostname[8] = '\0'; + +#if _DEBUG_ + printf("\n"); +#endif + + /* + * Summary report + * + * I know, this code could be tightened (rbd)... + */ + if(show_summary) + { + char t1[32], t2[32], t3[32], t4[32], t5[32]; + long ib, ob, b, rf, sf; + long t_ib=0, t_ob=0, t_b=0, t_rf=0, t_sf=0; + double it, ot, ir, or; + double t_it=0.0, t_ot=0.0; + int nhosts = 0; + + printf("\n\ + Remote ------- Bytes -------- --- Time ---- -- Avg CPS -- -- Files --\n"); + printf("\ + Host Rcvd Sent Total Rcvd Sent Rcvd Sent Rcvd Sent\n"); + printf("\ +-------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n"); + for (cur = hosts; cur != NULL; cur = cur->next) + { + ib = (cur->call[IN].flow[IN].bytes + + cur->call[OUT].flow[IN].bytes); + fmbytes(ib, t1); + t_ib += ib; + + ob = (cur->call[IN].flow[OUT].bytes + + cur->call[OUT].flow[OUT].bytes); + fmbytes(ob, t2); + t_ob += ob; + + b = ib + ob; + fmbytes(b, t3); + t_b += b; + + it = cur->call[IN].flow[IN].time + + cur->call[OUT].flow[IN].time; + fmtime(it, t4); + t_it += it; + + ot = cur->call[IN].flow[OUT].time + + cur->call[OUT].flow[OUT].time; + fmtime(ot, t5); + t_ot += ot; + + rf = cur->call[IN].flow[IN].files + + cur->call[OUT].flow[IN].files; + t_rf += rf; + + sf = cur->call[IN].flow[OUT].files + + cur->call[OUT].flow[OUT].files; + t_sf += sf; + + ir = (it == 0.0) ? 0.0 : (ib / it); + or = (ot == 0.0) ? 0.0 : (ob / ot); + + printf("%-8s %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n", + cur->Hostname, + t1, t2, t3, t4, t5, + ir, or, rf, sf); + } + + if(nhosts > 1) + { + fmbytes(t_ib, t1); + fmbytes(t_ob, t2); + fmbytes(t_b, t3); + fmtime(t_it, t4); + fmtime(t_ot, t5); + ir = (t_it == 0.0) ? 0.0 : (t_ib / t_it); + or = (t_ot == 0.0) ? 0.0 : (t_ob / t_ot); + + printf("\ +-------- ------- ------- ------- ------ ------ ------ ------ ----- -----\n"); + printf("\ +Totals %7s %7s %7s %6s %6s %6.1f %6.1f %5d %5d\n", + t1, t2, t3, t4, t5, + ir, or, t_rf, t_sf); + } + } + + + /* + * Call statistics report + */ + if(show_calls && have_calls) + { + char t1[32], t2[32]; + + printf("\nCall statistics:\n"); + printf("\ + sysname callto failto totime callfm failfm fmtime\n"); + printf("\ + -------- ------ ------ -------- ------ ------ --------\n"); + for (cur = hosts; cur != NULL; cur = cur->next) + { + fmtime(cur->call[OUT].connect_time, t1); + fmtime(cur->call[IN].connect_time, t2), + printf(" %-8s %6d %6d %8s %6d %6d %8s\n", + cur->Hostname, + cur->call[OUT].calls, + cur->call[OUT].calls - cur->call[OUT].succs, + t1, + cur->call[IN].calls, + cur->call[IN].calls - cur->call[IN].succs, + t2); + } + } + + /* + * File statistics report + */ + if(show_files && have_files) + { + char t1[32], t2[32]; + + for (sent = IN; sent <= OUT; ++sent) + { + printf(file_hdr[sent]); + printf(" sysname files bytes xfr time byte/s\n"); + printf(" -------- ------ -------- -------- ------\n"); + for (cur = hosts; cur != NULL; cur = cur->next) + { + double rate; + double time; + + time = cur->call[IN].flow[sent].time + + cur->call[OUT].flow[sent].time; + if (time == 0.0) + continue; + rate = (cur->call[IN].flow[sent].bytes + + cur->call[OUT].flow[sent].bytes) / time; + fmbytes((cur->call[IN].flow[sent].bytes + + cur->call[OUT].flow[sent].bytes), t1); + fmtime((cur->call[IN].flow[sent].time + + cur->call[OUT].flow[sent].time), t2); + printf(" %-8s %6d %8s %8s %6.1f\n", + cur->Hostname, + cur->call[IN].flow[sent].files + + cur->call[OUT].flow[sent].files, + t1, t2, rate); + } + } + } + + /* + * Efficiency report + */ + if (show_efficiency && have_files) + { + char t1[32], t2[32], t3[32]; + double total, flow; + + printf("\nEfficiency:\n"); + printf(" sysname conntime flowtime ovhdtime eff. %%\n"); + printf(" -------- -------- -------- -------- ------\n"); + for (cur = hosts; cur != NULL; cur = cur->next) + { + total = cur->call[IN].connect_time + cur->call[OUT].connect_time; + 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); + printf(" %-8s %8s %8s %8s %5.1f%%\n", + cur->Hostname, t1, t2, t3, ((flow / total) * 100.0)); + } + } + + /* + * Command execution report + */ + if (show_commands & have_commands) + { + printf("\nCommand executions:\n"); + printf(" sysname rmail rnews other\n"); + printf(" -------- ------ ------ ------\n"); + for (cur = hosts; cur != NULL; cur = cur->next) + { + int rmail, rnews, other; + + if (cur->cmds == NULL) + continue; + rmail = rnews = other = 0; + for (cmd = cur->cmds; cmd != NULL; cmd = cmd->next) + { + if (strcmp(cmd->Commandname, "rmail") == 0) + rmail += cmd->count; + else if (strcmp(cmd->Commandname, "rnews") == 0) + rnews += cmd->count; + else + other += cmd->count; + } + printf(" %-8s %6d %6d %6d\n", cur->Hostname, + rmail, rnews, other); + } + } + return; + + usage: + fprintf(stderr, + "Usage uurate [-cfexai] [-h hostname] [logfile ... logfile]\n"); + fprintf(stderr,"where:\t-c\tReport call statistics\n"); + fprintf(stderr, "\t-f\tReport file transfer statistics\n"); + fprintf(stderr, "\t-e\tReport efficiency statistics\n"); + fprintf(stderr, "\t-x\tReport command execution statistics\n"); + fprintf(stderr, "\t-a\tAll of the above reports\n"); + fprintf(stderr, "\t-h host\tReport activities involving ONLY host\n"); + fprintf(stderr, "\t-i\tRead log info from standard input\n"); + fprintf(stderr, + "If no report options given, a compact summary report is given.\n"); + fprintf(stderr, + "If neither -i nor logfiles given, defaults to reading from\n"); + fprintf(stderr, "%s and %s\n\n", LOGFILE, STATFILE); +} + +/* + * fmtime() - Format time in hours & minutes; + */ +static void fmtime(dsec, buf) + double dsec; + char *buf; +{ + long hrs, min, lsec; + + lsec = dsec; + hrs = lsec / 3600L; + min = (lsec - (hrs * 3600L)) / 60L; + + sprintf(buf, "%02ld:%02ld", hrs, min); +} + +/* + * fmbytes - Format size in bytes + */ +static void fmbytes(n, buf) + unsigned long n; + char *buf; +{ + char t; + double s = n; + + if(s >= 10239897.6) /* More than 9999.9K ? */ + { + s = (double)n / 1048576.0; /* Yes, display in Megabytes */ + t = 'M'; + } + else + { + s = (double)n / 1024.0; /* Display in Kilobytes */ + t = 'K'; + } + + sprintf(buf, "%.1f%c", s, t); +} + diff --git a/gnu/libexec/uucp/contrib/uurate.man b/gnu/libexec/uucp/contrib/uurate.man new file mode 100644 index 000000000000..9f33ef303862 --- /dev/null +++ b/gnu/libexec/uucp/contrib/uurate.man @@ -0,0 +1,217 @@ +.TH uurate 1 +.SH NAME +uurate \- Report Taylor UUCP statistics +.SH SYNOPSIS +.BR uurate " [ " "\-cfexai" " ] [ " "\-h " +.I host +.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 files given to +.I uurate +must be in the ``Taylor'' 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 +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, as defined at compilation time. +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, the +.B call +and +.B file +reports are displayed. If there is no relevant data for a particular +report or host, that report or host will be supressed. +.SH OPTIONS +The following options may be given to +.I uurate: +.TP 5 +.B \-c +Report on call statistics. Requires data from a +.I Log +file. +.TP 5 +.B \-f +Report on file transfer statistics. Requires data from a +.I Stats +file. +.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 \-x +Report on remote execution requests (e.g., +.IR rmail ")." +Requires data from a +.I Log +file. +.TP 5 +.B \-a +All reports. Identical to +.B \-cfex. +.TP 5 +.BI "\-h " "host" +Restrict report output to +.I host. +.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 option +.B \-a. +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 "Call report" +The call report gives statistics on inbound and outbound calls for +each active host system. The fields are described below: +.br +.nf +.in +.5i +.ta 1.0i +.BR "sysname " "UUCP node name of neighbor host system" +.BR "callto " "Outbound calls attempted to that system" +.BR "failto " "Failed outbound calls to that system" +.BR "totime " "Connect time (sec.) on outbound calls" +.BR "callfm " "Inbound calls attempted by that system" +.BR "failfm " "Failed inbound calls from that system" +.BR "fmtime " "Connect time (sec.) on inbound calls" +.in -.5 +.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: +.br +.nf +.in +.5i +.ta 1.0i +.BR "sysname " "UUCP node name of neighbor host system" +.BR "files " "Number of files transferred" +.BR "bytes " "Total size (bytes) of files transferred" +.BR "seconds " "Total time (sec.) to transfer files" +.BR "byte/sec " "Average transfer rate (bytes/sec)" +.in -.5 +.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: +.br +.nf +.in +.5i +.ta 1.0i +.BR "sysname " "UUCP node name of neighbor host system" +.BR "conntime " "Total connect time for that system" +.BR "flowtime " "Total file transfer time for that system" +.BR "ovhdtime " "Connect time not used to transfer files" +.BR "effcy (%) " "Ratio of connect time to transfer time" +.in -.5 +.SS "Remote execution report" +The remote execution report describes remotely +requested command executions from each active host system. +Executions of +.I rmail +and +.I rnews +are the most common, and are detailed separately. The fields +are described below: +.br +.nf +.in +.5i +.ta 1.0i +.BR "sysname " "UUCP node name of neighbor host system" +.BR "rmail " "Number of rmail requests from that system" +.BR "rnews " "Number of rnews requests from that system" +.BR "other " "Number of other requests from that system" +.in -.5i +.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 +.5in +.ta 2.0i +.IR "/usr/spool/uucp/Log " "Taylor format call/execution log" +.IR "/usr/spool/uucp/Stats " "Taylor format file transfer log" +.SS "SEE ALSO" +.IR uucico "(8)" +.SS BUGS +Does not understand older (V2, BNU) logging formats. Anyone care to +volunteer to add this? I don't use the stuff myself. +.PP +The entries that Taylor UUCP makes in the log file for incoming calls +don't have a host name. This confuses +.I uurate +into thinking that the calls came in for system "-". This may require +a change to Taylor logging. +.PP +Should check the configuration file to locate the currently active +.I Log +and +.I Stats +files when using them for default inputs. Instead, it uses the +compile-time settings only. +.PP +Should report packet protocol error statistics by host and +protocol type. +.SS AUTHOR +Robert B. Denny (denny@alisa.com) +.br +Loosely based on the DECUS UUCP program +.I uurate +by Mark Pizzolato. + + + + + + diff --git a/gnu/libexec/uucp/contrib/uureroute b/gnu/libexec/uucp/contrib/uureroute new file mode 100755 index 000000000000..3eeb654e1e27 --- /dev/null +++ b/gnu/libexec/uucp/contrib/uureroute @@ -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 000000000000..0f878c1e0547 --- /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 1993/08/04 19:31:43 jtc 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 000000000000..8b56d0f6b4f5 --- /dev/null +++ b/gnu/libexec/uucp/contrib/uutraf @@ -0,0 +1,203 @@ +#!/usr/local/bin/perl +# uutraf.pl -- UUCP Traffic Analyzer +# SCCS Status : @(#)@ uutraf 1.7 +# Author : Johan Vromans +# Created On : *** +# Last Modified By: Johan Vromans +# Last Modified On: Wed Feb 26 08:52:56 1992 +# Update Count : 4 +# 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/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 ("Unknown UUCP type: $uucp_type\n"); +} + +$garbage = 0; + +while ( <> ) { + unless ( /$pat/o ) { + print STDERR "Possible garbage: $_"; + if ( $garbage++ > 10 ) { + die ("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 = `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 000000000000..bc0cf299e99c --- /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/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 [ $s != "" ]; 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/xc-conf.h-dist b/gnu/libexec/uucp/contrib/xc-conf.h-dist new file mode 100644 index 000000000000..8810dd78d92f --- /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 000000000000..cfb4d359662f --- /dev/null +++ b/gnu/libexec/uucp/contrib/xchat.c @@ -0,0 +1,1444 @@ +/* + * *********** + * * 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) + * + * 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. + * + * 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_END 42 /* 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}, + {"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 */ + 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; + + } + } + } +} + +/* + * 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 000000000000..c980e202fcb4 --- /dev/null +++ b/gnu/libexec/uucp/contrib/xchat.man @@ -0,0 +1,614 @@ +.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 "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 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? + |