[net.sources] UNaXcess 0.4.4 REPOST -- Part 2 of 3

allbery@ncoast.UUCP (08/05/86)

Sorry if this goes out twice -- I only saw 1 and 3 posted on ncoast.

++Brandon
-------------------------------------------------------------------------------
#! /bin/sh
#
# Shell archive created Sat., Aug. 02, 1986 by tdi2!brandon.
# Contents:
#
#	-rw-r--r--   1 brandon  sys        17590 Aug  2 10:59 msg.c
#	-rw-r--r--   1 brandon  sys        14370 Aug  2 10:59 conf.c
#	-rw-r--r--   1 brandon  sys         2599 Aug  2 10:59 ua.h
#	-rw-r--r--   1 brandon  sys         1825 Aug  2 10:59 user.h
#	-rw-r--r--   1 brandon  sys         3164 Aug  2 10:59 dir.h
#	-rw-r--r--   1 brandon  sys         1779 Aug  2 10:59 sys.h
#	-rw-r--r--   1 brandon  sys        12008 Aug  2 10:59 README
#
# You may unpack this archive with sh or ksh, but not csh.
#

if test -r "msg.c"; then
	echo "File msg.c exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="msg.c"
	esac
else
	newname="msg.c"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:msg.c--' > "$newname"
