[net.sources] Chat - A multi user communications package

slb@bnl44.UUCP (Sanford L. Barr @ Brookhaven National Labs. Long Island, N.Y.) (09/26/85)

(Watch for signature)
#!/bin/sh
#
# *This is a shell archive.  Remove anything before this line and run the rest*
# *of this file through the 'sh' command.  Or use the 'unshar' command.       *
# *****************************************************************************
# *                                                                           *
# *                          Chat Version 6.0                                 *
# *                                                                           *
# *       This is a copy of the Chat system developed at Brookhaven           *
# *  National Labs (Later drastically improved at my house) to allow a        *
# *  group conversation between users.                                        *
# *                                                                           *
# *       A very early version of this program was released a while           *
# *  ago and I apologize to all the non-V7 people who struggled with it.      *
# *       This version (6.0) was developed on both a PDP-11/44 and an AT&T    *
# *  UNIX PC. So, I can almost guarentee no problems with sysV or V7.         *
# *   For 4.x BSD there should be little or no modifications to make.         *
# *                                                                           *
# *       6.0 adds a few goodies like wordwrap, accessing of the termcap      *
# *  library for special functions, and an overall enhancement in the way it  *
# *  works.                                                                   *
# *****************************************************************************
#  Files included are:
# 
# Makefile
# README		Read this for some insight.
# README2		Read this to get started.
# chat.h
# chat.1 	        Manual page for chat system.
# cursub.c
# cwho.c 	        C-source for the cwho command (similar to who(1))
# defs.h 	        Easy access list of major Chat variables.
# main.c
# misc.c
# page.c
# quit.c
# readmsg.c
# ruser.c	        C-source for the remove user system utility.
# send.c
# ttyset.c
# 
# Sanford L. Barr                 |     slb\@bnl44.ARPA
# 39 Royalston Lane               |     slb\@bnl44.UUCP
# S. Setauket, N.Y. 11720
# (516) 736-4155 (home)
# 
# 	Please send me any updates that you may make, especially regarding
# 4.x BSD.  Thanks.
# ______
# This program, with permission from the author, is being posted as a favor
# to the UN*X community.  In no way may this material be reproduced in any
# other way, shape or form other than electronic mail, without written
# permission from the author.  Any use of this program or any part thereof
# other than for non-profit also requires written permission from the author.
# ***************************************************************************
#
echo 'Start of Chat.shar, part 01 of 01:'
echo 'x - Makefile'
sed 's/^X//' > Makefile << '/'
X###############################################################################
X####		   Makefile for The Chat System by SLB                     ####
X###############################################################################
XCC=cc
X
X###############################################################################
X# The DESTDIR is the final location of the compiled chat system along with
X#  All commands (cwho, ruser)
XDESTDIR=/usr/local/bin
X
X###############################################################################
X# OWNER and GROUP are the names of the owner and group of the chat system
X# (usually bin bin or whoever decides to oversee Chat)
XOWNER=bin
XGROUP=bin
X
X###############################################################################
X# MANDIR is where the manual page for chat is to be stored (if at all).
XMANDIR=/usr/man/man1
X
X###############################################################################
X# Defined flags:
X# If your system has TERMIO then define it, otherwise Chat assumes you have
X#   CBREAK mode in sgtty.h
X# Define ENEMY if you wish to be able to "squelch" users who abuse their
X#   Chat privledges (see README).
X# Define VOID if your system has the void type.
X# Define INDEX if your system has INDEX insted of STRCHR
XCFLAGS= -Os -DTERMIO -DINDEX -DENEMY -DVOID
X
XOBJECTS= main.o cursub.o ttyset.o page.o readmsg.o send.o misc.o quit.o
X
Xall: chat cwho ruser
X
Xchat:   chat.h $(OBJECTS) defs.h
X	$(CC) -Os $(OBJECTS) -o chat -ltermlib
X
Xcwho:	defs.h cwho.c
X	$(CC) -Os cwho.c -o cwho
X
Xruser:	defs.h ruser.c
X	$(CC) -Os ruser.c -o ruser
X
Xlint:
X	lint -bxa *.c
X
Xinstall:
X	mv chat ${DESTDIR}
X	chown ${OWNER} ${DESTDIR}/chat
X	chgrp ${GROUP} ${DESTDIR}/chat
X	chmod ug+s     ${DESTDIR}/chat
X	mv cwho ${DESTDIR}
X	mv ruser ${DESTDIR}
X	chown ${OWNER} ${DESTDIR}/ruser
X	chgrp ${GROUP} ${DESTDIR}/ruser
X	chmod ug+s     ${DESTDIR}/ruser
X	mv chat.1 ${MANDIR}
X
Xclean:
X	rm -f ${OBJECTS}
/
echo 'x - README'
sed 's/^X//' > README << '/'
XFiles included in this directory are as follow:
X
X     main.c misc.c page.c ttyset.c cursub.c send.c readmsg.c
X
X        These files are the source code for the chat system.  After
XChat has been compiled it must be setuid to "root" or another
Xsystem user with read-write permission on the directory in which
Xthe LOGFILE is stored.  (See defs.h)
X
X        defs.h
X
X        This file contains all the major Chat system variables. Included
Xare:
X
XMAXUSERS        = Maximum amount of users in a single chat session.
XLOGFILE         = User file for chat.  Similar to /etc/utmp in nature.
XPREFIX          = The prefix and directory name for system buffers.
XFNAME           = File containg list of users logged in host system (utmp)
XPAGER           = The utility to notify other system users.
XSYSTEMFILE      = ** File which holds "squelch" information. And info. on
X                  system status. (See following comments).
X
X	chat.1
X
X	Manual page for Chat.  Formatted in man macros.
X
X        cwho.c
X
X        Source for a small utility which prints a list of users logged
Xinto the Chat system  This file requires no special permission.
X
X        ruser.c
X
X        Due to some system malfunctions and/or screwups, on rare
Xoccasions a user may not be removed from the LOGFILE.  The drawback
Xis that messages still get sent to the user's buffer and could
Xaccount for a lenghty /tmp file.   If such an occurance ever happens
Xthis utility will allow you to delete the user from the LOGFILE without
Xdisturbing any other system users in chat.  This has only 
Xhappened once during he duration of Chat's development.  But I included
Xthe utility just in case.
X------
X
X        In the rare event that it is necessary to take the Chat system
Xdown it may be accomplished by simply using a standard editor on the
XChat SYSTEMFILE and adding  the line:
X
Xsystem-down
X
X        When called up Chat will display a system down notice
Xand exit.   This is a hangover from the development stage and I have
Xfound no practical use otherwise - enjoy it anoyhow.
X
X        In the case of a system user abusing the Chat system
Xor the users on it,  he/she may be denied access until the owner
Xfeels confident that the user has straightened out.  This is a last
Xresort.  The perferred methind would be to communicate wih the
Xuser in question first.  If that dosen't seem to work then you
Xmay remove their access.
X
X        To remove a user's access simply add a line to the
Xchat SYSTEMFILE saying
X
Xsquelch username
X
XWhere username is the user in question.  When the user tries
Xto enter Chat they will be given a notice regarding removal of
Xaccess.
/
echo 'x - README2'
sed 's/^X//' > README2 << '/'
XTo get Chat up and running:
X
X	#1 unpack and rummage through the Makefile.  Tailor it to your
X		needs.
X
X	#2 Edit and change "defs.h" to suit your particular system.
X
X	#3 Type "make" and sit back and watch the fun.
X
XIf you defined what you wanted the makefile to do for installation type
X"make install" and that will move Chat, and it's subprograms, to the
Xdestination directory. Along with changing it to the correct permissions.
X
XOther important stuff is in README2.
/
echo 'x - chat.1'
sed 's/^X//' > chat.1 << '/'
X.TH CHAT 1 
X.SH NAME
Xchat \-  Chat with up to 10 users
X.PP
Xcwho \-  See who\'s logged into Chat.
X.SH SYNOPSIS
X.B chat
X.PP
X.B cwho
X.SH DESCRIPTION
X.I Chat,
Xis a multi-user communications system
Xwhich allows a group of users to join in conversation.
XThe maximum amount of users in a single
X.I Chat
Xsession is 10 by default.
X.PP
XUpon entering
X.I Chat
Xthe users logged into the current
XChat session are displayed, along with their tty, and when they
Xentered.  No prompt will be given but the various system
Xfunctions can be accessed at the touch of a key.
X.PP
XChat system functions are as follow
X.TP
Xno input
X.PP
XWithout input from the user's terminal,
X.I Chat 
Xwill display all incoming
Xmessages from other users along with notification of when users enter
Xand exit the current chat session.  All messages from other users are
Xterminated by "<" and include the sender's name, handle, and tty.  A
Xstandard message would look something like this:
X
X05 joeluser(Handle)= This is a test message.<
X
XAs of revision 6.0,
X.I Chat
Xnow includes wordwrap along with formatting the incoming messages to line
Xup with the "="'s.   This gives a much more desirable effect and aleviates the
Xproblem with terminals that do not have linewrap.
X
XUser login and logout notification is inclosed in asterisks (*) and describes
Xthe current status.  A sample message would looks something like this:
X
X** joeluser logged in/out on 01 **
X
XA user may give themselves a handle by adding the environment variable
XHANDLE and defining it to their preference (up to 10 characters).
XFrom sh(1) this can be done by typing:
X
X$ HANDLE="Your Handle Here"; export HANDLE
X
XFrom csh(1):
X
X% setenv HANDLE "Your Handle Here"
X
X.TP
X.I L
XList users logged into host system.
X.PP
XThis command prints a list of users logged into the host system,
Xincluding their tty and when they logged in. (Similar to who(1))
X.TP
X.I P
XPage a user to come into Chat.
X.PP
XThis command allows a user to page another user who's logged into the
Xhost system.  Upon typing this command a list of all users users is
Xdisplayed along with a Job number.  The user will then be prompted to
Xenter a Job to be paged.  The page will be sent through mail(1) so
Xas to not disturb the person being paged.
X.TP
X.I S
XSend a message to all users in Chat.
X.PP
XAfter typing "s" the user will be prompted with "TEXT>" at which point
Xthe user is to enter his/her message to be sent out.  A
Xmessage may be up to 4 lines of 80 characters each and is terminated
Xby a carriage return.
X.TP
X.I W
XDisplay all users logged into Chat.
X.PP
XThis command displays the name, handle, time and tty of all users
Xcurrently logged into the Chat system.
X.TP
X.I Q
XExit chat session.
X.PP
XUpon receiving an INTERRUPT or QUIT signal, as well as the user typing "q",
XChat will exit the current session.
X.TP
X.I !
XShell escape.
X.PP
XThe shell escape allows a user to execute a command via sh(1).  Time consuming
Xcommands are not advised due to the fact Chat buffers all incoming
Xmessages which would flood the user's terminal upon re-entry to
Xcommand returns control to
X.I Chat.
X.TP
X.I ?
XPrint a command summary.
X.PP
XThis command will print a brief summary of all current
X.I Chat
Xcommands.
X.TP
X.I cwho(1)
X.PP
XCwho is essentially a short program which allows a user who's not in the current
Xchat session to get a listing of the people in it.
X.I Cwho
Xrequires no arguments and exits with "No users logged into Chat" if no-one
Xis currently in
X.I chat.
X.I cwho\'s
Xoutput is essentially identical to that of the
X.I chat
Xcommand "W".
X.PP
XAll signals received by
X.I Chat
X, with the exception of SIGALRM and
XSIGKILL, will cause
X.I Chat
Xto exit and remove the user from the current logs.
X.SH FILES
X/etc/utmp       user's in host system
X.br
X/tmp/ct.*       message buffers
X.br
X/lib/CHATLOG    log of user's in current chat session
X.SH "SEE ALSO"
Xmail(1)
X.SH BUGS
XUser's handles are left up to their imagination.
X
XChat doesn't seem to react well to users logged in as root.
/
echo 'x - chat.h'
sed 's/^X//' > chat.h << '/'
X/*      This file contains all the major variables for the Chat       */
X/*	system.		->slb\@bnl.ARPA                                */
X/* chat.h :-: 9/19/85 */
X
X#include <stdio.h>			/* All those .h	files! */
X#include "defs.h"
X#include <signal.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <utmp.h>
X#include <time.h>
X
X#define	ON	1
X#define	OFF	0
X#define	OK	0
X#define FERROR	0
X#define ERR	(-1)
X#define	INLEN	(80 * 4)	/* Max number of chars input */
X
X#ifndef VOID
X#define	void	int
X#endif
X
Xstruct	stat	sbuf;
Xstruct	logs	lbuf;
X
Xextern  char				/* String Function Defs */
X	*strcpy(),
X	*strncpy(),
X	*strcat(),
X	*strncat(),
X	*strtok(),
X#ifdef INDEX
X	*rindex(),
X	*index();
X#else
X	*strrchr(),
X	*strchr();
X#endif INDEX
X
Xchar	mytty[6],			/* User's tty */
X	myname[16],			/* Username */
X	mixname[32],			/* Both	uname and handle */
X	myfile[64],			/* User	message	file */
X	buffer[512];
X
Xint	quit(),
X	bye(),
X	length,				/* Length of ttyname */
X	lfile;				/* Descriptor for LOGFILE */
X
Xunsigned int	users;		/* No of users in Chat	  */
X
Xlong	time(),
X	lseek();
X
Xunsigned alarm();
X
XFILE	*wfd;
X
Xvoid	exit(),perror(),
X	_exit(), qsort();
X
X/* Termcap  Stuff */
Xextern char *BC, *CM, *CL, *tgoto(),
X	    *CE, *SO, *SE, *CD,
X	    *TI, *TE;
Xextern int CO, LI;
/
echo 'x - cursub.c'
sed 's/^X//' > cursub.c << '/'
X/* cursub.c :=: 9/25/85   By SLB */
X
X/*  Various cursor subroutines to add nice touches to Chat */
X#include "chat.h"
X
X#define	NULLCHAR	((char *)0)
X#define CR	015
X
Xchar *BC, *CM, *CL, *CE, *SO, *SE;
Xchar *CD, *TI, *TE;
Xint CO, LI;
X
Xchar tspace[512], *bufspace;
Xchar *tgetstr(), *getenv();
Xint putch();
X
Xcinit() 
X{
X	char bbuf[1024];
X	char *tgoto();
X	char *TERM;
X
X	if ((TERM=getenv("TERM")) == FERROR)
X		TERM = "dumb";
X
X	tgetent (bbuf, TERM);
X	bufspace = tspace;
X	CM = tgetstr ("cm", &bufspace);
X	CL = tgetstr ("cl", &bufspace);
X	BC = tgetstr ("bc", &bufspace);
X	if (BC == NULLCHAR || tgetflag("bs"))
X		BC = "\b";
X	CO = tgetnum ("co");
X	LI = tgetnum ("li");
X	SO = tgetstr ("so", &bufspace);
X	SE = tgetstr ("se", &bufspace);
X	CD = tgetstr ("cd", &bufspace);
X	TI = tgetstr ("ti", &bufspace);
X	TE = tgetstr ("te", &bufspace);
X
X	if (SO == NULLCHAR)
X	SO = "";
X	if (SE == NULLCHAR)
X	SE = "";
X	if (CM == NULLCHAR) 
X	return 1;
X	return 0;
X}
X
Xhilight(str)
Xchar *str;
X{
X	tputs(SO, 0, putch);
X	fputs(str, stdout);
X	tputs(SE, 0, putch);
X}
X
X/*  Move cursor to specified spot.  (1,1) upper left.  (80,24) lower right */
X
Xmvcur(x, y)
Xint x, y; 
X{
X	tputs (tgoto (CM, x-1, y-1), 0, putch);
X}
X
X/* Clear screen */
Xclear() 
X{
X	int i;
X
X	if (CL) {
X		tputs(CL, 0, putch);
X		putch(CR);
X	}
X	mvcur(1,1);
X}
X
X/* Erase current line */
Xzapline() 
X{
X	if (CE) {
X		putch('\r');
X		tputs(CE, 0, putch);
X	} else
X		puts("\r");
X}
/
echo 'x - cwho.c'
sed 's/^X//' > cwho.c << '/'
X/* cwho.c :=: 9/25/85   By SLB */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "defs.h"
X
Xstruct logs     lbuf;
Xstruct stat	sbuf;
X
Xmain()          /* Show who's logged into chat */
X{
X        int     lfile;
X
X        if (stat(LOGFILE, &sbuf) == EOF || sbuf.st_size == 0) {
X		puts("No users logged into Chat.");
X		exit(0);
X	}
X
X	if ((lfile=open(LOGFILE, 0)) == EOF) {
X		perror(LOGFILE);
X                exit(1);
X	}
X
X        puts("Users In Chat        Tty    When");
X
X        while (read(lfile, (char *) &lbuf, sizeof(lbuf))==sizeof(lbuf)) {
X                if (lbuf.l_line[0]=='\0' || lbuf.l_name[0]=='\0' ||
X			!strncmp(lbuf.l_name, "LOGIN", 5))
X                        continue;       /* Skip blankies */
X
X        printf("%-20.20s %-5.5s  %7.7s\n",lbuf.l_name,
X                                                   lbuf.l_line,lbuf.l_time);
X
X        }
X        if (close(lfile) == EOF) {
X                perror(LOGFILE);
X                exit(1);
X        }
X}
/
echo 'x - defs.h'
sed 's/^X//' > defs.h << '/'
X/*      Chat System Definition Header File     */
X/*		->slb\@bnl.ARPA		       */
X/* chat.h :-: 9/19/85 */
X
X#define SYSTEMFILE "/usr/slb/Chat_sfile"
X#define PREFIX  "/tmp/ct."              /* Storage for messages */
X#define FNAME   "/etc/utmp"             /* To see who's on the system */
X#define PAGER 	"/bin/mail "		/* Medium for paging */
X#define LOGFILE	"/usr/slb/CHATLOG"	/* List of users in chat */
X#define MAXUSERS 10			/* Max # of users in chat */
X
Xstruct	logs {
X	char	l_line[5];		/* User's tty */
X	char	l_name[20];		/* User's name and handle */
X	char	l_time[7];		/* Entered chat	*/
X}
Xnames[MAXUSERS];
/
echo 'x - header'
sed 's/^X//' > header << '/'
X*This is a shell archive.  Remove anything before this line and run the rest*
X*of this file through the 'sh' command.  Or use the 'unshar' command.       *
X*****************************************************************************
X*                                                                           *
X*                          Chat Version 6.0                                 *
X*                                                                           *
X*       This is a copy of the Chat system developed at Brookhaven           *
X*  National Labs (Later drastically improved at my house) to allow a        *
X*  group conversation between users.                                        *
X*                                                                           *
X*       A very early version of this program was released a while           *
X*  ago and I apologize to all the non-V7 people who struggled with it.      *
X*       This version (6.0) was developed on both a PDP-11/44 and an AT&T    *
X*  UNIX PC. So, I can almost guarentee no problems with sysV or V7.         *
X*   For 4.x BSD there should be little or no modifications to make.         *
X*                                                                           *
X*       6.0 adds a few goodies like wordwrap, accessing of the termcap      *
X*  library for special functions, and an overall enhancement in the way it  *
X*  works.                                                                   *
X*****************************************************************************
X Files included are:
X
XMakefile
XREADME		Read this for some insight.
XREADME2		Read this to get started.
Xchat.h
Xchat.1 	        Manual page for chat system.
Xcursub.c
Xcwho.c 	        C-source for the cwho command (similar to who(1))
Xdefs.h 	        Easy access list of major Chat variables.
Xmain.c
Xmisc.c
Xpage.c
Xquit.c
Xreadmsg.c
Xruser.c	        C-source for the remove user system utility.
Xsend.c
Xttyset.c
X
XSanford L. Barr                 |     slb\@bnl44.ARPA
X39 Royalston Lane               |     slb\@bnl44.UUCP
XS. Setauket, N.Y. 11720
X(516) 736-4155 (home)
X
X	Please send me any updates that you may make, especially regarding
X4.x BSD.  Thanks.
X______
XThis program, with permission from the author, is being posted as a favor
Xto the UN*X community.  In no way may this material be reproduced in any
Xother way, shape or form other than electronic mail, without written
Xpermission from the author.  Any use of this program or any part thereof
Xother than for non-profit also requires written permission from the author.
X***************************************************************************
/
echo 'x - main.c'
sed 's/^X//' > main.c << '/'
X/*			     Chat ver 6.0				*/
X/*	      Written by Sanford L. Barr  (slb\@BNL44.ARPA)		*/
X/* misc.c :=: 9/25/85 */
X#define	VERSION	"6.0 by SLB"
X
X/****************************
X**	    CHAT           **
X**			   **
X**	A multi-user	   **
X**  communication system   **
X****************************/
X
X#include "chat.h"
X
Xint cptty(a, b)		/* Compare routine for qsort */
Xstruct logs  *a, *b;
X{
X	return(strcmp(a->l_line, b->l_line));
X}
X
Xmain()
X{
X	char	inp,
X		*getlogin(),
X		*getenv(),
X		*ttyname(),
X		*temptty = "\0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 
X		*handle	= "(\0xxxxxxxx",
X		login[8],		/* Time	entered	chat */
X		jline[128],
X		*junk;			/* Used	for handle and read */
X
X	int	i = 0,
X		s = 0,
X		l;
X
X	long	ti;
X
X
X	cinit();			/* Initalize cursor routines */
X	temptty = ttyname(2);				/* Get tty */
X#ifdef INDEX
X	temptty = rindex(temptty,'/') + 1;
X#else
X	temptty = strrchr(temptty,'/') + 1;
X#endif
X	sprintf(mytty, "%5.5s", temptty);		/* Truncate */
X	length = strlen(mytty);
X	strcpy(myname, getlogin());			/* Get username	*/
X	junk = &jline[0];
X
X	ti = time(0);
X	prtime(ti,login);			/* Set login time */
X
X	if ((wfd=fopen(SYSTEMFILE,"r"))	!= FERROR) {	/* Squelch users */
X		for(;;)	{
X			if (fgets(junk,	32, wfd) == OK)
X				i = 1;
X			if (!strncmp(junk, "system-down", 11)) {
X				puts("The chat system is down at the moment.  It should	be up shortly.");
X				exit(0);
X			}
X#ifdef ENEMY
X			if (!strncmp(junk, "squelch ", 8)) {
X				junk = junk + 8;
X				if (!strncmp(myname, junk, strlen(myname))) {
X				puts("\
XYou have been disallowed system	access.\n\
XIf you have any	questions, talk	to your	system administrator.");
X				exit(1);
X				}
X			}
X#endif
X			if (i)
X				break;
X		}
X		if (fclose(wfd)	== ERR)	{
X			perror(SYSTEMFILE);
X			exit(1);
X		}
X	}
X	junk = &jline[0];
X	strcpy(mixname, myname);		/* Get handle and */
X	if ((junk=getenv("HANDLE")) != FERROR) {/* Add it to mixname */
X		strncat(handle, junk, 10);
X		strcat(handle,")");
X		strncat(mixname, handle, strlen(handle));
X	}
X
X	s = 3;
X	while (s++ < 19)			/* Catch signals and */
X		if ((s != 18) && (s != SIGALRM))/* ignore them.      */
X			signal(s, SIG_IGN);
X			
X	signal(SIGHUP, quit);			/* These signals get */
X	signal(SIGINT, quit);			/* sent to quit      */
X	signal(SIGQUIT,quit);
X
X	if (access(LOGFILE, 00) != OK) {
X		close(creat(LOGFILE, 0644)); /* Create logfile */
X		chmod(LOGFILE, 0644);
X	}
X
X	if((lfile=open(LOGFILE, 0)) == FERROR) {  /* Open logfile */
X		perror(LOGFILE);
X		exit(1);
X	}
X
X	if (ridname() == ERR)			/* Clear out dead users	*/
X		exit(1);			/*	  if any	*/
X
X	who(ON, OFF);				/* Get who's logged in.	*/
X	if (users > MAXUSERS) {
X		puts("Sorry, no	available slots	left at	the moment.  Try later");
X		exit(1);
X	}
X
X	sprintf(names[users].l_line, "%5.5s", mytty);
X	sprintf(names[users].l_name, "%-20.20s", mixname);
X	sprintf(names[users].l_time, "%7.7s", login);
X
X	qsort((char *) names, users+1, sizeof(*names), cptty);	/* Sort tty's */
X
X	if ((wfd=fopen(LOGFILE,"w")) ==	FERROR) {
X		error("Couldn\'t open LOGFILE", ON);
X		exit(1);
X	}
X
X					/* Add name, tty, time to log */
X	for (l = 0; l <	users+1; l++)
X	fprintf(wfd, "%-5.5s%-20.20s%-7.7s", names[l].l_line,
X					 names[l].l_name, names[l].l_time);
X
X	if (fclose(wfd)	== ERR)	{
X		perror(LOGFILE);
X		quit();
X	}
X
X	strcpy(myfile, PREFIX);		/* Set up name for my message file */
X	strncat(myfile, mytty, 5);
X	if (close(creat(myfile,	0)) == ERR);	/* Create message file */
X	chmod(myfile, 0644);
X
X	send(1);			/* Say hello to	everyone */
X
X	tstore();			/* Save terminal settings */
X
X	ttyset(ON,OFF);			/* Set cbreak mode - no	echo */
X
X	clear();			/* Clear Screen */
X	printf("\r\nChat %s - press '?' for help.\r\n", VERSION);
X	who(OFF, OFF);			/* Show	who's logged in	Chat */
X
X	while(ON)
X	{
X
X		inp = get();			/* Get a key */
X
X		switch(inp)			/* Check it */
X		{
X		case 'w':
X			who(OFF, ON);
X			break;
X		case 'p':
X			if (page(ON) == ERR)
X				fputs("Page(ON) ML: unsucessful.\r\n", stderr);
X			break;
X		case 's':
X			send(0);
X			break;
X		case 'q':
X			quit();
X		case 'l':
X			if (page(OFF) == ERR)
X				fputs("Page(OFF): unsucessful.\r\n", stderr); 
X			break;
X		case 'v':
X			printf("\r\nVer %s\r\n",VERSION);
X			break;
X		case '!':
X			shell();
X			break;
X		case '?':
X			cmds();
X			break;
X	       default:
X			readmsg();
X			break;
X		}
X	}
X}
X
Xget()	/* get char routine for	chat,  waits 1 sec for input */
X	/*     (There's	probably a better way to do it.)     */
X{
X	char ch;
X
X	signal(SIGALRM, bye);
X
X	alarm(ON);
X	ch = getchar() & 127;
X	alarm(OFF);
X
X	if (!isprint(ch))
X		ch = 0;
X	else
X		if (isupper(ch))
X			ch = tolower(ch);
X
X	return(ch);
X}
X
Xbye()	/* called if the alarm signal is caught	*/
X{
X	return;
X}
X
/
echo 'x - misc.c'
sed 's/^X//' > misc.c << '/'
X/*********************
X**      Chat        **   The Chat System by SLB
X**  Miscellaneous   ** 
X**   Subroutines    **        Revision 6.0
X**		    **
X** prtime()	    **            September 18, 1985
X** who()	    **
X** ridname()	    **
X** cmds()	    **  (misc.c - Written by Sanford L. Barr)
X** putch()	    **
X** shell()	    **
X** error()	    **
X** sysexec()	    **
X**********************/
X
X#include "chat.h"
X
Xprtime(ti, strng)	/* prtime returns the time in 12 hour format to	strng */
Xchar	*strng;
Xlong	ti;
X{
X	struct	tm	*tp;
X	struct	tm	*localtime();
X	int	tim,
X		min,
X		pm;
X
X	tp = localtime(&ti);
X	tim = tp->tm_hour;		/* Set hours */
X	min = tp->tm_min;		/* Set mins  */
X	pm = (tim > 11);
X	if (tim	> 11)
X		tim -= 12;
X	if (tim	== 0)
X		tim = 12;
X	sprintf(strng, "%2d:%02d%s", tim, min, pm ? "pm" : "am");
X	return;
X}
X
Xcmds()	/* Print command list */
X{
X	char	input;
X
X	clear();			/* Clear Screen */
X	puts("\r\n\r\n\r\n\
X------------------------------------\r\n\
X------Chat System Command List------\r\n\
X------------------------------------\r\n\
XThese are the available	commands:  -\r\n\
X                                   -\r\n\
X(L)	Display	users logged in.   -\r\n\
X(P)	Page a user via mail(1).   -\r\n\
X(Q)	Exit chat session.         -\r\n\
X(S)	Send message.              -\r\n\
X(V)	Display	version	number.    -\r\n\
X(W)	See who's logged into Chat.-\r\n\
X(!)	Execute	shell command.     -\r\n\
X(!sh)	Escape to shell.	   -\r\n\
X(?)	Print this menu.           -\r\n\
X------------------------------------\r\n\
X");
X	hilight("Press [Return] to Continue:");
X	input = getchar();
X	clear();
X	return;
X}
X
Xputch(ch)			/* output a character */
Xint ch;
X{
X	putchar(ch);
X}
X
Xshell()		/* Read	and execute a shell command */
X{
X	char	input[80],
X		chr;
X
X	ttyset(OFF,ON);				/* back	to normal */
X	fputs("\r\nSuspending Chat: Enter command and hit return\r\n!",stdout);
X	fgets(input, 80, stdin);
X
X	if (sysexec(input) == 127)
X		puts("EXECUTION ERROR: Can't generate a shell\r");
X
X	ttyset(ON,OFF);				/* Cbreak again */
X	hilight("Press [Return] to Resume Chat:");
X	chr = getchar();
X	clear();				/* Clear Screen */
X}
X
Xwho(f, cl)		/* Show	who's logged into chat */
Xint f, cl;
X{
X
X	users =	0;
X
X	lseek(lfile, 0L, 0);		/* Rewind LOGFILE */
X	if (!f)	{
X		if (cl)
X			clear(); 	/* Clear Screen */
X		puts("\r\n\r");
X		puts("Users In Chat         Tty          When\r");
X	}
X
X	while (read(lfile, (char *) &lbuf, sizeof(lbuf))==sizeof(lbuf))	{
X		if (lbuf.l_line[0]=='\0' || lbuf.l_name[0]=='\0')
X			continue;	/* Skip	blankies */
X		if (users > MAXUSERS)
X			break;
X
X		sprintf(names[users].l_line, "%5.5s", lbuf.l_line);
X		sprintf(names[users].l_name, "%-20.20s", lbuf.l_name);
X		sprintf(names[users].l_time, "%7.7s", lbuf.l_time);
X
X		if (!f)
X			printf("%-20.20s %-5.5s	 %7.7s\r\n",lbuf.l_name,
X						    lbuf.l_line,lbuf.l_time);
X
X	users++;
X	}
X	if (!f)
X		puts("\r");
X	return;
X}
X
Xerror(estring,file)
Xchar	*estring;
X{
X
X	fputs("SYSTEM FILE ERROR",stderr);
X	if (file)
X		fprintf(stderr,"\r\n%s\r\n",estring);
X	else
X		fprintf(stderr," %s\r\n");
X}
X
Xridname()	/* Get's rid of	user, on mytty,	in LOGFILE */
X{
X
X	lseek(lfile, 0L, 0);			/* Rewind file */
X
X	buffer[0] = '\0';
X	while(read(lfile, (char	*) &lbuf, sizeof(lbuf))	== sizeof(lbuf)) {
X		if (!strncmp(lbuf.l_line, mytty, length))
X			continue;
X
X		strncat(buffer,	lbuf.l_line, sizeof(lbuf.l_line));
X		strncat(buffer,	lbuf.l_name, sizeof(lbuf.l_name));
X		strncat(buffer,	lbuf.l_time, sizeof(lbuf.l_time));
X
X	}
X	strcat(buffer, "\0");
X
X	if ((wfd=fopen(LOGFILE,	"w")) == FERROR) {
X		perror(LOGFILE);
X		return(ERR);
X	}
X	fputs(buffer, wfd);
X
X	if (fclose(wfd)	== ERR)	{
X		perror(LOGFILE);
X		return(ERR);
X	}
X	return(OK);
X}
X
Xsysexec(s)
Xchar *s;
X{
X	int status, pid, w;
X	register int (*istat)(), (*qstat)();
X
X	if ((pid = fork()) == 0) {
X		setuid(getuid());
X		execl("/bin/sh", "sh", "-c", s,	0);
X		_exit(127);
X	}
X	istat =	signal(SIGINT, SIG_IGN);
X	qstat =	signal(SIGQUIT,	SIG_IGN);
X	while ((w = wait(&status)) != pid && w != -1)
X		;
X	if (w == -1)
X		status = -1;
X	signal(SIGINT, istat);
X	signal(SIGQUIT,	qstat);
X	return(status);
X}
X
/
echo 'x - page.c'
sed 's/^X//' > page.c << '/'
X/* page.c :=: 9/25/85  by SLB */
X
X/* Page	another	user...for use with the	chat system.  */
X/* calling this	routine	with a 1 will activate "page" */
X/* calling with	a 0 will only call the print routine  */
X
X#include "chat.h"
X
Xpage(c)
X{
X
X
X	struct	utmp	ubuf;
X
X	FILE	*fp;
X	char	hisname[32],
X		_name[20][11],
X		*timein	= "00:00am",
X		inp[256];
X	int fd;
X	int i =	0, ttyn;
X
X
X	clear();				/* Clear Screen */
X	printf("\r\n\r\n\r\nUSERS LOGGED IN->\r\n");
X	if ((fd=open(FNAME, 0))== ERR) {
X		error("Page can't open /etc/utmp", ON);
X		quit();
X	}
X
X	while (read(fd,	(char *) &ubuf,	sizeof(ubuf))==sizeof(ubuf)) {
X		if (ubuf.ut_line[0]=='\0' || ubuf.ut_name[0]=='\0'
X			|| !strcmp(ubuf.ut_name, "LOGIN"))
X			continue;	/* skip	unused entries */
X		strcpy(_name[i],ubuf.ut_name);
X		prtime(ubuf.ut_time, timein);
X		printf("Job%d %-8.8s %-7.7s in \@ %s\r\n", i+1, 
X					ubuf.ut_name, ubuf.ut_line, timein);
X		i++;
X	}
X
X	if(close(fd) ==	ERR)
X	{
X		error("Page can't close	utmp.", ON);
X		quit();
X	}
X
X					/* page	another	user routine */
X	if (c == 0)
X		return(OK);
X
X	fputs("\nPage which job? [CR exits] ", stdout);
X	ttyset(OFF,ON);			/* Turn on echo for input */
X
X	gets(inp);
X	ttyn = atoi(inp);
X
X	ttyset(ON,OFF);			/* All good things must	be undone */
X
X	if (ttyn <= i && ttyn >= 1)
X	{
X		strcpy(hisname, PAGER);
X		strcat(hisname, _name[ttyn-1]);
X
X		if ((fp=popen(hisname,"w")) == FERROR)
X		{
X			error("Unable to page user.", ON);
X			return(ERR);
X		}
X
X		fprintf(fp,"\n>>YOU ARE BEING REQUESTED TO<<\n");
X		fprintf(fp,"      >>ENTER CHAT BY<<\n");
X		fprintf(fp,"--->%s -%s-\n", mixname, mytty);
X
X		if (fclose(fp) == ERR)
X		{
X			error("Unable to close PAGER.", ON);
X			quit();
X		}
X		printf("Page on it\'s way.  Please give %s enough time to respond.\r\n",_name[ttyn-1]);
X	} else
X		puts("No page sent.\r");
X	return(0);
X}
X
X
/
echo 'x - quit.c'
sed 's/^X//' > quit.c << '/'
X/* QUIT - Written By Sanford L. Barr for the Chat System 1985 */
X/* quit.c :=: 9/25/85 */
X
X#include "chat.h"
X
Xquit()		/* Exit	chat */
X{
X
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGHUP, SIG_IGN);
X
X	send(2);			/* Say goodbye */
X
X	if (unlink(myfile) == ERR)	/* Clear out msg file */
X		perror(myfile);
X
X	trestore();			/* Back	to normal */
X
X	puts("\n<*End of Chat Session*>");
X
X	if (ridname() == ERR)		/* Take	my name	off the	list */
X		exit(1);
X
X
X	if (close(lfile) == ERR) {	/* Close up the	LOGFILE	*/
X		perror(LOGFILE);
X		exit(1);
X	}
X	if (stat(LOGFILE, &sbuf) == ERR) {
X		perror(LOGFILE);
X		exit(1);
X	}
X	if (sbuf.st_size == 0) {
X		if (unlink(LOGFILE) == ERR) {
X			perror(LOGFILE);
X			exit(1);
X		}
X	}
X	exit(OK);			/* Goodbye! */
X}
X
/
echo 'x - readmsg.c'
sed 's/^X//' > readmsg.c << '/'
X/* readmsg.c :=: 9/25/85   By SLB */
X
X#include "chat.h"
X
X#define	STARTTXT	'='
X#define LOGMSG		'*'
X#define ENDTXT		'<'
X#define	READLEN	INLEN + 50	/* Max number of chars input */
X
Xint	CO;
X
Xreadmsg()
X{
X	char	linebuf[READLEN];
X
X	if (stat(myfile, &sbuf)	== ERR)
X		return;
X	if (sbuf.st_size == 0)
X		return;
X
X	if ((wfd=fopen(myfile, "r")) ==	FERROR) {
X		error("readmsg(): can't	open myfile", ON);
X		quit();
X	}
X
X	while (fgets(linebuf, READLEN, wfd) != NULL)
X		wordwrap(linebuf);
X
X	if (fclose(wfd)	== ERR)	{
X		error("readmsg(): closing error.", ON);
X		quit();
X	}
X	close(creat(myfile, 0644));	/* Wipe out file */
X}
X
Xwordwrap(s)	/* Wordwrap s to output */
Xchar	*s;
X{
X	int	buflen, tmplen, cmplen;
X	int	indent;
X
X	char	buffer[800],
X		temp[40],
X		*ptr;
X
X	cmplen = CO - 1;
X					/* Check possible text types */
X#ifdef INDEX
X	if ((s[0] == LOGMSG) || ((ptr=index(s, STARTTXT)) == NULL)) {
X#else
X	if ((s[0] == LOGMSG) || ((ptr=strchr(s, STARTTXT)) == NULL)) {
X#endif INDEX
X		fputs(s, stdout);
X		fputs("\r", stdout);
X		return;
X	}
X
X	indent = strlen(s) - strlen(ptr) + 2; /* Get message indent */
X	
X	strcpy(buffer, "");
X
X	while(strip(s, temp) != EOF) {
X		buflen = strlen(buffer);
X		tmplen = strlen(temp);
X		if ((buflen + tmplen) < cmplen) {
X			strcat(buffer, temp);
X		} else {
X			buflen = strlen(buffer);
X			cmplen = buflen + CO + 2;
X			strcat(buffer, "\r\n");
X			strncat(buffer, "                    ", indent);
X			strcat(buffer, temp);
X		}
X	}
X	fputs(buffer, stdout);
X	puts("\r");
X}
X
Xstrip(str, outstr)	/* Break string into words 20 chars or less */
Xchar *str, *outstr;
X{
X	int	i, j;
X
X	for (i=0,j=0; j < 20 && (str[i] != ' ' && str[i] != '\n'); i++, j++) {
X			outstr[j] = str[i];
X			if (str[i] == '\0')
X				return(EOF);
X	}
X	if (str[i] != '\n') 
X		outstr[j++] = str[i];
X	outstr[j] = '\0';
X	strcpy(str, &str[i+1]);
X	return;
X}
/
echo 'x - ruser.c'
sed 's/^X//' > ruser.c << '/'
X/* ruser.c :=: 9/25/85   By SLB */
X
X/*  Remove a pesky luser from the chat system.  */
X/*  To use type: riduser ttyname                */
X
X#include <stdio.h>
X#include "defs.h"
X
Xstruct logs     lbuf;
X
Xmain(argc, argv)                /* Get's rid of user, on mytty, in logfile */
Xint argc;
Xchar *argv[];
X{
X        char    *buffer = "\0";
X        int     lfile;
X        FILE    *fp;
X
X        if (argc != 2) {
X                fputs("usage: ruser <ttyname>\n", stderr);
X                exit(1);
X        }
X
X        if ((lfile=open(LOGFILE, 0)) == EOF) {
X                puts("No users in logfile.");
X                exit(0);
X        }
X
X        while(read(lfile, (char *) &lbuf, sizeof(lbuf)) == sizeof(lbuf)) {
X                if (strncmp(lbuf.l_line, argv[1], 5) == NULL) 
X                        continue;
X
X                strncat(buffer, lbuf.l_line, sizeof(lbuf.l_line));
X                strncat(buffer, lbuf.l_name, sizeof(lbuf.l_name));
X                strncat(buffer, lbuf.l_time, sizeof(lbuf.l_time));
X
X        }
X
X        if (close(lfile) == EOF) {
X                perror(LOGFILE);
X                exit(1);
X        }
X
X	if (strlen(buffer) == 0) {
X        	unlink(LOGFILE);
X		exit(0);
X	}
X
X	if ((fp=fopen(LOGFILE, "w")) == NULL) {
X                perror(LOGFILE);
X                exit(1);
X        }
X
X        fputs(buffer, fp);
X
X        if (fclose(fp) == EOF) {
X                perror(LOGFILE);
X                exit(1);
X        }
X}
/
echo 'x - send.c'
sed 's/^X//' > send.c << '/'
X/* send.c :=: 9/25/85   By SLB */
X
X#include "chat.h"
X
Xsend(o)		/* Send	messages, 0=input, 1=login, 2=logout */
Xint o;
X{
X	int	i = 0,
X		t, ch,
X		nusers = 0;
X	char	line[512],
X		*sname,
X		shrtname[5],
X		fname[64];
X
X	sname = mytty;
X	if ((!strncmp(sname, "tty", 3)) || (!strncmp(sname, "   ", 3)))
X		sname =	sname+3;
X
X	if (o == 0) {
X		fputs("\r\nTEXT> ",stdout);
X		while (ON) {
X			ch =  getchar();
X			if ((i + 1 > INLEN) && ((ch != '\r') && (ch != '\n') && (ch != '\b'))) {
X				putchar('\007');
X				continue;
X			}
X			if ((ch == '\b') && i > 0) {
X				i--;
X				fputs("\b \b", stdout);
X				continue;
X			} else if (isprint(ch) || (isspace(ch) && ch != '\t')) {
X				line[i]	= ch;
X				putchar(ch);
X				if (ch == '\n' || ch == '\r')
X					if (i > 0) {
X						line[i]	= '\0';
X						putchar('\n');
X						break;
X					} else {
X						zapline();
X						puts("Aborted\r");
X						return;
X					}
X				i++;
X			}
X		}
X	} else if (o ==	1)
X		sprintf(line, "** %s logged in on %s **", myname, sname);
X	else
X		sprintf(line, "** %s logged out on %s **", myname, sname);
X
X/* File	routine	- appends message to all tty's except mine */
X
X/* Note:  This system is not perfect.  All devicenames throughout
Xthe program get truncated to 5 chars which could cause trouble with
Xsystems that have long and similar devicenames.                 */
X
X
X	if (o == 0)
X		fputs("Sent to ",stdout);
X
X	lseek(lfile, 0L, 0);			/* Rewind */
X	while(read(lfile, (char	*) &lbuf, sizeof(lbuf))	== sizeof(lbuf)) {
X
X		if (!strncmp(lbuf.l_line, mytty, length))
X			continue;
X
X		strcpy(fname, PREFIX);
X		strncat(fname, lbuf.l_line, 5);
X
X		strncpy(shrtname, lbuf.l_line, 5);
X		if ((!strncmp(shrtname,"tty",3))||(!strncmp(shrtname,"   ", 3)))
X			strcpy(shrtname, &shrtname[3]);
X
X		if ((wfd=fopen(fname, "a")) == FERROR) {
X			if (o == 0)
X				printf("*%-2.2s* ", shrtname);
X			continue;
X		} else
X			if (o != 0)
X				fprintf(wfd, "%s\n", line);
X			else {
X				printf("%-.5s ", shrtname);
X				fprintf(wfd, "%s %s= %s<\n",
X							 sname, mixname, line);
X			}
X		nusers++;
X
X		if (fclose(wfd)	== ERR)	{
X			error("( send()	)", OFF);
X			quit();
X		}
X	}
X	if (o == 0) {
X		if (nusers == 0)
X			fputs("-Nobody", stdout);
X		puts("\r");
X	}
X}
X
/
echo 'x - ttyset.c'
sed 's/^X//' > ttyset.c << '/'
X/* ttyset.c :=: 9/25/85   By SLB */
X
X#include "chat.h"
X
X#ifdef TERMIO
X# include <termio.h>
X#else
X# include <sgtty.h>
X# include <sys/ioctl.h>
X#endif
X
X#ifdef TERMIO
X struct	termio	Nmode, Omode;
X#else
X struct	sgttyb	Nmode, Omode;
X#endif
X		
Xttyset(cbreak,echo)	/* set tty to/from cbreak & echo mode */
X{
X#ifdef TERMIO
X	if (ioctl(0, TCGETA, &Nmode) == ERR) {
X#else
X	if (ioctl(0, TIOCGETP, &Nmode) == ERR) {
X#endif TERMIO
X		puts("No terminal");
X		exit(1);
X	}
X	if (cbreak) {
X#ifdef TERMIO
X		Nmode.c_lflag &= ~ICANON;
X		Nmode.c_cc[VMIN]=1;
X		Nmode.c_cc[VTIME]=0;
X#else
X		Nmode.sg_flags |= CBREAK;
X#endif TERMIO
X	} else {
X#ifdef TERMIO
X		Nmode.c_lflag |= ICANON;
X		Nmode.c_cc[VEOF]=CEOF;
X		Nmode.c_cc[VEOL]=CNUL;
X#else
X		Nmode.sg_flags &= ~CBREAK;
X#endif TERMIO
X	}
X
X	if (echo)
X#ifdef TERMIO
X		Nmode.c_lflag |= ECHO;
X#else
X		Nmode.sg_flags |= (ECHO	| CRMOD);
X#endif TERMIO
X	else
X#ifdef TERMIO
X		Nmode.c_lflag &= ~ECHO;
X#else
X		Nmode.sg_flags &= ~(ECHO | CRMOD);
X#endif TERMIO
X
X#ifdef TERMIO
X	if (ioctl(0, TCSETA, &Nmode) == ERR) {
X#else
X	if (ioctl(0, TIOCSETP, &Nmode) == ERR) {
X#endif TERMIO
X		puts("Mode switch error.");
X		exit(1);
X	}
X}
X
Xtstore()	/* Store previous terminal settings */
X{
X#ifdef TERMIO
X	if (ioctl(0, TCGETA, &Omode) == ERR) {
X#else
X	if (ioctl(0, TIOCGETP, &Omode) == ERR) {
X#endif TERMIO
X		fputs("No terminal.",stderr);
X		quit();
X	}
X}
X
Xtrestore()	/* Restore previous terminal settings */
X{
X
X#ifdef TERMIO
X	if (ioctl(0, TCSETA, &Omode) == ERR)
X#else
X	if (ioctl(0, TIOCSETP, &Omode) == ERR)
X#endif TERMIO
X		fputs("Mode switch error.",stderr);
X}
/
echo 'Part 01 of Chat.shar complete.'
exit

-- 
                        Sanford L. Barr
           Famous designer of the Write Only Memory.
                       --             --
	     ..!decvax!mcnc!philabs!sbcs!bnl44!slb
		       ...slb@bnl44.ARPA
		       ...slb@bnl44.UUCP

Voice phone: (516) 736-4155

Address (USnail):

Almagmated Tech.
39 Royalston La.
S. Setauket, N.Y. 11720
ATTN: Sanford L. Barr