v08i037: UNaXcess Conferencing, version 1.00.02, Part01/04

sources-request at mirror.UUCP sources-request at mirror.UUCP
Fri Feb 6 07:18:58 AEST 1987


Submitted by: abic!cwruecmp!allbery%ncoast.UUCP
Mod.sources: Volume 8, Issue 37
Archive-name: unaxcess2/Part01

[  Like with UUMAIL, I got this new release before I would have published
   the old release.  --r$  ]

#--------------------------------CUT HERE-------------------------------------
#! /bin/sh
#
# 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:
#
# -rw-r--r--   1 allbery  System      4044 Feb  3 21:44 README
# -rw-rw-rw-   1 allbery  System      3428 Feb  3 21:49 bulletin.c
# -rw-rw-rw-   1 allbery  System     19341 Feb  3 21:07 conference.c
# -rw-rw-rw-   1 allbery  System      1837 Feb  3 21:08 date.c
# -rw-rw-rw-   1 allbery  System      2649 Nov 22 19:50 dir.c
# -rw-rw-rw-   1 allbery  System      3164 Nov 22 19:50 dir.h
# -rw-rw-rw-   1 allbery  System     13499 Feb  3 21:08 fileudl.c
# -rw-r--r--   1 allbery  System     13080 Feb  3 21:09 io.c
#
echo 'x - README'
sed 's/^X//' << '________This_Is_The_END________' > README
X[The README files for 1.00.01 and 1.00.00 are included below.]
X
XThis is the UNaXcess Conferencing 1.00.02 distribution.  It provides bug
Xfixes to the 1.00.01 distribution.
X
XThe installation instructions have not changed; see the included README files
Xbelow.
X
XThere were six primary fixes:
X
X(1) Private messages were still broken.  Code was added in conference.c to
X    fix this.
X
X(2) Conference membership had a bug; while I had known about it, I had thought
X    it was an I/O bug.  Code was changed in conference.c to fix this.
X
X(3) Panics were not dumping core as they should have.  Code was added to
X    system.c to correct this; also, a "double-panic" quick exit was provided
X    to forestall infinite loops.
X
X(4) The format of the "directory" file was incorrect in install.sh and in
X    admin.man.  Fixed, albeit via what can only be termed a hack in install.
X    At least UA-Conf doesnt' do anything other than print dates.
X
X(5) The terminal handling code in io.c had some casts that were mangled by
X    Ultrix cc (VAX 8600 and MicroVAX II); this resulted in a warning from
X    the Ultrix assembler, and caused UA-Conf to go into convulsions on start-
X    up.  The casts were removed; I hope DEC fixes its compiler soon.
X
X(6) Yet another locking fix.  If you still get "UNaXcess internal error:
X    LOCKFILE DELETED" messages, let me know; I haven't had a lock work in
X    this thing since I used Xenix semaphores back in V0.3.3.
X
X-------------------------------------------------------------------------------
X
X[The README file for 1.00.00 is included below.]
X
XThis is the UNaXcess 1.00.01 distribution.  It provides bug fixes and enhance-
Xments to the 1.00.00 distribution; however, enough was changed that a new
Xdistribution was a good idea.
X
XRead the various manuals and the Makefile, as well as the 1.00.00 README
Xbelow, for information on installing this program.
X
XNOTE!!!  If you already have UNaXcess 1.00.00 or 0.4.x, you must run the
Xscript reinstall.sh after you run install.sh, in order to upgrade your
Xua-config and userfile to the new version.  To run it, become the owner of
Xthe BBS system and issue the command "sh reinstall.sh /path/to/BBS".  It will
Xfigure out whether you are using an alternate BBS directory.
X
XEnjoy.  ++Brandon
X
XP.S.  There is now a mailing list for UNaXcess; if you wish to subscribe, send
Xmail to "cbatt!cwruecmp!ncoast!unaxcess-request" or to
X"ncoast!unaxcess-request%Case.CSNET at relay.CS.NET", as your system (UUCP or
XInternet) requires.  Submissions may be sent to the user "unaxcess" at the
Xabove-named site.
X
X===============================================================================
X
XThis is the UNaXcess 1.00.00 distribution.  It is not in its "final" form yet;
XI have to rewrite the UDL module, and I expect to add the UANet interface as
Xsoon as possible; this, however, will require me to develop a replacement for
X"sendmail" on those systems (e.g. V7, System III/V) which don't have it.  (And
Xperhaps for those that do, given the horror stories...)  There will also be
Xnew administration commands forthcoming.
X
XThere are three manuals included in this distribution:
X
X(1) The UNaXcess Installation Manual, which explains the installation
X    procedure.  This replaces the old README file, and is much more readable.
X
X(2) The UNaXcess User's Manual, an nroff'ed version of which is automatically
X    placed in the UDL area by the installation script.  This guides the user
X    through UNaXces in more detail than the help messages and help files.
X
X(3) The UNaXcess Administrator's Manual, which guides the administrator
X    through the process of maintaining UNaXcess.
X
XThe "noautopath" mode is still supported, but it may disappear in the future,
Xsince it interferes strongly with UNaXcess security.
X
XThe author may be contacted at ..ihnp4!sun!cwruecmp!ncoast!allbery, or by
Xless mundane means as:
X
X			Brandon S. Allbery
X			6615 N. Center St., Apt. A1-105
X			Mentor, OH 44060-4101
X			
X			Phone: +1 216 974 9210
X
XPlease read the Installation Manual before compiling UNaXcess.
X
X++Brandon
________This_Is_The_END________
echo 'x - bulletin.c'
sed 's/^X//' << '________This_Is_The_END________' > bulletin.c
X/*
X *	bulletin.c	1.2 (TDI) 2/3/87
X *	Copyright (C) 1984, 85, 86, 87 by Brandon S. Allbery.
X *	This file is part of UNaXcess version 1.0.2.
X */
X
X#ifndef lint
Xstatic char _FileID_[] = "@(#)bulletin.c	1.2 (TDI) 2/3/87";
Xstatic char _UAID_[]   = "@(#)UNaXcess version 1.0.2";
X#endif lint
X
X#include "ua.h"
X
Xbulletin() {
X	short mcnt, himotd;
X	char tmps[256];
X	FILE *fp;
X
X	if (user.u_access == A_MKUSER)
X		return 1;
X	sprintf(tmps, "%s/himotd", MOTD);
X	if ((fp = fopen(tmps, "r")) == NULL) {
X		log("Error %d opening %s", errno, tmps);
X		panic("himotd");
X	}
X	fgets(tmps, 32, fp);
X	fclose(fp);
X	himotd = atoi(tmps);
X	if (s_cmp(user.u_name, "guest") == 0)
X		mcnt = 1;
X	else
X		mcnt = user.u_nbull + 1;
X	for (; mcnt <= himotd; mcnt++) {
X		sprintf(tmps, "%s/%d", MOTD, mcnt);
X		if (!readmotd(tmps, mcnt))
X			break;
X	}
X	return 1;
X}
X
Xreadmotd(motd, mnum)
Xchar *motd;
Xshort mnum; {
X	char ch;
X
X	writef("Bulletin #%d:\n", mnum);
X	cat(motd);
X	writef("\nContinue or Stop? C\b");
X	ch = readc();
X	log("C/S? %c", ch);
X	return ToLower(ch) != 's';
X}
X
Xmkbull() {
X	static char lockfile[] = "bulletin.lock";
X	char *tempfile = mktemp("/tmp/UAbXXXXXX");
X	FILE *mfp, *sfp;
X	char line[1024], *p, ch;
X	short mcnt;
X
X	if (user.u_access != A_WITNESS) {
X		log("Attempted mkbull by non-FW.");
X		writes("You aren't permitted to enter bulletins.");
X		return 1;
X	}
X	if ((mfp = fopen(tempfile, "w")) == NULL) {
X		log("Error %d opening %s", errno, tempfile);
X		panic("tmp");
X	}
X	fclose(mfp);
X	input(tempfile);
X	for (;;) {
X		writef("\nList, Continue entry, Edit, Save, or Abort? ");
X		ch = readc();
X		log("Edit command: %c", ch);
X		switch (ch) {
X		case 'L':
X			writes("\n--------------------");
X			cat(tempfile);
X			writes("--------------------");
X			break;
X		case 'C':
X			input(tempfile);
X			break;
X		case 'E':
X			edit(tempfile);
X			break;
X		case 'A':
X			writef("Do you really want to abort this edit? N\b");
X			line[0] = readc();
X			log("Abort? %c", line[0]);
X			if (line[0] == 'Y') {
X				unlink(tempfile);
X				return 0;
X			}
X			break;
X		case '?':
X			writes("Bulletin create commands:\n\nL - List message\nC - Continue message entry\nE - Edit message\nS - Save message\nA - Abort message\n");
X			break;
X		case 'S':
X			writes("Saving bulletin...");
X			mklock(lockfile);
X			sprintf(line, "%s/himotd", MOTD);
X			if ((sfp = fopen(line, "r")) == NULL) {
X				log("Error %d opening %s", errno, line);
X				rmlock(lockfile);
X				unlink(tempfile);
X				panic("himotd");
X			}
X			fgets(line, 32, sfp);
X			fclose(sfp);
X			mcnt = atoi(line) + 1;
X			sprintf(line, "%s/%d", MOTD, mcnt);
X			if ((sfp = fopen(line, "w")) == NULL) {
X				log("Error %d opening %s", errno, line);
X				unlink(tempfile);
X				rmlock(lockfile);
X				panic("motd");
X			}
X			fprintf(mfp, "UNaXcess Conferencing, Version 1.00.02\nDate: %s\nFrom: %s\n\n", longdate(), upstr(user.u_name));
X			if ((mfp = fopen(tempfile, "r")) == NULL) {
X				fclose(sfp);
X				log("Error %d opening %s", errno, tempfile);
X				unlink(tempfile);
X				unlink(line);
X				rmlock(lockfile);
X				panic("btmp");
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/himotd", MOTD);
X			if ((sfp = fopen(line, "w")) == NULL) {
X				log("Error %d opening %s", errno, line);
X				panic("himotd_w");
X			}
X			fprintf(sfp, "%d\n", mcnt);
X			fclose(sfp);
X			rmlock(lockfile);
X			return 1;
X		default:
X			writes("Please enter L, C, E, S, or A; or ? for help.");
X		}
X	}
X}
________This_Is_The_END________
echo 'x - conference.c'
sed 's/^X//' << '________This_Is_The_END________' > conference.c
X/*
X *	conference.c	1.2 (TDI) 2/3/87
X *	Copyright (C) 1984, 85, 86, 87 by Brandon S. Allbery.
X *	This file is part of UNaXcess version 1.0.2.
X *
X *	Permission is hereby granted to copy and distribute this program
X *	freely.  Permission is NOT given to modify this program or distribute
X *	it at cost, except for charging a reasonable media/copying fee.
X */
X
X#ifndef lint
Xstatic char _FileID_[] = "@(#)conference.c	1.2 (TDI) 2/3/87";
Xstatic char _UAID_[]   = "@(#)UNaXcess version 1.0.2";
X#endif lint
X
X#include "ua.h"
X
Xchar conference[33];
X
Xconfidx() {
X	FILE *ifd;
X	short himsg;
X	char line[256];
X	DIR *dp;
X	struct direct *dfd;
X
X	writes("\nConference                      Subscribed?  Messages  # Read  Restricted?\n");
X	if ((dp = opendir(MSGBASE)) == NULL) {
X		log("Error %d opening dir %s/", errno, MSGBASE);
X		panic("msgdir");
X	}
X	while ((dfd = readdir(dp)) != NULL) {
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			log("No himsg in conference %s", dfd->d_name);
X			continue;
X		}
X		fgets(line, 32, ifd);
X		himsg = atoi(line);
X		writef("%-32.32s     %c        %5d    %5d        %c\n", dfd->d_name, (isunsub(dfd->d_name)? 'N': 'Y'), himsg, cnread(dfd->d_name), (isrconf(dfd->d_name)? 'Y': 'N'));
X		fclose(ifd);
X	}
X	closedir(dp);
X	return 1;
X}
X
Xjoin() {
X	char line[256], *p;
X
X	do {
X		writef("Enter conference: ");
X		reads(line);
X		log("Enter conference: %s", line);
X		if (line[0] == '\0')
X			return 1;
X	} while (!verify(line));
X	strcpy(conference, line);
X	log("Current conference is %s", conference);
X	return 1;
X}
X
Xverify(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		if (errno != ENOENT) {
X			log("Error %d accessing dir %s/", errno, line);
X			return 0;
X		}
X		else
X			return newconf(conf);
X	}
X	if (chdir(parms.ua_home) == -1) {
X		log("Can't chdir to HOME (errno=%d)", errno);
X		system("pwd");
X		panic("isconf_cd");
X	}
X	if (isunsub(conf)) {
X		writef("You are unsubscribed from this conference.  Rejoin? N\b");
X		line[0] = readc();
X		log("Unsubscribed.  Resubscribe? %c", line[0]);
X		if (line[0] == 'Y')
X			resubscribe(conf);
X		else
X			return 0;
X	}
X	if (user.u_access != A_WITNESS && parms.ua_xrc && !isrcmem(user.u_name, conf)) {
X		log("No access to restricted conference %s", conf);
X		writes("I'm sorry, but that conference has restricted membership.");
X		return 0;
X	}
X	return 1;
X}
X
Xkillmsg() {
X	short mnum;
X	char line[256], *p;
X
X	if (user.u_access == A_GUEST) {
X		writes("You aren't authorized for this function.");
X		log("Security violation:  KILL by a GUEST");
X		return 1;
X	}
X	writef("Enter message number to kill: ");
X	reads(line);
X	if (line[0] == '\0')
X		return 1;
X	if ((mnum = atoi(line)) < 1) {
X		writes("Bad message number.");
X		log("Bad message number: %s", line);
X		return 1;
X	}
X	dokill(mnum);
X	return 1;
X}
X
Xdokill(msg)
Xshort msg; {
X	char mfile[256];
X
X	sprintf(mfile, "%s/%s/%d", MSGBASE, conference, msg);
X	if (user.u_access != A_WITNESS && s_cmp(getowner(mfile), user.u_name) != 0) {
X		writes("Sorry, you don't own that message.");
X		log("Security violation:  KILL by non-owner");
X		return;
X	}
X	if (unlink(mfile) < 0) {
X		writef("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)
Xchar *file; {
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			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)
Xchar *conf; {
X	char line[256];
X	FILE *f;
X
X	if (user.u_access == A_GUEST) {
X		log("Security violation:  attempted MKCONF by guest");
X		writes("Sorry, there is no such conference.");
X		return 0;
X	}
X	writef("There is no conference by that name.  Do you want to create it? N\b");
X	line[0] = readc();
X	log("Nonexistent.  Create? %c", line[0]);
X	if (line[0] != 'Y')
X		return 0;
X	if (parms.ua_roc && conf[0] == 'r' && conf[1] == '-')
X		if (user.u_access != A_WITNESS) {
X			writes("Only Fairwitnesses can make READ-ONLY conferences.  If you really want one, you will have to ask the Sysop to make you a Fairwitness.  Otherwise, try using a conference name not beginning with \"R-\".");
X			log("Attempted mk of RO conf by non-FW");
X			return 0;
X		}
X		else {
X			writef("This conference will be READ-ONLY, except to Fairwitnesses.  If you want anyone to be able to add to it, answer NO and use a name not beginning with \"R-\".  Do you want to make this READ-ONLY conference? N\b");
X			line[0] = readc();
X			log("Read-only.  Create? %c", line[0]);
X			if (line[0] != 'Y')
X				return 0;
X		}
X#ifdef BSD
X	sprintf(line, "%s/%s", MSGBASE, conf);
X	if (mkdir(line, 0600) < 0) {
X		log("Mkconf of %s failed", conf);
X		writes("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		log("Mkconf of %s failed.", conf);
X		writes("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		log("Error %d opening %s", line);
X		writes("Can't create high message file.  Strange...");
X		return 0;
X	}
X	fputs("0\n", f);
X	fclose(f);
X	writes("You will now be placed in the message editor to make a message describing this conference.  It will be addressed to, and readable by, all users.");
X	mkmsg("All", "This conference", conf, 0);
X	return 1;
X}
X
Xisprivate(msg)
Xchar *msg; {
X	FILE *fp;
X	char line[1024], to[1024], from[1024];
X	short pflag;
X	register char *cp;
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		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	for (cp = to; *cp != '\0'; cp++)	/* OOPS!  2/3/87 ++bsa */
X		if (*cp == '\n') {
X			*cp = '\0';
X			break;
X		}
X	for (cp = from; *cp != '\0'; cp++)
X		if (*cp == '\n') {
X			*cp = '\0';
X			break;
X		}
X	if (!pflag)
X		return 0;
X	if (s_cmp(user.u_name, to) == 0)
X		return 0;
X	else if (s_cmp(user.u_name, from) == 0)
X		return 0;
X	else {
X		log("Message %s is private.", msg);
X		return 1;
X	}						/* end mods 2/3/87 */
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		writes("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		writef("Unsubscribe to login conference? N\b");
X		line[0] = readc();
X		log("Unsub login conf? %c", line[0]);
X		if (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			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	writehigh(hicnts);
X	log("Unsubscribed to %s", conf);
X	writef("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			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	writehigh(hicnts);
X	log("Resubscribed to %s", conf);
X	writef("Resubscribed to conference %s.\n", conf);
X}
X
Xunsub() {
X	char line[256], *p;
X
X	for (;;) {
X		writef("Unsubscribe to which conference (ENTER to abort): ");
X		reads(line);
X		log("Unsub conference: %s", line);
X		if (line[0] == '\0')
X			return 1;
X		if (isconf(line)) {
X			unsubscribe(line);
X			return 1;
X		}
X		writef("That's not a valid conference.  ");
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	if (chdir(parms.ua_home) == -1) {
X		log("Can't chdir to HOME (errno=%d)", errno);
X		system("pwd");
X		panic("isconf_cd");
X	}
X	return 1;
X}
X
Xsetlconf() {
X	char line[256], *p;
X
X	if (s_cmp(user.u_name, "guest") == 0) {
X		log("Guest SET LOGIN CONF denied.");
X		writes("GUEST can't set a login conference.");
X		return 1;
X	}
X	do {
X		writef("Enter new login conference: ");
X		reads(line);
X		log("Login conference: %s", line);
X		if (line[0] == '\0')
X			return 1;
X	} while (!isconf(line));
X	if (isunsub(line)) {
X		writes("You're unsubscribed from it.  <J>oin it and resubscribe.");
X		log("Unsubscribed -- login conf set aborted.");
X		return 1;
X	}
X	if (!isrcmem(user.u_name, line)) {
X		writes("You aren't a member of that conference.");
X		log("Not a member -- 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(uname, conf)
Xchar *uname, *conf; {
X	struct _himsg *hip, *uhi;
X	char *cp;
X
X	for (cp = uname; *cp != '\0'; cp++)
X		*cp = ToLower(*cp);
X	if ((uhi = readhigh(uname)) < 0) {
X		log("Couldn't read %s's userindex.", uname);
X		return 0;
X	}
X	writef("Checking %s's user index...\n", uname);
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 *confs;
X	struct direct *conf;
X	int nunread;
X	char line[80];
X	FILE *fp;
X	
X	lastp = NULL;
X	writes("Checking for deleted conferences...");
X	for (hip = hicnts; hip != NULL; lastp = hip, hip = hip->hi_next) {
X		if (!isconf(hip->hi_conf)) {
X			writef("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	writes("\nChecking for new messages and conferences...");
X	if ((confs = opendir(MSGBASE)) == NULL) {
X		log("Error %d opening dir %s/", errno, MSGBASE);
X		panic("msgdir");
X	}
X	while ((conf = readdir(confs)) != 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				sprintf(line, "%s/%s/himsg", MSGBASE, conf->d_name);
X				if ((fp = fopen(line, "r")) == (FILE *) 0)
X					break;
X				fgets(line, 32, fp);
X				fclose(fp);
X				nunread = atoi(line);
X				if ((nunread -= hip->hi_num) <= 0)
X					break;
X				writef("There are %d new messages in \"%s\".\n", nunread, conf->d_name);
X				break;
X			}
X		if (hip == NULL) {
X			writef("Conference \"%s\" has been created since your last session.\n", conf->d_name);
X			if ((hip = (struct _himsg *) calloc((unsigned) 1, sizeof (struct _himsg))) == NULL) {
X				log("Error %d allocating _himsg for %s", errno, conf);
X				panic("alloc");
X			}
X			strcpy(hip->hi_conf, conf->d_name);
X			hip->hi_num = 0;
X			hip->hi_next = hicnts;
X			hicnts = hip;
X		}
X	}
X	writehigh(hicnts);
X	closedir(confs);
X}
X
Xcnread(conf)
Xchar *conf; {
X	struct _himsg *hi;
X	
X	for (hi = hicnts; hi != (struct _himsg *) 0; hi = hi->hi_next)
X		if (s_cmp(conf, hi->hi_conf) == 0)
X			return hi->hi_num;
X	return -1;
X}
X
Xedrest() {
X	char rconf[256], line[256];
X	char *p;
X	FILE *fp;
X
X	if (user.u_access != A_WITNESS) {
X		writes("You aren't permitted to edit Restricted conference membership lists.");
X		log("Non-FW attempted to edit restricted conf membership lists");
X		return 1;
X	}
X	if (!parms.ua_xrc) {
X		writes("Restricted conferences are not permitted on this BBS.");
X		log("redit: restricted conferences disabled");
X		return 1;
X	}
X	writef("Enter conference (RETURN / ENTER to abort): ");
X	reads(rconf);
X	log("Rconf: %s", rconf);
X	if (rconf[0] == '\0')
X		return 1;
X	if (!isconf(rconf)) {
X		writef("Conference \"%s\" doesn't exist.", rconf);
X		log("Bad conference: %s", rconf);
X		return 1;
X	}
X	for (p = rconf; *p != '\0'; p++)
X		*p = ToLower(*p);
X	if (s_cmp(user.u_name, parms.ua_sysop) != 0 && !isrcmem(user.u_name, rconf)) {
X		log("FW not a member; list only");
X		rcmemlist(rconf);
X		return 1;
X	}
X	if (!isrconf(rconf))
X		if (s_cmp(user.u_name, parms.ua_sysop) != 0) {
X			writes("Only the Sysop can restrict a conference's membership.");
X			return 1;
X		}
X		else {
X			writef("Conference \"%s\" isn't restricted.  Restrict? N\b", rconf);
X			line[0] = readc();
X			log("Restrict %s? %c", rconf, line[0]);
X			if (line[0] != 'Y')
X				return 1;
X			sprintf(line, "%s/%s", MEMLIST, rconf);
X			if ((fp = fopen(line, "w")) == (FILE *) 0) {
X				log("Error %d creating %s", errno, line);
X				panic("rest_mk");
X			}
X			fclose(fp);
X		}
X	for (;;) {
X		writef("\nList members, Add a member, Delete a member, Clear membership list, or Quit: ");
X		line[0] = readc();
X		switch (line[0]) {
X		case 'L':
X			rcmemlist(rconf);
X			break;
X		case 'A':
X			rcmemadd(rconf);
X			break;
X		case 'D':
X			rcmemdel(rconf);
X			break;
X		case 'C':
X			rcmemclr(rconf);
X			break;
X		case 'Q':
X			return 1;
X		default:
X			writes("Please enter L, A, D, C, or Q.");
X		}
X	}
X}
X
Xisrcmem(uname, conf)
Xchar *uname, *conf; {
X	FILE *fp;
X	char line[256];
X	char *cp;
X
X	if (!parms.ua_xrc || s_cmp(uname, parms.ua_sysop) == 0)
X		return 1;
X	sprintf(line, "%s/%s", MEMLIST, conf);
X	if ((fp = fopen(line, "r")) == (FILE *) 0)
X		return 1;	/* no mem list == no restrictions */
X	while (fgets(line, sizeof line, fp) != (char *) 0) {
X		if ((cp = RIndex(line, '\n')) != (char *) 0)
X			*cp = '\0';
X		if (s_cmp(line, uname) == 0) {
X			fclose(fp);
X			log("%s is a member of restricted conf %s", uname, conf);
X			return 1;
X		}
X	}
X	fclose(fp);
X	log("%s isn't a member of restricted conf %s", uname, conf);
X	return 0;
X}
X
Xrcmemlist(conf)
Xchar *conf; {
X	FILE *fp;
X	char line[256];
X	short headf;
X
X	if (!parms.ua_xrc) {
X		writef("Conference \"%s\" has no restrictions on membership.\n", conf);
X		return;
X	}
X	sprintf(line, "%s/%s", MEMLIST, conf);
X	if ((fp = fopen(line, "r")) == (FILE *) 0) {
X		writef("Conference \"%s\" has no restrictions on membership.\n", conf);
X		return;
X	}
X	headf = 0;
X	while (fgets(line, sizeof line, fp) != (char *) 0) {
X		if (!headf) {
X			writef("Members of the \"%s\" conference:\n\n", conf);
X			headf++;
X		}
X		writef("\t%s\n", upstr(line));
X		/* OOPS!  1 line deleted 2/3/87 ++bsa */
X	}
X	if (!headf)
X		writef("Conference \"%s\" is restricted to Fairwitnesses and the Sysop.\n", conf);
X	fclose(fp);
X}
X
Xrcmemadd(conf)
Xchar *conf; {
X	char line[256], uname[256];
X	struct user ubuf;
X	FILE *fp;
X	
X	writef("Name (RETURN to abort): ");
X	reads(uname);
X	log("Add user %s to %s's mem list", uname, conf);
X	if (uname[0] == '\0')
X		return;
X	if (!getuser(uname, &ubuf)) {
X		writef("User \"%s\" doesn't exist.\n", upstr(uname));
X		log("No such user: %s", uname);
X		return;
X	}
X	if (ubuf.u_access == A_WITNESS && s_cmp(user.u_name, "sysop") != 0) {
X		log("FW attempted to change membership of %s in %s", ubuf.u_name, conf);
X		writes("Sorry, only the Sysop can change a FairWitness's conference membership.");
X		return;
X	}
X	if (isrcmem(uname, conf)) {
X		log("Already a member.");
X		writef("\"%s\" is already a member of this conference.\n", upstr(uname));
X		return;
X	}
X	mklock("memlist.lock");
X	sprintf(line, "%s/%s", MEMLIST, conf);
X	if ((fp = fopen(line, "a")) == (FILE *) 0) {
X		rmlock(conf);
X		log("Error %d opening %s", errno, line);
X		panic("memlist_app");
X	}
X	fprintf(fp, "%s\n", upstr(uname));	/* OOPS!  2/3/87 ++bsa */
X	fclose(fp);
X	rmlock("memlist.lock");
X}
X
Xrcmemdel(conf)
Xchar *conf; {
X	char line[256], uname[256], tname[256];
X	struct user ubuf;
X	FILE *fp, *tp;
X	
X	writef("Name (RETURN to abort): ");
X	reads(uname);
X	log("Del user %s from %s's mem list", uname, conf);
X	if (uname[0] == '\0')
X		return;
X	if (!getuser(uname, &ubuf)) {
X		writef("User \"%s\" doesn't exist.\n", upstr(uname));
X		log("No such user: %s", uname);
X		return;
X	}
X	if (ubuf.u_access == A_WITNESS && s_cmp(user.u_name, "sysop") != 0) {
X		log("FW attempted to change membership of %s in %s", ubuf.u_name, conf);
X		writes("Sorry, only the Sysop can change a FairWitness's conference membership.");
X		return;
X	}
X	if (!isrcmem(uname, conf)) {
X		log("Not a member.");
X		writef("\"%s\" isn't a member of this conference.\n", upstr(uname));
X		return;
X	}
X	sprintf(tname, "/tmp/UAxD%05d", getpid());
X	if ((tp = fopen(tname, "w")) == (FILE *) 0) {
X		log("Error %d opening %s", errno, tname);
X		panic("memlist_dtmp");
X	}
X	mklock("memlist.lock");
X	sprintf(line, "%s/%s", MEMLIST, conf);
X	if ((fp = fopen(line, "r")) == (FILE *) 0) {
X		rmlock(conf);
X		fclose(tp);
X		unlink(tname);
X		log("Error %d opening %s", errno, line);
X		panic("memlist_app");
X	}
X	while (fgets(line, sizeof line, fp) != (char *) 0)
X		if (s_cmp(line, uname) != 0)
X			fputs(line, tp);
X	fclose(fp);
X	fclose(tp);
X	sprintf(line, "%s/%s", MEMLIST, conf);
X	if (unlink(line) < 0) {
X		log("Error %d unlinking %s", errno, line);
X		rmlock("memlist.lock");
X		panic("memlist_drmv");
X	}
X	if (copylink(tname, line) < 0) {
X		log("Error %d copylinking %s to %s", errno, tname, line);
X		rmlock("memlist.lock");
X		panic("memlist_dclnk");
X	}
X	rmlock("memlist.lock");
X}
X
Xrcmemclr(conf)
Xchar *conf; {
X	char mlist[256];
X	
X	if (s_cmp(user.u_name, parms.ua_sysop) != 0) {
X		log("Attempt to clear %s's mem list by non-sysop", conf);
X		writes("Only the Sysop can clear a conference's membership list.");
X		return;
X	}
X	writef("Clear membership list for the \"%s\" conference? N\b", conf);
X	mlist[0] = readc();
X	log("Clear? %c", mlist[0]);
X	if (mlist[0] != 'Y') {
X		log("Aborted.");
X		writes("Aborted.");
X		return;
X	}
X	sprintf(mlist, "%s/%s", MEMLIST, conf);
X	if (unlink(mlist) < 0) {
X		log("Error %s unlinking %s", errno, mlist);
X		writes("Can't remove the membership list.");
X	}
X}
X
Xisrconf(rconf)
Xchar *rconf; {
X	char line[256];
X	FILE *fp;
X	
X	sprintf(line, "%s/%s", MEMLIST, rconf);
X	if ((fp = fopen(line, "r")) == (FILE *) 0)
X		return 0;
X	fclose(fp);
X	return 1;
X}
________This_Is_The_END________
echo 'x - date.c'
sed 's/^X//' << '________This_Is_The_END________' > date.c
X/*
X *	@(#)date.c	1.1 (TDI) 2/3/87
X *	@(#)Copyright (C) 1984, 85, 86, 87 by Brandon S. Allbery.
X *	@(#)This file is part of UNaXcess version 1.0.2.
X *
X *	Permission is hereby granted to copy and distribute this program
X *	freely.  Permission is NOT given to modify this program or distribute
X *	it at cost, except for charging a reasonable media/copying fee.
X */
X
X#ifndef lint
Xstatic char _FileID_[] = "@(#)date.c	1.1 (TDI) 2/3/87";
Xstatic char _UAID_[]   = "@(#)UNaXcess version 1.0.2";
X#endif lint
X
X#include "ua.h"
X
Xstatic char *month[] = {
X	"January",	"February",	"March",	"April",
X	"May",		"June",		"July",		"August",
X	"September",	"October",	"November",	"December"
X};
X
Xstatic char *wkday[] = {
X	"Sunday",	"Monday",	"Tuesday",	"Wednesday",
X	"Thursday",	"Friday",	"Saturday"
X};
X
Xchar *date() {
X	long clock;
X	struct tm *ltbuf;
X	static char tbuf[18];
X
X	time(&clock);
X	ltbuf = localtime(&clock);
X	sprintf(tbuf, "%02d/%02d/%02d %02d:%02d:%02d", ltbuf->tm_mon + 1, ltbuf->tm_mday, ltbuf->tm_year, ltbuf->tm_hour, ltbuf->tm_min, ltbuf->tm_sec);
X	return tbuf;
X}
X
Xchar *longdate() {
X	long clock;
X	struct tm *ltbuf;
X	static char tbuf[80];
X	short hour;
X	char ampm;
X
X	time(&clock);
X	ltbuf = localtime(&clock);
X	if (ltbuf->tm_hour == 0) {
X		hour = 12;
X		ampm = 'A';
X	}
X	else if (ltbuf->tm_hour < 12) {
X		hour = ltbuf->tm_hour;
X		ampm = 'A';
X	}
X	else if (ltbuf->tm_hour == 12) {
X		hour = 12;
X		ampm = 'P';
X	}
X	else {
X		hour = ltbuf->tm_hour - 12;
X		ampm = 'P';
X	}
X	sprintf(tbuf, "%s, %s %d, 19%02d - %d:%02d %cM", wkday[ltbuf->tm_wday], month[ltbuf->tm_mon], ltbuf->tm_mday, ltbuf->tm_year, hour, ltbuf->tm_min, ampm);
X	return tbuf;
X}
X
Xchar *today() {
X	long now;
X	struct tm *datebuf;
X	static char buf[11];
X	
X	time(&now);
X	datebuf = localtime(&now);
X	sprintf(buf, "%d/%d/%d", datebuf->tm_mon + 1, datebuf->tm_mday, datebuf->tm_year);
X	return buf;
X}
________This_Is_The_END________
echo 'x - dir.c'
sed 's/^X//' << '________This_Is_The_END________' > dir.c
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#include <sys/types.h>
X#include "dir.h"
X
X#ifndef BSD
X
Xextern char *malloc();
X
X/*
X * close a directory.
X */
Xclosedir(dirp)
X        register DIR *dirp;
X{
X        close(dirp->dd_fd);
X        dirp->dd_fd = -1;
X        dirp->dd_loc = 0;
X        free(dirp);
X}
X
X
X
X/*
X * open a directory.
X */
XDIR *
Xopendir(name)
X        char *name;
X{
X        register DIR *dirp;
X        register int fd;
X
X        if ((fd = open(name, 0)) == -1)
X                return NULL;
X        if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
X                close (fd);
X                return NULL;
X        }
X        dirp->dd_fd = fd;
X        dirp->dd_loc = 0;
X        return dirp;
X}
X
X
X
X/*
X * read an old style directory entry and present it as a new one
X */
X#define ODIRSIZ 14
X
Xstruct  olddirect {
X        ino_t   od_ino;
X        char    od_name[ODIRSIZ];
X};
X
X/*
X * get next entry in a directory.
X */
Xstruct direct *
Xreaddir(dirp)
X        register DIR *dirp;
X{
X        register struct olddirect *dp;
X        static struct direct dir;
X
X        for (;;) {
X                if (dirp->dd_loc == 0) {
X                        dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 
X                            DIRBLKSIZ);
X                        if (dirp->dd_size <= 0)
X                                return NULL;
X                }
X                if (dirp->dd_loc >= dirp->dd_size) {
X                        dirp->dd_loc = 0;
X                        continue;
X                }
X                dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
X                dirp->dd_loc += sizeof(struct olddirect);
X                if (dp->od_ino == 0)
X                        continue;
X                dir.d_ino = dp->od_ino;
X                strncpy(dir.d_name, dp->od_name, ODIRSIZ);
X                dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
X                dir.d_namlen = strlen(dir.d_name);
X                dir.d_reclen = DIRBLKSIZ;
X                return (&dir);
X        }
X}
X
X#endif BSD
________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 - fileudl.c'
sed 's/^X//' << '________This_Is_The_END________' > fileudl.c
X/*
X *	@(#)fileudl.c	1.1 (TDI) 2/3/87
X *	@(#)Copyright (C) 1984, 85, 86, 87 by Brandon S. Allbery.
X *	@(#)This file is part of UNaXcess version 1.0.2.
X *
X *	Permission is hereby granted to copy and distribute this program
X *	freely.  Permission is NOT given to modify this program or distribute
X *	it at cost, except for charging a reasonable media/copying fee.
X */
X
X#ifndef lint
Xstatic char _FileID_[] = "@(#)fileudl.c	1.1 (TDI) 2/3/87";
Xstatic char _UAID_[]   = "@(#)UNaXcess version 1.0.2";
X#endif lint
X
X#include "ua.h"
X#include <varargs.h>
X
X#define A_UPLOAD	parms.ua_auc
X#define A_DOWNLOAD	parms.ua_adc
X
X#define X_UPLOAD	parms.ua_xuc
X#define X_DOWNLOAD	parms.ua_xdc
X
X#define K_UPLOAD	parms.ua_kuc
X#define K_DOWNLOAD	parms.ua_kdc
X
X#define LIBRARY		"library"
X#define DIRECTORY	"directory"
X#define STORAGE		"uploads"
X#define UPLOG		"upload-log"
X
X#define DIRFORMAT	"%[^ ] %*1[Ff]%*1[Ii]%*1[Ll]%*1[Ee] %[^;]; %[^ ] %*1[Bb]%*1[Yy] %[^:]: %[^\n]"
X
Xjmp_buf brchloop, fileloop;
X
Xchar *whatis(), *cpmform(), *upstr(), *today();
X
Xextern struct tm *localtime();
X
Xudl() {
X	int again();
X	int (*oldint)();
X	char *cp;
X
X	if (user.u_access < A_FILES) {
X		writes("\nYou will not be able to upload or download files.  You may, however, download File Lists.");
X		log("File Section entered; access restricted");
X	}
X	oldint = signal(SIGINT, again);
X	setjmp(brchloop);
X	while (libmenu())
X		;
X	writef("\n");
X	signal(SIGINT, oldint);
X}
X
Xagain() {
X	signal(SIGINT, again);
X	writef("\nInterrupt\n");
X	log("Interrupt");
X	longjmp(brchloop, 1);
X}
X
Xlibmenu() {
X	struct direct *branch;
X	DIR *library;
X	char cmd[512], bname[512];
X	int (*oldsig)();
X	int brch_cmd();
X	char *desc;
X	
X	if ((library = opendir(LIBRARY)) == NULL) {
X		writef("The Library is closed\n");
X		return 0;
X	}
X	writef("\nThe UNaXcess File Section.  Please select one of the following\nbranches, or EXIT to leave the Library.\n\n");
X	while ((branch = readdir(library)) != NULL) {
X		if ((desc = whatis(branch->d_name, NULL)) == NULL)
X			continue;
X		writef("    %-8.8s   %s\n", upstr(branch->d_name), desc);
X	}
X	closedir(library);
X	writef("\nBranch: ");
X	reads(cmd);
X	log("Branch: %s", cmd);
X	if (cmd[0] == '\0' || s_cmp(cmd, "EXIT") == 0)
X		return 0;
X	if (whatis(cmd, NULL) != NULL) {
X		library = opendir(LIBRARY);
X		while ((branch = readdir(library)) != NULL)
X			if (s_cmp(branch->d_name, cmd) == 0) {
X				closedir(library);
X				strcpy(bname, branch->d_name);
X				oldsig = signal(SIGINT, brch_cmd);
X				setjmp(fileloop);
X				while (visit(bname))
X					;
X				signal(SIGINT, oldsig);
X				return 1;
X			}
X	}
X	closedir(library);
X	writef("There is no such branch.  If you wish to open a new branch,\nleave a message to %s.\n", parms.ua_sysop);
X	return 1;
X}
X
Xvisit(branch)
Xchar *branch; {
X	char cmd[512];
X	DIR *directory;
X	
X	sprintf(cmd, "%s/%s", LIBRARY, branch);
X	if ((directory = opendir(cmd)) == NULL) {
X		writef("The %s branch is closed.\n", upstr(branch));
X		return 0;
X	}
X	closedir(directory);
X	writef("\n%s Branch\nUpload, Download, List of Files, Get File List, Exit: ", upstr(branch));
X	cmd[0] = readc();
X	log("Branch cmd: %c", cmd[0]);
X	switch (cmd[0]) {
X		case 'E':
X			return 0;
X		case 'U':
X			upload(branch);
X			break;
X		case 'D':
X			download(branch);
X			break;
X		case 'L':
X			filelist(branch);
X			break;
X		case 'G':
X			getlist(branch);
X			break;
X		default:
X			writef("Unrecognized command.\n");
X	}
X	return 1;
X}
X
Xbrch_cmd() {
X	writef("\nInterrupt\n");
X	log("Interrupt");
X	signal(SIGINT, brch_cmd);
X	longjmp(fileloop, 1);
X}
X
Xfilelist(branch)
Xchar *branch; {
X	char path[512];
X	DIR *directory;
X	struct direct *file;
X	char *desc;
X
X	sprintf(path, "%s/%s", LIBRARY, branch);
X	directory = opendir(path);
X	writef("\nFile Directory for the %s Branch:\n\n", upstr(branch));
X	while ((file = readdir(directory)) != NULL) {
X		if ((desc = whatis(branch, file->d_name)) == NULL)
X			continue;
X		writef("    %-12.12s   %s\n", cpmform(file->d_name), desc);
X	}
X	writef("\n");
X	closedir(directory);
X}
X
Xgetlist(branch)
Xchar *branch; {
X	char path[512], listfile[30], cmd[512];
X	DIR *directory;
X	struct direct *file;
X	int (*oldsig)();
X	char *desc;
X	FILE *list;
X
X	sprintf(listfile, "/tmp/cli%05d", getpid());
X	if ((list = fopen(listfile, "w")) == NULL) {
X		writef("Can't open temporary list file???\n");
X		log("Error %d opening %s", errno,listfile);
X		panic("gfl_temp");
X	}
X	writef("\nDownload file listing from the %s branch\n\nSupported transfer protocols are: Ascii, Xmodem, and Kermit.\n\nEnter File Transfer Protocol (XMODEM default): ", upstr(branch));
X	reads(cmd);
X	log("List dnld mode: %s", cmd);
X	switch (cmd[0]) {
X		case 'A':
X		case 'a':
X			if (!validudl(A_DOWNLOAD)) {
X				writef("\nAscii Download is not supported.\n");
X				log("No Ascii");
X				return;
X			}
X			sprintf(cmd, A_DOWNLOAD, listfile);
X			break;
X		case 'K':
X		case 'k':
X			if (!validudl(K_DOWNLOAD)) {
X				writef("\nKermit Download is not supported.\n");
X				log("No Kermit");
X				return;
X			}
X			sprintf(cmd, K_DOWNLOAD, listfile);
X			break;
X		case 'X':
X		case 'x':
X			if (!validudl(X_DOWNLOAD)) {
X				writef("\nXModem Download is not supported.\n");
X				log("No Xmodem");
X				return;
X			}
X			sprintf(cmd, X_DOWNLOAD, listfile);
X			break;
X		case '\0':
X			cmd[0] = 'X';
X			if (!validudl(X_DOWNLOAD)) {
X				writef("\nXModem Download is not supported.\n");
X				log("No Xmodem");
X				return;
X			}
X			sprintf(cmd, X_DOWNLOAD, listfile);
X			break;
X		default:
X			writef("Invalid protocol designation.\n");
X			return;
X	}
X	sprintf(path, "%s/%s", LIBRARY, branch);
X	directory = opendir(path);
X	fprintf(list, "File Directory for the %s Branch:\r\n\r\n", upstr(branch));
X	while ((file = readdir(directory)) != NULL) {
X		if ((desc = whatis(branch, file->d_name)) == NULL)
X			continue;
X		fprintf(list, "    %-12.12s   %s\r\n", cpmform(file->d_name), desc);
X	}
X	fclose(list);
X	closedir(directory);
X	writef("You have 30 seconds to prepare for file transmission.\nPress BREAK to abort transmission.\n\n");
X	sleep(30);
X	oldsig = signal(SIGINT, SIG_IGN);
X	udlrun(cmd, (char *) 0);
X#ifdef SYS3
X	udlrun("stty", "echoe");
X#endif SYS3
X	signal(SIGINT, oldsig);
X	unlink(listfile);
X}
X
Xdownload(branch)
Xchar *branch; {
X	char path[512], filename[512], cmd[512];
X	DIR *directory;
X	struct direct *file;
X	int (*oldsig)();
X	
X	if (user.u_access < A_FILES) {
X		log("Attempted download, access denied.");
X		writes("You may not download files.");
X		return;
X	}
X	writef("\nDownload from the %s branch\n\nEnter file to download: ", branch);
X	reads(filename);
X	log("Dnld file: %s", filename);
X	if (filename[0] == '.' || Index(filename, '/') != NULL) {
X		writef("No such file: \"%s\"\n", upstr(filename));
X		return;
X	}
X	if (whatis(branch, filename) != NULL) {
X		sprintf(path, "%s/%s", LIBRARY, branch);
X		directory = opendir(path);
X		while ((file = readdir(directory)) != NULL) {
X			if (s_cmp(file->d_name, filename) == 0) {
X				closedir(directory);
X				sprintf(path, "%s/%s/%s", LIBRARY, branch, file->d_name);
X				writef("Supported transfer protocols are: Ascii, Xmodem, and Kermit.\n\nEnter File Transfer Protocol (XMODEM default): ", upstr(branch));
X				reads(cmd);
X				switch (cmd[0]) {
X					case 'A':
X					case 'a':
X						if (!validudl(A_DOWNLOAD)) {
X							writef("\nAscii Download is not supported.\n");
X							log("No Ascii");
X							return;
X						}
X						sprintf(cmd, A_DOWNLOAD, path);
X						break;
X					case 'K':
X					case 'k':
X						if (!validudl(K_DOWNLOAD)) {
X							writef("\nKermit Download is not supported.\n");
X							log("No Kermit");
X							return;
X						}
X						sprintf(cmd, K_DOWNLOAD, path);
X						break;
X					case 'X':
X					case 'x':
X						if (!validudl(X_DOWNLOAD)) {
X							writef("\nXModem Download is not supported.\n");
X							log("No Xmodem");
X							return;
X						}
X						sprintf(cmd, X_DOWNLOAD, path);
X						break;
X					case '\0':
X						cmd[0] = 'X';
X						if (!validudl(X_DOWNLOAD)) {
X							writef("\nXModem Download is not supported.\n");
X							log("No Xmodem");
X							return;
X						}
X						sprintf(cmd, X_DOWNLOAD, path);
X						break;
X					default:
X						writef("Invalid protocol designation.\n");
X						return;
X				}
X				writef("You have 30 seconds to prepare for file transmission.\nPress BREAK to abort transmission.\n\n");
X				sleep(30);
X				oldsig = signal(SIGINT, SIG_IGN);
X				udlrun(cmd, (char *) 0);
X#ifdef SYS3
X				udlrun("stty", "echoe");
X#endif SYS3
X				signal(SIGINT, oldsig);
X				return;
X			}
X		}
X		closedir(directory);
X	}
X	writef("No such file: \"%s\"\n", upstr(filename));
X	log("No such file");
X}
X
Xupload(branch)
Xchar *branch; {
X	char path[512], filename[512], cmd[512], desc[512];
X	DIR *directory;
X	struct direct *file;
X	int (*oldsig)();
X	FILE *logf;
X	
X	if (user.u_access < A_FILES) {
X		log("Attempted upload, access denied.");
X		writes("You may not upload files.");
X		return;
X	}
X	writef("\nUpload to the %s branch\n\nEnter the name to give the new file: ", branch);
X	reads(filename);
X	log("Upld file: %s", filename);
X	if (filename[0] == '.' || Index(filename, '/') != NULL || Index(filename, ';') != NULL) {
X		writef("Invalid filename: \"%s\"\n", upstr(filename));
X		log("Invalid filename");
X		return;
X	}
X	sprintf(path, "%s/%s", STORAGE, branch);
X	if ((directory = opendir(path)) == NULL) {
X		writef("The %s has denied upload ability for this branch.\n", parms.ua_sysop);
X		return;
X	}
X	while ((file = readdir(directory)) != NULL) {
X		if (s_cmp(file->d_name, filename) == 0) {
X			closedir(directory);
X			writef("That file name is used.  Please try again with a different filename.\n");
X			log("File exists");
X			return;
X		}
X	}
X	closedir(directory);
X	writef("Enter a description for the file: ");
X	reads(desc);
X	log("Description: %s", desc);
X	if ((logf = fopen(UPLOG, "a")) == NULL) {
X		log("Error %d opening %s", errno, UPLOG);
X		writef("Can't log the new file.\n");
X		return;
X	}
X	fprintf(logf, "%s file %s; %s by %s: %s\n", branch, filename, today(), upstr(user.u_name), desc);
X	fclose(logf);
X	sprintf(path, "%s/%s/%s", STORAGE, branch, filename);
X	writef("Supported transfer protocols are: Ascii, Xmodem, and Kermit.\nXmodem protocol uses checksums; CCITT CRC is not supported.\n\nEnter File Transfer Protocol (XMODEM default): ", upstr(branch));
X	reads(cmd);
X	log("Upld protocol: %s", cmd);
X	switch (cmd[0]) {
X		case 'A':
X		case 'a':
X			if (!validudl(A_UPLOAD)) {
X				writef("\nAscii Upload is not supported.\n");
X				log("No Ascii");
X				return;
X			}
X			sprintf(cmd, A_UPLOAD, path);
X			break;
X		case 'K':
X		case 'k':
X			if (!validudl(K_UPLOAD)) {
X				writef("\nKermit Upload is not supported.\n");
X				log("No Kermit");
X				return;
X			}
X			sprintf(cmd, K_UPLOAD, path);
X			break;
X		case 'X':
X		case 'x':
X			if (!validudl(X_UPLOAD)) {
X				writef("\nXModem Upload is not supported.\n");
X				log("No Xmodem");
X				return;
X			}
X			sprintf(cmd, X_UPLOAD, path);
X			break;
X		case '\0':
X			cmd[0] = 'X';
X			if (!validudl(X_UPLOAD)) {
X				writef("\nXModem Upload is not supported.\n");
X				log("No Xmodem");
X				return;
X			}
X			sprintf(cmd, X_UPLOAD, path);
X			break;
X		default:
X			writef("Invalid protocol designation.\n");
X			return;
X	}
X	writef("You have 30 seconds to prepare for file transmission.\nPress BREAK to abort transmission.\n\n");
X	sleep(30);
X	oldsig = signal(SIGINT, SIG_IGN);
X	udlrun(cmd, (char *) 0);
X#ifdef SYS3
X	udlrun("stty", "echoe");
X#endif SYS3
X	signal(SIGINT, oldsig);
X}
X
Xchar *whatis(branch, file)
Xchar *branch, *file; {
X	static FILE *directory = NULL;
X	static char dent[512];
X	char tbr[512], tfi[512], fdate[512], who[512], desc[512];
X	
X	if (directory != NULL || (directory = fopen(DIRECTORY, "r")) != NULL) {
X		fseek(directory, 0L, 0);
X		while (fgets(dent, sizeof dent, directory) != NULL) {
X			if (dent[0] == '%' || dent[0] == '\n')
X				continue;
X			tbr[0] = '\0';
X			tfi[0] = '\0';
X			fdate[0] = '\0';
X			who[0] = '\0';
X			desc[0] = '\0';
X			if (sscanf(dent, DIRFORMAT, tbr, tfi, fdate, who, desc) != 5)
X				continue;
X			if (s_cmp(tbr, branch) == 0) {
X				if (s_cmp(tfi, (file == NULL? "branch": file)) != 0)
X					continue;
X				sprintf(dent, "%s [Created %s by %s]", desc, fdate, who);
X				return dent;
X			}
X		}
X	}
X	if (directory == NULL)
X		log("No download directory");
X	return NULL;
X}
X
Xchar *cpmform(fn)
Xchar *fn; {
X	static char buf[13];
X	register int cnt, scnt;
X	
X	for (scnt = 0, cnt = 0; cnt < 8 && fn[cnt] != '.' && fn[cnt] != '\0'; cnt++, scnt++)
X		buf[scnt] = ToUpper(fn[cnt]);
X	while (scnt < 8)
X		buf[scnt++] = ' ';
X	buf[scnt++] = '.';
X	while (fn[cnt] != '.' && fn[cnt] != '\0')
X		cnt++;
X	if (fn[cnt] == '.')
X		cnt++;
X	while (scnt < 12 && fn[cnt] != '\0') {
X		buf[scnt++] = ToUpper(fn[cnt]);
X		cnt++;
X	}
X	while (scnt < 12)
X		buf[scnt++] = ' ';
X	buf[scnt] = '\0';
X	return buf;
X}
X
Xvalidudl(cmd)
Xchar *cmd; {
X	if (cmd[0] == '\0')
X		return 0;
X	if (Index(cmd, '%') != RIndex(cmd, '%'))
X		return 0;
X	if (Index(cmd, '%') == (char *) 0) {
X		strcat(cmd, " %s");
X		return 1;
X	}
X	if (*(Index(cmd, '%') + 1) != 's')
X		return 0;
X	return 1;
X}
X
Xudlrun(cmd, arg)
Xchar *cmd, *arg; {
X	int pid, sig, status;
X
X	switch (pid = fork()) {
X	case -1:
X		log("Error %d on fork for udlrun", errno);
X		writes("The system is too busy; try again later.");
X		return -1;
X	case 0:
X		for (sig = SIGINT; sig <= SIGTERM; sig++)
X			signal(sig, SIG_DFL);
X		setuid(getuid());
X		run(cmd, arg);
X		exit(-1);
X	default:
X		CRIT();
X		io_off();
X		for (sig = SIGIOT; sig <= SIGTERM; sig++)
X			signal(sig, SIG_IGN);
X		while (wait(&status) != pid)
X			;
X		if (status != 0) {
X			log("Status from \"%s %s\": %d", cmd, arg, status);
X			writes("Error executing UDL program");
X		}
X		for (sig = SIGIOT; sig <= SIGTERM; sig++)
X			signal(sig, logsig);
X		signal(SIGALRM, thatsall);
X		io_on(0);
X		NOCRIT();
X	}
X	return 1;
X}
________This_Is_The_END________
echo 'x - io.c'
sed 's/^X//' << '________This_Is_The_END________' > io.c
X/*
X *	@(#)io.c	1.2 (TDI) 2/3/87
X *	@(#)Copyright (C) 1984, 85, 86, 87 by Brandon S. Allbery.
X *	@(#)This file is part of UNaXcess version 1.0.2.
X *
X *	Permission is hereby granted to copy and distribute this program
X *	freely.  Permission is NOT given to modify this program or distribute
X *	it at cost, except for charging a reasonable media/copying fee.
X */
X
X#ifndef lint
Xstatic char _FileID_[] = "@(#)io.c	1.1 (TDI) 2/3/87";
Xstatic char _UAID_[]   = "@(#)UNaXcess version 1.0.2";
X#endif lint
X
X#include "ua.h"
X#include <varargs.h>
X
X#define linelen	user.u_llen
X#define pagelen	user.u_lines
X
X#ifdef SYS3
X#  include <sys/ioctl.h>
X#  include <termio.h>
X#  define TERMPARAMS		struct termio
X#  define GETPARAMS(fd, buf)	ioctl(fd, TCGETA, buf)
X#  define SETPARAMS(fd, buf)	ioctl(fd, TCSETAW, buf)
X#  define TERM_CHARMODE(buf)	((buf)->c_lflag &= ~(ICANON|ECHO), (buf)->c_cc[VMIN] = 1, (buf)->c_cc[VTIME] = 0)	/* OOPS!  2/3/87 ++bsa */
X#else
X#  include <sgtty.h>
X#  ifdef V7
X#    define SETPARAMS(fd, buf)	gtty(fd, buf)
X#    define SETPARAMS(fd, buf)	stty(fd, buf)
X#    define TERMPARAMS		struct sgttyb
X#    define TERM_CHARMODE(buf)	((buf)->sg_flags &= ~ECHO, (buf)->sg_flags |= RAW)	/* OOPS!  2/3/87 ++bsa */
X#  else
X#    include <sys/ioctl.h>
X#    define GETPARAMS(fd, buf)	(ioctl(fd, TIOCGETP, &((*(buf)).__tp)), ioctl(fd, TIOCGETC, &((*(buf)).__tc)))
X#    define SETPARAMS(fd, buf)	(ioctl(fd, TIOCSETN, &((*(buf)).__tp)), ioctl(fd, TIOCSETC, &((*(buf)).__tc)))
X#    define TERMPARAMS		struct { struct sgttyb __tp; struct tchars __tc; }
X#    define TERM_CHARMODE(buf)	((buf)->__tp.sg_flags &= ~ECHO, (buf)->__tp.sg_flags |= CBREAK, (buf)->__tc.t_intrc = '\003')	/* OOPS!  2/387 ++bsa */
X#  endif V7
X#endif SYS3
X
Xstatic int __pager = -1, __wrap, __bwrap, __col, __didwrp, __suppsp, __echo;
Xstatic TERMPARAMS __oldterm, __newterm;
Xstatic char __buf[133];
Xstatic char *__bufp;
Xstatic char __so_buf[BUFSIZ];
X
Xio_on(flag) {
X	setbuf(stdout, __so_buf);
X	__pager = 1;
X	__wrap = 1;
X	__echo = 1;
X	__bwrap = 1;
X	__didwrp = 0;
X	__col = 0;
X	__suppsp = 0;
X	__bufp = __buf;
X	if (flag) {
X		user.u_lines = 16;
X		user.u_llen = 80;
X	}
X	if (GETPARAMS(fileno(stdin), &__oldterm) < 0)
X		return;
X	__newterm = __oldterm;
X	TERM_CHARMODE(&__newterm);
X	SETPARAMS(fileno(stdout), &__newterm);
X}
X
Xio_off() {
X	if (__pager == -1)
X		return;
X	__flushwd();
X	SETPARAMS(fileno(stdout), &__oldterm);
X}
X
Xwritec(ch)
Xregister char ch; {
X	register int cnt;
X	register char *cp;
X
X	ch &= 0x7f;
X	if (ch == '\t') {
X		do {
X			writec(' ');
X		} while (__col % 8 != 0);
X		return;
X	}
X	if (ch < ' ' && ch != '\r' && ch != '\n' && ch != '\b') {
X		writec('^');
X		writec(uncntrl(ch));
X		return;
X	}
X	if (ch == '\177') {
X		writec('^');
X		writec('?');
X		return;
X	}
X	if (!__wrap) {
X		__outch(ch);
X		return;
X	}
X	__didwrp = 0;
X	if (!__bwrap) {
X		if (__col == linelen - 1 && ch != '\b' && ch != '\r' && ch != '\n') {
X			for (cnt = 0; &__buf[cnt] < __bufp; cnt++)
X				__didwrp++;
X			for (cp = __bufp - 1; cp >= __buf; cp--) {
X				__outch('\b');
X				__outch(' ');
X				__outch('\b');
X				if (*cp == '\177' || *cp < ' ') {
X					__outch('\b');
X					__outch(' ');
X					__outch('\b');
X				}
X			}
X			__outch('\n');
X			__suppsp = 1;
X			for (cp++; cp < __bufp; cp++)
X				__outch(*cp);
X		}
X		__outch(ch);
X		fflush(stdout);
X	}
X	if (ch == ' ' || ch == '\n') {
X		if (__bwrap)
X			__flushwd();
X		__bufp = __buf;
X		if (__bwrap) {
X			if (ch == ' ') {
X				if (!__suppsp)
X					__outch(' ');
X			}
X			if (ch == '\n')
X				__outch('\n');
X		}
X		return;
X	}
X	__suppsp = 0;
X	*__bufp = '\0';
X	if (__bwrap && strlen(__buf) == linelen - 1) {
X		__outch('\n');
X		__suppsp = 1;
X		for (__bufp = __buf; *__bufp != '\0'; __bufp++)
X			if (*__bufp != ' ' || !__suppsp) {
X				__outch(*__bufp);
X				__suppsp = 0;
X			}
X		__outch('\n');
X		__bufp = __buf;
X		__suppsp = 1;
X		return;
X	}
X	*__bufp++ = ch;
X}
X
X__outch(ch)
Xregister char ch; {
X	switch (ch) {
X	case '\n':
X		putchar('\r');
X		putchar('\n');
X		__col = 0;
X		if (pagelen > 0 && __pager > 0 && ++__pager == pagelen) {
X			fputs("--More--", stdout);
X			fflush(stdout);
X			ch = getchar();
X			__pager = 1;
X			fputs("\b \b\b \b\b \b\b \b\b \b\b \b\b \b\b \b", stdout);
X		}
X		fflush(stdout);
X		__suppsp = 0;
X		break;
X	case '\r':
X		putchar('\r');
X		__col = 0;
X		__suppsp = 0;
X		break;
X	case '\b':
X		if (__col == 0)
X			break;
X		putchar('\b');
X		__col--;
X		__suppsp = 0;
X		break;
X	default:
X		if (__col == linelen - 1) {
X			__outch('\n');
X			__suppsp = 1;
X		}
X		if (ch < ' ' || ch > '~')
X			putchar('.');
X		else if (ch != ' ' || !__suppsp) {
X			putchar(ch);
X			__suppsp = 0;
X		}
X		__col++;
X		break;
X	}
X}
X
Xwrites(str)
Xregister char *str; {
X	for (; *str != '\0'; str++)
X		writec(*str);
X	writec('\n');
X}
X
X/*VARARGS*/
Xwritef(va_alist)
Xva_dcl {
X	register va_list args;
X	register char *fmt;
X	register char esch;
X	register short esclen;
X	short lzflag, ljflag, width, prec, longf, precf;
X	
X	va_start(args);
X	for (fmt = va_arg(args, char *); *fmt != '\0'; fmt++) {
X		if (*fmt == '\\')
X			switch (*++fmt) {
X			case '\0':
X				va_end(args);
X				return;
X			case 'n':
X				writec('\n');
X				break;
X			case 't':
X				writec('\t');
X				break;
X			case 'r':
X				writec('\r');
X				break;
X			case 'b':
X				writec('\b');
X				break;
X			case 'f':
X				writec('\f');
X				break;
X			case '0':
X			case '1':
X			case '2':
X			case '3':
X			case '4':
X			case '5':
X			case '7':
X				esch = '\0';
X				for (esclen = 0; esclen < 3; esclen++) {
X					esch = esch << 3;
X					esch += *fmt - '0';
X					if (*++fmt != '0' &&
X					      *fmt != '1' &&
X					      *fmt != '2' &&
X					      *fmt != '3' &&
X					      *fmt != '4' &&
X					      *fmt != '5' &&
X					      *fmt != '6' &&
X					      *fmt != '7')
X					      	break;
X				}
X				writec(esch);
X				break;
X			default:
X				writec(*fmt);
X				break;
X			}
X		else if (*fmt != '%')
X			writec(*fmt);
X		else {
X			lzflag = 0;
X			ljflag = 0;
X			width = 0;
X			prec = 0;
X			longf = 0;
X			precf = 0;
X
Xmorefmt:
X			switch (*++fmt) {
X			case '\0':
X				writec('%');
X				va_end(args);
X				return;
X			case 'c':
X				__fmtc(va_arg(args, int), ljflag, width);
X				break;
X			case 'd':
X				if (longf)
X					__fmti(va_arg(args, long), lzflag, ljflag, width, 10);
X				else
X					__fmti((long) va_arg(args, int), lzflag, ljflag, width, 10);
X				break;
X			case 'x':
X				if (longf)
X					__fmti(va_arg(args, long), lzflag, ljflag, width, 16);
X				else
X					__fmti((long) va_arg(args, int), lzflag, ljflag, width, 16);
X				break;
X			case 'o':
X				if (longf)
X					__fmti(va_arg(args, long), lzflag, ljflag, width, 8);
X				else
X					__fmti((long) va_arg(args, int), lzflag, ljflag, width, 8);
X				break;
X			case 's':
X				__fmts(va_arg(args, char *), ljflag, width, prec);
X				break;
X			case 'f':
X				__fmtf(va_arg(args, double), ljflag, width, prec);
X				break;
X			case 'e':
X				__fmte(va_arg(args, double), ljflag, width, prec);
X				break;
X			case 'g':
X				__fmtg(va_arg(args, double), ljflag, width, prec);
X				break;
X			case 'l':
X				if (longf)
X					break;
X				longf = 1;
X				goto morefmt;
X			case '-':
X				if (precf || width > 0 || lzflag || ljflag)
X					break;
X				ljflag = 1;
X				goto morefmt;
X			case '*':
X				if (!precf)
X					if (width != 0) {
X						writec('*');
X						break;
X					}
X					else
X						width = va_arg(args, int);
X				else if (prec != 0) {
X					writec('*');
X					break;
X				}
X				else
X					prec = va_arg(args, int);
X				goto morefmt;
X			case '0':
X				if (!precf && width == 0)
X					lzflag = 1;
X				else if (precf)
X					prec *= 10;
X				else
X					width *= 10;
X				goto morefmt;
X			case '1':
X			case '2':
X			case '3':
X			case '4':
X			case '5':
X			case '6':
X			case '7':
X			case '8':
X			case '9':
X				if (precf) {
X					prec *= 10;
X					prec += *fmt - '0';
X				}
X				else {
X					width *= 10;
X					width += *fmt - '0';
X				}
X				goto morefmt;
X			case '.':
X				if (precf)
X					break;
X				precf = 1;
X				goto morefmt;
X			default:
X				break;
X			}
X		}
X	}
X	va_end(args);
X}
X
X__fmtc(ch, ljflag, width)
Xregister int width; {
X	if (width > 255)
X		width = 255;
X	if (width < 2) {
X		writec(ch);
X		return;
X	}
X	width--;
X	if (!ljflag)
X		while (width-- > 0)
X			writec(' ');
X	writec(ch);
X	if (ljflag)
X		while (width-- > 0)
X			writec(' ');
X}
X
X__fmts(str, ljflag, width, prec)
Xregister char *str;
Xregister int width, prec; {
X	register int len;
X
X	if (str == (char *) 0)
X		str = "(null)";
X	if (prec == 0)
X		prec = strlen(str);
X	for (len = 0; str[len] != '\0' && len < prec; len++)
X		;
X	if (width < len)
X		width = 0;
X	else
X		width -= len;
X	if (!ljflag)
X		while (width-- > 0)
X			writec(' ');
X	while (len-- > 0)
X		writec(*str++);
X	if (ljflag)
X		while (width-- > 0)
X			writec(' ');
X}
X
X__fmti(num, lzflag, ljflag, width, base)
Xlong num;
Xregister int width; {
X	char buf[19];
X	char *bufp, *dp;
X	int sign;
X	static char digit[] = "0123456789ABCDEF";
X	
X	sign = 0;
X	if (num < 0L) {
X		num = -num;
X		sign = 1;
X	}
X	if (width > 18)
X		width = 18;
X	bufp = &buf[width? width: 18];
X	*bufp-- = '\0';
X	while (bufp >= buf) {
X		*bufp-- = digit[num % base];
X		num /= base;
X	}
X	for (bufp = buf; *bufp == '0'; bufp++)
X		;
X	if (*bufp == '\0')
X		bufp--;
X	width -= strlen(bufp) + sign;
X	if (width < 0)
X		width = 0;
X	if (lzflag)
X		ljflag = 0;
X	if (!ljflag)
X		while (width-- > 0)
X			writec(lzflag? '0': ' ');
X	if (sign)
X		writec('-');
X	while (*bufp != '\0')
X		writec(*bufp++);
X	if (ljflag)
X		while (width-- > 0)
X			writec(' ');
X}
X
X__fmte(num, ljflag, width, prec)
Xdouble num;
Xregister int width; {
X	char buf[20];
X	int isneg, expon;
X	register char *bufp;
X	
X	if (width > 18)
X		width = 18;
X	strcpy(buf, ecvt(num, (prec? prec: 18) - 6 - (num < 0.0), &expon, &isneg));
X	if (prec == 0)
X		for (bufp = &buf[12 - (num < 0.0? 1: 0)]; bufp != buf && *bufp != '\0'; bufp--)
X			*bufp = '\0';
X	if (width < strlen(buf) + 6 + (num < 0.0? 1: 0))
X		width = strlen(buf) + 6 + (num < 0.0? 1: 0);
X	width -= strlen(buf) + 6 + (num < 0.0);
X	if (!ljflag)
X		while (width-- > 0)
X			writec(' ');
X	if (isneg)
X		writec('-');
X	writec('.');
X	for (bufp = buf; *bufp != '\0'; bufp++)
X		writec(*bufp);
X	writec('E');
X	writec(expon < 0? '-': '+');
X	__fmti((long) expon, 1, 0, 2, 10);
X	if (ljflag)
X		while (width-- > 0)
X			writec(' ');
X}
X
X__fmtf(num, ljflag, width, prec)
Xdouble num;
Xregister int width; {
X	char buf[40];
X	int isneg, expon;
X	register char *bufp;
X	
X	if (width > 18)
X		width = 18;
X	strcpy(buf, ecvt(num, prec, &expon, &isneg));
X	if (width < strlen(buf) + 1 + (num < 0.0))
X		width = strlen(buf) + 1 + (num < 0.0);
X	width -= strlen(buf) + 1 + (num < 0.0);
X	if (!ljflag)
X		while (width-- > 0)
X			writec(' ');
X	if (isneg)
X		writec('-');
X	for (bufp = buf; *bufp != '\0'; bufp++) {
X		if (expon-- == 0)
X			writec('.');
X		writec(*bufp);
X	}
X	if (expon == 0)
X		writec('.');
X	if (ljflag)
X		while (width-- > 0)
X			writec(' ');
X}
X
X__fmtg(num, ljflag, width, prec)
Xdouble num;
Xregister int width; {
X	char buf[40];
X	register char *bufp;
X	
X	if (width > 18)
X		width = 18;
X	strcpy(buf, gcvt(num, prec, buf));
X	if (width < strlen(buf))
X		width = strlen(buf);
X	width -= strlen(buf);
X	if (!ljflag)
X		while (width-- > 0)
X			writec(' ');
X	for (bufp = buf; *bufp != '\0'; bufp++)
X		writec(*bufp);
X	if (ljflag)
X		while (width-- > 0)
X			writec(' ');
X}
X
Xchar *reads(buf)
Xchar *buf; {
X	short bp;
X	int savecol, rpos;
X	char ch;
X	
X	savecol = __col;
X	__pager = 0;
X	__wrap = 0;
X	__flushwd();
X	bp = 0;
X	fflush(stdout);
X	while ((ch = getchar() & 0x7f) != '\n' && ch != '\r') {
X		switch (ch) {
X		case '\177':
X		case '\b':
X			if (bp == 0)
X				putchar('\7');
X			else {
X				bp--;
X				if (__echo) {
X					if (__col > 0) {
X						writec('\b');
X						writec(' ');
X						writec('\b');
X					}
X					else {
X						if (bp - linelen < -1) {
X							while (__col < savecol)
X								writec(' ');
X							rpos = 0;
X						}
X						else
X							rpos = bp - linelen + 1;
X						while (rpos < bp)
X							writec(buf[rpos++]);
X					}
X				}
X			}
X			break;
X		case '\030':
X		case '\025':
X			if (__echo) {
X				writec('X');
X				writec('X');
X				writec('X');
X				writec('\n');
X				while (__col < savecol)
X					writec(' ');
X			}
X			bp = 0;
X			break;
X		default:
X			if (ch < ' ' || bp == 255)
X				putchar('\7');
X			else {
X				if (__echo)
X					__outch(ch);
X				buf[bp++] = ch;
X			}
X		}
X		fflush(stdout);
X	}
X	writec('\n');
X	fflush(stdout);
X	__wrap = 1;
X	__pager = 1;
X	buf[bp] = '\0';
X	return buf;
X}
X
Xinteract() {
X	__flushwd();
X	__bwrap = 0;
X	__pager = 0;
X}
X
Xbuffer() {
X	__bwrap = 1;
X	__bufp = __buf;
X	__pager = 1;
X}
X
Xwrapped() {
X	return __didwrp;
X}
X
X__flushwd() {
X	*__bufp = '\0';
X	if (strlen(__buf) >= linelen - __col) {
X		__outch('\n');
X		__suppsp = 1;
X	}
X	for (__bufp = __buf; *__bufp != '\0'; __bufp++)
X		if (*__bufp != ' ' || !__suppsp) {
X			__outch(*__bufp);
X			__suppsp = 0;
X		}
X	__bufp = __buf;
X	fflush(stdout);
X}
X
Xdoecho() {
X	__echo = 1;
X}
X
Xxecho() {
X	__echo = 0;
X}
X
Xcat(file)
Xchar *file; {
X	FILE *f;
X	int ch;
X
X	if ((f = fopen(file, "r")) == NULL) {
X		log("Error %d opening %s", errno, file);
X		writes("Cannot open file.");
X		return;
X	}
X	while ((ch = getc(f)) != EOF)
X		writec(ch);
X	fclose(f);
X}
X
Xreadc() {
X	char ch;
X	
X	__flushwd();
X	__pager = 0;
X	while (((ch = getchar() & 0x7f) < ' ' && ch != '\r' && ch != '\n') || ch == '\177') {
X		putchar('\7');
X		fflush(stdout);
X	}
X	if (ch > ' ') {
X		ch = ToUpper(ch);
X		writec(ch);
X	}
X	else
X		ch = ' ';
X	writec('\n');
X	fflush(stdout);
X	__pager = 1;
X	return ch;
X}
________This_Is_The_END________
exit 0
--
++Brandon (Resident Elf @ ncoast.UUCP)
 ____   ______________
/    \ / __   __   __ \   Brandon S. Allbery	    <backbone>!ncoast!allbery
 ___  | /__> /  \ /  \    aXcess Co., Consulting    ncoast!allbery at Case.CSNET
/   \ | |    `--, `--,    6615 Center St. #A1-105 	   (... at relay.CS.NET)
|     | \__/ \__/ \__/    Mentor, OH 44060-4101     
\____/ \______________/   +1 216 781 6201



More information about the Mod.sources mailing list