X/*
X *	@(#)msg.c	1.1 (TDI) 7/18/86 21:01:49
X *
X * Modification History:
X *
X *   Ver. 1.1 created 07/18/86 at 21:01:49 by brandon
X *     Converted to SCCS 07/18/86 21:01:48
X *	@(#)Copyright (C) 1984, 85, 86 by Brandon S. Allbery.
X *
X * Modification History:
X *
X *   Ver. 1.1 created 07/18/86 at 21:01:49 by brandon
X *     Converted to SCCS 07/18/86 21:01:48
X *
X *	@(#)This file is part of UNaXcess version 0.4.5.
X *
X * Modification History:
X *
X *   Ver. 1.1 created 07/18/86 at 21:01:49 by brandon
X *     Converted to SCCS 07/18/86 21:01:48
X *
X *	Permission is hereby granted to copy and distribute this program
X *	freely.  Permission is NOT given to modify this program or distribute
X *	it at cost, except for charging a reasonable media/copying fee.
X */
X
X#ifndef lint
Xstatic char _FileID_[] = "@(#)msg.c	1.1 (TDI) 7/18/86 21:01:49";
Xstatic char _UAID_[]   = "@(#)UNaXcess version 0.4.5";
X#endif lint
X
X#include "ua.h"
X
Xselmsg(s, fn)
X    char *s;
X    int (*fn)();
X    {
X    char line[256], *p;
X    short lomsg, himsg;
X    FILE *f;
X
X    sprintf(line, "%s/%s/himsg", MSGBASE, conference);
X    if ((f = fopen(line, "r")) == NULL)
X	{
X	log("Error %d opening %s", errno, line);
X	if (strcmp(conference, "general") == 0)
X	    {
X	    panic("conf");
X	    }
X	puts("I can't find the high message file.  Moving back to general...");
X	strcpy(conference, "general");
X	return 1;
X	}
X    fgets(line, 32, f);
X    fclose(f);
X    himsg = atoi(line);
X    for (p = s; *p != 0; p++)
X	if (*p == ' ')
X	    {
X	    if (strcmp(++p, "new") == 0)
X		{
X		domsg(conference, 0, himsg, fn);
X		return 1;
X		}
X	    else if ((lomsg = atoi(p)) < 1 || lomsg > himsg)
X		break;
X	    else
X		{
X		domsg(conference, lomsg, lomsg, fn);
X		return 1;
X		}
X	    }
X    printf("<F>orward, <R>everse, <I>ndividual, or <N>ew: ");
X    gets(line);
X    log("Mode: %s", line);
X    switch (line[0])
X	{
X	case 'F':
X	case 'f':
X	    lomsg = 1;
X	    break;
X	case 'R':
X	case 'r':
X	    lomsg = himsg;
X	    himsg = 1;
X	    break;
X	case 'I':
X	case 'i':
X	    printf("Enter message number: ");
X	    gets(line);
X	    log("Message: %s", line);
X	    if ((lomsg = atoi(line)) < 1 || lomsg > himsg)
X		{
X		puts("No such message.");
X		log("No such message.");
X		return 1;
X		}
X	    domsg(conference, lomsg, lomsg, fn);
X	    return 1;
X	case 'N':
X	case 'n':
X	    lomsg = 0;
X	    break;
X	case '\0':
X	    return 1;
X	default:
X	    puts("What?");
X	    log("Illegal search mode.");
X	    return 1;
X	}
X    if (lomsg != 0)
X	{
X	printf("Starting message (%d): ", lomsg);
X	gets(line);
X	log("Start: %s", line);
X	if (line[0] != 0)
X	    if (atoi(line) < 1 || (lomsg > 1 && atoi(line) > lomsg))
X		{
X		puts("Bad message number.");
X		log("Bad message number.");
X		return 1;
X		}
X	    else
X		lomsg = atoi(line);
X	printf("Ending message (%d): ", himsg);
X	gets(line);
X	log("End: %s", line);
X	if (line[0] != 0)
X	    if (atoi(line) < 1 || (himsg > 1 && atoi(line) > himsg))
X		{
X		puts("Bad message number.");
X		log("Bad message number.");
X		return 1;
X		}
X	    else
X		himsg = atoi(line);
X	}
X    domsg(conference, lomsg, himsg, fn);
X    return 1;
X    }
X
Xreadmsg(s)
X    char *s;
X    {
X    return selmsg(s, doread);
X    }
X
Xscanmsg(s)
X    char *s;
X    {
X    return selmsg(s, doscan);
X    }
X
Xdoread(msg, conf, mnum)
X    char *msg, *conf;
X    short mnum;
X    {
X    char line[256];
X
X    printf("\nMessage %d of %s:\n", mnum, conf);
X    if (isprivate(msg))
X	{
X	puts("This message is private.");
X	return 1;
X	}
X    cat(msg);
X
XDR_Loop:
X    printf("\nContinue, Stop, Unsubscribe, or Reply (C): ");
X    if (!isatty(0) || nopause)
X	{
X	line[0] = '\0';
X	putchar('\n');
X	}
X    else
X	gets(line);
X    log("C/S/U/R: %s", line);
X    switch (line[0])
X	{
X	case 'c':
X	case 'C':
X	case '\0':
X	    return 1;
X        case 'U':
X        case 'u':
X            unsubscribe(conf);
X            return 0;
X	case 's':
X	case 'S':
X	    return 0;
X	case 'r':
X	case 'R':
X	    reply(msg, conf);
X	    goto DR_Loop;
X	default:
X	    puts("What?  Please enter one of C, S, U, or R.");
X	    goto DR_Loop;
X	}
X    }
X
Xmsgok(file)
X    char *file;
X    {
X    FILE *fp;
X
X    if ((fp = fopen(file, "r")) == NULL)
X	return 0;
X    fclose(fp);
X    return 1;
X    }
X
Xdoscan(msg, conf, mnum)
Xchar *msg, *conf;
Xshort mnum; {
X    char line[1024];
X    FILE *f;
X    short dflag, fflag, tflag, sflag;
X
X    if ((f = fopen(msg, "r")) == NULL) {
X	puts("Cannot open file.");
X	log("Error %d opening %s", errno, msg);
X	return 1;
X    }
X    printf("\nMessage %d of %s: \n", mnum, conf);
X    dflag = fflag = tflag = sflag = 0;
X    if (isprivate(msg))
X	puts("Message is private.");
X    else {
X	while (fgets(line, 1024, f) != NULL) {
X	    if (line[0] == '\n')
X		break;
X	    if (!dflag && strncmp(line, "Date: ", 6) == 0) {
X		printf("%s", line);
X		dflag++;
X		continue;
X	    }
X	    if (!fflag && strncmp(line, "From: ", 6) == 0) {
X		printf("%s", line);
X		fflag++;
X		continue;
X	    }
X	    if (!tflag && strncmp(line, "To: ", 4) == 0) {
X		printf("%s", line);
X		tflag++;
X		continue;
X	    }
X	    if (!sflag && strncmp(line, "Subject: ", 9) == 0) {
X		printf("%s", line);
X		sflag++;
X		continue;
X	    }
X	    if (!sflag && strncmp(line, "Subject (Private): ", 19) == 0) {
X		printf("%s", line);
X		sflag++;
X		continue;
X	    }
X	}
X        if (!tflag)
X	    puts("To: All");
X    }
X    fclose(f);
X    puts("--------------------------------");
X    if (mnum % 3 == 0)	/* kludged, but there isn't an easy fix without */
X        if (!cont())	/* rewriting the I/O system. */
X            longjmp(cmdloop, 1);	/* also a kludge... */
X    return 1;
X    }
X
Xdomsg(conf, lomsg, himsg, fn)
X    char *conf;
X    short lomsg, himsg;
X    int (*fn)();
X    {
X    short mcnt;
X    char tmps[256];
X    struct _himsg *ptr, *lastp;
X
X    for (ptr = hicnts, lastp = NULL; ptr != NULL; lastp = ptr, ptr = ptr->hi_next)
X	if (strcmp(conf, ptr->hi_conf) == 0)
X	    break;
X    if (ptr == NULL)
X	{
X	if ((ptr = (struct _himsg *) calloc((unsigned) 1, sizeof (struct _himsg))) == NULL)
X	    {
X	    log("Error %d allocating _himsg for %s", errno, conf);
X	    panic("alloc");
X	    }
X	ptr->hi_next = hicnts;
X        hicnts = ptr;
X        ptr->hi_uns = HI_SUBSCR;
X	strcpy(ptr->hi_conf, conf);
X	ptr->hi_num = 0;
X	}
X    if (lomsg == 0)			/* read new messages */
X	for (mcnt = ptr->hi_num + 1; mcnt <= himsg; mcnt++)
X	    {
X	    sprintf(tmps, "%s/%s/%d", MSGBASE, conf, mcnt);
X	    if (msgok(tmps) <= 0)
X		continue;
X	    if (!(*fn)(tmps, conf, mcnt))
X		break;
X	    }
X    else if (lomsg <= himsg)		/* forward or individual read */
X	for (mcnt = lomsg; mcnt <= himsg; mcnt++)
X	    {
X	    sprintf(tmps, "%s/%s/%d", MSGBASE, conf, mcnt);
X	    if (msgok(tmps) <= 0)
X		continue;
X	    if (!(*fn)(tmps, conf, mcnt))
X		break;
X	    }
X    else
X	for (mcnt = lomsg; mcnt >= himsg; mcnt--)
X	    {
X	    sprintf(tmps, "%s/%s/%d", MSGBASE, conf, mcnt);
X	    if (msgok(tmps) <= 0)
X		continue;
X	    if (!(*fn)(tmps, conf, mcnt))
X		break;
X	    }
X    ptr->hi_num = himsg;
X    writehigh(hicnts);
X    }
X
Xreadnew()
X    {
X    DIR *dp;
X    struct direct *dirp;
X    FILE *hp;
X    short himsg;
X    char line[256];
X
X    if ((dp = opendir(MSGBASE)) == NULL)
X	{
X	log("Error %d reading dir %s/", errno, MSGBASE);
X	panic("msgdir");
X	}
X    while ((dirp = readdir(dp)) != NULL)
X	{
X	if (dirp->d_name[0] == '.')
X	    continue;
X        if (isunsub(dirp->d_name))
X            continue;
X	printf("\nExamining conference %s...\n", dirp->d_name);
X	log("Reading %s.", dirp->d_name);
X	if (parms.ua_xrc && dirp->d_name[0] == 'x' && dirp->d_name[1] == '-')
X	    {
X            if (user.u_access == A_GUEST) {
X                log("Guest skipping Restricted conference.");
X                continue;
X            }
X	    printf("This conference is Restricted (X-RATED).  The material within may not be\nsuitable for, or acceptable to, some users.\n\nDo you wish to skip it (Y)? ");
X	    if (!isatty(0) || nopause)
X		{
X		line[0] = '\0';
X		putchar('\n');
X		}
X	    else
X		gets(line);
X	    log("Restricted.  Skip? %s", line);
X	    if (ToLower(line[0]) != 'n')
X		continue;
X	    }
X	sprintf(line, "%s/%s/himsg", MSGBASE, dirp->d_name);
X	if ((hp = fopen(line, "r")) == NULL)
X	    {
X	    log("Error %d opening %s", errno, line);
X	    puts("Can't open high message file.");
X	    continue;
X	    }
X	fgets(line, 32, hp);
X	fclose(hp);
X	himsg = atoi(line);
X	domsg(dirp->d_name, 0, himsg, doread);
X    
X    RN_Loop:
X	printf("\nNext conference, Unsubscribe, or Stop (N): ");
X	if (!isatty(0) || nopause)
X	    {
X	    putchar('\n');
X	    line[0] = '\0';
X	    }
X	else
X	    gets(line);
X	log("Next/Unsub/Stop: %s", line);
X	switch (line[0])
X	    {
X	    case 'N':
X	    case 'n':
X	    case '\0':
X		break;
X	    case 'U':
X	    case 'u':
X	        unsubscribe(dirp->d_name);
X	        break;
X	    case 'S':
X	    case 's':
X		closedir(dp);
X		return 1;
X	    default:
X		puts("Please enter one of N, U, or S.");
X		goto RN_Loop;
X	    }
X	}
X    closedir(dp);
X    return 1;
X    }
X
Xenter(s)
X    char *s;
X    {
X    char to[256], subj[256], *p, line[256];
X    short pflag;
X
X    if (user.u_access == A_GUEST && strcmp(conference, "guest") != 0)
X	{
X	log("Security violation:  GUEST entering messages.");
X	puts("You aren't allowed to enter messages in this conference.");
X	return 1;
X	}
X    for (p = s; *p != '\0'; p++)
X	if (*p == ' ')
X	    {
X	    strcpy(to, ++p);
X	    break;
X	    }
X    if (*p == '\0')
X	{
X	printf("Who is this message to (ALL)? ");
X	gets(line);
X	log("To: %s", line);
X	if (line[0] == '\0')
X	    strcpy(line, "all");
X	for (p = line; *p != '\0'; p++)
X	    *p = ToLower(*p);
X	strcpy(to, line);
X	}
X    printf("Subject: ");
X    gets(line);
X    strcpy(subj, line);
X    log("Subject: %s", line);
X    pflag = 0;
X    if (parms.ua_pm) {
X    	printf("Is this message to be private (N)? ");
X    	gets(line);
X    	log("Private? %s", line);
X    	if (ToLower(line[0]) == 'y')
X	    pflag = 1;
X    }
X    mkmsg(to, subj, conference, pflag);
X    return 1;
X    }
X
Xreply(msg, conf)
X    char *msg, *conf;
X    {
X    char to[256], subj[256], line[1024], rconf[256];
X    short fflag, sflag, pflag;
X    FILE *f;
X
X    if (user.u_access == A_GUEST && strcmp(conf, "guest") != 0)
X	{
X	log("Security violation:  GUEST entering messages");
X	puts("You aren't allowed to enter messages.");
X	return;
X	}
X    if ((f = fopen(msg, "r")) == NULL)
X	{
X	log("Error %d opening %s", errno, msg);
X	puts("Can't re-open message file.");
X	return;
X	}
X    fflag = sflag = 0;
X    strcpy(to, "All\n");
X    strcpy(subj, "Re: Orphaned Response\n");	/* now you know... */
X    while (fgets(line, 1024, f) != NULL)
X	{
X	if (line[0] == '\n')
X	    break;
X	if (!fflag && strncmp(line, "From: ", 6) == 0)
X	    {
X	    strcpy(to, &line[6]);
X	    fflag++;
X	    continue;
X	    }
X	if (!sflag && strncmp(line, "Subject: ", 9) == 0)
X	    {
X	    if (strncmp(&line[9], "Re: ", 4) == 0)
X		strcpy(subj, &line[9]);
X	    else
X		strcpy(&subj[4], &line[9]);
X	    sflag++;
X	    continue;
X	    }
X	if (!sflag && strncmp(line, "Subject (Private): ", 19) == 0)
X	    {
X	    if (strncmp(&line[19], "Re: ", 4) == 0)
X		strcpy(subj, &line[19]);
X	    else
X		strcpy(&subj[4], &line[19]);
X	    sflag++;
X	    continue;
X	    }
X	}
X    fclose(f);
X    to[strlen(to) - 1] = '\0';			/* get rid of trailing nl */
X    subj[strlen(subj) - 1] = '\0';
X    printf("What conference do you wish this reply to be in (%s): ", conf);
X    gets(line);
X    if (line[0] != '\0' && verify(line))
X	{
X	strcpy(rconf, line);
X	conf = rconf;
X	}
X    pflag = 0;
X    if (parms.ua_pm) {
X	    printf("Is this message to be private (N)? ");
X	    gets(line);
X	    log("Private? %s", line);
X	    if (ToLower(line[0]) == 'y')
X		pflag = 1;
X    }
X    mkmsg(to, subj, conf, pflag);
X    }
X
Xmkmsg(to, subj, conf, ispriv)
X    char *to, *subj, *conf;
X    {
X    static char lockfile[] = "msgbase.lock";
X    char *tempfile = mktemp("/tmp/UAmXXXXXX");
X    FILE *mfp, *sfp;
X    char line[1024], *p;
X    long clock;
X    short mcnt;
X    struct tm *ltbuf;
X    struct user ubuf;
X
X    if (user.u_access != A_WITNESS && parms.ua_roc && conf[0] == 'r' && conf[1] == '-')
X	{
X	conf = "general";			/* responses get redirected */
X	puts("Read-only conference; message will be added to \"general\".");
X	}
X    if (ispriv && !getuser(to, &ubuf))
X	{
X	printf("Can't send private message to \"%s\"; he's unregistered.\n", to);
X	log("Attempted private message to unregistered user.");
X	return 0;
X	}
X    if ((mfp = fopen(tempfile, "w")) == NULL)
X	{
X	log("Error %d opening %s", errno, tempfile);
X	panic("tmp");
X	}
X    for (p = to; *p != '\0'; p++)
X	*p = ToUpper(*p);
X    fprintf(mfp, "To: %s\nSubject%s: %s\n\n", to, (ispriv? " (Private)": ""), subj);
X    fclose(mfp);
X    input(tempfile);
X    for (;;)
X	{
X	printf("\nEdit command (L, C, E, S, or A): ");
X	gets(line);
X	log("Edit command: %s", line);
X	switch (line[0])
X	    {
X	    case 'l':
X	    case 'L':
X		cat(tempfile);
X		break;
X	    case 'c':
X	    case 'C':
X		input(tempfile);
X		break;
X	    case 'e':
X	    case 'E':
X		if (user.u_access == A_SYSTEM || user.u_access == A_WITNESS)
X		    xedit(tempfile);
X		else
X		    edit(tempfile);
X		break;
X	    case 'a':
X	    case 'A':
X		printf("Do you really want to abort this edit (N)? ");
X		gets(line);
X		log("Abort? %s", line);
X		if (ToLower(line[0]) == 'y')
X		    {
X		    unlink(tempfile);
X		    return 0;
X		    }
X		break;
X	    case '?':
X		puts("Editor commands:\nL - List message\nC - Continue message entry\nE - Edit message\nS - Save message\nA - Abort message");
X		break;
X	    case '\0':
X		break;
X	    case 's':
X	    case 'S':
X		puts("Saving message...");
X		mklock(lockfile);
X		sprintf(line, "%s/%s/himsg", MSGBASE, conf);
X		if ((sfp = fopen(line, "r")) == NULL)
X		    {
X		    log("Error %d opening %s", errno, line);
X		    rmlock(lockfile);
X		    unlink(tempfile);
X		    panic("himsg");
X		    }
X		fgets(line, 32, sfp);
X		fclose(sfp);
X		mcnt = atoi(line) + 1;
X		sprintf(line, "%s/%s/%d", MSGBASE, conf, mcnt);
X		if ((sfp = fopen(line, "w")) == NULL)
X		    {
X		    log("Error %d opening %s", errno, line);
X		    unlink(tempfile);
X		    rmlock(lockfile);
X		    panic("msg");
X		    }
X		fprintf(sfp, "Date: %s\nFrom: ", longdate());
X		for (p = user.u_name; *p != '\0'; p++)
X		    putc(ToUpper(*p), sfp);
X		putc('\n', sfp);
X		if ((mfp = fopen(tempfile, "r")) == NULL)
X		    {
X		    fclose(sfp);
X		    log("Error %d opening %s", errno, tempfile);
X		    unlink(tempfile);
X		    unlink(line);
X		    rmlock(lockfile);
X		    panic("tmp");
X		    }
X		while (fgets(line, 1024, mfp) != NULL)
X		    fputs(line, sfp);
X		fclose(sfp);
X		fclose(mfp);
X		unlink(tempfile);
X		sprintf(line, "%s/%s/himsg", MSGBASE, conf);
X		if ((sfp = fopen(line, "w")) == NULL)
X		    {
X		    log("Error %d opening %s", errno, line);
X		    panic("himsg");
X		    }
X		fprintf(sfp, "%d\n", mcnt);
X		fclose(sfp);
X		rmlock(lockfile);
X		return 1;
X	    default:
X		puts("Please enter L, C, E, S, or A; or ? for help.");
X	    }
X	}
X    }
X
Xinput(file)
X    char *file;
X    {
X    FILE *fp;
X    char line[256], *p;
X
X    if ((fp = fopen(file, "a")) == NULL)
X	{
X	log("Error %d opening %s", errno, file);
X	unlink(file);
X	panic("tmp");
X	}
X    puts("\nEnter your text now.  End it with a slash on a line by itself.\n");
X    log("Entering text...");
X    for (;;)
X	{
X	printf("] ");
X	if (gets(line) == NULL)
X	    {
X	    log("Illegal character: EOF");
X	    clearerr(stdin);			/* 4.2 brain damage fix */
X	    continue;
X	    }
X	if (strcmp(line, "/") == 0)
X	    break;
X	for (p = line; *p != '\0'; p++)
X	    if (iscntrl(*p) && *p != '\t')
X		{
X		log("Illegal character: ^%c", uncntrl(*p));
X		putc('^', fp);
X		putc(uncntrl(*p), fp);
X		}
X	    else
X		putc(*p, fp);
X	putc('\n', fp);
X	}
X    fclose(fp);
X    }
X
Xedit(file)
X    char *file;
X    {
X    char line[256], rline[256], *edtemp = mktemp("/tmp/UaEdXXXXXX");
X    short lcnt, lnum;
X    FILE *ip, *fp;
X
X    for (;;)
X	{
X	printf("\nLine number to edit (<ENTER> to exit): ");
X	gets(line);
X	log("Line #: %s", line);
X	if (line[0] == '\0')
X	    return;
X	lnum = atoi(line);
X	if (lnum < 1)
X	    continue;
X	if ((fp = fopen(file, "r")) == NULL)
X	    {
X	    log("Error %d opening %s", errno, file);
X	    panic("tmp");
X	    }
X	if ((ip = fopen(edtemp, "w")) == NULL)
X	    {
X	    log("Error %d opening %s", errno, edtemp);
X	    puts("Can't open the temporary file.");
X	    fclose(fp);
X	    return;
X	    }
X	for (lcnt = 1; lcnt < lnum; lcnt++)
X	    {
X	    fgets(line, 256, fp);
X	    fputs(line, ip);
X	    }
X	fgets(line, 256, fp);
X	if (feof(fp))
X	    {
X	    puts("Not that many lines in the message.");
X	    fclose(fp);
X	    fclose(ip);
X	    unlink(edtemp);
X	    continue;
X	    }
X	printf("\nLine %d currently reads:\n\n> %s\nRe-enter the line, or hit <ENTER> to leave it unchanged:\n\n] ", lnum, line);
X	gets(rline);
X	log("Replacement: %s", rline);
X	if (rline[0] == '\0')
X	    fputs(line, ip);
X	else
X	    fprintf(ip, "%s\n", rline);
X	while (fgets(line, 256, fp) != NULL)
X	    fputs(line, ip);
X	fclose(ip);
X	fclose(fp);
X	unlink(file);
X	if (copylink(edtemp, file) < 0)
X	    {
X	    log("Error %d copylinking %s to %s", errno, edtemp, file);
X	    panic("copylink");
X	    }
X	unlink(edtemp);
X	}
X    }
X    
Xdoqscan(msg, conf, mnum)
X    char *msg, *conf;
X    short mnum;
X    {
X    char line[1024];
X    FILE *f;
X
X    if ((f = fopen(msg, "r")) == NULL)
X	{
X	puts("Cannot open file.");
X	log("Error %d opening %s", errno, msg);
X	return 1;
X	}
X    printf("%5d. ", mnum);
X    if (isprivate(msg))
X	puts("Private message.");
X    else
X	while (fgets(line, 1024, f) != NULL)
X	    {
X	    if (line[0] == '\n')
X		break;
X	    if (strncmp(line, "Subject: ", 9) == 0)
X		{
X		printf("%s", &line[9]);
X		break;
X		}
X	    if (strncmp(line, "Subject (Private): ", 19) == 0)
X		{
X		printf("%s", &line[8]);		/* include privacy tag */
X		break;
X		}
X	    }
X    fclose(f);
X    if (mnum % 16 == 0)	/* kludge, see comment in doscan() */
X    	if (!cont())
X    	    longjmp(cmdloop, 1);
X    return 1;
X    }
X
Xqscan(s)
X    char *s;
X    {
X    return selmsg(s, doqscan);
X    }
--EOF:msg.c--
fi

