lex.c revision 29574
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 * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 351590Srgrimesstatic char sccsid[] = "@(#)lex.c 8.1 (Berkeley) 6/6/93"; 361590Srgrimes#endif /* not lint */ 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 491590Srgrimeschar *prompt = "& "; 501590Srgrimes 511590Srgrimes/* 521590Srgrimes * Set up editing on the given file name. 531590Srgrimes * If the first character of name is %, we are considered to be 541590Srgrimes * editing the file, otherwise we are reading our mail which has 551590Srgrimes * signficance for mbox and so forth. 561590Srgrimes */ 571590Srgrimesint 581590Srgrimessetfile(name) 591590Srgrimes char *name; 601590Srgrimes{ 611590Srgrimes FILE *ibuf; 621590Srgrimes int i; 631590Srgrimes struct stat stb; 641590Srgrimes char isedit = *name != '%'; 651590Srgrimes char *who = name[1] ? name + 1 : myname; 661590Srgrimes static int shudclob; 671590Srgrimes extern char tempMesg[]; 681590Srgrimes extern int errno; 691590Srgrimes 701590Srgrimes if ((name = expand(name)) == NOSTR) 711590Srgrimes return -1; 721590Srgrimes 731590Srgrimes if ((ibuf = Fopen(name, "r")) == NULL) { 741590Srgrimes if (!isedit && errno == ENOENT) 751590Srgrimes goto nomail; 761590Srgrimes perror(name); 771590Srgrimes return(-1); 781590Srgrimes } 791590Srgrimes 801590Srgrimes if (fstat(fileno(ibuf), &stb) < 0) { 811590Srgrimes perror("fstat"); 821590Srgrimes Fclose(ibuf); 831590Srgrimes return (-1); 841590Srgrimes } 851590Srgrimes 861590Srgrimes switch (stb.st_mode & S_IFMT) { 871590Srgrimes case S_IFDIR: 881590Srgrimes Fclose(ibuf); 891590Srgrimes errno = EISDIR; 901590Srgrimes perror(name); 911590Srgrimes return (-1); 921590Srgrimes 931590Srgrimes case S_IFREG: 941590Srgrimes break; 951590Srgrimes 961590Srgrimes default: 971590Srgrimes Fclose(ibuf); 981590Srgrimes errno = EINVAL; 991590Srgrimes perror(name); 1001590Srgrimes return (-1); 1011590Srgrimes } 1021590Srgrimes 1031590Srgrimes /* 1041590Srgrimes * Looks like all will be well. We must now relinquish our 1051590Srgrimes * hold on the current set of stuff. Must hold signals 1061590Srgrimes * while we are reading the new file, else we will ruin 1071590Srgrimes * the message[] data structure. 1081590Srgrimes */ 1091590Srgrimes 1101590Srgrimes holdsigs(); 1111590Srgrimes if (shudclob) 1121590Srgrimes quit(); 1131590Srgrimes 1141590Srgrimes /* 1151590Srgrimes * Copy the messages into /tmp 1161590Srgrimes * and set pointers. 1171590Srgrimes */ 1181590Srgrimes 1191590Srgrimes readonly = 0; 1201590Srgrimes if ((i = open(name, 1)) < 0) 1211590Srgrimes readonly++; 1221590Srgrimes else 1231590Srgrimes close(i); 1241590Srgrimes if (shudclob) { 1251590Srgrimes fclose(itf); 1261590Srgrimes fclose(otf); 1271590Srgrimes } 1281590Srgrimes shudclob = 1; 1291590Srgrimes edit = isedit; 1301590Srgrimes strcpy(prevfile, mailname); 1311590Srgrimes if (name != mailname) 1321590Srgrimes strcpy(mailname, name); 1331590Srgrimes mailsize = fsize(ibuf); 1341590Srgrimes if ((otf = fopen(tempMesg, "w")) == NULL) { 1351590Srgrimes perror(tempMesg); 1361590Srgrimes exit(1); 1371590Srgrimes } 1381590Srgrimes (void) fcntl(fileno(otf), F_SETFD, 1); 1391590Srgrimes if ((itf = fopen(tempMesg, "r")) == NULL) { 1401590Srgrimes perror(tempMesg); 1411590Srgrimes exit(1); 1421590Srgrimes } 1431590Srgrimes (void) fcntl(fileno(itf), F_SETFD, 1); 1441590Srgrimes rm(tempMesg); 1451590Srgrimes setptr(ibuf); 1461590Srgrimes setmsize(msgCount); 1471590Srgrimes Fclose(ibuf); 1481590Srgrimes relsesigs(); 1491590Srgrimes sawcom = 0; 1501590Srgrimes if (!edit && msgCount == 0) { 1511590Srgrimesnomail: 1521590Srgrimes fprintf(stderr, "No mail for %s\n", who); 1531590Srgrimes return -1; 1541590Srgrimes } 1551590Srgrimes return(0); 1561590Srgrimes} 1571590Srgrimes 1581590Srgrimesint *msgvec; 1591590Srgrimesint reset_on_stop; /* do a reset() if stopped */ 1601590Srgrimes 1611590Srgrimes/* 1621590Srgrimes * Interpret user commands one by one. If standard input is not a tty, 1631590Srgrimes * print no prompt. 1641590Srgrimes */ 1651590Srgrimesvoid 1661590Srgrimescommands() 1671590Srgrimes{ 1681590Srgrimes int eofloop = 0; 1691590Srgrimes register int n; 1701590Srgrimes char linebuf[LINESIZE]; 1711590Srgrimes void intr(), stop(), hangup(); 1721590Srgrimes 1731590Srgrimes if (!sourcing) { 1741590Srgrimes if (signal(SIGINT, SIG_IGN) != SIG_IGN) 1751590Srgrimes signal(SIGINT, intr); 1761590Srgrimes if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 1771590Srgrimes signal(SIGHUP, hangup); 1781590Srgrimes signal(SIGTSTP, stop); 1791590Srgrimes signal(SIGTTOU, stop); 1801590Srgrimes signal(SIGTTIN, stop); 1811590Srgrimes } 1821590Srgrimes setexit(); 1831590Srgrimes for (;;) { 1841590Srgrimes /* 1851590Srgrimes * Print the prompt, if needed. Clear out 1861590Srgrimes * string space, and flush the output. 1871590Srgrimes */ 1881590Srgrimes if (!sourcing && value("interactive") != NOSTR) { 1891590Srgrimes reset_on_stop = 1; 1901590Srgrimes printf(prompt); 1911590Srgrimes } 1921590Srgrimes fflush(stdout); 1931590Srgrimes sreset(); 1941590Srgrimes /* 1951590Srgrimes * Read a line of commands from the current input 1961590Srgrimes * and handle end of file specially. 1971590Srgrimes */ 1981590Srgrimes n = 0; 1991590Srgrimes for (;;) { 2001590Srgrimes if (readline(input, &linebuf[n], LINESIZE - n) < 0) { 2011590Srgrimes if (n == 0) 2021590Srgrimes n = -1; 2031590Srgrimes break; 2041590Srgrimes } 2051590Srgrimes if ((n = strlen(linebuf)) == 0) 2061590Srgrimes break; 2071590Srgrimes n--; 2081590Srgrimes if (linebuf[n] != '\\') 2091590Srgrimes break; 2101590Srgrimes linebuf[n++] = ' '; 2111590Srgrimes } 2121590Srgrimes reset_on_stop = 0; 2131590Srgrimes if (n < 0) { 2141590Srgrimes /* eof */ 2151590Srgrimes if (loading) 2161590Srgrimes break; 2171590Srgrimes if (sourcing) { 2181590Srgrimes unstack(); 2191590Srgrimes continue; 2201590Srgrimes } 2211590Srgrimes if (value("interactive") != NOSTR && 2221590Srgrimes value("ignoreeof") != NOSTR && 2231590Srgrimes ++eofloop < 25) { 2241590Srgrimes printf("Use \"quit\" to quit.\n"); 2251590Srgrimes continue; 2261590Srgrimes } 2271590Srgrimes break; 2281590Srgrimes } 2291590Srgrimes eofloop = 0; 2301590Srgrimes if (execute(linebuf, 0)) 2311590Srgrimes break; 2321590Srgrimes } 2331590Srgrimes} 2341590Srgrimes 2351590Srgrimes/* 2361590Srgrimes * Execute a single command. 2371590Srgrimes * Command functions return 0 for success, 1 for error, and -1 2381590Srgrimes * for abort. A 1 or -1 aborts a load or source. A -1 aborts 2391590Srgrimes * the interactive command loop. 2401590Srgrimes * Contxt is non-zero if called while composing mail. 2411590Srgrimes */ 2421590Srgrimesint 2431590Srgrimesexecute(linebuf, contxt) 2441590Srgrimes char linebuf[]; 2451590Srgrimes int contxt; 2461590Srgrimes{ 2471590Srgrimes char word[LINESIZE]; 2481590Srgrimes char *arglist[MAXARGC]; 2491590Srgrimes struct cmd *com; 2501590Srgrimes register char *cp, *cp2; 2511590Srgrimes register int c; 2521590Srgrimes int muvec[2]; 2531590Srgrimes int e = 1; 2541590Srgrimes 2551590Srgrimes /* 2561590Srgrimes * Strip the white space away from the beginning 2571590Srgrimes * of the command, then scan out a word, which 2581590Srgrimes * consists of anything except digits and white space. 2591590Srgrimes * 2601590Srgrimes * Handle ! escapes differently to get the correct 2611590Srgrimes * lexical conventions. 2621590Srgrimes */ 2631590Srgrimes 2641590Srgrimes for (cp = linebuf; isspace(*cp); cp++) 2651590Srgrimes ; 2661590Srgrimes if (*cp == '!') { 2671590Srgrimes if (sourcing) { 2681590Srgrimes printf("Can't \"!\" while sourcing\n"); 2691590Srgrimes goto out; 2701590Srgrimes } 2711590Srgrimes shell(cp+1); 2721590Srgrimes return(0); 2731590Srgrimes } 2741590Srgrimes cp2 = word; 2751590Srgrimes while (*cp && index(" \t0123456789$^.:/-+*'\"", *cp) == NOSTR) 2761590Srgrimes *cp2++ = *cp++; 2771590Srgrimes *cp2 = '\0'; 2781590Srgrimes 2791590Srgrimes /* 2801590Srgrimes * Look up the command; if not found, bitch. 2811590Srgrimes * Normally, a blank command would map to the 2821590Srgrimes * first command in the table; while sourcing, 2831590Srgrimes * however, we ignore blank lines to eliminate 2841590Srgrimes * confusion. 2851590Srgrimes */ 2861590Srgrimes 2871590Srgrimes if (sourcing && *word == '\0') 2881590Srgrimes return(0); 2891590Srgrimes com = lex(word); 2901590Srgrimes if (com == NONE) { 2911590Srgrimes printf("Unknown command: \"%s\"\n", word); 2921590Srgrimes goto out; 2931590Srgrimes } 2941590Srgrimes 2951590Srgrimes /* 2961590Srgrimes * See if we should execute the command -- if a conditional 2971590Srgrimes * we always execute it, otherwise, check the state of cond. 2981590Srgrimes */ 2991590Srgrimes 3001590Srgrimes if ((com->c_argtype & F) == 0) 3011590Srgrimes if (cond == CRCV && !rcvmode || cond == CSEND && rcvmode) 3021590Srgrimes return(0); 3031590Srgrimes 3041590Srgrimes /* 3051590Srgrimes * Process the arguments to the command, depending 3061590Srgrimes * on the type he expects. Default to an error. 3071590Srgrimes * If we are sourcing an interactive command, it's 3081590Srgrimes * an error. 3091590Srgrimes */ 3101590Srgrimes 3111590Srgrimes if (!rcvmode && (com->c_argtype & M) == 0) { 3121590Srgrimes printf("May not execute \"%s\" while sending\n", 3131590Srgrimes com->c_name); 3141590Srgrimes goto out; 3151590Srgrimes } 3161590Srgrimes if (sourcing && com->c_argtype & I) { 3171590Srgrimes printf("May not execute \"%s\" while sourcing\n", 3181590Srgrimes com->c_name); 3191590Srgrimes goto out; 3201590Srgrimes } 3211590Srgrimes if (readonly && com->c_argtype & W) { 3221590Srgrimes printf("May not execute \"%s\" -- message file is read only\n", 3231590Srgrimes com->c_name); 3241590Srgrimes goto out; 3251590Srgrimes } 3261590Srgrimes if (contxt && com->c_argtype & R) { 3271590Srgrimes printf("Cannot recursively invoke \"%s\"\n", com->c_name); 3281590Srgrimes goto out; 3291590Srgrimes } 3301590Srgrimes switch (com->c_argtype & ~(F|P|I|M|T|W|R)) { 3311590Srgrimes case MSGLIST: 3321590Srgrimes /* 3331590Srgrimes * A message list defaulting to nearest forward 3341590Srgrimes * legal message. 3351590Srgrimes */ 3361590Srgrimes if (msgvec == 0) { 3371590Srgrimes printf("Illegal use of \"message list\"\n"); 3381590Srgrimes break; 3391590Srgrimes } 3401590Srgrimes if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0) 3411590Srgrimes break; 3421590Srgrimes if (c == 0) { 3431590Srgrimes *msgvec = first(com->c_msgflag, 3441590Srgrimes com->c_msgmask); 34529574Sphk msgvec[1] = 0; 3461590Srgrimes } 34729574Sphk if (*msgvec == 0) { 3481590Srgrimes printf("No applicable messages\n"); 3491590Srgrimes break; 3501590Srgrimes } 3511590Srgrimes e = (*com->c_func)(msgvec); 3521590Srgrimes break; 3531590Srgrimes 3541590Srgrimes case NDMLIST: 3551590Srgrimes /* 3561590Srgrimes * A message list with no defaults, but no error 3571590Srgrimes * if none exist. 3581590Srgrimes */ 3591590Srgrimes if (msgvec == 0) { 3601590Srgrimes printf("Illegal use of \"message list\"\n"); 3611590Srgrimes break; 3621590Srgrimes } 3631590Srgrimes if (getmsglist(cp, msgvec, com->c_msgflag) < 0) 3641590Srgrimes break; 3651590Srgrimes e = (*com->c_func)(msgvec); 3661590Srgrimes break; 3671590Srgrimes 3681590Srgrimes case STRLIST: 3691590Srgrimes /* 3701590Srgrimes * Just the straight string, with 3711590Srgrimes * leading blanks removed. 3721590Srgrimes */ 3731590Srgrimes while (isspace(*cp)) 3741590Srgrimes cp++; 3751590Srgrimes e = (*com->c_func)(cp); 3761590Srgrimes break; 3771590Srgrimes 3781590Srgrimes case RAWLIST: 3791590Srgrimes /* 3801590Srgrimes * A vector of strings, in shell style. 3811590Srgrimes */ 3821590Srgrimes if ((c = getrawlist(cp, arglist, 3831590Srgrimes sizeof arglist / sizeof *arglist)) < 0) 3841590Srgrimes break; 3851590Srgrimes if (c < com->c_minargs) { 3861590Srgrimes printf("%s requires at least %d arg(s)\n", 3871590Srgrimes com->c_name, com->c_minargs); 3881590Srgrimes break; 3891590Srgrimes } 3901590Srgrimes if (c > com->c_maxargs) { 3911590Srgrimes printf("%s takes no more than %d arg(s)\n", 3921590Srgrimes com->c_name, com->c_maxargs); 3931590Srgrimes break; 3941590Srgrimes } 3951590Srgrimes e = (*com->c_func)(arglist); 3961590Srgrimes break; 3971590Srgrimes 3981590Srgrimes case NOLIST: 3991590Srgrimes /* 4001590Srgrimes * Just the constant zero, for exiting, 4011590Srgrimes * eg. 4021590Srgrimes */ 4031590Srgrimes e = (*com->c_func)(0); 4041590Srgrimes break; 4051590Srgrimes 4061590Srgrimes default: 4071590Srgrimes panic("Unknown argtype"); 4081590Srgrimes } 4091590Srgrimes 4101590Srgrimesout: 4111590Srgrimes /* 4121590Srgrimes * Exit the current source file on 4131590Srgrimes * error. 4141590Srgrimes */ 4151590Srgrimes if (e) { 4161590Srgrimes if (e < 0) 4171590Srgrimes return 1; 4181590Srgrimes if (loading) 4191590Srgrimes return 1; 4201590Srgrimes if (sourcing) 4211590Srgrimes unstack(); 4221590Srgrimes return 0; 4231590Srgrimes } 4241590Srgrimes if (value("autoprint") != NOSTR && com->c_argtype & P) 4251590Srgrimes if ((dot->m_flag & MDELETED) == 0) { 4261590Srgrimes muvec[0] = dot - &message[0] + 1; 4271590Srgrimes muvec[1] = 0; 4281590Srgrimes type(muvec); 4291590Srgrimes } 4301590Srgrimes if (!sourcing && (com->c_argtype & T) == 0) 4311590Srgrimes sawcom = 1; 4321590Srgrimes return(0); 4331590Srgrimes} 4341590Srgrimes 4351590Srgrimes/* 4361590Srgrimes * Set the size of the message vector used to construct argument 4371590Srgrimes * lists to message list functions. 4381590Srgrimes */ 4391590Srgrimesvoid 4401590Srgrimessetmsize(sz) 4411590Srgrimes int sz; 4421590Srgrimes{ 4431590Srgrimes 4441590Srgrimes if (msgvec != 0) 4451590Srgrimes free((char *) msgvec); 4461590Srgrimes msgvec = (int *) calloc((unsigned) (sz + 1), sizeof *msgvec); 4471590Srgrimes} 4481590Srgrimes 4491590Srgrimes/* 4501590Srgrimes * Find the correct command in the command table corresponding 4511590Srgrimes * to the passed command "word" 4521590Srgrimes */ 4531590Srgrimes 4541590Srgrimesstruct cmd * 4551590Srgrimeslex(word) 4561590Srgrimes char word[]; 4571590Srgrimes{ 4581590Srgrimes register struct cmd *cp; 4591590Srgrimes extern struct cmd cmdtab[]; 4601590Srgrimes 46110067Sjoerg /* 46210067Sjoerg * ignore trailing chars after `#' 46310067Sjoerg * 46410067Sjoerg * lines with beginning `#' are comments 46510067Sjoerg * spaces befor `#' are ignored in execute() 46610067Sjoerg */ 46710067Sjoerg 46810067Sjoerg if (*word == '#') 46910067Sjoerg *(word+1) = '\0'; 47010067Sjoerg 47110067Sjoerg 4721590Srgrimes for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++) 4731590Srgrimes if (isprefix(word, cp->c_name)) 4741590Srgrimes return(cp); 4751590Srgrimes return(NONE); 4761590Srgrimes} 4771590Srgrimes 4781590Srgrimes/* 4791590Srgrimes * Determine if as1 is a valid prefix of as2. 4801590Srgrimes * Return true if yep. 4811590Srgrimes */ 4821590Srgrimesint 4831590Srgrimesisprefix(as1, as2) 4841590Srgrimes char *as1, *as2; 4851590Srgrimes{ 4861590Srgrimes register char *s1, *s2; 4871590Srgrimes 4881590Srgrimes s1 = as1; 4891590Srgrimes s2 = as2; 4901590Srgrimes while (*s1++ == *s2) 4911590Srgrimes if (*s2++ == '\0') 4921590Srgrimes return(1); 4931590Srgrimes return(*--s1 == '\0'); 4941590Srgrimes} 4951590Srgrimes 4961590Srgrimes/* 4971590Srgrimes * The following gets called on receipt of an interrupt. This is 4981590Srgrimes * to abort printout of a command, mainly. 4991590Srgrimes * Dispatching here when command() is inactive crashes rcv. 5001590Srgrimes * Close all open files except 0, 1, 2, and the temporary. 5011590Srgrimes * Also, unstack all source files. 5021590Srgrimes */ 5031590Srgrimes 5041590Srgrimesint inithdr; /* am printing startup headers */ 5051590Srgrimes 5061590Srgrimes/*ARGSUSED*/ 5071590Srgrimesvoid 5081590Srgrimesintr(s) 5091590Srgrimes int s; 5101590Srgrimes{ 5111590Srgrimes 5121590Srgrimes noreset = 0; 5131590Srgrimes if (!inithdr) 5141590Srgrimes sawcom++; 5151590Srgrimes inithdr = 0; 5161590Srgrimes while (sourcing) 5171590Srgrimes unstack(); 5181590Srgrimes 5191590Srgrimes close_all_files(); 5201590Srgrimes 5211590Srgrimes if (image >= 0) { 5221590Srgrimes close(image); 5231590Srgrimes image = -1; 5241590Srgrimes } 5251590Srgrimes fprintf(stderr, "Interrupt\n"); 5261590Srgrimes reset(0); 5271590Srgrimes} 5281590Srgrimes 5291590Srgrimes/* 5301590Srgrimes * When we wake up after ^Z, reprint the prompt. 5311590Srgrimes */ 5321590Srgrimesvoid 5331590Srgrimesstop(s) 5341590Srgrimes int s; 5351590Srgrimes{ 5361590Srgrimes sig_t old_action = signal(s, SIG_DFL); 5371590Srgrimes 5381590Srgrimes sigsetmask(sigblock(0) & ~sigmask(s)); 5391590Srgrimes kill(0, s); 5401590Srgrimes sigblock(sigmask(s)); 5411590Srgrimes signal(s, old_action); 5421590Srgrimes if (reset_on_stop) { 5431590Srgrimes reset_on_stop = 0; 5441590Srgrimes reset(0); 5451590Srgrimes } 5461590Srgrimes} 5471590Srgrimes 5481590Srgrimes/* 5491590Srgrimes * Branch here on hangup signal and simulate "exit". 5501590Srgrimes */ 5511590Srgrimes/*ARGSUSED*/ 5521590Srgrimesvoid 5531590Srgrimeshangup(s) 5541590Srgrimes int s; 5551590Srgrimes{ 5561590Srgrimes 5571590Srgrimes /* nothing to do? */ 5581590Srgrimes exit(1); 5591590Srgrimes} 5601590Srgrimes 5611590Srgrimes/* 5621590Srgrimes * Announce the presence of the current Mail version, 5631590Srgrimes * give the message count, and print a header listing. 5641590Srgrimes */ 5651590Srgrimesvoid 5661590Srgrimesannounce() 5671590Srgrimes{ 5681590Srgrimes int vec[2], mdot; 5691590Srgrimes 5701590Srgrimes mdot = newfileinfo(); 5711590Srgrimes vec[0] = mdot; 5721590Srgrimes vec[1] = 0; 5731590Srgrimes dot = &message[mdot - 1]; 5741590Srgrimes if (msgCount > 0 && value("noheader") == NOSTR) { 5751590Srgrimes inithdr++; 5761590Srgrimes headers(vec); 5771590Srgrimes inithdr = 0; 5781590Srgrimes } 5791590Srgrimes} 5801590Srgrimes 5811590Srgrimes/* 5821590Srgrimes * Announce information about the file we are editing. 5831590Srgrimes * Return a likely place to set dot. 5841590Srgrimes */ 5851590Srgrimesint 5861590Srgrimesnewfileinfo() 5871590Srgrimes{ 5881590Srgrimes register struct message *mp; 5891590Srgrimes register int u, n, mdot, d, s; 5901590Srgrimes char fname[BUFSIZ], zname[BUFSIZ], *ename; 5911590Srgrimes 5921590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 5931590Srgrimes if (mp->m_flag & MNEW) 5941590Srgrimes break; 5951590Srgrimes if (mp >= &message[msgCount]) 5961590Srgrimes for (mp = &message[0]; mp < &message[msgCount]; mp++) 5971590Srgrimes if ((mp->m_flag & MREAD) == 0) 5981590Srgrimes break; 5991590Srgrimes if (mp < &message[msgCount]) 6001590Srgrimes mdot = mp - &message[0] + 1; 6011590Srgrimes else 6021590Srgrimes mdot = 1; 6031590Srgrimes s = d = 0; 6041590Srgrimes for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) { 6051590Srgrimes if (mp->m_flag & MNEW) 6061590Srgrimes n++; 6071590Srgrimes if ((mp->m_flag & MREAD) == 0) 6081590Srgrimes u++; 6091590Srgrimes if (mp->m_flag & MDELETED) 6101590Srgrimes d++; 6111590Srgrimes if (mp->m_flag & MSAVED) 6121590Srgrimes s++; 6131590Srgrimes } 6141590Srgrimes ename = mailname; 6151590Srgrimes if (getfold(fname) >= 0) { 6161590Srgrimes strcat(fname, "/"); 6171590Srgrimes if (strncmp(fname, mailname, strlen(fname)) == 0) { 6181590Srgrimes sprintf(zname, "+%s", mailname + strlen(fname)); 6191590Srgrimes ename = zname; 6201590Srgrimes } 6211590Srgrimes } 6221590Srgrimes printf("\"%s\": ", ename); 6231590Srgrimes if (msgCount == 1) 6241590Srgrimes printf("1 message"); 6251590Srgrimes else 6261590Srgrimes printf("%d messages", msgCount); 6271590Srgrimes if (n > 0) 6281590Srgrimes printf(" %d new", n); 6291590Srgrimes if (u-n > 0) 6301590Srgrimes printf(" %d unread", u); 6311590Srgrimes if (d > 0) 6321590Srgrimes printf(" %d deleted", d); 6331590Srgrimes if (s > 0) 6341590Srgrimes printf(" %d saved", s); 6351590Srgrimes if (readonly) 6361590Srgrimes printf(" [Read only]"); 6371590Srgrimes printf("\n"); 6381590Srgrimes return(mdot); 6391590Srgrimes} 6401590Srgrimes 6411590Srgrimes/* 6421590Srgrimes * Print the current version number. 6431590Srgrimes */ 6441590Srgrimes 6451590Srgrimes/*ARGSUSED*/ 6461590Srgrimesint 6471590Srgrimespversion(e) 6481590Srgrimes int e; 6491590Srgrimes{ 6501590Srgrimes extern char *version; 6511590Srgrimes 6521590Srgrimes printf("Version %s\n", version); 6531590Srgrimes return(0); 6541590Srgrimes} 6551590Srgrimes 6561590Srgrimes/* 6571590Srgrimes * Load a file of user definitions. 6581590Srgrimes */ 6591590Srgrimesvoid 6601590Srgrimesload(name) 6611590Srgrimes char *name; 6621590Srgrimes{ 6631590Srgrimes register FILE *in, *oldin; 6641590Srgrimes 6651590Srgrimes if ((in = Fopen(name, "r")) == NULL) 6661590Srgrimes return; 6671590Srgrimes oldin = input; 6681590Srgrimes input = in; 6691590Srgrimes loading = 1; 6701590Srgrimes sourcing = 1; 6711590Srgrimes commands(); 6721590Srgrimes loading = 0; 6731590Srgrimes sourcing = 0; 6741590Srgrimes input = oldin; 6751590Srgrimes Fclose(in); 6761590Srgrimes} 677