1: /*
   2:  * Copyright (c) 1980 Regents of the University of California.
   3:  * All rights reserved.
   4:  *
   5:  * Redistribution and use in source and binary forms, with or without
   6:  * modification, are permitted provided that the following conditions
   7:  * are met:
   8:  * 1. Redistributions of source code must retain the above copyright
   9:  *    notice, this list of conditions and the following disclaimer.
  10:  * 2. Redistributions in binary form must reproduce the above copyright
  11:  *    notice, this list of conditions and the following disclaimer in the
  12:  *    documentation and/or other materials provided with the distribution.
  13:  * 3. All advertising materials mentioning features or use of this software
  14:  *    must display the following acknowledgement:
  15:  *	This product includes software developed by the University of
  16:  *	California, Berkeley and its contributors.
  17:  * 4. Neither the name of the University nor the names of its contributors
  18:  *    may be used to endorse or promote products derived from this software
  19:  *    without specific prior written permission.
  20:  *
  21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31:  * SUCH DAMAGE.
  32:  */
  33: 
  34: #if !defined(lint) && defined(DOSCCS)
  35: static char sccsid[] = "@(#)lex.c	5.23 (Berkeley) 4/1/91";
  36: #endif
  37: 
  38: #include "rcv.h"
  39: #include <sys/stat.h>
  40: #include <errno.h>
  41: 
  42: /*
  43:  * Mail -- a mail program
  44:  *
  45:  * Lexical processing of commands.
  46:  */
  47: 
  48: char    *prompt = "& ";
  49: 
  50: /*
  51:  * Set up editing on the given file name.
  52:  * If the first character of name is %, we are considered to be
  53:  * editing the file, otherwise we are reading our mail which has
  54:  * signficance for mbox and so forth.
  55:  */
  56: setfile(name)
  57:     char *name;
  58: {
  59:     FILE *ibuf;
  60:     int i;
  61:     struct stat stb;
  62:     char isedit = *name != '%';
  63:     char *who = name[1] ? name + 1 : myname;
  64:     static int shudclob;
  65:     extern char tempMesg[];
  66:     extern int errno;
  67: 
  68:     if ((name = expand(name)) == NOSTR)
  69:         return -1;
  70: 
  71:     if ((ibuf = Fopen(name, "r")) == NULL) {
  72:         if (!isedit && errno == ENOENT)
  73:             goto nomail;
  74:         perror(name);
  75:         return(-1);
  76:     }
  77: 
  78:     if (fstat(fileno(ibuf), &stb) < 0) {
  79:         perror("fstat");
  80:         Fclose(ibuf);
  81:         return (-1);
  82:     }
  83: 
  84:     switch (stb.st_mode & S_IFMT) {
  85:     case S_IFDIR:
  86:         Fclose(ibuf);
  87:         errno = EISDIR;
  88:         perror(name);
  89:         return (-1);
  90: 
  91:     case S_IFREG:
  92:         break;
  93: 
  94:     default:
  95:         Fclose(ibuf);
  96:         errno = EINVAL;
  97:         perror(name);
  98:         return (-1);
  99:     }
 100: 
 101:     /*
 102: 	 * Looks like all will be well.  We must now relinquish our
 103: 	 * hold on the current set of stuff.  Must hold signals
 104: 	 * while we are reading the new file, else we will ruin
 105: 	 * the message[] data structure.
 106: 	 */
 107: 
 108:     holdsigs();
 109:     if (shudclob)
 110:         quit();
 111: 
 112:     /*
 113: 	 * Copy the messages into /tmp
 114: 	 * and set pointers.
 115: 	 */
 116: 
 117:     readonly = 0;
 118:     if ((i = open(name, 1)) < 0)
 119:         readonly++;
 120:     else
 121:         close(i);
 122:     if (shudclob) {
 123:         fclose(itf);
 124:         fclose(otf);
 125:     }
 126:     shudclob = 1;
 127:     edit = isedit;
 128:     strcpy(prevfile, mailname);
 129:     if (name != mailname)
 130:         strcpy(mailname, name);
 131:     mailsize = fsize(ibuf);
 132:     if ((otf = fopen(tempMesg, "w")) == NULL) {
 133:         perror(tempMesg);
 134:         exit(1);
 135:     }
 136:     if ((itf = fopen(tempMesg, "r")) == NULL) {
 137:         perror(tempMesg);
 138:         exit(1);
 139:     }
 140:     rm(tempMesg);
 141:     setptr(ibuf);
 142:     setmsize(msgCount);
 143:     Fclose(ibuf);
 144:     relsesigs();
 145:     sawcom = 0;
 146:     if (!edit && msgCount == 0) {
 147: nomail:
 148:         fprintf(stderr, "No mail for %s\n", who);
 149:         return -1;
 150:     }
 151:     return(0);
 152: }
 153: 
 154: int *msgvec;
 155: int reset_on_stop;          /* do a reset() if stopped */
 156: 
 157: /*
 158:  * Interpret user commands one by one.  If standard input is not a tty,
 159:  * print no prompt.
 160:  */
 161: commands()
 162: {
 163:     int eofloop = 0;
 164:     register int n;
 165:     char linebuf[LINESIZE];
 166:     void intr(), stop(), hangup();
 167: 
 168:     if (!sourcing) {
 169:         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
 170:             signal(SIGINT, intr);
 171:         if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
 172:             signal(SIGHUP, hangup);
 173:         signal(SIGTSTP, stop);
 174:         signal(SIGTTOU, stop);
 175:         signal(SIGTTIN, stop);
 176:     }
 177:     setexit();
 178:     for (;;) {
 179:         /*
 180: 		 * Print the prompt, if needed.  Clear out
 181: 		 * string space, and flush the output.
 182: 		 */
 183:         if (!sourcing && value("interactive") != NOSTR) {
 184:             reset_on_stop = 1;
 185:             printf(prompt);
 186:         }
 187:         fflush(stdout);
 188:         sreset();
 189:         /*
 190: 		 * Read a line of commands from the current input
 191: 		 * and handle end of file specially.
 192: 		 */
 193:         n = 0;
 194:         for (;;) {
 195:             if (readline(input, &linebuf[n], LINESIZE - n) < 0) {
 196:                 if (n == 0)
 197:                     n = -1;
 198:                 break;
 199:             }
 200:             if ((n = strlen(linebuf)) == 0)
 201:                 break;
 202:             n--;
 203:             if (linebuf[n] != '\\')
 204:                 break;
 205:             linebuf[n++] = ' ';
 206:         }
 207:         reset_on_stop = 0;
 208:         if (n < 0) {
 209:                 /* eof */
 210:             if (loading)
 211:                 break;
 212:             if (sourcing) {
 213:                 unstack();
 214:                 continue;
 215:             }
 216:             if (value("interactive") != NOSTR &&
 217:                 value("ignoreeof") != NOSTR &&
 218:                 ++eofloop < 25) {
 219:                 printf("Use \"quit\" to quit.\n");
 220:                 continue;
 221:             }
 222:             break;
 223:         }
 224:         eofloop = 0;
 225:         if (execute(linebuf, 0))
 226:             break;
 227:     }
 228: }
 229: 
 230: /*
 231:  * Execute a single command.
 232:  * Command functions return 0 for success, 1 for error, and -1
 233:  * for abort.  A 1 or -1 aborts a load or source.  A -1 aborts
 234:  * the interactive command loop.
 235:  * Contxt is non-zero if called while composing mail.
 236:  */
 237: execute(linebuf, contxt)
 238:     char linebuf[];
 239: {
 240:     char word[LINESIZE];
 241:     char *arglist[MAXARGC];
 242:     struct cmd *com;
 243:     register char *cp, *cp2;
 244:     register int c;
 245:     int muvec[2];
 246:     int e = 1;
 247: 
 248:     /*
 249: 	 * Strip the white space away from the beginning
 250: 	 * of the command, then scan out a word, which
 251: 	 * consists of anything except digits and white space.
 252: 	 *
 253: 	 * Handle ! escapes differently to get the correct
 254: 	 * lexical conventions.
 255: 	 */
 256: 
 257:     for (cp = linebuf; isspace(*cp); cp++)
 258:         ;
 259:     if (*cp == '!') {
 260:         if (sourcing) {
 261:             printf("Can't \"!\" while sourcing\n");
 262:             goto out;
 263:         }
 264:         shell(cp+1);
 265:         return(0);
 266:     }
 267:     cp2 = word;
 268:     while (*cp && index(" \t0123456789$^.:/-+*'\"", *cp) == NOSTR)
 269:         *cp2++ = *cp++;
 270:     *cp2 = '\0';
 271: 
 272:     /*
 273: 	 * Look up the command; if not found, bitch.
 274: 	 * Normally, a blank command would map to the
 275: 	 * first command in the table; while sourcing,
 276: 	 * however, we ignore blank lines to eliminate
 277: 	 * confusion.
 278: 	 */
 279: 
 280:     if (sourcing && *word == '\0')
 281:         return(0);
 282:     com = lex(word);
 283:     if (com == NONE) {
 284:         printf("Unknown command: \"%s\"\n", word);
 285:         goto out;
 286:     }
 287: 
 288:     /*
 289: 	 * See if we should execute the command -- if a conditional
 290: 	 * we always execute it, otherwise, check the state of cond.
 291: 	 */
 292: 
 293:     if ((com->c_argtype & F) == 0)
 294:         if (cond == CRCV && !rcvmode || cond == CSEND && rcvmode)
 295:             return(0);
 296: 
 297:     /*
 298: 	 * Process the arguments to the command, depending
 299: 	 * on the type he expects.  Default to an error.
 300: 	 * If we are sourcing an interactive command, it's
 301: 	 * an error.
 302: 	 */
 303: 
 304:     if (!rcvmode && (com->c_argtype & M) == 0) {
 305:         printf("May not execute \"%s\" while sending\n",
 306:             com->c_name);
 307:         goto out;
 308:     }
 309:     if (sourcing && com->c_argtype & I) {
 310:         printf("May not execute \"%s\" while sourcing\n",
 311:             com->c_name);
 312:         goto out;
 313:     }
 314:     if (readonly && com->c_argtype & W) {
 315:         printf("May not execute \"%s\" -- message file is read only\n",
 316:            com->c_name);
 317:         goto out;
 318:     }
 319:     if (contxt && com->c_argtype & R) {
 320:         printf("Cannot recursively invoke \"%s\"\n", com->c_name);
 321:         goto out;
 322:     }
 323:     switch (com->c_argtype & ~(F|P|I|M|T|W|R)) {
 324:     case MSGLIST:
 325:         /*
 326: 		 * A message list defaulting to nearest forward
 327: 		 * legal message.
 328: 		 */
 329:         if (msgvec == 0) {
 330:             printf("Illegal use of \"message list\"\n");
 331:             break;
 332:         }
 333:         if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0)
 334:             break;
 335:         if (c  == 0) {
 336:             *msgvec = first(com->c_msgflag,
 337:                 com->c_msgmask);
 338:             msgvec[1] = NULL;
 339:         }
 340:         if (*msgvec == NULL) {
 341:             printf("No applicable messages\n");
 342:             break;
 343:         }
 344:         e = (*com->c_func)(msgvec);
 345:         break;
 346: 
 347:     case NDMLIST:
 348:         /*
 349: 		 * A message list with no defaults, but no error
 350: 		 * if none exist.
 351: 		 */
 352:         if (msgvec == 0) {
 353:             printf("Illegal use of \"message list\"\n");
 354:             break;
 355:         }
 356:         if (getmsglist(cp, msgvec, com->c_msgflag) < 0)
 357:             break;
 358:         e = (*com->c_func)(msgvec);
 359:         break;
 360: 
 361:     case STRLIST:
 362:         /*
 363: 		 * Just the straight string, with
 364: 		 * leading blanks removed.
 365: 		 */
 366:         while (isspace(*cp))
 367:             cp++;
 368:         e = (*com->c_func)(cp);
 369:         break;
 370: 
 371:     case RAWLIST:
 372:         /*
 373: 		 * A vector of strings, in shell style.
 374: 		 */
 375:         if ((c = getrawlist(cp, arglist,
 376:                 sizeof arglist / sizeof *arglist)) < 0)
 377:             break;
 378:         if (c < com->c_minargs) {
 379:             printf("%s requires at least %d arg(s)\n",
 380:                 com->c_name, com->c_minargs);
 381:             break;
 382:         }
 383:         if (c > com->c_maxargs) {
 384:             printf("%s takes no more than %d arg(s)\n",
 385:                 com->c_name, com->c_maxargs);
 386:             break;
 387:         }
 388:         e = (*com->c_func)(arglist);
 389:         break;
 390: 
 391:     case NOLIST:
 392:         /*
 393: 		 * Just the constant zero, for exiting,
 394: 		 * eg.
 395: 		 */
 396:         e = (*com->c_func)(0);
 397:         break;
 398: 
 399:     default:
 400:         panic("Unknown argtype");
 401:     }
 402: 
 403: out:
 404:     /*
 405: 	 * Exit the current source file on
 406: 	 * error.
 407: 	 */
 408:     if (e) {
 409:         if (e < 0)
 410:             return 1;
 411:         if (loading)
 412:             return 1;
 413:         if (sourcing)
 414:             unstack();
 415:         return 0;
 416:     }
 417:     if (value("autoprint") != NOSTR && com->c_argtype & P)
 418:         if ((dot->m_flag & MDELETED) == 0) {
 419:             muvec[0] = dot - &message[0] + 1;
 420:             muvec[1] = 0;
 421:             type(muvec);
 422:         }
 423:     if (!sourcing && (com->c_argtype & T) == 0)
 424:         sawcom = 1;
 425:     return(0);
 426: }
 427: 
 428: /*
 429:  * Set the size of the message vector used to construct argument
 430:  * lists to message list functions.
 431:  */
 432: 
 433: setmsize(sz)
 434: {
 435: 
 436:     if (msgvec != 0)
 437:         cfree((char *) msgvec);
 438:     msgvec = (int *) calloc((unsigned) (sz + 1), sizeof *msgvec);
 439: }
 440: 
 441: /*
 442:  * Find the correct command in the command table corresponding
 443:  * to the passed command "word"
 444:  */
 445: 
 446: struct cmd *
 447: lex(word)
 448:     char word[];
 449: {
 450:     register struct cmd *cp;
 451:     extern struct cmd cmdtab[];
 452: 
 453:     for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++)
 454:         if (isprefix(word, cp->c_name))
 455:             return(cp);
 456:     return(NONE);
 457: }
 458: 
 459: /*
 460:  * Determine if as1 is a valid prefix of as2.
 461:  * Return true if yep.
 462:  */
 463: 
 464: isprefix(as1, as2)
 465:     char *as1, *as2;
 466: {
 467:     register char *s1, *s2;
 468: 
 469:     s1 = as1;
 470:     s2 = as2;
 471:     while (*s1++ == *s2)
 472:         if (*s2++ == '\0')
 473:             return(1);
 474:     return(*--s1 == '\0');
 475: }
 476: 
 477: /*
 478:  * The following gets called on receipt of an interrupt.  This is
 479:  * to abort printout of a command, mainly.
 480:  * Dispatching here when command() is inactive crashes rcv.
 481:  * Close all open files except 0, 1, 2, and the temporary.
 482:  * Also, unstack all source files.
 483:  */
 484: 
 485: int inithdr;            /* am printing startup headers */
 486: 
 487: /*ARGSUSED*/
 488: void
 489: intr(s)
 490: {
 491: 
 492:     noreset = 0;
 493:     if (!inithdr)
 494:         sawcom++;
 495:     inithdr = 0;
 496:     while (sourcing)
 497:         unstack();
 498: 
 499:     close_all_files();
 500: 
 501:     if (image >= 0) {
 502:         close(image);
 503:         image = -1;
 504:     }
 505:     fprintf(stderr, "Interrupt\n");
 506:     reset(0);
 507: }
 508: 
 509: /*
 510:  * When we wake up after ^Z, reprint the prompt.
 511:  */
 512: void
 513: stop(s)
 514: {
 515:     sig_t old_action = signal(s, SIG_DFL);
 516: 
 517:     sigsetmask(sigblock(0L) & ~sigmask(s));
 518:     kill(0, s);
 519:     sigblock(sigmask(s));
 520:     signal(s, old_action);
 521:     if (reset_on_stop) {
 522:         reset_on_stop = 0;
 523:         reset(0);
 524:     }
 525: }
 526: 
 527: /*
 528:  * Branch here on hangup signal and simulate "exit".
 529:  */
 530: /*ARGSUSED*/
 531: void
 532: hangup(s)
 533: {
 534: 
 535:     /* nothing to do? */
 536:     exit(1);
 537: }
 538: 
 539: /*
 540:  * Announce the presence of the current Mail version,
 541:  * give the message count, and print a header listing.
 542:  */
 543: 
 544: announce()
 545: {
 546:     int vec[2], mdot;
 547: 
 548:     mdot = newfileinfo();
 549:     vec[0] = mdot;
 550:     vec[1] = 0;
 551:     dot = &message[mdot - 1];
 552:     if (msgCount > 0 && value("noheader") == NOSTR) {
 553:         inithdr++;
 554:         headers(vec);
 555:         inithdr = 0;
 556:     }
 557: }
 558: 
 559: /*
 560:  * Announce information about the file we are editing.
 561:  * Return a likely place to set dot.
 562:  */
 563: newfileinfo()
 564: {
 565:     register struct message *mp;
 566:     register int u, n, mdot, d, s;
 567:     char fname[BUFSIZ], zname[BUFSIZ], *ename;
 568: 
 569:     for (mp = &message[0]; mp < &message[msgCount]; mp++)
 570:         if (mp->m_flag & MNEW)
 571:             break;
 572:     if (mp >= &message[msgCount])
 573:         for (mp = &message[0]; mp < &message[msgCount]; mp++)
 574:             if ((mp->m_flag & MREAD) == 0)
 575:                 break;
 576:     if (mp < &message[msgCount])
 577:         mdot = mp - &message[0] + 1;
 578:     else
 579:         mdot = 1;
 580:     s = d = 0;
 581:     for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) {
 582:         if (mp->m_flag & MNEW)
 583:             n++;
 584:         if ((mp->m_flag & MREAD) == 0)
 585:             u++;
 586:         if (mp->m_flag & MDELETED)
 587:             d++;
 588:         if (mp->m_flag & MSAVED)
 589:             s++;
 590:     }
 591:     ename = mailname;
 592:     if (getfold(fname) >= 0) {
 593:         strcat(fname, "/");
 594:         if (strncmp(fname, mailname, strlen(fname)) == 0) {
 595:             sprintf(zname, "+%s", mailname + strlen(fname));
 596:             ename = zname;
 597:         }
 598:     }
 599:     printf("\"%s\": ", ename);
 600:     if (msgCount == 1)
 601:         printf("1 message");
 602:     else
 603:         printf("%d messages", msgCount);
 604:     if (n > 0)
 605:         printf(" %d new", n);
 606:     if (u-n > 0)
 607:         printf(" %d unread", u);
 608:     if (d > 0)
 609:         printf(" %d deleted", d);
 610:     if (s > 0)
 611:         printf(" %d saved", s);
 612:     if (readonly)
 613:         printf(" [Read only]");
 614:     printf("\n");
 615:     return(mdot);
 616: }
 617: 
 618: /*
 619:  * Print the current version number.
 620:  */
 621: 
 622: /*ARGSUSED*/
 623: pversion(e)
 624: {
 625:     extern char *version;
 626: 
 627:     printf("Version %s\n", version);
 628:     return(0);
 629: }
 630: 
 631: /*
 632:  * Load a file of user definitions.
 633:  */
 634: load(name)
 635:     char *name;
 636: {
 637:     register FILE *in, *oldin;
 638: 
 639:     if ((in = Fopen(name, "r")) == NULL)
 640:         return;
 641:     oldin = input;
 642:     input = in;
 643:     loading = 1;
 644:     sourcing = 1;
 645:     commands();
 646:     loading = 0;
 647:     sourcing = 0;
 648:     input = oldin;
 649:     Fclose(in);
 650: }

Defined functions

announce defined in line 544; used 2 times
commands defined in line 161; used 2 times
execute defined in line 237; used 2 times
hangup defined in line 531; used 2 times
intr defined in line 488; used 2 times
isprefix defined in line 464; used 1 times
lex defined in line 446; used 2 times
load defined in line 634; used 2 times
newfileinfo defined in line 563; used 2 times
pversion defined in line 623; used 2 times
setfile defined in line 56; used 2 times
setmsize defined in line 433; used 1 times
stop defined in line 512; used 4 times

Defined variables

inithdr defined in line 485; used 4 times
msgvec defined in line 154; used 13 times
prompt defined in line 48; used 1 times
reset_on_stop defined in line 155; used 4 times
sccsid defined in line 35; never used
Last modified: 1992-10-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3552
Valid CSS Valid XHTML 1.0 Strict