if test -r "conf.c"; then
	echo "File conf.c exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="conf.c"
	esac
else
	newname="conf.c"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:conf.c--' > "$newname"
X/*
X *	@(#)conf.c	1.1 (TDI) 7/18/86 21:01:41
X *
X * Modification History:
X *
X *   Ver. 1.1 created 07/18/86 at 21:01:41 by brandon
X *     Converted to SCCS 07/18/86 21:01:40
X *	@(#)Copyright (C) 1984, 85, 86 by Brandon S. Allbery.
X *
X * Modification History:
X *
X *   Ver. 1.1 created 07/18/86 at 21:01:41 by brandon
X *     Converted to SCCS 07/18/86 21:01:40
X *
X *	@(#)This file is part of UNaXcess version 0.4.5.
X *
X * Modification History:
X *
X *   Ver. 1.1 created 07/18/86 at 21:01:41 by brandon
X *     Converted to SCCS 07/18/86 21:01:40
X *
X *	Permission is hereby granted to copy and distribute this program
X *	freely.  Permission is NOT given to modify this program or distribute
X *	it at cost, except for charging a reasonable media/copying fee.
X */
X
X#ifndef lint
Xstatic char _FileID_[] = "@(#)conf.c	1.1 (TDI) 7/18/86 21:01:41";
Xstatic char _UAID_[]   = "@(#)UNaXcess version 0.4.5";
X#endif lint
X
X#include "ua.h"
X
Xchar conference[33];
X
Xconfidx()
X    {
X    FILE *ifd;
X    short icnt, himsg;
X    char line[256];
X    DIR *dp;
X    struct direct *dfd;
X
X    icnt = 0;
X    puts("\n\"!\" after a conference name indicates an unsubscribed-to conference.\n\nConference                        HiMsg Conference                        HiMsg");
X    if ((dp = opendir(MSGBASE)) == NULL)
X	{
X	log("Error %d opening dir %s/", errno, MSGBASE);
X	panic("msgdir");
X	}
X    while ((dfd = readdir(dp)) != NULL)
X	{
X	if (dfd->d_name[0] == '.')
X	    continue;
X	sprintf(line, "%s/%s/himsg", MSGBASE, dfd->d_name);
X	if ((ifd = fopen(line, "r")) == NULL)
X	    {
X	    log("No himsg in conference %s", dfd->d_name);
X	    continue;
X	    }
X	fgets(line, 32, ifd);
X	himsg = atoi(line);
X	printf("%-32.32s%c %-5d", dfd->d_name, (isunsub(dfd->d_name)? '!': ':'), himsg);
X	fclose(ifd);
X	if (user.u_llen < 80 || ++icnt % 2 == 0)
X	    putchar('\n');
X	else if (icnt % 2 != 0)
X	    putchar('|');
X	}
X    closedir(dp);
X    puts("\n");
X    return 1;
X    }
X
Xjoin(c)
X    char *c;
X    {
X    char line[256], *p;
X
X    p = c - 1;
X    while (*++p != '\0')
X	if (*p == ' ')
X	    if (verify(++p))
X		{
X		strcpy(conference, p);
X		return 1;
X		}
X    do
X	{
X	printf("Enter conference: ");
X	gets(line);
X	log("Enter conference: %s", line);
X	if (line[0] == '\0')
X	    return 1;
X	}
X    while (!verify(line));
X    strcpy(conference, line);
X    log("Current conference is %s", conference);
X    return 1;
X    }
X
Xverify(conf)
X    char *conf;
X    {
X    char *cp, line[256];
X
X    for (cp = conf; *cp != 0; cp++)
X	{
X	if (!isprint(*cp))
X	    return 0;
X	else if (*cp == '/' || *cp == '!' || *cp == ':')
X	    *cp = '.';
X	else
X	    *cp = ToLower(*cp);
X	}
X    if (cp - conf > CONFSIZE)
X	conf[CONFSIZE] = '\0';
X    sprintf(line, "%s/%s", MSGBASE, conf);
X    if (chdir(line) == -1)
X	{
X	if (errno != ENOENT)
X	    {
X	    log("Error %d accessing dir %s/", errno, line);
X	    return 0;
X	    }
X	else
X	    return newconf(conf);
X	}
X    chdir("../..");
X    if (isunsub(conf)) {
X        printf("You are unsubscribed from this conference.  Rejoin (N)? ");
X        gets(line);
X        log("Unsubscribed.  Resubscribe? %s", line);
X        if (ToLower(line[0]) == 'y')
X            resubscribe(conf);
X        else
X            return 0;
X    }
X    if (parms.ua_xrc && conf[0] == 'x' && conf[1] == '-')
X	{
X	printf("This is a Restricted Access (X-RATED) conference.  The material within\n may be unsuitable for, or unacceptable to, some users of UNaXcess.\n\nDo you still wish to join this conference (N)? ");
X	gets(line);
X	log("Restricted.  Join? %s", line);
X	return (ToLower(line[0]) == 'y');
X	}
X    return 1;
X    }
X
Xkillmsg(n)
X    char *n;
X    {
X    short mnum, flag;
X    char line[256], *p;
X
X    if (user.u_access == A_GUEST)
X	{
X	puts("You aren't authorized for this function.");
X	log("Security violation:  KILL by a GUEST");
X	return 1;
X	}
X    flag = 0;
X    for (p = n; *p != '\0'; p++)
X	if (*p == ' ')
X	    {
X	    if ((mnum = atoi(++p)) < 1)
X		break;
X	    dokill(mnum);
X	    flag++;
X	    }
X    if (flag)
X	return 1;
X    printf("Enter message number to kill: ");
X    gets(line);
X    if (line[0] == '\0')
X	return 1;
X    if ((mnum = atoi(line)) < 1)
X	{
X	puts("Bad message number.");
X	log("Bad message number: %s", line);
X	return 1;
X	}
X    dokill(mnum);
X    return 1;
X    }
X
Xdokill(msg)
X    short msg;
X    {
X    char mfile[256];
X
X    sprintf(mfile, "%s/%s/%d", MSGBASE, conference, msg);
X    if (user.u_access != A_WITNESS && strcmp(getowner(mfile), user.u_name) != 0)
X	{
X	puts("Sorry, you don't own that message.");
X	log("Security violation:  KILL by non-owner");
X	return;
X	}
X    if (unlink(mfile) < 0)
X	{
X	printf("No such message: %d", msg);
X	log("Error %d unlinking %s", errno, mfile);
X	return;
X	}
X    log("Deleted %s:%d", conference, msg);
X    }
X
Xchar *getowner(file)
X    char *file;
X    {
X    FILE *f;
X    char line[1024], *p;
X    static char owner[256];
X
X    strcpy(owner, parms.ua_sysop);
X    if ((f = fopen(file, "r")) == NULL)
X	return owner;
X    while (fgets(line, 1024, f) != NULL)
X	if (line[0] == '\n')
X	    break;
X	else if (strncmp(line, "From: ", 6) == 0)
X	    {
X	    strcpy(owner, &line[6]);
X	    break;
X	    }
X    fclose(f);
X    for (p = owner; *p != '\0'; p++)
X	*p = ToLower(*p);
X    return owner;
X    }
X
Xnewconf(conf)
X    char *conf;
X    {
X    char line[256];
X    FILE *f;
X
X    if (user.u_access == A_GUEST)
X	{
X	log("Security violation:  attempted MKCONF by guest");
X	puts("Sorry, there is no such conference.");
X	return 0;
X	}
X    printf("There is no conference by that name.  Do you want to create it (N)? ");
X    gets(line);
X    log("Nonexistent.  Create? %s", line);
X    if (ToLower(line[0]) != 'y')
X	return 0;
X    if (parms.ua_xrc && conf[0] == 'x' && conf[1] == '-')
X	{
X	printf("Conferences beginning with \"x-\" are designated as Restricted Access (X-RATED)\nconferences under UNaXcess, and will often carry information unsuitable for some\n");
X	printf("users or unacceptable to some users.  If you do not wish to create such a\nconference, answer NO to the next question and choose a conference name not\n");
X	printf("beginning with the characters \"x-\".\n\nDo you wish to create an X-RATED conference (N)? ");
X	gets(line);
X	log("Restricted.  Create? %s", line);
X	if (ToLower(line[0]) != 'y')
X	    return 0;
X	}
X    if (parms.ua_roc && conf[0] == 'r' && conf[1] == '-')
X	if (user.u_access != A_WITNESS)
X	    {
X	    puts("Only Fairwitnesses can make READ-ONLY conferences.");
X	    log("Attempted mk of RO conf by non-FW");
X	    return 0;
X	    }
X	else
X	    {
X	    puts("This conference will be READ-ONLY, except to Fairwitnesses.\nIf you want anyone to be able to add to it, answer NO and use a name not\nbeginning with \"R-\".");
X	    printf("\nDo you want to make this READ-ONLY conference (N)? ");
X	    gets(line);
X	    log("Read-only.  Create? %s", line);
X	    if (ToLower(line[0]) != 'y')
X		return 0;
X	    }
X#ifdef BSD
X    sprintf(line, "%s/%s", MSGBASE, conf);
X    if (mkdir(line) < 0) {
X    	log("Mkconf of %s failed", conf);
X    	puts("Hmmm... guess you aren't allowed.");
X    	return 0;
X    }
X    chown(line, geteuid(), getegid());
X#else  !BSD
X    sprintf(line, "exec mkconf %s/%s %d", MSGBASE, conf, geteuid());
X    if (system(line) != 0)
X	{
X	log("Mkconf of %s failed.", conf);
X	puts("Hmmm... guess you aren't allowed.");
X	return 0;
X	}
X#endif BSD
X    log("New conference: %s", conf);
X    sprintf(line, "%s/%s/himsg", MSGBASE, conf);
X    if ((f = fopen(line, "w")) == NULL)
X	{
X	log("Error %d opening %s", line);
X	puts("Can't create high message file.  Strange...");
X	return 0;
X	}
X    fputs("0\n", f);
X    fclose(f);
X    puts("You will now be placed in the message editor to make a message describing\nthis conferemnce.  It will be addressed to, and readable by, all users.");
X    mkmsg("All", "This conference", conf, 0);
X    return 1;
X    }
X
Xisprivate(msg)
X    char *msg;
X    {
X    FILE *fp;
X    char line[1024], to[1024], from[1024];
X    short pflag;
X
X    if (user.u_access == A_WITNESS)
X	return 0;
X    if ((fp = fopen(msg, "r")) == NULL)
X	return 0;
X    strcpy(to, "All");
X    pflag = 0;
X    while (fgets(line, 1024, fp) != NULL)
X	{
X	if (line[0] == '\n')
X	    break;
X	else if (strncmp(line, "To: ", 4) == 0)
X	    strcpy(to, &line[4]);
X	else if (strncmp(line, "From: ", 6) == 0)
X	    strcpy(from, &line[6]);
X	else if (strncmp(line, "Subject (Private): ", 19) == 0)
X	    pflag = 1;
X	}
X    fclose(fp);
X    if (pflag && strcmp(user.u_name, to) == 0)
X	return 0;
X    else if (pflag && strcmp(user.u_name, from) == 0)
X	return 0;
X    else if (pflag)
X	{
X	log("Message %s is private.", msg);
X	return 1;
X	}
X    else
X	return 0;
X    }
X
Xisunsub(conf)
Xchar *conf; {
X    struct _himsg *hip;
X
X    for (hip = hicnts; hip != NULL; hip = hip->hi_next)
X        if (strcmp(hip->hi_conf, conf) == 0)
X            break;
X    return (hip != NULL && hip->hi_uns == HI_UNSUB);
X}
X
Xunsubscribe(conf)
Xchar *conf; {
X    struct _himsg *hip, *workp;
X    char line[512];
X    
X    if (s_cmp(conf, "general") == 0) {
X        puts("Can't unsubscribe the general conference.");
X        log("Attempted to unsubscribe to general.");
X        return;
X    }
X    if (s_cmp(conf, user.u_lconf) == 0) {
X        printf("Unsubscribe to login conference (N)? ");
X        gets(line);
X        log("Unsub login conf? %s", line);
X        if (ToLower(line[0]) != 'y')
X            return;
X        strcpy(user.u_lconf, "general");
X    }
X    for (hip = hicnts; hip != NULL; hip = hip->hi_next)
X        if (strcmp(hip->hi_conf, conf) == 0)
X            break;
X    if (hip != NULL)
X        hip->hi_uns = HI_UNSUB;
X    else {
X	if ((workp = (struct _himsg *) calloc((unsigned) 1, sizeof (struct _himsg))) == NULL)
X	    {
X	    log("Error %d allocating _himsg for %s", errno, conf);
X	    panic("alloc");
X	    }
X	strcpy(workp->hi_conf, conf);
X	workp->hi_num = 0;
X	workp->hi_next = hicnts;
X	hicnts = workp;
X	workp->hi_uns = HI_UNSUB;
X    }
X    log("Unsubscribed to %s", conf);
X    printf("Unsubscribed to conference %s.\n", conf);
X}
X
Xresubscribe(conf)
Xchar *conf; {
X    struct _himsg *hip, *workp;
X    
X    for (hip = hicnts; hip != NULL; hip = hip->hi_next)
X        if (strcmp(hip->hi_conf, conf) == 0)
X            break;
X    if (hip != NULL)
X        hip->hi_uns = HI_SUBSCR;
X    else {
X	if ((workp = (struct _himsg *) calloc((unsigned) 1, sizeof (struct _himsg))) == NULL)
X	    {
X	    log("Error %d allocating _himsg for %s", errno, conf);
X	    panic("alloc");
X	    }
X	strcpy(workp->hi_conf, conf);
X	workp->hi_num = 0;
X	workp->hi_next = hicnts;
X	hicnts = workp;
X	workp->hi_uns = HI_SUBSCR;
X    }
X    log("Resubscribed to %s", conf);
X    printf("Resubscribed to conference %s.\n", conf);
X}
X
Xunsub(c)
Xchar *c; {
X    char line[256], *p;
X
X    p = c - 1;
X    while (*++p != '\0')
X	if (*p == ' ')
X	    if (isconf(++p))
X		{
X		unsubscribe(p);
X		return 1;
X		}
X    for (;;) {
X	printf("Unsubscribe to which conference (%s) [NONE to abort]: ", conference);
X	gets(line);
X	log("Unsub conference: %s", line);
X	if (line[0] == '\0') {
X	    unsubscribe(conference);
X	    return 1;
X	}
X	if (s_cmp(line, "none") == 0)
X	    return 1;
X	if (isconf(line)) {
X	    unsubscribe(line);
X	    return 1;
X	}
X    }
X}
X
Xisconf(conf)
Xchar *conf; {
X    char *cp, line[256];
X
X    for (cp = conf; *cp != 0; cp++) {
X    	if (!isprint(*cp))
X	    return 0;
X	else if (*cp == '/' || *cp == '!' || *cp == ':')
X	    *cp = '.';
X	else
X	    *cp = ToLower(*cp);
X	}
X    if (cp - conf > CONFSIZE)
X	conf[CONFSIZE] = '\0';
X    sprintf(line, "%s/%s", MSGBASE, conf);
X    if (chdir(line) == -1)
X        return 0;
X    chdir("../..");
X    return 1;
X}
X
Xsetlconf(conf)
Xchar *conf; {
X    char line[256], *p;
X
X    if (s_cmp(user.u_name, "guest") == 0) {
X        log("Guest SET LOGIN CONF denied.");
X        puts("GUEST can't set a login conference.");
X        return 1;
X    }
X    p = conf - 1;
X    while (*++p != '\0')
X	if (*p == ' ')
X	    if (isconf(++p)) {
X                if (isunsub(p)) {
X                    puts("You're unsubscribed from it.  <J>oin it and resubscribe.");
X                    log("Unsubscribed -- login conf set aborted.");
X                    return 1;
X                }
X		strcpy(user.u_lconf, p);
X		log("New login conference: %s", user.u_lconf);
X                putuser(user.u_name, &user);
X		return 1;
X	    }
X    do {
X	printf("Enter new login conference: ");
X	gets(line);
X	log("Login conference: %s", line);
X	if (line[0] == '\0')
X	    return 1;
X    } while (!isconf(line));
X    if (isunsub(line)) {
X        puts("You're unsubscribed from it.  <J>oin it and resubscribe.");
X        log("Unsubscribed -- login conf set aborted.");
X        return 1;
X    }
X    strcpy(user.u_lconf, line);
X    log("New login conference: %s", user.u_lconf);
X    putuser(user.u_name, &user);
X    return 1;
X}
X
Xuisunsub(user, conf)
Xchar *user, *conf; {
X    struct _himsg *hip, *uhi;
X    char *cp;
X
X    for (cp = user; *cp != '\0'; cp++)
X        *cp = ToLower(*cp);
X    if ((uhi = readhigh(user)) < 0) {
X        log("Couldn't read %s's userindex.", user);
X        return 0;
X    }
X    printf("Checking %s's user index...\n", user);
X    for (hip = uhi; hip != NULL; hip = hip->hi_next)
X        if (strcmp(hip->hi_conf, conf) == 0)
X            break;
X    cp = (hip != NULL && hip->hi_uns == HI_UNSUB? "!": ":");
X    for (hip = uhi; hip != NULL; hip = uhi) {
X    	uhi = hip->hi_next;
X    	free((char *) hip);
X    }
X    return (*cp == '!');
X}
X
Xcleanhigh() {
X    struct _himsg *hip, *lastp;
X    DIR *conferences;
X    struct direct *conf;
X    
X    lastp = NULL;
X    puts("Checking for deleted conferences...");
X    for (hip = hicnts; hip != NULL; lastp = hip, hip = hip->hi_next) {
X        if (!isconf(hip->hi_conf)) {
X            printf("Conference \"%s\" was deleted since your last session.\n", hip->hi_conf);
X            if (lastp == NULL)
X                hicnts = hip->hi_next;
X            else
X                lastp->hi_next = hip->hi_next;
X            free((char *) hip);
X        }
X    }
X    puts("\nChecking for new conferences...");
X    if ((conferences = opendir(MSGBASE)) == NULL) {
X        log("Error %d opening dir %s/", errno, MSGBASE);
X        panic("msgdir");
X    }
X    while ((conf = readdir(conferences)) != NULL) {
X        if (strcmp(conf->d_name, ".") == 0)
X            continue;
X        if (strcmp(conf->d_name, "..") == 0)
X            continue;
X        for (hip = hicnts; hip != NULL; hip = hip->hi_next)
X            if (strcmp(hip->hi_conf, conf->d_name) == 0)
X                break;
X        if (hip == NULL)
X            printf("Conference \"%s\" has been created since your last session.\n", conf->d_name);
X    }
X    closedir(conferences);
X}
--EOF:conf.c--
fi

