[comp.sources.misc] v10i069: MultiTalk1.2 - Multi-user Talk Parlour

al@questar.questar.mn.org (Al Viall) (02/14/90)

Posting-number: Volume 10, Issue 69
Submitted-by: Al Viall <al@questar.questar.mn.org>
Archive-name: multitalk

 Multitalk is a multi-user talk program which allows up to 20 users
online at one time. For BSD and System V machines only.
-----------------------  Cut here, then type sh 'file' --------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  Readme.1st cmds.txt mtalk.1 mtalk.man multitalk.c
#   multitalk.h news.txt
# Wrapped by al@hobbes on Thu Feb  8 15:11:16 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Readme.1st -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Readme.1st\"
else
echo shar: Extracting \"Readme.1st\" \(5104 characters\)
sed "s/^X//" >Readme.1st <<'END_OF_Readme.1st'
X                    Helpfull hints from the Author
XHello, if you are reading this right now, then obviously you have decided to
Xtry out the enclosed program, Multitalk. Henceforth, the words Mtalk and
XMultiTalk will conversely mean the same thing.
XI'll try to keep this as brief as possible, since the purpose of me writing
Xthis was only to point out certain things which may be helpfull in maintaining
XMtalk, but most of the comments included with the source are pretty self-
Xexplanatory.
X
XPURPOSE
X	The purpose behind writing Multitalk was actually two-fold. I needed
Xa project to do in my spare time in order to understand and write in 'C', and
XI thought that this type of a program would be rather usefull and entertaining
Xon BSD systems which only had TALK or NTALK to interactively converse with 
Xothers on the system. Mtalk does not have the limitation of ONE to ONE chatting
Xlike TALK or NTALK (These programs are ussually supplied with BSD systems), but
Xcan have up to 20 users online at once. Mtalk also allows private conversation
Xbetween individuals or groups(sitting at a table). Mtalk was very easy to
Xwrite after the initial things were out of the way, so I decided to make it
Xeasy for others to use. No object modules. No Makefile's. Just a simple script
Xthat will compile and then if successful, will setuid the executable so that
Xothers may use it.
X
XINSTALLATION
X	Installation requires a few steps, none of which should take very
Xlong to accomplish.
X
X	Step 1: Decide where you would like Mtalk to reside. Make that directory
X	read/write/execute for the person in charge of Mtalk. From this point on
X	we shall assume it is you. The reason for this, is that we wouldn't
X	want unwanted visitors into the directory since Mtalk has certain
X	security functions for users who abuse it. Those people would just end
X	up mucking things all to hell.
X
X	Step 2: Put all of the enclosed files into that directory except for
X	the /bin/sh script file called 'mtalk'. This file should be put into
X	a default login directory like /usr/local/bin. Before you do that, 
X	be sure to edit the script for the pathname to the Mtalk directory.
X
X	Step 3: Edit the multitalk.h file to correspond with the filenames 
X	that you wish things to be. Be sure to specify a HEADMOO <--Don't Ask.
X	Without a UID name for this definition, certain caretaker features can
X	not be used by you. These features include tasklock and user removal.
X
X	Step 4: Now compile the multitalk.c file using the /bin/sh script
X	'Makeit'. All this does is compile the source and then SETUID the
X	executable file so that others can use it without Permission errors.
X
X	Step 5: Mtalk is now runnable. Too make sure, just type 'mtalk'.
X
X	I have not run into any errors or major bugs while using Mtalk. The
Xonly problem so far is when someone ungracefully exits the program while in
Xauto_mode(/AUTO). In this case, which is worst-case scenario, all you need
Xto do, once you are told about it, is just edit the 'loginfile' and remove
Xthat persons entry from the file. Also, you will want to remove that persons
XPID-unique commfile.
X
XHOW IT WORKS
X	As you may already know, when one runs a particular job or command
Xin UNIX, the OS gives it a unique Process Identification Number(PID) so that
Xit may be able to reference that number later.
X	When you logon, Mtalk gets that PID number and a global variable is set
Xto correspond to that number. This is now your personal CommFile. Each user
Xwho logs on will get their own CommFile, which will be unique to that particular
Xprocess, and the corresponding PID number is then written to the loginfile
Xalong with other information pertinent to that user(i.e. UID_name, tty, etc.).
X	When you input a line of text for others to see, the loginfile is loaded
Xinto a structure array. Each entry is then taken, one by one, and your text is
Xappended to that entry's CommFile. When the user/users that you sent the text
Xto either hits C/R alone or uses a command AND there is text in their CommFile
Xto display, then it is displayed. Mtalk is not a Parent Process dependent
Xprogram. In other words, Mtalk does not start a parent process and spawn
Xchildren whenever a new user executes the program. Doing it that way would
Xhave been more work than it was worth!! Mtalk uses very little system resources,
Xsince the  SIZE and RES, as reported by TOP is 134K and 38K, 
Xrespectively.
X
XFINAL NOTES
X	I hope this pretty much explains the naughty bits of Mtalk. I am
Xsure you will either have good things to say about the program, are maybe you
Xmight tell me where to put the thing, either way, I would like to hear about
Xit. One serious note, I realize that more portable version of this would
Xbe usefull to others, but considering the time involved, I just could not do
Xit at this time, but it will be forthcoming. Right now, we only have the
Xversion for BSD and System V.    If you have bug reports, and/or
Xcriticisms and suggestions please read below.
X
X		Albert Viall
X		6881 MeadowBrook Blvd #317
X		St. Louis Park, MN 55426
X
X		E-Mail: al@{questar,hobbes}.QUESTAR.MN.ORG
X		Voice : 1-612-688-0089 X42  (8:00am-5:00pm CST)
X
X
X
END_OF_Readme.1st
if test 5104 -ne `wc -c <Readme.1st`; then
    echo shar: \"Readme.1st\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f cmds.txt -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"cmds.txt\"
else
echo shar: Extracting \"cmds.txt\" \(1506 characters\)
sed "s/^X//" >cmds.txt <<'END_OF_cmds.txt'
X
XAvailable Commands as of: 1/11/90
X
X          Commands preceded by an '*' are for Caretaker use ONLY.
X
X /? .......... Displays this command help file.
X /q .......... Quit. Logout of the Mtalk program.
X /auto ....... Puts you in auto-mode. Constant 'returns' are not needed in this
X	       mode because Mtalk will wait until there is output to display.
X*/broadcast .. Sends a highlighted message to all users.
X*/dayfile .... Displays a dayfile of activity and users in Mtalk.
X /echo ....... Toggles echo mode on/off.
X /look ....... Tells you what table or room you are located.
X*/lock ....... Puts the Mtalk program into a locked/unlocked state. This will
X	       prevent others from entering the Parlour.
X /message .... Allows you to leave a short message for a user who is not logged
X	       on at the time. When that person logs on, it can be displayed.
X /news ....... Displays any important bulletins or news if there is any to 
X	       report.
X /page ....... Allows you to PAGE a user to Mtalk.
X /prompt ..... Will change your default 'Say?' prompt to whatever you choose.
X*/purge ...... Effectively bans a user from further use of Mtalk.
X /sit ........ Moves you to whatever table of your choosing.
X /status ..... Shows who is currently logged into Mtalk.
X /time ....... Displays the current time and date.
X /whisper .... Send a private message to someone anywhere in the Parlour.
X /yell ....... Sends a message to everyone in the Parlour.
X*/logoff ..... Forcibly logs off a current user of Mtalk.
X
X
X
END_OF_cmds.txt
if test 1506 -ne `wc -c <cmds.txt`; then
    echo shar: \"cmds.txt\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f mtalk.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"mtalk.1\"
