xref: /onnv-gate/usr/src/cmd/mailx/lex.c (revision 2931:6348b43829d4)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2931Sas145665  * Common Development and Distribution License (the "License").
6*2931Sas145665  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate 
220Sstevel@tonic-gate /*
23*2931Sas145665  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
27*2931Sas145665 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28*2931Sas145665 /*	All Rights Reserved   */
29*2931Sas145665 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
320Sstevel@tonic-gate  * The Regents of the University of California
330Sstevel@tonic-gate  * All Rights Reserved
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
360Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
370Sstevel@tonic-gate  * contributors.
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include "rcv.h"
430Sstevel@tonic-gate #include <locale.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * mailx -- a modified version of a University of California at Berkeley
470Sstevel@tonic-gate  *	mail program
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  * Lexical processing of commands.
500Sstevel@tonic-gate  */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #ifdef SIGCONT
530Sstevel@tonic-gate static void		contin(int);
540Sstevel@tonic-gate #endif
550Sstevel@tonic-gate static int		isprefix(char *as1, char *as2);
560Sstevel@tonic-gate static const struct cmd	*lex(char word[]);
570Sstevel@tonic-gate static int		Passeren(void);
580Sstevel@tonic-gate static void		setmsize(int sz);
590Sstevel@tonic-gate 
600Sstevel@tonic-gate /*
610Sstevel@tonic-gate  * Set up editing on the given file name.
620Sstevel@tonic-gate  * If isedit is true, we are considered to be editing the file,
630Sstevel@tonic-gate  * otherwise we are reading our mail which has signficance for
640Sstevel@tonic-gate  * mbox and so forth.
650Sstevel@tonic-gate  */
660Sstevel@tonic-gate 
67*2931Sas145665 int
setfile(char * name,int isedit)680Sstevel@tonic-gate setfile(char *name, int isedit)
690Sstevel@tonic-gate {
700Sstevel@tonic-gate 	FILE *ibuf;
710Sstevel@tonic-gate 	int i;
720Sstevel@tonic-gate 	static int shudclob;
730Sstevel@tonic-gate 	static char efile[PATHSIZE];
740Sstevel@tonic-gate 	char fortest[128];
750Sstevel@tonic-gate 	struct stat stbuf;
760Sstevel@tonic-gate 	int exrc = 1;
770Sstevel@tonic-gate 	int rc = -1;
780Sstevel@tonic-gate 	int fd = -1;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	if (!isedit && issysmbox)
810Sstevel@tonic-gate 		lockmail();
820Sstevel@tonic-gate 	if (stat(name, &stbuf) < 0 && errno == EOVERFLOW) {
830Sstevel@tonic-gate 		fprintf(stderr, gettext("mailbox %s is too large to"
840Sstevel@tonic-gate 		    " accept incoming mail\n"), name);
850Sstevel@tonic-gate 		goto doret;
860Sstevel@tonic-gate 	}
870Sstevel@tonic-gate 	if ((ibuf = fopen(name, "r")) == NULL) {
88*2931Sas145665 		extern int errno;
890Sstevel@tonic-gate 		int sverrno = errno;
90*2931Sas145665 		int filethere = (access(name, 0) == 0);
910Sstevel@tonic-gate 		errno = sverrno;
920Sstevel@tonic-gate 		if (exitflg)
930Sstevel@tonic-gate 			goto doexit;	/* no mail, return error */
940Sstevel@tonic-gate 		if (isedit || filethere)
950Sstevel@tonic-gate 			perror(name);
960Sstevel@tonic-gate 		else if (!Hflag) {
97*2931Sas145665 			char *f = strrchr(name, '/');
980Sstevel@tonic-gate 			if (f == NOSTR)
990Sstevel@tonic-gate 				fprintf(stderr, gettext("No mail.\n"));
1000Sstevel@tonic-gate 			else
1010Sstevel@tonic-gate 				fprintf(stderr, gettext("No mail for %s\n"),
1020Sstevel@tonic-gate f+1);
1030Sstevel@tonic-gate 		}
1040Sstevel@tonic-gate 		goto doret;
1050Sstevel@tonic-gate 	}
1060Sstevel@tonic-gate 	fstat(fileno(ibuf), &stbuf);
1070Sstevel@tonic-gate 	if (stbuf.st_size == 0L || (stbuf.st_mode&S_IFMT) != S_IFREG) {
1080Sstevel@tonic-gate 		if (exitflg)
1090Sstevel@tonic-gate 			goto doexit;	/* no mail, return error */
1100Sstevel@tonic-gate 		if (isedit)
1110Sstevel@tonic-gate 			if (stbuf.st_size == 0L)
1120Sstevel@tonic-gate 				fprintf(stderr, gettext("%s: empty file\n"),
1130Sstevel@tonic-gate name);
1140Sstevel@tonic-gate 			else
1150Sstevel@tonic-gate 				fprintf(stderr,
1160Sstevel@tonic-gate 				    gettext("%s: not a regular file\n"), name);
1170Sstevel@tonic-gate 		else if (!Hflag) {
118*2931Sas145665 			if (strrchr(name, '/') == NOSTR)
1190Sstevel@tonic-gate 				fprintf(stderr, gettext("No mail.\n"));
1200Sstevel@tonic-gate 			else
1210Sstevel@tonic-gate 				fprintf(stderr, gettext("No mail for %s\n"),
1220Sstevel@tonic-gate strrchr(name, '/') + 1);
1230Sstevel@tonic-gate 		}
1240Sstevel@tonic-gate 		fclose(ibuf);
1250Sstevel@tonic-gate 		goto doret;
1260Sstevel@tonic-gate 	}
1270Sstevel@tonic-gate 
128*2931Sas145665 	if (fgets(fortest, sizeof (fortest), ibuf) == NULL) {
129*2931Sas145665 		perror(gettext("mailx: Unable to read from mail file"));
130*2931Sas145665 		goto doexit;
131*2931Sas145665 	}
132*2931Sas145665 
1330Sstevel@tonic-gate 	fseek(ibuf, (long)(BUFSIZ+1), 0);	/* flush input buffer */
1340Sstevel@tonic-gate 	fseek(ibuf, 0L, 0);
1350Sstevel@tonic-gate 	if (strncmp(fortest, "Forward to ", 11) == 0) {
1360Sstevel@tonic-gate 		if (exitflg)
1370Sstevel@tonic-gate 			goto doexit;	/* no mail, return error */
1380Sstevel@tonic-gate 		fprintf(stderr, gettext("Your mail is being forwarded to %s"),
1390Sstevel@tonic-gate fortest+11);
1400Sstevel@tonic-gate 		fclose(ibuf);
1410Sstevel@tonic-gate 		goto doret;
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 	if (exitflg) {
1440Sstevel@tonic-gate 		exrc = 0;
1450Sstevel@tonic-gate 		goto doexit;	/* there is mail, return success */
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	/*
1490Sstevel@tonic-gate 	 * Looks like all will be well. Must hold signals
1500Sstevel@tonic-gate 	 * while we are reading the new file, else we will ruin
1510Sstevel@tonic-gate 	 * the message[] data structure.
1520Sstevel@tonic-gate 	 * Copy the messages into /tmp and set pointers.
1530Sstevel@tonic-gate 	 */
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	holdsigs();
1560Sstevel@tonic-gate 	if (shudclob) {
1570Sstevel@tonic-gate 		/*
1580Sstevel@tonic-gate 		 * Now that we know we can switch to the new file
1590Sstevel@tonic-gate 		 * it's safe to close out the current file.
1600Sstevel@tonic-gate 		 *
1610Sstevel@tonic-gate 		 * If we're switching to the file we are currently
1620Sstevel@tonic-gate 		 * editing, don't allow it to be removed as a side
1630Sstevel@tonic-gate 		 * effect of closing it out.
1640Sstevel@tonic-gate 		 */
1650Sstevel@tonic-gate 		if (edit)
1660Sstevel@tonic-gate 			edstop(strcmp(editfile, name) == 0);
1670Sstevel@tonic-gate 		else {
1680Sstevel@tonic-gate 			quit(strcmp(editfile, name) == 0);
1690Sstevel@tonic-gate 			if (issysmbox)
1700Sstevel@tonic-gate 				Verhogen();
1710Sstevel@tonic-gate 		}
1720Sstevel@tonic-gate 		fflush(stdout);
1730Sstevel@tonic-gate 		fclose(itf);
1740Sstevel@tonic-gate 		fclose(otf);
1750Sstevel@tonic-gate 		free(message);
176*2931Sas145665 		space = 0;
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 	readonly = 0;
1790Sstevel@tonic-gate 	if (!isedit && issysmbox && !Hflag)
180*2931Sas145665 		readonly = Passeren() == -1;
1810Sstevel@tonic-gate 	lock(ibuf, "r", 1);
1820Sstevel@tonic-gate 	fstat(fileno(ibuf), &stbuf);
1830Sstevel@tonic-gate 	utimep->actime = stbuf.st_atime;
1840Sstevel@tonic-gate 	utimep->modtime = stbuf.st_mtime;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	if (!readonly)
1870Sstevel@tonic-gate 		if ((i = open(name, O_WRONLY)) < 0)
1880Sstevel@tonic-gate 			readonly++;
1890Sstevel@tonic-gate 		else
1900Sstevel@tonic-gate 			close(i);
1910Sstevel@tonic-gate 	shudclob = 1;
1920Sstevel@tonic-gate 	edit = isedit;
1930Sstevel@tonic-gate 	nstrcpy(efile, PATHSIZE, name);
1940Sstevel@tonic-gate 	editfile = efile;
1950Sstevel@tonic-gate #ifdef notdef
1960Sstevel@tonic-gate 	if (name != mailname)
1970Sstevel@tonic-gate 		nstrcpy(mailname, PATHSIZE, name);
1980Sstevel@tonic-gate #endif
1990Sstevel@tonic-gate 	mailsize = fsize(ibuf);
2000Sstevel@tonic-gate 	if ((fd = open(tempMesg, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
2010Sstevel@tonic-gate 	(otf = fdopen(fd, "w")) == NULL) {
2020Sstevel@tonic-gate 		perror(tempMesg);
2030Sstevel@tonic-gate 		if (!edit && issysmbox)
2040Sstevel@tonic-gate 			Verhogen();
2050Sstevel@tonic-gate 		goto doexit;
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 	if ((itf = fopen(tempMesg, "r")) == NULL) {
2080Sstevel@tonic-gate 		perror(tempMesg);
2090Sstevel@tonic-gate 		if (!edit && issysmbox)
2100Sstevel@tonic-gate 			Verhogen();
2110Sstevel@tonic-gate 		goto doexit;
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 	removefile(tempMesg);
2140Sstevel@tonic-gate 	setptr(ibuf);
2150Sstevel@tonic-gate 	setmsize(msgCount);
2160Sstevel@tonic-gate 	fclose(ibuf);
2170Sstevel@tonic-gate 	relsesigs();
2180Sstevel@tonic-gate 	sawcom = 0;
2190Sstevel@tonic-gate 	rc = 0;
2200Sstevel@tonic-gate 
221*2931Sas145665 doret:
2220Sstevel@tonic-gate 	if (!isedit && issysmbox)
2230Sstevel@tonic-gate 		unlockmail();
224*2931Sas145665 	return (rc);
2250Sstevel@tonic-gate 
226*2931Sas145665 doexit:
2270Sstevel@tonic-gate 	if (!isedit && issysmbox)
2280Sstevel@tonic-gate 		unlockmail();
2290Sstevel@tonic-gate 	exit(exrc ? exrc : rpterr);
2300Sstevel@tonic-gate 	/* NOTREACHED */
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate /* global to semaphores */
2340Sstevel@tonic-gate static char semfn[128];
2350Sstevel@tonic-gate static FILE *semfp = NULL;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate  *  return -1 if file is already being read, 0 otherwise
2390Sstevel@tonic-gate  */
2400Sstevel@tonic-gate static int
Passeren(void)2410Sstevel@tonic-gate Passeren(void)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate 	char *home;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	if ((home = getenv("HOME")) == NULL)
246*2931Sas145665 		return (0);
247*2931Sas145665 	snprintf(semfn, sizeof (semfn), "%s%s", home, "/.Maillock");
2480Sstevel@tonic-gate 	if ((semfp = fopen(semfn, "w")) == NULL) {
2490Sstevel@tonic-gate 		fprintf(stderr,
2500Sstevel@tonic-gate 	    gettext("WARNING: Can't open mail lock file (%s).\n"), semfn);
2510Sstevel@tonic-gate 		fprintf(stderr,
2520Sstevel@tonic-gate 	    gettext("\t Assuming you are not already reading mail.\n"));
253*2931Sas145665 		return (0);
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 	if (lock(semfp, "w", 0) < 0) {
2560Sstevel@tonic-gate 		if (errno == ENOLCK) {
2570Sstevel@tonic-gate 			fprintf(stderr,
2580Sstevel@tonic-gate gettext("WARNING: Unable to acquire mail lock, no record locks available.\n"));
2590Sstevel@tonic-gate 			fprintf(stderr,
2600Sstevel@tonic-gate 		    gettext("\t Assuming you are not already reading mail.\n"));
261*2931Sas145665 			return (0);
2620Sstevel@tonic-gate 		}
2630Sstevel@tonic-gate 		fprintf(stderr,
2640Sstevel@tonic-gate 		    gettext("WARNING: You are already reading mail.\n"));
2650Sstevel@tonic-gate 		fprintf(stderr,
2660Sstevel@tonic-gate 		    gettext("\t This instance of mail is read only.\n"));
2670Sstevel@tonic-gate 		fclose(semfp);
2680Sstevel@tonic-gate 		semfp = NULL;
269*2931Sas145665 		return (-1);
2700Sstevel@tonic-gate 	}
271*2931Sas145665 	return (0);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate 
274*2931Sas145665 void
Verhogen(void)2750Sstevel@tonic-gate Verhogen(void)
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate 	if (semfp != NULL) {
2780Sstevel@tonic-gate 		unlink(semfn);
2790Sstevel@tonic-gate 		fclose(semfp);
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate  * Interpret user commands one by one.  If standard input is not a tty,
2850Sstevel@tonic-gate  * print no prompt.
2860Sstevel@tonic-gate  */
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate static int	*msgvec;
2890Sstevel@tonic-gate static int	shudprompt;
2900Sstevel@tonic-gate 
291*2931Sas145665 void
commands(void)2920Sstevel@tonic-gate commands(void)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	int eofloop;
2950Sstevel@tonic-gate 	register int n;
2960Sstevel@tonic-gate 	char linebuf[LINESIZE];
2970Sstevel@tonic-gate 	char line[LINESIZE];
2980Sstevel@tonic-gate 	struct stat minfo;
2990Sstevel@tonic-gate 	FILE *ibuf;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate #ifdef SIGCONT
3020Sstevel@tonic-gate 	sigset(SIGCONT, SIG_DFL);
3030Sstevel@tonic-gate #endif
3040Sstevel@tonic-gate 	if (rcvmode && !sourcing) {
3050Sstevel@tonic-gate 		if (sigset(SIGINT, SIG_IGN) != SIG_IGN)
3060Sstevel@tonic-gate 			sigset(SIGINT, stop);
3070Sstevel@tonic-gate 		if (sigset(SIGHUP, SIG_IGN) != SIG_IGN)
3080Sstevel@tonic-gate 			sigset(SIGHUP, hangup);
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 	for (;;) {
3110Sstevel@tonic-gate 		setjmp(srbuf);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 		/*
3140Sstevel@tonic-gate 		 * Print the prompt, if needed.  Clear out
3150Sstevel@tonic-gate 		 * string space, and flush the output.
3160Sstevel@tonic-gate 		 */
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 		if (!rcvmode && !sourcing)
3190Sstevel@tonic-gate 			return;
3200Sstevel@tonic-gate 		eofloop = 0;
3210Sstevel@tonic-gate top:
3220Sstevel@tonic-gate 		if ((shudprompt = (intty && !sourcing)) != 0) {
323*2931Sas145665 			if (prompt == NOSTR) {
3240Sstevel@tonic-gate 				if ((int)value("bsdcompat"))
3250Sstevel@tonic-gate 					prompt = "& ";
3260Sstevel@tonic-gate 				else
327*2931Sas145665 					prompt = "";
3280Sstevel@tonic-gate 			}
3290Sstevel@tonic-gate #ifdef SIGCONT
3300Sstevel@tonic-gate 			sigset(SIGCONT, contin);
3310Sstevel@tonic-gate #endif
3320Sstevel@tonic-gate 			if (intty && value("autoinc") &&
333*2931Sas145665 			    stat(editfile, &minfo) >= 0 &&
3340Sstevel@tonic-gate 			    minfo.st_size > mailsize) {
3350Sstevel@tonic-gate 				int OmsgCount, i;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 				OmsgCount = msgCount;
3380Sstevel@tonic-gate 				fseek(otf, 0L, 2);
3390Sstevel@tonic-gate 				holdsigs();
3400Sstevel@tonic-gate 				if (!edit && issysmbox)
3410Sstevel@tonic-gate 					lockmail();
342*2931Sas145665 				if ((ibuf = fopen(editfile, "r")) == NULL) {
3430Sstevel@tonic-gate 					fprintf(stderr,
3440Sstevel@tonic-gate 					    gettext("Can't reopen %s\n"),
3450Sstevel@tonic-gate 					    editfile);
3460Sstevel@tonic-gate 					if (!edit && issysmbox)
3470Sstevel@tonic-gate 						unlockmail();
3480Sstevel@tonic-gate 					exit(1);
3490Sstevel@tonic-gate 					/* NOTREACHED */
3500Sstevel@tonic-gate 				}
3510Sstevel@tonic-gate 				if (edit || !issysmbox)
3520Sstevel@tonic-gate 					lock(ibuf, "r", 1);
3530Sstevel@tonic-gate 				fseek(ibuf, mailsize, 0);
3540Sstevel@tonic-gate 				mailsize = fsize(ibuf);
3550Sstevel@tonic-gate 				setptr(ibuf);
3560Sstevel@tonic-gate 				setmsize(msgCount);
3570Sstevel@tonic-gate 				fclose(ibuf);
3580Sstevel@tonic-gate 				if (!edit && issysmbox)
3590Sstevel@tonic-gate 					unlockmail();
3600Sstevel@tonic-gate 				if (msgCount-OmsgCount > 0) {
3610Sstevel@tonic-gate 					printf(gettext(
3620Sstevel@tonic-gate 					    "New mail has arrived.\n"));
3630Sstevel@tonic-gate 					if (msgCount - OmsgCount == 1)
3640Sstevel@tonic-gate 						printf(gettext(
3650Sstevel@tonic-gate 						    "Loaded 1 new message\n"));
3660Sstevel@tonic-gate 					else
3670Sstevel@tonic-gate 						printf(gettext(
3680Sstevel@tonic-gate 						    "Loaded %d new messages\n"),
3690Sstevel@tonic-gate 						    msgCount-OmsgCount);
3700Sstevel@tonic-gate 					if (value("header") != NOSTR)
3710Sstevel@tonic-gate 						for (i = OmsgCount+1;
372*2931Sas145665 						    i <= msgCount; i++) {
3730Sstevel@tonic-gate 							printhead(i);
3740Sstevel@tonic-gate 							sreset();
3750Sstevel@tonic-gate 						}
3760Sstevel@tonic-gate 				}
3770Sstevel@tonic-gate 				relsesigs();
3780Sstevel@tonic-gate 			}
3790Sstevel@tonic-gate 			printf("%s", prompt);
3800Sstevel@tonic-gate 		}
3810Sstevel@tonic-gate 		flush();
3820Sstevel@tonic-gate 		sreset();
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 		/*
3850Sstevel@tonic-gate 		 * Read a line of commands from the current input
3860Sstevel@tonic-gate 		 * and handle end of file specially.
3870Sstevel@tonic-gate 		 */
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 		n = 0;
3900Sstevel@tonic-gate 		linebuf[0] = '\0';
3910Sstevel@tonic-gate 		for (;;) {
3920Sstevel@tonic-gate 			if (readline(input, line) <= 0) {
3930Sstevel@tonic-gate 				if (n != 0)
3940Sstevel@tonic-gate 					break;
3950Sstevel@tonic-gate 				if (loading)
3960Sstevel@tonic-gate 					return;
3970Sstevel@tonic-gate 				if (sourcing) {
3980Sstevel@tonic-gate 					unstack();
3990Sstevel@tonic-gate 					goto more;
4000Sstevel@tonic-gate 				}
4010Sstevel@tonic-gate 				if (value("ignoreeof") != NOSTR && shudprompt) {
4020Sstevel@tonic-gate 					if (++eofloop < 25) {
4030Sstevel@tonic-gate 						printf(gettext(
4040Sstevel@tonic-gate 						    "Use \"quit\" to quit.\n"));
4050Sstevel@tonic-gate 						goto top;
4060Sstevel@tonic-gate 					}
4070Sstevel@tonic-gate 				}
4080Sstevel@tonic-gate 				return;
4090Sstevel@tonic-gate 			}
4100Sstevel@tonic-gate 			if ((n = strlen(line)) == 0)
4110Sstevel@tonic-gate 				break;
4120Sstevel@tonic-gate 			n--;
4130Sstevel@tonic-gate 			if (line[n] != '\\')
4140Sstevel@tonic-gate 				break;
4150Sstevel@tonic-gate 			line[n++] = ' ';
4160Sstevel@tonic-gate 			if (n > LINESIZE - (int)strlen(linebuf) - 1)
4170Sstevel@tonic-gate 				break;
4180Sstevel@tonic-gate 			strcat(linebuf, line);
4190Sstevel@tonic-gate 		}
4200Sstevel@tonic-gate 		n = LINESIZE - strlen(linebuf) - 1;
4210Sstevel@tonic-gate 		if ((int)strlen(line) > n) {
4220Sstevel@tonic-gate 			printf(gettext(
4230Sstevel@tonic-gate 		"Line plus continuation line too long:\n\t%s\n\nplus\n\t%s\n"),
4240Sstevel@tonic-gate 			    linebuf, line);
4250Sstevel@tonic-gate 			if (loading)
4260Sstevel@tonic-gate 				return;
4270Sstevel@tonic-gate 			if (sourcing) {
4280Sstevel@tonic-gate 				unstack();
4290Sstevel@tonic-gate 				goto more;
4300Sstevel@tonic-gate 			}
4310Sstevel@tonic-gate 			return;
4320Sstevel@tonic-gate 		}
433*2931Sas145665 		strncat(linebuf, line, n);
4340Sstevel@tonic-gate #ifdef SIGCONT
4350Sstevel@tonic-gate 		sigset(SIGCONT, SIG_DFL);
4360Sstevel@tonic-gate #endif
4370Sstevel@tonic-gate 		if (execute(linebuf, 0))
4380Sstevel@tonic-gate 			return;
439*2931Sas145665 more:;
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate /*
4440Sstevel@tonic-gate  * Execute a single command.  If the command executed
4450Sstevel@tonic-gate  * is "quit," then return non-zero so that the caller
4460Sstevel@tonic-gate  * will know to return back to main, if he cares.
4470Sstevel@tonic-gate  * Contxt is non-zero if called while composing mail.
4480Sstevel@tonic-gate  */
4490Sstevel@tonic-gate 
450*2931Sas145665 int
execute(char linebuf[],int contxt)4510Sstevel@tonic-gate execute(char linebuf[], int contxt)
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate 	char word[LINESIZE];
4540Sstevel@tonic-gate 	char *arglist[MAXARGC];
4550Sstevel@tonic-gate 	const struct cmd *com;
4560Sstevel@tonic-gate 	register char *cp, *cp2;
4570Sstevel@tonic-gate 	register int c, e;
4580Sstevel@tonic-gate 	int muvec[2];
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	/*
4610Sstevel@tonic-gate 	 * Strip the white space away from the beginning
4620Sstevel@tonic-gate 	 * of the command, then scan out a word, which
4630Sstevel@tonic-gate 	 * consists of anything except digits and white space.
4640Sstevel@tonic-gate 	 *
4650Sstevel@tonic-gate 	 * Handle |, ! and # differently to get the correct
4660Sstevel@tonic-gate 	 * lexical conventions.
4670Sstevel@tonic-gate 	 */
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	cp = linebuf;
4700Sstevel@tonic-gate 	while (any(*cp, " \t"))
4710Sstevel@tonic-gate 		cp++;
4720Sstevel@tonic-gate 	cp2 = word;
4730Sstevel@tonic-gate 	if (any(*cp, "!|#"))
4740Sstevel@tonic-gate 		*cp2++ = *cp++;
4750Sstevel@tonic-gate 	else
4760Sstevel@tonic-gate 		while (*cp && !any(*cp, " \t0123456789$^.:/-+*'\""))
4770Sstevel@tonic-gate 			*cp2++ = *cp++;
4780Sstevel@tonic-gate 	*cp2 = '\0';
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	/*
4810Sstevel@tonic-gate 	 * Look up the command; if not found, complain.
4820Sstevel@tonic-gate 	 * Normally, a blank command would map to the
4830Sstevel@tonic-gate 	 * first command in the table; while sourcing,
4840Sstevel@tonic-gate 	 * however, we ignore blank lines to eliminate
4850Sstevel@tonic-gate 	 * confusion.
4860Sstevel@tonic-gate 	 */
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	if (sourcing && equal(word, ""))
489*2931Sas145665 		return (0);
4900Sstevel@tonic-gate 	com = lex(word);
4910Sstevel@tonic-gate 	if (com == NONE) {
4920Sstevel@tonic-gate 		fprintf(stderr, gettext("Unknown command: \"%s\"\n"), word);
4930Sstevel@tonic-gate 		if (loading) {
4940Sstevel@tonic-gate 			cond = CANY;
495*2931Sas145665 			return (1);
4960Sstevel@tonic-gate 		}
4970Sstevel@tonic-gate 		if (sourcing) {
4980Sstevel@tonic-gate 			cond = CANY;
4990Sstevel@tonic-gate 			unstack();
5000Sstevel@tonic-gate 		}
501*2931Sas145665 		return (0);
5020Sstevel@tonic-gate 	}
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	/*
5050Sstevel@tonic-gate 	 * See if we should execute the command -- if a conditional
5060Sstevel@tonic-gate 	 * we always execute it, otherwise, check the state of cond.
5070Sstevel@tonic-gate 	 */
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if ((com->c_argtype & F) == 0)
5100Sstevel@tonic-gate 		if (cond == CRCV && !rcvmode || cond == CSEND && rcvmode ||
5110Sstevel@tonic-gate 		    cond == CTTY && !intty || cond == CNOTTY && intty)
512*2931Sas145665 			return (0);
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	/*
5150Sstevel@tonic-gate 	 * Special case so that quit causes a return to
5160Sstevel@tonic-gate 	 * main, who will call the quit code directly.
5170Sstevel@tonic-gate 	 * If we are in a source file, just unstack.
5180Sstevel@tonic-gate 	 */
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if (com->c_func == (int (*)(void *))edstop) {
5210Sstevel@tonic-gate 		if (sourcing) {
5220Sstevel@tonic-gate 			if (loading)
523*2931Sas145665 				return (1);
5240Sstevel@tonic-gate 			unstack();
525*2931Sas145665 			return (0);
5260Sstevel@tonic-gate 		}
527*2931Sas145665 		return (1);
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	/*
5310Sstevel@tonic-gate 	 * Process the arguments to the command, depending
5320Sstevel@tonic-gate 	 * on the type he expects.  Default to an error.
5330Sstevel@tonic-gate 	 * If we are sourcing an interactive command, it's
5340Sstevel@tonic-gate 	 * an error.
5350Sstevel@tonic-gate 	 */
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	if (!rcvmode && (com->c_argtype & M) == 0) {
5380Sstevel@tonic-gate 		fprintf(stderr,
5390Sstevel@tonic-gate 		    gettext("May not execute \"%s\" while sending\n"),
5400Sstevel@tonic-gate 		    com->c_name);
5410Sstevel@tonic-gate 		if (loading)
542*2931Sas145665 			return (1);
5430Sstevel@tonic-gate 		if (sourcing)
5440Sstevel@tonic-gate 			unstack();
545*2931Sas145665 		return (0);
5460Sstevel@tonic-gate 	}
5470Sstevel@tonic-gate 	if (sourcing && com->c_argtype & I) {
5480Sstevel@tonic-gate 		fprintf(stderr,
5490Sstevel@tonic-gate 		    gettext("May not execute \"%s\" while sourcing\n"),
5500Sstevel@tonic-gate 		    com->c_name);
5510Sstevel@tonic-gate 		rpterr = 1;
5520Sstevel@tonic-gate 		if (loading)
553*2931Sas145665 			return (1);
5540Sstevel@tonic-gate 		unstack();
555*2931Sas145665 		return (0);
5560Sstevel@tonic-gate 	}
5570Sstevel@tonic-gate 	if (readonly && com->c_argtype & W) {
5580Sstevel@tonic-gate 		fprintf(stderr, gettext(
5590Sstevel@tonic-gate 		    "May not execute \"%s\" -- message file is read only\n"),
5600Sstevel@tonic-gate 		    com->c_name);
5610Sstevel@tonic-gate 		if (loading)
562*2931Sas145665 			return (1);
5630Sstevel@tonic-gate 		if (sourcing)
5640Sstevel@tonic-gate 			unstack();
565*2931Sas145665 		return (0);
5660Sstevel@tonic-gate 	}
5670Sstevel@tonic-gate 	if (contxt && com->c_argtype & R) {
5680Sstevel@tonic-gate 		fprintf(stderr, gettext("Cannot recursively invoke \"%s\"\n"),
5690Sstevel@tonic-gate 		    com->c_name);
570*2931Sas145665 		return (0);
5710Sstevel@tonic-gate 	}
5720Sstevel@tonic-gate 	e = 1;
5730Sstevel@tonic-gate 	switch (com->c_argtype & ~(F|P|I|M|T|W|R)) {
5740Sstevel@tonic-gate 	case MSGLIST:
5750Sstevel@tonic-gate 		/*
5760Sstevel@tonic-gate 		 * A message list defaulting to nearest forward
5770Sstevel@tonic-gate 		 * legal message.
5780Sstevel@tonic-gate 		 */
5790Sstevel@tonic-gate 		if (msgvec == 0) {
5800Sstevel@tonic-gate 			fprintf(stderr,
5810Sstevel@tonic-gate 			    gettext("Illegal use of \"message list\"\n"));
582*2931Sas145665 			return (-1);
5830Sstevel@tonic-gate 		}
5840Sstevel@tonic-gate 		if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0)
5850Sstevel@tonic-gate 			break;
5860Sstevel@tonic-gate 		if (c  == 0)
5870Sstevel@tonic-gate 			if (msgCount == 0)
5880Sstevel@tonic-gate 				*msgvec = NULL;
5890Sstevel@tonic-gate 			else {
5900Sstevel@tonic-gate 				*msgvec = first(com->c_msgflag,
5910Sstevel@tonic-gate 					com->c_msgmask);
5920Sstevel@tonic-gate 				msgvec[1] = NULL;
5930Sstevel@tonic-gate 			}
5940Sstevel@tonic-gate 		if (*msgvec == NULL) {
5950Sstevel@tonic-gate 			fprintf(stderr, gettext("No applicable messages\n"));
5960Sstevel@tonic-gate 			break;
5970Sstevel@tonic-gate 		}
5980Sstevel@tonic-gate 		e = (*com->c_func)(msgvec);
5990Sstevel@tonic-gate 		break;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	case NDMLIST:
6020Sstevel@tonic-gate 		/*
603*2931Sas145665 		 * A message operand with no defaults, but no error
604*2931Sas145665 		 * if none exists. There will be an error if the
605*2931Sas145665 		 * msgvec pointer is of zero value.
6060Sstevel@tonic-gate 		 */
6070Sstevel@tonic-gate 		if (msgvec == 0) {
6080Sstevel@tonic-gate 			fprintf(stderr,
609*2931Sas145665 			    gettext("Illegal use of \"message operand\"\n"));
610*2931Sas145665 			return (-1);
6110Sstevel@tonic-gate 		}
612*2931Sas145665 		if (getmessage(cp, msgvec, com->c_msgflag) < 0)
6130Sstevel@tonic-gate 			break;
6140Sstevel@tonic-gate 		e = (*com->c_func)(msgvec);
6150Sstevel@tonic-gate 		break;
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	case STRLIST:
6180Sstevel@tonic-gate 		/*
6190Sstevel@tonic-gate 		 * Just the straight string, with
6200Sstevel@tonic-gate 		 * leading blanks removed.
6210Sstevel@tonic-gate 		 */
6220Sstevel@tonic-gate 		while (any(*cp, " \t"))
6230Sstevel@tonic-gate 			cp++;
6240Sstevel@tonic-gate 		e = (*com->c_func)(cp);
6250Sstevel@tonic-gate 		break;
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	case RAWLIST:
6280Sstevel@tonic-gate 		/*
6290Sstevel@tonic-gate 		 * A vector of strings, in shell style.
6300Sstevel@tonic-gate 		 */
6310Sstevel@tonic-gate 		if ((c = getrawlist(cp, arglist,
632*2931Sas145665 				sizeof (arglist) / sizeof (*arglist))) < 0)
6330Sstevel@tonic-gate 			break;
6340Sstevel@tonic-gate 		if (c < com->c_minargs) {
6350Sstevel@tonic-gate 			fprintf(stderr,
6360Sstevel@tonic-gate 			    gettext("%s requires at least %d arg(s)\n"),
6370Sstevel@tonic-gate 			    com->c_name, com->c_minargs);
6380Sstevel@tonic-gate 			break;
6390Sstevel@tonic-gate 		}
6400Sstevel@tonic-gate 		if (c > com->c_maxargs) {
6410Sstevel@tonic-gate 			fprintf(stderr,
6420Sstevel@tonic-gate 			    gettext("%s takes no more than %d arg(s)\n"),
6430Sstevel@tonic-gate 			    com->c_name, com->c_maxargs);
6440Sstevel@tonic-gate 			break;
6450Sstevel@tonic-gate 		}
6460Sstevel@tonic-gate 		e = (*com->c_func)(arglist);
6470Sstevel@tonic-gate 		break;
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	case NOLIST:
6500Sstevel@tonic-gate 		/*
6510Sstevel@tonic-gate 		 * Just the constant zero, for exiting,
6520Sstevel@tonic-gate 		 * eg.
6530Sstevel@tonic-gate 		 */
6540Sstevel@tonic-gate 		e = (*com->c_func)(0);
6550Sstevel@tonic-gate 		break;
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	default:
6580Sstevel@tonic-gate 		panic("Unknown argtype");
6590Sstevel@tonic-gate 	}
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	/*
6620Sstevel@tonic-gate 	 * Exit the current source file on
6630Sstevel@tonic-gate 	 * error.
6640Sstevel@tonic-gate 	 */
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	if (e && loading)
667*2931Sas145665 		return (1);
6680Sstevel@tonic-gate 	if (e && sourcing)
6690Sstevel@tonic-gate 		unstack();
6700Sstevel@tonic-gate 	if (com->c_func == (int (*)(void *))edstop)
671*2931Sas145665 		return (1);
6720Sstevel@tonic-gate 	if (value("autoprint") != NOSTR && com->c_argtype & P)
6730Sstevel@tonic-gate 		if ((dot->m_flag & MDELETED) == 0) {
6740Sstevel@tonic-gate 			muvec[0] = dot - &message[0] + 1;
6750Sstevel@tonic-gate 			muvec[1] = 0;
6760Sstevel@tonic-gate 			type(muvec);
6770Sstevel@tonic-gate 		}
6780Sstevel@tonic-gate 	if (!sourcing && (com->c_argtype & T) == 0)
6790Sstevel@tonic-gate 		sawcom = 1;
680*2931Sas145665 	return (0);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate #ifdef SIGCONT
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate  * When we wake up after ^Z, reprint the prompt.
6860Sstevel@tonic-gate  */
687*2931Sas145665 static void
6880Sstevel@tonic-gate #ifdef	__cplusplus
contin(int)6890Sstevel@tonic-gate contin(int)
6900Sstevel@tonic-gate #else
6910Sstevel@tonic-gate /* ARGSUSED */
6920Sstevel@tonic-gate contin(int s)
6930Sstevel@tonic-gate #endif
6940Sstevel@tonic-gate {
6950Sstevel@tonic-gate 	if (shudprompt)
6960Sstevel@tonic-gate 		printf("%s", prompt);
6970Sstevel@tonic-gate 	fflush(stdout);
6980Sstevel@tonic-gate }
6990Sstevel@tonic-gate #endif
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate /*
7020Sstevel@tonic-gate  * Branch here on hangup signal and simulate quit.
7030Sstevel@tonic-gate  */
704*2931Sas145665 void
7050Sstevel@tonic-gate #ifdef	__cplusplus
hangup(int)7060Sstevel@tonic-gate hangup(int)
7070Sstevel@tonic-gate #else
7080Sstevel@tonic-gate /* ARGSUSED */
7090Sstevel@tonic-gate hangup(int s)
7100Sstevel@tonic-gate #endif
7110Sstevel@tonic-gate {
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	holdsigs();
714*2931Sas145665 #ifdef OLD_BSD_SIGS
7150Sstevel@tonic-gate 	sigignore(SIGHUP);
716*2931Sas145665 #endif
7170Sstevel@tonic-gate 	if (edit) {
7180Sstevel@tonic-gate 		if (setjmp(srbuf))
7190Sstevel@tonic-gate 			exit(rpterr);
7200Sstevel@tonic-gate 		edstop(0);
7210Sstevel@tonic-gate 	} else {
7220Sstevel@tonic-gate 		if (issysmbox)
7230Sstevel@tonic-gate 			Verhogen();
7240Sstevel@tonic-gate 		if (value("exit") != NOSTR)
7250Sstevel@tonic-gate 			exit(1);
7260Sstevel@tonic-gate 		else
7270Sstevel@tonic-gate 			quit(0);
7280Sstevel@tonic-gate 	}
7290Sstevel@tonic-gate 	exit(rpterr);
7300Sstevel@tonic-gate }
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate /*
7330Sstevel@tonic-gate  * Set the size of the message vector used to construct argument
7340Sstevel@tonic-gate  * lists to message list functions.
7350Sstevel@tonic-gate  */
7360Sstevel@tonic-gate 
737*2931Sas145665 static void
setmsize(int sz)7380Sstevel@tonic-gate setmsize(int sz)
7390Sstevel@tonic-gate {
7400Sstevel@tonic-gate 
741*2931Sas145665 	if (msgvec != (int *)0)
7420Sstevel@tonic-gate 		free(msgvec);
7430Sstevel@tonic-gate 	if (sz < 1)
7440Sstevel@tonic-gate 		sz = 1; /* need at least one cell for terminating 0 */
7450Sstevel@tonic-gate 	if ((msgvec = (int *)
7460Sstevel@tonic-gate 	    calloc((unsigned)(sz + 1), sizeof (*msgvec))) == NULL)
7470Sstevel@tonic-gate 		panic("Failed to allocate memory for message vector");
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate /*
7510Sstevel@tonic-gate  * Find the correct command in the command table corresponding
7520Sstevel@tonic-gate  * to the passed command "word"
7530Sstevel@tonic-gate  */
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate static const struct cmd *
lex(char word[])7560Sstevel@tonic-gate lex(char word[])
7570Sstevel@tonic-gate {
7580Sstevel@tonic-gate 	register const struct cmd *cp;
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++)
7610Sstevel@tonic-gate 		if (isprefix(word, cp->c_name))
762*2931Sas145665 			return (cp);
763*2931Sas145665 	return (NONE);
7640Sstevel@tonic-gate }
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate /*
7670Sstevel@tonic-gate  * Determine if as1 is a valid prefix of as2.
7680Sstevel@tonic-gate  */
769*2931Sas145665 static int
isprefix(char * as1,char * as2)7700Sstevel@tonic-gate isprefix(char *as1, char *as2)
7710Sstevel@tonic-gate {
7720Sstevel@tonic-gate 	register char *s1, *s2;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	s1 = as1;
7750Sstevel@tonic-gate 	s2 = as2;
7760Sstevel@tonic-gate 	while (*s1++ == *s2)
7770Sstevel@tonic-gate 		if (*s2++ == '\0')
778*2931Sas145665 			return (1);
779*2931Sas145665 	return (*--s1 == '\0');
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate /*
7830Sstevel@tonic-gate  * The following gets called on receipt of a rubout.  This is
7840Sstevel@tonic-gate  * to abort printout of a command, mainly.
7850Sstevel@tonic-gate  * Dispatching here when command() is inactive crashes rcv.
7860Sstevel@tonic-gate  * Close all open files except 0, 1, 2, and the temporary.
7870Sstevel@tonic-gate  * The special call to getuserid() is needed so it won't get
7880Sstevel@tonic-gate  * annoyed about losing its open file.
7890Sstevel@tonic-gate  * Also, unstack all source files.
7900Sstevel@tonic-gate  */
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate static int	inithdr;		/* am printing startup headers */
7930Sstevel@tonic-gate 
794*2931Sas145665 void
stop(int s)7950Sstevel@tonic-gate stop(int s)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	register NODE *head;
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	noreset = 0;
8000Sstevel@tonic-gate 	if (!inithdr)
8010Sstevel@tonic-gate 		sawcom++;
8020Sstevel@tonic-gate 	inithdr = 0;
8030Sstevel@tonic-gate 	while (sourcing)
8040Sstevel@tonic-gate 		unstack();
805*2931Sas145665 	(void) getuserid((char *)0);
8060Sstevel@tonic-gate 	for (head = fplist; head != (NODE *)NULL; head = head->next) {
8070Sstevel@tonic-gate 		if (head->fp == stdin || head->fp == stdout)
8080Sstevel@tonic-gate 			continue;
8090Sstevel@tonic-gate 		if (head->fp == itf || head->fp == otf)
8100Sstevel@tonic-gate 			continue;
8110Sstevel@tonic-gate 		if (head->fp == stderr)
8120Sstevel@tonic-gate 			continue;
8130Sstevel@tonic-gate 		if (head->fp == semfp)
8140Sstevel@tonic-gate 			continue;
8150Sstevel@tonic-gate 		if (head->fp == pipef) {
8160Sstevel@tonic-gate 			npclose(pipef);
8170Sstevel@tonic-gate 			pipef = NULL;
8180Sstevel@tonic-gate 			continue;
8190Sstevel@tonic-gate 		}
8200Sstevel@tonic-gate 		fclose(head->fp);
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 	if (image >= 0) {
8230Sstevel@tonic-gate 		close(image);
8240Sstevel@tonic-gate 		image = -1;
8250Sstevel@tonic-gate 	}
8260Sstevel@tonic-gate 	if (s) {
8270Sstevel@tonic-gate 		fprintf(stderr, gettext("Interrupt\n"));
8280Sstevel@tonic-gate 		fflush(stderr);
829*2931Sas145665 #ifdef OLD_BSD_SIGS
8300Sstevel@tonic-gate 		sigrelse(s);
831*2931Sas145665 #endif
8320Sstevel@tonic-gate 	}
8330Sstevel@tonic-gate 	longjmp(srbuf, 1);
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate /*
8370Sstevel@tonic-gate  * Announce the presence of the current mailx version,
8380Sstevel@tonic-gate  * give the message count, and print a header listing.
8390Sstevel@tonic-gate  */
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate #define	GREETING	"%s  Type ? for help.\n"
8420Sstevel@tonic-gate 
843*2931Sas145665 void
announce(void)8440Sstevel@tonic-gate announce(void)
8450Sstevel@tonic-gate {
8460Sstevel@tonic-gate 	int vec[2], mdot;
8470Sstevel@tonic-gate 	extern const char *const version;
8480Sstevel@tonic-gate 
849*2931Sas145665 	if (!Hflag && value("quiet") == NOSTR)
8500Sstevel@tonic-gate 		printf(gettext(GREETING), version);
8510Sstevel@tonic-gate 	mdot = newfileinfo(1);
8520Sstevel@tonic-gate 	vec[0] = mdot;
8530Sstevel@tonic-gate 	vec[1] = 0;
8540Sstevel@tonic-gate 	dot = &message[mdot - 1];
8550Sstevel@tonic-gate 	if (msgCount > 0 && !noheader) {
8560Sstevel@tonic-gate 		inithdr++;
8570Sstevel@tonic-gate 		headers(vec);
8580Sstevel@tonic-gate 		inithdr = 0;
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate /*
8630Sstevel@tonic-gate  * Announce information about the file we are editing.
8640Sstevel@tonic-gate  * Return a likely place to set dot.
8650Sstevel@tonic-gate  */
866*2931Sas145665 int
newfileinfo(int start)8670Sstevel@tonic-gate newfileinfo(int start)
8680Sstevel@tonic-gate {
8690Sstevel@tonic-gate 	register struct message *mp;
8700Sstevel@tonic-gate 	register int u, n, mdot, d, s;
8710Sstevel@tonic-gate 	char fname[BUFSIZ], zname[BUFSIZ], *ename;
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	if (Hflag)
874*2931Sas145665 		return (1);		/* fake it--return message 1 */
8750Sstevel@tonic-gate 	for (mp = &message[start - 1]; mp < &message[msgCount]; mp++)
8760Sstevel@tonic-gate 		if ((mp->m_flag & (MNEW|MREAD)) == MNEW)
8770Sstevel@tonic-gate 			break;
8780Sstevel@tonic-gate 	if (mp >= &message[msgCount])
8790Sstevel@tonic-gate 		for (mp = &message[start - 1]; mp < &message[msgCount]; mp++)
8800Sstevel@tonic-gate 			if ((mp->m_flag & MREAD) == 0)
8810Sstevel@tonic-gate 				break;
8820Sstevel@tonic-gate 	if (mp < &message[msgCount])
8830Sstevel@tonic-gate 		mdot = mp - &message[0] + 1;
8840Sstevel@tonic-gate 	else
8850Sstevel@tonic-gate 		mdot = 1;
8860Sstevel@tonic-gate 	n = u = d = s = 0;
8870Sstevel@tonic-gate 	for (mp = &message[start - 1]; mp < &message[msgCount]; mp++) {
8880Sstevel@tonic-gate 		if (mp->m_flag & MNEW)
8890Sstevel@tonic-gate 			n++;
8900Sstevel@tonic-gate 		if ((mp->m_flag & MREAD) == 0)
8910Sstevel@tonic-gate 			u++;
8920Sstevel@tonic-gate 		if (mp->m_flag & MDELETED)
8930Sstevel@tonic-gate 			d++;
8940Sstevel@tonic-gate 		if (mp->m_flag & MSAVED)
8950Sstevel@tonic-gate 			s++;
8960Sstevel@tonic-gate 	}
897*2931Sas145665 	ename = origname;
8980Sstevel@tonic-gate 	if (getfold(fname) >= 0) {
8990Sstevel@tonic-gate 		nstrcat(fname, sizeof (fname), "/");
9000Sstevel@tonic-gate 		if (strncmp(fname, editfile, strlen(fname)) == 0) {
9010Sstevel@tonic-gate 			snprintf(zname, sizeof (zname),
9020Sstevel@tonic-gate 				"+%s", editfile + strlen(fname));
9030Sstevel@tonic-gate 			ename = zname;
9040Sstevel@tonic-gate 		}
9050Sstevel@tonic-gate 	}
9060Sstevel@tonic-gate 	printf("\"%s\": ", ename);
9070Sstevel@tonic-gate 	if (msgCount == 1)
9080Sstevel@tonic-gate 		printf(gettext("1 message"));
9090Sstevel@tonic-gate 	else
9100Sstevel@tonic-gate 		printf(gettext("%d messages"), msgCount);
9110Sstevel@tonic-gate 	if (n > 0)
9120Sstevel@tonic-gate 		printf(gettext(" %d new"), n);
9130Sstevel@tonic-gate 	if (u-n > 0)
9140Sstevel@tonic-gate 		printf(gettext(" %d unread"), u);
9150Sstevel@tonic-gate 	if (d > 0)
9160Sstevel@tonic-gate 		printf(gettext(" %d deleted"), d);
9170Sstevel@tonic-gate 	if (s > 0)
9180Sstevel@tonic-gate 		printf(gettext(" %d saved"), s);
9190Sstevel@tonic-gate 	if (readonly)
9200Sstevel@tonic-gate 		printf(gettext(" [Read only]"));
9210Sstevel@tonic-gate 	printf("\n");
922*2931Sas145665 	return (mdot);
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate /*
9260Sstevel@tonic-gate  * Print the current version number.
9270Sstevel@tonic-gate  */
9280Sstevel@tonic-gate 
929*2931Sas145665 int
9300Sstevel@tonic-gate #ifdef	__cplusplus
pversion(char *)9310Sstevel@tonic-gate pversion(char *)
9320Sstevel@tonic-gate #else
9330Sstevel@tonic-gate /* ARGSUSED */
9340Sstevel@tonic-gate pversion(char *s)
9350Sstevel@tonic-gate #endif
9360Sstevel@tonic-gate {
9370Sstevel@tonic-gate 	printf("%s\n", version);
938*2931Sas145665 	return (0);
9390Sstevel@tonic-gate }
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate /*
9420Sstevel@tonic-gate  * Load a file of user definitions.
9430Sstevel@tonic-gate  */
944*2931Sas145665 void
load(char * name)9450Sstevel@tonic-gate load(char *name)
9460Sstevel@tonic-gate {
9470Sstevel@tonic-gate 	register FILE *in, *oldin;
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	if ((in = fopen(name, "r")) == NULL)
9500Sstevel@tonic-gate 		return;
9510Sstevel@tonic-gate 	oldin = input;
9520Sstevel@tonic-gate 	input = in;
9530Sstevel@tonic-gate 	loading = 1;
9540Sstevel@tonic-gate 	sourcing = 1;
9550Sstevel@tonic-gate 	commands();
9560Sstevel@tonic-gate 	loading = 0;
9570Sstevel@tonic-gate 	sourcing = 0;
9580Sstevel@tonic-gate 	input = oldin;
9590Sstevel@tonic-gate 	fclose(in);
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate /*
9630Sstevel@tonic-gate  * Incorporate any new mail into the current session.
9640Sstevel@tonic-gate  *
9650Sstevel@tonic-gate  * XXX - Since autoinc works on "edited" files as well as the
9660Sstevel@tonic-gate  * system mailbox, this probably ought to as well.
9670Sstevel@tonic-gate  */
9680Sstevel@tonic-gate 
969*2931Sas145665 int
inc(void)9700Sstevel@tonic-gate inc(void)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate 	FILE *ibuf;
9730Sstevel@tonic-gate 	int mdot;
9740Sstevel@tonic-gate 	struct stat stbuf;
9750Sstevel@tonic-gate 	int firstnewmsg = msgCount + 1;
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	if (edit) {
9780Sstevel@tonic-gate 		fprintf(stderr, gettext("Not in system mailbox\n"));
979*2931Sas145665 		return (-1);
9800Sstevel@tonic-gate 	}
9810Sstevel@tonic-gate 	if (((ibuf = fopen(mailname, "r")) == NULL) ||
9820Sstevel@tonic-gate 	    (fstat(fileno(ibuf), &stbuf) < 0) || stbuf.st_size == 0L ||
9830Sstevel@tonic-gate 	    stbuf.st_size == mailsize || (stbuf.st_mode&S_IFMT) != S_IFREG) {
9840Sstevel@tonic-gate 		if (strrchr(mailname, '/') == NOSTR)
9850Sstevel@tonic-gate 			fprintf(stderr, gettext("No new mail.\n"));
9860Sstevel@tonic-gate 		else
9870Sstevel@tonic-gate 			fprintf(stderr, gettext("No new mail for %s\n"),
9880Sstevel@tonic-gate 			    strrchr(mailname, '/')+1);
9890Sstevel@tonic-gate 		if (ibuf != NULL)
9900Sstevel@tonic-gate 			fclose(ibuf);
991*2931Sas145665 		return (-1);
9920Sstevel@tonic-gate 	}
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	fseek(otf, 0L, 2);
9950Sstevel@tonic-gate 	holdsigs();
9960Sstevel@tonic-gate 	if (issysmbox)
9970Sstevel@tonic-gate 		lockmail();
9980Sstevel@tonic-gate 	fseek(ibuf, mailsize, 0);
9990Sstevel@tonic-gate 	mailsize = fsize(ibuf);
10000Sstevel@tonic-gate 	setptr(ibuf);
10010Sstevel@tonic-gate 	setmsize(msgCount);
10020Sstevel@tonic-gate 	fclose(ibuf);
10030Sstevel@tonic-gate 	if (issysmbox)
10040Sstevel@tonic-gate 		unlockmail();
10050Sstevel@tonic-gate 	relsesigs();
10060Sstevel@tonic-gate 	mdot = newfileinfo(firstnewmsg);
10070Sstevel@tonic-gate 	dot = &message[mdot - 1];
10080Sstevel@tonic-gate 	sawcom = 0;
1009*2931Sas145665 	return (0);
10100Sstevel@tonic-gate }
1011