if test -r "ua.h"; then
	echo "File ua.h exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="ua.h"
	esac
else
	newname="ua.h"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:ua.h--' > "$newname"
X/*
X *	@(#)ua.h	1.1 (TDI) 7/18/86 21:01:59
X#
X# Modification History:
X#
X#   Ver. 1.1 created 07/18/86 at 21:01:59 by brandon
X#     Converted to SCCS 07/18/86 21:01:59
X *	@(#)Copyright (C) 1984, 85, 86 by Brandon S. Allbery.
X#
X# Modification History:
X#
X#   Ver. 1.1 created 07/18/86 at 21:01:59 by brandon
X#     Converted to SCCS 07/18/86 21:01:59
X *
X *	@(#)This file is part of UNaXcess version 0.4.5.
X#
X# Modification History:
X#
X#   Ver. 1.1 created 07/18/86 at 21:01:59 by brandon
X#     Converted to SCCS 07/18/86 21:01:59
X *
X *	Permission is hereby granted to copy and distribute this program
X *	freely.  Permission is NOT given to modify this program or distribute
X *	it at cost, except for charging a reasonable media/copying fee.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <setjmp.h>
X#include <pwd.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <errno.h>
X#include "user.h"
X#include "dir.h"
X#include "sys.h"
X
X#ifndef SIGUSR1
X#define SIGUSR1		NSIG-1
X#endif
X
X#define SYSOP	parms.ua_sysop
X#define LOG	"Logfile"
X#define MOTD	"motd"
X#define PASSWD	"userfile"
X#define MSGBASE	"msgdir"
X#define NEWMSGS	"userind"
X#define NEWUSER	"NewMessage"
X#define CONFIG	"ua-config"
X
Xextern jmp_buf cmdloop;			/* so intrp() works */
Xextern int logsig(), quit(), intrp(), thatsall();
Xextern int doread(), doscan();
Xextern struct _himsg *readhigh();
Xextern struct tm *localtime();
Xextern struct passwd *getpwuid();
Xextern char *getowner(), *visible(), *mktemp(), *crypt(), *date(), *longdate(), *getenv(), *gets(), *fgets();
Xextern int errno, nopause;
Xextern char conference[];
X
X#define ToLower(x) (isupper(x)?tolower(x):x)	/* not all tolower() work */
X#define ToUpper(x) (islower(x)?toupper(x):x)	/* not all toupper() work */
X#define uncntrl(x) (x+'@')	/* beware of non-ASCII character sets! */
X
X#ifdef SYS5
X#  define SYS3
X#endif SYS5
X
X#ifndef SYS3
X#  ifdef XENIX3
X#    define RIndex(s,c) strrchr(s, c)
X#    define Index(s,c) strchr(s, c)
Xextern char *strrchr(), *strchr();
X#  else  XENIX3
X#    ifdef XENIX5
X#      define RIndex(s,c) strrchr(s, c)
X#      define Index(s,c) strchr(s, c)
Xextern char *strrchr(), *strchr();
X#    else  XENIX5
X#      define RIndex(s,c) rindex(s,c)
X#      define Index(s,c) index(s,c)
Xextern char *rindex(), *index();
X#    endif XENIX5
X#  endif XENIX3
X#else
X#  define RIndex(s,c) strrchr(s, c)
X#  define Index(s,c) strchr(s, c)
Xextern char *strrchr(), *strchr();
X#endif
X
X#ifdef BSD
X#  define CONFSIZE	32
X#else
X#  define CONFSIZE	14
X#endif BSD
X
X#ifdef XENIX3
X#  define XENIX
X#else  XENIX3
X#  ifdef XENIX5
X#    define XENIX
X#  endif XENIX5
X#endif XENIX3
--EOF:ua.h--
fi

