v16i001: Multi-user conference system, Part01/05

Rich Salz rsalz at uunet.uu.net
Tue Sep 13 06:05:27 AEST 1988


Submitted-by: Keith Gabryelski <ucsd!elgar!ag>
Posting-number: Volume 16, Issue 1
Archive-name: conf2/part01

Conf is a line oriented multi-user chat program designed to work on any
SysV, BSD, or Xenix system.

Conf has several advantages over the standard write program supplied
with most Unix and Xenix operating systems.
	+ Unlimited users conferencing at once.
	+ 100 separate discussion lines.
	+ Public and private messages in addition to password
	  encrypted messages.
	+ Quick and efficient user interaction.
	+ User definable formats for messages.
	+ Intelligent message display algorithm.


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	MANIFEST
#	Makefile
#	conf.c
#	conf.el
export PATH; PATH=/bin:$PATH
if test -f 'MANIFEST'
then
	echo shar: will not over-write existing file "'MANIFEST'"
else
cat << \SHAR_EOF > 'MANIFEST'
A Manifest		   Archived in
------------------------------------------------------------------------
MANIFEST			1
Makefile			1
conf.c				1
conf.el				1
conf.h				2
confalloc.c			2
config.h			2
confopts.c			2
confprnt.c			3
confrots.c			3
confrw.c			3
confsig.c			4
confstr.c			4
extern.h			4
structs.h			4
doc/READ_ME			5
doc/conf.1			5
doc/conf.txt			5
doc/confhelp			5
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
SHELL=/bin/sh
INSTALL= mv
CFLAGS= -g
SRCS= conf.c confrw.c confrots.c confopts.c confalloc.c confstr.c confprnt.c confsig.c
OBJS= conf.o confrw.o confrots.o confopts.o confalloc.o confstr.o confprnt.o confsig.o
HEADERS= conf.h config.h extern.h structs.h
NEW= xconf
NAME= conf
LISP= conf.el
MAKES= Makefile
DOCDIR= doc
CONFLIB= /usr/lib/conf
CONFSPOOL= /usr/spool/conf
BINDIR= /usr/local/bin
LINT=lint
OWNER=conf
GROUP=conf

LIBS= -ltermlib

$(NEW): $(OBJS)
	$(CC) $(CFLAGS) -o $(NEW) $(OBJS) $(LIBS)

all: $(NEW) install

clean:
	rm -f *.o $(NEW) core

shar:
	shar MANIFEST Makefile conf.c conf.el > confshar.1
	shar conf.h confalloc.c config.h confopts.c > confshar.2
	shar confprnt.c confrots.c confrw.c > confshar.3
	shar confsig.c confstr.c extern.h structs.h > confshar.4
	shar doc > confshar.5

lint:
	$(LINT) $(LIBS) $(SRCS)

install:
	cp $(NEW) $(BINDIR)/$(NAME)

	-mkdir $(CONFLIB)

	cp $(DOCDIR)/confhelp $(CONFLIB)
	-chgrp $(GROUP) $(CONFLIB) $(CONFLIB)/confhelp $(BINDIR)/$(NAME)
	-chown $(OWNER) $(CONFLIB) $(CONFLIB)/confhelp $(BINDIR)/$(NAME)
	-chmod u+s $(BINDIR)/$(NAME)
	-chmod 644 $(CONFLIB)/confhelp
	-chmod 755 $(CONFLIB)
SHAR_EOF
fi # end of overwriting check
if test -f 'conf.c'
then
	echo shar: will not over-write existing file "'conf.c'"
else
cat << \SHAR_EOF > 'conf.c'
#include "conf.h"
		/* Talk, talk ... it's all talk! */

char *progname;					/* program name (argv[0]) */
char *logname, *homedir;

int lfd, log_rfd, log_wfd, usr_fd;
long ourplace;
FILE *rec_fp;
int confing = FALSE;

char replyname[MAXNAMELEN] = "";
char replytty[MAXTTYLEN+1] = "";	/* there is a reason for the + 1
						although I have forgotten it
						right now, I'm sure it should
						be there.
					 */

char *wrdata;
unsigned wdlen=0;

struct cusrfil cuser, tuser;
struct clogfil clog, tlog;

#ifdef	SYSV
struct termio term, saveterm;
#endif	SYSV