else
echo shar: Extracting \"mtalk.1\" \(953 characters\)
sed "s/^X//" >mtalk.1 <<'END_OF_mtalk.1'
X.TH MTALK 1-Questar 
X.SH NAME
Xmtalk \- Multitalk multi-user Talk Parlour
X.SH ORIGIN
XQuestar Data Systems
X.SH SYNOPSIS
X.nf
Xmtalk
X.fi
X.SH DESCRIPTION
X.I mtalk 
Xis a multi-user conference program which can support up to 20 users at
Xthe same time. When you run
X.I mtalk
X, you actually run a shell script which then runs the main program and
Xis controlled in the 
X.I mtalk
Xdirectory which is defined upon compilation. This program allows you to have
Xeither public or private conversations with others who are logged into
Xthe program at that particular time. For information on the many commands,
Xand procedures for using
X.I mtalk
X, refer to you site administrator for copies of the manual.
X.nf
X.SH FILES
X/usr/local/bin/mtalk - script that runs multitalk.
X.SH BUGS
X.I mtalk
Xwill lose track of its loginfile if someone ctrl-C's out while in /auto. Other
Xthan that, the program is bulletproof.
X.SH AUTHOR
XAlbert Viall
X.\"	@(#)multitalk.c  2.0 (Questar)  8/9/89
END_OF_mtalk.1
if test 953 -ne `wc -c <mtalk.1`; then
    echo shar: \"mtalk.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f mtalk.man -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"mtalk.man\"
else
echo shar: Extracting \"mtalk.man\" \(1140 characters\)
sed "s/^X//" >mtalk.man <<'END_OF_mtalk.man'
X
X
X
XMTALK(1-Questar)  Pyramid OSx Operating System   MTALK(1-Questar)
X
X
X
XNAME
X     mtalk - Multitalk multi-user Talk Parlour
X
XORIGIN
X     Questar Data Systems
X
XSYNOPSIS
X     mtalk
X
XDESCRIPTION
X     _m_t_a_l_k is a multi-user conference program which can support
X     up to 20 users at the same time. When you run _m_t_a_l_k , you
X     actually run a shell script which then runs the main program
X     and is controlled in the _m_t_a_l_k directory which is defined
X     upon compilation. This program allows you to have either
X     public or private conversations with others who are logged
X     into the program at that particular time. For information on
X     the many commands, and procedures for using _m_t_a_l_k , refer to
X     you site administrator for copies of the manual.
X
XFILES
X     /usr/local/bin/mtalk - script that runs multitalk.
X
XBUGS
X     _m_t_a_l_k will lose track of its loginfile if someone ctrl-C's
X     out while in /auto. Other than that, the program is bullet-
X     proof.
X
XAUTHOR
X     Albert Viall
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XPrinted 12/27/89                                                1
X
X
X
END_OF_mtalk.man
echo shar: 25 control characters may be missing from \"mtalk.man\"
if test 1140 -ne `wc -c <mtalk.man`; then
    echo shar: \"mtalk.man\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f multitalk.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"multitalk.c\"