if test -r "user.h"; then
	echo "File user.h exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="user.h"
	esac
else
	newname="user.h"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:user.h--' > "$newname"
X/*
X *	@(#)user.h	1.1 (TDI) 7/18/86 21:02:06
X#
X# Modification History:
X#
X#   Ver. 1.1 created 07/18/86 at 21:02:06 by brandon
X#     Converted to SCCS 07/18/86 21:02:06
X *	@(#)Copyright (C) 1984, 85, 86 by Brandon S. Allbery.
X#
X# Modification History:
X#
X#   Ver. 1.1 created 07/18/86 at 21:02:06 by brandon
X#     Converted to SCCS 07/18/86 21:02:06
X *
X *	@(#)This file is part of UNaXcess version 0.4.5.
X#
X# Modification History:
X#
X#   Ver. 1.1 created 07/18/86 at 21:02:06 by brandon
X#     Converted to SCCS 07/18/86 21:02:06
X *
X *	Permission is hereby granted to copy and distribute this program
X *	freely.  Permission is NOT given to modify this program or distribute
X *	it at cost, except for charging a reasonable media/copying fee.
X */
X
Xstruct user
X    {
X    char u_name[33];			/* user name */
X    char u_pass[12];			/* password */
X    short u_access;			/* can killmsg() or shell() ? */
X    char u_login[9];			/* Intended for system login name */
X    short u_llen;			/* line length, or default u_access */
X    short u_nbull;			/* highest numbered bulletin read */
X    char u_lconf[33];			/* login conference (dft = general) */
X    }
X    ;					/* current user */
X
Xextern struct user user;
X
X/* access modes, in u_access */
X
X#define A_NONE		0		/* invalidated login */
X#define A_GUEST		1		/* read-only access */
X#define A_USER		2		/* standard access */
X#define A_FILES		3		/* can udl() */
X#define A_SYSTEM	4		/* can system() */
X#define A_WITNESS	5		/* Fairwitness */
X#define A_MKUSER	6		/* Special: user creator */
X
Xstruct _himsg
X    {
X    char hi_conf[33];			/* conference this record refers to */
X    char hi_uns;			/* unsubscribed to this conference */
X    short hi_num;			/* high message in this conference */
X    struct _himsg *hi_next;
X    }
X    ;
X
Xextern struct _himsg *hicnts;
X
X#define HI_SUBSCR	0
X#define HI_UNSUB	1
--EOF:user.h--
fi