#ifdef	BSD
struct tchars chrstr;
struct sgttyb ktty;
int ttyflags;
#endif	BSD

char ichar = CTRL('C');				/* interrupt character */
char qchar = CTRL('\\');			/* quit character */

jmp_buf env;

int columns = 80, lines = 24, banner = TRUE, seeme = TRUE, informe = FALSE,
    lineinput = FALSE, beep = FALSE, expand8bit = TRUE, expandctrl = TRUE;

char *cls = NULL, *pager, *shell, *normform, *lineform, *shoutform, *sendform,
    *informform, *recfile;

my_int()
{
    longjmp(env, 1);
}

#ifdef BSD
stopit()
{
    ktty.sg_flags = ttyflags;
    stty(0, &ktty);
    (void) signal(SIGTSTP, SIG_DFL);
    (void) kill(0, SIGTSTP);
    gtty(0, &ktty);
    ttyflags = ktty.sg_flags;

    if (!(ttyflags&ECHO))
	lineinput = TRUE;

    ktty.sg_flags |= CBREAK;
    ktty.sg_flags &= ~ECHO;
    stty(0, &ktty);

    (void) ioctl(0, TIOCGETC, &chrstr);
    
    ichar = chrstr.t_intrc;
    qchar = chrstr.t_quitc;
    (void) signal(SIGTSTP, stopit);
}
#endif BSD