else
echo shar: Extracting \"multitalk.c\" \(37371 characters\)
sed "s/^X//" >multitalk.c <<'END_OF_multitalk.c'
X/***********************************************
X * 
X * MultiTalk - Talk Parlour
X * Multi-user Conferencing Program.
X *
X * Written and Developed by Albert Viall
X * WARNING: Do not remove this header or alter it
X *  in anyway. By releasing this source code into
X *  public domain, the author allows minor changes
X *  to the source code to suit the needs of the
X *  user.
X * 
X * (C)1989
X * All Rights Reserved
X **********************************************/
X
X
X#include <stdio.h>
X#include <ctype.h>
X#include <errno.h>
X#include <signal.h>
X#include <sgtty.h>
X#include <assert.h>
X#include <sys/file.h> 
X#include <sys/time.h> 
X#include "multitalk.h"
X
X#define BELL '\007'
X#define WRITELOCAL "m_local"
X#define WRITEALL   "m_all"
X#define SENDLOCAL  "s_local"
X#define SENDALL    "s_all"
X#define WHISPER    "m_whisper"
X#define SENDTO	   "s_to"
X
Xchar name[40],*myroom,myfile[35];
Xchar prompt[8];
Xint yellcnt,mypid,echo,master;
X
X/* Global structure used for loginfile
X * If you add or delete any login parameters, it must be
X * done here first
X */
Xstruct logon {
X	char thetty[12]; /* tty filename, i.e. /dev/ttyi34  */
X	char uid_name[8]; /* the system login name */
X	char logon_name[40]; /* Mtalk login name */
X	char room[11]; /* current room */
X	int thepid; /* this structures pidnumber */
X	} logon_info[MAXUSERS]; /* MAXUSERS is defined in multitalk.h */
Xint	cleanup();
X
Xmain()
X{
X	int x,z,y;
X	char str[256],junk[9],*myname,*getlogin(),*mytty,*ttyname();  
X
X	/* Perform a tidy cleanup upon signal.
X	 * Thank you for keeping your area clean.
X	 */ 
X	signal(SIGHUP,cleanup);
X	signal(SIGINT,cleanup);
X	security("compare",junk);  /* Am I in the purgefile? */
X	master=0;
X	mypid=getpid();
X	myname=getlogin();
X	mytty=ttyname(fileno(stdin));
X	/* set global 'myfile' to search for my commfile */
X	sprintf(myfile,"%s%d\0",PATH,mypid);  
X	fopen(myfile,"a");  /* Open my commfile just to make sure its there */
X	do_login();  
X        sprintf(str,"### %s was just escorted into the Talk Parlour on %s.",&name,mytty);
X	mwrite(SENDALL,"",str);
X	get_comfile(); 
X	do_message(myname,"read");
X	yellcnt=0;
X	echo=1;
X	sprintf(prompt,"Say? \0"); /* set default input prompt */
X	
X
X	/* main processing - things branch from here */
X	for(;;) {
X                str[0]='\0';
X		printf("%s",prompt);
X		gets(str);
X		
X		get_room();
X		/* is str a command? */
X		if (str[0]=='/') {
X			parse_cmd(str);
X			get_comfile();
X			continue;
X				}
X
X		/* did I input regular text? */
X		if (strlen(str) != 0) {
X			mwrite(WRITELOCAL,"",str);
X			get_comfile();
X			continue;  
X				}  
X		/* or did I hit a c/r */
X		if (strlen(str) == 0) {
X			get_comfile();
X			continue;
X			}
X
X
X		} /* end of main processing */
X} /* NOTREACHED */
X
Xchar     *
Xdate()  /* returns date and time in the 26 character format */
X{
X	long t;
X	register char *s;
X	char *ctime();
X
X	time(&t);
X	s=ctime(&t);
X	return s;
X}
X
Xvoid init_flds()
X{  
X	int t;
X	
X	/* This should be the first function to be called whenever a new
X	 * set of fields are incorporated into the array. It will
X	 * Initialize the entire array.
X	 */
X	for (t=0; t<MAXUSERS; t++) {
X		logon_info[t].thetty[0]='\0';
X		logon_info[t].uid_name[0]='\0';
X		logon_info[t].logon_name[0]='\0';
X		logon_info[t].room[0]='\0';
X		} 
X}
X
X
Xdo_login()
X{
X	/* This function performs all entry duties into the parlour
X	 * such as name input, status_display, and adding this entry
X	 * to the loginfile.
X	 */ 
X	int z;
X	FILE *lgnfd;
X	char *ttyname(), *getlogin(), *mytty, *myname,*room;
X	char byname[40],text[230];
X	int accessible; 
X
X	mytty=ttyname(fileno(stdin));
X	myname=getlogin();
X	check_max(); /* check on how many slots are being used */ 
X	/* Test access of lockfile and exit if found after user notify */
X	if ((strcmp(myname,HEADMOO)==0)) goto bypass; /* Icck! I hate goto's */
X	if ((accessible=access(LOCKFIL, 0))== 0) {
X                 	putchar(BELL);
X			printf("\n\nThe Task has been locked from further entry by the Caretaker.");
X			printf("\nFor further information, contact the Caretaker(%s)\n\n",HEADMOO);
X			exit(0);
X			}
Xbypass: /* like I said above, I hate goto's, but there was no choice here
X	 * this is written here to allow noone into Mtalk when it has been
X	 * LOCKED except for the Caretaker.
X	 */
X	printf("\n___________________________________________________________");
X	printf("\n Multi*Talk           Talk Parlour                 Ver1.2 ");
X	printf("\n      Multi-user Conferencing Program  by  Albert Viall");
X	printf("\n-----------------------------------------------------------\n");
X	printf("\n'Please sign-in at the Register' (%s): ", myname);
X	gets(byname);
X
X	if (strlen(byname) ==0) {
X                strcpy(byname,myname);
X		strcpy(name,myname);
X		} else {
X			strcpy(name,byname);
X			}
X	room="Reception"; 
X	myroom="Reception";
X	check_users(); /* Check the uniqueness of your name. */
X
X	if ((lgnfd=fopen(LGNFILE,"a")) == NULL) {
X		perror("do_login/lgnfd open error");
X		exit(-1); 
X				}
X
X	fprintf(lgnfd,"%s %s %s %s %d\n",mytty,myname,&byname,room,mypid);
X	fflush(lgnfd); fclose(lgnfd);
X    	status_display(); 
X
X 	printf("\nAll commands must be preceded by '/'. Type '/q' to Quit.\n");
X	printf("Type '/?' for commands. Type '/news' for current news.\n");
X	printf("\n'Greeves, the butler, escorts you into the Reception Hall.'\n");
X	/* show a login entry in the dayfile for this person. */
X	security("dayfile","Login ");
X			return;  
X}
X
Xparse_cmd(str)
Xchar *str;  
X{
X	/* This function parses an Mtalk commandline which is always
X	 * preceded by a '/'.
X	 */ 
X        FILE *lckfd,*pgfd;
X	int i;
X	int j=0;
X	int b,y,accessible;
X	char cmd[15],tty[8],ch;
X        char arg[15],ttybuf[13];
X        char obj[230],yell[230];
X	char bro[230],t_lock[35],m_togl[35];   
X	char *myname,*getlogin(),*mytty,*ttyname();
X
X	myname=getlogin();
X	mytty=ttyname(fileno(stdin)); 
X	obj[0]='\0';
X	/* This FOR loop spans the string looking for how many spaces it can
X	 * find. We are only worried about the first two which would incorporate
X	 * a complete command I.e. CMD ARG OBJ
X	 */	
X	    y=0;
X	for(i=0;i<strlen(str);i++) {
X		if (isspace(str[i])) y++;
X	/* If there is only one command argument. Null out ARG and OBJ */
X		}
X	if (y==0) {
X		sscanf(str,"%s",cmd);
X		arg[0]='\0';
X		obj[0]='\0';
X		}
X	/* If there are two arguments ONLY. Null out the OBJ  */
X	if (y==1) {
X		sscanf(str,"%s %s",cmd,arg);
X		obj[0]='\0';
X		}
X      	/* More than than 2 args? Scan for CMD and ARG, then construct
X	 * OBJ character by character ending with a NULL.
X	 */
X	if (y > 1) {
X		y=0;
X		sscanf(str,"%s %s",cmd,arg);
X        	for(i=0;!isspace(str[i]);i++) { continue; } 
X		for(i++;!isspace(str[i]);i++) { continue; }
X		for(i++;i<strlen(str);i++) {  
X			obj[y]=str[i];
X			y++;
X			}
X                obj[y]='\0';
X		y=0;
X		}
X	/*	printf("\nCMD:%s\nARG:%s\nOBJ:%s\n",cmd,arg,obj);  */ 
X        /* These string compares do the matching of the 'cmd' to whatever
X	 * command you are defining. All new commands MUST be defined in this
X	 * area.
X	*/  
X	if (b=strcmp(cmd, "/q") == 0) {
X                        do_logout(); 
X			exit(0);
X			}
X	if (b=strcmp(cmd, "/?") == 0) {
X                        read_text(CMDS,"pause"); 
X			return;
X			}
X	if (b=strcmp(cmd, "/auto") == 0) {
X			auto_mode(); 
X			return;
X			}
X	if (b=strcmp(cmd, "/echo") == 0) {
X			if (echo==1) {
X				echo=0;
X				printf("Echo Mode is OFF.\n");
X				return;
X				}
X			if (echo==0) {
X				echo=1;
X				printf("Echo Mode is ON.\n");
X				return;
X				}
X			return;
X			}
X	if (b=strcmp(cmd, "/news") == 0) {
X                        read_text(NEWS,"pause"); 
X			return;
X			}
X	if (b=strcmp(cmd, "/prompt") == 0) {
X			if (strlen(arg)==0) {
X				sprintf(prompt,"Say? \0");
X				return;
X				}
X			sprintf(prompt,"%s \0",arg);
X			return;
X			}
X	if (b=strcmp(cmd, "/whisper") == 0) {
X			if (strlen(arg)==0) {
X				printf("Usage is: /whisper [logon name] [mesg]\n");
X				return;
X				}
X			mwrite(WHISPER,arg,obj);
X			return;
X			}
X	/* by some of the following undocumented commands, you can see that
X	 * I intended for Mtalk to be somewhat humorous
X	 */ 
X	if (b=strcmp(cmd, "/wear") == 0) {
X			if (strlen(arg)==0) {
X				sprintf(bro,"`%s just put on a lampshade.'",&name);
X				mwrite(SENDLOCAL,"",bro);
X				return;
X				}
X			sprintf(bro,"`%s just put on %s %s'",&name,arg,obj);
X			mwrite(SENDLOCAL,"",bro);
X			return;
X			}
X	if (b=strcmp(cmd, "/drink") == 0) {
X			if (strlen(arg)==0) {
X				sprintf(bro,"`%s just drank some Coke.'",&name);
X				mwrite(SENDLOCAL,"",bro);
X				return;
X				}
X			sprintf(bro,"`%s just drank %s %s'",&name,arg,obj);
X			mwrite(SENDLOCAL,"",bro);
X			return;
X			}
X	if (b=strcmp(cmd, "/eat") == 0) {
X			if (strlen(arg)==0) {
X				sprintf(bro,"`%s just ate some potato chips.'",&name);
X				mwrite(SENDLOCAL,"",bro);
X				return;
X				}
X			sprintf(bro,"`%s just ate %s %s.'",&name,arg,obj);
X			mwrite(SENDLOCAL,"",bro);
X			return;
X			}
X	if (b=strcmp(cmd, "/throwup") == 0) {
X			if (strlen(arg)==0) {
X				sprintf(bro,"`%s just threw up.'",&name);
X				mwrite(SENDLOCAL,"",bro);
X				return;
X				}
X			sprintf(bro,"`%s just threw up %s %s.'",&name,arg,obj);
X			mwrite(SENDLOCAL,"",bro);
X			return;
X			}
X	if (b=strcmp(cmd, "/fart") == 0) {
X			sprintf(bro,"`%s just broke wind.'",&name);
X			mwrite(SENDLOCAL,"",bro);
X			return;
X			}
X	/* OKAY, Let's get back to serious */
X	if (b=strcmp(cmd, "/time") == 0) {
X                        printf("The Time is: %s",date()); 
X			return;
X			}
X	if (b=strcmp(cmd, "/status") == 0) {
X                        status_display(); 
X			return;
X			}
X	if (b=strcmp(cmd, "/moderator") == 0) {
X		if (strcmp(myroom,"Reception")!=0) {
X			if (master==1) {
X				moderator("unmaster","moo");
X				return;
X				} else {
X				moderator("master","moo");
X				return;
X				}
X			} else {
X			printf("You may not Moderate the Reception Hall.\n");
X			return;
X			}
X		}
X	if (b=strcmp(cmd, "/remove") == 0) {
X		if (strcmp(myroom,"Reception")!=0) {
X			if (master==1) {
X				moderator("remove",arg);
X				return;
X				}
X			printf("You are not the Moderator of this table.\n");
X			return;
X			} else {
X			printf("You may not Remove anyone from the Reception Hall.\n");
X			return;
X			}
X		}
X	if (b=strcmp(cmd, "/open") == 0) {
X		if (strcmp(myroom,"Reception")!=0) {
X			if (master==1) {
X				moderator("open","moo");
X				return;
X				}
X			printf("You are not the Moderator of this table.\n");
X			return;
X			} else {
X			printf("You may not Open/Close the Reception Hall.\n");
X			return;
X			}
X		}
X	if (b=strcmp(cmd, "/close") == 0) {
X		if (strcmp(myroom,"Reception")!=0) {
X			if (master==1) {
X				moderator("close","moo");
X				return;
X				}
X			printf("You are not the Moderator of this table.\n");
X			return;
X			} else {
X			printf("You may not Open/Close the Reception Hall.\n");
X			return;
X			}
X		}
X	if (b=strcmp(cmd, "/message") == 0) {
X			if (strlen(arg)==0) {
X				printf("You must specify someone to send it to.\n");
X				return;
X				}
X			do_message(arg,"write");
X			return;
X			}
X	if (b=strcmp(cmd, "/lock") == 0) {
X		if (y=strcmp(myname,HEADMOO)!=0) {
X			putchar(BELL); 
X			printf("This Command reserved for Caretaker.\n");
X                        return;  
X			}   
X                if ((accessible=access(LOCKFIL,0)) ==0) {
X			unlink(LOCKFIL);
X			security("dayfile","UNLOCK");
X			mwrite(SENDALL,"","`Greeves just opened the doors to the Parlour.'");
X			return;
X			} else { 
X			fopen(LOCKFIL,"a"); 
X				} 	
X			mwrite(SENDALL,"","`Greeves has just bolted the doors shut. No further entry is permitted.'");
X			security("dayfile","LOCK  ");
X			return;
X			}
X	if (b=strcmp(cmd, "/logoff") == 0) {
X		if (y=strcmp(myname,HEADMOO)!=0) {
X			putchar(BELL); 
X			printf("\nThis Command reserved for Caretaker.\n");
X                        return;  
X			}   
X		if (strlen(arg)==0) {
X			printf("You must specify someone to 'logoff'.\n");
X			return;
X			}
X		sprintf(bro,"### %s was just forcibly logged off by a Caretaker.",arg);
X		logoff(arg);
X		mwrite(SENDALL,"",bro);	
X		return;
X		}
X	if (b=strcmp(cmd, "/dayfile") == 0) {
X		if (y=strcmp(myname,HEADMOO)!=0) {
X			putchar(BELL); 
X			printf("\nThis Command reserved for Caretaker.\n");
X                        return;  
X			}   
X		printf("\nSTATUS - UID - LOGINAME - TIME DESCRIPTION\n");
X		printf("=============================================\n\n"); 
X		read_text(DAYFILE,"pause"); /* show dayfile and pause */
X		return;
X		}
X	if (b=strcmp(cmd, "/broadcast") == 0) {
X		if (y=strcmp(myname,HEADMOO)!=0) {
X			putchar(BELL); 
X			printf("This Command reserved for Caretaker.\n");
X                        return;  
X			}   
X		sprintf(bro,"### BROADCAST(%s): %s %s",&name,arg,obj);
X		mwrite(SENDALL,"",bro);
X		return;
X		}
X	if (b=strcmp(cmd, "/purge") == 0) {
X		if (y=strcmp(myname,HEADMOO)!=0) {
X			putchar(BELL); 
X			printf("This Command reserved for Caretaker.\n");
X                        return;  
X			}   
X		security("purge",arg); 
X		return;
X		}
X	if (b=strcmp(cmd, "/page") == 0) {
X			system("who | more");
X			printf("\nPage which TTY(i.e. ttyi19)?");
X			gets(tty);
X			sprintf(ttybuf,"/dev/%s",tty);
X			if ((pgfd=fopen(ttybuf,"w"))==NULL) {
X				perror("PAGE Device not found");
X				return;
X				}
X			fputc(BELL,pgfd);
X			fprintf(pgfd,"\n** %s(%s) Paged you to the Talk Parlour **\n respond with 'mtalk' , %s",myname,mytty,date());
X			fflush(pgfd); fclose(pgfd);
X			return;
X			}
X	if (b=strcmp(cmd, "/yell") == 0) {
X			sprintf(yell,"%s %s",arg,obj);
X			mwrite(WRITEALL,"",yell);
X			return;
X			}  
X	if (b=strcmp(cmd, "/sit") == 0) {
X			if (strlen(arg)==0) {
X				moderator("cleanup","moo");
X				moderator("unmaster","moo");	
X				sit("Reception");
X				printf("You get up and walk back to the Reception Hall.\n");
X				return;
X				}
X			sprintf(t_lock,"%s%s.LCK\0",PATH,arg);
X			if ((accessible=access(t_lock,0))==0) {
X				printf("The `%s' table has been closed from further entry.\n",arg);
X				return;
X				}
X			sit(arg);
X			printf("You sit down at the `%s' table.\n",arg);
X			return;
X			}  
X	if (b=strcmp(cmd, "/look") == 0) {
X      			if (strcmp(myroom,"Reception")==0) {
X				printf("You are in the Reception Hall.\n");
X				return;
X				}
X			printf("You are sitting at the `%s' table.\n",myroom);
X			sprintf(t_lock,"%s%s.LCK\0",PATH,myroom);
X			sprintf(m_togl,"%s%s.MAS\0",PATH,myroom);
X			if ((accessible=access(m_togl,0))==0) {
X				printf("This table is Moderated.\n");
X				}
X			if (master==1) {
X				printf("You are the Moderator.\n");
X				}
X			if ((accessible=access(t_lock,0))==0) {
X				printf("The table is Closed from further entry.\n");
X				}
X			return;
X			}  
X	/* Stupid? or what?? */	         
X	printf("Huh? I don't understand.\nType '/?' for commands.\n");	        
X	return;
X}
Xvoid status_display()
X{
X	/* This will display the user status of Mtalk. It also tests
X	 * to see if you are HEADMOO, and displays usefull information
X	 * for Caretakers eye's only.
X	 */
X	int z,y,i,max_i,accessible;
X	FILE *lgofd;
X	char shmoo[80],*myname,*getlogin();
X
X	if ((lgofd=fopen(LGNFILE,"r")) == NULL) { /* Open the loginfile */ 
X		perror("Open Error reading LGNFILE");
X		exit(-1);
X			}
X	myname=getlogin(); 
X	init_flds();
X        /* Read a line from LGOFD until EOF. Each line in loginfile consists
X	 * of info regarding each user logged into MTALK.
X	 */
X	max_i=0;
X	for (i=0; i<MAXUSERS; i++) {
X		if (feof(lgofd)) break;
X		fscanf(lgofd,"%s %s %s %s %d",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,&logon_info[i].thepid); 
X		} 
X        max_i=i-1;  
X	fclose(lgofd);
X
X	/* Okay, now format the header */
X        printf("\nThe following are currently in the Talk Parlour:");
X	printf("\n==================================================================");
X	printf("\n Name                           Terminal        Uid       Room    ");
X	printf("\n------------------------------------------------------------------");
X
X	/* Now print out status, all fields are left justified  */
X	for (i=0; i<max_i; i++) { 
X            if ((strcmp(logon_info[i].room,"Reception")==0)) {
X	          printf("\n%-17.17s             %-11.11s       %-8.8s %-10.10s",logon_info[i].logon_name,logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].room);
X                  continue;
X                                }  
X            if ((strcmp(logon_info[i].room,"Casino")==0)) {
X	          printf("\n%-17.17s             %-11.11s       %-8.8s %-10.10s",logon_info[i].logon_name,logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].room);
X                  continue;
X                                }  
X
X	          printf("\n%-17.17s             %-11.11s       %-8.8s *********",logon_info[i].logon_name,logon_info[i].thetty,logon_info[i].uid_name);
X                                 }
X        /* Print the trailer */ 
X	printf("\n==================================================================\n");
X	/* If I am HEADMOO, tell me if the task is locked */
X	if (y=strcmp(myname,HEADMOO)==0) {
X		if ((accessible=access(LOCKFIL,0))==0){
X			printf("\t\t\tThe Task is LOCKED.\n");
X			}
X		}  
X}  
Xvoid do_logout()
X{
X	/* This function performs a gracefull logout. What is done, is that
X	 * the loginfile is loaded into the logon_info array. Then, the
X	 * program matches you with your corresponding login entry and
X	 * NULLS it out. Lastly, the loginfile is unlinked and the remaining
X	 * entries are written to a new loginfile minus your's.
X	 */
X	int z,y,i,max_i;
X	FILE *lgofd; 
X	char *ttyname(), *getlogin(), *mytty, *myname,junk[230];
X
X	/* Initialize the array fields */
X	init_flds();
X	mytty=ttyname(fileno(stdin));
X	myname=getlogin();
X	sprintf(junk,"### %s just left the Talk Parlour on %s.",&name,mytty);
X	mwrite(SENDALL,"",junk);
X
X	/* Open this blasted file */
X	if ((lgofd=fopen(LGNFILE,"r+"))==NULL) {
X		perror("Open error on do_logout()");
X		exit(-1);
X		}
X	/* Read in the loginfile */
X	for (i=0; i<MAXUSERS; i++) {
X		if (feof(lgofd)) break;
X		fscanf(lgofd,"%s %s %s %s %d",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,&logon_info[i].thepid); 
X		} 
X        max_i=i-1; 
X	fclose(lgofd);
X
X	/* Compare Array 'thetty' to mine to get a match */
X	for (i=0; i<max_i; i++) {
X		if (strcmp(mytty,logon_info[i].thetty)==0) {
X			/* A match to my tty is found */
X			logon_info[i].thetty[0]='\0'; /* NULL it out */
X			break;
X			}
X		}
X	unlink(LGNFILE); /* We don't need it now, erase it */
X        /* Open the new loginfile */
X	if ((lgofd=fopen(LGNFILE,"a"))==NULL) {
X		perror("Open error on do_logout()2");
X		exit(-1);
X		}
X
X	/* Put the array into the new file except for mine */
X	for (i=0; i<max_i; i++) {
X		if (strlen(logon_info[i].thetty)!=0) {
X			fprintf(lgofd,"%s %s %s %s %d\n",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,logon_info[i].thepid);
X			}
X		continue;
X		}
X	fclose(lgofd);
X	get_comfile();
X	moderator("cleanup","moo");  /* Do this on the possibility that someone
X				* logs out while at a table.
X				*/
X	/* put entry into dayfile that I logged out */
X	security("dayfile","Logout");
X        printf("\nThanks for using M*Talk...\n");
X}
X 
Xread_text(news,pause) 
Xchar *news;
Xchar *pause; 
X{
X	/* This function will read a text file in one of two ways depending
X	 * upon the parameters it has been given. If "pause" is passed
X	 * it will display the file and pause every 23 lines and wait for
X	 * a c/r. Otherwise, "nopause" should be passed.
X	 */
X	FILE *rn;
X	int c,y,cnt;
X	char ch;
X
X	if ((rn=fopen(news,"r"))==NULL) {
X		return;
X		}
X	
X	if (y=strcmp(pause,"nopause") == 0) {
X		while ((c=getc(rn))!=EOF)
X			putc(c,stdout);
X
X		fclose(rn);  
X		return;
X		}
X
X	if (y=strcmp(pause,"pause") == 0) {
X		while ((c=getc(rn))!=EOF) {
X			if (c=='\n') cnt++;
X			if (cnt==23) {
X		 		printf("\n- 'Return' for more or 'q' to Quit -");
X			 	ch=getchar();
X				if (strcmp(ch,'q')==0) {
X					break;
X					} else {
X				printf("\013\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
X					cnt=0;
X					continue;
X					}
X				}
X			putc(c,stdout);
X			}
X		fclose(rn);
X		return;
X		}
X
X}  	
X
Xsit(where)
Xchar *where;
X{
X	/* function is self-explanatory. It corresponds to the /SIT
X	 * command.
X	 */
X
X	FILE *lgnfd,*outfd;
X	int max_i,i,y,accessible;
X	char *ttyname(),*getlogin(),*mytty,*myname,stuff[230],pid[5],t_lock[35];
X
X	sprintf(t_lock,"%s%s.LCK\0",PATH,where);
X
X	if ((lgnfd=fopen(LGNFILE,"r"))== NULL) {
X		perror("Open error on sit()/LGNFD");
X		return;
X		}
X        strcpy(myroom,where);
X	mytty=ttyname(fileno(stdin));
X	myname=getlogin();
X	init_flds(); /* Initialize the array */
X	max_i=0;
X	
X	/* Get the info */
X	for(i=0;i<MAXUSERS;i++) {
X		if (feof(lgnfd)) break;
X		fscanf(lgnfd,"%s %s %s %s %d",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,&logon_info[i].thepid); 
X		}
X	max_i=i-1;
X
X	/* Set my array table equal to my physical table */
X	for(i=0; i<max_i; i++) {
X		if (strcmp(mytty,logon_info[i].thetty)==0) {
X			strcpy(logon_info[i].room, myroom);
X			break;
X			}
X		continue;
X		}
X	/* Now tell everyone but me, that I sat down at their table */
X	for(i=0; i<max_i; i++) {
X		if (strlen(where)==0) break;  
X		if (strcmp(mytty,logon_info[i].thetty)==0) {
X			continue;
X			}
X		sprintf(pid,"%s%d",PATH,logon_info[i].thepid);
X		if (strcmp(logon_info[i].room,myroom) ==0) {
X			if ((outfd=fopen(pid,"a"))==NULL) {
X				perror("open error commfile/sit");
X				continue;
X				}
X			sprintf(stuff,"`%s' just sat down at your table.\n\0",&name);
X			fwrite(stuff,sizeof(char),strlen(stuff),outfd);
X			fflush(outfd); fclose(outfd);
X			continue;
X			}
X		continue;
X		}
X
X				
X	unlink(LGNFILE);
X	if ((outfd=fopen(LGNFILE,"a")) ==NULL) {
X		perror("sit()/outfd");
X		exit(-1);
X		}
X	for(i=0; i<max_i; i++) {
X			fprintf(outfd,"%s %s %s %s %d\n",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,logon_info[i].thepid);
X 			}
X	fclose(outfd);
X}
X
Xsecurity(which,who)
Xchar *which;
Xchar *who;
X{
X	/* This function deals with security specific operations.
X	 * Most notably, the /PURGE command. But also, handles the
X	 * dayfile entry.
X	 */
X	FILE *prgfd;
X	char *getlogin(),*myname,junk[9];
X
X	myname=getlogin();
X
X	if (strcmp(which,"purge")==0) {
X		if ((prgfd=fopen(PRGFILE,"a"))==NULL) {
X			perror("security/purge open error");
X			return;
X			}
X		fprintf(prgfd,"%s\n",who);
X		fflush(prgfd); fclose(prgfd);
X		printf("\n`%s' has now been purged from Mtalk.\n",who);
X		return;
X		}
X	if (strcmp(which,"dayfile")==0) {
X		if ((prgfd=fopen(DAYFILE,"a"))==NULL) {
X			perror("security/dayfile open error");
X			return;
X			}
X		fprintf(prgfd,"%s-%s-%s-%s",who,myname,&name,date());
X		fflush(prgfd); fclose(prgfd);
X		return;
X		}
X	if (strcmp(which,"compare")==0) {
X		if ((prgfd=fopen(PRGFILE,"r"))==NULL) {
X			return;
X			}   
X		for(;;) {
X			if (feof(prgfd)) break;
X			fscanf(prgfd,"%s",junk);
X			if (strcmp(myname,junk)==0) {
X				putchar(BELL); 
X				printf("\n**** Your access to M*talk has been removed indefinately.\n**** Please see the Caretaker for further info.\n");
X				exit(1);
X				}
X			continue;
X			}
X		return;
X		}
X} /* NOTREACHED End of Security function */
X
Xget_comfile()
X{
X	/* This function will read your corresponding commfile and then
X	 * unlink it to ready it for further appendages. 
X	 */
X	read_text(myfile,"nopause");
X	unlink(myfile);
X}
X
Xvoid check_max()
X{
X	/* This function checks to make sure there arent MAXUSERS on Mtalk
X	 * and is called before anything else.
X	 */
X	int z,y,i,max_i;
X	FILE *lgofd; 
X	char *ttyname(), *getlogin(), *mytty, *myname;
X
X	/* Initialize the array fields */
X	init_flds();
X	mytty=ttyname(fileno(stdin));
X	myname=getlogin();
X
X	/* Open this blasted file */
X	if ((lgofd=fopen(LGNFILE,"r+"))==NULL) {
X		perror("Warning: Open error on loginfile, no big deal.");
X		return;
X		}
X	for (i=0; i<MAXUSERS; i++) {
X		if (feof(lgofd)) break;
X		fscanf(lgofd,"%s %s %s %s %d",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,&logon_info[i].thepid); 
X		} 
X        max_i=i-1; 
X	fclose(lgofd);
X	if (max_i < MAXUSERS) {
X		return;
X		}
X	putchar(BELL);
X	printf("\n\n*** Sorry, M*Talk is full right Now. Try again later. ***\n\n");
X	exit(0);
X}
Xauto_mode()
X{
X	/* The function for /AUTO. Here, we must change the term. 
X	 * characteristics, and then build a bitmap of the file descriptors
X	 * we are interested in looking at. In this case, stdin does just fine.
X	 * Then, we delay one second, so as not to tie anything up, and 
X	 * constantly check for our commfile. If it's there, display it.
X	 */
X	int accessible, mypid, template[2], mask[2], st;
X	struct sgttyb ttysettings;
X	struct timeval delay;
X
X	/* set the terminal characteristics */
X	assert(ioctl(fileno(stdin), TIOCGETP, &ttysettings) ==0);
X	ttysettings.sg_flags &= (~ECHO); /* no echo */
X	ttysettings.sg_flags |= CBREAK; /* half raw, still allows signals */
X	template[fileno(stdin)/32] = 1 << (fileno(stdin)%32);
X
X	delay.tv_sec=1;
X	delay.tv_usec=0;
X
X	printf("\nAuto Mode - Press `ENTER' to abort.\n");
X	for(;;) {
X		int n;
X		/* We must do this copy because select smashes the mask all
X		 * to hell each time it is called.
X		 */
X		(void) bcopy(template,mask,2 * sizeof(int));
X		assert(n=select(1,mask,0L,0L,&delay) >= 0);
X
X	/* If input pending, store it and read it. Mask is now hosed */
X	if (n && (mask[fileno(stdin)/32] & (1 << (fileno(stdin)%32)))) {
X		char c;
X		assert(read(fileno(stdin),&c,sizeof(char)) > 0);
X		if (c=='\n') break;
X		}
X	/* if Myfile is there, read the thing */
X	if ((accessible=access(myfile,0))==0) {
X		get_comfile();
X		continue;
X		}
X	}
X	/* Reset the terminal. This should really be a signal call, in case
X	 * someone hits control-C, but most people use TCSH, and the shell
X	 * does all that for us.
X	 */	
X	ttysettings.sg_flags |= ECHO;
X	ttysettings.sg_flags &= (~CBREAK);
X	assert(ioctl(fileno(stdin), TIOCSETP, &ttysettings)==0);
X	return;
X}
Xcleanup(sig)
X{
X	/* This routine provides a tidy exit from the program upon
X	 * an ungracefull exit by the user. This routine is used only
X	 * with the signal calls shown at the beginning of this
X 	 * source code.
X	 */
X	kill(mypid,SIGHUP); 
X	do_logout();
X	exit(0);
X}
Xvoid check_users() 
X{
X	/* This function compares your name that you inputted with the
X	 * logonnames which are in the parlour at your login. If we get
X	 * a match, then we can't let you in. Must not have more than one
X	 * person of the same name online.
X	 */
X	int z,y,i,max_i,accessible;
X	FILE *lgofd;
X	char shmoo[80],*myname,*getlogin();
X
X	if ((lgofd=fopen(LGNFILE,"r")) == NULL) { /* Open the loginfile */ 
X		perror("Warning: Open Error reading loginfile, no big deal.");
X		return;
X			}
X	myname=getlogin(); 
X	init_flds();
X        /* Read a line from LGOFD until EOF. Each line in loginfile consists
X	 * of info regarding each user logged into MTALK.
X	 */
X	max_i=0;
X	for (i=0; i<MAXUSERS; i++) {
X		if (feof(lgofd)) break;
X		fscanf(lgofd,"%s %s %s %s %d",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,&logon_info[i].thepid); 
X		} 
X        max_i=i-1;  
X	fclose(lgofd);
X
X	/* Now compare all the logonnames. */
X	for (i=0; i<max_i; i++) {
X		if (strcmp(&name,logon_info[i].logon_name)==0) {
X			putchar(BELL);
X			printf("\n\nThat Name is already in use. Try another name.\n\n");
X			exit(-1);
X			}
X		continue;
X		}
X}
Xdo_message(who,what)
Xchar *who;
Xchar *what;
X{
X	FILE *msgfd;
X	int y,accessible,i,lineno;
X	char *myname, *getlogin(), stuff[20], msg[80], file[35],ch;
X	struct message {
X		char line[80];
X		} text[20];
X
X	myname=getlogin();
X	sprintf(file,"%s%s\0",PATH,who);
X
X	if (strcmp(what,"write")==0) {
X		printf("\nGreeves says,`You wish to write a small message to (%s)?'\n`First, make sure that is the correct logon for this person.'\n",who);
X		printf("\nContinue(yes or no)?");
X		gets(stuff);
X		if (strcmp(stuff,"no")==0) { return; }
X		if (strlen(stuff)==0) return;
X
X		sprintf(msg,"********* A message from (%s), sent on %s\n",myname,date());
X		lineno=1;
X		printf("\nMessage to (%s) on %sYou may write up to 20 lines. End the message with a 'blank' line.\n\n",who,date());
X		for (i=0; i<20; i++) {
X			printf("%d> ",lineno);
X			gets(text[i].line);
X			if (strlen(text[i].line)==0) break;
X			lineno++;
X			}
X		printf("Do you want to (s)end it, or (f)orget it? ");
X		ch=getchar();
X		
X		switch(ch) {
X			case 's':
X				break;
X			case 'f':
X				printf("\n`Nothing sent..'");
X				return;
X			default:
X				printf("\n`Nothing sent..'");
X				return;
X			}
X
X				
X		if ((msgfd=fopen(file,"a"))==NULL) {
X			perror("error on msgfd");
X			return;
X			}
X		fprintf(msgfd,"-------------------------------------------------------------------\n");
X		fprintf(msgfd,"%s\0",msg);
X		for (i=0; i<lineno; i++) {
X			fprintf(msgfd,"%s\n\0",text[i].line);
X			}
X		fprintf(msgfd,"-------------------------------------------------------------------\n");
X		fflush(msgfd); fclose(msgfd);
X		printf("\nGreeves says,`Allright %s, when I see %s, I shall givehim/her the message.'\n",&name,who);
X		sprintf(file,"Wmsg (%s)\0",who);
X		security("dayfile",file);	
X		return;
X		}
X
X	if (strcmp(what,"read")==0) {
X		if ((accessible=access(file,0))==0) {
X			putchar(BELL);
X			printf("\nGreeves says,`Excuse me, I believe you have a message.'\n Would you like it now(yes or no)?");
X			gets(stuff);
X			if (strlen(stuff)==0) return;
X			if (strcmp(stuff,"no")==0) {
X				printf("\nGreeves says,`Allright %s, I shall save it for you until later.'\n\n",&name);
X				return;
X				}
X
X			printf("\n`Greeves hands you a piece of paper and then leaves.'\n");
X			read_text(file,"pause");
X			unlink(file);
X			return;
X			}
X		return;
X		}
X}
X
Xmoderator(what,who)
Xchar *what;
Xchar *who;
X{
X	FILE *lgnfd,*outfd;
X	int max_i,i,accessible;
X	char stuff[80],*myname,*getlogin(),m_togl[35],t_lock[35];
X
X	sprintf(t_lock,"%s%s.LCK\0",PATH,myroom);
X	sprintf(m_togl,"%s%s.MAS\0",PATH,myroom);
X
X	myname=getlogin();
X
X	if (strcmp(what,"master")==0) {
X		if (((accessible=access(m_togl,0))==0)&&(master==1)) {
X			printf("You are already Moderator of this table.\n");
X			return;
X			}
X		if (((accessible=access(m_togl,0))==0)&&(master==0)) {
X			printf("Someone is already Moderator of this table.\n");
X			return;
X			}
X		master=1;
X		sprintf(stuff,"`%s' is now Moderator of this table.",&name);
X		mwrite(SENDLOCAL,"",stuff);
X		fopen(m_togl,"a");
X		return;
X		}
X	if (strcmp(what,"unmaster")==0) {
X		if (((accessible=access(m_togl,0))==0)&&(master==1)) {
X			unlink(m_togl);
X			master=0;
X			return;
X			}
X		return;
X		}
X
X	if (strcmp(what,"close")==0) {
X		if (((accessible=access(t_lock,0))==0)&&(master==1)) {
X			printf("This table is already Closed.\n");
X			return;
X			}
X		fopen(t_lock,"a");
X		sprintf(stuff,"`%s' has just Closed this table from further entry.",&name);
X		mwrite(SENDLOCAL,"",stuff);
X		return;
X		}
X	if (strcmp(what,"open")==0) {
X		if (((accessible=access(t_lock,0))!=0)&&(master==1)) {
X			printf("This table is already Open.\n");
X			return;
X			}
X		unlink(t_lock);
X		sprintf(stuff,"`%s' has just Opened this table.",&name);
X		mwrite(SENDLOCAL,"",stuff);
X		return;
X		}
X	if (strcmp(what,"cleanup")==0) {
X		if (((accessible=access(m_togl,0))==0)&&(master==1)) {
X			unlink(m_togl);
X			}
X		if (((accessible=access(t_lock,0))==0)&&(master==1)) {
X			unlink(t_lock);
X			}
X		return;
X		}
X	if (strcmp(what,"remove")==0) {
X	  if (strcmp(who,&name)==0) {
X		printf("You can't 'remove' yourself from a table.\n");
X		return;
X		}
X	  if ((lgnfd=fopen(LGNFILE,"r"))== NULL) {
X		perror("Open error on sit()/LGNFD");
X		return;
X		}
X	  init_flds(); /* Initialize the array */
X	  max_i=0;
X	
X	  /* Get the info */
X	  for(i=0;i<MAXUSERS;i++) {
X		if (feof(lgnfd)) break;
X		fscanf(lgnfd,"%s %s %s %s %d",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,&logon_info[i].thepid); 
X		}
X		fclose(lgnfd);
X	  max_i=i-1;
X	for(i=0;i<max_i;i++) {
X		if ((strcmp(logon_info[i].logon_name,who)==0)&&(strcmp(logon_info[i].room,myroom)==0)) {
X			sprintf(stuff,"*** `%s' was just removed from the table by the Moderator.",who);
X			mwrite(SENDLOCAL,"",stuff);
X			strcpy(logon_info[i].room,"Reception");
X			break;
X			}
X		continue;
X		}
X	unlink(LGNFILE);
X	if ((outfd=fopen(LGNFILE,"a"))==NULL) {
X		perror("/master - remove");
X		return;
X		}
X	for(i=0; i<max_i; i++) {
X			fprintf(outfd,"%s %s %s %s %d\n",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,logon_info[i].thepid);
X 			}
X	fclose(outfd);
X	}
X
X}
Xget_room()
X{
X	FILE *lgnfd;
X	int i,y,max_i;
X	char *mytty,*ttyname();
X	
X	  if ((lgnfd=fopen(LGNFILE,"r"))== NULL) {
X		perror("Open error on sit()/LGNFD");
X		return;
X		}
X	  init_flds(); /* Initialize the array */
X	  max_i=0;
X	mytty=ttyname(fileno(stdin));
X	
X	  /* Get the info */
X	  for(i=0;i<MAXUSERS;i++) {
X		if (feof(lgnfd)) break;
X		fscanf(lgnfd,"%s %s %s %s %d",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,&logon_info[i].thepid); 
X		}
X		fclose(lgnfd);
X	  max_i=i-1;
X	for(i=0;i<max_i;i++) {
X		if (strcmp(mytty,logon_info[i].thetty)==0) {
X			strcpy(myroom,logon_info[i].room);
X			break;
X			}
X		continue;
X		}
X	return;
X}
X
Xmwrite(attr,who,msg)
Xchar *attr;
Xchar *who;
Xchar *msg;
X{
X	/* Mwrite() is the core of the whole Mtalk program. Given the
X	 * different attributes as parameters, this function controls all
X	 * of the input/output to the other users in Mtalk.
X	 */    
X	FILE *lgnfd,*outfd;
X	int max_i,i,accessible,y;
X	char *ttyname(),*getlogin(),*mytty,*myname,pid[5],stuff[230];
X
X
X	if ((lgnfd=fopen(LGNFILE,"r"))== NULL) {
X		perror("Open error on Mwrite/LGNFD");
X		return;
X		}
X
X	mytty=ttyname(fileno(stdin));
X	myname=getlogin();
X	init_flds(); /* Initialize the array */
X	max_i=0;
X	
X	/* Get the info & fill the structure */
X	for(i=0;i<MAXUSERS;i++) {
X		if (feof(lgnfd)) break;
X		fscanf(lgnfd,"%s %s %s %s %d",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,&logon_info[i].thepid); 
X		}
X	max_i=i-1; /* max_i is physical number of users. I have to do this */
X	fclose(lgnfd);
X
X
X	if (strcmp(attr,"m_local")==0) {
X		for(i=0;i<max_i;i++) {
X		if ((y=strcmp(logon_info[i].logon_name,&name)==0)&&(echo==0)) {
X			continue; }
X		sprintf(pid,"%s%d",PATH,logon_info[i].thepid);
X		if (y=strcmp(logon_info[i].room, myroom) == 0) {  
X			if ((outfd=fopen(pid,"a"))==NULL) {
X				perror("Open error to %s",logon_info[i].thetty);
X				continue;
X				}
X			fprintf(outfd,"%s says,`%s'\n",&name,msg);
X		if (max_i==1) {
X			fprintf(outfd,"Greeves says,`Talking to yourself again, %s? I see.'\n",&name);
X			}
X			fflush(outfd);fclose(outfd);
X     			}  
X		}  
X	}
X
X	if (strcmp(attr,"m_all")==0) {
X		for(i=0;i<max_i;i++) {
X		if ((y=strcmp(logon_info[i].logon_name,&name)==0)&&(echo==0)) {
X			continue; }
X			sprintf(pid,"%s%d",PATH,logon_info[i].thepid);  
X			if ((outfd=fopen(pid,"a"))==NULL) {
X				perror("Open error to %s",logon_info[i].thetty);
X				continue;
X				}
X			sprintf(stuff,"%s yells,`%s'\n",&name,msg);
X                        fwrite(stuff, sizeof(char), strlen(stuff), outfd);
X			fflush(outfd);fclose(outfd);
X		}
X	/* So as not to abuse the /YELL command and have people ticked off
X	 * at you for disturbing their conversation with rash yells, I built
X	 * in this humorous yell counter. Feel free to change the counts
X	 * and/or the printf's
X	 */
X		yellcnt=yellcnt+1;
X		if (yellcnt==3) {
X			printf("Greeves says,`Could you please keep it down. You are disturbing others.\n");
X		}
X		if (yellcnt==4) {
X			printf("Greeves says,`One more outburst like that, and you will have to leave.\n");
X		}
X		if (yellcnt==5) {
X			printf("Greeves says,`Allright buster, you've had it!!\n");
X			printf("`Greeves takes you by the scruff of the neck and boots you out the door.'\n");
X			sprintf(stuff,"### %s was just forcibly removed by the butler for yelling too much.\n\0",&name);
X			mwrite(SENDALL,"",stuff);
X			do_logout();
X			exit(0);
X		}
X	}
X	if (strcmp(attr,"s_local")==0) {
X
X		for(i=0;i<max_i;i++) {
X		sprintf(pid,"%s%d",PATH,logon_info[i].thepid);
X		if (y=strcmp(logon_info[i].room, myroom) == 0) {  
X			if ((outfd=fopen(pid,"a"))==NULL) {
X				perror("Open error to %s",logon_info[i].thetty);
X				continue;
X				}
X			sprintf(stuff,"%s\n\0",msg);
X			fwrite(stuff,sizeof(char),strlen(stuff),outfd);
X			fflush(outfd);fclose(outfd);
X     			}  
X		}  
X	}
X	if (strcmp(attr,"s_all")==0) {
X
X		for(i=0;i<max_i;i++) {
X			sprintf(pid,"%s%d",PATH,logon_info[i].thepid);
X			if ((outfd=fopen(pid,"a"))==NULL) {
X				perror("Open error to %s",logon_info[i].thetty);
X				continue;
X				}
X			sprintf(stuff,"%s\n\0",msg);
X			fwrite(stuff, sizeof(char), strlen(stuff), outfd);
X			fflush(outfd);fclose(outfd);
X		}
X	}
X	if (strcmp(attr,"m_whisper")==0) {
X
X		for(i=0;i<max_i;i++) {
X			sprintf(pid,"%s%d",PATH,logon_info[i].thepid); 
X			if (strcmp(logon_info[i].logon_name,who)==0) {
X				if ((outfd=fopen(pid,"a"))==NULL) {
X				perror("Open error to %s",logon_info[i].thetty);
X				return;
X				}
X				sprintf(stuff,"%s whispers, `%s'\n",&name,msg);
X				fwrite(stuff, sizeof(char), strlen(stuff), outfd);
X				fflush(outfd); fclose(outfd);
X				return;
X				}
X			continue;
X			}
X		printf("`%s' is not logged into Mtalk.\n",who);
X	}
X} /** End of Mwrite function **/
Xlogoff(who)
Xchar *who;
X{
X
X	FILE *lgnfd,*outfd;
X	int max_i,i,accessible,y;
X	char *ttyname(),*getlogin(),*mytty,*myname,pid[5],stuff[80];
X
X
X	if ((lgnfd=fopen(LGNFILE,"r"))== NULL) {
X		perror("Open error on Mwrite/LGNFD");
X		return;
X		}
X
X	mytty=ttyname(fileno(stdin));
X	myname=getlogin();
X	init_flds(); /* Initialize the array */
X	max_i=0;
X	
X	/* Get the info & fill the structure */
X	for(i=0;i<MAXUSERS;i++) {
X		if (feof(lgnfd)) break;
X		fscanf(lgnfd,"%s %s %s %s %d",logon_info[i].thetty,logon_info[i].uid_name,logon_info[i].logon_name,logon_info[i].room,&logon_info[i].thepid); 
X		}
X	max_i=i-1; /* max_i is physical number of users. I have to do this */
X	fclose(lgnfd);
X
X	for(i=0;i<max_i;i++) {
X		if (strcmp(who,logon_info[i].logon_name)==0) {
X			kill(logon_info[i].thepid,SIGINT);
X			return;
X		}
X	continue;
X	} /* Reached if Unsuccessful */
X	printf("That person is not logged on.");
X	return;
X} /* Notreached  */
X
X
END_OF_multitalk.c
if test 37371 -ne `wc -c <multitalk.c`; then
    echo shar: \"multitalk.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f multitalk.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"multitalk.h\"
else
echo shar: Extracting \"multitalk.h\" \(1088 characters\)
sed "s/^X//" >multitalk.h <<'END_OF_multitalk.h'
X/***************************************
X * Multitalk.h -  Albert Viall
X * (C) 1989
X * Global macros for certain file accesses
X *  This file may be changed to reflect any location changes for
X *  any/or all files associated with Multitalk.
X **************************************/
X
X#define LGNFILE  "/u1/prg/al/C/TALK/loginfile"  /* login records file */
X#define PATH     "/u1/prg/al/C/TALK/" /* Path for CommFiles */
X#define GAME     "/u1/prg/al/C/TALK/multitalk"  /* actual game  */ 
X#define NEWS     "/u1/prg/al/C/TALK/news.txt"   /* news file, if any */ 
X#define CMDS     "/u1/prg/al/C/TALK/cmds.txt"   /* list of commands */  
X#define DAYFILE  "/u1/prg/al/C/TALK/.dayfile"    /* daily logon report */ 
X#define LOCKFIL  "/u1/prg/al/C/TALK/.tasklock"  /* is TASK Locked     */
X#define PRGFILE  "/u1/prg/al/C/TALK/.purgefile" /* Purged user file   */
X#define HEADMOO  "al" /* This is defined as the Caretaker */
X#define MAXUSERS 10 /* Please keep this reasonable, it should never be   
X		     * raised to more than 20, unless you KNOW that your
X		     * system can hadle it.
X		     */
X
END_OF_multitalk.h
if test 1088 -ne `wc -c <multitalk.h`; then
    echo shar: \"multitalk.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f news.txt -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"news.txt\"
else
echo shar: Extracting \"news.txt\" \(319 characters\)
sed "s/^X//" >news.txt <<'END_OF_news.txt'
X
XMultiTalk News: 1/25/90 
X	New Commands that have been installed since 1/14/90 are a new /message
X and the /logoff command. /logoff allows the Caretaker to forcibly logoff a
X obnoxious user. Mtalk is now up to Ver.1.2, after correcting messy displays
X and fixing two bugs pertaining to the loginfile during 'login'.
X
X
X
END_OF_news.txt
if test 319 -ne `wc -c <news.txt`; then
    echo shar: \"news.txt\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
-- 
| INTERNET: al@questar.QUESTAR.MN.ORG      |    NEW PRODUCT ON THE MARKET     |
|     UUCP: ..!amdahl!tcnet!questar!al     |        "Flame in a Can"          |
|  FIDONET: 1/282:2,3 (Al Viall)           | Just tear off the protective     |
| "MMMMMMM. And so good for you!"          | seal, point and shoot. Great fun!|


--- End of forwarded message from Al Viall <uunet.uu.net!questar!al@tektronix.TEK.COM>


-- 

	-Bill Randle
	Tektronix, Inc.
	billr@saab.CNA.TEK.COM