xref: /csrg-svn/usr.bin/msgs/msgs.c (revision 69023)
141441Sbostic /*-
262133Sbostic  * Copyright (c) 1980, 1993
362133Sbostic  *	The Regents of the University of California.  All rights reserved.
441441Sbostic  *
541441Sbostic  * %sccs.include.redist.c%
621983Sdist  */
721983Sdist 
86856Srrh #ifndef lint
962133Sbostic static char copyright[] =
1062133Sbostic "@(#) Copyright (c) 1980, 1993\n\
1162133Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1241441Sbostic #endif /* not lint */
1321983Sdist 
1421983Sdist #ifndef lint
15*69023Sbostic static char sccsid[] = "@(#)msgs.c	8.2 (Berkeley) 04/28/95";
1641441Sbostic #endif /* not lint */
1721983Sdist 
186856Srrh /*
196856Srrh  * msgs - a user bulletin board program
206856Srrh  *
216856Srrh  * usage:
226856Srrh  *	msgs [fhlopq] [[-]number]	to read messages
236856Srrh  *	msgs -s				to place messages
246856Srrh  *	msgs -c [-days]			to clean up the bulletin board
256856Srrh  *
266856Srrh  * prompt commands are:
276856Srrh  *	y	print message
286856Srrh  *	n	flush message, go to next message
296856Srrh  *	q	flush message, quit
306856Srrh  *	p	print message, turn on 'pipe thru more' mode
316856Srrh  *	P	print message, turn off 'pipe thru more' mode
326856Srrh  *	-	reprint last message
336856Srrh  *	s[-][<num>] [<filename>]	save message
346856Srrh  *	m[-][<num>]	mail with message in temp mbox
356856Srrh  *	x	exit without flushing this message
3616335Sralph  *	<num>	print message number <num>
376856Srrh  */
386856Srrh 
396856Srrh #define V7		/* will look for TERM in the environment */
406856Srrh #define OBJECT		/* will object to messages without Subjects */
416856Srrh /* #define REJECT	/* will reject messages without Subjects
426856Srrh 			   (OBJECT must be defined also) */
436856Srrh /* #define UNBUFFERED	/* use unbuffered output */
446856Srrh 
456858Srrh #include <sys/param.h>
4613616Ssam #include <sys/dir.h>
47*69023Sbostic #include <sys/ioctl.h>
486856Srrh #include <sys/stat.h>
496856Srrh #include <ctype.h>
5046257Storek #include <errno.h>
516856Srrh #include <pwd.h>
5246257Storek #include <setjmp.h>
5346257Storek #include <signal.h>
5437893Sbostic #include <stdio.h>
5546257Storek #include <stdlib.h>
5646257Storek #include <string.h>
57*69023Sbostic #include <termios.h>
5846257Storek #include <time.h>
5960134Sbostic #include <unistd.h>
6037893Sbostic #include "pathnames.h"
616856Srrh 
626856Srrh #define CMODE	0666		/* bounds file creation mode */
636856Srrh #define NO	0
646856Srrh #define YES	1
656856Srrh #define SUPERUSER	0	/* superuser uid */
666856Srrh #define DAEMON		1	/* daemon uid */
676856Srrh #define NLINES	24		/* default number of lines/crt screen */
686856Srrh #define NDAYS	21		/* default keep time for messages */
696856Srrh #define DAYS	*24*60*60	/* seconds/day */
706856Srrh #define MSGSRC	".msgsrc"	/* user's rc file */
716856Srrh #define BOUNDS	"bounds"	/* message bounds file */
726856Srrh #define NEXT	"Next message? [yq]"
736856Srrh #define MORE	"More? [ynq]"
746856Srrh #define NOMORE	"(No more) [q] ?"
756856Srrh 
766856Srrh typedef	char	bool;
776856Srrh 
7846257Storek FILE	*msgsrc;
796856Srrh FILE	*newmsg;
806856Srrh char	*sep = "-";
816856Srrh char	inbuf[BUFSIZ];
826856Srrh char	fname[128];
836856Srrh char	cmdbuf[128];
846856Srrh char	subj[128];
856856Srrh char	from[128];
866856Srrh char	date[128];
876856Srrh char	*ptr;
886856Srrh char	*in;
896856Srrh bool	local;
906856Srrh bool	ruptible;
916856Srrh bool	totty;
926856Srrh bool	seenfrom;
936856Srrh bool	seensubj;
946856Srrh bool	blankline;
956856Srrh bool	printing = NO;
966856Srrh bool	mailing = NO;
976856Srrh bool	quitit = NO;
986856Srrh bool	sending = NO;
996856Srrh bool	intrpflg = NO;
1006856Srrh int	uid;
1016856Srrh int	msg;
1026856Srrh int	prevmsg;
1036856Srrh int	lct;
1046856Srrh int	nlines;
10527026Sbloom int	Lpp = 0;
1066856Srrh time_t	t;
1076856Srrh time_t	keep;
1086856Srrh 
10946160Sbostic char	*mktemp();
1106856Srrh char	*nxtfld();
11146160Sbostic void	onintr();
11246160Sbostic void	onsusp();
1136856Srrh 
1146856Srrh /* option initialization */
1156856Srrh bool	hdrs = NO;
1166856Srrh bool	qopt = NO;
1176856Srrh bool	hush = NO;
11846160Sbostic bool	send_msg = NO;
1196856Srrh bool	locomode = NO;
12046160Sbostic bool	use_pager = NO;
1216856Srrh bool	clean = NO;
1226856Srrh bool	lastcmd = NO;
12314052Ssam jmp_buf	tstpbuf;
1246856Srrh 
main(argc,argv)1256856Srrh main(argc, argv)
1266856Srrh int argc; char *argv[];
1276856Srrh {
1286856Srrh 	bool newrc, already;
1296856Srrh 	int rcfirst = 0;		/* first message to print (from .rc) */
13012515Sralph 	int rcback = 0;			/* amount to back off of rcfirst */
1316856Srrh 	int firstmsg, nextmsg, lastmsg = 0;
1326856Srrh 	int blast = 0;
13346257Storek 	FILE *bounds;
1346856Srrh 
13517196Sralph #ifdef UNBUFFERED
1366856Srrh 	setbuf(stdout, NULL);
1376856Srrh #endif
1386856Srrh 
1396856Srrh 	time(&t);
1406856Srrh 	setuid(uid = getuid());
1416856Srrh 	ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL);
1426856Srrh 	if (ruptible)
1436856Srrh 		signal(SIGINT, SIG_DFL);
1446856Srrh 
1456856Srrh 	argc--, argv++;
1466856Srrh 	while (argc > 0) {
1476856Srrh 		if (isdigit(argv[0][0])) {	/* starting message # */
1486856Srrh 			rcfirst = atoi(argv[0]);
1496856Srrh 		}
1506856Srrh 		else if (isdigit(argv[0][1])) {	/* backward offset */
1516856Srrh 			rcback = atoi( &( argv[0][1] ) );
1526856Srrh 		}
1536856Srrh 		else {
1546856Srrh 			ptr = *argv;
1556856Srrh 			while (*ptr) switch (*ptr++) {
1566856Srrh 
1576856Srrh 			case '-':
1586856Srrh 				break;
1596856Srrh 
1606856Srrh 			case 'c':
1616856Srrh 				if (uid != SUPERUSER && uid != DAEMON) {
1626856Srrh 					fprintf(stderr, "Sorry\n");
1636856Srrh 					exit(1);
1646856Srrh 				}
1656856Srrh 				clean = YES;
1666856Srrh 				break;
1676856Srrh 
1686856Srrh 			case 'f':		/* silently */
1696856Srrh 				hush = YES;
1706856Srrh 				break;
1716856Srrh 
1726856Srrh 			case 'h':		/* headers only */
1736856Srrh 				hdrs = YES;
1746856Srrh 				break;
1756856Srrh 
1766856Srrh 			case 'l':		/* local msgs only */
1776856Srrh 				locomode = YES;
1786856Srrh 				break;
1796856Srrh 
1806856Srrh 			case 'o':		/* option to save last message */
1816856Srrh 				lastcmd = YES;
1826856Srrh 				break;
1836856Srrh 
1846856Srrh 			case 'p':		/* pipe thru 'more' during long msgs */
18546160Sbostic 				use_pager = YES;
1866856Srrh 				break;
1876856Srrh 
1886856Srrh 			case 'q':		/* query only */
1896856Srrh 				qopt = YES;
1906856Srrh 				break;
1916856Srrh 
1926856Srrh 			case 's':		/* sending TO msgs */
19346160Sbostic 				send_msg = YES;
1946856Srrh 				break;
1956856Srrh 
1966856Srrh 			default:
1976856Srrh 				fprintf(stderr,
1986856Srrh 					"usage: msgs [fhlopq] [[-]number]\n");
1996856Srrh 				exit(1);
2006856Srrh 			}
2016856Srrh 		}
2026856Srrh 		argc--, argv++;
2036856Srrh 	}
2046856Srrh 
2056856Srrh 	/*
2066856Srrh 	 * determine current message bounds
2076856Srrh 	 */
20837893Sbostic 	sprintf(fname, "%s/%s", _PATH_MSGS, BOUNDS);
2096856Srrh 	bounds = fopen(fname, "r");
2106856Srrh 
2116856Srrh 	if (bounds != NULL) {
2126856Srrh 		fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg);
2136856Srrh 		fclose(bounds);
2146856Srrh 		blast = lastmsg;	/* save upper bound */
2156856Srrh 	}
2166856Srrh 
2176856Srrh 	if (clean)
2186856Srrh 		keep = t - (rcback? rcback : NDAYS) DAYS;
2196856Srrh 
2206856Srrh 	if (clean || bounds == NULL) {	/* relocate message bounds */
2216858Srrh 		struct direct *dp;
2226856Srrh 		struct stat stbuf;
2236856Srrh 		bool seenany = NO;
2246858Srrh 		DIR	*dirp;
2256856Srrh 
22637893Sbostic 		dirp = opendir(_PATH_MSGS);
2276858Srrh 		if (dirp == NULL) {
22837893Sbostic 			perror(_PATH_MSGS);
2296856Srrh 			exit(errno);
2306856Srrh 		}
2316856Srrh 
2326856Srrh 		firstmsg = 32767;
2336856Srrh 		lastmsg = 0;
2346856Srrh 
2356858Srrh 		for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){
2366858Srrh 			register char *cp = dp->d_name;
2376856Srrh 			register int i = 0;
2386856Srrh 
2396858Srrh 			if (dp->d_ino == 0)
2406856Srrh 				continue;
2416858Srrh 			if (dp->d_namlen == 0)
2426858Srrh 				continue;
2436856Srrh 
2446856Srrh 			if (clean)
24537893Sbostic 				sprintf(inbuf, "%s/%s", _PATH_MSGS, cp);
2466856Srrh 
2476856Srrh 			while (isdigit(*cp))
2486856Srrh 				i = i * 10 + *cp++ - '0';
2496856Srrh 			if (*cp)
2506856Srrh 				continue;	/* not a message! */
2516856Srrh 
2526856Srrh 			if (clean) {
2536856Srrh 				if (stat(inbuf, &stbuf) != 0)
2546856Srrh 					continue;
2556856Srrh 				if (stbuf.st_mtime < keep
2566856Srrh 				    && stbuf.st_mode&S_IWRITE) {
2576856Srrh 					unlink(inbuf);
2586856Srrh 					continue;
2596856Srrh 				}
2606856Srrh 			}
2616856Srrh 
2626856Srrh 			if (i > lastmsg)
2636856Srrh 				lastmsg = i;
2646856Srrh 			if (i < firstmsg)
2656856Srrh 				firstmsg = i;
2666856Srrh 			seenany = YES;
2676856Srrh 		}
2686858Srrh 		closedir(dirp);
2696856Srrh 
2706856Srrh 		if (!seenany) {
2716856Srrh 			if (blast != 0)	/* never lower the upper bound! */
2726856Srrh 				lastmsg = blast;
2736856Srrh 			firstmsg = lastmsg + 1;
2746856Srrh 		}
2756856Srrh 		else if (blast > lastmsg)
2766856Srrh 			lastmsg = blast;
2776856Srrh 
27846160Sbostic 		if (!send_msg) {
2796856Srrh 			bounds = fopen(fname, "w");
2806856Srrh 			if (bounds == NULL) {
2816856Srrh 				perror(fname);
2826856Srrh 				exit(errno);
2836856Srrh 			}
2846856Srrh 			chmod(fname, CMODE);
2856856Srrh 			fprintf(bounds, "%d %d\n", firstmsg, lastmsg);
2866856Srrh 			fclose(bounds);
2876856Srrh 		}
2886856Srrh 	}
2896856Srrh 
29046160Sbostic 	if (send_msg) {
2916856Srrh 		/*
29237893Sbostic 		 * Send mode - place msgs in _PATH_MSGS
2936856Srrh 		 */
2946856Srrh 		bounds = fopen(fname, "w");
2956856Srrh 		if (bounds == NULL) {
2966856Srrh 			perror(fname);
2976856Srrh 			exit(errno);
2986856Srrh 		}
2996856Srrh 
3006856Srrh 		nextmsg = lastmsg + 1;
30137893Sbostic 		sprintf(fname, "%s/%d", _PATH_MSGS, nextmsg);
3026856Srrh 		newmsg = fopen(fname, "w");
3036856Srrh 		if (newmsg == NULL) {
3046856Srrh 			perror(fname);
3056856Srrh 			exit(errno);
3066856Srrh 		}
3076856Srrh 		chmod(fname, 0644);
3086856Srrh 
3096856Srrh 		fprintf(bounds, "%d %d\n", firstmsg, nextmsg);
3106856Srrh 		fclose(bounds);
3116856Srrh 
3126856Srrh 		sending = YES;
3136856Srrh 		if (ruptible)
3146856Srrh 			signal(SIGINT, onintr);
3156856Srrh 
3166856Srrh 		if (isatty(fileno(stdin))) {
3176856Srrh 			ptr = getpwuid(uid)->pw_name;
3186856Srrh 			printf("Message %d:\nFrom %s %sSubject: ",
3196856Srrh 				nextmsg, ptr, ctime(&t));
3206856Srrh 			fflush(stdout);
3216856Srrh 			fgets(inbuf, sizeof inbuf, stdin);
3226856Srrh 			putchar('\n');
3236856Srrh 			fflush(stdout);
3246856Srrh 			fprintf(newmsg, "From %s %sSubject: %s\n",
3256856Srrh 				ptr, ctime(&t), inbuf);
3266856Srrh 			blankline = seensubj = YES;
3276856Srrh 		}
3286856Srrh 		else
3296856Srrh 			blankline = seensubj = NO;
3306856Srrh 		for (;;) {
3316856Srrh 			fgets(inbuf, sizeof inbuf, stdin);
3326856Srrh 			if (feof(stdin) || ferror(stdin))
3336856Srrh 				break;
3346856Srrh 			blankline = (blankline || (inbuf[0] == '\n'));
3356856Srrh 			seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0)));
3366856Srrh 			fputs(inbuf, newmsg);
3376856Srrh 		}
3386856Srrh #ifdef OBJECT
3396856Srrh 		if (!seensubj) {
3406856Srrh 			printf("NOTICE: Messages should have a Subject field!\n");
3416856Srrh #ifdef REJECT
3426856Srrh 			unlink(fname);
3436856Srrh #endif
3446856Srrh 			exit(1);
3456856Srrh 		}
3466856Srrh #endif
3476856Srrh 		exit(ferror(stdin));
3486856Srrh 	}
3496856Srrh 	if (clean)
3506856Srrh 		exit(0);
3516856Srrh 
3526856Srrh 	/*
3536856Srrh 	 * prepare to display messages
3546856Srrh 	 */
3556856Srrh 	totty = (isatty(fileno(stdout)) != 0);
35646160Sbostic 	use_pager = use_pager && totty;
3576856Srrh 
3586856Srrh 	sprintf(fname, "%s/%s", getenv("HOME"), MSGSRC);
3596856Srrh 	msgsrc = fopen(fname, "r");
3606856Srrh 	if (msgsrc) {
3616856Srrh 		newrc = NO;
3626856Srrh 		fscanf(msgsrc, "%d\n", &nextmsg);
3636856Srrh 		fclose(msgsrc);
36416335Sralph 		if (nextmsg > lastmsg+1) {
36516335Sralph 			printf("Warning: bounds have been reset (%d, %d)\n",
36616335Sralph 				firstmsg, lastmsg);
36746160Sbostic 			truncate(fname, (off_t)0);
36816335Sralph 			newrc = YES;
36916335Sralph 		}
37016335Sralph 		else if (!rcfirst)
3716856Srrh 			rcfirst = nextmsg - rcback;
3726856Srrh 	}
37316335Sralph 	else
3746856Srrh 		newrc = YES;
37558212Sbostic 	msgsrc = fopen(fname, "r+");
37658212Sbostic 	if (msgsrc == NULL)
37758212Sbostic 		msgsrc = fopen(fname, "w");
3786856Srrh 	if (msgsrc == NULL) {
3796856Srrh 		perror(fname);
3806856Srrh 		exit(errno);
3816856Srrh 	}
38216335Sralph 	if (rcfirst) {
38316335Sralph 		if (rcfirst > lastmsg+1) {
38416335Sralph 			printf("Warning: the last message is number %d.\n",
38516335Sralph 				lastmsg);
38616335Sralph 			rcfirst = nextmsg;
38716335Sralph 		}
38816335Sralph 		if (rcfirst > firstmsg)
38916335Sralph 			firstmsg = rcfirst;	/* don't set below first msg */
39016335Sralph 	}
3916856Srrh 	if (newrc) {
3926856Srrh 		nextmsg = firstmsg;
3936856Srrh 		fseek(msgsrc, 0L, 0);
3946856Srrh 		fprintf(msgsrc, "%d\n", nextmsg);
3956856Srrh 		fflush(msgsrc);
3966856Srrh 	}
3976856Srrh 
3986856Srrh #ifdef V7
3996856Srrh 	if (totty) {
40027026Sbloom 		struct winsize win;
40127026Sbloom 		if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1)
40227026Sbloom 			Lpp = win.ws_row;
40327026Sbloom 		if (Lpp <= 0) {
40427026Sbloom 			if (tgetent(inbuf, getenv("TERM")) <= 0
40527026Sbloom 			    || (Lpp = tgetnum("li")) <= 0) {
40627026Sbloom 				Lpp = NLINES;
40727026Sbloom 			}
4086856Srrh 		}
4096856Srrh 	}
4106856Srrh #endif
4116856Srrh 	Lpp -= 6;	/* for headers, etc. */
4126856Srrh 
4136856Srrh 	already = NO;
4146856Srrh 	prevmsg = firstmsg;
4156856Srrh 	printing = YES;
4166856Srrh 	if (ruptible)
4176856Srrh 		signal(SIGINT, onintr);
4186856Srrh 
4196856Srrh 	/*
4206856Srrh 	 * Main program loop
4216856Srrh 	 */
4226856Srrh 	for (msg = firstmsg; msg <= lastmsg; msg++) {
4236856Srrh 
42437893Sbostic 		sprintf(fname, "%s/%d", _PATH_MSGS, msg);
4256856Srrh 		newmsg = fopen(fname, "r");
4266856Srrh 		if (newmsg == NULL)
4276856Srrh 			continue;
4286856Srrh 
4296856Srrh 		gfrsub(newmsg);		/* get From and Subject fields */
4306856Srrh 		if (locomode && !local) {
4316856Srrh 			fclose(newmsg);
4326856Srrh 			continue;
4336856Srrh 		}
4346856Srrh 
4356856Srrh 		if (qopt) {	/* This has to be located here */
4366856Srrh 			printf("There are new messages.\n");
4376856Srrh 			exit(0);
4386856Srrh 		}
4396856Srrh 
4406856Srrh 		if (already && !hdrs)
4416856Srrh 			putchar('\n');
4426856Srrh 
4436856Srrh 		/*
4446856Srrh 		 * Print header
4456856Srrh 		 */
44611939Sleres 		if (totty)
44711939Sleres 			signal(SIGTSTP, onsusp);
44814052Ssam 		(void) setjmp(tstpbuf);
44946257Storek 		already = YES;
4506856Srrh 		nlines = 2;
4516856Srrh 		if (seenfrom) {
4526856Srrh 			printf("Message %d:\nFrom %s %s", msg, from, date);
4536856Srrh 			nlines++;
4546856Srrh 		}
4556856Srrh 		if (seensubj) {
4566856Srrh 			printf("Subject: %s", subj);
4576856Srrh 			nlines++;
4586856Srrh 		}
4596856Srrh 		else {
4606856Srrh 			if (seenfrom) {
4616856Srrh 				putchar('\n');
4626856Srrh 				nlines++;
4636856Srrh 			}
4646856Srrh 			while (nlines < 6
4656856Srrh 			    && fgets(inbuf, sizeof inbuf, newmsg)
4666856Srrh 			    && inbuf[0] != '\n') {
4676856Srrh 				fputs(inbuf, stdout);
4686856Srrh 				nlines++;
4696856Srrh 			}
4706856Srrh 		}
4716856Srrh 
4726856Srrh 		lct = linecnt(newmsg);
4736856Srrh 		if (lct)
4746856Srrh 			printf("(%d%slines) ", lct, seensubj? " " : " more ");
4756856Srrh 
4766856Srrh 		if (hdrs) {
4776856Srrh 			printf("\n-----\n");
4786856Srrh 			fclose(newmsg);
4796856Srrh 			continue;
4806856Srrh 		}
4816856Srrh 
4826856Srrh 		/*
4836856Srrh 		 * Ask user for command
4846856Srrh 		 */
4856856Srrh 		if (totty)
4866856Srrh 			ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT));
4876856Srrh 		else
4886856Srrh 			inbuf[0] = 'y';
48911939Sleres 		if (totty)
49011939Sleres 			signal(SIGTSTP, SIG_DFL);
4916856Srrh cmnd:
4926856Srrh 		in = inbuf;
4936856Srrh 		switch (*in) {
4946856Srrh 			case 'x':
4956856Srrh 			case 'X':
4966856Srrh 				exit(0);
4976856Srrh 
4986856Srrh 			case 'q':
4996856Srrh 			case 'Q':
5006856Srrh 				quitit = YES;
5016856Srrh 				printf("--Postponed--\n");
5026856Srrh 				exit(0);
5036856Srrh 				/* intentional fall-thru */
5046856Srrh 			case 'n':
5056856Srrh 			case 'N':
5066856Srrh 				if (msg >= nextmsg) sep = "Flushed";
50713427Slayer 				prevmsg = msg;
5086856Srrh 				break;
5096856Srrh 
5106856Srrh 			case 'p':
5116856Srrh 			case 'P':
51246160Sbostic 				use_pager = (*in++ == 'p');
5136856Srrh 				/* intentional fallthru */
5146856Srrh 			case '\n':
5156856Srrh 			case 'y':
5166856Srrh 			default:
5176856Srrh 				if (*in == '-') {
5186856Srrh 					msg = prevmsg-1;
5196856Srrh 					sep = "replay";
5206856Srrh 					break;
5216856Srrh 				}
5226856Srrh 				if (isdigit(*in)) {
5236856Srrh 					msg = next(in);
5246856Srrh 					sep = in;
5256856Srrh 					break;
5266856Srrh 				}
5276856Srrh 
5286856Srrh 				prmesg(nlines + lct + (seensubj? 1 : 0));
5296856Srrh 				prevmsg = msg;
5306856Srrh 
5316856Srrh 		}
5326856Srrh 
5336856Srrh 		printf("--%s--\n", sep);
5346856Srrh 		sep = "-";
5356856Srrh 		if (msg >= nextmsg) {
5366856Srrh 			nextmsg = msg + 1;
5376856Srrh 			fseek(msgsrc, 0L, 0);
5386856Srrh 			fprintf(msgsrc, "%d\n", nextmsg);
5396856Srrh 			fflush(msgsrc);
5406856Srrh 		}
5416856Srrh 		if (newmsg)
5426856Srrh 			fclose(newmsg);
5436856Srrh 		if (quitit)
5446856Srrh 			break;
5456856Srrh 	}
5466856Srrh 
54712254Sleres 	/*
54812254Sleres 	 * Make sure .rc file gets updated
54912254Sleres 	 */
55012254Sleres 	if (--msg >= nextmsg) {
55112254Sleres 		nextmsg = msg + 1;
55212254Sleres 		fseek(msgsrc, 0L, 0);
55312254Sleres 		fprintf(msgsrc, "%d\n", nextmsg);
55412254Sleres 		fflush(msgsrc);
55512254Sleres 	}
5566856Srrh 	if (already && !quitit && lastcmd && totty) {
5576856Srrh 		/*
5586856Srrh 		 * save or reply to last message?
5596856Srrh 		 */
5606856Srrh 		msg = prevmsg;
5616856Srrh 		ask(NOMORE);
5626856Srrh 		if (inbuf[0] == '-' || isdigit(inbuf[0]))
5636856Srrh 			goto cmnd;
5646856Srrh 	}
5656856Srrh 	if (!(already || hush || qopt))
5666856Srrh 		printf("No new messages.\n");
5676856Srrh 	exit(0);
5686856Srrh }
5696856Srrh 
prmesg(length)5706856Srrh prmesg(length)
5716856Srrh int length;
5726856Srrh {
57346160Sbostic 	FILE *outf;
5746856Srrh 
57546160Sbostic 	if (use_pager && length > Lpp) {
57614961Sralph 		signal(SIGPIPE, SIG_IGN);
57714961Sralph 		signal(SIGQUIT, SIG_IGN);
57837893Sbostic 		sprintf(cmdbuf, _PATH_PAGER, Lpp);
5796856Srrh 		outf = popen(cmdbuf, "w");
5806856Srrh 		if (!outf)
5816856Srrh 			outf = stdout;
5826856Srrh 		else
58346160Sbostic 			setbuf(outf, (char *)NULL);
5846856Srrh 	}
5856856Srrh 	else
5866856Srrh 		outf = stdout;
5876856Srrh 
5886856Srrh 	if (seensubj)
5896856Srrh 		putc('\n', outf);
5906856Srrh 
59114961Sralph 	while (fgets(inbuf, sizeof inbuf, newmsg)) {
5926856Srrh 		fputs(inbuf, outf);
59316076Sralph 		if (ferror(outf)) {
59416076Sralph 			clearerr(outf);
59514961Sralph 			break;
59616076Sralph 		}
59714961Sralph 	}
5986856Srrh 
5996856Srrh 	if (outf != stdout) {
6006856Srrh 		pclose(outf);
60114961Sralph 		signal(SIGPIPE, SIG_DFL);
60214961Sralph 		signal(SIGQUIT, SIG_DFL);
6036856Srrh 	}
6046856Srrh 	else {
6056856Srrh 		fflush(stdout);
6066856Srrh 	}
6076856Srrh 
6086856Srrh 	/* trick to force wait on output */
609*69023Sbostic 	tcdrain(fileno(stdout));
6106856Srrh }
6116856Srrh 
61246160Sbostic void
onintr()6136856Srrh onintr()
6146856Srrh {
6156856Srrh 	signal(SIGINT, onintr);
6166856Srrh 	if (mailing)
6176856Srrh 		unlink(fname);
6186856Srrh 	if (sending) {
6196856Srrh 		unlink(fname);
6206856Srrh 		puts("--Killed--");
6216856Srrh 		exit(1);
6226856Srrh 	}
6236856Srrh 	if (printing) {
6246856Srrh 		putchar('\n');
6256856Srrh 		if (hdrs)
6266856Srrh 			exit(0);
6276856Srrh 		sep = "Interrupt";
6286856Srrh 		if (newmsg)
6296856Srrh 			fseek(newmsg, 0L, 2);
6306856Srrh 		intrpflg = YES;
6316856Srrh 	}
6326856Srrh }
6336856Srrh 
63411939Sleres /*
63511939Sleres  * We have just gotten a susp.  Suspend and prepare to resume.
63611939Sleres  */
63746160Sbostic void
onsusp()63811939Sleres onsusp()
63911939Sleres {
64014052Ssam 
64111939Sleres 	signal(SIGTSTP, SIG_DFL);
64213999Ssam 	sigsetmask(0);
64311939Sleres 	kill(0, SIGTSTP);
64411939Sleres 	signal(SIGTSTP, onsusp);
64515689Sleres 	if (!mailing)
64646160Sbostic 		longjmp(tstpbuf, 0);
64711939Sleres }
64811939Sleres 
linecnt(f)6496856Srrh linecnt(f)
6506856Srrh FILE *f;
6516856Srrh {
6526856Srrh 	off_t oldpos = ftell(f);
6536856Srrh 	int l = 0;
6546856Srrh 	char lbuf[BUFSIZ];
6556856Srrh 
6566856Srrh 	while (fgets(lbuf, sizeof lbuf, f))
6576856Srrh 		l++;
6586856Srrh 	clearerr(f);
6596856Srrh 	fseek(f, oldpos, 0);
6606856Srrh 	return (l);
6616856Srrh }
6626856Srrh 
next(buf)6636856Srrh next(buf)
6646856Srrh char *buf;
6656856Srrh {
6666856Srrh 	int i;
6676856Srrh 	sscanf(buf, "%d", &i);
6686856Srrh 	sprintf(buf, "Goto %d", i);
6696856Srrh 	return(--i);
6706856Srrh }
6716856Srrh 
ask(prompt)6726856Srrh ask(prompt)
6736856Srrh char *prompt;
6746856Srrh {
6756856Srrh 	char	inch;
6766856Srrh 	int	n, cmsg;
6776856Srrh 	off_t	oldpos;
6786856Srrh 	FILE	*cpfrom, *cpto;
6796856Srrh 
6806856Srrh 	printf("%s ", prompt);
6816856Srrh 	fflush(stdout);
6826856Srrh 	intrpflg = NO;
68342448Sbostic 	(void) fgets(inbuf, sizeof inbuf, stdin);
68442448Sbostic 	if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n')
68542448Sbostic 		inbuf[n - 1] = '\0';
6866856Srrh 	if (intrpflg)
6876856Srrh 		inbuf[0] = 'x';
6886856Srrh 
6896856Srrh 	/*
6906856Srrh 	 * Handle 'mail' and 'save' here.
6916856Srrh 	 */
6926856Srrh 	if ((inch = inbuf[0]) == 's' || inch == 'm') {
6936856Srrh 		if (inbuf[1] == '-')
6946856Srrh 			cmsg = prevmsg;
6956856Srrh 		else if (isdigit(inbuf[1]))
6966856Srrh 			cmsg = atoi(&inbuf[1]);
6976856Srrh 		else
6986856Srrh 			cmsg = msg;
69937893Sbostic 		sprintf(fname, "%s/%d", _PATH_MSGS, cmsg);
7006856Srrh 
7016856Srrh 		oldpos = ftell(newmsg);
7026856Srrh 
7036856Srrh 		cpfrom = fopen(fname, "r");
7046856Srrh 		if (!cpfrom) {
7056856Srrh 			printf("Message %d not found\n", cmsg);
7066856Srrh 			ask (prompt);
7076856Srrh 			return;
7086856Srrh 		}
7096856Srrh 
7106856Srrh 		if (inch == 's') {
7116856Srrh 			in = nxtfld(inbuf);
7126856Srrh 			if (*in) {
7136856Srrh 				for (n=0; in[n] > ' '; n++) { /* sizeof fname? */
7146856Srrh 					fname[n] = in[n];
7156856Srrh 				}
7166856Srrh 				fname[n] = NULL;
7176856Srrh 			}
7186856Srrh 			else
7196856Srrh 				strcpy(fname, "Messages");
7206856Srrh 		}
7216856Srrh 		else {
72237893Sbostic 			strcpy(fname, _PATH_TMP);
7236856Srrh 			mktemp(fname);
72437893Sbostic 			sprintf(cmdbuf, _PATH_MAIL, fname);
7256856Srrh 			mailing = YES;
7266856Srrh 		}
7276856Srrh 		cpto = fopen(fname, "a");
7286856Srrh 		if (!cpto) {
7296856Srrh 			perror(fname);
7306856Srrh 			mailing = NO;
7316856Srrh 			fseek(newmsg, oldpos, 0);
7326856Srrh 			ask(prompt);
7336856Srrh 			return;
7346856Srrh 		}
7356856Srrh 
7366856Srrh 		while (n = fread(inbuf, 1, sizeof inbuf, cpfrom))
7376856Srrh 			fwrite(inbuf, 1, n, cpto);
7386856Srrh 
7396856Srrh 		fclose(cpfrom);
7406856Srrh 		fclose(cpto);
7416856Srrh 		fseek(newmsg, oldpos, 0);	/* reposition current message */
7426856Srrh 		if (inch == 's')
7436856Srrh 			printf("Message %d saved in \"%s\"\n", cmsg, fname);
7446856Srrh 		else {
7456856Srrh 			system(cmdbuf);
7466856Srrh 			unlink(fname);
7476856Srrh 			mailing = NO;
7486856Srrh 		}
7496856Srrh 		ask(prompt);
7506856Srrh 	}
7516856Srrh }
7526856Srrh 
gfrsub(infile)7536856Srrh gfrsub(infile)
7546856Srrh FILE *infile;
7556856Srrh {
7566856Srrh 	off_t frompos;
7576856Srrh 
7586856Srrh 	seensubj = seenfrom = NO;
7596856Srrh 	local = YES;
7606856Srrh 	subj[0] = from[0] = date[0] = NULL;
7616856Srrh 
7626856Srrh 	/*
7636856Srrh 	 * Is this a normal message?
7646856Srrh 	 */
7656856Srrh 	if (fgets(inbuf, sizeof inbuf, infile)) {
7666856Srrh 		if (strncmp(inbuf, "From", 4)==0) {
7676856Srrh 			/*
7686856Srrh 			 * expected form starts with From
7696856Srrh 			 */
7706856Srrh 			seenfrom = YES;
7716856Srrh 			frompos = ftell(infile);
7726856Srrh 			ptr = from;
7736856Srrh 			in = nxtfld(inbuf);
7746856Srrh 			if (*in) while (*in && *in > ' ') {
7758936Smckusick 				if (*in == ':' || *in == '@' || *in == '!')
7766856Srrh 					local = NO;
7776856Srrh 				*ptr++ = *in++;
7786856Srrh 				/* what about sizeof from ? */
7796856Srrh 			}
7806856Srrh 			*ptr = NULL;
7816856Srrh 			if (*(in = nxtfld(in)))
7826856Srrh 				strncpy(date, in, sizeof date);
7836856Srrh 			else {
7846856Srrh 				date[0] = '\n';
7856856Srrh 				date[1] = NULL;
7866856Srrh 			}
7876856Srrh 		}
7886856Srrh 		else {
7896856Srrh 			/*
7906856Srrh 			 * not the expected form
7916856Srrh 			 */
7926856Srrh 			fseek(infile, 0L, 0);
7936856Srrh 			return;
7946856Srrh 		}
7956856Srrh 	}
7966856Srrh 	else
7976856Srrh 		/*
7986856Srrh 		 * empty file ?
7996856Srrh 		 */
8006856Srrh 		return;
8016856Srrh 
8026856Srrh 	/*
8036856Srrh 	 * look for Subject line until EOF or a blank line
8046856Srrh 	 */
8056856Srrh 	while (fgets(inbuf, sizeof inbuf, infile)
8066856Srrh 	    && !(blankline = (inbuf[0] == '\n'))) {
8076856Srrh 		/*
8086856Srrh 		 * extract Subject line
8096856Srrh 		 */
8106856Srrh 		if (!seensubj && strncmp(inbuf, "Subj", 4)==0) {
8116856Srrh 			seensubj = YES;
8126856Srrh 			frompos = ftell(infile);
8136856Srrh 			strncpy(subj, nxtfld(inbuf), sizeof subj);
8146856Srrh 		}
8156856Srrh 	}
8166856Srrh 	if (!blankline)
8176856Srrh 		/*
8186856Srrh 		 * ran into EOF
8196856Srrh 		 */
8206856Srrh 		fseek(infile, frompos, 0);
8216856Srrh 
8226856Srrh 	if (!seensubj)
8236856Srrh 		/*
8246856Srrh 		 * for possible use with Mail
8256856Srrh 		 */
8266856Srrh 		strncpy(subj, "(No Subject)\n", sizeof subj);
8276856Srrh }
8286856Srrh 
8296856Srrh char *
nxtfld(s)8306856Srrh nxtfld(s)
8316856Srrh char *s;
8326856Srrh {
8336856Srrh 	if (*s) while (*s && *s > ' ') s++;	/* skip over this field */
8346856Srrh 	if (*s) while (*s && *s <= ' ') s++;	/* find start of next field */
8356856Srrh 	return (s);
8366856Srrh }
837