main(argc, argv)
int argc;
char *argv[];
{
    char *ptr, *word, *line, answer;
    int num, x, c, old_umask, rotten_egg;
    struct passwd *pt;

    progname = *argv++; --argc; 

    /* Open all support files */

    old_umask = umask(0);

    x = 0;
    while ((lfd = open(CONFLOCK, O_CREAT|O_EXCL, 0666)) < 0)
    {
	if (++x > 60)	    /* looks like the lock file may be hosed */
	{
	    printf("The lock file %s looks like it is wedged.\n", CONFLOCK);
	    printf("What should I do; (A)bort, (C)ontinue, or (R)emove? ");

	    answer = 'a';

	    while (((c = getchar()) != '\n') && (c != CR))
	    {
		switch(c)
		{
		case 'a':
		case 'A':
		case 'C':
		case 'c':
		case 'R':
		case 'r':
		    answer = c;
		    break;

		default:
		    printf("\n(A)bort, (C)ontinue, or (R)emove? ");
		    break;
		}
	    }
	    
	    switch(answer)
	    {
	    case 'a':
	    case 'A':
		(void) umask(old_umask);
		exit(-1);

	    case 'c':
	    case 'C':
		x = 0;
		continue;

	    case 'r':
	    case 'R':
		(void) unlink(CONFLOCK);
		continue;
	    }

	    sleep(1);
	}
    }

    close(lfd);

    if ((usr_fd = open(CONFUSERS, O_RDWR|O_CREAT, FILEMASK)) < 0)
    {
	(void) fprintf(stderr, "%s: couldn't open %s (%s)\n", progname,
		       CONFUSERS, puterr(errno));
	(void) exit(-1);
    }

    (void) lseek(usr_fd, 0L, 0);

    if ((argc == 1) && (!strcmp(*argv, "-T")))
    {
	(void) lseek(usr_fd, 0L, 0);

#ifdef	SYSV
	lockf(usr_fd, F_LOCK, 0L);	/* lock user file */
#endif	SYSV

#ifdef	BSD
	flock(usr_fd, LOCK_EX);
#endif	BSD

	rotten_egg = TRUE;
	while (read(usr_fd, (char *)&tuser, sizeof(struct cusrfil)) ==
	       sizeof(struct cusrfil))
	    if (tuser.cu_flags != USER_OFF)
	    {
		c = kill(tuser.cu_procid, 0);
		if ((!c) || ((c < 0) && (errno != ESRCH)))
		    rotten_egg = FALSE;
	    }

#ifdef	SYSV
	(void) lseek(usr_fd, 0L, 0);
	lockf(usr_fd, F_ULOCK, 0L);
#endif	SYSV

#ifdef	BSD
	flock(usr_fd, LOCK_UN);
#endif	BSD

	if (rotten_egg)
	{
	    close(usr_fd);
	    open(CONFLOG, O_TRUNC);
	    open(CONFUSERS, O_TRUNC);
	}

	unlink(CONFLOCK);
	exit(0);
    }

    if ((log_wfd = open(CONFLOG, O_WRONLY|O_CREAT|O_APPEND, FILEMASK)) < 0)
    {
	(void) fprintf(stderr,"%s: couldn't create/open %s for writing(%s)\n",
		       progname, CONFLOG, puterr(errno));
	(void) exit(-1);
    }

    (void) umask(old_umask);

    if ((log_rfd = open(CONFLOG, O_RDONLY)) < 0)
    {
	(void) fprintf(stderr,"%s: couldn't open %s for reading (%s)\n",
		       progname, CONFLOG, puterr(errno));
	(void) exit(-1);
    }

    unlink(CONFLOCK);

    setuid(getuid());

    (void) lseek(log_rfd, 0L, 2);

    /* set up some pointers to interesting stuff */

    wrdata = mymalloc(wdlen = PAGESIZ);

    cuser.cu_line = 1;
    cuser.cu_flags = USER_ON;
    cuser.cu_procid = getpid();

    pt = getpwuid(getuid());

    if ((ptr = getlogin()) == NULL)
	if ((ptr = pt->pw_name) == NULL)
	    ptr = "somebody";		/* can't figure this guy out */

    logname = mymalloc((unsigned)(strlen(ptr)+1));
    (void) strcpy(logname, ptr);

    (void) strcpy(cuser.cu_cname, ptr);

    if ((ptr = ttyname(0)) == NULL)
	strcpy(cuser.cu_tty, "tty??");
    else
	strcpy(cuser.cu_tty, ((ptr= strrchr(ptr, '/')) ? ptr+1 : "tty??"));

    homedir = mymalloc((unsigned)(strlen(pt->pw_dir)+1));
    (void) strcpy(homedir, pt->pw_dir);

    cls = mymalloc((unsigned)1);
    *cls = '\0';

    normform = mymalloc((unsigned)(sizeof(DEF_FORM_NORM)));
    (void) strcpy(normform, DEF_FORM_NORM);

    sendform = mymalloc((unsigned)(sizeof(DEF_FORM_SEND)));
    (void) strcpy(sendform, DEF_FORM_SEND);

    shoutform = mymalloc((unsigned)(sizeof(DEF_FORM_SHOUT)));
    (void) strcpy(shoutform, DEF_FORM_SHOUT);

    informform = mymalloc((unsigned)(sizeof(DEF_FORM_INFORM)));
    (void) strcpy(informform, DEF_FORM_INFORM);

    lineform = mymalloc((unsigned)(sizeof(DEF_FORM_LINE)));
    (void) strcpy(lineform, DEF_FORM_LINE);

    pager = mymalloc((unsigned)(sizeof(DEF_PAGER)));
    (void) strcpy(pager, DEF_PAGER);

    shell = mymalloc((unsigned)(sizeof(DEF_SHELL)));
    (void) strcpy(shell, DEF_SHELL);

    recfile = mymalloc((unsigned)(sizeof(DEF_RECFILE)));
    (void) strcpy(recfile, DEF_RECFILE);

    gettcap();			/* get termcap stuff */
    getrc();			/* get some defaults from rc file */
    getopts();			/* get some defaults from environment */

    while (word = *argv++, argc--)
    {
	if (*word == '-')
	{
	   word++;

	   while (*word != '\0')
	   {
	       switch(*word++)
	       {
	       case 'T':
		   printf("%s: -T wasn't specified by itself.  Ignoring...\n",
			  progname);

	       case 'l':
		   if (*word == '\0')
		   {
		       if (!argc)
		       {
			   (void) printf("%s: -l switch specified without a conference line number\n",
					 progname);
			   usage();
		       }
		       word = *argv++; --argc;
		   }

		   num = atoi(word);
		   if ((num < 1) || (num > MAXCONFLINES))
		   {
		      (void) printf("%s: invalid conference line number: %d\n",
				    progname, num);
		      usage();
		  }
		   cuser.cu_line = num;
		   *word = '\0';
		   break;

	       case 's':
		   if (*word == '\0')
		   {
		       if (!argc)
		       {
			   (void) fprintf(stderr,
					  "%s: -s specified without a parameter\n",
					  progname);
			   usage();
		       }
		       word = *argv++; --argc;
		   }

		   if ((x = setopts(parsestr(word, strlen(word), NEXTWORD)))
		       != FOUNDOPT)
		   {
		       char *errmess;

		       if (x == AMBIGUOUS)
			   errmess = "Ambiguous";
		       else
			   errmess = "Invalid";
				
		       (void) fprintf(stderr, "%s: %s -s parameter: %s\n",
				      progname, errmess, word);
		       usage();
		   }
		   *word = '\0';
		   break;

	       case 'w':
		   (void) do_who(0);
		   (void) exit(0);

	       default:
		   (void)fprintf(stderr, "%s: invalid parameter '%c'\n",
				 progname, *(word-1));
		   usage();
	       }
	   }
       }
	else
	    (void) do_ring(word);
    }

    /* by this point, all parameters/options have been parsed */

    confing = TRUE;

    clog.f_line = cuser.cu_line;
    clog.f_usrlen = strlen(cuser.cu_cname) + 1;
    clog.f_ttylen = strlen(cuser.cu_tty) + 1;

    (void) lseek(usr_fd, 0L, 0);

#ifdef	SYSV
    lockf(usr_fd, F_LOCK, 0L);	/* lock user file */
#endif	SYSV

#ifdef	BSD
    flock(usr_fd, LOCK_EX);
#endif	BSD

    ourplace = lseek(usr_fd, 0L, 1);
    while (read(usr_fd, (char *)&tuser, sizeof(struct cusrfil)) ==
	sizeof(struct cusrfil))
	if (tuser.cu_flags == USER_OFF)
	    break;
	else
	    ourplace = lseek(usr_fd, 0L, 1);

    (void) lseek(usr_fd, ourplace, 0);

    write(usr_fd, (char *)&cuser, sizeof(struct cusrfil));

#ifdef	SYSV
    (void) lseek(usr_fd, 0L, 0);
    lockf(usr_fd, F_ULOCK, 0L);
#endif	SYSV

#ifdef	BSD
    flock(usr_fd, LOCK_UN);
#endif	BSD

    /* any fatal errors pass this point must do a nice_exit(status) */

    write_log(INFORM, "Login", (char *)NULL, 0, (unsigned)strlen("Login"));

#ifdef	SYSV
    (void) ioctl(0, TCGETA, &term);
    saveterm=term;

    if (!(term.c_lflag&ECHO))
	lineinput = TRUE;

    ichar = term.c_cc[VINTR];
    qchar = term.c_cc[VQUIT];

    term.c_iflag &= ~(ICRNL);
    term.c_lflag &= ~(ICANON|ECHO);
    term.c_cc[VEOF] = 1;
    term.c_cc[VEOL] = 0;
    (void) ioctl(0, TCSETAW, &term);
    
#endif	SYSV

#ifdef	BSD
    gtty(0, &ktty);
    ttyflags = ktty.sg_flags;

    if (!(ttyflags&ECHO))
	lineinput = TRUE;

    ktty.sg_flags |= CBREAK;
    ktty.sg_flags &= ~ECHO;
    stty(0, &ktty);

    (void) ioctl(0, TIOCGETC, &chrstr);
    
    ichar = chrstr.t_intrc;
    qchar = chrstr.t_quitc;
#endif	BSD

    (void) signal(SIGINT, SIG_IGN);
    (void) signal(SIGQUIT, fatal);
    (void) signal(SIGHUP, nice_exit);
    (void) signal(SIGTERM, nice_exit);
    (void) signal(SIGILL, fatal);
    (void) signal(SIGTRAP, fatal);
    (void) signal(SIGIOT, fatal);
    (void) signal(SIGEMT, fatal);
    (void) signal(SIGFPE, fatal);
    (void) signal(SIGBUS, fatal);
    (void) signal(SIGSEGV, fatal);
    (void) signal(SIGSYS, fatal);
    (void) signal(SIGPIPE, fatal);

#ifdef SIGTSTP
    (void) signal(SIGTSTP, stopit);
#endif SIGTSTP

    if (banner)
	(void) version(FALSE);

    (void) printf("login user %s (%s) on conference line %d\n",
		  cuser.cu_cname, cuser.cu_tty, cuser.cu_line);

    if (setjmp(env))
    {
	(void) signal(SIGINT, my_int);
	dispchar(ichar, stdout, NOVIS);
	(void) putchar('\n');
	(void) lseek(log_rfd, 0L, 2);
    }
    else
	(void) signal(SIGINT, my_int);

    forever
    {
	read_log();

	fflush(stdout);		/* damnit */
	line = getline();
	(void) signal(SIGINT, my_int);
	if (line != NULL)
	{
	    if ((*line == ':') && (*(line+1) != ':'))
	    {
	        if (*(line+1) == '!')
		    keep_shell(line+2);
		else
		{
		    --linelen;
		    (void) intpret(line+1);
		}
	    }
	    else
	    {
		if (*line == ':')
		    write_log(NORMAL, line+1, (char *)NULL, 0, linelen-1);
		else
		    write_log(NORMAL, line, (char *)NULL, 0, linelen);
	    }
	    free(line);
	}
    }
}

