[alt.sources] Multi-user chat program

darcy@druid.uucp (D'Arcy J.M. Cain) (10/10/90)

This is the multi user chat program what I mentioned in comp.unix.questions
last week.  Since the requests for it have been high I am posting it here
instead of mailing it individually to everyone who asked for it.

#!/bin/sh
# This is a shell archive (shar 3.10)
# made 08/21/1990 14:40 UTC by darcy@druid
# Source directory /usr/darcy/work/Chat
#
# existing files will NOT be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   9136 -r--r--r-- chat.c
#   3908 -r--r--r-- chatter.c
#   1568 -r--r--r-- chc_msg.c
#   2327 -r--r--r-- chs_msg.c
#    537 -r-xr--r-- lchat
#    682 -r-xr-xr-x chatyell
#   2516 -r--r--r-- chat.readme
#    520 -r--r--r-- chat.make
#
touch 2>&1 | fgrep '[-amc]' > /tmp/s3_touch$$
if [ -s /tmp/s3_touch$$ ]
then
	TOUCH=can
else
	TOUCH=cannot
fi
rm -f /tmp/s3_touch$$
# ============= chat.c ==============
if test -f chat.c; then echo "File chat.c exists"; else
echo "x - extracting chat.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > chat.c &&
X/*
X
Xchat
XWritten by D'Arcy J.M. Cain
XAll rights reserved
X
XThis is the front end to the chatter program.  It is run by any number
Xof users who wish to communicate conference style with each other.  The
Xchatter program serves each user.
X
XPermission is hereby granted to freely copy and redistribute this
Xsoftware, provided that the author is clearly credited in all
Xcopies and derivations.  This software is provided ``As Is'' and
Xwithout any express or implied warranties.
X
X*/
X
X#include	<stdio.h>
X#include	<stdlib.h>
X#include	<string.h>
X#include	<curses.h>
X#include	<signal.h>
X#include	<process.h>
X#include	<getopt.h>
X#include	<ctype.h>
X#include	<errno.h>
X#include	"chat.h"
X
Xchar chat_rcsid[] = "$Id: chat.c,v 1.1 90/08/19 19:03:22 darcy Exp $";
X
X#ifndef	NO_CHG_NAME
Xstatic char	*options = "hn:f:";
X#else
Xstatic char	*options = "hf:";
X#endif
X
Xstatic FILE		*cap_file = NULL;
Xstatic WINDOW	*disp, *inp;
X
X#ifdef	HALFDELAY_BROKEN
Xint		chat_suspended = 0;
X#endif
X
Xvoid	cleanup(void)		/* come here on just about any signal */
X{
X	while (chk_q())					/* clean up your own mess */
X		;
X
X	if (cap_file != NULL)
X		fclose(cap_file);
X
X	chc_send("x");
X
X	mvwprintw(inp, 1, 1, "%-77s", "    So long...   It's been nice chatting");
X	wrefresh(disp);					/* display any leftovers */
X	wrefresh(inp);					/* display polite message */
X
X	delwin(disp);
X	delwin(inp);
X	endwin();
X	ch_close();
X	exit(0);
X}
X
Xvoid	disp_str(char *str)	/* add latest string to list just above box */
X{
X	scroll(disp);				/* make room for it first */
X	mvwprintw(disp, LINES - 5, 0, "%s", str);
X
X	if (cap_file != NULL)		/* save to file if it is open */
X		fprintf(cap_file, "%s\n", str);
X}
X
Xstatic int	need_to_refresh = 0;
X
Xint		chk_q(void)
X{
X	char	msgbuf[256];
X
X	if (ch_get(msgbuf))
X	{
X		disp_str(msgbuf);			/*let user know what chatter has to say */
X
X		if (*msgbuf == 'e')			/* is chatter telling us to get lost? */
X		{
X			wrefresh(disp);			/* display anything pending */
X			cleanup();				/* take the Big Sleep */
X		}
X
X		need_to_refresh = -1;
X		return(1);					/* let caller know */
X	}
X
X	return(0);						/* nothing happened */
X}
X
X#ifndef	NO_SH_ESC
Xstatic void	run_command(char *s)
X{
X	int		status, pid, w, tty;
X	void	(*istat)(), (*qstat)();
X
X	if ((tty = open("/dev/tty", 2)) == -1)
X	{
X		fprintf(stderr, "Can't open /dev/tty\n");
X		return;
X	}
X
X	if ((pid = fork()) == 0)
X	{
X		close(0); dup(tty);
X		close(1); dup(tty);
X		close(1); dup(tty);
X		close(tty);
X		execlp("sh", "sh", (*s ? "-c" : NULL), s, NULL);
X		exit(0);		/* note:  We don't care about failure here */
X	}
X
X	close(tty);
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X
X	while ((w = wait(&status)) != pid)
X		if ((w == -1) && (errno != EINTR))
X			break;
X
X	signal(SIGINT, istat);
X	signal(SIGQUIT, qstat);
X}
X#endif
X
Xvoid	help(void)
X{
X	WINDOW	*w;
X	int		k;
X	static char *help_msg[] = {
X		"CHAT - multi user conference utility",
X		"Written by D'Arcy J.M. Cain (darcy@druid.uucp)",
X		"Copyright 1990 - All rights reserved",
X		"$Revision: 1.1 $\b " + 1,
X		"",
X		"chat commands consist of a slash (/) followed by a command",
X		"   ?     this Help screen",
X#ifndef	NO_SH_ESC
X		"   !     shell Escape",
X#endif
X		"   c     Change channel i.e: \"/c3\" - change to channel 3",
X		"         Note: \"/c*\" will change to first empty channel",
X		"   h     Same as ?",
X#ifndef	NO_CHG_NAME
X		"   n     change Name to following string",
X#endif
X		"   r     Redraw screen",
X#ifndef	NO_SHOW_USERS
X		"   s     Show current users using chat",
X#endif
X		"   x     eXit from chat",
X		"",
X		"                       Hit a key to continue ..."
X	};
X#define	HELP_SZ	(sizeof(help_msg)/sizeof(char *))	
X
X	w = newwin(HELP_SZ + 3, 71, 1, 3);	/* get a new window */
X	box(w, 0, 0);						/* and box it */
X
X	for (k = 0; k < HELP_SZ; k++)		/*  display the help screen */
X		mvwprintw(w, k + 1, 3, "%s", help_msg[k]);
X
X	wrefresh(w);		/* show the screen */
X
X	while (wgetch(w) == ERR)
X		;				/* wait for keystroke */
X
X	delwin(w);			/* clear the window */
X	touchwin(disp);		/* update display window */
X	wrefresh(disp);		/* get everything back in sync */
X	wrefresh(inp);
X}
X
Xint		main(int argc, char **argv)
X{
X	int		c;
X	char	entry[512], *ptr = NULL, *ptr1, msgbuf[256];
X
X	if ((ptr1 = ch_init()) != NULL)
X	{
X		perror(ptr1);
X		return(1);
X	}
X
X	/* curses stuff */
X	initscr();
X	nonl();
X	noecho();
X	cbreak();
X#ifndef	HALFDELAY_BROKEN
X	halfdelay(20);
X#endif
X
X	/* make sure we always exit through cleanup */
X	signal(SIGINT, cleanup);
X	signal(SIGABRT, cleanup);
X	signal(SIGQUIT, cleanup);
X	signal(SIGKILL, cleanup);
X	signal(SIGTERM, cleanup);
X
X	disp = newwin(LINES - 4, COLS, 0, 0);	/* conversation window */
X	idlok(disp, TRUE);
X	scrollok(disp, TRUE);
X
X	inp = newwin(3, COLS, LINES - 4, 0);	/* input window */
X	box(inp, 0, 0);
X
X	mvwprintw(inp, 1, 1, "-> ");			/* prompt string */
X
X	while ((c = getopt(argc, argv, options)) != -1)
X	{
X		switch (c)
X		{
X			case '?':
X			default:
X				sprintf(entry, "%s: Invalid option %c", argv[0], c);
X				disp_str(entry);
X
X			case 'h':
X				sprintf(entry,
X#ifndef	NO_CHG_NAME
X					"Usage: %s [-h] [-c channel] [-n name] [-f file]",
X#else
X					"Usage: %s [-h] [-c channel] [-f file]",
X#endif
X					argv[0]);
X				disp_str(entry);
X				cleanup();
X				break;
X
X#ifndef	NO_CHG_NAME
X			case 'n':
X				ptr = optarg;
X				break;
X#endif
X
X			case 'f':
X				if ((cap_file = fopen(optarg, "a")) == NULL)
X				{
X					sprintf(entry, "Can't open log file: %s", SYS_ERRLIST);
X					cleanup();
X				}
X				break;
X		}
X	}
X	
X	disp_str("chat - multi user conferencing utility");	/* signon string */
X	disp_str("Written by D'Arcy J.M. Cain");
X	disp_str("Copyright 1990 by D'Arcy J.M. Cain - All rights reserved");
X	disp_str("$Revision: 1.1 $\b " + 1);
X	disp_str("");
X
X	/* open chat link */
X	ch_init();
X	sprintf(entry, "o%s", (ptr == NULL) ? cuserid(NULL) : ptr);
X	chc_send(entry);
X	sleep(1);								/* messages are not FIFO     */
X
X	disp_str("Enter /h or /? for help");
X	disp_str("");
X	wrefresh(disp);
X
X	ptr = entry;
X	chc_send("s");							/* get list of current users */
X
X	for (;;)					/* loop till the cows come home */
X	{
X		while (chk_q())
X			;
X
X		if (need_to_refresh)
X			wrefresh(disp);		/* refresh display if necessary*/
X
X		wrefresh(inp);			/* refresh this to place cursor */
X
X		if ((c = wgetch(inp)) != ERR);	/* if got a character (not timed out) */
X		{
X			if (c == 4)
X				cleanup();	/* end of session ? */
X
X			if (c == '\r')	/* end of line ? */
X			{
X				*ptr = 0;					
X
X				if (*entry == '/')		/* command? */
X				{
X					switch (entry[1])
X					{
X						case '?':		/* request for help */
X						case 'h':
X							help();
X							break;
X
X#ifndef	NO_SH_ESC
X						case '!':		/* shell escape */
X							ptr = entry + 2;
X							while (isspace(*ptr))
X								ptr++;
X
X#ifdef	HALFDELAY_BROKEN
X							chat_suspended = 1;
X#endif
X							endwin();
X							run_command(ptr);
X							printf("\n[Press 'Enter' to continue ...]");
X
X							while (gets(entry) == NULL)
X								;
X
X							doupdate();
X#ifdef	HALFDELAY_BROKEN
X							chat_suspended = 0;
X#endif
X							break;
X#endif
X
X						case 'l':		/* redraw screen */
X						case 'r':
X							clearok(disp, TRUE);	/* update display window */
X							clearok(inp, TRUE);		/* update input window */
X							wrefresh(disp);			/* redraw both windows */
X							wrefresh(inp);
X							clearok(disp, FALSE);	/* reset display window */
X							clearok(inp, FALSE);	/* reset input window */
X							break;
X
X#ifndef	NO_CHG_NAME
X						case 'n':		/* these are passed to chatter */
X#endif
X#ifndef	NO_SHOW_USERS
X						case 's':
X#endif
X						case 'c':
X							ptr = entry + 2;
X							while (isspace(*ptr))
X								ptr++;
X							sprintf(msgbuf, "%c%s", entry[1], ptr);
X							chc_send(msgbuf);
X							break;
X
X						case 'x':		/* exit from chat */
X						case 'q':		/* for Dennis Breckenridge :-) */
X							cleanup();
X							break;
X
X						default:
X							beep();
X					}
X				}
X				else if (*entry)		/* else send it if not blank */
X				{
X					sprintf(msgbuf, "m%s", entry);
X					chc_send(msgbuf);
X				}
X
X				ptr = entry;	/* reset input box */
X				mvwprintw(inp, 1, 1, "%77s", "");
X				mvwprintw(inp, 1, 1, "-> ");
X			}
X			else if (c == '\b')	/* take care of backspaces */
X			{
X				if (ptr != entry)
X				{
X					wprintw(inp, "\b \b");
X					ptr--;
X				}
X			}
X			else if (c == '\t')	/* expand tabs */
X			{
X				ptr1 = ptr + 8 - ((ptr - entry) % 8);
X				while (ptr != ptr1)
X				{
X					*(ptr++) = ' ';
X					waddch(inp, ' ');
X				}
X			}
X			else if ((c >= ' ') && (c < 0x7f))	/* otherwise if printable */
X			{
X				if ((ptr - entry) > 62)			/* time for word wrap? */
X				{
X					*(ptr++) = c;				/* don't lose latest char */
X					*ptr = 0;					/* terminate string */
X
X					while (!isspace(*ptr))		/* find latest space */
X					{
X						if (--ptr == entry)		/* special case - no spaces */
X						{
X							ptr += strlen(entry);
X							*(ptr + 2) = 0;
X							break;
X						}
X					}
X
X					*(ptr++) = 0;				/* change space to zero */
X					sprintf(msgbuf, "m%s", entry);
X					chc_send(msgbuf);
X					strcpy(entry, ptr);			/* change string to leftover */
X					ptr = entry + strlen(entry);
X					mvwprintw(inp, 1, 1, "%77s", "");	/* clear input box */
X					mvwprintw(inp, 1, 1, "-> %s", entry);	/* print string */
X				}
X				else
X					waddch(inp, (*(ptr++) = c));		/* print character */
X			}
X		}
X	}
X}
SHAR_EOF
chmod 0444 chat.c || echo "restore of chat.c fails"
if [ $TOUCH = can ]
then
    touch -am 0820223590 chat.c
fi
fi
# ============= chatter.c ==============
if test -f chatter.c; then echo "File chatter.c exists"; else
echo "x - extracting chatter.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > chatter.c &&
X/*
X
Xchatter
Xserver process for multi-user chat
XWritten by D'Arcy J.M. Cain
XWest Hill, Ontario
Xdarcy@druid.UUCP
XAll rights reserved
X
XThis is the server for the chat program.  It handles various
Xrequests and sends messages to the users of chat.
X
XPermission is hereby granted to freely copy and redistribute this
Xsoftware, provided that the author is clearly credited in all
Xcopies and derivations.  This software is provided ``As Is'' and
Xwithout any express or implied warranties.
X
X*/
X
X#include	<stdio.h>
X#include	<signal.h>
X#include	<string.h>
X#include	<stdlib.h>
X#include	<sys/types.h>
X#include	<ctype.h>
X#include	<errno.h>
X#include	"chat.h"
X
Xchar chatter_rcsid[] = "$Id: chatter.c,v 1.1 90/08/19 19:03:46 darcy Exp $";
X
X#define		MAX_CHATTERS		32
XCHATTER		u[MAX_CHATTERS];
X
Xchar	progname[64];
X
Xvoid	cleanup(int sig)	/* exit through here always */
X{
X	ch_close();
X	fprintf(stderr, "\nchatter exiting\n");
X	exit(sig);
X}
X
X/* open message queue */
Xvoid	init(void)
X{
X	char	*p;
X
X	if ((p = ch_init()) != NULL)
X	{
X		fprintf(stderr, "%s: %s\n", progname, p);
X		exit(1);
X	}
X}
X
Xvoid	main(int argc, char **argv)
X{
X	int		k, u_id;
X	char	ch, msgbuf[512], message[256];
X
X	strcpy(progname, argv[0]);
X
X	/* all trap everything to go through cleanup */
X	signal(SIGINT, cleanup);
X	signal(SIGABRT, cleanup);
X	signal(SIGKILL, cleanup);
X	signal(SIGTERM, cleanup);
X
X	init();
X
X	/* reset all channels */
X	for (k = 0; k < MAX_CHATTERS; k++)
X		u[k].channel = 0;
X
X	for (;;)		/* till the stars fall from the sky */
X	{
X		while ((u_id = ch_get(msgbuf)) == -1)
X			;
X
X		if (u[u_id].channel == 0)
X			u[u_id].channel = '0';
X
X		ch = u[u_id].channel;
X
X		switch (*msgbuf)
X		{
X			case 'o':	/* open a chat channel */
X				strcpy(u[u_id].logname, msgbuf + 1);
X				sprintf(msgbuf, "[%-12.12s] Joining Chat", u[u_id].logname);
X
X				/* advise the chat world of newcomer */
X				for (k = 0; k < MAX_CHATTERS; k++)
X					if (u[k].channel)
X						ch_send(msgbuf, k);
X
X				break;
X
X
X			case 'x':		/* user exiting from chat */
X				sprintf(msgbuf, "[%-12.12s] Leaving Chat", u[u_id].logname);
X
X				/* check each user */
X				for (k = 0; k < MAX_CHATTERS; k++)
X				{
X					if (k == u_id)				/* this user */
X						u[k].channel = 0;
X					else if (u[k].channel)		/* other user */
X						if (u[k].channel == ch)	/* same channel */
X							ch_send(msgbuf, k);
X				}
X
X				ch_send(NULL, u_id);			/* remove user from list */
X				break;
X
X			case 'c':			/* change channel */
X				if (isascii(msgbuf[1]))			/* only allow ASCII */
X				{
X					if (msgbuf[1] == '*')
X					{
X						int c = '0';
X
X						while (isascii(c))
X						{
X							if (c == '*')
X								continue;
X
X							for (k = 0; k < MAX_CHATTERS; k++)
X								if (u[k].channel == c)
X									k = MAX_CHATTERS + 1;
X
X							if (k == MAX_CHATTERS)
X							{
X								u[u_id].channel = c;
X								sprintf(msgbuf,
X										"[%-12.12s] switched to channel %c",
X										u[u_id].logname, c);
X
X								for (k = 0; k < MAX_CHATTERS; k++)
X									if (u[k].channel)
X										ch_send(msgbuf, k);
X
X								break;
X							}
X
X							c++;
X						}
X
X						break;
X					}
X							
X					u[u_id].channel = msgbuf[1];
X					sprintf(msgbuf, "[%-12.12s] switched to channel %c",
X						u[u_id].logname, u[u_id].channel);
X
X					for (k = 0; k < MAX_CHATTERS; k++)
X						if (u[k].channel)
X							ch_send(msgbuf, k);
X				}
X
X				break;
X
X			case 's':			/* show users */
X				for (k = 0; k < MAX_CHATTERS; k++)
X				{
X					if (u[k].channel)
X					{
X						sprintf(msgbuf, "[%-12.12s] is on channel %c",
X								u[k].logname, u[k].channel);
X						ch_send(msgbuf, u_id);
X					}
X				}
X
X				break;
X
X			case 'n':			/* change user's display name */
X				if (msgbuf[1])
X					strcpy(u[u_id].logname, msgbuf + 1);
X				break;
X				
X			case 'm':			/* send a message */
X				msgbuf[64] = 0;
X				sprintf(message, "[%-12.12s] %s",
X						u[u_id].logname, msgbuf + 1);
X
X				for (k = 0; k < MAX_CHATTERS; k++)
X					if (u[k].channel == ch)
X						ch_send(message, k);
X
X				break;
X		}
X	}
X}
SHAR_EOF
chmod 0444 chatter.c || echo "restore of chatter.c fails"
if [ $TOUCH = can ]
then
    touch -am 0820223590 chatter.c
fi
fi
# ============= chc_msg.c ==============
if test -f chc_msg.c; then echo "File chc_msg.c exists"; else
echo "x - extracting chc_msg.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > chc_msg.c &&
X/*
Xchc_msg
X
Xsupport routines for chat client - message IPC version
XWritten by D'Arcy J.M. Cain
XWest Hill, Ontario
Xdarcy@druid.UUCP
XAll rights reserved
X
XThis module is linked with chat to implement a message based
Xversion of chat.
X
XPermission is hereby granted to freely copy and redistribute this
Xsoftware, provided that the author is clearly credited in all
Xcopies and derivations.  This software is provided ``As Is'' and
Xwithout any express or implied warranties.
X
X*/
X
X#include	<signal.h>
X#include	<sys/ipc.h>
X#include	<sys/msg.h>
X#include	<string.h>
X#include	<process.h>
X#include	"chat.h"
X
Xchar chc_msg_rcsid[] = "$Id: chc_msg.c,v 1.1 90/08/19 19:03:55 darcy Exp $";
X
X#define		KEY		0x63
X
Xstatic struct msgbuf	sndbuf, rcvbuf;
Xstatic int	q;
Xstatic long	my_pid;
X
X#ifdef	HALFDELAY_BROKEN
Xstatic void	checker(int sig)
X{
X	extern int chat_suspended;
X
X	if (!chat_suspended)
X		while (chk_q())
X			;
X
X	sigset(SIGALRM, checker);
X	alarm(2);
X}
X#endif
X
X/* open message queue */
Xchar	*ch_init(void)
X{
X	if ((q = msgget(KEY, 0666)) == -1)
X		return("Can't open chat queue");
X
X#ifdef	HALFDELAY_BROKEN
X	checker(0);			/* set up timer */
X#endif
X	my_pid = getpid();
X	return(NULL);
X}
X
Xint		ch_close(void)	/* exit through here always */
X{
X	/* nothing to do in message IPC version */
X	return(0);
X}
X
Xvoid	chc_send(char *s)			/* send message to chatter */
X{
X	sndbuf.mtype = 1L;
X	strcpy(sndbuf.mtext, s);
X	msgsnd(q, &sndbuf, 256, 0);
X}
X
X/* don't block */
Xint		ch_get(char *s)
X{
X	if (msgrcv(q, &rcvbuf, 256, my_pid, IPC_NOWAIT) > 0)
X	{
X		strcpy(s, rcvbuf.mtext);
X		return(1);
X	}
X
X	return(0);
X}
X
SHAR_EOF
chmod 0444 chc_msg.c || echo "restore of chc_msg.c fails"
if [ $TOUCH = can ]
then
    touch -am 0820223590 chc_msg.c
fi
fi
# ============= chs_msg.c ==============
if test -f chs_msg.c; then echo "File chs_msg.c exists"; else
echo "x - extracting chs_msg.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > chs_msg.c &&
X/*
Xchs_msg
X
Xsupport routines for chatter - message IPC version
XWritten by D'Arcy J.M. Cain
XWest Hill, Ontario
Xdarcy@druid.UUCP
XAll rights reserved
X
XThis module is linked with chatter to implement a message IPC based
Xversion of chatter.
X
XPermission is hereby granted to freely copy and redistribute this
Xsoftware, provided that the author is clearly credited in all
Xcopies and derivations.  This software is provided ``As Is'' and
Xwithout any express or implied warranties.
X
X*/
X
X#include	<signal.h>
X#include	<sys/ipc.h>
X#include	<sys/msg.h>
X#include	<string.h>
X#include	"chat.h"
X
Xchar chs_msg_rcsid[] = "$Id: chs_msg.c,v 1.1 90/08/19 19:04:32 darcy Exp $";
X
X#define		KEY		0x63
X
Xstatic struct msgbuf	sndbuf, rcvbuf;
Xstatic struct msqid_ds	msqid;
Xstatic int	q;
X
Xstatic long	u_pid[MAX_CHATTERS];
X
Xstatic int	get_u(long i)
X{
X	int		k;
X
X	for (k = 0; k < MAX_CHATTERS; k++)
X		if (u_pid[k] == i)
X			return(k);
X
X	return(-1);
X}
X
X/* open message queue */
Xchar	*ch_init(void)
X{
X	if ((q = msgget(KEY, 0666 | IPC_CREAT)) == -1)
X		return("Chat queue in use");
X
X	return(NULL);
X}
X
Xint		ch_close(void)	/* exit through here always */
X{
X	/* remove chat message queue */
X	return(msgctl(q, IPC_RMID, NULL));
X}
X
Xvoid	ch_send(char *s, int id)			/* send message to user */
X{
X	if (s == NULL)
X		u_pid[id] = 0;
X	else if (u_pid[id])
X	{
X		sndbuf.mtype = u_pid[id];
X		strcpy(sndbuf.mtext, s);
X		msgsnd(q, &sndbuf, 256, 0);
X	}
X}
X
X/* block until a message is received */
Xint		ch_get(char *s)
X{
X	int		u;
X
X	/* check for dead process */
X	for (u = 0; u < MAX_CHATTERS; u++)
X	{
X		if (u_pid[u])
X		{
X			if ((kill(u_pid[u], 0)) /* && (errno == ESRCH) */ )
X			/* We shouldn't have to test */
X			/* for ESRCH since that is   */
X			/* only theoretical return   */
X			{
X				while (msgrcv(q, &rcvbuf, 256, u_pid[u], IPC_NOWAIT) != -1)
X					;
X
X				/* simulate a close command */	
X				strcpy(s, "x");
X				u_pid[u] = 0;
X				return(u);
X			}
X		}
X	}
X
X	if (msgrcv(q, &rcvbuf, 256, 1L, 0) == -1)
X		return(-1);
X
X	/* set up various variables from message */
X	strcpy(s, rcvbuf.mtext);
X	msgctl(q, IPC_STAT, &msqid);
X
X	if ((u = get_u(msqid.msg_lspid)) == -1)
X	{
X		if ((u = get_u(0L)) == -1)
X		{
X			strcpy(sndbuf.mtext, "e2 Chatter table full");
X			sndbuf.mtype = msqid.msg_lspid;
X			msgsnd(q, &sndbuf, 256, 0);
X			return(-1);
X		}
X		else
X			u_pid[u] = msqid.msg_lspid;
X	}
X
X	return(u);
X}
X
SHAR_EOF
chmod 0444 chs_msg.c || echo "restore of chs_msg.c fails"
if [ $TOUCH = can ]
then
    touch -am 0820223590 chs_msg.c
fi
fi
# ============= lchat ==============
if test -f lchat; then echo "File lchat exists"; else
echo "x - extracting lchat (Text)"
sed 's/^X//' << 'SHAR_EOF' > lchat &&
X:
X# $Id: lchat,v 1.1 90/08/19 19:06:00 darcy Exp $
X# This script calls chat with some arguments.  Set LOGFILE equal to 
X# a log file to capture your session to.  Set REALNAME to the name
X# to display on the output.
X
X# If a user's name is entered, chat is called via chatyell which 
X# sends a message to the named user to run chat before running chat.
X
XLOGFILE=/usr/darcy/chat.log
XREALNAME="D'Arcy"
X
Xecho "\n`date`" >> $LOGFILE
X
Xif [ $# = 0 ]
Xthen
X	chat -n $REALNAME -f $LOGFILE
Xelse
X	chatyell $1 -n $REALNAME -f $LOGFILE $2 $3 $4 $5
Xfi
X
SHAR_EOF
chmod 0544 lchat || echo "restore of lchat fails"
if [ $TOUCH = can ]
then
    touch -am 0820223690 lchat
fi
fi
# ============= chatyell ==============
if test -f chatyell; then echo "File chatyell exists"; else
echo "x - extracting chatyell (Text)"
sed 's/^X//' << 'SHAR_EOF' > chatyell &&
X:
X# chatyell tells someone to join the chat.
X# Written by D'Arcy J.M. Cain
X# $Id: chatyell,v 1.1 90/08/19 19:05:45 darcy Exp $
X
Xif [ $# -lt 1 ]
Xthen
X	echo "Usage: chatyell user"
Xelse
X# The following test isn't perfect.  If you want to chat
X# with user bill and he is not logged in but billy is then
X# the test shows bill as logged in.  I'm sure there is a
X# really easy way to find out if someone is logged in but
X# I just don't happen to know it.
X	if [ `who | awk "/$1/ {print \$1}" | wc -l` != 0 ]
X	then
X		write $1 <<- END_ECHO
X		$LOGNAME wants to chat with you.
X		Type chat at the prompt
X		END_ECHO
X		chat $2 $3 $4 $5 $6 $7 $8 $9
X	else
X		echo "$1 not currently logged on"
X	fi
Xfi
SHAR_EOF
chmod 0555 chatyell || echo "restore of chatyell fails"
if [ $TOUCH = can ]
then
    touch -am 0820223690 chatyell
fi
fi
# ============= chat.readme ==============
if test -f chat.readme; then echo "File chat.readme exists"; else
echo "x - extracting chat.readme (Text)"
sed 's/^X//' << 'SHAR_EOF' > chat.readme &&
Xchat
X====
X
XWritten by D'Arcy J.M. Cain 1990
X(darcy@cain)
XAll rights reserved
X
XPermission is hereby granted to freely copy and redistribute this
Xsoftware, provided that the author is clearly credited in all
Xcopies and derivations.  This software is provided ``As Is'' and
Xwithout any express or implied warranties.
X
XChat allows more than one user on a system to be involved
Xin a conference via their terminal.  It consists of a foreground
Xpart and a background part.
X
Xchatter is the background process.  It looks for messages from 
Xother processes and sends messages to them.  It should be put into
Xinittab so that it always restarts.
X
Xchat is the front end and is the program run by users wishing to
Xjoin or start a chat.  In chat, lines starting with / are commands.
Xenter /? or /h for a list of commands
X
XTo call chat simply enter chat from the command line.  Various 
Xoptions are available and are accessed by adding '-x' to the command
Xwhere x is one of the following letters:
X
Xh   Displays a usage message instead of running the program.
Xn   Takes the following name and uses it instead of login name.
Xf   Takes the following file and keeps a log of the conversation in it.
X
XExample:
X
Xchat -n "D'Arcy" -f chat.log
X
XThis starts chat, sets up the name as D'Arcy, opens the file chat.log
Xand keeps a record of the chat in it.  Note that the quotes around
XD'Arcy are only neccessary because of the apostrophe.
X
XThe n option can be set from within the program as well.
X
XMove chat.make to Makefile and run make to create the programs.
X
X
XChat Wish List:
X
XThese are a few things that I hope to add to chat later.  If you can
Xthink of other enhancements please let me know.
X
X- A TLI version.  I have made a small start on this but if anyone wants
X  to give it a try, go ahead.  Use the ???_msg.c files as models.  You
X  should be able to write ???_tli.c files that just link into the other
X  files without changing them.
X
X- A monitor program.  This is mostly a matter of deciding what it should
X  do.  One idea would be to print the name of the user any time there was
X  any activity from the chatter.  This could be monitored in any way one
X  chooses.  A simplistic method would be to run the monitor program in
X  background and allow it to interupt the user each time there was any
X  activity.  Of course there are other possibilities.  On my system, for
X  example, I would put it in background and pipe it to a program that
X  displays the name on the LED's on my front panel.
X
X
XEnjoy.
XD'Arcy J.M. Cain
X(darcy@druid)
X
SHAR_EOF
chmod 0444 chat.readme || echo "restore of chat.readme fails"
if [ $TOUCH = can ]
then
    touch -am 0820223690 chat.readme
fi
fi
# ============= chat.make ==============
if test -f chat.make; then echo "File chat.make exists"; else
echo "x - extracting chat.make (Text)"
sed 's/^X//' << 'SHAR_EOF' > chat.make &&
X# Makefile for chat
X# Written by D'Arcy J.M. Cain
X# $Id: chat.make,v 1.1 90/08/21 10:40:17 darcy Exp $
X#
X
X# So far only message based method supported.
XMETHOD=msg
X
Xall:	chat chatter
X
Xchatter:	chatter.o chs_$(METHOD).o
X	$(CC) $(CFLAGS) chatter.o chs_$(METHOD).o $(LDFLAGS) -o chatter
X
Xchat:	chat.o chc_$(METHOD).o
X	$(CC) $(CFLAGS) chat.o chc_$(METHOD).o $(LDFLAGS) -lcurses -o chat
X
Xchat.o:				chat.c chat.h
X
Xchatter.o:			chatter.c chat.h
X
Xchc_$(METHOD).o:	chc_$(METHOD).c chat.h
X
Xchs_$(METHOD).o:	chs_$(METHOD).c chat.h
SHAR_EOF
chmod 0444 chat.make || echo "restore of chat.make fails"
if [ $TOUCH = can ]
then
    touch -am 0821104090 chat.make
fi
fi
exit 0
-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   MS-DOS:  The Andrew Dice Clay
West Hill, Ontario, Canada         |   of operating systems.
+ 416 281 6094                     |

water@wheaton.UUCP (Paul Waterman) (10/12/90)

In article <1990Oct10.141259.11468@druid.uucp> darcy@druid.uucp (D'Arcy J.M. Cain) writes:
>>from: darcy@druid.uucp (D'Arcy J.M. Cain)
>
>This is the multi user chat program what I mentioned in comp.unix.questions
>last week.  Since the requests for it have been high I am posting it here
>instead of mailing it individually to everyone who asked for it.

There's just one problem - chat.h isn't included in the shar.  Chat would 
probably be easier to compile if we could get it too.

	  - Paul
-- 

.------------------------------------------------.     Paul Waterman
| But I thought you said STRAITjackets and ties! |     water@wheaton.UUCP
`------------------------------------------------'     voice: (708) 260-5877

vreed@sandstorm.Berkeley.EDU (Vincent Reed) (10/23/90)

To: darcy@druid.uucp
Subject: Re: Multi-user chat program
Newsgroups: alt.sources
In-Reply-To: <1990Oct10.141259.11468@druid.uucp>
Organization: ucb
Cc: 
Bcc: 

I grabbed your Multi-User Chat to use on our system, but we are missing a few 
of the header files necessary. Could you please send me your stdlib.h process.h
and getopt.h header files? The copies of these we do have seem to be program 
specific. I'm posting this to the net because I was unable to get mail 
directly to you.

THanx in Advance.

VInce Reed
vreed@ocf.berkeley.edu
ucbvax!ocf!vreed

darcy@druid.uucp (D'Arcy J.M. Cain) (10/24/90)

In article <1990Oct22.172500.26286@agate.berkeley.edu> vreed@sandstorm.Berkeley.EDU (Vincent Reed) writes:
>I grabbed your Multi-User Chat to use on our system, but we are missing a few 
>of the header files necessary. Could you please send me your stdlib.h process.h
>and getopt.h header files? The copies of these we do have seem to be program 
>specific. I'm posting this to the net because I was unable to get mail 
>directly to you.
>
I assumed these were ANSI standard header files but except for stdlib.h I
can't find mention of them in my K&R2.  On my system, stdlib.h is just a
link to unistd.h.  That file is obviously OS specific so I try to avoid it.
I can't send you a copy because it is copyright AT&T.  Your best bet is to
remove the include directive for this and see what prototypes you are
missing.

I would think that getopt.h would be obvious from the name but here it is:

------------------------- getopt.h -------------------------------
/*
declarations for getopt
*/

#ifndef		_GETOPT_H
#define		_GETOPT_H

extern int getopt(int argc, char **argv, const char *opts);
extern int optind, opterr;
extern char *optarg;

#endif
------------------------ end of getopt.h ----------------------------

The file process.h holds mainly prototypes fork() and exec() calls as well
as wait().  I have built up this file from various files and although I
have modified it to an unrecognizable form I hesitate to send out the whole
thing.  Here are the relevant prototypes:

---------------------------- process.h -------------------------------
/*
	process.h
*/

#ifndef		_PROCESS_H
#define		_PROCESS_H

int		execlp(const char *path, const char *arg0, ...);
int		fork(void);
int		getpid(void);
int		system(const char *command);
int		wait(int *stat_loc);

#endif
--------------------------- end of process.h -------------------------

Was I wrong to assume that these files would be available under a standard
compiler?

BTW:  This belongs in alt.sources.d where followups are directed.

-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   I support gun control.
West Hill, Ontario, Canada         |   Let's start with the government!
+ 416 281 6094                     |

dilvish@anasaz.UUCP (Dilvish the Damned) (10/24/90)

Could someone please mail me the entire multi-user chat program.  It appears 
I missed it when I was on vacation and we can't ftp from here (sigh).

Thanks

Dilvish

You can mail me at:

{asuvax,mcdphx}!anasaz!usp1!dilvish

nab1@rosemary.cs.reading.ac.uk (The Phoenix) (10/24/90)

vreed@sandstorm.Berkeley.EDU (Vincent Reed) writes:

>I grabbed your Multi-User Chat to use on our system, but we are missing a few 
>of the header files necessary. Could you please send me your stdlib.h process.h
>and getopt.h header files? The copies of these we do have seem to be program 
>specific. I'm posting this to the net because I was unable to get mail 
>directly to you.

 ... ditto. Maybe you could post them...?
 - Phoenix

=============================  F.N.X  =======================================
The Phoenix   |These are the voyages of the starship ENTERPRISE, its continuing
nab1@csug.cs. |mission: to explore strange, new worlds, to seek out new life &
 reading.ac.uk|new civilisations; to baldly go where noone has gone before ...
=============================  F.N.X  =======================================
The Phoenix   |These are the voyages of the starship ENTERPRISE, its continuing
nab1@csug.cs. |mission: to explore strange, new worlds, to seek out new life &
 reading.ac.uk|new civilisations; to baldly go where noone has gone before ...

mra@srchtec.UUCP (Michael Almond) (10/25/90)

In article <3091@anasaz.UUCP> dilvish@anasaz.UUCP (Dilvish the Damned) writes:
>Could someone please mail me the entire multi-user chat program.  It appears 
>I missed it when I was on vacation and we can't ftp from here (sigh).

I'm missing the chat.h file.  I tried mailing a message to the original poster/
author of chat, but it bounced.  I'm  not sure what else I might be missing.

Maybe a repost is in order?

Thanks.

---
Michael R. Almond                                  mra@srchtec.uucp (registered)
search technology, inc.				        emory!stiatl!srchtec!mra
Atlanta, Georgia                                         (404) 441-1457 (office)
.'.'.'.'.'.'.'.'.'.'.'.'.'. Georgia Tech Alumnus .'.'.'.'.'.'.'.'.'.'.'.'.'.'.'.

darcy@druid.uucp (D'Arcy J.M. Cain) (10/27/90)

In article <286@srchtec.UUCP> mra@srchtec.UUCP (Michael Almond) writes:
>In article <3091@anasaz.UUCP> dilvish@anasaz.UUCP (Dilvish the Damned) writes:
>>Could someone please mail me the entire multi-user chat program.  It appears 
>>I missed it when I was on vacation and we can't ftp from here (sigh).
>
>I'm missing the chat.h file.  I tried mailing a message to the original poster/
>author of chat, but it bounced.  I'm  not sure what else I might be missing.
>
>Maybe a repost is in order?
>
OK.  I want to clean up a few things and then I will repost it.

-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   I support gun control.
West Hill, Ontario, Canada         |   Let's start with the government!
+ 416 281 6094                     |