IMS (mail system) Part 1/2

Brandon S. Allbery allbery at ncoast.UUCP
Tue Jul 22 12:05:50 AEST 1986


IMS is a simple ``folder''-oriented mail reader (think of a baby MH).  It can
be used in interactive mode, or combined with shell scripts to manipulate mail
a' la MH.  (One simple idea is a shell script:

#! /bin/sh
exec ims "$0" "$@"

which is linked to IMS command names and executes the IMS commands.)  The
manual page describes its use.

I have found that it is faster than mailx (Mail) in most things, faster than
/bin/mail in many... and ENORMOUSLY faster than msg (although I haven't tried
its new incarnation as ``elm'' yet).  But it's not full-screen oriented.

This mailer is still tiny and simple at present.  I'll be adding to it, in
particular adding to the folder support, as only the current folder and the
save folder are generally accessible.  But for now it's fast and does the
things I want it to do.

It has been tested under System III and System V; it should work under 4.2BSD
if you #define BSD (it uses BSD-compatible directory routines under USG
unices) but it won't work as is under V7.  It also doesn't store timezones in
messages under 4.2; I haven't the faintest idea how to retrieve the timezone.

Cut at the dotted line, feed to /bin/sh, make, and enjoy!

++Brandon
-------------------------------- coupe ici ----------------------------------
#! /bin/sh
#
# Shell archive created Thu., Jul. 17, 1986 by tdi2!brandon.
# Contents:
#
#	-rw-r--r--   1 brandon  20          8881 Jul 17 08:54 ims.c
#	-rw-r--r--   1 brandon  20         10207 Jul 17 08:55 imsread.c
#	-rw-r--r--   1 brandon  20          3279 Jul 17 09:04 imsdel.c
#	-rw-r--r--   1 brandon  20          5932 Jul 17 11:11 imsinc.c
#	-rw-r--r--   1 brandon  20         12610 Jul 17 09:42 imssend.c
#	-rw-r--r--   1 brandon  20          4618 Jul 17 09:07 imsset.c
#	-rw-r--r--   1 brandon  sys         5411 Jul 17 09:11 imsalias.c
#	-rw-r--r--   1 brandon  20          1934 Jul  4 19:47 ndir.c
#	-rw-r--r--   1 brandon  20          1540 Jul  4 20:01 eopen.c
#	-rw-r--r--   1 brandon  sys         1756 Jul 17 09:47 ims.h
#	-rw-rw-rw-   1 brandon  20          2471 Jul  3 19:52 ndir.h
#	-rw-r--r--   1 brandon  20         18403 Jul 17 10:44 ims.1
#	-rw-r--r--   1 brandon  20          1501 Jul 17 11:26 Makefile
#
# You may unpack this archive with sh or ksh, but not csh.
#

if test -r "ims.c"; then
	echo "File ims.c exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="ims.c"
	esac
else
	newname="ims.c"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:ims.c--' > "$newname"
X#include "ims.h"
X
Xstruct cmdtab {
X	char *c_cmd;
X	int (*c_func)();
X	char *c_help;
X} cmdtab[] = {
X	"delete",	delmsg,		"Delete a message",
X	"undelete",	undelmsg,	"Recover a deleted message",
X	"expunge",	expunge,	"Recover space occupied by deleted messages",
X	"type",		readmsg,	"Display a message",
X	"print",	printmsg,	"Print a message on printer",
X	"save",		savemsg,	"Save a message in a file or folder",
X	"set",		varops,		"Display or modify IMS variables",
X	"next",		nextmsg,	"Go to the next message",
X	"+",		nextmsg,	"Go to the next message",
X	"previous",	prevmsg,	"Go to the previous message",
X	"-",		prevmsg,	"Go to the previous message",
X	"write",	savemsg,	"Save a message in a file or folder",
X	"reply",	reply,		"Reply to a message",
X	"goto",		gomsg,		"Set the current message",
X	"mail",		mailto,		"Send mail to users",
X	"send",		mailto,		"Send mail to users",
X	"list",		listmsg,	"List the headers of messages",
X	"headers",	listmsg,	"List the headers of messages",
X	"forward",	forward,	"Forward a message to another person",
X	"from",		listmsg,	"List the headers of messages",
X	"quit",		byebye,		"Leave IMS, expunging deleted messages",
X	"exit",		nxbyebye,	"Leave IMS without expunging messages",
X	"xit",		nxbyebye,	"Leave IMS without expunging messages",
X	"?",		help,		"Get help on a command",
X	"help",		help,		"Get help on a command",
X	"folder",	setfolder,	"Set or show the current folder",
X	"read",		readmbox,	"Read old-style mailbox into folder",
X	"inc",		readmbox,	"Read old-style mailbox into folder",
X	"folders",	foldlist,	"List the existing folders",
X	"alias",	aliasops,		"Display or create mail aliases",
X	"unalias",	unalias,	"Delete mail aliases",
X	(char *) 0,	readmsg,	"Read the named or numbered message",
X};
X
Xchar folder[256];
Xchar cabinet[256];
Xchar mailbox[1024];
Xchar prompt[256];
Xint msg;
Xjmp_buf mainloop;
Xchar sysmbox[1024];
Xchar autoread[256] = "No";
Xchar lines[256] = "24";
Xint _x;
X
Xintr() {
X	longjmp(mainloop, 1);
X}
X
Xmain(argc, argv)
Xchar *argv[]; {
X	char line[512];
X	char *cp;
X	int nmsg, incf;
X	struct stat sbuf;
X
X	if ((cp = getenv("HOME")) == (char *) 0)
X		cp = "/usr/guest";
X	sprintf(cabinet, "%s/.mail", cp);
X	sprintf(sysmbox, SYSMAILBOX, getlogin());
X	strcpy(mailbox, sysmbox);
X	strcpy(line, "incoming-mail");
X	strcpy(prompt, "IMS> ");
X	readvars();
X	readalias();
X	if (access(cabinet, 0) < 0)
X		if (mkdir(cabinet) < 0) {
X			puts("Can't create your mail cabinet.  Please check your CABINET and your home\ndirectory.");
X			exit(1);
X		}
X	if ((cp = getenv("FOLDER")) != (char *) 0)
X		strcpy(line, cp);
X	if (setfolder(line) < 0) {
X		puts("Please check your CABINET and FOLDER.");
X		exit(1);
X	}
X	if ((cp = getenv("MAIL")) != (char *) 0)
X		strcpy(mailbox, cp);
X	if ((cp = getenv("PAGER")) != (char *) 0)
X		strcpy(pager, cp);
X	if ((cp = getenv("VISUAL")) == (char *) 0)
X		if ((cp = getenv("EDITOR")) == (char *) 0)
X			cp = (char *) 0;
X	if (cp != (char *) 0)
X		strcpy(editor, cp);
X	if ((cp = getenv("PRINTMSG")) == (char *) 0)
X		strcpy(printcmd, "pr -h \"Printed by: ${LOGNAME:-${USER:-anonymous}} \" | lpr");
X	else
X		strcpy(printcmd, cp);
X	if ((cp = getenv("SAVEFOLDER")) != (char *) 0)
X		strcpy(savefolder, cp);
X	if ((cp = getenv("LINES")) != (char *) 0)
X		strcpy(lines, cp);
X	incf = 1;
X	nmsg = 1;
X	if (argc >= nmsg + 1 && strcmp(argv[nmsg], "-i") == 0) {
X		incf = 0;
X		nmsg++;
X	}
X	line[0] = '\0';
X	for (; nmsg < argc; nmsg++) {
X		strcat(line, " ");
X		strcat(line, argv[nmsg]);
X	}
X	if (line[0] != '\0') {
X		dispatch(line);
X		exit(0);
X	}
X	if (incf) {
X		msg = receive(mailbox);
X		if (msg == -1)
X			puts("Your system mailbox has been deleted.  Please contact your system administrator\nin order to have it restored.");
X		if (msg != 0)
X			printf("New messages start at %d.\n", msg);
X		else {
X			listmsg("");
X			msg = 1;
X		};
X	}
X	_x = 0;
X	if (isatty(2)) {
X		stat(ttyname(2), &sbuf);
X		if (sbuf.st_mode & 0111) {
X			_x = 1;
X			chmod(ttyname(2), sbuf.st_mode & ~0111);
X		}
X	}
X	signal(SIGINT, intr);
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGPIPE, SIG_IGN);
X	if (setjmp(mainloop) != 0)
X		puts("\nCommand interrupted.");
X	for (;;) {
X		if (newmail(mailbox)) {
X			puts("New mail has arrived.  Reading your mailbox...");
X			if (autoread[0] == 'Y' || autoread[0] == 'y' || autoread[0] == 'T' || autoread[0] == 't') {
X				nmsg = receive(mailbox);
X				if (nmsg == -1)
X					puts("Your system mailbox has been deleted.  Please contact your system administrator\nin order to have it restored.");
X				if (nmsg != 0)
X					printf("New messages start at %d.\n", nmsg);
X			}
X		}
X		printf("%s", prompt);
X		if (gets(line) == (char *) 0) {
X			putchar('\n');
X			expunge("");
X			break;
X		}
X		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
X			;
X		if (*cp == '!') {
X			system(cp + 1);
X			continue;
X		}
X		if (dispatch(cp) == 0)
X			break;
X	}
X	if (_x) {
X		stat(ttyname(2), &sbuf);
X		chmod(ttyname(2), sbuf.st_mode | 0111);
X	}
X	exit(0);
X}
X
Xdispatch(cmd)
Xchar *cmd; {
X	char *cp, *cmdp, *nextp;
X	int cnt, status, ran;
X	
X	for (;;) {
X		if ((nextp = strchr(cmd, ';')) == (char *) 0)
X			nextp = "\376";
X		else
X			*nextp++ = '\0';
X		for (cp = cmd; *cp == ' ' || *cp == '\t'; cp++)
X			;
X		for (cmdp = cp; *cp != '\0' && *cp != '\t' && *cp != ' '; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		if (*cmdp == '\376')
X			break;
X		ran = 0;
X		cnt = 0;
X		if (strlen(cmdp) != 0) {
X			for (cnt = 0; cmdtab[cnt].c_cmd != (char *) 0; cnt++) {
X				if (strlen(cmdp) > strlen(cmdtab[cnt].c_cmd))
X					continue;
X				if (strncmp(cmdp, cmdtab[cnt].c_cmd, strlen(cmdp)) == 0)
X					if ((status = (*cmdtab[cnt].c_func)(cp)) < 1)
X						return status;
X					else {
X						ran = 1;
X						break;
X					}
X			}
X		}
X		while (cmdtab[cnt].c_cmd != (char *) 0)
X			cnt++;
X		if (!ran) {
X			if (cmdtab[cnt].c_func != (int (*)()) 0) {
X				if ((status = (*cmdtab[cnt].c_func)(cmdp)) < 1)
X					return status;
X			}
X			else {
X				printf("Unknown command: \"%s\".  Type \"help\" for help.\n", cmdp);
X				return -1;
X			}
X		}
X		cmd = nextp;
X	}
X	return status;
X}
X
Xhelp(cmdp)
Xchar *cmdp; {
X	char *cp, *dp;
X	int cnt, icnt;
X
X	for (cp = cmdp; *cp == ' ' || *cp == '\t'; cp++)
X		;
X	for (dp = cp; *dp != ' ' && *dp != '\t' && *dp != '\0'; dp++)
X		;
X	if (*dp != '\0')
X		*dp++ = '\0';
X	while (*dp == ' ' || *dp == '\t')
X		;
X	if (*dp != '\0') {
X		puts("Usage:  help [topic]");
X		return -1;
X	}
X	icnt = 0;
X	if (atoi(lines) <= 3)
X		strcpy(lines, "24");
X	for (cnt = 0; cmdtab[cnt].c_cmd != (char *) 0; cnt++) {
X		if (strlen(cp) > strlen(cmdtab[cnt].c_cmd))
X			continue;
X		if (*cp == '\0' || strncmp(cp, cmdtab[cnt].c_cmd, strlen(cp)) == 0) {
X			printf("  %-16s   %s\n", cmdtab[cnt].c_cmd, cmdtab[cnt].c_help);
X			icnt++;
X			if (icnt % (atoi(lines) - 1) == 0)
X				getcont();
X		}
X	}
X	if (*cp != '\0' && icnt == 0)
X		if (strcmp(cp, "default") == 0)
X			printf("  %-16s   %s\n", "Default:", cmdtab[cnt].c_help);
X		else {
X			printf("Unknown topic: \"%s\".\n", cp);
X			return -1;
X		}
X	else if (*cp == '\0')
X		printf("  %-16s   %s\n", "Default:", cmdtab[cnt].c_help);
X	return 1;
X}
X
Xsetfolder(cmdp)
Xchar *cmdp; {
X	char *cp;
X	
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp == '\0') {
X		printf("The current folder is \"%s\".\n", folder);
X		return 1;
X	}
X	for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X		;
X	if (*cp != '\0')
X		*cp++ = '\0';
X	while (*cp != '\0')
X		if (*cp != ' ' || *cp != '\t') {
X			puts("Too many arguments.  Usage: folder [folder-name]");
X			return -1;
X		}
X	if (access(location(cmdp), 0) < 0) {
X		if (mkdir(location(cmdp)) < 0) {
X			fprintf(stderr, "Can't create \"%s\" folder.\n", cmdp);
X			return -1;
X		}
X		if (access(location(cmdp), 0) < 0) {
X			fprintf(stderr, "I can't get at your \"%s\" folder.\n, cmdp");
X			return -1;
X		}
X	}
X	strcpy(folder, cmdp);
X	return 1;
X}
X
Xmkdir(dir)
Xchar *dir; {
X	int pid, status;
X	
X	switch (pid = fork()) {
X		case -1:
X			perror("");
X			printf("Can't create directory \"%s\".\n", dir);
X			return -1;
X		case 0:
X			execl("/bin/mkdir", "mkdir", dir, (char *) 0);
X			_exit(-100);
X		default:
X			while (wait(&status) != pid)
X				;
X			if (status != 0)
X				return -1;
X	}
X	return 0;
X}
X
Xchar *location(folder)
Xchar *folder; {
X	static char buf[1024];
X	
X	if (folder[0] == '/' || folder[0] == '.')
X		return folder;
X	sprintf(buf, "%s/%s", cabinet, folder);
X	return buf;
X}
X
Xbyebye(cmdp)
Xchar *cmdp; {
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp != '\0') {
X		puts("Too many arguments.  Usage: quit\n                        Or: xit");
X		return -1;
X	}
X	if (expunge("") < 0)
X		return -1;
X	return 0;
X}
X
Xnxbyebye(cmdp)
Xchar *cmdp; {
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp != '\0') {
X		puts("Too many arguments.  Usage: xit");
X		return -1;
X	}
X	return 0;
X}
X
Xchar *basename(s)
Xchar *s; {
X	char *cp;
X	
X	if ((cp = strrchr(s, '/')) != (char *) 0)
X		return cp + 1;
X	return s;
X}
X
Xisfolder(f)
Xchar *f; {
X	struct stat s;
X	
X	if (stat(location(f), &s) < 0)
X		return 0;
X	return (s.st_mode & S_IFMT) == S_IFDIR;
X}
X
Xissysmbox(mbox)
Xchar *mbox; {
X	return strcmp(mbox, sysmbox) == 0;
X}
--EOF:ims.c--
fi