nice_exit(status)
int status;
{
    make_nice(TRUE);

    (void) signal(SIGALRM, SIG_DFL);
    (void) signal(SIGINT, SIG_DFL);
    (void) signal(SIGQUIT, SIG_DFL);
    (void) signal(SIGHUP, SIG_DFL);
    (void) signal(SIGTERM, SIG_DFL);
    (void) signal(SIGILL, SIG_DFL);
    (void) signal(SIGTRAP, SIG_DFL);
    (void) signal(SIGIOT, SIG_DFL);
    (void) signal(SIGEMT, SIG_DFL);
    (void) signal(SIGFPE, SIG_DFL);
    (void) signal(SIGBUS, SIG_DFL);
    (void) signal(SIGSEGV, SIG_DFL);
    (void) signal(SIGSYS, SIG_DFL);
    (void) signal(SIGPIPE, SIG_DFL);

    (void) exit(status);
}

make_nice(status)
int status;
{
    (void) alarm(0);

    if (status)
	write_log(INFORM,"Logout",(char *)NULL,0, (unsigned)strlen("Logout"));

    if (cuser.cu_flags&USER_RECORD)
	(void)fclose(rec_fp);

    cuser.cu_flags = USER_OFF;
    write_usr();

    (void) close(usr_fd);
    (void) close(log_rfd);
    (void) close(log_wfd);

#ifdef	SYSV
    (void) ioctl(0, TCSETAW, &saveterm);
#endif	SYSV

#ifdef	BSD
    ktty.sg_flags = ttyflags;
    stty(0, &ktty);
#endif	BSD

    execlp(progname, progname, "-T", (char *)0);
}