if test -r "dir.h"; then
	echo "File dir.h exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="dir.h"
	esac
else
	newname="dir.h"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:dir.h--' > "$newname"
X/*
X *
X *				N O T I C E
X *
X * This file is NOT a copyrighted part of the UNaXcess distribution.  These
X * are directory-reading routines which are compatible with the Berkeley Unix
X * (4.2BSD, 4.3BSD) directory routines.  They come from the Usenet news
X * distribution and are in the public domain.
X *
X * To get the best use of them:  install the file "dir.h" in /usr/include
X * -- standard usage calls it "ndir.h", and make a random archive of dir.o and
X * put it in /usr/lib/libndir.a .  It is then available with "-lndir".
X *
X * Bell System {III, V} sites, just make an archive -- it is only one file
X * anyway.  Other sites will have to run ranlib on the archive to keep ld
X * happy.
X */
X
X/*	dir.h	4.4	82/07/25	*/
X
X#ifdef BSD
X#include <sys/dir.h>
X#else
X
X/*
X * A directory consists of some number of blocks of DIRBLKSIZ
X * bytes, where DIRBLKSIZ is chosen such that it can be transferred
X * to disk in a single atomic operation (e.g. 512 bytes on most machines).
X *
X * Each DIRBLKSIZ byte block contains some number of directory entry
X * structures, which are of variable length.  Each directory entry has
X * a struct direct at the front of it, containing its inode number,
X * the length of the entry, and the length of the name contained in
X * the entry.  These are followed by the name padded to a 4 byte boundary
X * with null bytes.  All names are guaranteed null terminated.
X * The maximum length of a name in a directory is MAXNAMLEN.
X *
X * The macro DIRSIZ(dp) gives the amount of space required to represent
X * a directory entry.  Free space in a directory is represented by
X * entries which have dp->d_reclen >= DIRSIZ(dp).  All DIRBLKSIZ bytes
X * in a directory block are claimed by the directory entries.  This
X * usually results in the last entry in a directory having a large
X * dp->d_reclen.  When entries are deleted from a directory, the
X * space is returned to the previous entry in the same directory
X * block by increasing its dp->d_reclen.  If the first entry of
X * a directory block is free, then its dp->d_ino is set to 0.
X * Entries other than the first in a directory do not normally have
X * dp->d_ino set to 0.
X */
X#define DIRBLKSIZ	512
X#define	MAXNAMLEN	255
X
Xstruct	direct {
X	long	d_ino;			/* inode number of entry */
X	short	d_reclen;		/* length of this record */
X	short	d_namlen;		/* length of string in d_name */
X	char	d_name[MAXNAMLEN + 1];	/* name must be no longer than this */
X};
X
X/*
X * The DIRSIZ macro gives the minimum record length which will hold
X * the directory entry.  This requires the amount of space in struct direct
X * without the d_name field, plus enough space for the name with a terminating
X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
X */
X#ifdef DIRSIZ
X#undef DIRSIZ
X#endif
X#define DIRSIZ(dp) \
X    ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
X
X#ifndef KERNEL
X/*
X * Definitions for library routines operating on directories.
X */
Xtypedef struct _dirdesc {
X	int	dd_fd;
X	long	dd_loc;
X	long	dd_size;
X	char	dd_buf[DIRBLKSIZ];
X} DIR;
X#ifndef NULL
X#define NULL 0
X#endif
Xextern	DIR *opendir();
Xextern	struct direct *readdir();
Xextern	closedir();
X#endif KERNEL
X
X#endif BSD
--EOF:dir.h--
fi