if test -r "imsread.c"; then
	echo "File imsread.c exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="imsread.c"
	esac
else
	newname="imsread.c"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:imsread.c--' > "$newname"
X#include "ims.h"
X
Xchar pager[1024] = "/usr/ucb/more";
Xchar printcmd[1024];
Xchar savefolder[256] = "saved-mail";
Xchar askappend[] = "Yes";
X
Xnextmsg(cmdp)
Xchar *cmdp; {
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp != '\0') {
X		puts("Usage:  next");
X		return -1;
X	}
X	msg++;
X	if (autonext[0] == 'y' || autonext[0] == 'Y' || autonext[0] == 't' || autonext[0] == 'T')
X		if (readmsg("-q") < 0) {
X			puts("No next message.");
X			return -1;
X		}
X	else if (!ismsg(msg)) {
X		puts("No next message.");
X		return -1;
X	}
X	return 1;
X}
X
Xprevmsg(cmdp)
Xchar *cmdp; {
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp != '\0') {
X		puts("Usage:  previous");
X		return -1;
X	}
X	msg--;
X	if (autonext[0] == 'y' || autonext[0] == 'Y' || autonext[0] == 't' || autonext[0] == 'T')
X		if (readmsg("-q") < 0) {
X			puts("No next message.");
X			return -1;
X		}
X	else if (!ismsg(msg)) {
X		puts("No next message.");
X		return -1;
X	}
X	return 1;
X}
X
Xreadmsg(cmdp)
Xchar *cmdp; {
X	char *cp;
X	int foldmsg, quiet;
X	char mname[80];
X
X	quiet = 0;
X
X_again:
X	foldmsg = 0;
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp != '\0') {
X		for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X			if (strchr("0123456789", *cp) == (char *) 0)
X				foldmsg = 1;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		if (strcmp(cmdp, "-q") == 0) {
X			if (quiet) {
X				puts("Usage:  type [-q] [message-number]");
X				return -1;
X			}
X			else {
X				quiet = 1;
X				cmdp = cp;
X				goto _again;
X			}
X		}
X		while (*cp != '\0')
X			if (*cp != '\t' && *cp != ' ') {
X				puts("Too many arguments.  Usage: type [-q] [message-number]");
X				return -1;
X			}
X		if (!ismsg(cmdp)) {
X			if (!quiet)
X				puts("No such message.");
X			return -1;
X		}
X		if (!foldmsg)
X			msg = atoi(cmdp);
X	}
X	if (foldmsg)
X		return dorms(cmdp, pager);
X	sprintf(mname, ".%d", msg);
X	if (ismsg(mname))
X		return dorms(mname, pager);
X	sprintf(mname, "%d", msg);
X	if (!ismsg(mname)) {
X		if (!quiet)
X			printf("Message %d doesn't exist.\n", msg);
X		return -1;
X	}
X	return dorms(mname, pager);
X}
X
Xchar *mlocation(msg)
Xchar *msg; {
X	static char path[1024];
X	
X	if ((msg[0] == '.' && msg[1] == '/') || msg[0] == '/')
X		strcpy(path, msg);
X	else
X		sprintf(path, "%s/%s", location(folder), msg);
X	return path;
X}
X
Xchar *mflocation(folder, msg)
Xchar *folder, *msg; {
X	static char path[1024];
X	
X	if ((msg[0] == '.' && msg[1] == '/') || msg[0] == '/')
X		strcpy(path, msg);
X	else
X		sprintf(path, "%s/%s", location(folder), msg);
X	return path;
X}
X
Xdorms(msg, cmd)
Xchar *msg, *cmd; {
X	FILE *fp;
X	int status;
X
X	if (cmd == (char *) 0)
X		fp = (FILE *) 0;
X	else if ((fp = epopen(cmd, "w")) == (FILE *) 0) {
X		printf("Can't open pipe to command: %s\n", cmd);
X		return -1;
X	}
X	status = docopy(msg, fp);
X	if (fp != (FILE *) 0)
X		pclose(fp);
X	return 1;
X}
X
Xdosave(msg, file)
Xchar *msg, *file; {
X	FILE *fp;
X	int status;
X	char yesno[512];
X	char *cp;
X
X	if ((askappend[0] == 'Y' || askappend[0] == 'y' || askappend[0] == 'T' || askappend[0] == 't') && file != (char *) 0 && access(file, 0) == 0) {
X		printf("File exists.  Do you wish to append to it? ");
X		if (gets(yesno) == (char *) 0) {
X			puts("No");
X			return -1;
X		}
X		for (cp = yesno; *cp != ' ' && *cp != '\t'; cp++)
X			;
X		if (*cp != 'y' && *cp != 'Y')
X			return -1;
X	}
X	if (file == (char *) 0)
X		fp = (FILE *) 0;
X	else if ((fp = efopen(file, "a")) == (FILE *) 0) {
X		printf("Can't open file: %s\n", file);
X		return -1;
X	}
X	status = docopy(msg, fp);
X	if (fp != (FILE *) 0)
X		fclose(fp);
X	return status;
X}
X
Xdocopy(msg, mfp)
Xchar *msg;
XFILE *mfp; {
X	char line[1024];
X	FILE *fp;
X
X	if ((fp = efopen(mlocation(msg), "r")) == (FILE *) 0) {
X		printf("Message %s doesn't exist.\n", msg);
X		return -1;
X	}
X	if (mfp == (FILE *) 0)
X		mfp = stdout;
X	if (msg[0] == '.')
X		fprintf(mfp, "Message %s (deleted):\n", msg + 1);
X	else
X		fprintf(mfp, "Message %s:\n", msg);
X	dopipe(fp, mfp);
X	fclose(fp);
X	return 1;
X}
X
Xdopipe(msg, outp)
XFILE *msg, *outp; {
X	char ch;
X	
X	while ((ch = getc(msg)) != EOF)
X		putc(ch, outp);
X}
X
Xismsg(msg)
Xchar *msg; {
X	char delmsg[256];
X	struct stat sbuf;
X
X	strcpy(delmsg, ".");
X	strcat(delmsg, msg);
X	if (access(mlocation(delmsg), 0) == 0) {
X		stat(mlocation(delmsg), &sbuf);
X		return (sbuf.st_mode & S_IFMT) != S_IFDIR;
X	}
X	if (access(mlocation(msg), 0) < 0)
X		return 0;
X	stat(mlocation(msg), &sbuf);
X	return (sbuf.st_mode & S_IFMT) != S_IFDIR;
X}
X
Xisdeleted(msg)
Xchar *msg; {
X	char delmsg[256];
X
X	strcpy(delmsg, ".");
X	strcat(delmsg, msg);
X	return access(mlocation(delmsg), 0) == 0;
X}
X
Xprintmsg(cmdp)
Xchar *cmdp; {
X	char *cp;
X	int foldmsg;
X	char mname[80];
X
X	foldmsg = 0;
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp != '\0') {
X		for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X			if (strchr("0123456789", *cp) == (char *) 0)
X				foldmsg = 1;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		while (*cp != '\0')
X			if (*cp != '\t' && *cp != ' ') {
X				puts("Too many arguments.  Usage: print [message-number]");
X				return -1;
X			}
X		if (!ismsg(cmdp)) {
X			puts("No such message.");
X			return -1;
X		}
X		if (!foldmsg)
X			msg = atoi(cmdp);
X	}
X	if (foldmsg)
X		return dorms(cmdp, printcmd);
X	sprintf(mname, ".%d", msg);
X	if (ismsg(mname))
X		return dorms(mname, printcmd);
X	sprintf(mname, "%d", msg);
X	if (!ismsg(mname)) {
X		printf("Message %d doesn't exist.\n", msg);
X		return -1;
X	}
X	return dorms(mname, printcmd);
X}
X
Xsavemsg(cmdp)
Xchar *cmdp; {
X	char *cp, *savep;
X	int foldmsg, status;
X	char mname[80], savefile[80];
X
X	foldmsg = 0;
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp == '\0')
X		sprintf(savefile, "%s/%s", location(savefolder), folder);
X	else {
X		for (cp = cmdp; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		if (strchr(cmdp, '/') != (char *) 0)
X			strcpy(savefile, cmdp);
X		else
X			sprintf(savefile, "%s/%s", location(savefolder), cmdp);
X		for (savep = cp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X			if (strchr("0123456789", *cp) == (char *) 0)
X				foldmsg = 1;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		while (*cp == ' ' || *cp == '\t')
X			cp++;
X		if (*cp != '\0') {
X			puts("Too many arguments.  Usage: save file [message-number]");
X			return -1;
X		}
X		if (*savep != '\0') {
X			if (!ismsg(savep)) {
X				puts("No such message.");
X				return -1;
X			}
X			if (!foldmsg)
X				msg = atoi(savep);
X		}
X	}
X	if (foldmsg)
X		return dosave(savep, savefile);
X	sprintf(mname, ".%d", msg);
X	if (ismsg(mname))
X		status = dosave(mname, savefile);
X	else {
X		sprintf(mname, "%d", msg);
X		if (!ismsg(mname)) {
X			printf("Message %d doesn't exist.\n", msg);
X			return -1;
X		}
X		status = dosave(mname, savefile);
X	}
X	if (status < 1)
X		return status;
X	return delmsg("");
X}
X
Xgomsg(cmdp)
Xchar *cmdp; {
X	char *cp;
X
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp == '\0') {
X		puts("Usage: goto message-number");
X		return -1;
X	}
X	for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X		if (strchr("0123456789", *cp) == (char *) 0) {
X			puts("Invalid message number.  Usage: goto message-number");
X			return -1;
X		}
X	if (*cp != '\0')
X		*cp++ = '\0';
X	while (*cp != '\0')
X		if (*cp != '\t' && *cp != ' ') {
X			puts("Too many arguments.  Usage: goto message-number");
X			return -1;
X		}
X	if (!ismsg(cmdp)) {
X		puts("No such message.");
X		return -1;
X	}
X	msg = atoi(cmdp);
X	if (autonext[0] == 'y' || autonext[0] == 'Y' || autonext[0] == 't' || autonext[0] == 'T')
X		return readmsg("");
X	return 1;
X}
X
Xlistmsg(cmdp)
Xchar *cmdp; {
X	char *cp;
X	DIR *dp;
X	struct direct *entry;
X	extern int errno;
X	extern char *sys_errlist[];
X	FILE *mp;
X	char mline[2048], from[21], subj[51];
X	int cnt, cmsg;
X
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp == '\0')
X		cmdp = folder;
X	else {
X		for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		while (*cp != '\0')
X			if (*cp != '\t' && *cp != ' ') {
X				puts("Too many arguments.  Usage: list [folder-name]\nOr: list folders");
X				return -1;
X			}
X		if (!isfolder(cmdp)) {
X			puts("No such folder.");
X			return -1;
X		}
X	}
X	if ((dp = opendir(location(cmdp))) == (DIR *) 0) {
X		puts("Can't open folder for listing.");
X		return -1;
X	}
X	cnt = 0;
X	if (atoi(lines) < 3)
X		strcpy(lines, "24");
X	while ((entry = readdir(dp)) != (struct direct *) 0) {
X		if (entry->d_name[0] == '.' && (entry->d_name[1] == '\0' || (entry->d_name[1] == '.' && entry->d_name[2] == '\0')))
X			continue;
X		from[0] = '\0';
X		subj[0] = '\0';
X		cnt++;
X		if (cnt == 1)
X			printf("Contents of folder \"%s\":\nSt Name     From                 Subject\n", cmdp);
X		if (sscanf(entry->d_name, "%d", &cmsg) != 1)
X			putchar(' ');
X		else if (cmsg == msg)
X			putchar('*');
X		else
X			putchar(' ');
X		if (entry->d_name[0] == '.')
X			printf("D %-8.8s ", &entry->d_name[1]);
X		else
X			printf("  %-8.8s ", entry->d_name);
X		if ((mp = efopen(mflocation(cmdp, entry->d_name), "r")) == (FILE *) 0) {
X			puts("unreadable");
X			if (cnt % (atoi(lines) - 1) == 0)
X				getcont();
X			continue;
X		}
X		while (fgets(mline, sizeof mline, mp) != (char *) 0) {
X			if (mline[0] == '\n')
X				break;
X			if (strncmp(mline, "Subject: ", 9) == 0) {
X				mline[strlen(mline) - 1] = '\0';
X				strncpy(subj, &mline[9], 50);
X				subj[50] = '\0';
X			}
X			if (strncmp(mline, "From: ", 6) == 0) {
X				mline[strlen(mline) - 1] = '\0';
X				strncpy(from, &mline[6], 20);
X				from[20] = '\0';
X			}
X		}
X		printf("%-20.20s", from);
X		if (subj[0] != '\0')
X			printf(" \"%.50s\"", subj);
X		putchar('\n');
X		if (cnt % (atoi(lines) - 1) == 0)
X			getcont();
X		fclose(mp);
X	}
X	if (cnt == 0)
X		printf("No messages in folder \"%s\".\n", folder);
X	return 1;
X}
X
Xfoldlist(cmdp)
Xchar *cmdp; {
X	DIR *dp;
X	struct direct *entry;
X	int cnt;
X	
X	while (*cmdp == '\t' || *cmdp == ' ')
X		cmdp++;
X	if (*cmdp != '\0') {
X		puts("Usage:  folders");
X		return -1;
X	}
X	if ((dp = opendir(cabinet)) == (DIR *) 0) {
X		puts("Can't open cabinet to list folders.");
X		return -1;
X	}
X	puts("The following folders exist in the cabinet:");
X	if (atoi(lines) <= 3)
X		strcpy(lines, "24");
X	while ((entry = readdir(dp)) != (struct direct *) 0) {
X		if (entry->d_name[0] == '.' && (entry->d_name[1] == '\0' || (entry->d_name[1] == '.' && entry->d_name[2] == '\0')))
X			continue;
X		printf("  %s\n", entry->d_name);
X		if (++cnt % atoi(lines) - 1 == 0)
X			getcont();
X	}
X	return 1;
X}
--EOF:imsread.c--
fi

