[net.sources] UNaXcess 0.4.4 - Part 2 of 4

allbery@ncoast.UUCP (Brandon S. Allbery) (07/26/86)

[We're short on disk space, so the other parts will go out later.  ++Brandon]
---------------------------------- cut here ---------------------------------
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#           msg.c         conf.c           ua.h         user.h
#           dir.h          sys.h         README
#
echo 'x - msg.c'
sed 's/^X//' <<'________This_Is_The_END________' >>msg.c
X/*
X * @(#)msg.c	1.1 86/05/05 01:43:43 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)msg.c	1.1 86/05/05 01:43:43 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
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    }
________This_Is_The_END________
echo 'x - conf.c'
sed 's/^X//' <<'________This_Is_The_END________' >>conf.c
X/*
X * @(#)conf.c	1.1 86/05/05 01:43:35 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)conf.c	1.1 86/05/05 01:43:35 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
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}
________This_Is_The_END________
echo 'x - ua.h'
sed 's/^X//' <<'________This_Is_The_END________' >>ua.h
X/*
X * @(#)ua.h	1.1 86/05/05 01:43:58 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
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
________This_Is_The_END________
echo 'x - user.h'
sed 's/^X//' <<'________This_Is_The_END________' >>user.h
X/*
X * @(#)user.h	1.1 86/05/05 01:44:11 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
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[6];			/* 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
________This_Is_The_END________
echo 'x - dir.h'
sed 's/^X//' <<'________This_Is_The_END________' >>dir.h
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
________This_Is_The_END________
echo 'x - sys.h'
sed 's/^X//' <<'________This_Is_The_END________' >>sys.h
X/*
X * @(#)sys.h	1.1 86/05/05 01:43:52 tdi2!brandon @(#)
X * @(#) Copyright (C) 1985 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
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;
________This_Is_The_END________
echo 'x - README'
sed 's/^X//' <<'________This_Is_The_END________' >>README
XUNaXcess Version 0.04.04		    Sunday, May 4, 1986 - 10:11 PM
X
X		  Supplemental notes for installing UNaXcess
X
X
XThis is UNaXcess, in this incarnation (V0.xx.xx) 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.  Berkeley
XUnix should work; I have attempted to account for System V (the utmp file
Xchanges are the only known problem as yet), but I cannot as yet test it.
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... but you'll have to be Lazarus Long to live to see it!  :-)
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! ! !  This will reduce the security on UNaXcess,
Xpossibly to the point where it cannot be made secure.  I strongly suggest NOT
Xusing NOAUTOPATH.
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, UNaXcess Version 0.04.03 and
Xderivatives ONLY.  Version 1.00.00 and later may NOT be copied or distributed
Xwithout the author's written permission. You may charge only a reasonable
Xhandling/copying fee for distribution of this code; you may not sell it or
Xinclude 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.
________This_Is_The_END________
exit
-- 
  ---------------- /--/	Brandon S. Allbery		UUCP:
 /              / /|\/	Tridelta Industries, Inc.       decvax!cwruecmp!ncoast!
----    -------- /-++	7350 Corporate Blvd.		    tdi2!brandon
   /   / /---,  /--/	Mentor, Ohio 44060		PHONE:  (home)
  /   / /    / /  /	     -- HOME --			+1 216 974 9210
 /   / /    / /  /	6615 Center St. Apt. A1-105	ARPA:  ncoast!allbery%
----  /----~ /--/	Mentor, Ohio 44060-4101		case.CSNET@csnet-relay
-------------------------------------------------------------------------------
			Space -- The Final Frontier

allbery@ncoast.UUCP (Brandon S. Allbery) (07/29/86)

# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#           msg.c         conf.c           ua.h         user.h
#           dir.h          sys.h         README
#
echo 'x - msg.c'
sed 's/^X//' <<'________This_Is_The_END________' >>msg.c
X/*
X * @(#)msg.c	1.1 86/05/05 01:43:43 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)msg.c	1.1 86/05/05 01:43:43 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
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    }
________This_Is_The_END________
echo 'x - conf.c'
sed 's/^X//' <<'________This_Is_The_END________' >>conf.c
X/*
X * @(#)conf.c	1.1 86/05/05 01:43:35 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)conf.c	1.1 86/05/05 01:43:35 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
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}
________This_Is_The_END________
echo 'x - ua.h'
sed 's/^X//' <<'________This_Is_The_END________' >>ua.h
X/*
X * @(#)ua.h	1.1 86/05/05 01:43:58 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
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
________This_Is_The_END________
echo 'x - user.h'
sed 's/^X//' <<'________This_Is_The_END________' >>user.h
X/*
X * @(#)user.h	1.1 86/05/05 01:44:11 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
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[6];			/* 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
________This_Is_The_END________
echo 'x - dir.h'
sed 's/^X//' <<'________This_Is_The_END________' >>dir.h
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
________This_Is_The_END________
echo 'x - sys.h'
sed 's/^X//' <<'________This_Is_The_END________' >>sys.h
X/*
X * @(#)sys.h	1.1 86/05/05 01:43:52 tdi2!brandon @(#)
X * @(#) Copyright (C) 1985 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
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;
________This_Is_The_END________
echo 'x - README'
sed 's/^X//' <<'________This_Is_The_END________' >>README
XUNaXcess Version 0.04.04		    Sunday, May 4, 1986 - 10:11 PM
X
X		  Supplemental notes for installing UNaXcess
X
X
XThis is UNaXcess, in this incarnation (V0.xx.xx) 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.  Berkeley
XUnix should work; I have attempted to account for System V (the utmp file
Xchanges are the only known problem as yet), but I cannot as yet test it.
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... but you'll have to be Lazarus Long to live to see it!  :-)
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! ! !  This will reduce the security on UNaXcess,
Xpossibly to the point where it cannot be made secure.  I strongly suggest NOT
Xusing NOAUTOPATH.
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, UNaXcess Version 0.04.03 and
Xderivatives ONLY.  Version 1.00.00 and later may NOT be copied or distributed
Xwithout the author's written permission. You may charge only a reasonable
Xhandling/copying fee for distribution of this code; you may not sell it or
Xinclude 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.
________This_Is_The_END________
exit
Newsgroups: net.sources
Subject: UNaXcess 0.4.4 - Part 4 of 4
Expires: 
References: 
Sender: 
Reply-To: allbery@ncoast.UUCP (Brandon S. Allbery)
Followup-To: 
Distribution: 
Organization: North Coast Public Access UN*X, Cleveland, Ohio
Keywords: 

Before the shar file, an apology:

I have been excising the V0.04.03/V1.0 messages, since I've decided that the
shell will be called something else (UNaXcess the BBS seems to be more popular
than I thought!).  But when I scanned the two shars I posted a few days ago,
I discovered that I missed a few.  However, fear not; there will be at least
one more V0.x release before the full shebang comes out and I label it 1.0.
(I'm still working on features for this thing, and working on a new I/O system
possibly based on a rewritten version of the ``format'' functions posted
recently.)

++Brandon

---------------------------------- cut here --------------------------------
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#        mkconf.c        mvmsg.c       uanews.c        udate.c
#          uwho.c     install.sh       umotd.sh       upost.sh
#
#
if test ! -f Utilities; then
	echo 'x - Utiltities (directory)'
	mkdir Utilities
	cd Utilities
fi
echo 'x - mkconf.c'
sed 's/^X//' <<'________This_Is_The_END________' >>mkconf.c
X/*
X * @(#)mkconf.c	1.1 86/05/05 01:44:13 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)mkconf.c	1.1 86/05/05 01:44:13 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X
Xchar line[256];
X
X#ifdef SYS5
X#  define SYS3
X#endif SYS5
X
X#ifdef SYS3
X#  define RIndex	strrchr
X#else
X#  ifdef XENIX3
X#    define RIndex	strrchr
X#  else
X#    ifdef XENIX5
X#      define RIndex	strrchr
X#    else
X#      define RIndex	rindex
X#    endif XENIX5
X#  endif XENIX3
X#endif SYS3
X
Xchar *RIndex();
X
Xmain(argc, argv)
X    char **argv;
X    {
X    if (argc != 3)
X	exit(1);
X    mknod(argv[1], S_IFDIR|0755, 0);
X    chown(argv[1], atoi(argv[2]), 50);
X    sprintf(line, "%s/.", argv[1]);
X    link(argv[1], line);
X    *RIndex(argv[1], '/') = '\0';
X    strcat(line, ".");
X    link(argv[1], line);
X    }
________This_Is_The_END________
echo 'x - mvmsg.c'
sed 's/^X//' <<'________This_Is_The_END________' >>mvmsg.c
X/*
X * @(#)mvmsg.c	1.1 86/05/05 01:44:16 tdi2!brandon @(#)
X * @(#) Copyright (C) 1985 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)mvmsg.c	1.1 86/05/05 01:44:16 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
X#include <stdio.h>
X#include <pwd.h>
X#include <sys/types.h>
X#include <sys/stat.h>
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
Xextern long atol();
Xextern struct passwd *getpwuid();
X
Xmain(argc, argv)
Xchar **argv; {
X	char msgdir[256], conf[33];
X	long msg;
X	char *cp, *dp;
X	int status;
X
X	if (argc != 3) {
X		fprintf(stderr, "Usage: mvmsg conf[/n] conf\n");
X		exit(1);
X	}
X	strcpy(msgdir, getpwuid(geteuid())->pw_dir);
X	strcat(msgdir, "/msgdir");
X	for (cp = argv[1], dp = conf; *cp != '/' && *cp != '\0'; cp++, dp++)
X		*dp = *cp;
X	*dp = '\0';
X	if (*cp == '\0') {
X		FILE *fp;
X		char tmp[512];
X		long limit, cnt;
X		
X		sprintf(tmp, "%s/%s/himsg", msgdir, conf);
X		if ((fp = fopen(tmp, "r")) == (FILE *) 0) {
X			fprintf(stderr, "Conference %s: missing himsg...\n", conf);
X			exit(7);
X		}
X		fgets(tmp, sizeof tmp, fp);
X		fclose(fp);
X		if ((limit = atol(tmp)) <= 0) {
X			fprintf(stderr, "Conference %s: invalid himsg...\n", conf);
X			exit(8);
X		}
X		for (cnt = 0, msg = 1; msg <= limit; msg++)
X			if ((status = mvmsg(msgdir, conf, msg, argv[2])) > 0)
X				exit(status);
X			else if (status == 0)
X				cnt++;
X		printf("%ld messages moved from %s to %s.\n", cnt, conf, argv[2]);
X		sprintf(tmp, "%s/%s/himsg", msgdir, conf);
X		if (unlink(tmp) != 0)
X			exit(12);
X		sprintf(tmp, "%s/%s", msgdir, conf);
X		if (rmdir(tmp) != 0)
X			exit(13);
X		exit(cnt == 0? 9: 0);
X	}
X	msg = atol(++cp);
X	if (Index(argv[2], '/') != (char *) 0) {
X		fprintf(stderr, "Usage: mvmsg conf[/n] conf\n");
X		exit(1);
X	}
X	if ((status = mvmsg(msgdir, conf, msg, argv[2])) == -1)
X		fprintf(stderr, "Couldn't read %s/%ld\n", conf, msg);
X	exit(status);
X}
X
Xmvmsg(base, conf, msg, dest)
Xchar *base, *conf, *dest;
Xlong msg; {
X	char path[512], temp[512];
X	long newmsg;
X	FILE *ifp, *ofp;
X	struct stat sbuf;
X	
X	sprintf(path, "%s/%s/%ld", base, conf, msg);
X	if (stat(path, &sbuf) < 0)
X		return -1;	/* likely to be common... */
X	sprintf(path, "%s/%s/himsg", base, dest);
X	if ((ifp = fopen(path, "r")) == (FILE *) 0) {
X		fprintf(stderr, "Conference %s: missing himsg...\n", dest);
X		return 2;
X	}
X	fgets(temp, sizeof temp, ifp);
X	fclose(ifp);
X	if ((newmsg = atol(temp)) <= 0) {
X		fprintf(stderr, "Conference %s: invalid himsg...\n", dest);
X		return 2;
X	}
X	newmsg++;
X	sprintf(path, "%s/%s/%ld", base, conf, msg);
X	if ((ifp = fopen(path, "r")) == (FILE *) 0) {
X		fprintf(stderr, "Conference %s: check permissions on message %ld\n", conf, msg);
X		return 3;
X	}
X	sprintf(path, "%s/%s/%ld", base, dest, newmsg);
X	if (stat(path, &sbuf) == 0) {
X		fprintf(stderr, "Conference %s: corrupted (himsg incorrect)\n", dest);
X		fclose(ifp);
X		return 4;
X	}
X	if ((ofp = fopen(path, "w")) == (FILE *) 0) {
X		fprintf(stderr, "Conference %s: check permissions (can't create message)\n", dest);
X		fclose(ifp);
X		return 5;
X	}
X	while (fgets(temp, sizeof temp, ifp) != (char *) 0) {
X		fputs(temp, ofp);
X		if (ferror(ofp)) {
X			fprintf(stderr, "Write error on %s/%ld\n", dest, newmsg);
X			exit(5);	/* fatal! */
X		}
X	}
X	if (ferror(ifp)) {
X		fprintf(stderr, "Read error on %s/%ld\n", conf, msg);
X		fclose(ifp);
X		fclose(ofp);
X		return 6;
X	}
X	fclose(ifp);
X	fclose(ofp);
X	sprintf(path, "%s/%s/himsg", base, dest);
X	if ((ifp = fopen(path, "w")) == (FILE *) 0) {
X		fprintf(stderr, "Conference %s: check permissions on himsg...\n", dest);
X		return 2;
X	}
X	fprintf(ifp, "%ld\n", newmsg);
X	fclose(ifp);
X	sprintf(path, "%s/%s/%ld", base, conf, msg);
X	if (unlink(path) < 0)
X		return 10;
X	return 0;
X}
X
X#ifndef BSD
X
X/* Berkeley has a rmdir() system call!  Heaven!  But I'm on sys3 (boo hiss) */
X
Xrmdir(path)
Xchar *path; {
X	int pid, status;
X	
X	switch (pid = fork()) {
X		case -1:
X			return -1;
X		case 0:
X			execl("/bin/rmdir", "rmdir", path, 0);
X			exit(-100);
X		default:
X			while (wait(&status) != pid)
X				;
X			return status;
X	}
X}
X
X#endif BSD
________This_Is_The_END________
echo 'x - uanews.c'
sed 's/^X//' <<'________This_Is_The_END________' >>uanews.c
X/*
X * @(#)uanews.c	1.1 86/05/05 01:44:19 tdi2!brandon @(#)
X * @(#) Copyright (C) 1985 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)uanews.c	1.1 86/05/05 01:44:19 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
X#include <stdio.h>
X#include <pwd.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#define NEWSRC		"%newslink"	/* simplified .newsrc */
X#define ACTIVE		"/usr/lib/news/active"
X#define NEWSDIR		"/usr/spool/news"
X/* no need to define special if you're 2.10.2; we can intuit the new active file */
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
Xextern long atol();
Xextern struct passwd *getpwuid();
X
Xextern int errno;
X
Xchar *headers[] = {
X	"From: ",
X	"Reply-To: ",
X	"Date: ",
X	"Subject: ",
X	"Newsgroups: ",
X	NULL,
X};
X
Xmain(argc, argv)
Xchar **argv; {
X	char msgdir[256], conf[33];
X	long msg;
X	char *cp, *dp;
X	int status;
X
X	if (argc != 3) {
X		fprintf(stderr, "Usage: uanews newsgroup[/article] conf\n");
X		exit(1);
X	}
X#ifdef NOAUTOPATH
X	strcpy(msgdir, NOAUTOPATH);
X#else
X	strcpy(msgdir, getpwuid(geteuid())->pw_dir);
X#endif NOAUTOPATH
X	strcat(msgdir, "/msgdir");
X	for (cp = argv[1], dp = conf; *cp != '/' && *cp != '\0'; cp++, dp++)
X		*dp = *cp;
X	*dp = '\0';
X	if (*cp == '\0') {
X		FILE *fp;
X		char tmp[512], ng[512];
X		long limit, cnt, minact;
X		
X		if ((fp = fopen(ACTIVE, "r")) == (FILE *) 0) {
X			fprintf(stderr, "Not a Usenet site (no active file)...\n", conf);
X			exit(7);
X		}
X		while (fgets(tmp, sizeof tmp, fp) != NULL) {
X			if (sscanf(tmp, "%s %ld %ld", ng, &limit, &minact) == 2)
X				minact = 1;	/* < 2.10.2 */
X			if (strcmp(ng, conf) == 0)
X				break;
X		}
X		fclose(fp);
X		if (strcmp(ng, conf) != 0) {
X			fprintf(stderr, "I can't find a newsgroup called %s.\n", conf);
X			exit(13);
X		}
X		if (minact == limit) {
X			fprintf(stderr, "Newsgroup %s is empty.\n", conf);
X			exit(14);
X		}
X		sprintf(tmp, "%s/%s/%s", msgdir, argv[2], NEWSRC);
X		if ((fp = fopen(tmp, "r")) != (FILE *) 0) {
X			char tmp2[512];
X
X			while (fgets(tmp, sizeof tmp, fp) != (char *) 0) {
X				sscanf(tmp, "%[^:]: %ld", tmp2, &cnt);
X				if (strcmp(tmp2, ng) == 0)
X					break;
X			}
X			if (strcmp(tmp2, ng) == 0)
X				minact = cnt + 1;
X			fclose(fp);
X		}
X		printf("News articles %d to %d\n", minact, limit);
X		for (cnt = 0, msg = minact; msg <= limit; msg++) {
X			if ((status = copynews(msgdir, conf, msg, argv[2])) > 0)
X				exit(status);
X			else if (status == 0)
X				cnt++;
X		}
X		printf("%ld news articles posted from %s to %s.\n", cnt, conf, argv[2]);
X		exit(cnt == 0? 9: 0);
X	}
X	msg = atol(++cp);
X	if (Index(argv[2], '/') != (char *) 0) {
X		fprintf(stderr, "Usage: uanews newsgroup[/article] conf\n");
X		exit(1);
X	}
X	if ((status = copynews(msgdir, conf, msg, argv[2])) == -1)
X		fprintf(stderr, "Couldn't read article %ld of %s\n", msg, conf);
X	exit(status);
X}
X
Xcopynews(base, ng, art, dest)
Xchar *base, *ng, *dest;
Xlong art; {
X	char path[512], temp[1024], ngpath[512];
X	int cnt, inhdr;
X	long newmsg;
X	FILE *ifp, *ofp;
X	struct stat sbuf;
X	char *cp, *dp;
X	
X	for (cp = ng, dp = ngpath; *cp != '\0'; cp++, dp++)
X		if (*cp == '.')
X			*dp = '/';
X		else
X			*dp = *cp;
X	sprintf(path, "%s/%s/%ld", NEWSDIR, ngpath, art);
X	if (stat(path, &sbuf) < 0)
X		return -1;	/* likely to be common... */
X	sprintf(path, "%s/%s/himsg", base, dest);
X	if ((ifp = fopen(path, "r")) == (FILE *) 0) {
X		fprintf(stderr, "Conference %s: missing himsg...\n", dest);
X		return 2;
X	}
X	fgets(temp, sizeof temp, ifp);
X	fclose(ifp);
X	if ((newmsg = atol(temp)) < 0) {
X		fprintf(stderr, "Conference %s: invalid himsg...\n", dest);
X		return 2;
X	}
X	newmsg++;
X	sprintf(path, "%s/%s/%ld", NEWSDIR, ngpath, art);
X	if ((ifp = fopen(path, "r")) == (FILE *) 0) {
X		fprintf(stderr, "Are you certain that you have permission to access news?\n");
X		return 3;
X	}
X	sprintf(path, "%s/%s/%ld", base, dest, newmsg);
X	if (stat(path, &sbuf) == 0) {
X		fprintf(stderr, "Conference %s: corrupted (himsg incorrect)\n", dest);
X		fclose(ifp);
X		return 4;
X	}
X	if ((ofp = fopen(path, "w")) == (FILE *) 0) {
X		fprintf(stderr, "Conference %s: check permissions (can't create message)\n", dest);
X		fclose(ifp);
X		return 5;
X	}
X	inhdr = 1;
X	while (fgets(temp, sizeof temp, ifp) != (char *) 0) {
X		if (temp[0] == '\n')
X			inhdr = 0;
X		if (inhdr) {
X			for (cnt = 0; headers[cnt] != NULL; cnt++)
X				if (strncmp(temp, headers[cnt], strlen(headers[cnt])) == 0)
X					break;
X			if (headers[cnt] == NULL)
X				continue;
X		}
X		fputs(temp, ofp);
X		if (ferror(ofp)) {
X			fprintf(stderr, "Write error on %s/%ld\n", dest, newmsg);
X			exit(5);	/* fatal! */
X		}
X	}
X	if (ferror(ifp)) {
X		fprintf(stderr, "Read error on %s/%ld\n", ng, art);
X		fclose(ifp);
X		fclose(ofp);
X		return 6;
X	}
X	fclose(ifp);
X	fclose(ofp);
X	sprintf(path, "%s/%s/himsg", base, dest);
X	if ((ifp = fopen(path, "w")) == (FILE *) 0) {
X		fprintf(stderr, "Conference %s: check permissions on himsg...\n", dest);
X		return 2;
X	}
X	fprintf(ifp, "%ld\n", newmsg);
X	fclose(ifp);
X	sprintf(path, "/tmp/uan%05d", getpid());
X	if ((ofp = fopen(path, "w")) == (FILE *) 0) {
X		fprintf(stderr, "Who moved /tmp?!\n");
X		return 16;
X	}
X	sprintf(path, "%s/%s/%s", base, dest, NEWSRC);
X	dp = "-";
X	if ((ifp = fopen(path, "r")) != (FILE *) 0) {
X		while (fgets(temp, sizeof temp, ifp) != (char *) 0) {
X			for (cp = temp; *cp != '\n' && *cp != ':'; cp++)
X				;
X			if (*cp == '\n')
X				continue;	/* silent cleanup */
X			else
X				*cp = '\0';
X			if (strcmp(temp, ng) == 0) {
X				sprintf(temp, "%s: %ld\n", ng, art);
X				dp = "#";
X			}
X			else
X				*cp = ':';
X			fputs(temp, ofp);
X		}
X		fclose(ifp);
X	}
X	if (*dp != '#')
X		fprintf(ofp, "%s: %ld\n", ng, art);
X	fclose(ofp);
X	sprintf(path, "/tmp/uan%05d", getpid());
X	if ((ifp = fopen(path, "r")) == (FILE *) 0) {
X		fprintf(stderr, "Can't reopen temp file, aborting...\n");
X		return 16;
X	}
X	sprintf(path, "%s/%s/%s", base, dest, NEWSRC);
X	if ((ofp = fopen(path, "w")) == (FILE *) 0) {
X		fprintf(stderr, "Conference %s: can't update news link file (E:%d)\n", dest, errno);
X		return 17;
X	}
X	while (fgets(temp, sizeof temp, ifp) != (char *) 0)
X		fputs(temp, ofp);
X	fclose(ofp);
X	fclose(ifp);
X	sprintf(path, "/tmp/uan%05d", getpid());
X	unlink(path);	/* not a tragedy if this fails... */
X	return 0;
X}
________This_Is_The_END________
echo 'x - udate.c'
sed 's/^X//' <<'________This_Is_The_END________' >>udate.c
X/*
X * @(#)udate.c	1.1 86/05/05 01:43:38 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)udate.c	1.1 86/05/05 01:43:38 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
Xmain() {
X	puts(longdate());
X}
________This_Is_The_END________
echo 'x - uwho.c'
sed 's/^X//' <<'________This_Is_The_END________' >>uwho.c
X/*
X * @(#)uwho.c	1.1 86/05/05 01:44:24 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)uwho.c	1.1 86/05/05 01:44:24 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
X#include <stdio.h>
X#include <pwd.h>
X#include <sys/types.h>
X#include <utmp.h>
X
X#ifndef NOAUTOPATH
Xstruct passwd *getpwuid();
X#endif  NOAUTOPATH
X
X#define TTYLIST "/etc/utmp"
X
Xmain(argc, argv)
Xchar **argv; {
X	int cnt, flg, users;
X	struct utmp user;
X	char tty[16];
X
X	if ((users = open(TTYLIST, "r")) < 0) {
X		fprintf(stderr, "%s: can't open %s\n", argv[0], TTYLIST);
X		exit(1);
X	}
X	flg = 0;
X	while (read(users, &user, sizeof user) > 0) {
X#ifdef SYS5
X		if (user.ut_type != USER_PROCESS)
X			continue;
X#endif SYS5
X		if (user.ut_name[0] == '\0')
X			continue;
X		sprintf(tty, "/dev/%.*s", sizeof user.ut_line, user.ut_line);
X		if (argc < 2)
X			showme(tty);
X		else
X			for (cnt = 1; argv[cnt] != NULL; cnt++)
X				if (strcmp(&tty[5], argv[cnt]) == 0) {
X					showme(tty);
X					break;
X				}
X	}
X	exit(0);
X}
X
Xshowme(ttyf)
Xchar *ttyf;
X{
X	FILE *fp;
X	char line[1024];
X#ifndef NOAUTOPATH
X	static char home[1024] = "";
X#endif NOAUTOPATH
X
X#ifdef NOAUTOPATH
X	sprintf(line, "%s/%s", NOAUTOPATH, ttyf);
X#else
X	if (home[0] == '\0')
X		strcpy(home, getpwuid(geteuid())->pw_dir);
X	sprintf(line, "%s/%s", home, ttyf);
X#endif NOAUTOPATH
X	if ((fp = fopen(line, "r")) == NULL)	/* not in use on this tty */
X		return;
X	fgets(line, 1024, fp);
X	printf("%s: %s", ttyf, line);		/* line already has newline */
X	fclose(fp);
X}
________This_Is_The_END________
echo 'x - install.sh'
sed 's/^X//' <<'________This_Is_The_END________' >>install.sh
Xecho ""
Xecho "UNaXcess V0.04.04 Installation Script"
Xecho "By Brandon S. Allbery"
Xecho ""
Xecho "You are free to copy, modify, etc. this installation script as much as you"
Xecho "wish; it's bound to come in handy if anyone on your system does programming."
Xecho "This script should run on most Unix-based systems.  If it doesn't, PLEASE let"
Xecho "me know at ...decvax!cwruecmp!ncoast!allbery."
Xecho ""
Xecho "I will be asking you for information as I install UNaXcess.  When I do, I'll"
Xecho "let you know by ending the question with two arrows, like this:  -> ->"
Xecho "When I do this, it's a signal for you to tell me something.  Usually, pressing"
Xecho "RETURN will do something reasonable."
Xecho ""
X:
X: Note to hackers -- the original idea for this script hails from lwall@sdcrdcf
X: but this script is entirely mine.  To see the original, ask anyone with rn
X: sources.
X:
X: Yes, the "-> ->" business is copped from Unify.  I sincerely doubt that it is
X: copyrighted, and it is fairly obvious.
X:
X
Xgrep NOAUTOPATH Makefile > /dev/null 2>&1
Xcase "$#" in
X0)	autopath=y
X	;;
X1)	autopath=n
X	UAHOME="`grep NOAUTOPATH Makefile | sed -n 's/.*[ 	]-DAUTOPATH=[^-A-Za-z\/.]*\([-A-Za-z\/.][-A-Za-z\/.]*\).*$/\1/p`"
X	if test ! -w "$UAHOME"; then
X		echo "I can't write in $UAHOME.  Please check your NOAUTOPATH definition"
X		echo "in the Makefile and recompile, or create the directory."
X		exit 1
X	fi
X	UAOWNER=${LOGNAME:-${USER:?'Who are you?'}}
X	;;
X2)	echo "I'm not being run from the UNaXcess distribution directory."
X	echo "Please re-run install.sh from the installation directory."
X	exit 1
X	;;
X*)	echo "Your grep does funny things.  You'll have to install UNaXcess by hand."
X	exit 1
X	;;
Xesac
Xcase $autopath in
Xy)	if test ! -w /etc/passwd; then
X		echo "I'm not running as root.  Please ask a system administrator to run this install"
X		echo "script as root, as I need to create directories and possibly even a user name."
X		exit 1
X	fi
X	: end of test for root.  This is about as portable as you get.
X	echo "Please enter the username of the owner of this UNaXcess system.  -> ->"
X	read UAOWNER
X	case "$UAOWNER" in
X	"")	echo "I hope you wanted to abort, because you just did."
X		exit 1
X	esac
X	if grep "^$UAOWNER:" /etc/passwd >/dev/null 2>&1; then
X		echo "I see $UAOWNER already exists.  Do you want to use him?  -> ->"
X		read yesno
X		case "$yesno" in
X		y*|Y*)	echo "Okay, we use $UAOWNER as the owner of UNaXcess."
X			;;
X		*)	echo "Then we'll start again from scratch."
X			exec sh Utilities/install.sh
X		esac
X	else
X		echo "I don't see a user named $UAOWNER on this system.  Should I create one?  -> ->"
X		read yesno
X		case "$yesno" in
X		y*|Y*)	echo "Okay, we make him."
X			;;
X		*)	echo "Then we'll start again from scratch."
X			exec sh Utilities/install.sh
X		esac
X		UAUID=`sed 's/^[^:]*:[^:]*:\([^:]*\):.*$/\1/' < /etc/passwd | sort -n | tail -1`
X		UAUID=`expr $UAUID + 1`
X		echo "I'm going to call $UAOWNER's home directory /usr/$UAOWNER."
X		echo "If you have a better idea, please tell me what it is.  -> ->"
X		read home
X		case "$home" in
X		"")	echo "Ok, we use /usr/$UAOWNER."
X			home=/usr/$UAOWNER
X		esac
X		if test -r $home; then
X			echo "It seems that this particular name's in use.  Let's try again."
X			exec sh Utilities/install.sh
X		fi
X		echo "$UAOWNER::$UAUID:1:UNaXcess Control Login:$home:" >> /etc/passwd
X		mkdir $home
X		chown $UAOWNER $home
X		echo "Now give $UAOWNER a password.  DON'T LEAVE IT UNPROTECTED!!!"
X		passwd $UAOWNER
X	fi
X	echo ""
X	UAHOME="`sed -n '/^'$UAOWNER':/s=^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\):.*\$=\1=p' < /etc/passwd`"
X	;;
Xn)	;;
Xesac
X
Xecho "UNaXcess will be installed in $UAHOME.  Is this okay?  -> ->"
Xread yesno
Xcase "$yesno" in
Xy*|Y*)	echo "Then we'll proceed with the installation."
X	;;
X*)	echo "Please check /etc/passwd for $UAOWNER's home directory, and fix it."
X	echo "Then type 'sh Utilities/install.sh' to try installation again."
X	exit 1
Xesac
Xchmod 711 $UAHOME || echo "Please inspect the permissions on $UAHOME; they should be -rwx--x--x."
X: now we know the home and owner of UNaXcess
X
Xif test ! -d $UAHOME/msgdir; then
X	echo "Creating $UAHOME/msgdir..."
X	rm -rf $UAHOME/msgdir
X	mkdir $UAHOME/msgdir
X	chown $UAOWNER $UAHOME/msgdir
Xfi
Xif test ! -d $UAHOME/motd; then
X	echo "Creating $UAHOME/motd..."
X	rm -rf $UAHOME/motd
X	mkdir $UAHOME/motd
X	chown $UAOWNER $UAHOME/motd
Xfi
Xif test ! -d $UAHOME/library; then
X	echo "Creating $UAHOME/library..."
X	rm -rf $UAHOME/library
X	mkdir $UAHOME/library
X	chown $UAOWNER $UAHOME/library
Xfi
Xif test ! -d $UAHOME/uploads; then
X	echo "Creating $UAHOME/uploads..."
X	rm -rf $UAHOME/uploads
X	mkdir $UAHOME/uploads
X	chown $UAOWNER $UAHOME/uploads
Xfi
Xecho "Creating $UAHOME/Logfile..."
Xrm -f $UAHOME/Logfile
Xchown $UAOWNER $UAHOME/Logfile > $UAHOME/Logfile
Xif test ! -f $UAHOME/userind; then
X	echo "Creating $UAHOME/userind..."
X	rm -rf $UAHOME/userind
X	chown $UAOWNER $UAHOME/userind > $UAHOME/userind
Xfi
Xif test ! -d $UAHOME/msgdir/general; then
X	echo "Creating conference general..."
X	rm -rf $UAHOME/msgdir/general
X	mkdir $UAHOME/msgdir/general
X	chown $UAOWNER $UAHOME/msgdir/general
X	echo 1 > $UAHOME/msgdir/general/himsg
X	chown $UAOWNER $UAHOME/msgdir/general/himsg
X	cat << --general/1-- > $UAHOME/msgdir/general/1
XDate: `Utilities/udate`
XFrom: The UNaXcess System Operator
XTo: All
XSubject: This BBS
X
XWelcome to UNaXcess V0.04.04 -- a computer bulletin board system designed for
Xthe UNIX(tm) operating system.  You are using the ONLY BBS which is designed
Xto USE Unix's unique features to their fullest potential.
X
XThis conference is the general-purpose conference.  Use it for discussions
Xthat don't fit in any of the existing conferences.  But if it's liable to be
Xlarge, consider making a new conference for it.
X
XThe basic UNaXcess commands are:
X
X	r	Read messages.  You may specify a message number on the
X		command line, or you will be asked how to read messages.
X	
X	n	Read all new messages in all conferences.
X	
X	e	Enter a new message.  You can specify the recipient's
X		name on the command line, like "e John Doe".
X	
X	j	Join a different conference.  You can also create a new
X		conference with this command.  You can specify the new
X		conference on the command line:  "j discussion".
X	
X	g	Exit UNaXcess.
X	
X	f	Enter the File Section.  UNaXcess is capable of file
X		uploading and downloading with ASCII, Xmodem and Kermit
X		(not all maybe available on all systems).
X
XPress BREAK (or DEL or CONTROL C, depending on the system) to stop a command.
XPress CONTROL-\ (CONTROL plus backslash) for a fast logout.
X
X--general/1--
Xfi
Xif test ! -d $UAHOME/msgdir/guest; then
X	echo "Creating conference guest..."
X	rm -rf $UAHOME/msgdir/guest
X	mkdir $UAHOME/msgdir/guest
X	chown $UAOWNER $UAHOME/msgdir/guest
X	echo 1 > $UAHOME/msgdir/guest/himsg
X	chown $UAOWNER $UAHOME/msgdir/guest/himsg
X	cat << --guest/1-- > $UAHOME/msgdir/guest/1
XDate: `Utilities/udate`
XFrom: The UNaXcess System Operator
XTo: All
XSubject: This conference
X
XThis conference is for any and all users of UNaXcess.  ANYONE may post
Xmessages to the guest conference at any time.
X
X--guest/1--
Xfi
X: end of system files build, for the most part
X
Xecho "Where do you want the programs to go?  ENTER defaults to /usr/bin.  -> ->"
Xread BIN
Xcase "$BIN" in
X"")	echo "I'll use /usr/bin, then."
X	BIN=/bin
X	;;
X*)	echo "Ok, I'll put them in $BIN."
X	;;
Xesac
Xif test ! -d $BIN; then
X	echo "I can't find $BIN.  Please start over after you make it."
X	exit 1
Xfi
Xecho "What do you want to call UNaXcess?  ENTER defaults to ua.  -> ->"
Xread ua
Xcase "$ua" in
X"")	ua="ua"
Xesac
Xecho "What do you want to call the user lister?  ENTER defaults to uwho.  -> ->"
Xread uwho
Xcase "$uwho" in
X"")	uwho="uwho"
Xesac
Xecho "What do you want to call the date printer?  Enter defaults to udate.  -> ->"
Xread udate
Xcase "$udate" in
X"")	udate="udate"
Xesac
Xecho "Creating $BIN/$ua..."
Xcp ua $BIN/$ua
Xcase $autopath in
Xy)	chown $UAOWNER $BIN/$ua
X	chmod 4711 $BIN/$ua
X	;;
Xesac
Xecho "Creating $BIN/$udate..."
Xcp Utilities/udate $BIN/$udate
Xchown $UAOWNER $BIN/$udate
Xchmod 711 $BIN/$udate
Xecho "Creating $BIN/$uwho..."
Xcp Utilities/uwho $BIN/$uwho
Xcase $autopath in
Xy)	chown $UAOWNER $BIN/$uwho
X	chmod 4711 $BIN/$uwho
X	echo "Creating $UAHOME/mkconf..."
X	cp Utilities/mkconf $UAHOME/mkconf
X	chown root $UAHOME/mkconf
X	chmod 4711 $UAHOME/mkconf
X	;;
Xesac
X: end of binary installation
X
Xecho "What do you want to call the shell message poster?  ENTER defaults to upost."
Xecho "  -> ->"
Xread upost
Xcase "$upost" in
X"")	upost="upost"
Xesac
Xecho "Creating $BIN/$upost..."
Xsed -e "s;@UAOWNER@;${UAOWNER};" -e "s;@udate@;BIN/${udate};" < Utilities/upost.sh > $BIN/$upost
Xchown $UAOWNER $BIN/$upost
Xchmod 755 $BIN/$upost
Xecho "What do you want to call the shell bulletin poster?  ENTER defaults to umotd."
Xecho "  -> ->"
Xread umotd
Xcase "$umotd" in
X"")	umotd="umotd"
Xesac
Xecho "Creating $BIN/$umotd..."
Xsed -e "s;@UAOWNER@;${UAOWNER};" -e "s;@udate@;$BIN/${udate};" < Utilities/umotd.sh > $BIN/$umotd
Xchown $UAOWNER $BIN/$umotd
Xchmod 755 $BIN/$umotd
Xecho "What do you want to call the message mover?  ENTER defaults to mvmsg."
Xecho "  -> ->"
Xread mvmsg
Xcase "$mvmsg" in
X"")	mvmsg="mvmsg"
Xesac
Xecho "Creating $BIN/$mvmsg..."
Xcp Utilities/mvmsg $BIN/$mvmsg
Xchown $UAOWNER $BIN/$mvmsg
Xchmod 4700 $BIN/$mvmsg
Xecho "Do you want to install the USENET News Transfer Facility?  ENTER defaults"
Xecho " to NO.  -> ->"
Xread instnews
Xcase "$instnews" in
Xy*|Y*)	echo "What do you want to call the transfer program?  ENTER defaults to"
X	echo "uanews.  -> ->"
X	read uanews
X	case "$uanews" in
X	"")	uanews="uanews"
X	esac
X	echo "Creating $BIN/$uanews..."
X	cp Utilities/uanews $BIN/$uanews
X	case $autopath in
X	y)	chown $UAOWNER $BIN/$uanews
X		chmod 4700 $BIN/$uanews
X		;;
X	esac
Xesac
X: end of shell utilities installation
X
Xecho ""
Xecho "Now I'm going to create the runtime configuration file for UNaXcess.  This"
Xecho "file allows you to decide what features of UNaXcess are allowed in your BBS"
Xecho "system."
Xecho ""
Xecho "I suggest you read the UNaXcess README file before doing this, so you'll"
Xecho "know what I'm talking about."
Xecho ""
Xecho "Do you want to allow READ-ONLY conferences?  Press RETURN for YES.  -> ->"
Xread yesno
Xcase "$yesno" in
X""|y*|Y*)
X	readonly=YES
X	;;
X*)	readonly=NO
Xesac
Xecho "Do you want to allow RESTRICTED (X-Rated) conferences?  Press RETURN for NO."
Xecho "  -> ->"
Xread yesno
Xcase "$yesno" in
Xy*|Y*)
X	xrated=YES
X	;;
X*)	xrated=NO
Xesac
Xecho "What is the editor to be run?  The default is the internal editor.  -> ->"
Xread editor
Xcase "$editor" in
X"")	editor=ua-edit
Xesac
Xecho "What is the shell to be run by the COMMAND option?  The default is /bin/sh."
Xecho "  -> ->"
Xread shell
Xcase "$shell" in
X"")	shell=/bin/sh
Xesac
Xecho "Do you want to have UNaXcess check the user's shell and editor preferences"
Xecho "via the EDITOR and SHELL environment variables?  The default is YES.  -> ->"
Xread env
Xcase "$env" in
XN*|n*)	env=NO
X	;;
X*)	env=YES
Xesac
Xecho "What is the login name of the user who can't log directly into UNaXcess?"
Xecho "RETURN if all users can log in directly  -> ->"
Xread bbsuser
Xecho "What is the time limit on UnaXcess, in minutes?  -> ->"
Xread tlimit
Xcase "$tlimit" in
X"")	tlimit=0
Xesac
Xecho "What is the system operator's UNaXcess login to be?  RETURN for SYSOP  -> ->"
Xread sysop
Xcase "$sysop" in
X"")	sysop="sysop"
Xesac
Xecho "Do you want to allow private messages?  RETURN for YES  -> ->"
Xread private
Xcase "$private" in
XN*|n*)	private=NO
X	;;
X*)	private=YES
Xesac
Xecho "Do you want to enable logging?  RETURN for YES  -> ->"
Xread logging
Xcase "$logging" in
XN*|n*)	logging=NO
X	;;
X*)	logging=YES
Xesac
Xecho "Please specify one of the following choices:"
Xecho "    nopause     Don't pause after 16 lines of output"
Xecho "    ask         Ask each user whether he wants puses or not"
Xecho "    pause       Pause after 16 lines of output always"
Xecho "Please select one, or press RETURN for ASK:  -> ->"
Xread pauses
Xcase "$pauses" in
XN*|n*)	pauses=2
X	;;
XP*|p*)	pauses=0
X	;;
X*)	pauses=1
Xesac
Xecho "How many tries should a user get to log in?  RETURN for 3  -> ->"
Xread logtries
Xcase "$logtries" in
X"")	logtries=3
Xesac
Xecho ""
Xecho "Creating $UAHOME/ua-config..."
Xcat << --CONFIG-- > $UAHOME/ua-config
Xreadonly	$readonly
Xx-rated		$xrated
Xeditor		$editor
Xshell		$shell
Xread-env	$env
Xbbs-user	$bbsuser
Xtime-limit	$tlimit
Xsysop		"$sysop"
Xprivate-msgs	$private
Xlogging		$logging
Xbanner		""
Xlogin-msg	""
Xpauses		$pauses
Xlogin-tries	$logtries
X--CONFIG--
Xchown $UAOWNER $UAHOME/ua-config
Xchmod 644 $UAHOME/ua-config
Xecho ""
Xecho "You can edit the config file yourself to change these and other options."
X: end of config file generation
X
Xecho ""
Xif test ! -f $UAHOME/userfile; then
X	echo "Creating $UAHOME/userfile..."
X	rm -rf $UAHOME/userfile
X	cat << --USERFILE-- > $UAHOME/userfile
X$sysop::5::80:0:
Xnew::6::2:0:
Xguest::1::40:0:
X--USERFILE--
X	chown $UAOWNER $UAHOME/userfile
X	chmod 644 $UAHOME/userfile
Xfi
X: end of userfile installation
X
Xecho ""
Xif test ! -d $UAHOME/lock; then
X	echo "Making lock directory..."
X	rm -rf $UAHOME/lock
X	mkdir $UAHOME/lock
X	chown $UAOWNER $UAHOME/lock
X	chmod 777 $UAHOME/lock
Xfi
Xif test ! -r $UAHOME/directory; then
X	rm -rf $UAHOME/directory
X	today="`date | sed -e 's/^... \(...\)  *\([0-9][0-9]*\) [^ ][^ ]* 19\(..\)$/\1\/\2\/\3/'`"
X	today="`echo $today | sed -e s/Jan/1/ -e s/Feb/2/ -e s/Mar/3/ -e s/Apr/4/ -e s/May/5/ -e s/Jun/6/`"
X	today="`echo $today | sed -e s/Jul/7/ -e s/Aug/8/ -e s/Sep/9/ -e s/Oct/10/ -e s/Nov/11/ -e s/Dec/12/`"
X	echo "Creating $UAHOME/directory..."
X	cat << --LIBCATLG-- > $UAHOME/directory
XGENERAL file branch; $today by $sysop: General up/downloading
X--LIBCATLG--
X	chown $UAOWNER $UAHOME/directory
X	chmod 644 $UAHOME/directory
Xfi
Xif test ! -f $UAHOME/upload-log; then
X	rm -rf $UAHOME/upload-log
X	echo "Creating $UAHOME/upload-log..."
X	cp /dev/null $UAHOME/upload-log
X	chown $UAOWNER $UAHOME/upload-log
X	chmod 644 $UAHOME/upload-log
Xfi
X: end of directory installation
X
Xif test ! -f $UAHOME/NewMessage; then
X	echo ""
X	echo "I am going to create a simple new-user bulletin.  It is your job to change it"
X	echo "to say what you want it to say."
X	echo ""
X	echo "Creating $UAHOME/NewMessage..."
Xcat << --NEWMESSAGE-- > $UAHOME/NewMessage
X
XWelcome to the UNaXcess System, Copyright (C) 1984, 1985 by Brandon S. Allbery.
XThis UNaXcess was installed `Utilities/udate`.
X
X--NEWMESSAGE--
X	chown $UAOWNER $UAHOME/NewMessage
X	chmod 644 $UAHOME/NewMessage
Xfi
Xif test ! -f $UAHOME/motd/himotd; then
X	echo "Creating $UAHOME/motd/himotd..."
X	echo 0 > $UAHOME/motd/himotd
X	chown $UAOWNER $UAHOME/motd/himotd
X	chmod 644 $UAHOME/motd/himotd
Xfi
Xecho ""
Xecho "Now you must create the main bulletin.  I will run the $umotd program"
Xecho "for you -- you will simply enter the bulletin.  I hope you have EDITOR set"
Xecho "up correctly!"
Xecho ""
X$BIN/$umotd
X: end of bulletin installation
X
Xecho ""
Xecho "Congratulations!  You have just successfully installed the UNaXcess System."
Xecho "Before you use it, I suggest you put a password on the '$sysop' login,"
Xecho "so nobody else can make trouble with it."
Xecho ""
X$BIN/$udate
Xecho "UNaXcess Version 0.04.04 has been installed."
________This_Is_The_END________
echo 'x - umotd.sh'
sed 's/^X//' <<'________This_Is_The_END________' >>umotd.sh
X:
X: "@(#)umotd.sh	1.1 86/05/05 01:44:30 tdi2!brandon @(#)"
X: "@(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)"
X: 
X: "Permission is hereby granted to copy and freely distribute this code,"
X: "UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later"
X: "may NOT be copied or distributed without the author's written permission."
X: "You may charge only a reasonable handling/copying fee for distribution of"
X: "this code; you may not sell it or include it in a commercial package for"
X: "resale."
X:
X
XUADIR="`sed -n 's/^@UAOWNER@:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\):[^:]*$/\1/p' < /etc/passwd`"
X
Xmsgnum=`cat $UADIR/motd/himotd`
Xcase "$msgnum" in
X[0-9]*)	;;
X*)	echo "$msgnum" >&2
X	exit 1
Xesac
Xmsgnum=`expr $msgnum + 1`
Xif echo "UNaXcess V0.04.04 -- `@udate@`
X" > $UADIR/motd/$msgnum 2>/dev/null
Xthen	${EDITOR-vi} $UADIR/motd/$msgnum
X	echo $msgnum > $UADIR/motd/himotd
Xelse	echo "$0: could not make new bulletin $msgnum"
X	exit 1
Xfi
________This_Is_The_END________
echo 'x - upost.sh'
sed 's/^X//' <<'________This_Is_The_END________' >>upost.sh
X:
X: "@(#)upost.sh	1.1 86/05/05 01:44:36 tdi2!brandon @(#)"
X: "@(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)"
X: 
X: "Permission is hereby granted to copy and freely distribute this code,"
X: "UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later"
X: "may NOT be copied or distributed without the author's written permission."
X: "You may charge only a reasonable handling/copying fee for distribution of"
X: "this code; you may not sell it or include it in a commercial package for"
X: "resale."
X:
X
XUADIR="`sed -n 's/^@UAOWNER@:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\):[^:]*$/\1/p' < /etc/passwd`"
X
Xconf=$1; shift
Xmsgnum=`cat $UADIR/msgdir/$conf/himsg`
Xcase "$msgnum" in
X[0-9]*)	;;
X*)	echo "$msgnum" >&2
X	exit 1
Xesac
Xmsgnum=`expr $msgnum + 1`
Xif echo "Date: `@udate@`
XFrom: Message Posting Daemon <${LOGNAME-daemon>
XTo: All
XSubject: $*
X" > $UADIR/msgdir/$conf/$msgnum 2>/dev/null
Xthen	cat >> $UADIR/msgdir/$conf/$msgnum
X	echo $msgnum > $UADIR/msgdir/$conf/himsg
Xelse	echo "$0: could not make new message $msgnum in $conf"
X	exit 1
Xfi
________This_Is_The_END________
exit
-- 
  ---------------- /--/	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