if test -r "sys.h"; then
	echo "File sys.h exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="sys.h"
	esac
else
	newname="sys.h"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:sys.h--' > "$newname"
X/*
X *	@(#)sys.h	1.1 (TDI) 7/18/86 21:01:55
X#
X# Modification History:
X#
X#   Ver. 1.1 created 07/18/86 at 21:01:55 by brandon
X#     Converted to SCCS 07/18/86 21:01:55
X *	@(#)Copyright (C) 1984, 85, 86 by Brandon S. Allbery.
X#
X# Modification History:
X#
X#   Ver. 1.1 created 07/18/86 at 21:01:55 by brandon
X#     Converted to SCCS 07/18/86 21:01:55
X *
X *	@(#)This file is part of UNaXcess version 0.4.5.
X#
X# Modification History:
X#
X#   Ver. 1.1 created 07/18/86 at 21:01:55 by brandon
X#     Converted to SCCS 07/18/86 21:01:55
X *
X *	Permission is hereby granted to copy and distribute this program
X *	freely.  Permission is NOT given to modify this program or distribute
X *	it at cost, except for charging a reasonable media/copying fee.
X */
X
Xstruct sys {
X	char ua_home[50];	/* UNaXcess lives here */
X	char ua_roc;	/* read-only conference flag */
X	char ua_xrc;	/* x-rated conference flag */
X	char ua_edit[50];	/* the default editor */
X	char ua_shell[50];	/* the default shell */
X	char ua_env;	/* read environment for SHELL, EDITOR */
X	char ua_bbs[32];	/* name of BBS login */
X	char ua_tlimit;	/* minutes until logout */
X	char ua_sysop[32];	/* name of the sysop login */
X	char ua_pm;	/* allow private messages? */
X	char ua_log;	/* keep a log? */
X	char ua_bnr[50];	/* path of banner file, EOS = internal */
X	char ua_login[256];	/* login message, EOS = internal */
X	char ua_hco;	/* hard-copy-output mode enable */
X	char ua_nla;	/* number of attempts to login allowed */
X	char ua_auc[256];	/* ascii upload command */
X	char ua_adc[256];	/* ascii download command */
X	char ua_xuc[256];	/* Xmodem upload command */
X	char ua_xdc[256];	/* Xmodem download command */
X	char ua_kuc[256];	/* Kermit upload command */
X	char ua_kdc[256];	/* Kermit download command */
X};
X
Xextern struct sys parms;
--EOF:sys.h--
fi

if test -r "README"; then
	echo "File README exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="README"
	esac
else
	newname="README"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:README--' > "$newname"