if test -r "imsdel.c"; then
	echo "File imsdel.c exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="imsdel.c"
	esac
else
	newname="imsdel.c"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:imsdel.c--' > "$newname"
X#include "ims.h"
X
Xchar autonext[128] = "No";
X
Xdelmsg(cmdp)
Xchar *cmdp; {
X	char *cp;
X	char mname[80], curmsg[80], mt1[100], mt2[100];
X
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp != '\0') {
X		for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		while (*cp != '\0')
X			if (*cp != '\t' && *cp != ' ') {
X				puts("Too many arguments.  Usage: delete [message-number]");
X				return -1;
X			}
X		if (!ismsg(cmdp)) {
X			puts("No such message.");
X			return -1;
X		}
X	}
X	else {
X		sprintf(curmsg, "%d", msg);
X		cmdp = curmsg;
X	}
X	sprintf(mname, ".%s", cmdp);
X	if (ismsg(mname)) {
X		puts("The message is already deleted.  Type \"expunge\" to free its space.");
X		return -1;
X	}
X	if (!ismsg(cmdp)) {
X		puts("There is no such message.");
X		return -1;
X	}
X	strcpy(mname, ".");
X	strcat(mname, cmdp);
X	strcpy(mt1, mlocation(cmdp));
X	strcpy(mt2, mlocation(mname));
X	if (link(mt1, mt2) < 0) {
X		puts("Could not flag the message as deleted.");
X		return -1;
X	}
X	if (unlink(mt1) < 0) {
X		puts("Could not flag the message as deleted.");
X		unlink(mt2);
X		return -1;
X	}
X	msg++;
X	if (autonext[0] == 'y' || autonext[0] == 'Y' || autonext[0] == 't' || autonext[0] == 'T')
X		if (readmsg("-q") < 0) {
X			puts("No next message.");
X			return -1;
X		}
X	return 1;
X}
X
Xundelmsg(cmdp)
Xchar *cmdp; {
X	char *cp;
X	char mname[80], curmsg[80], mt1[100], mt2[100];
X
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp != '\0') {
X		for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		while (*cp != '\0')
X			if (*cp != '\t' && *cp != ' ') {
X				puts("Too many arguments.  Usage: undelete [message-number]");
X				return -1;
X			}
X		if (!ismsg(cmdp)) {
X			puts("No such message.");
X			return -1;
X		}
X	}
X	else {
X		sprintf(curmsg, "%d", msg);
X		cmdp = curmsg;
X	}
X	sprintf(mname, ".%s", cmdp);
X	if (!ismsg(mname)) {
X		puts("The message isn't deleted.");
X		return -1;
X	}
X	strcpy(mname, ".");
X	strcat(mname, cmdp);
X	strcpy(mt1, mlocation(cmdp));
X	strcpy(mt2, mlocation(mname));
X	if (link(mt2, mt1) < 0) {
X		puts("Could not flag the message as restored.");
X		return -1;
X	}
X	if (unlink(mt2) < 0) {
X		puts("Could not flag the message as restored.");
X		unlink(mt1);
X		return -1;
X	}
X	return 1;
X}
X
Xexpunge(cmdp)
Xchar *cmdp; {
X	char *cp;
X	DIR *dp;
X	struct direct *entry;
X	extern int errno;
X	extern char *sys_errlist[];
X
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp == '\0')
X		cmdp = folder;
X	else {
X		for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		while (*cp != '\0')
X			if (*cp != '\t' && *cp != ' ') {
X				puts("Too many arguments.  Usage: expunge [folder-name]");
X				return -1;
X			}
X		if (!isfolder(cmdp)) {
X			puts("No such folder.");
X			return -1;
X		}
X	}
X	if ((dp = opendir(location(cmdp))) == (DIR *) 0) {
X		puts("Can't open folder for expunging.");
X		return -1;
X	}
X	while ((entry = readdir(dp)) != (struct direct *) 0) {
X		if (entry->d_name[0] != '.')
X			continue;
X		if (entry->d_name[1] == '\0' || (entry->d_name[1] == '.') && entry->d_name[2] == '\0')
X			continue;
X		if (unlink(mflocation(cmdp, entry->d_name)) < 0)
X			printf("Couldn't expunge message: %s (%s)\n", &entry->d_name[1], sys_errlist[errno]);
X	}
X	return 1;
X}
--EOF:imsdel.c--
fi