usage()
{
    (void) fprintf(stderr,
		   "usage: %s [-T][-w][-s switchname][-l line-number]\n",
		   progname);
    (void) exit(-1);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'conf.el'
then
	echo shar: will not over-write existing file "'conf.el'"
else
cat << \SHAR_EOF > 'conf.el'
;; Run conf(1) as asynchronous inferior of Emacs.
;; provided by Michael Ditto (ford at kenobi.cts.com)
;; This file is not part of GNU Emacs.

(defvar conf-process nil "The process of conf.")

(defun conference (switches)
  "Conference with other users."
  (interactive "sArgs to conference (switches): ")

  (require 'shell)

  (let ((buffer (get-buffer-create "*conference*")))
    (switch-to-buffer buffer)

    (if (get-buffer-process buffer)
	(error "A conference process is already running"))

    (setq conf-process
	  (start-process "conf" buffer
			 "/bin/sh" "-c" (format "conf %s" switches))))

  (shell-mode)
  (turn-on-auto-fill)
  (setq mode-name "Conference")
  (set-marker (process-mark conf-process) (point-max))
  (set-process-filter conf-process 'conf-filter))

(defun conf-filter (process string)
  (save-excursion
    (set-buffer (process-buffer process))
    (goto-char (process-mark process))
    (let ((start-line (point)))
      (insert-before-markers string)
      ;;    (fill-region start-line (point))
      )

    (if (get-buffer-window (process-buffer process))
	nil
      (beep t))))
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
  "If green is all there is to be, then green is good enough for me" - ktf
[  Keith   ]  UUCP: {ucsd, cbosgd!crash, sdcsvax!crash, nosc!crash}!elgar!ag
[Gabryelski]  INET: ag at elgar.cts.com                 ARPA: elgar!ag at ucsd.edu

-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.



More information about the Comp.sources.unix mailing list