X
X		  Supplemental notes for installing UNaXcess
X
X
XThis is UNaXcess, in this incarnation (V0.4.5) a BBS for Unix systems.
XV1.x is intended to be a business shell with a conferencing system, electronic
Xmail, and system administration utilities in it (along with WP, spreadsheet,
Xand database access).
X
XThis directory contains the UNaXcess Distribution.  There is no User's Guide
Xat present, and it is only known to work on V7 and AT&T System III and System
XV, although extensive testing has been done under Xenix 3.0.  Berkeley
XUnix should work.
X
XThe shar file should have created a number of files in this directory, and
Xa subdirectory called ``Utilities'' containing even more files.  Inspect the
XMakefile (it SHOULD work as it is on any system, but you never know), then
Xtype ``make SYSTEM=system all'', where system is one of:  BSD (4.2 and 4.3
Xonly), SYS3 (real AT&T System III only), SYS5 (ditto), XENIX3 (also Unisoft
X3.x), XENIX5 (possibly also Unisoft 5.x), and V7 (catchall).  If it doesn't
Xwork, let me know; I'd like this thing to be reasonably compatible.  (Someday
Xthey'll get a #include file on all systems to say which OS variant they're
Xusing...)
X
XIf you wish to install UNaXcess without using root privileges, place the
Xstring ``-DNOAUTOPATH='"/unaxcess/home/directory"''' in the Makefile, on the
XCFLAGS line.  WARNING! ! !  USING UNAXCESS WITHOUT SET-UID MAKES SECURITY
XARRANGEMENTS IMPOSSIBLE.
X
XTo install UNaXcess, type ``sh Utilities/install.sh'' while in the source
Xdirectory. You will be asked various questions and be placed in the editor to
Xcompose a bulletin.
X
XAfter installation, you should edit the NewMessage file as specified by the
Xinstallation script.  It should say anything you want new users to know before
Xregistering as UNaXcess users.
X
XYou should also run UnaXcess as the sysop and type ``user new'' to edit the
Xnewuser setup.  The parameter to be set is the access level granted.  As
Xdistributed, this is USER access level.  For business applications, this
Xshould be SYSTEM (allowing shell access).  For certain applications, it should
Xbe set to GUEST (users can only post to the GUEST conference).  Note that
Xthere are 6 access levels:
X
X	NONE		- de-activated logins or un-validated logins
X	MAKEUSER	- runs the user maker before entering
X	GUEST		- can read anything (except Restricted conferences),
X			  only add to GUEST
X	FILES		- can access the File Section
X	SYSTEM		- can use the C command (shell access), also
X			  can use a system editor to edit messages
X	FAIRWITNESS	- all but a sysop.  The only limitation is that
X			  only the Sysop (who is a fairwitness) can make
X			  or break other fairwitnesses.
X
X-----------------------
XSome notes:
X
XThe configuration file is stored in the home directory of the UNaXcess system
Xand is named ``ua-config''.  It contains lines of the format:
X
X			    variable	value
X
XThe defaults are contained in param.c, not that you should change them (that's
Xwhat the config file is for).  The variables are:
X
X	readonly	boolean	Indicates whether Read-Only conferences are
X				valid.  Read-Only conferences begin with
X				the characters ``r-''.
X
X	x-rated		boolean	Indicates whether X-Rated (restricted)
X				conferences are valid.  X-Rated conferences
X				begin with the characters ``x-''.
X
X	editor		string	The path of the editor to use in creating
X				messages.  The editor ``ua-edit'' is the
X				built-in editor.  This editor is used only
X				if the user has SYSTEM access or greater;
X				otherwise, the built-in editor is used.
X
X	shell		string	The path of the shell to use when the C
X				command is invoked.  The C command is not
X				valid for users whose access is less than
X				SYSTEM level.  (Note:  there is no reason
X				that this must be a shell.  The original
X				version of the File Section was a separate
X				program accessed by the C command.)
X
X	read-env	boolean	Indicates whether the user's environment
X				should be read to indicate the shell and
X				editor.
X
X	bbs-user	string	UNaXcess will permit a user whose Unix login
X				name is the same as his UA login name to log
X				in from the shell without specifying his name
X				or password.  The ``bbs-user'' is exempt from
X				this; it is intended to prevent breaches in
X				security by invoking a shell (C command) and
X				running ua from the shell.
X
X	time-limit	number	This is the time limit for UNaXcess in minutes.
X				If this is zero, no time-out occurs.  A warning
X				is given five minutes before a logout; if the
X				user is in the shell or editor when his time
X				runs out, exiting the shell or editor will
X				log him out.
X
X	sysop		string	The name of the UNaXcess sysop is configurable.
X				Special-purpose systems may indicate a more
X				descriptive name (i.e. DUNGEON MASTER for a
X				fantasy gaming BBS).
X
X	private-msgs	boolean	Indicates whether private messages may be
X				created.
X
X	logging		boolean	Indicates whether a session log should be kept
X				in Logfile.  This allows you to track security
X				problems, people who misuse the system, or
X				(heaven forbid) bugs.  However, the log gets
X				big rather quickly, so you may wish to leave
X				this off.
X
X	banner		string	This string contains the name of a file whose
X				contents are printed when a user runs UNaXcess,
X				before the login message.  If the string is
X				empty, a default banner is used.
X
X	login-msg	string	This string is printed as the login prompt.
X				If it is empty, a default string is used.
X				You might want to change this if you disallow
X				GUEST or NEW logins, or change their names.
X
X	pauses		number	This is 2 for no pauses, 1 for user-specified
X				pausing, and 0 for forced pausing.  A cheap
X				built-in pager is used.
X
X	login-tries	number	If this is not 0, it specifies the number of
X				login attempts permitted before UNaXcess exits.
X
X	bbs-directory	string	The directory where the UNaXcess file can be
X				found.  The home of the owner of UNaXcess is
X				used to find the ua-config file (or the
X				NOAUTOPATH directory if you have defined it);
X				after this, the directory is changed to the
X				bbs-directory and files are expected to be
X				found there. The default is the directory used
X				to find the ua-config file.
X
X	ascii-upload	string	These are the command strings to be passed to
X	ascii-download		/bin/sh via system() to perform the specified
X	xmodem-upload		action.  The defaults are:  a cat string for
X	xmodem-download		ascii, umodem -[sr]b for XModem, and C-Kermit
X	kermit-upload		command strings for Kermit.  The string ``%s''
X	kermit-download		will be replaced with the file's path; if no
X				``%s'' is specified, the pathname will be
X				appended to the command, preceded by a space.
X				If the string is empty, UNaXcess will assume
X				that no capacity exists for the action.
X
XA string is specified in double quotes:  "/bin/sh".  Actually, the quotes can
Xbe left off, but in this case the string cannot contain spaces or tabs.  A
Xboolean is indicated as YES or NO (Y or N will do, and case doesn't matter).
XA number is simply a number, but is limited to 0-255.  Strings may contain
Xescapes (\n \r \t \b \f \e \nnn \a) (\a is bell).  Comments are indicated by
X#; they do NOT have to be at the beginning of a line.
X
X---
X
XThe up/download (UDL) module uses a log file for uploads, and a directory for
Xdownloads.  Both files are created by the install script; "upload-log" is
Xempty, and "directory" contains one line:
X
X	GENERAL file branch; <date> by <sysop name>: General up/downloads
X
XThis is the basic format of a directory entry.  The word "branch" is reserved,
Xand indicates that this is the directory entry for the branch itself; files
Xin this branch have the word "branch" replaced by the file name.  There is
Xno way to automatically create or delete files or branches; it has to be done
Xfrom the shell.  (On the other hand, if the branch has a (UNIX) directory in
Xthe "uploads" directory, uploads will be logged there in such a way that the
Xlog entry may be simply copied from the upload-log to the directory.)
X
XNote that each branch is represented by a UNIX directory in the "library"
Xdirectory.  The name should be lowercase, although user input of the name
Xand the name listed in the "directory" file are case-independent.  If uploads
Xare to be permitted, a directory of the same name should be created in the
X"upload" directory.
X
X---
X
XUNaXcess depends on being setuid to its owner, not only for permissions in
Xthe BBS, but also to insure that the home directory (containing the message
Xdatabase and config file) can be located.  (You can avoid this by using
XNOAUTOPATH, as discussed above.)  If NOAUTOPATH is not defined, a program
X``mkconf'' is used to create conferences; it is essentially a (non-AT&T)
Xreimplementation of /bin/mkdir, except that it does not check the effective
XUID of the invoker.  This is necessary because of the way Unix handles set-
Xuid.  If NOAUTOPATH is defined, mkdir is used.  Please note that mkconf MUST
Xbe setuid to work, and if the ``ua'' executable is setuid, mkconf MUST be
Xused or conference creation will be impossible.
X
X---
X
XUNaXcess is Copyright (C) 1986 by Brandon S. Allbery.  Permission is hereby
Xgranted to copy and freely distribute this code. You may charge only a
Xreasonable handling/copying fee for distribution of this code; you may not
Xsell it or include it in a commercial package for resale.
X
X++Brandon Allbery
X(P.S.  Unix is a trademark of AT&T.)
X
X---------------
X
XA few more comments on this distribution:
X
XJohn P. Nelson couldn't figure out why I rewrote mkdir for UNaXcess.  The
Xreason is the way setuid programs are execed.  If UNaXcess is setuid to its
Xowner, a call to mkdir will result in, not the UNaXcess owner's permissions,
Xbut the USER'S permissions being used.  This should NEVER be a valid
Xaccess permission for UNaXcess files (if it is, you've got a security
Xproblem).  Therefore, mkconf -- which does not check permissions.  Not the
Xsafest way to do things, except that it should not be runnable by a uid not
Xthat of the owner of UA.  BSD4.2 has the *best* way to do it:  mkdir() system
Xcall.  I have put this in if BSD is #defined, and install.sh checks to see if
X/usr/include/sys/socket.h exists and if so does NOT install mkconf.  If you
Xare in 4.2BSD and have a superuser create the UNaXcess owner's login for you,
Xyou can run install without being root (but you have to be su'd to the owner
Xof the BBS).
X
XThe first distribution wouldn't run on Xenix or on 3B's because _doprnt()
Xwasn't available.  The v*printf() routines wouldn't have helped in this case.
XSo in this version, msg() is a (non-AT&T) printf().  The only formats
Xsupported are of the form:
X
X		%[-][width[.ext]]fmt (i.e. no USG extensions).
X
XThe hyphen indicates left-justified, vs. right (default).  Width specifies the
Xnumber of character positions to use; if it has a leading zero in a numeric
Xformat, leading zeroes are not suppressed.  The only format characters
Xsupported are:
X
X		%c
X		%d
X		%D
X		%ld
X		%s
X
Xall of which work as in printf().
X
XIt seems that BSD sscanf() is broken:  if %[span] does not match at least one
Xcharacter, it fails.  (Or maybe USG is broken, since it succeeds in that
Xcase.  I guess it depends on how you feel at the time...)  So the password
Xfile manipulation routines have been changed to correctly parse this, as well
Xas handle another potential problem:  the password structure uses short's, and
Xsscanf()'s with the %hd format so it works on 32-bit machines, but not all
Xmachines support %hd.  If anyone has had problems getting the password file
Xhandling to work right, this is probably the reason.
X
X-------------
X
XAdditional notes (7/18/86):
X
XThe elusive userindex bug has finally been caught.  Most configuration
Xproblems have also been dealt with; it should be much smoother on
Xinstallation.
X
XUNaXcess plans for expansion (expect these in coming releases):
X
X	- Unix mail support
X	- Bidirectional news support, without the uanews kludge
X	  (Both of these will require SYSTEM access.)
X	- Message forwarding to remote machines via mail.
X	- A system adminitration program
X
X++Brandon
--EOF:README--
fi

echo "End of archive."
exit 0


-- 
  ---------------- /--/	Brandon S. Allbery		UUCP: decvax!cwruecmp!
 /              / /|\/	Tridelta Industries, Inc.        ncoast!tdi2!brandon
----    -------- /-++	7350 Corporate Blvd.		PHONE: +1 216 974 9210
   /   / /---,  ----	Mentor, Ohio 44060		SYSOP: UNaXcess/ncoast
  /   / /    / /  /	     -- HOME --			 (216) 781-6201 24 hrs.
 /   / /    / /  /	6615 Center St. Apt. A1-105	ARPA:  ncoast!allbery%
----  -----~ ----	Mentor, Ohio 44060-4101		 case.CSNET@csnet-relay