if test -r "imsinc.c"; then
	echo "File imsinc.c exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="imsinc.c"
	esac
else
	newname="imsinc.c"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:imsinc.c--' > "$newname"
X#include "ims.h"
X
Xreadmbox(cmdp)
Xchar *cmdp; {
X	char *cp;
X	int cnt;
X
X	for (; *cmdp == ' ' || *cmdp == '\t'; cmdp++)
X		;
X	if (*cmdp != '\0') {
X		for (cp = cmdp; *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		while (*cp != '\0')
X			if (*cp != '\t' && *cp != ' ') {
X				puts("Too many arguments.  Usage: read [mailbox-name]");
X				return -1;
X			}
X	}
X	else
X		cmdp = mailbox;
X	if ((cnt = receive(cmdp)) == -1) {
X		puts("No mailbox.");
X		return -1;
X	}
X	return 1;
X}
X
Xreceive(mbox)
Xchar *mbox; {
X	FILE *mbp, *mp;
X	char line[1024], from[512], subj[512], date[512], msgn[40], path[1024];
X	static char cc[10240], to[10240];
X	char *cp;
X	int first, next, cnt;
X	enum {
X		Initial,
X		HLine1,
X		Header,
X		Body,
X	} state;
X
X	next = 0;
X	do
X		sprintf(msgn, "%d", ++next);
X	while (access(mlocation(msgn), 0) == 0);
X	if (issysmbox(mbox))
X		if (lockmbox(1) < 0) {
X			puts("Mailbox is locked.  Try again in a few minutes.");
X			return 0;
X		}
X	if ((mbp = efopen(mbox, "r")) == (FILE *) 0) {
X		printf("Can't open mailbox: %s\n", mbox);
X		if (issysmbox(mbox))
X			lockmbox(0);
X		return 0;
X	}
X	first = next;
X	state = Initial;
X	cnt = 0;
X	while (fgets(line, sizeof line, mbp) != (char *) 0) {
X		if (strncmp(line, "From ", 5) == 0) {
X			if (state != Initial) {
X				fclose(mp);
X				do
X					sprintf(msgn, "%d", ++next);
X				while (ismsg(msgn));
X			}
X			if ((mp = efopen(mlocation(msgn), "w")) == (FILE *) 0) {
X				printf("Error:  can't create new message %d.  Mailbox restored.\n", next);
X				fclose(mbp);
X				if (issysmbox(mbox))
X					lockmbox(0);
X				return 0;
X			}
X			cnt++;
X			strcpy(to, "");
X			strcpy(from, "");
X			strcpy(path, "Path: ");
X			strcpy(cc, "");
X			strcpy(subj, "");
X			strcpy(date, "Date: ");
X			for (cp = line + 5; *cp != ' '; cp++)
X				;
X			*cp++ = '\0';
X			strcat(path, line + 5);
X			strcat(path, "\n");
X			while (*cp == ' ')
X				cp++;
X			strcat(date, cp);
X			state = HLine1;
X			continue;
X		}
X		if (state == HLine1) {
X			state = Body;
X			if (strncmp(line, ">From ", 6) == 0 && rmtinc(path, line)) {
X				state = HLine1;
X				continue;
X			}
X			for (cp = line; *cp != '\0'; cp++)
X				if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01235456789_-", *cp) == (char *) 0)
X					break;
X			if (*cp == ':' && *(cp + 1) == ' ')
X				state = Header;
X			else {
X				if (from[0] == '\0') {
X					strcpy(from, "From: ");
X					strcat(from, &path[6]);
X				}
X				fputs(date, mp);
X				fputs(path, mp);
X				fputs(from, mp);
X				fputs(subj, mp);
X				fputs(to, mp);
X				fputs(cc, mp);
X				putc('\n', mp);
X				if (cnt == 1)
X					printf("New mail in folder \"%s\":\n", folder);
X				printf("  %5d   %-20.*s", next, (strlen(from) > 27? 20: strlen(from) - 7), &from[6]);
X				if (subj[0] != '\0')
X					printf(" \"%.*s\"", (subj[0] == '\0'? 0: (strlen(subj) < 50? strlen(subj) - 10: 40)), &subj[9]);
X				putchar('\n');
X			}
X		}
X		if (state == Header && line[0] == '\n') {
X			if (from[0] == '\0') {
X				strcpy(from, "From: ");
X				strcat(from, &path[6]);
X			}
X			fputs(date, mp);
X			fputs(path, mp);
X			fputs(from, mp);
X			fputs(subj, mp);
X			fputs(to, mp);
X			fputs(cc, mp);
X			if (cnt == 1)
X				printf("New mail in folder \"%s\":\n", folder);
X			printf("  %5d   %-20.*s", next, (strlen(from) > 27? 20: strlen(from) - 7), &from[6]);
X			if (subj[0] != '\0')
X				printf(" \"%.*s\"", (subj[0] == '\0'? 0: (strlen(subj) < 50? strlen(subj) - 10: 40)), &subj[9]);
X			putchar('\n');
X			state = Body;
X		}
X		if (state == Body) {	
X			fputs(line, mp);
X			continue;
X		}
X		if (strncmp(line, "Date: ", 6) == 0) {
X			strcpy(date, line);
X			continue;
X		}
X		if (strncmp(line, "From: ", 6) == 0) {
X			strcpy(from, line);
X			continue;
X		}
X		if (strncmp(line, "Subject: ", 9) == 0) {
X			strcpy(subj, line);
X			continue;
X		}
X		if (strncmp(line, "To: ", 4) == 0) {
X			strcat(to, line);
X			continue;
X		}
X		if (strncmp(line, "Cc: ", 4) == 0) {
X			strcat(cc, line);
X			continue;
X		}
X	}
X	if (state != Initial)
X		fclose(mp);
X	fclose(mbp);
X	if (!issysmbox(mbox)) {
X		if (unlink(mbox) < 0)
X			puts("Couldn't delete the mailbox.");
X	}
X	else {
X		if ((mbp = efopen(mbox, "w")) == (FILE *) 0)
X			puts("Couldn't empty your mailbox; check the ownership.");
X		else
X			fclose(mbp);
X		if (lockmbox(0) < 0)
X			puts("Can't unlock your mailbox (please inform a system administrator).");
X	}
X	if (cnt == 0) {
X		puts("No new messages.");
X		return 0;
X	}
X	printf("Received %d new message%s into folder.\n", cnt, (cnt == 1? "": "s"));
X	return first;
X}
X
Xlockmbox(flag) {
X	char lockname[1024];
X	struct stat sbuf;
X	long now;
X	int lfd;
X	
X	strcpy(lockname, sysmbox);
X	strcat(lockname, ".lock");
X	if (flag == 0)
X		return unlink(lockname);
X	if (stat(lockname, &sbuf) == 0) {
X		time(&now);
X		if (now - sbuf.st_ctime < 300)
X			return -1;
X		else if (unlink(lockname) < 0) {
X			puts("Can't unlock your mailbox (fatal error).");
X			exit(1);
X		}
X	}
X	if ((lfd = creat(lockname, 0600)) < 0) {
X		puts("Can't lock your mailbox (fatal error).");
X		exit(1);
X	}
X	close(lfd);
X	return 0;
X}
X
Xnewmail(f)
Xchar *f; {
X	struct stat sbuf;
X	
X	if (stat(f, &sbuf) < 0)
X		return 0;
X	return sbuf.st_size > 0L;
X}
X
X/*
X * line contains ``>From user ...''
X * if after date comes ``remote from ...'' then generate new path from it
X */
X
Xrmtinc(path, line)
Xchar *path, *line; {
X	char *cp, *rpath;
X	
X	if (line[strlen(line) - 1] == '\n')
X		line[strlen(line) - 1] = '\0';
X	for (cp = line + strlen(line) - 1; *cp == ' '; cp--)
X		if (cp == line)
X			return 0;
X	*(cp + 1) = '\0';
X	while (*cp != ' ')
X		if (--cp == line)
X			return 0;
X	rpath = cp + 1;
X	while (*cp == ' ')
X		if (--cp == line)
X			return 0;
X	*(cp + 1) = '\0';
X	while (*cp != ' ')
X		if (--cp == line)
X			return 0;
X	if (strcmp(cp + 1, "from") != 0)
X		return 0;
X	while (*cp == ' ')
X		if (--cp == line)
X			return 0;
X	*(cp + 1) = '\0';
X	while (*cp != ' ')
X		if (--cp == line)
X			return 0;
X	if (strcmp(cp + 1, "remote") != 0)
X		return 0;
X	cp = line + 6;
X	while (*cp != ' ')
X		cp++;
X	*cp = '\0';
X	sprintf(path, "Path: %s!%s\n", rpath, line + 6);
X	return 1;
X}
--EOF:imsinc.c--
fi

if test -r "imssend.c"; then
	echo "File imssend.c exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="imssend.c"
	esac
else
	newname="imssend.c"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:imssend.c--' > "$newname"
X#include "ims.h"
X
Xchar *mdate();
X
Xchar sender[1024] = "/bin/mail";
Xchar editor[1024] = "/usr/ucb/vi";
Xchar edforward[256] = "No";
Xchar alicount[256] = "20";
X
Xstatic char *_month_[] = {
X	"January",
X	"February",
X	"March",
X	"April",
X	"May",
X	"June",
X	"July",
X	"August",
X	"September",
X	"October",
X	"November",
X	"December",
X};
X
Xstatic char *_weekday_[] = {
X	"Sunday",
X	"Monday",
X	"Tuesday",
X	"Wednesday",
X	"Thursday",
X	"Friday",
X	"Saturday",
X};
X
Xsendmail(fd, to, cc, subj, bcc)
XFILE *fd;
Xchar *to, *cc, *subj, *bcc; {
X	char *cp;
X	FILE *rmail;
X	char name[512];
X	static char toline[512], ccline[512];
X	struct passwd *curuser;
X	
X	if (fd == (FILE *) 0)
X		return 0;
X	if ((curuser = getpwnam(getlogin())) == (struct passwd *) 0) {
X		puts("Who are you, anyway?  I can't send mail from nobody!");
X		return -1;
X	}
X	strcpy(name, curuser->pw_gecos);
X	if ((cp = strchr(name, ',')) != (char *) 0)
X		*cp = '\0';
X	strcpy(toline, to);
X	strcpy(ccline, cc);
X	while (*to == ' ' || *to == '\t')
X		to++;
X	if (*to == '\0') {
X		puts("Empty To: list.");
X		return 0;
X	}
X	sendlist(to, name, toline, ccline, subj, fd, 0);
X	sendlist(cc, name, toline, ccline, subj, fd, 0);
X	sendlist(bcc, name, toline, ccline, subj, fd, 0);
X	return 1;
X}
X
Xsendlist(list, from, toline, ccline, subj, fd, acount)
Xchar *list, *from, *toline, *ccline, *subj;
XFILE *fd; {
X	char *cp;
X	char aexp[1024];
X
X	if (atoi(alicount) < 0)
X		strcpy(alicount, "20");
X	if (acount > atoi(alicount)) {
X		puts("Alias loop.");
X		return -1;
X	}
X	while (*list != '\0') {
X		while (*list == ' ' || *list == '\t')
X			list++;
X		for (cp = list; *cp != ',' && *cp != '\0' && *cp != ' ' && *cp != '\t'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		if (*list == '\0')
X			break;
X		if (xalias(list, aexp))
X			return sendlist(aexp, from, toline, ccline, subj, fd, acount + 1);
X		smtp(from, list, toline, ccline, subj, fd);
X		list = cp;
X	}
X	return 1;
X}
X
Xsmtp(from, to, toline, ccline, subjline, fp)
Xchar *from, *to, *toline, *ccline, *subjline;
XFILE *fp; {
X	char cmd[256];
X	char ch;
X	FILE *rmail;
X
X	sprintf(cmd, "exec %s %s", sender, to);
X	if ((rmail = epopen(cmd, "w")) == (FILE *) 0) {
X		puts("Can't run mailer.");
X		return 0;
X	}
X	fprintf(rmail, "Date: %s\nFrom: %s  <%s>\nSubject: %s\nTo: %s\n%s%s\n", mdate(), from, getlogin(), subjline, toline, (ccline[0] == '\0'? "": "Cc: "), ccline, (ccline[0] == '\0'? "": "\n"));
X	rewind(fp);
X	while ((ch = getc(fp)) != EOF)
X		putc(ch, rmail);
X	if (pclose(rmail) != 0)
X		printf("Mailer failed to %s.\n", to);
X}
X
Xreply(cmdp)
Xchar *cmdp; {
X	char *cp;
X	char curbuf[256], to[256], cc[256], subj[256], bcc[256], tmpf[80], mline[5120];
X	FILE *fp, *mfp;
X
X	while (*cmdp == ' ' || *cmdp == '\t')
X		cmdp++;
X	if (*cmdp != '\0') {
X		for (cp = cmdp; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		while (*cp == ' ' || *cp == '\t')
X			cp++;
X		if (*cp != '\0') {
X			puts("Wrong number of arguments.  Usage:  reply [message-number]");
X			return -1;
X		}
X		if (!ismsg(cmdp)) {
X			puts("No such message.");
X			return -1;
X		}
X		if (isdeleted(cmdp)) {
X			sprintf(curbuf, ".%s", cmdp);
X			cmdp = curbuf;
X		}
X	}
X	else {
X		sprintf(curbuf, "%d", msg);
X		if (isdeleted(curbuf))
X			sprintf(curbuf, ".%d", msg);
X		cmdp = curbuf;
X	}
X	bcc[0] = '\0';
X	gettcs(cmdp, to, cc, subj);
X	edenv(to, cc, subj, bcc);
X	sprintf(tmpf, "/tmp/ms%05dr", getpid());
X	if ((fp = efopen(tmpf, "w")) == (FILE *) 0) {
X		puts("Can't open message temp file.");
X		return -1;
X	}
X	if ((mfp = efopen(mlocation(cmdp), "r")) == (FILE *) 0) {
X		perror(mlocation(cmdp));
X		puts("Can't open original message.");
X		fputs("> Couldn't copy the original message.\n", fp);
X		fclose(fp);
X	}
X	else {
X		fputs("+---------------\n", fp);
X		while (fgets(mline, sizeof mline, mfp) != (char *) 0) {
X			fputs("| ", fp);
X			fputs(mline, fp);
X		}
X		fputs("+---------------\n\n\n", fp);
X		fclose(fp);
X		fclose(mfp);
X	}
X	enter(tmpf);
X	if (!suresend()) {
X		unlink(tmpf);
X		puts("Reply aborted.");
X		return 1;
X	}
X	puts("Please check the envelope below and make any necessary changes.");
X	if (!edenv(to, cc, subj, bcc))
X		return -1;
X	if ((fp = efopen(tmpf, "r")) == (FILE *) 0) {
X		puts("Can't open reply file.");
X		return -1;
X	}
X	if (!sendmail(fp, to, cc, subj, bcc)) {
X		fclose(fp);
X		dead(tmpf);
X	}
X	fclose(fp);
X	unlink(tmpf);
X	return 1;
X}
X
Xmailto(cmdp)
Xchar *cmdp; {
X	char *cp;
X	char curbuf[256], to[256], cc[256], subj[256], bcc[256], tmpf[80];
X	FILE *fp;
X
X	while (*cmdp == ' ' || *cmdp == '\t')
X		cmdp++;
X	if (*cmdp != '\0') {
X		for (cp = cmdp; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		while (*cp == ' ' || *cp == '\t')
X			cp++;
X		if (*cp != '\0') {
X			puts("Wrong number of arguments.  Usage:  mail [user-name]");
X			return -1;
X		}
X	}
X	bcc[0] = '\0';
X	strcpy(to, cmdp);
X	subj[0] = '\0';
X	cc[0] = '\0';
X	edenv(to, cc, subj, bcc);
X	sprintf(tmpf, "/tmp/ms%05ds", getpid());
X	if ((fp = efopen(tmpf, "w")) == (FILE *) 0) {
X		puts("Can't open message temp file.");
X		return -1;
X	}
X	fclose(fp);
X	enter(tmpf);
X	if (!suresend()) {
X		unlink(tmpf);
X		puts("Mail aborted.");
X		return 1;
X	}
X	puts("Please check the envelope below and make any necessary changes.");
X	if (!edenv(to, cc, subj, bcc))
X		return -1;
X	if ((fp = efopen(tmpf, "r")) == (FILE *) 0) {
X		puts("Can't open message temp file.");
X		return -1;
X	}
X	if (!sendmail(fp, to, cc, subj, bcc)) {
X		fclose(fp);
X		dead(tmpf);
X	}
X	fclose(fp);
X	unlink(tmpf);
X	return 1;
X}
X
Xforward(cmdp)
Xchar *cmdp; {
X	char *cp;
X	char curbuf[256], to[256], cc[256], subj[256], bcc[256], tmpf[80];
X	static char mline[5120];
X	FILE *fp, *mfp;
X
X	while (*cmdp == ' ' || *cmdp == '\t')
X		cmdp++;
X	if (*cmdp == '\0') {
X		puts("Wrong number of arguments.  Usage:  forward user-name [message-number]");
X		return -1;
X	}
X	for (cp = cmdp; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++)
X		;
X	if (*cp != '\0')
X		*cp++ = '\0';
X	strcpy(to, cmdp);
X	cmdp = cp;
X	if (*cmdp != '\0') {
X		for (cp = cmdp; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		while (*cp == ' ' || *cp == '\t')
X			cp++;
X		if (*cp != '\0') {
X			puts("Wrong number of arguments.  Usage:  forward user-name [message-number]");
X			return -1;
X		}
X		if (!ismsg(cmdp)) {
X			puts("No such message.");
X			return -1;
X		}
X		if (isdeleted(cmdp)) {
X			sprintf(curbuf, ".%s", cmdp);
X			cmdp = curbuf;
X		}
X	}
X	else {
X		sprintf(curbuf, "%d", msg);
X		if (isdeleted(curbuf))
X			sprintf(curbuf, ".%d", msg);
X		cmdp = curbuf;
X	}
X	gettcs(cmdp, (char *) 0, (char *) 0, subj);
X	if (subj[0] == '\0')
X		sprintf(subj, "Mail forwarded from \"%s\"", getlogin());
X	bcc[0] = '\0';
X	cc[0] = '\0';
X	edenv(to, cc, subj, bcc);
X	sprintf(tmpf, "/tmp/ms%05df", getpid());
X	if ((fp = efopen(tmpf, "w")) == (FILE *) 0) {
X		puts("Can't open message temp file.");
X		return -1;
X	}
X	if ((mfp = efopen(mlocation(cmdp), "r")) == (FILE *) 0) {
X		perror(mlocation(cmdp));
X		puts("Can't open original message.");
X		fclose(fp);
X		unlink(tmpf);
X		return -1;
X	}
X	else {
X		while (fgets(mline, sizeof mline, mfp) != (char *) 0)
X			fputs(mline, fp);
X		fclose(fp);
X		fclose(mfp);
X	}
X	if ((edforward[0] == 'Y' || edforward[0] == 'y' || edforward[0] == 'T' || edforward[0] == 't') && isatty(0))
X		enter(tmpf);
X	if (!suresend()) {
X		unlink(tmpf);
X		puts("Forward aborted.");
X		return 1;
X	}
X	if (edforward[0] == 'Y' || edforward[0] == 'y' || edforward[0] == 'T' || edforward[0] == 't')
X		edenv(to, cc, subj, bcc);
X	if ((fp = efopen(tmpf, "r")) == (FILE *) 0) {
X		puts("Can't open message temp file.");
X		return -1;
X	}
X	if (!sendmail(fp, to, cc, subj, bcc)) {
X		fclose(fp);
X		dead(tmpf);
X	}
X	fclose(fp);
X	unlink(tmpf);
X	return 1;
X}
X
Xenter(file)
Xchar *file; {
X	int (*intr)(), (*quit)();
X	int pid, status;
X
X	if (!isatty(0)) {
X		FILE *fp;
X		char iline[1024];
X		
X		if ((fp = efopen(file, "w")) == (FILE *) 0) {
X			printf("Can't open file \"%s\".\n", file);
X			return;
X		}
X		while (gets(iline) != (char *) 0)
X			fprintf(fp, "%s\n", iline);
X		fclose(fp);
X		return;
X	}
X	switch (pid = fork()) {
X		case -1:
X			puts("Couldn't fork.");
X			break;
X		case 0:
X			setgid(getgid());
X			setuid(getuid());
X			execlp(editor, editor, file, (char *) 0);
X			perror(editor);
X			exit(0);
X		default:
X			intr = signal(SIGINT, SIG_IGN);
X			quit = signal(SIGQUIT, SIG_IGN);
X			while (wait(&status) != pid)
X				;
X			signal(SIGINT, intr);
X			signal(SIGQUIT, quit);
X			if (status != 0)
X				puts("Editor failure detected.");
X	}
X}
X
Xdead(file)
Xchar *file; {
X/*
X * Usually, the real mailer (rmail) will deal with dead.letter files.  If
X * yours doesn't, change this function.
X */
X}
X
Xedenv(to, cc, subj, bcc)
Xchar *to, *subj, *cc, *bcc; {
X	printf("To: ");
X	edstr(to);
X	printf("Subject: ");
X	edstr(subj);
X	printf("Cc: ");
X	edstr(cc);
X	printf("Bcc: ");
X	edstr(bcc);
X}
X
Xedstr(str)
Xchar *str; {
X	char ch;
X	char *sp;
X	struct TERMIO ottyp, nttyp;
X	int (*intr)(), (*quit)();
X	
X	if (ioctl(0, TIO_GET, &ottyp) < 0)
X		return;
X	intr = signal(SIGINT, SIG_IGN);
X	quit = signal(SIGQUIT, SIG_IGN);
X	nttyp = ottyp;
X#ifdef USG
X	nttyp.c_lflag &= ~(ICANON|ECHO|ECHOE);
X	nttyp.c_cc[VMIN] = 1;
X	nttyp.c_cc[VTIME] = 0;
X#else  USG
X	nttyp.sg_flags |= CBREAK;
X	nttyp.sg_flags &= ~ECHO;
X#endif USG
X	ioctl(0, TIO_SET, &nttyp);
X	for (sp = str; *sp != '\0'; sp++)
X		putchar(*sp);
X	for (;;) {
X		if ((ch = (getchar() & 0x7f)) == '\n')
X			break;
X		if (ch == nttyp.TIO_ERASE) {
X			if (sp == str) {
X				putchar('\7');
X				continue;
X			}
X			putchar('\b');
X			putchar(' ');
X			putchar('\b');
X			sp--;
X			continue;
X		}
X		if (ch < ' ') {
X			putchar('\7');
X			continue;
X		}
X		putchar(ch);
X		*sp++ = ch;
X	}
X	ioctl(0, TIO_SET, &ottyp);
X	putchar('\n');
X	*sp = '\0';
X	signal(SIGINT, intr);
X	signal(SIGQUIT, quit);
X}
X
Xgettcs(msg, to, cc, subj)
Xchar *msg, *to, *cc, *subj; {
X	FILE *fp;
X	char mline[5120];
X	char *cp;
X	
X	if ((fp = efopen(mlocation(msg), "r")) == (FILE *) 0) {
X		puts("Can't read envelope of message.");
X		return;
X	}
X	if (to != (char *) 0)
X		to[0] = '\0';
X	if (cc != (char *) 0)
X		cc[0] = '\0';
X	if (subj != (char *) 0)
X		subj[0] = '\0';
X	while (fgets(mline, sizeof mline, fp) != (char *) 0) {
X		if (mline[0] == '\n' || mline[0] == ' ')
X			break;
X		if ((cp = strrchr(mline, '\n')) != (char *) 0)
X			*cp = '\0';
X		if (to != (char *) 0 && strncmp(mline, "Path: ", 6) == 0) {
X			if (to[0] != '\0')
X				strcat(to, ", ");
X			strcat(to, &mline[6]);
X			continue;
X		}
X		if (to != (char *) 0 && strncmp(mline, "To: ", 4) == 0) {
X			if (to[0] != '\0')
X				strcat(to, ", ");
X			strcat(to, &mline[4]);
X			continue;
X		}
X		if (subj != (char *) 0 && strncmp(mline, "Subject: ", 9) == 0) {
X			strcpy(subj, &mline[9]);
X			continue;
X		}
X		if (cc != (char *) 0 && strncmp(mline, "Cc: ", 4) == 0) {
X			if (cc[0] != '\0')
X				strcat(cc, ", ");
X			strcat(cc, &mline[4]);
X			continue;
X		}
X	}
X	fclose(fp);
X}
X
Xchar *mdate() {
X	long now;
X	struct tm *today;
X	static char dbuf[80];
X	int hr;
X	char ap;
X#ifdef USG
X	extern int daylight;
X	extern char *tzname[];
X#endif USG
X	
X	time(&now);
X	today = localtime(&now);
X	if (today->tm_hour < 12) {
X		ap = 'A';
X		hr = today->tm_hour;
X	}
X	else {
X		ap = 'P';
X		hr = today->tm_hour - 12;
X	}
X	if (hr == 0)
X		hr = 12;
X	sprintf(dbuf, "%s, %s %d, 19%d at %d:%02d %c.M.", _weekday_[today->tm_wday], _month_[today->tm_mon], today->tm_mday, today->tm_year, hr, today->tm_min, ap);
X#ifdef USG
X	tzset();
X	strcat(dbuf, " ");
X	strcat(dbuf, tzname[daylight]);
X#endif USG
X	return dbuf;
X}
X
Xsuresend() {
X	char ch;
X	struct TERMIO ottyp, nttyp;
X	int (*intr)(), (*quit)();
X	
X	if (ioctl(0, TIO_GET, &ottyp) < 0)
X		return 1;
X	intr = signal(SIGINT, SIG_IGN);
X	quit = signal(SIGQUIT, SIG_IGN);
X	nttyp = ottyp;
X#ifdef USG
X	nttyp.c_lflag &= ~(ICANON|ECHO|ECHOE);
X	nttyp.c_cc[VMIN] = 1;
X	nttyp.c_cc[VTIME] = 0;
X#else  USG
X	nttyp.sg_flags |= CBREAK;
X	nttyp.sg_flags &= ~ECHO;
X#endif USG
X	ioctl(0, TIO_SET, &nttyp);
X	printf("Are you sure you want to send this (Y)? ");
X	while ((ch = getchar()) == EOF || (ch < ' ' && ch != '\r' && ch != '\n' && ch != '\t') || ch > '~')
X		;
X	if (ch == 'N' || ch == 'n' || ch == '\t')
X		puts("No");
X	else
X		puts("Yes");
X	ioctl(0, TIO_SET, &ottyp);
X	signal(SIGINT, intr);
X	signal(SIGQUIT, quit);
X	return ch != 'N' && ch != 'n' && ch != '\t';
X}
X
Xgetcont() {
X	struct TERMIO ottyp, nttyp;
X	int (*intr)(), (*quit)();
X	
X	intr = signal(SIGINT, SIG_IGN);
X	quit = signal(SIGQUIT, SIG_IGN);
X	if (ioctl(0, TIO_GET, &ottyp) < 0)
X		return;
X	nttyp = ottyp;
X#ifdef USG
X	nttyp.c_lflag &= ~(ICANON|ECHO|ECHOE);
X	nttyp.c_cc[VMIN] = 1;
X	nttyp.c_cc[VTIME] = 0;
X#else  USG
X	nttyp.sg_flags |= CBREAK;
X	nttyp.sg_flags &= ~ECHO;
X#endif USG
X	ioctl(0, TIO_SET, &nttyp);
X	printf("--- Press any key to continue ---");
X	getchar();
X	printf("\r                                 \r");
X	ioctl(0, TIO_SET, &ottyp);
X	signal(SIGINT, intr);
X	signal(SIGQUIT, quit);
X}
--EOF:imssend.c--
fi

if test -r "imsset.c"; then
	echo "File imsset.c exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="imsset.c"
	esac
else
	newname="imsset.c"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:imsset.c--' > "$newname"
X#include "ims.h"
X
Xstruct var {
X	char *v_name;
X	char *v_val;
X} var[] = {
X	"folder",			folder,
X	"cabinet",			cabinet,
X	"prompt",			prompt,
X	"pager",			pager,
X	"system-mailbox",		sysmbox,
X	"mail-sending-command",		sender,
X	"mailbox",			mailbox,
X	"editor",			editor,
X	"save-folder",			savefolder,
X	"print-command",		printcmd,
X	"type-next-automatically",	autonext,
X	"read-new-mail-automatically",	autoread,
X	"ask-before-append",		askappend,
X	"lines",			lines,
X	"edit-forwarded-mail",		edforward,
X	"alias-recursion-level",	alicount,
X	(char *) 0,			(char *) 0,
X};
X
Xreadvars() {
X	char vfile[256];
X	char *cp;
X	
X	varead(IMSINIT);
X	if ((cp = getenv("IMSINIT")) != (char *) 0)
X		strcpy(vfile, cp);
X	else {
X		if ((cp = getenv("HOME")) == (char *) 0)
X			cp = "/usr/guest";
X		sprintf(vfile, "%s/.imsinit", cp);
X	}
X	varead(vfile);
X}
X
Xvaread(vfile)
Xchar *vfile; {
X	char vline[512], v[80], val[128];
X	char *cp, *dp, *ip;
X	FILE *fp;
X	int lineno, canon;
X
X	if ((fp = efopen(vfile, "r")) == (FILE *) 0)
X		return;
X	lineno = 0;
X	while (fgets(vline, sizeof vline, fp) != (char *) 0) {
X		lineno++;
X		if ((cp = strchr(vline, '\n')) != (char *) 0)
X			*cp = '\0';
X		if ((cp = strchr(vline, '#')) != (char *) 0)
X			*cp = '\0';
X		for (cp = vline; *cp == ' ' || *cp == '\t'; cp++)
X			;
X		if (*cp == '\0')
X			continue;
X		for (dp = v; *cp != '\0' && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01235456789_-", *cp) != (char *) 0; cp++)
X			*dp++ = *cp;
X		*dp = '\0';
X		if (v[0] == '\0') {
X			printf("Error in \"%s\", line %d:  Missing or invalid variable name\n", vfile, lineno);
X			continue;
X		}
X		while (*cp == ' ' || *cp == '\t')
X			cp++;
X		if (*cp != '=') {
X			printf("Error in \"%s\", line %d:  Missing ``=''\n", vfile, lineno);
X			continue;
X		}
X		cp++;
X		while (*cp == ' ' || *cp == '\t')
X			cp++;
X		canon = 0;
X		if (*cp == '"') {
X			canon = 1;
X			cp++;
X		}
X		for (dp = val; *cp != '\0' && (canon? *cp != '"': *cp != ' ' && *cp != '\t'); cp++) {
X			if (*cp == '\\' && *(cp + 1) != '\0')
X				*dp++ = *++cp;
X			else if (*cp != '\\')
X				*dp++ = *cp;
X			else {
X				*dp++ = '\n';
X				if (fgets(vline, sizeof vline, fp) == (char *) 0) {
X					cp++;
X					printf("Unexpected end of file in \"%s\", line %d\n", vfile, lineno + 1);
X					break;
X				}
X				lineno++;
X				if ((ip = strchr(vline, '\n')) != (char *) 0)
X					*ip = '\0';
X				if ((ip = strchr(vline, '#')) != (char *) 0)
X					*ip = '\0';
X				cp = vline;
X				*dp++ = *cp;
X			}
X		}
X		if (canon) {
X			if (*cp == '\0') {
X				printf("Error in \"%s\", line %d:  No closing quote\n", vfile, lineno);
X				continue;
X			}
X			cp++;
X		}
X		*dp = '\0';
X		while (*cp == ' ' || *cp == '\t')
X			cp++;
X		if (*cp != '\0') {
X			printf("Error in \"%s\", line %d:  Text after set command\n", vfile, lineno);
X			continue;
X		}
X		setvar(v, val);
X	}
X	fclose(fp);
X}
X
Xsetvar(v, val)
Xchar *v, *val; {
X	struct var *vp;
X	
X	for (vp = var; vp->v_name != (char *) 0; vp++)
X		if (strcmp(vp->v_name, v) == 0)
X			break;
X	if (vp->v_name == (char *) 0) {
X		printf("Unknown variable: %s\n", v);
X		return -1;
X	}
X	strcpy(vp->v_val, val);
X	return 0;
X}
X
Xvarops(cmdp)
Xchar *cmdp; {
X	char *cp, *dp;
X	char v[80], val[128];
X	int canon;
X	
X	while (*cmdp == ' ' || *cmdp == '\t')
X		;
X	if (*cmdp == '\0') {
X		listvar("");
X		return 1;
X	}
X	for (dp = v, cp = cmdp; *cp != '\0' && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01235456789_-", *cp) != (char *) 0; cp++)
X		*dp++ = *cp;
X	*dp = '\0';
X	while (*cp == ' ' || *cp == '\t')
X		cp++;
X	if (*cp == '\0') {
X		listvar(v);
X		return 1;
X	}
X	if (*cp != '=') {
X		puts("Invalid assignment statement syntax.  Usage:  set [variable [= value]]");
X		return -1;
X	}
X	cp++;
X	while (*cp == ' ' || *cp == '\t')
X		cp++;
X	canon = 0;
X	if (*cp == '"') {
X		canon = 1;
X		cp++;
X	}
X	for (dp = val; *cp != '\0' && (canon? *cp != '"': *cp != ' ' && *cp != '\t'); cp++) {
X		if (*cp == '\\' && *(cp + 1) != '\0')
X			*dp++ = *++cp;
X		else if (*cp != '\\')
X			*dp++ = *cp;
X		else {
X			puts("Multiline variables invalid on command line.");
X			return -1;
X		}
X	}
X	if (canon) {
X		if (*cp == '\0') {
X			printf("Missing closing quote.");
X			return -1;
X		}
X		cp++;
X	}
X	*dp = '\0';
X	while (*cp == ' ' || *cp == '\t')
X		cp++;
X	if (*cp != '\0') {
X		printf("Extra text after assignment.");
X		return -1;
X	}
X	setvar(v, val);
X	return 1;
X}
X
Xlistvar(v)
Xchar *v; {
X	struct var *vp;
X	int cnt;
X	
X	cnt = 0;
X	for (vp = var; vp->v_name != (char *) 0; vp++)
X		if (v[0] == '\0' || strcmp(vp->v_name, v) == 0) {
X			printf("%s => \"%s\"\n", vp->v_name, vp->v_val);
X			cnt++;
X		}
X	if (cnt == 0)
X		if (v[0] == '\0')
X			puts("There are no variables in this version of IMS.");
X		else
X			printf("Unknown variable: \"%s\".\n", v);
X}
--EOF:imsset.c--
fi

if test -r "imsalias.c"; then
	echo "File imsalias.c exists.  Enter new name or RETURN to skip.  (. to replace.)"
	read newname
	case "$newname" in
	".")	newname="imsalias.c"
	esac
else
	newname="imsalias.c"
fi
if test -z "$newname"; then
	echo "shx - $newname (skipped)"
else
	case "$newname" in
	"$sfile")
		echo "shx - $sfile (as $newname)"
		;;
	*)	echo "shx - $newname"
	esac
	sed 's/^X//' << '--EOF:imsalias.c--' > "$newname"
X#include "ims.h"
X
Xstruct alias {
X	char *a_name;
X	char *a_value;
X	struct alias *a_next;
X} *alias = (struct alias *) 0;
X
Xreadalias() {
X	char vfile[256];
X	char *cp;
X	
X	aliread(IMSALIAS);
X	if ((cp = getenv("IMSALIAS")) != (char *) 0)
X		strcpy(vfile, cp);
X	else {
X		if ((cp = getenv("HOME")) == (char *) 0)
X			cp = "/usr/guest";
X		sprintf(vfile, "%s/.imsalias", cp);
X	}
X	aliread(vfile);
X}
X
Xaliread(vfile)
Xchar *vfile; {
X	char vline[1024], v[80], val[1024];
X	char *cp, *dp, *ip;
X	FILE *fp;
X	int lineno;
X	
X	if ((fp = efopen(vfile, "r")) == (FILE *) 0)
X		return;
X	lineno = 0;
X	while (fgets(vline, sizeof vline, fp) != (char *) 0) {
X		lineno++;
X		if ((cp = strchr(vline, '\n')) != (char *) 0)
X			*cp = '\0';
X		if ((cp = strchr(vline, '#')) != (char *) 0)
X			*cp = '\0';
X		for (cp = vline; *cp == ' ' || *cp == '\t'; cp++)
X			;
X		if (*cp == '\0')
X			continue;
X		for (dp = v; *cp != '\0' && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01235456789_-", *cp) != (char *) 0; cp++)
X			*dp++ = *cp;
X		*dp = '\0';
X		if (v[0] == '\0') {
X			printf("Error in \"%s\", line %d:  Missing or invalid alias name\n", vfile, lineno);
X			continue;
X		}
X		while (*cp == ' ' || *cp == '\t')
X			cp++;
X		if (*cp != ':') {
X			printf("Error in \"%s\", line %d:  Missing ``:''\n", vfile, lineno);
X			continue;
X		}
X		cp++;
X		while (*cp == ' ' || *cp == '\t')
X			cp++;
X		for (dp = val; *cp != '\0'; cp++) {
X			if (*cp == '\\' && *(cp + 1) != '\0')
X				*dp++ = *++cp;
X			else if (*cp != '\\')
X				*dp++ = *cp;
X			else {
X				*dp++ = '\n';
X				if (fgets(vline, sizeof vline, fp) == (char *) 0) {
X					cp++;
X					printf("Unexpected end of file in \"%s\", line %d\n", vfile, lineno + 1);
X					break;
X				}
X				lineno++;
X				if ((ip = strchr(vline, '\n')) != (char *) 0)
X					*ip = '\0';
X				if ((ip = strchr(vline, '#')) != (char *) 0)
X					*ip = '\0';
X				cp = vline;
X				*dp++ = *cp;
X			}
X		}
X		setalias(v, val);
X	}
X	fclose(fp);
X}
X
Xsetalias(ali, value)
Xchar *ali, *value; {
X	struct alias *ap, *newa;
X	
X	for (ap = alias; ap->a_name != (char *) 0; ap = ap->a_next)
X		if (strcmp(ap->a_name, ali) == 0)
X			break;
X	if (ap->a_name == (char *) 0) {
X		if (value == (char *) 0 || value[0] == '\0') {
X			printf("No such alias: %s.\n", ali);
X			return -1;
X		}
X		if ((newa = (struct alias *) calloc(1, sizeof *newa)) == (struct alias *) 0) {
X			fprintf(stderr, "No room for new alias: %s.\n", ali);
X			return -1;
X		}
X		if ((newa->a_name = calloc(strlen(ali) + 1, sizeof *newa->a_name)) == (char *) 0) {
X			fprintf(stderr, "No room for new alias name: %s.\n", ali);
X			free((char *) newa);
X			return -1;
X		}
X		if ((newa->a_value = calloc(strlen(value) + 1, sizeof *newa->a_value)) == (char *) 0) {
X			fprintf(stderr, "No room for new alias value: %s.\n", ali);
X			free(newa->a_name);
X			free((char *) newa);
X			return -1;
X		}
X		strcpy(newa->a_name, ali);
X		strcpy(newa->a_value, value);
X		newa->a_next = alias;
X		alias = newa;
X		return 2;
X	}
X	free(ap->a_value);
X	if (value == (char *) 0 || value[0] == '\0') {
X		free(ap->a_name);
X		for (newa = alias; newa->a_next != (struct alias *) 0; newa = ap->a_next)
X			if (newa->a_next == ap)
X				break;
X		if (newa == (struct alias *) 0)
X			alias = ap->a_next;
X		else
X			newa->a_next = ap->a_next;
X		free((char *) ap);
X		return 0;
X	}
X	if ((ap->a_value = calloc(strlen(value), sizeof *ap->a_value)) == (char *) 0) {
X		fprintf(stderr, "No space for new value of alias: %s.  Alias deleted.\n", ali);
X		for (newa = alias; newa->a_next != (struct alias *) 0; newa = newa->a_next)
X			if (newa->a_next == ap)
X				break;
X		if (newa == (struct alias *) 0)
X			alias = ap->a_next;
X		else
X			newa->a_next = ap->a_next;
X		free(ap->a_name);
X		free((char *) ap);
X		return -1;
X	}
X	strcpy(ap->a_value, value);
X	return 1;
X}
X
Xxalias(to, buf)
Xchar *to, *buf; {
X	struct alias *ap;
X	
X	for (ap = alias; ap != (struct alias *) 0; ap = ap->a_next)
X		if (strcmp(ap->a_name, to) == 0)
X			break;
X	if (ap == (struct alias *) 0) {
X		strcpy(buf, to);
X		return 0;
X	}
X	strcpy(buf, ap->a_value);
X	return 1;
X}
X
Xunalias(cmdp)
Xchar *cmdp; {
X	char *cp;
X	int didalias;
X	
X	didalias = 0;
X	
X	while (*cmdp != '\0') {
X		while (*cmdp == ' ' || *cmdp == '\t')
X			cmdp++;
X		if (*cmdp == '\0')
X			break;
X		for (cp = cmdp; *cp != ',' && *cp != ' ' && *cp != '\t'; cp++)
X			;
X		if (*cp != '\0')
X			*cp++ = '\0';
X		didalias++;
X		setalias(cmdp, "");
X		cmdp = cp;
X	}
X	if (didalias == 0) {
X		puts("Usage:  unalias alias-list\n");
X		return -1;
X	}
X	return 1;
X}
X
Xaliasops(cmdp)
Xchar *cmdp; {
X	char *cp, *dp;
X	char aexp[1024];
X	
X	while (*cmdp == ' ' || *cmdp == '\t')
X		cmdp++;
X	if (*cmdp == '\0')
X		return listalias();
X	for (cp = cmdp; *cp != '\0' && *cp != '\t' && *cp != ' '; cp++)
X		;
X	if (*cp != '\0')
X		*cp++ = '\0';
X	for (dp = cmdp; *dp != '\0' && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01235456789_-", *dp) != (char *) 0; dp++)
X		;
X	if (*dp != '\0') {
X		printf("Illegal alias name: %s.\n", cmdp);
X		return -1;
X	}
X	while (*cp == ' ' || *cp == '\t')
X		cp++;
X	if (*cp == '\0')
X		if (xalias(cmdp, aexp)) {
X			printf("Alias %s: %s\n", cmdp, aexp);
X			return 1;
X		}
X		else {
X			printf("Unknown alias: %s.\n", cmdp);
X			return -1;
X		}
X	if (setalias(cmdp, cp) < 0)
X		return -1;
X	return 1;
X}
X
Xlistalias() {
X	struct alias *ap;
X	int nalias;
X	
X	nalias = 0;
X	for (ap = alias; ap != (struct alias *) 0; ap = ap->a_next, nalias++)
X		printf("  %s: %s\n", ap->a_name, ap->a_value);
X	if (nalias != 0)
X		return 1;
X	puts("No aliases defined.");
X	return -1;
X}
--EOF:imsalias.c--
fi
exit 0
-- 
  ---------------- ****	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 at csnet-relay
-------------------------------------------------------------------------------
			Space -- The Final Frontier



More information about the Comp.sources.unix mailing list