17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5eb2b0a61Sas * Common Development and Distribution License (the "License").
6eb2b0a61Sas * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate
227c478bd9Sstevel@tonic-gate /*
23eb2b0a61Sas * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
2548bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
28eb2b0a61Sas /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29eb2b0a61Sas /* All Rights Reserved */
30eb2b0a61Sas
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
337c478bd9Sstevel@tonic-gate * The Regents of the University of California
347c478bd9Sstevel@tonic-gate * All Rights Reserved
357c478bd9Sstevel@tonic-gate *
367c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
377c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
387c478bd9Sstevel@tonic-gate * contributors.
397c478bd9Sstevel@tonic-gate */
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate #include "rcv.h"
427c478bd9Sstevel@tonic-gate #include <locale.h>
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate * mailx -- a modified version of a University of California at Berkeley
467c478bd9Sstevel@tonic-gate * mail program
477c478bd9Sstevel@tonic-gate *
487c478bd9Sstevel@tonic-gate * Lexical processing of commands.
497c478bd9Sstevel@tonic-gate */
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate #ifdef SIGCONT
527c478bd9Sstevel@tonic-gate static void contin(int);
537c478bd9Sstevel@tonic-gate #endif
547c478bd9Sstevel@tonic-gate static int isprefix(char *as1, char *as2);
557c478bd9Sstevel@tonic-gate static const struct cmd *lex(char word[]);
567c478bd9Sstevel@tonic-gate static int Passeren(void);
577c478bd9Sstevel@tonic-gate static void setmsize(int sz);
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate * Set up editing on the given file name.
617c478bd9Sstevel@tonic-gate * If isedit is true, we are considered to be editing the file,
627c478bd9Sstevel@tonic-gate * otherwise we are reading our mail which has signficance for
637c478bd9Sstevel@tonic-gate * mbox and so forth.
647c478bd9Sstevel@tonic-gate */
657c478bd9Sstevel@tonic-gate
66eb2b0a61Sas int
setfile(char * name,int isedit)677c478bd9Sstevel@tonic-gate setfile(char *name, int isedit)
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate FILE *ibuf;
707c478bd9Sstevel@tonic-gate int i;
717c478bd9Sstevel@tonic-gate static int shudclob;
727c478bd9Sstevel@tonic-gate static char efile[PATHSIZE];
737c478bd9Sstevel@tonic-gate char fortest[128];
747c478bd9Sstevel@tonic-gate struct stat stbuf;
757c478bd9Sstevel@tonic-gate int exrc = 1;
767c478bd9Sstevel@tonic-gate int rc = -1;
777c478bd9Sstevel@tonic-gate int fd = -1;
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate if (!isedit && issysmbox)
807c478bd9Sstevel@tonic-gate lockmail();
817c478bd9Sstevel@tonic-gate if (stat(name, &stbuf) < 0 && errno == EOVERFLOW) {
827c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("mailbox %s is too large to"
837c478bd9Sstevel@tonic-gate " accept incoming mail\n"), name);
847c478bd9Sstevel@tonic-gate goto doret;
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate if ((ibuf = fopen(name, "r")) == NULL) {
87eb2b0a61Sas extern int errno;
887c478bd9Sstevel@tonic-gate int sverrno = errno;
89eb2b0a61Sas int filethere = (access(name, 0) == 0);
907c478bd9Sstevel@tonic-gate errno = sverrno;
917c478bd9Sstevel@tonic-gate if (exitflg)
927c478bd9Sstevel@tonic-gate goto doexit; /* no mail, return error */
937c478bd9Sstevel@tonic-gate if (isedit || filethere)
947c478bd9Sstevel@tonic-gate perror(name);
957c478bd9Sstevel@tonic-gate else if (!Hflag) {
96eb2b0a61Sas char *f = strrchr(name, '/');
977c478bd9Sstevel@tonic-gate if (f == NOSTR)
987c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("No mail.\n"));
997c478bd9Sstevel@tonic-gate else
1007c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("No mail for %s\n"),
101*13539f0dSToomas Soome f+1);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate goto doret;
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate fstat(fileno(ibuf), &stbuf);
1067c478bd9Sstevel@tonic-gate if (stbuf.st_size == 0L || (stbuf.st_mode&S_IFMT) != S_IFREG) {
1077c478bd9Sstevel@tonic-gate if (exitflg)
1087c478bd9Sstevel@tonic-gate goto doexit; /* no mail, return error */
1097c478bd9Sstevel@tonic-gate if (isedit)
1107c478bd9Sstevel@tonic-gate if (stbuf.st_size == 0L)
1117c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("%s: empty file\n"),
112*13539f0dSToomas Soome name);
1137c478bd9Sstevel@tonic-gate else
1147c478bd9Sstevel@tonic-gate fprintf(stderr,
1157c478bd9Sstevel@tonic-gate gettext("%s: not a regular file\n"), name);
1167c478bd9Sstevel@tonic-gate else if (!Hflag) {
117eb2b0a61Sas if (strrchr(name, '/') == NOSTR)
1187c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("No mail.\n"));
1197c478bd9Sstevel@tonic-gate else
1207c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("No mail for %s\n"),
121*13539f0dSToomas Soome strrchr(name, '/') + 1);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate fclose(ibuf);
1247c478bd9Sstevel@tonic-gate goto doret;
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate
127eb2b0a61Sas if (fgets(fortest, sizeof (fortest), ibuf) == NULL) {
128eb2b0a61Sas perror(gettext("mailx: Unable to read from mail file"));
129eb2b0a61Sas goto doexit;
130eb2b0a61Sas }
131eb2b0a61Sas
1327c478bd9Sstevel@tonic-gate fseek(ibuf, (long)(BUFSIZ+1), 0); /* flush input buffer */
1337c478bd9Sstevel@tonic-gate fseek(ibuf, 0L, 0);
1347c478bd9Sstevel@tonic-gate if (strncmp(fortest, "Forward to ", 11) == 0) {
1357c478bd9Sstevel@tonic-gate if (exitflg)
1367c478bd9Sstevel@tonic-gate goto doexit; /* no mail, return error */
1377c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Your mail is being forwarded to %s"),
138*13539f0dSToomas Soome fortest+11);
1397c478bd9Sstevel@tonic-gate fclose(ibuf);
1407c478bd9Sstevel@tonic-gate goto doret;
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate if (exitflg) {
1437c478bd9Sstevel@tonic-gate exrc = 0;
1447c478bd9Sstevel@tonic-gate goto doexit; /* there is mail, return success */
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate * Looks like all will be well. Must hold signals
1497c478bd9Sstevel@tonic-gate * while we are reading the new file, else we will ruin
1507c478bd9Sstevel@tonic-gate * the message[] data structure.
1517c478bd9Sstevel@tonic-gate * Copy the messages into /tmp and set pointers.
1527c478bd9Sstevel@tonic-gate */
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate holdsigs();
1557c478bd9Sstevel@tonic-gate if (shudclob) {
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate * Now that we know we can switch to the new file
1587c478bd9Sstevel@tonic-gate * it's safe to close out the current file.
1597c478bd9Sstevel@tonic-gate *
1607c478bd9Sstevel@tonic-gate * If we're switching to the file we are currently
1617c478bd9Sstevel@tonic-gate * editing, don't allow it to be removed as a side
1627c478bd9Sstevel@tonic-gate * effect of closing it out.
1637c478bd9Sstevel@tonic-gate */
1647c478bd9Sstevel@tonic-gate if (edit)
1657c478bd9Sstevel@tonic-gate edstop(strcmp(editfile, name) == 0);
1667c478bd9Sstevel@tonic-gate else {
1677c478bd9Sstevel@tonic-gate quit(strcmp(editfile, name) == 0);
1687c478bd9Sstevel@tonic-gate if (issysmbox)
1697c478bd9Sstevel@tonic-gate Verhogen();
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate fflush(stdout);
1727c478bd9Sstevel@tonic-gate fclose(itf);
1737c478bd9Sstevel@tonic-gate fclose(otf);
1747c478bd9Sstevel@tonic-gate free(message);
175eb2b0a61Sas space = 0;
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate readonly = 0;
1787c478bd9Sstevel@tonic-gate if (!isedit && issysmbox && !Hflag)
179eb2b0a61Sas readonly = Passeren() == -1;
1807c478bd9Sstevel@tonic-gate lock(ibuf, "r", 1);
1817c478bd9Sstevel@tonic-gate fstat(fileno(ibuf), &stbuf);
1827c478bd9Sstevel@tonic-gate utimep->actime = stbuf.st_atime;
1837c478bd9Sstevel@tonic-gate utimep->modtime = stbuf.st_mtime;
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate if (!readonly)
1867c478bd9Sstevel@tonic-gate if ((i = open(name, O_WRONLY)) < 0)
1877c478bd9Sstevel@tonic-gate readonly++;
1887c478bd9Sstevel@tonic-gate else
1897c478bd9Sstevel@tonic-gate close(i);
1907c478bd9Sstevel@tonic-gate shudclob = 1;
1917c478bd9Sstevel@tonic-gate edit = isedit;
1927c478bd9Sstevel@tonic-gate nstrcpy(efile, PATHSIZE, name);
1937c478bd9Sstevel@tonic-gate editfile = efile;
1947c478bd9Sstevel@tonic-gate #ifdef notdef
1957c478bd9Sstevel@tonic-gate if (name != mailname)
1967c478bd9Sstevel@tonic-gate nstrcpy(mailname, PATHSIZE, name);
1977c478bd9Sstevel@tonic-gate #endif
1987c478bd9Sstevel@tonic-gate mailsize = fsize(ibuf);
1997c478bd9Sstevel@tonic-gate if ((fd = open(tempMesg, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
200*13539f0dSToomas Soome (otf = fdopen(fd, "w")) == NULL) {
2017c478bd9Sstevel@tonic-gate perror(tempMesg);
2027c478bd9Sstevel@tonic-gate if (!edit && issysmbox)
2037c478bd9Sstevel@tonic-gate Verhogen();
2047c478bd9Sstevel@tonic-gate goto doexit;
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate if ((itf = fopen(tempMesg, "r")) == NULL) {
2077c478bd9Sstevel@tonic-gate perror(tempMesg);
2087c478bd9Sstevel@tonic-gate if (!edit && issysmbox)
2097c478bd9Sstevel@tonic-gate Verhogen();
2107c478bd9Sstevel@tonic-gate goto doexit;
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate removefile(tempMesg);
2137c478bd9Sstevel@tonic-gate setptr(ibuf);
2147c478bd9Sstevel@tonic-gate setmsize(msgCount);
2157c478bd9Sstevel@tonic-gate fclose(ibuf);
2167c478bd9Sstevel@tonic-gate relsesigs();
2177c478bd9Sstevel@tonic-gate sawcom = 0;
2187c478bd9Sstevel@tonic-gate rc = 0;
2197c478bd9Sstevel@tonic-gate
220eb2b0a61Sas doret:
2217c478bd9Sstevel@tonic-gate if (!isedit && issysmbox)
2227c478bd9Sstevel@tonic-gate unlockmail();
223eb2b0a61Sas return (rc);
2247c478bd9Sstevel@tonic-gate
225eb2b0a61Sas doexit:
2267c478bd9Sstevel@tonic-gate if (!isedit && issysmbox)
2277c478bd9Sstevel@tonic-gate unlockmail();
2287c478bd9Sstevel@tonic-gate exit(exrc ? exrc : rpterr);
2297c478bd9Sstevel@tonic-gate /* NOTREACHED */
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate /* global to semaphores */
2337c478bd9Sstevel@tonic-gate static char semfn[128];
2347c478bd9Sstevel@tonic-gate static FILE *semfp = NULL;
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate /*
2377c478bd9Sstevel@tonic-gate * return -1 if file is already being read, 0 otherwise
2387c478bd9Sstevel@tonic-gate */
2397c478bd9Sstevel@tonic-gate static int
Passeren(void)2407c478bd9Sstevel@tonic-gate Passeren(void)
2417c478bd9Sstevel@tonic-gate {
2427c478bd9Sstevel@tonic-gate char *home;
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate if ((home = getenv("HOME")) == NULL)
245eb2b0a61Sas return (0);
246eb2b0a61Sas snprintf(semfn, sizeof (semfn), "%s%s", home, "/.Maillock");
2477c478bd9Sstevel@tonic-gate if ((semfp = fopen(semfn, "w")) == NULL) {
2487c478bd9Sstevel@tonic-gate fprintf(stderr,
2497c478bd9Sstevel@tonic-gate gettext("WARNING: Can't open mail lock file (%s).\n"), semfn);
2507c478bd9Sstevel@tonic-gate fprintf(stderr,
2517c478bd9Sstevel@tonic-gate gettext("\t Assuming you are not already reading mail.\n"));
252eb2b0a61Sas return (0);
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate if (lock(semfp, "w", 0) < 0) {
2557c478bd9Sstevel@tonic-gate if (errno == ENOLCK) {
2567c478bd9Sstevel@tonic-gate fprintf(stderr,
2577c478bd9Sstevel@tonic-gate gettext("WARNING: Unable to acquire mail lock, no record locks available.\n"));
2587c478bd9Sstevel@tonic-gate fprintf(stderr,
2597c478bd9Sstevel@tonic-gate gettext("\t Assuming you are not already reading mail.\n"));
260eb2b0a61Sas return (0);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate fprintf(stderr,
2637c478bd9Sstevel@tonic-gate gettext("WARNING: You are already reading mail.\n"));
2647c478bd9Sstevel@tonic-gate fprintf(stderr,
2657c478bd9Sstevel@tonic-gate gettext("\t This instance of mail is read only.\n"));
2667c478bd9Sstevel@tonic-gate fclose(semfp);
2677c478bd9Sstevel@tonic-gate semfp = NULL;
268eb2b0a61Sas return (-1);
2697c478bd9Sstevel@tonic-gate }
270eb2b0a61Sas return (0);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate
273eb2b0a61Sas void
Verhogen(void)2747c478bd9Sstevel@tonic-gate Verhogen(void)
2757c478bd9Sstevel@tonic-gate {
2767c478bd9Sstevel@tonic-gate if (semfp != NULL) {
2777c478bd9Sstevel@tonic-gate unlink(semfn);
2787c478bd9Sstevel@tonic-gate fclose(semfp);
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate * Interpret user commands one by one. If standard input is not a tty,
2847c478bd9Sstevel@tonic-gate * print no prompt.
2857c478bd9Sstevel@tonic-gate */
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate static int *msgvec;
2887c478bd9Sstevel@tonic-gate static int shudprompt;
2897c478bd9Sstevel@tonic-gate
290eb2b0a61Sas void
commands(void)2917c478bd9Sstevel@tonic-gate commands(void)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate int eofloop;
29446d64c14SToomas Soome int n;
2957c478bd9Sstevel@tonic-gate char linebuf[LINESIZE];
2967c478bd9Sstevel@tonic-gate char line[LINESIZE];
2977c478bd9Sstevel@tonic-gate struct stat minfo;
2987c478bd9Sstevel@tonic-gate FILE *ibuf;
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate #ifdef SIGCONT
3017c478bd9Sstevel@tonic-gate sigset(SIGCONT, SIG_DFL);
3027c478bd9Sstevel@tonic-gate #endif
3037c478bd9Sstevel@tonic-gate if (rcvmode && !sourcing) {
3047c478bd9Sstevel@tonic-gate if (sigset(SIGINT, SIG_IGN) != SIG_IGN)
3057c478bd9Sstevel@tonic-gate sigset(SIGINT, stop);
3067c478bd9Sstevel@tonic-gate if (sigset(SIGHUP, SIG_IGN) != SIG_IGN)
3077c478bd9Sstevel@tonic-gate sigset(SIGHUP, hangup);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate for (;;) {
3107c478bd9Sstevel@tonic-gate setjmp(srbuf);
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate /*
3137c478bd9Sstevel@tonic-gate * Print the prompt, if needed. Clear out
3147c478bd9Sstevel@tonic-gate * string space, and flush the output.
3157c478bd9Sstevel@tonic-gate */
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate if (!rcvmode && !sourcing)
3187c478bd9Sstevel@tonic-gate return;
3197c478bd9Sstevel@tonic-gate eofloop = 0;
3207c478bd9Sstevel@tonic-gate top:
3217c478bd9Sstevel@tonic-gate if ((shudprompt = (intty && !sourcing)) != 0) {
322eb2b0a61Sas if (prompt == NOSTR) {
3237c478bd9Sstevel@tonic-gate if ((int)value("bsdcompat"))
3247c478bd9Sstevel@tonic-gate prompt = "& ";
3257c478bd9Sstevel@tonic-gate else
326eb2b0a61Sas prompt = "";
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate #ifdef SIGCONT
3297c478bd9Sstevel@tonic-gate sigset(SIGCONT, contin);
3307c478bd9Sstevel@tonic-gate #endif
3317c478bd9Sstevel@tonic-gate if (intty && value("autoinc") &&
332eb2b0a61Sas stat(editfile, &minfo) >= 0 &&
3337c478bd9Sstevel@tonic-gate minfo.st_size > mailsize) {
3347c478bd9Sstevel@tonic-gate int OmsgCount, i;
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate OmsgCount = msgCount;
3377c478bd9Sstevel@tonic-gate fseek(otf, 0L, 2);
3387c478bd9Sstevel@tonic-gate holdsigs();
3397c478bd9Sstevel@tonic-gate if (!edit && issysmbox)
3407c478bd9Sstevel@tonic-gate lockmail();
341eb2b0a61Sas if ((ibuf = fopen(editfile, "r")) == NULL) {
3427c478bd9Sstevel@tonic-gate fprintf(stderr,
3437c478bd9Sstevel@tonic-gate gettext("Can't reopen %s\n"),
3447c478bd9Sstevel@tonic-gate editfile);
3457c478bd9Sstevel@tonic-gate if (!edit && issysmbox)
3467c478bd9Sstevel@tonic-gate unlockmail();
3477c478bd9Sstevel@tonic-gate exit(1);
3487c478bd9Sstevel@tonic-gate /* NOTREACHED */
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate if (edit || !issysmbox)
3517c478bd9Sstevel@tonic-gate lock(ibuf, "r", 1);
3527c478bd9Sstevel@tonic-gate fseek(ibuf, mailsize, 0);
3537c478bd9Sstevel@tonic-gate mailsize = fsize(ibuf);
3547c478bd9Sstevel@tonic-gate setptr(ibuf);
3557c478bd9Sstevel@tonic-gate setmsize(msgCount);
3567c478bd9Sstevel@tonic-gate fclose(ibuf);
3577c478bd9Sstevel@tonic-gate if (!edit && issysmbox)
3587c478bd9Sstevel@tonic-gate unlockmail();
3597c478bd9Sstevel@tonic-gate if (msgCount-OmsgCount > 0) {
3607c478bd9Sstevel@tonic-gate printf(gettext(
3617c478bd9Sstevel@tonic-gate "New mail has arrived.\n"));
3627c478bd9Sstevel@tonic-gate if (msgCount - OmsgCount == 1)
3637c478bd9Sstevel@tonic-gate printf(gettext(
3647c478bd9Sstevel@tonic-gate "Loaded 1 new message\n"));
3657c478bd9Sstevel@tonic-gate else
3667c478bd9Sstevel@tonic-gate printf(gettext(
3677c478bd9Sstevel@tonic-gate "Loaded %d new messages\n"),
3687c478bd9Sstevel@tonic-gate msgCount-OmsgCount);
3697c478bd9Sstevel@tonic-gate if (value("header") != NOSTR)
3707c478bd9Sstevel@tonic-gate for (i = OmsgCount+1;
371eb2b0a61Sas i <= msgCount; i++) {
3727c478bd9Sstevel@tonic-gate printhead(i);
3737c478bd9Sstevel@tonic-gate sreset();
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate relsesigs();
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate printf("%s", prompt);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate flush();
3817c478bd9Sstevel@tonic-gate sreset();
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate * Read a line of commands from the current input
3857c478bd9Sstevel@tonic-gate * and handle end of file specially.
3867c478bd9Sstevel@tonic-gate */
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate n = 0;
3897c478bd9Sstevel@tonic-gate linebuf[0] = '\0';
3907c478bd9Sstevel@tonic-gate for (;;) {
3917c478bd9Sstevel@tonic-gate if (readline(input, line) <= 0) {
3927c478bd9Sstevel@tonic-gate if (n != 0)
3937c478bd9Sstevel@tonic-gate break;
3947c478bd9Sstevel@tonic-gate if (loading)
3957c478bd9Sstevel@tonic-gate return;
3967c478bd9Sstevel@tonic-gate if (sourcing) {
3977c478bd9Sstevel@tonic-gate unstack();
3987c478bd9Sstevel@tonic-gate goto more;
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate if (value("ignoreeof") != NOSTR && shudprompt) {
4017c478bd9Sstevel@tonic-gate if (++eofloop < 25) {
4027c478bd9Sstevel@tonic-gate printf(gettext(
4037c478bd9Sstevel@tonic-gate "Use \"quit\" to quit.\n"));
4047c478bd9Sstevel@tonic-gate goto top;
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate return;
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate if ((n = strlen(line)) == 0)
4107c478bd9Sstevel@tonic-gate break;
4117c478bd9Sstevel@tonic-gate n--;
4127c478bd9Sstevel@tonic-gate if (line[n] != '\\')
4137c478bd9Sstevel@tonic-gate break;
4147c478bd9Sstevel@tonic-gate line[n++] = ' ';
4157c478bd9Sstevel@tonic-gate if (n > LINESIZE - (int)strlen(linebuf) - 1)
4167c478bd9Sstevel@tonic-gate break;
4177c478bd9Sstevel@tonic-gate strcat(linebuf, line);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate n = LINESIZE - strlen(linebuf) - 1;
4207c478bd9Sstevel@tonic-gate if ((int)strlen(line) > n) {
4217c478bd9Sstevel@tonic-gate printf(gettext(
4227c478bd9Sstevel@tonic-gate "Line plus continuation line too long:\n\t%s\n\nplus\n\t%s\n"),
4237c478bd9Sstevel@tonic-gate linebuf, line);
4247c478bd9Sstevel@tonic-gate if (loading)
4257c478bd9Sstevel@tonic-gate return;
4267c478bd9Sstevel@tonic-gate if (sourcing) {
4277c478bd9Sstevel@tonic-gate unstack();
4287c478bd9Sstevel@tonic-gate goto more;
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate return;
4317c478bd9Sstevel@tonic-gate }
432eb2b0a61Sas strncat(linebuf, line, n);
4337c478bd9Sstevel@tonic-gate #ifdef SIGCONT
4347c478bd9Sstevel@tonic-gate sigset(SIGCONT, SIG_DFL);
4357c478bd9Sstevel@tonic-gate #endif
4367c478bd9Sstevel@tonic-gate if (execute(linebuf, 0))
4377c478bd9Sstevel@tonic-gate return;
438eb2b0a61Sas more:;
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate /*
4437c478bd9Sstevel@tonic-gate * Execute a single command. If the command executed
4447c478bd9Sstevel@tonic-gate * is "quit," then return non-zero so that the caller
44548bbca81SDaniel Hoffman * will know to return back to main, if it cares.
4467c478bd9Sstevel@tonic-gate * Contxt is non-zero if called while composing mail.
4477c478bd9Sstevel@tonic-gate */
4487c478bd9Sstevel@tonic-gate
449eb2b0a61Sas int
execute(char linebuf[],int contxt)4507c478bd9Sstevel@tonic-gate execute(char linebuf[], int contxt)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate char word[LINESIZE];
4537c478bd9Sstevel@tonic-gate char *arglist[MAXARGC];
4547c478bd9Sstevel@tonic-gate const struct cmd *com;
45546d64c14SToomas Soome char *cp, *cp2;
45646d64c14SToomas Soome int c, e;
4577c478bd9Sstevel@tonic-gate int muvec[2];
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate /*
4607c478bd9Sstevel@tonic-gate * Strip the white space away from the beginning
4617c478bd9Sstevel@tonic-gate * of the command, then scan out a word, which
4627c478bd9Sstevel@tonic-gate * consists of anything except digits and white space.
4637c478bd9Sstevel@tonic-gate *
4647c478bd9Sstevel@tonic-gate * Handle |, ! and # differently to get the correct
4657c478bd9Sstevel@tonic-gate * lexical conventions.
4667c478bd9Sstevel@tonic-gate */
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate cp = linebuf;
4697c478bd9Sstevel@tonic-gate while (any(*cp, " \t"))
4707c478bd9Sstevel@tonic-gate cp++;
4717c478bd9Sstevel@tonic-gate cp2 = word;
4727c478bd9Sstevel@tonic-gate if (any(*cp, "!|#"))
4737c478bd9Sstevel@tonic-gate *cp2++ = *cp++;
4747c478bd9Sstevel@tonic-gate else
4757c478bd9Sstevel@tonic-gate while (*cp && !any(*cp, " \t0123456789$^.:/-+*'\""))
4767c478bd9Sstevel@tonic-gate *cp2++ = *cp++;
4777c478bd9Sstevel@tonic-gate *cp2 = '\0';
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate * Look up the command; if not found, complain.
4817c478bd9Sstevel@tonic-gate * Normally, a blank command would map to the
4827c478bd9Sstevel@tonic-gate * first command in the table; while sourcing,
4837c478bd9Sstevel@tonic-gate * however, we ignore blank lines to eliminate
4847c478bd9Sstevel@tonic-gate * confusion.
4857c478bd9Sstevel@tonic-gate */
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate if (sourcing && equal(word, ""))
488eb2b0a61Sas return (0);
4897c478bd9Sstevel@tonic-gate com = lex(word);
4907c478bd9Sstevel@tonic-gate if (com == NONE) {
4917c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Unknown command: \"%s\"\n"), word);
4927c478bd9Sstevel@tonic-gate if (loading) {
4937c478bd9Sstevel@tonic-gate cond = CANY;
494eb2b0a61Sas return (1);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate if (sourcing) {
4977c478bd9Sstevel@tonic-gate cond = CANY;
4987c478bd9Sstevel@tonic-gate unstack();
4997c478bd9Sstevel@tonic-gate }
500eb2b0a61Sas return (0);
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate
5037c478bd9Sstevel@tonic-gate /*
5047c478bd9Sstevel@tonic-gate * See if we should execute the command -- if a conditional
5057c478bd9Sstevel@tonic-gate * we always execute it, otherwise, check the state of cond.
5067c478bd9Sstevel@tonic-gate */
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate if ((com->c_argtype & F) == 0)
5097c478bd9Sstevel@tonic-gate if (cond == CRCV && !rcvmode || cond == CSEND && rcvmode ||
5107c478bd9Sstevel@tonic-gate cond == CTTY && !intty || cond == CNOTTY && intty)
511eb2b0a61Sas return (0);
5127c478bd9Sstevel@tonic-gate
5137c478bd9Sstevel@tonic-gate /*
5147c478bd9Sstevel@tonic-gate * Special case so that quit causes a return to
5157c478bd9Sstevel@tonic-gate * main, who will call the quit code directly.
5167c478bd9Sstevel@tonic-gate * If we are in a source file, just unstack.
5177c478bd9Sstevel@tonic-gate */
5187c478bd9Sstevel@tonic-gate
519*13539f0dSToomas Soome if ((uintptr_t)com->c_func == (uintptr_t)edstop) {
5207c478bd9Sstevel@tonic-gate if (sourcing) {
5217c478bd9Sstevel@tonic-gate if (loading)
522eb2b0a61Sas return (1);
5237c478bd9Sstevel@tonic-gate unstack();
524eb2b0a61Sas return (0);
5257c478bd9Sstevel@tonic-gate }
526eb2b0a61Sas return (1);
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate /*
5307c478bd9Sstevel@tonic-gate * Process the arguments to the command, depending
53148bbca81SDaniel Hoffman * on the type it expects. Default to an error.
5327c478bd9Sstevel@tonic-gate * If we are sourcing an interactive command, it's
5337c478bd9Sstevel@tonic-gate * an error.
5347c478bd9Sstevel@tonic-gate */
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate if (!rcvmode && (com->c_argtype & M) == 0) {
5377c478bd9Sstevel@tonic-gate fprintf(stderr,
5387c478bd9Sstevel@tonic-gate gettext("May not execute \"%s\" while sending\n"),
5397c478bd9Sstevel@tonic-gate com->c_name);
5407c478bd9Sstevel@tonic-gate if (loading)
541eb2b0a61Sas return (1);
5427c478bd9Sstevel@tonic-gate if (sourcing)
5437c478bd9Sstevel@tonic-gate unstack();
544eb2b0a61Sas return (0);
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate if (sourcing && com->c_argtype & I) {
5477c478bd9Sstevel@tonic-gate fprintf(stderr,
5487c478bd9Sstevel@tonic-gate gettext("May not execute \"%s\" while sourcing\n"),
5497c478bd9Sstevel@tonic-gate com->c_name);
5507c478bd9Sstevel@tonic-gate rpterr = 1;
5517c478bd9Sstevel@tonic-gate if (loading)
552eb2b0a61Sas return (1);
5537c478bd9Sstevel@tonic-gate unstack();
554eb2b0a61Sas return (0);
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate if (readonly && com->c_argtype & W) {
5577c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(
5587c478bd9Sstevel@tonic-gate "May not execute \"%s\" -- message file is read only\n"),
5597c478bd9Sstevel@tonic-gate com->c_name);
5607c478bd9Sstevel@tonic-gate if (loading)
561eb2b0a61Sas return (1);
5627c478bd9Sstevel@tonic-gate if (sourcing)
5637c478bd9Sstevel@tonic-gate unstack();
564eb2b0a61Sas return (0);
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate if (contxt && com->c_argtype & R) {
5677c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Cannot recursively invoke \"%s\"\n"),
5687c478bd9Sstevel@tonic-gate com->c_name);
569eb2b0a61Sas return (0);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate e = 1;
5727c478bd9Sstevel@tonic-gate switch (com->c_argtype & ~(F|P|I|M|T|W|R)) {
5737c478bd9Sstevel@tonic-gate case MSGLIST:
5747c478bd9Sstevel@tonic-gate /*
5757c478bd9Sstevel@tonic-gate * A message list defaulting to nearest forward
5767c478bd9Sstevel@tonic-gate * legal message.
5777c478bd9Sstevel@tonic-gate */
5787c478bd9Sstevel@tonic-gate if (msgvec == 0) {
5797c478bd9Sstevel@tonic-gate fprintf(stderr,
5807c478bd9Sstevel@tonic-gate gettext("Illegal use of \"message list\"\n"));
581eb2b0a61Sas return (-1);
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0)
5847c478bd9Sstevel@tonic-gate break;
5857c478bd9Sstevel@tonic-gate if (c == 0)
5867c478bd9Sstevel@tonic-gate if (msgCount == 0)
58746d64c14SToomas Soome *msgvec = 0;
5887c478bd9Sstevel@tonic-gate else {
5897c478bd9Sstevel@tonic-gate *msgvec = first(com->c_msgflag,
590*13539f0dSToomas Soome com->c_msgmask);
59146d64c14SToomas Soome msgvec[1] = 0;
5927c478bd9Sstevel@tonic-gate }
59346d64c14SToomas Soome if (*msgvec == 0) {
5947c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("No applicable messages\n"));
5957c478bd9Sstevel@tonic-gate break;
5967c478bd9Sstevel@tonic-gate }
5977c478bd9Sstevel@tonic-gate e = (*com->c_func)(msgvec);
5987c478bd9Sstevel@tonic-gate break;
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate case NDMLIST:
6017c478bd9Sstevel@tonic-gate /*
602eb2b0a61Sas * A message operand with no defaults, but no error
603eb2b0a61Sas * if none exists. There will be an error if the
604eb2b0a61Sas * msgvec pointer is of zero value.
6057c478bd9Sstevel@tonic-gate */
6067c478bd9Sstevel@tonic-gate if (msgvec == 0) {
6077c478bd9Sstevel@tonic-gate fprintf(stderr,
608eb2b0a61Sas gettext("Illegal use of \"message operand\"\n"));
609eb2b0a61Sas return (-1);
6107c478bd9Sstevel@tonic-gate }
611eb2b0a61Sas if (getmessage(cp, msgvec, com->c_msgflag) < 0)
6127c478bd9Sstevel@tonic-gate break;
6137c478bd9Sstevel@tonic-gate e = (*com->c_func)(msgvec);
6147c478bd9Sstevel@tonic-gate break;
6157c478bd9Sstevel@tonic-gate
6167c478bd9Sstevel@tonic-gate case STRLIST:
6177c478bd9Sstevel@tonic-gate /*
6187c478bd9Sstevel@tonic-gate * Just the straight string, with
6197c478bd9Sstevel@tonic-gate * leading blanks removed.
6207c478bd9Sstevel@tonic-gate */
6217c478bd9Sstevel@tonic-gate while (any(*cp, " \t"))
6227c478bd9Sstevel@tonic-gate cp++;
6237c478bd9Sstevel@tonic-gate e = (*com->c_func)(cp);
6247c478bd9Sstevel@tonic-gate break;
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate case RAWLIST:
6277c478bd9Sstevel@tonic-gate /*
6287c478bd9Sstevel@tonic-gate * A vector of strings, in shell style.
6297c478bd9Sstevel@tonic-gate */
6307c478bd9Sstevel@tonic-gate if ((c = getrawlist(cp, arglist,
631*13539f0dSToomas Soome sizeof (arglist) / sizeof (*arglist))) < 0)
6327c478bd9Sstevel@tonic-gate break;
6337c478bd9Sstevel@tonic-gate if (c < com->c_minargs) {
6347c478bd9Sstevel@tonic-gate fprintf(stderr,
6357c478bd9Sstevel@tonic-gate gettext("%s requires at least %d arg(s)\n"),
6367c478bd9Sstevel@tonic-gate com->c_name, com->c_minargs);
6377c478bd9Sstevel@tonic-gate break;
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate if (c > com->c_maxargs) {
6407c478bd9Sstevel@tonic-gate fprintf(stderr,
6417c478bd9Sstevel@tonic-gate gettext("%s takes no more than %d arg(s)\n"),
6427c478bd9Sstevel@tonic-gate com->c_name, com->c_maxargs);
6437c478bd9Sstevel@tonic-gate break;
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate e = (*com->c_func)(arglist);
6467c478bd9Sstevel@tonic-gate break;
6477c478bd9Sstevel@tonic-gate
6487c478bd9Sstevel@tonic-gate case NOLIST:
6497c478bd9Sstevel@tonic-gate /*
6507c478bd9Sstevel@tonic-gate * Just the constant zero, for exiting,
6517c478bd9Sstevel@tonic-gate * eg.
6527c478bd9Sstevel@tonic-gate */
6537c478bd9Sstevel@tonic-gate e = (*com->c_func)(0);
6547c478bd9Sstevel@tonic-gate break;
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate default:
6577c478bd9Sstevel@tonic-gate panic("Unknown argtype");
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate /*
6617c478bd9Sstevel@tonic-gate * Exit the current source file on
6627c478bd9Sstevel@tonic-gate * error.
6637c478bd9Sstevel@tonic-gate */
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate if (e && loading)
666eb2b0a61Sas return (1);
6677c478bd9Sstevel@tonic-gate if (e && sourcing)
6687c478bd9Sstevel@tonic-gate unstack();
669*13539f0dSToomas Soome if ((uintptr_t)com->c_func == (uintptr_t)edstop)
670eb2b0a61Sas return (1);
6717c478bd9Sstevel@tonic-gate if (value("autoprint") != NOSTR && com->c_argtype & P)
6727c478bd9Sstevel@tonic-gate if ((dot->m_flag & MDELETED) == 0) {
6737c478bd9Sstevel@tonic-gate muvec[0] = dot - &message[0] + 1;
6747c478bd9Sstevel@tonic-gate muvec[1] = 0;
6757c478bd9Sstevel@tonic-gate type(muvec);
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate if (!sourcing && (com->c_argtype & T) == 0)
6787c478bd9Sstevel@tonic-gate sawcom = 1;
679eb2b0a61Sas return (0);
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate #ifdef SIGCONT
6837c478bd9Sstevel@tonic-gate /*
6847c478bd9Sstevel@tonic-gate * When we wake up after ^Z, reprint the prompt.
6857c478bd9Sstevel@tonic-gate */
686eb2b0a61Sas static void
contin(int s __unused)687*13539f0dSToomas Soome contin(int s __unused)
6887c478bd9Sstevel@tonic-gate {
6897c478bd9Sstevel@tonic-gate if (shudprompt)
6907c478bd9Sstevel@tonic-gate printf("%s", prompt);
6917c478bd9Sstevel@tonic-gate fflush(stdout);
6927c478bd9Sstevel@tonic-gate }
6937c478bd9Sstevel@tonic-gate #endif
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate /*
6967c478bd9Sstevel@tonic-gate * Branch here on hangup signal and simulate quit.
6977c478bd9Sstevel@tonic-gate */
698eb2b0a61Sas void
hangup(int s __unused)699*13539f0dSToomas Soome hangup(int s __unused)
7007c478bd9Sstevel@tonic-gate {
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate holdsigs();
703eb2b0a61Sas #ifdef OLD_BSD_SIGS
7047c478bd9Sstevel@tonic-gate sigignore(SIGHUP);
705eb2b0a61Sas #endif
7067c478bd9Sstevel@tonic-gate if (edit) {
7077c478bd9Sstevel@tonic-gate if (setjmp(srbuf))
7087c478bd9Sstevel@tonic-gate exit(rpterr);
7097c478bd9Sstevel@tonic-gate edstop(0);
7107c478bd9Sstevel@tonic-gate } else {
7117c478bd9Sstevel@tonic-gate if (issysmbox)
7127c478bd9Sstevel@tonic-gate Verhogen();
7137c478bd9Sstevel@tonic-gate if (value("exit") != NOSTR)
7147c478bd9Sstevel@tonic-gate exit(1);
7157c478bd9Sstevel@tonic-gate else
7167c478bd9Sstevel@tonic-gate quit(0);
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate exit(rpterr);
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate /*
7227c478bd9Sstevel@tonic-gate * Set the size of the message vector used to construct argument
7237c478bd9Sstevel@tonic-gate * lists to message list functions.
7247c478bd9Sstevel@tonic-gate */
7257c478bd9Sstevel@tonic-gate
726eb2b0a61Sas static void
setmsize(int sz)7277c478bd9Sstevel@tonic-gate setmsize(int sz)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate
730eb2b0a61Sas if (msgvec != (int *)0)
7317c478bd9Sstevel@tonic-gate free(msgvec);
7327c478bd9Sstevel@tonic-gate if (sz < 1)
7337c478bd9Sstevel@tonic-gate sz = 1; /* need at least one cell for terminating 0 */
7347c478bd9Sstevel@tonic-gate if ((msgvec = (int *)
7357c478bd9Sstevel@tonic-gate calloc((unsigned)(sz + 1), sizeof (*msgvec))) == NULL)
7367c478bd9Sstevel@tonic-gate panic("Failed to allocate memory for message vector");
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate /*
7407c478bd9Sstevel@tonic-gate * Find the correct command in the command table corresponding
7417c478bd9Sstevel@tonic-gate * to the passed command "word"
7427c478bd9Sstevel@tonic-gate */
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate static const struct cmd *
lex(char word[])7457c478bd9Sstevel@tonic-gate lex(char word[])
7467c478bd9Sstevel@tonic-gate {
74746d64c14SToomas Soome const struct cmd *cp;
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++)
7507c478bd9Sstevel@tonic-gate if (isprefix(word, cp->c_name))
751eb2b0a61Sas return (cp);
752eb2b0a61Sas return (NONE);
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate /*
7567c478bd9Sstevel@tonic-gate * Determine if as1 is a valid prefix of as2.
7577c478bd9Sstevel@tonic-gate */
758eb2b0a61Sas static int
isprefix(char * as1,char * as2)7597c478bd9Sstevel@tonic-gate isprefix(char *as1, char *as2)
7607c478bd9Sstevel@tonic-gate {
76146d64c14SToomas Soome char *s1, *s2;
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate s1 = as1;
7647c478bd9Sstevel@tonic-gate s2 = as2;
7657c478bd9Sstevel@tonic-gate while (*s1++ == *s2)
7667c478bd9Sstevel@tonic-gate if (*s2++ == '\0')
767eb2b0a61Sas return (1);
768eb2b0a61Sas return (*--s1 == '\0');
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate /*
7727c478bd9Sstevel@tonic-gate * The following gets called on receipt of a rubout. This is
7737c478bd9Sstevel@tonic-gate * to abort printout of a command, mainly.
7747c478bd9Sstevel@tonic-gate * Dispatching here when command() is inactive crashes rcv.
7757c478bd9Sstevel@tonic-gate * Close all open files except 0, 1, 2, and the temporary.
7767c478bd9Sstevel@tonic-gate * The special call to getuserid() is needed so it won't get
7777c478bd9Sstevel@tonic-gate * annoyed about losing its open file.
7787c478bd9Sstevel@tonic-gate * Also, unstack all source files.
7797c478bd9Sstevel@tonic-gate */
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate static int inithdr; /* am printing startup headers */
7827c478bd9Sstevel@tonic-gate
783eb2b0a61Sas void
stop(int s)7847c478bd9Sstevel@tonic-gate stop(int s)
7857c478bd9Sstevel@tonic-gate {
78646d64c14SToomas Soome NODE *head;
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate noreset = 0;
7897c478bd9Sstevel@tonic-gate if (!inithdr)
7907c478bd9Sstevel@tonic-gate sawcom++;
7917c478bd9Sstevel@tonic-gate inithdr = 0;
7927c478bd9Sstevel@tonic-gate while (sourcing)
7937c478bd9Sstevel@tonic-gate unstack();
794eb2b0a61Sas (void) getuserid((char *)0);
7957c478bd9Sstevel@tonic-gate for (head = fplist; head != (NODE *)NULL; head = head->next) {
7967c478bd9Sstevel@tonic-gate if (head->fp == stdin || head->fp == stdout)
7977c478bd9Sstevel@tonic-gate continue;
7987c478bd9Sstevel@tonic-gate if (head->fp == itf || head->fp == otf)
7997c478bd9Sstevel@tonic-gate continue;
8007c478bd9Sstevel@tonic-gate if (head->fp == stderr)
8017c478bd9Sstevel@tonic-gate continue;
8027c478bd9Sstevel@tonic-gate if (head->fp == semfp)
8037c478bd9Sstevel@tonic-gate continue;
8047c478bd9Sstevel@tonic-gate if (head->fp == pipef) {
8057c478bd9Sstevel@tonic-gate npclose(pipef);
8067c478bd9Sstevel@tonic-gate pipef = NULL;
8077c478bd9Sstevel@tonic-gate continue;
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate fclose(head->fp);
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate if (image >= 0) {
8127c478bd9Sstevel@tonic-gate close(image);
8137c478bd9Sstevel@tonic-gate image = -1;
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate if (s) {
8167c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Interrupt\n"));
8177c478bd9Sstevel@tonic-gate fflush(stderr);
818eb2b0a61Sas #ifdef OLD_BSD_SIGS
8197c478bd9Sstevel@tonic-gate sigrelse(s);
820eb2b0a61Sas #endif
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate longjmp(srbuf, 1);
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate
8257c478bd9Sstevel@tonic-gate /*
8267c478bd9Sstevel@tonic-gate * Announce the presence of the current mailx version,
8277c478bd9Sstevel@tonic-gate * give the message count, and print a header listing.
8287c478bd9Sstevel@tonic-gate */
8297c478bd9Sstevel@tonic-gate
8307c478bd9Sstevel@tonic-gate #define GREETING "%s Type ? for help.\n"
8317c478bd9Sstevel@tonic-gate
832eb2b0a61Sas void
announce(void)8337c478bd9Sstevel@tonic-gate announce(void)
8347c478bd9Sstevel@tonic-gate {
8357c478bd9Sstevel@tonic-gate int vec[2], mdot;
8367c478bd9Sstevel@tonic-gate extern const char *const version;
8377c478bd9Sstevel@tonic-gate
838eb2b0a61Sas if (!Hflag && value("quiet") == NOSTR)
8397c478bd9Sstevel@tonic-gate printf(gettext(GREETING), version);
8407c478bd9Sstevel@tonic-gate mdot = newfileinfo(1);
8417c478bd9Sstevel@tonic-gate vec[0] = mdot;
8427c478bd9Sstevel@tonic-gate vec[1] = 0;
8437c478bd9Sstevel@tonic-gate dot = &message[mdot - 1];
8447c478bd9Sstevel@tonic-gate if (msgCount > 0 && !noheader) {
8457c478bd9Sstevel@tonic-gate inithdr++;
8467c478bd9Sstevel@tonic-gate headers(vec);
8477c478bd9Sstevel@tonic-gate inithdr = 0;
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate /*
8527c478bd9Sstevel@tonic-gate * Announce information about the file we are editing.
8537c478bd9Sstevel@tonic-gate * Return a likely place to set dot.
8547c478bd9Sstevel@tonic-gate */
855eb2b0a61Sas int
newfileinfo(int start)8567c478bd9Sstevel@tonic-gate newfileinfo(int start)
8577c478bd9Sstevel@tonic-gate {
85846d64c14SToomas Soome struct message *mp;
85946d64c14SToomas Soome int u, n, mdot, d, s;
8607c478bd9Sstevel@tonic-gate char fname[BUFSIZ], zname[BUFSIZ], *ename;
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate if (Hflag)
863eb2b0a61Sas return (1); /* fake it--return message 1 */
8647c478bd9Sstevel@tonic-gate for (mp = &message[start - 1]; mp < &message[msgCount]; mp++)
8657c478bd9Sstevel@tonic-gate if ((mp->m_flag & (MNEW|MREAD)) == MNEW)
8667c478bd9Sstevel@tonic-gate break;
8677c478bd9Sstevel@tonic-gate if (mp >= &message[msgCount])
8687c478bd9Sstevel@tonic-gate for (mp = &message[start - 1]; mp < &message[msgCount]; mp++)
8697c478bd9Sstevel@tonic-gate if ((mp->m_flag & MREAD) == 0)
8707c478bd9Sstevel@tonic-gate break;
8717c478bd9Sstevel@tonic-gate if (mp < &message[msgCount])
8727c478bd9Sstevel@tonic-gate mdot = mp - &message[0] + 1;
8737c478bd9Sstevel@tonic-gate else
8747c478bd9Sstevel@tonic-gate mdot = 1;
8757c478bd9Sstevel@tonic-gate n = u = d = s = 0;
8767c478bd9Sstevel@tonic-gate for (mp = &message[start - 1]; mp < &message[msgCount]; mp++) {
8777c478bd9Sstevel@tonic-gate if (mp->m_flag & MNEW)
8787c478bd9Sstevel@tonic-gate n++;
8797c478bd9Sstevel@tonic-gate if ((mp->m_flag & MREAD) == 0)
8807c478bd9Sstevel@tonic-gate u++;
8817c478bd9Sstevel@tonic-gate if (mp->m_flag & MDELETED)
8827c478bd9Sstevel@tonic-gate d++;
8837c478bd9Sstevel@tonic-gate if (mp->m_flag & MSAVED)
8847c478bd9Sstevel@tonic-gate s++;
8857c478bd9Sstevel@tonic-gate }
886eb2b0a61Sas ename = origname;
8877c478bd9Sstevel@tonic-gate if (getfold(fname) >= 0) {
8887c478bd9Sstevel@tonic-gate nstrcat(fname, sizeof (fname), "/");
8897c478bd9Sstevel@tonic-gate if (strncmp(fname, editfile, strlen(fname)) == 0) {
8907c478bd9Sstevel@tonic-gate snprintf(zname, sizeof (zname),
891*13539f0dSToomas Soome "+%s", editfile + strlen(fname));
8927c478bd9Sstevel@tonic-gate ename = zname;
8937c478bd9Sstevel@tonic-gate }
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate printf("\"%s\": ", ename);
8967c478bd9Sstevel@tonic-gate if (msgCount == 1)
8977c478bd9Sstevel@tonic-gate printf(gettext("1 message"));
8987c478bd9Sstevel@tonic-gate else
8997c478bd9Sstevel@tonic-gate printf(gettext("%d messages"), msgCount);
9007c478bd9Sstevel@tonic-gate if (n > 0)
9017c478bd9Sstevel@tonic-gate printf(gettext(" %d new"), n);
9027c478bd9Sstevel@tonic-gate if (u-n > 0)
9037c478bd9Sstevel@tonic-gate printf(gettext(" %d unread"), u);
9047c478bd9Sstevel@tonic-gate if (d > 0)
9057c478bd9Sstevel@tonic-gate printf(gettext(" %d deleted"), d);
9067c478bd9Sstevel@tonic-gate if (s > 0)
9077c478bd9Sstevel@tonic-gate printf(gettext(" %d saved"), s);
9087c478bd9Sstevel@tonic-gate if (readonly)
9097c478bd9Sstevel@tonic-gate printf(gettext(" [Read only]"));
9107c478bd9Sstevel@tonic-gate printf("\n");
911eb2b0a61Sas return (mdot);
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate /*
9157c478bd9Sstevel@tonic-gate * Print the current version number.
9167c478bd9Sstevel@tonic-gate */
9177c478bd9Sstevel@tonic-gate
918eb2b0a61Sas int
pversion(char * s __unused)919*13539f0dSToomas Soome pversion(char *s __unused)
9207c478bd9Sstevel@tonic-gate {
9217c478bd9Sstevel@tonic-gate printf("%s\n", version);
922eb2b0a61Sas return (0);
9237c478bd9Sstevel@tonic-gate }
9247c478bd9Sstevel@tonic-gate
9257c478bd9Sstevel@tonic-gate /*
9267c478bd9Sstevel@tonic-gate * Load a file of user definitions.
9277c478bd9Sstevel@tonic-gate */
928eb2b0a61Sas void
load(char * name)9297c478bd9Sstevel@tonic-gate load(char *name)
9307c478bd9Sstevel@tonic-gate {
93146d64c14SToomas Soome FILE *in, *oldin;
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate if ((in = fopen(name, "r")) == NULL)
9347c478bd9Sstevel@tonic-gate return;
9357c478bd9Sstevel@tonic-gate oldin = input;
9367c478bd9Sstevel@tonic-gate input = in;
9377c478bd9Sstevel@tonic-gate loading = 1;
9387c478bd9Sstevel@tonic-gate sourcing = 1;
9397c478bd9Sstevel@tonic-gate commands();
9407c478bd9Sstevel@tonic-gate loading = 0;
9417c478bd9Sstevel@tonic-gate sourcing = 0;
9427c478bd9Sstevel@tonic-gate input = oldin;
9437c478bd9Sstevel@tonic-gate fclose(in);
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate
9467c478bd9Sstevel@tonic-gate /*
9477c478bd9Sstevel@tonic-gate * Incorporate any new mail into the current session.
9487c478bd9Sstevel@tonic-gate *
9497c478bd9Sstevel@tonic-gate * XXX - Since autoinc works on "edited" files as well as the
9507c478bd9Sstevel@tonic-gate * system mailbox, this probably ought to as well.
9517c478bd9Sstevel@tonic-gate */
9527c478bd9Sstevel@tonic-gate
953eb2b0a61Sas int
inc(void)9547c478bd9Sstevel@tonic-gate inc(void)
9557c478bd9Sstevel@tonic-gate {
9567c478bd9Sstevel@tonic-gate FILE *ibuf;
9577c478bd9Sstevel@tonic-gate int mdot;
9587c478bd9Sstevel@tonic-gate struct stat stbuf;
9597c478bd9Sstevel@tonic-gate int firstnewmsg = msgCount + 1;
9607c478bd9Sstevel@tonic-gate
9617c478bd9Sstevel@tonic-gate if (edit) {
9627c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Not in system mailbox\n"));
963eb2b0a61Sas return (-1);
9647c478bd9Sstevel@tonic-gate }
9657c478bd9Sstevel@tonic-gate if (((ibuf = fopen(mailname, "r")) == NULL) ||
9667c478bd9Sstevel@tonic-gate (fstat(fileno(ibuf), &stbuf) < 0) || stbuf.st_size == 0L ||
9677c478bd9Sstevel@tonic-gate stbuf.st_size == mailsize || (stbuf.st_mode&S_IFMT) != S_IFREG) {
9687c478bd9Sstevel@tonic-gate if (strrchr(mailname, '/') == NOSTR)
9697c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("No new mail.\n"));
9707c478bd9Sstevel@tonic-gate else
9717c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("No new mail for %s\n"),
9727c478bd9Sstevel@tonic-gate strrchr(mailname, '/')+1);
9737c478bd9Sstevel@tonic-gate if (ibuf != NULL)
9747c478bd9Sstevel@tonic-gate fclose(ibuf);
975eb2b0a61Sas return (-1);
9767c478bd9Sstevel@tonic-gate }
9777c478bd9Sstevel@tonic-gate
9787c478bd9Sstevel@tonic-gate fseek(otf, 0L, 2);
9797c478bd9Sstevel@tonic-gate holdsigs();
9807c478bd9Sstevel@tonic-gate if (issysmbox)
9817c478bd9Sstevel@tonic-gate lockmail();
9827c478bd9Sstevel@tonic-gate fseek(ibuf, mailsize, 0);
9837c478bd9Sstevel@tonic-gate mailsize = fsize(ibuf);
9847c478bd9Sstevel@tonic-gate setptr(ibuf);
9857c478bd9Sstevel@tonic-gate setmsize(msgCount);
9867c478bd9Sstevel@tonic-gate fclose(ibuf);
9877c478bd9Sstevel@tonic-gate if (issysmbox)
9887c478bd9Sstevel@tonic-gate unlockmail();
9897c478bd9Sstevel@tonic-gate relsesigs();
9907c478bd9Sstevel@tonic-gate mdot = newfileinfo(firstnewmsg);
9917c478bd9Sstevel@tonic-gate dot = &message[mdot - 1];
9927c478bd9Sstevel@tonic-gate sawcom = 0;
993eb2b0a61Sas return (0);
9947c478bd9Sstevel@tonic-gate }
995