11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3174769Smikeh#if 0 3288150Smikehstatic char sccsid[] = "@(#)lex.c 8.2 (Berkeley) 4/20/95"; 3374769Smikeh#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes#include "rcv.h" 391590Srgrimes#include <errno.h> 401590Srgrimes#include <fcntl.h> 411590Srgrimes#include "extern.h" 421590Srgrimes 431590Srgrimes/* 441590Srgrimes * Mail -- a mail program 451590Srgrimes * 461590Srgrimes * Lexical processing of commands. 471590Srgrimes */ 481590Srgrimes 49173439Sddsstatic const char *prompt = "& "; 501590Srgrimes 5177274Smikehextern const struct cmd cmdtab[]; 5277274Smikehextern const char *version; 5377274Smikeh 541590Srgrimes/* 551590Srgrimes * Set up editing on the given file name. 561590Srgrimes * If the first character of name is %, we are considered to be 571590Srgrimes * editing the file, otherwise we are reading our mail which has 581590Srgrimes * signficance for mbox and so forth. 59126415Smikeh * 60126415Smikeh * If the -e option is being passed to mail, this function has a 61126415Smikeh * tri-state return code: -1 on error, 0 on no mail, 1 if there is 62126415Smikeh * mail. 631590Srgrimes */ 641590Srgrimesint 65216564Scharniersetfile(char *name) 661590Srgrimes{ 671590Srgrimes FILE *ibuf; 68126415Smikeh int checkmode, i, fd; 691590Srgrimes struct stat stb; 7088150Smikeh char isedit = *name != '%' || getuserid(myname) != getuid(); 711590Srgrimes char *who = name[1] ? name + 1 : myname; 7274769Smikeh char tempname[PATHSIZE]; 731590Srgrimes static int shudclob; 741590Srgrimes 75126691Smikeh checkmode = value("checkmode") != NULL; 7677274Smikeh if ((name = expand(name)) == NULL) 7777274Smikeh return (-1); 781590Srgrimes 791590Srgrimes if ((ibuf = Fopen(name, "r")) == NULL) { 801590Srgrimes if (!isedit && errno == ENOENT) 811590Srgrimes goto nomail; 8274769Smikeh warn("%s", name); 8377274Smikeh return (-1); 841590Srgrimes } 851590Srgrimes 861590Srgrimes if (fstat(fileno(ibuf), &stb) < 0) { 8774769Smikeh warn("fstat"); 8877274Smikeh (void)Fclose(ibuf); 891590Srgrimes return (-1); 901590Srgrimes } 911590Srgrimes 9274769Smikeh if (S_ISDIR(stb.st_mode) || !S_ISREG(stb.st_mode)) { 9377274Smikeh (void)Fclose(ibuf); 9474769Smikeh errno = S_ISDIR(stb.st_mode) ? EISDIR : EINVAL; 9574769Smikeh warn("%s", name); 961590Srgrimes return (-1); 971590Srgrimes } 981590Srgrimes 991590Srgrimes /* 1001590Srgrimes * Looks like all will be well. We must now relinquish our 1011590Srgrimes * hold on the current set of stuff. Must hold signals 1021590Srgrimes * while we are reading the new file, else we will ruin 1031590Srgrimes * the message[] data structure. 1041590Srgrimes */ 1051590Srgrimes 1061590Srgrimes holdsigs(); 1071590Srgrimes if (shudclob) 1081590Srgrimes quit(); 1091590Srgrimes 1101590Srgrimes /* 1111590Srgrimes * Copy the messages into /tmp 1121590Srgrimes * and set pointers. 1131590Srgrimes */ 1141590Srgrimes 1151590Srgrimes readonly = 0; 1161590Srgrimes if ((i = open(name, 1)) < 0) 1171590Srgrimes readonly++; 1181590Srgrimes else 11977274Smikeh (void)close(i); 1201590Srgrimes if (shudclob) { 12177274Smikeh (void)fclose(itf); 12277274Smikeh (void)fclose(otf); 1231590Srgrimes } 1241590Srgrimes shudclob = 1; 1251590Srgrimes edit = isedit; 12674769Smikeh strlcpy(prevfile, mailname, sizeof(prevfile)); 1271590Srgrimes if (name != mailname) 12874769Smikeh strlcpy(mailname, name, sizeof(mailname)); 1291590Srgrimes mailsize = fsize(ibuf); 13077274Smikeh (void)snprintf(tempname, sizeof(tempname), 13177274Smikeh "%s/mail.RxXXXXXXXXXX", tmpdir); 13274769Smikeh if ((fd = mkstemp(tempname)) == -1 || (otf = fdopen(fd, "w")) == NULL) 13374769Smikeh err(1, "%s", tempname); 13477274Smikeh (void)fcntl(fileno(otf), F_SETFD, 1); 13574769Smikeh if ((itf = fopen(tempname, "r")) == NULL) 13674769Smikeh err(1, "%s", tempname); 13777274Smikeh (void)fcntl(fileno(itf), F_SETFD, 1); 13877274Smikeh (void)rm(tempname); 13988150Smikeh setptr(ibuf, 0); 1401590Srgrimes setmsize(msgCount); 14188150Smikeh /* 14288150Smikeh * New mail may have arrived while we were reading 14388150Smikeh * the mail file, so reset mailsize to be where 14488150Smikeh * we really are in the file... 14588150Smikeh */ 14688227Sache mailsize = ftello(ibuf); 14777274Smikeh (void)Fclose(ibuf); 1481590Srgrimes relsesigs(); 1491590Srgrimes sawcom = 0; 150126415Smikeh 151126415Smikeh if ((checkmode || !edit) && msgCount == 0) { 1521590Srgrimesnomail: 153126415Smikeh if (!checkmode) { 154126415Smikeh fprintf(stderr, "No mail for %s\n", who); 155126415Smikeh return (-1); 156126415Smikeh } else 157126415Smikeh return (0); 1581590Srgrimes } 159126415Smikeh return (checkmode ? 1 : 0); 1601590Srgrimes} 1611590Srgrimes 16288150Smikeh/* 16388150Smikeh * Incorporate any new mail that has arrived since we first 16488150Smikeh * started reading mail. 16588150Smikeh */ 16688150Smikehint 167216564Scharnierincfile(void) 16888150Smikeh{ 16988227Sache off_t newsize; 17088150Smikeh int omsgCount = msgCount; 17188150Smikeh FILE *ibuf; 17288150Smikeh 17388150Smikeh ibuf = Fopen(mailname, "r"); 17488150Smikeh if (ibuf == NULL) 17588150Smikeh return (-1); 17688150Smikeh holdsigs(); 17788150Smikeh newsize = fsize(ibuf); 17888150Smikeh if (newsize == 0) 17988150Smikeh return (-1); /* mail box is now empty??? */ 18088150Smikeh if (newsize < mailsize) 18188150Smikeh return (-1); /* mail box has shrunk??? */ 18288150Smikeh if (newsize == mailsize) 18388150Smikeh return (0); /* no new mail */ 18488150Smikeh setptr(ibuf, mailsize); 18588150Smikeh setmsize(msgCount); 18688227Sache mailsize = ftello(ibuf); 18788150Smikeh (void)Fclose(ibuf); 18888150Smikeh relsesigs(); 18988150Smikeh return (msgCount - omsgCount); 19088150Smikeh} 19188150Smikeh 192173439Sddsstatic int *msgvec; 193173439Sddsstatic int reset_on_stop; /* do a reset() if stopped */ 1941590Srgrimes 1951590Srgrimes/* 1961590Srgrimes * Interpret user commands one by one. If standard input is not a tty, 1971590Srgrimes * print no prompt. 1981590Srgrimes */ 1991590Srgrimesvoid 200216564Scharniercommands(void) 2011590Srgrimes{ 20277274Smikeh int n, eofloop = 0; 2031590Srgrimes char linebuf[LINESIZE]; 2041590Srgrimes 2051590Srgrimes if (!sourcing) { 2061590Srgrimes if (signal(SIGINT, SIG_IGN) != SIG_IGN) 20777274Smikeh (void)signal(SIGINT, intr); 2081590Srgrimes if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 20977274Smikeh (void)signal(SIGHUP, hangup); 21077274Smikeh (void)signal(SIGTSTP, stop); 21177274Smikeh (void)signal(SIGTTOU, stop); 21277274Smikeh (void)signal(SIGTTIN, stop); 2131590Srgrimes } 2141590Srgrimes setexit(); 2151590Srgrimes for (;;) { 2161590Srgrimes /* 2171590Srgrimes * Print the prompt, if needed. Clear out 2181590Srgrimes * string space, and flush the output. 2191590Srgrimes */ 22077274Smikeh if (!sourcing && value("interactive") != NULL) { 22188150Smikeh if ((value("autoinc") != NULL) && (incfile() > 0)) 22288150Smikeh printf("New mail has arrived.\n"); 2231590Srgrimes reset_on_stop = 1; 22469249Skris printf("%s", prompt); 2251590Srgrimes } 22677274Smikeh (void)fflush(stdout); 2271590Srgrimes sreset(); 2281590Srgrimes /* 2291590Srgrimes * Read a line of commands from the current input 2301590Srgrimes * and handle end of file specially. 2311590Srgrimes */ 2321590Srgrimes n = 0; 2331590Srgrimes for (;;) { 2341590Srgrimes if (readline(input, &linebuf[n], LINESIZE - n) < 0) { 2351590Srgrimes if (n == 0) 2361590Srgrimes n = -1; 2371590Srgrimes break; 2381590Srgrimes } 2391590Srgrimes if ((n = strlen(linebuf)) == 0) 2401590Srgrimes break; 2411590Srgrimes n--; 2421590Srgrimes if (linebuf[n] != '\\') 2431590Srgrimes break; 2441590Srgrimes linebuf[n++] = ' '; 2451590Srgrimes } 2461590Srgrimes reset_on_stop = 0; 2471590Srgrimes if (n < 0) { 2481590Srgrimes /* eof */ 2491590Srgrimes if (loading) 2501590Srgrimes break; 2511590Srgrimes if (sourcing) { 2521590Srgrimes unstack(); 2531590Srgrimes continue; 2541590Srgrimes } 25577274Smikeh if (value("interactive") != NULL && 25677274Smikeh value("ignoreeof") != NULL && 2571590Srgrimes ++eofloop < 25) { 2581590Srgrimes printf("Use \"quit\" to quit.\n"); 2591590Srgrimes continue; 2601590Srgrimes } 2611590Srgrimes break; 2621590Srgrimes } 2631590Srgrimes eofloop = 0; 2641590Srgrimes if (execute(linebuf, 0)) 2651590Srgrimes break; 2661590Srgrimes } 2671590Srgrimes} 2681590Srgrimes 2691590Srgrimes/* 2701590Srgrimes * Execute a single command. 2711590Srgrimes * Command functions return 0 for success, 1 for error, and -1 2721590Srgrimes * for abort. A 1 or -1 aborts a load or source. A -1 aborts 2731590Srgrimes * the interactive command loop. 2741590Srgrimes * Contxt is non-zero if called while composing mail. 2751590Srgrimes */ 2761590Srgrimesint 277216564Scharnierexecute(char linebuf[], int contxt) 2781590Srgrimes{ 2791590Srgrimes char word[LINESIZE]; 2801590Srgrimes char *arglist[MAXARGC]; 28177274Smikeh const struct cmd *com; 28277274Smikeh char *cp, *cp2; 28377274Smikeh int c, muvec[2]; 2841590Srgrimes int e = 1; 2851590Srgrimes 2861590Srgrimes /* 2871590Srgrimes * Strip the white space away from the beginning 2881590Srgrimes * of the command, then scan out a word, which 2891590Srgrimes * consists of anything except digits and white space. 2901590Srgrimes * 2911590Srgrimes * Handle ! escapes differently to get the correct 2921590Srgrimes * lexical conventions. 2931590Srgrimes */ 2941590Srgrimes 29588227Sache for (cp = linebuf; isspace((unsigned char)*cp); cp++) 2961590Srgrimes ; 2971590Srgrimes if (*cp == '!') { 2981590Srgrimes if (sourcing) { 2991590Srgrimes printf("Can't \"!\" while sourcing\n"); 3001590Srgrimes goto out; 3011590Srgrimes } 3021590Srgrimes shell(cp+1); 30377274Smikeh return (0); 3041590Srgrimes } 3051590Srgrimes cp2 = word; 30677274Smikeh while (*cp != '\0' && strchr(" \t0123456789$^.:/-+*'\"", *cp) == NULL) 3071590Srgrimes *cp2++ = *cp++; 3081590Srgrimes *cp2 = '\0'; 3091590Srgrimes 3101590Srgrimes /* 3111590Srgrimes * Look up the command; if not found, bitch. 3121590Srgrimes * Normally, a blank command would map to the 3131590Srgrimes * first command in the table; while sourcing, 3141590Srgrimes * however, we ignore blank lines to eliminate 3151590Srgrimes * confusion. 3161590Srgrimes */ 3171590Srgrimes 3181590Srgrimes if (sourcing && *word == '\0') 31977274Smikeh return (0); 3201590Srgrimes com = lex(word); 32177274Smikeh if (com == NULL) { 3221590Srgrimes printf("Unknown command: \"%s\"\n", word); 3231590Srgrimes goto out; 3241590Srgrimes } 3251590Srgrimes 3261590Srgrimes /* 3271590Srgrimes * See if we should execute the command -- if a conditional 3281590Srgrimes * we always execute it, otherwise, check the state of cond. 3291590Srgrimes */ 3301590Srgrimes 3311590Srgrimes if ((com->c_argtype & F) == 0) 33277274Smikeh if ((cond == CRCV && !rcvmode) || (cond == CSEND && rcvmode)) 33377274Smikeh return (0); 3341590Srgrimes 3351590Srgrimes /* 3361590Srgrimes * Process the arguments to the command, depending 3371590Srgrimes * on the type he expects. Default to an error. 3381590Srgrimes * If we are sourcing an interactive command, it's 3391590Srgrimes * an error. 3401590Srgrimes */ 3411590Srgrimes 3421590Srgrimes if (!rcvmode && (com->c_argtype & M) == 0) { 3431590Srgrimes printf("May not execute \"%s\" while sending\n", 3441590Srgrimes com->c_name); 3451590Srgrimes goto out; 3461590Srgrimes } 3471590Srgrimes if (sourcing && com->c_argtype & I) { 3481590Srgrimes printf("May not execute \"%s\" while sourcing\n", 3491590Srgrimes com->c_name); 3501590Srgrimes goto out; 3511590Srgrimes } 3521590Srgrimes if (readonly && com->c_argtype & W) { 3531590Srgrimes printf("May not execute \"%s\" -- message file is read only\n", 3541590Srgrimes com->c_name); 3551590Srgrimes goto out; 3561590Srgrimes } 3571590Srgrimes if (contxt && com->c_argtype & R) { 3581590Srgrimes printf("Cannot recursively invoke \"%s\"\n", com->c_name); 3591590Srgrimes goto out; 3601590Srgrimes } 3611590Srgrimes switch (com->c_argtype & ~(F|P|I|M|T|W|R)) { 3621590Srgrimes case MSGLIST: 3631590Srgrimes /* 3641590Srgrimes * A message list defaulting to nearest forward 3651590Srgrimes * legal message. 3661590Srgrimes */ 3671590Srgrimes if (msgvec == 0) { 3681590Srgrimes printf("Illegal use of \"message list\"\n"); 3691590Srgrimes break; 3701590Srgrimes } 3711590Srgrimes if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0) 3721590Srgrimes break; 3731590Srgrimes if (c == 0) { 37477274Smikeh *msgvec = first(com->c_msgflag, com->c_msgmask); 37529574Sphk msgvec[1] = 0; 3761590Srgrimes } 37729574Sphk if (*msgvec == 0) { 3781590Srgrimes printf("No applicable messages\n"); 3791590Srgrimes break; 3801590Srgrimes } 3811590Srgrimes e = (*com->c_func)(msgvec); 3821590Srgrimes break; 3831590Srgrimes 3841590Srgrimes case NDMLIST: 3851590Srgrimes /* 3861590Srgrimes * A message list with no defaults, but no error 3871590Srgrimes * if none exist. 3881590Srgrimes */ 3891590Srgrimes if (msgvec == 0) { 3901590Srgrimes printf("Illegal use of \"message list\"\n"); 3911590Srgrimes break; 3921590Srgrimes } 3931590Srgrimes if (getmsglist(cp, msgvec, com->c_msgflag) < 0) 3941590Srgrimes break; 3951590Srgrimes e = (*com->c_func)(msgvec); 3961590Srgrimes break; 3971590Srgrimes 3981590Srgrimes case STRLIST: 3991590Srgrimes /* 4001590Srgrimes * Just the straight string, with 4011590Srgrimes * leading blanks removed. 4021590Srgrimes */ 40388227Sache while (isspace((unsigned char)*cp)) 4041590Srgrimes cp++; 4051590Srgrimes e = (*com->c_func)(cp); 4061590Srgrimes break; 4071590Srgrimes 4081590Srgrimes case RAWLIST: 4091590Srgrimes /* 4101590Srgrimes * A vector of strings, in shell style. 4111590Srgrimes */ 4121590Srgrimes if ((c = getrawlist(cp, arglist, 41377274Smikeh sizeof(arglist) / sizeof(*arglist))) < 0) 4141590Srgrimes break; 4151590Srgrimes if (c < com->c_minargs) { 4161590Srgrimes printf("%s requires at least %d arg(s)\n", 41777274Smikeh com->c_name, com->c_minargs); 4181590Srgrimes break; 4191590Srgrimes } 4201590Srgrimes if (c > com->c_maxargs) { 4211590Srgrimes printf("%s takes no more than %d arg(s)\n", 42277274Smikeh com->c_name, com->c_maxargs); 4231590Srgrimes break; 4241590Srgrimes } 4251590Srgrimes e = (*com->c_func)(arglist); 4261590Srgrimes break; 4271590Srgrimes 4281590Srgrimes case NOLIST: 4291590Srgrimes /* 4301590Srgrimes * Just the constant zero, for exiting, 4311590Srgrimes * eg. 4321590Srgrimes */ 4331590Srgrimes e = (*com->c_func)(0); 4341590Srgrimes break; 4351590Srgrimes 4361590Srgrimes default: 43774769Smikeh errx(1, "Unknown argtype"); 4381590Srgrimes } 4391590Srgrimes 4401590Srgrimesout: 4411590Srgrimes /* 4421590Srgrimes * Exit the current source file on 4431590Srgrimes * error. 4441590Srgrimes */ 4451590Srgrimes if (e) { 4461590Srgrimes if (e < 0) 44777274Smikeh return (1); 4481590Srgrimes if (loading) 44977274Smikeh return (1); 4501590Srgrimes if (sourcing) 4511590Srgrimes unstack(); 45277274Smikeh return (0); 4531590Srgrimes } 45488150Smikeh if (com == NULL) 45588150Smikeh return (0); 45677274Smikeh if (value("autoprint") != NULL && com->c_argtype & P) 4571590Srgrimes if ((dot->m_flag & MDELETED) == 0) { 4581590Srgrimes muvec[0] = dot - &message[0] + 1; 4591590Srgrimes muvec[1] = 0; 4601590Srgrimes type(muvec); 4611590Srgrimes } 4621590Srgrimes if (!sourcing && (com->c_argtype & T) == 0) 4631590Srgrimes sawcom = 1; 46477274Smikeh return (0); 4651590Srgrimes} 4661590Srgrimes 4671590Srgrimes/* 4681590Srgrimes * Set the size of the message vector used to construct argument 4691590Srgrimes * lists to message list functions. 4701590Srgrimes */ 4711590Srgrimesvoid 472216564Scharniersetmsize(int sz) 4731590Srgrimes{ 4741590Srgrimes 47588150Smikeh if (msgvec != NULL) 47677274Smikeh (void)free(msgvec); 47777274Smikeh msgvec = calloc((unsigned)(sz + 1), sizeof(*msgvec)); 4781590Srgrimes} 4791590Srgrimes 4801590Srgrimes/* 4811590Srgrimes * Find the correct command in the command table corresponding 4821590Srgrimes * to the passed command "word" 4831590Srgrimes */ 4841590Srgrimes 485228468Sedconst struct cmd * 486216564Scharnierlex(char word[]) 4871590Srgrimes{ 48877274Smikeh const struct cmd *cp; 4891590Srgrimes 49010067Sjoerg /* 49177274Smikeh * ignore trailing chars after `#' 49210067Sjoerg * 49310067Sjoerg * lines with beginning `#' are comments 49474769Smikeh * spaces before `#' are ignored in execute() 49510067Sjoerg */ 49610067Sjoerg 49710067Sjoerg if (*word == '#') 49810067Sjoerg *(word+1) = '\0'; 49910067Sjoerg 50010067Sjoerg 50177274Smikeh for (cp = &cmdtab[0]; cp->c_name != NULL; cp++) 5021590Srgrimes if (isprefix(word, cp->c_name)) 50377274Smikeh return (cp); 50477274Smikeh return (NULL); 5051590Srgrimes} 5061590Srgrimes 5071590Srgrimes/* 5081590Srgrimes * Determine if as1 is a valid prefix of as2. 5091590Srgrimes * Return true if yep. 5101590Srgrimes */ 5111590Srgrimesint 512216564Scharnierisprefix(const char *as1, const char *as2) 5131590Srgrimes{ 51477274Smikeh const char *s1, *s2; 5151590Srgrimes 5161590Srgrimes s1 = as1; 5171590Srgrimes s2 = as2; 5181590Srgrimes while (*s1++ == *s2) 5191590Srgrimes if (*s2++ == '\0') 52077274Smikeh return (1); 52177274Smikeh return (*--s1 == '\0'); 5221590Srgrimes} 5231590Srgrimes 5241590Srgrimes/* 5251590Srgrimes * The following gets called on receipt of an interrupt. This is 5261590Srgrimes * to abort printout of a command, mainly. 5271590Srgrimes * Dispatching here when command() is inactive crashes rcv. 5281590Srgrimes * Close all open files except 0, 1, 2, and the temporary. 5291590Srgrimes * Also, unstack all source files. 5301590Srgrimes */ 5311590Srgrimes 532173439Sddsstatic int inithdr; /* am printing startup headers */ 5331590Srgrimes 5341590Srgrimesvoid 535216564Scharnierintr(int s __unused) 5361590Srgrimes{ 5371590Srgrimes 5381590Srgrimes noreset = 0; 5391590Srgrimes if (!inithdr) 5401590Srgrimes sawcom++; 5411590Srgrimes inithdr = 0; 5421590Srgrimes while (sourcing) 5431590Srgrimes unstack(); 5441590Srgrimes 5451590Srgrimes close_all_files(); 5461590Srgrimes 5471590Srgrimes if (image >= 0) { 54877274Smikeh (void)close(image); 5491590Srgrimes image = -1; 5501590Srgrimes } 5511590Srgrimes fprintf(stderr, "Interrupt\n"); 5521590Srgrimes reset(0); 5531590Srgrimes} 5541590Srgrimes 5551590Srgrimes/* 5561590Srgrimes * When we wake up after ^Z, reprint the prompt. 5571590Srgrimes */ 5581590Srgrimesvoid 559216564Scharnierstop(int s) 5601590Srgrimes{ 5611590Srgrimes sig_t old_action = signal(s, SIG_DFL); 56288150Smikeh sigset_t nset; 5631590Srgrimes 56488150Smikeh (void)sigemptyset(&nset); 56588150Smikeh (void)sigaddset(&nset, s); 56688150Smikeh (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 56777274Smikeh (void)kill(0, s); 56888150Smikeh (void)sigprocmask(SIG_BLOCK, &nset, NULL); 56977274Smikeh (void)signal(s, old_action); 5701590Srgrimes if (reset_on_stop) { 5711590Srgrimes reset_on_stop = 0; 5721590Srgrimes reset(0); 5731590Srgrimes } 5741590Srgrimes} 5751590Srgrimes 5761590Srgrimes/* 5771590Srgrimes * Branch here on hangup signal and simulate "exit". 5781590Srgrimes */ 5791590Srgrimesvoid 580216564Scharnierhangup(int s __unused) 5811590Srgrimes{ 5821590Srgrimes 5831590Srgrimes /* nothing to do? */ 5841590Srgrimes exit(1); 5851590Srgrimes} 5861590Srgrimes 5871590Srgrimes/* 5881590Srgrimes * Announce the presence of the current Mail version, 5891590Srgrimes * give the message count, and print a header listing. 5901590Srgrimes */ 5911590Srgrimesvoid 592216564Scharnierannounce(void) 5931590Srgrimes{ 5941590Srgrimes int vec[2], mdot; 5951590Srgrimes 59688150Smikeh mdot = newfileinfo(0); 5971590Srgrimes vec[0] = mdot; 5981590Srgrimes vec[1] = 0; 5991590Srgrimes dot = &message[mdot - 1]; 60077274Smikeh if (msgCount > 0 && value("noheader") == NULL) { 6011590Srgrimes inithdr++; 6021590Srgrimes headers(vec); 6031590Srgrimes inithdr = 0; 6041590Srgrimes } 6051590Srgrimes} 6061590Srgrimes 6071590Srgrimes/* 6081590Srgrimes * Announce information about the file we are editing. 6091590Srgrimes * Return a likely place to set dot. 6101590Srgrimes */ 6111590Srgrimesint 612216564Scharniernewfileinfo(int omsgCount) 6131590Srgrimes{ 61477274Smikeh struct message *mp; 61577274Smikeh int u, n, mdot, d, s; 61674769Smikeh char fname[PATHSIZE+1], zname[PATHSIZE+1], *ename; 6171590Srgrimes 61888150Smikeh for (mp = &message[omsgCount]; mp < &message[msgCount]; mp++) 6191590Srgrimes if (mp->m_flag & MNEW) 6201590Srgrimes break; 6211590Srgrimes if (mp >= &message[msgCount]) 62288150Smikeh for (mp = &message[omsgCount]; mp < &message[msgCount]; mp++) 6231590Srgrimes if ((mp->m_flag & MREAD) == 0) 6241590Srgrimes break; 6251590Srgrimes if (mp < &message[msgCount]) 6261590Srgrimes mdot = mp - &message[0] + 1; 6271590Srgrimes else 62888150Smikeh mdot = omsgCount + 1; 6291590Srgrimes s = d = 0; 6301590Srgrimes for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) { 6311590Srgrimes if (mp->m_flag & MNEW) 6321590Srgrimes n++; 6331590Srgrimes if ((mp->m_flag & MREAD) == 0) 6341590Srgrimes u++; 6351590Srgrimes if (mp->m_flag & MDELETED) 6361590Srgrimes d++; 6371590Srgrimes if (mp->m_flag & MSAVED) 6381590Srgrimes s++; 6391590Srgrimes } 6401590Srgrimes ename = mailname; 64174769Smikeh if (getfold(fname, sizeof(fname) - 1) >= 0) { 6421590Srgrimes strcat(fname, "/"); 6431590Srgrimes if (strncmp(fname, mailname, strlen(fname)) == 0) { 64477274Smikeh (void)snprintf(zname, sizeof(zname), "+%s", 64577274Smikeh mailname + strlen(fname)); 6461590Srgrimes ename = zname; 6471590Srgrimes } 6481590Srgrimes } 6491590Srgrimes printf("\"%s\": ", ename); 6501590Srgrimes if (msgCount == 1) 6511590Srgrimes printf("1 message"); 6521590Srgrimes else 6531590Srgrimes printf("%d messages", msgCount); 6541590Srgrimes if (n > 0) 6551590Srgrimes printf(" %d new", n); 6561590Srgrimes if (u-n > 0) 6571590Srgrimes printf(" %d unread", u); 6581590Srgrimes if (d > 0) 6591590Srgrimes printf(" %d deleted", d); 6601590Srgrimes if (s > 0) 6611590Srgrimes printf(" %d saved", s); 6621590Srgrimes if (readonly) 6631590Srgrimes printf(" [Read only]"); 6641590Srgrimes printf("\n"); 66577274Smikeh return (mdot); 6661590Srgrimes} 6671590Srgrimes 6681590Srgrimes/* 6691590Srgrimes * Print the current version number. 6701590Srgrimes */ 6711590Srgrimes 6721590Srgrimesint 673216564Scharnierpversion(int e __unused) 6741590Srgrimes{ 6751590Srgrimes 6761590Srgrimes printf("Version %s\n", version); 67777274Smikeh return (0); 6781590Srgrimes} 6791590Srgrimes 6801590Srgrimes/* 6811590Srgrimes * Load a file of user definitions. 6821590Srgrimes */ 6831590Srgrimesvoid 684216564Scharnierload(char *name) 6851590Srgrimes{ 68677274Smikeh FILE *in, *oldin; 6871590Srgrimes 6881590Srgrimes if ((in = Fopen(name, "r")) == NULL) 6891590Srgrimes return; 6901590Srgrimes oldin = input; 6911590Srgrimes input = in; 6921590Srgrimes loading = 1; 6931590Srgrimes sourcing = 1; 6941590Srgrimes commands(); 6951590Srgrimes loading = 0; 6961590Srgrimes sourcing = 0; 6971590Srgrimes input = oldin; 69877274Smikeh (void)Fclose(in); 6991590Srgrimes} 700