1: #
   2: 
   3: #include "rcv.h"
   4: 
   5: /*
   6:  * Mail -- a mail program
   7:  *
   8:  * Lexical processing of commands.
   9:  */
  10: 
  11: static char *SccsId = "@(#)lex.c	2.13 6/15/83";
  12: 
  13: char    *prompt = "& ";
  14: 
  15: /*
  16:  * Set up editing on the given file name.
  17:  * If isedit is true, we are considered to be editing the file,
  18:  * otherwise we are reading our mail which has signficance for
  19:  * mbox and so forth.
  20:  */
  21: 
  22: setfile(name, isedit)
  23:     char *name;
  24: {
  25:     FILE *ibuf;
  26:     int i;
  27:     static int shudclob;
  28:     static char efile[128];
  29:     extern char tempMesg[];
  30: 
  31:     if ((ibuf = fopen(name, "r")) == NULL)
  32:         return(-1);
  33: 
  34:     /*
  35: 	 * Looks like all will be well.  We must now relinquish our
  36: 	 * hold on the current set of stuff.  Must hold signals
  37: 	 * while we are reading the new file, else we will ruin
  38: 	 * the message[] data structure.
  39: 	 */
  40: 
  41:     holdsigs();
  42:     if (shudclob) {
  43:         if (edit)
  44:             edstop();
  45:         else
  46:             quit();
  47:     }
  48: 
  49:     /*
  50: 	 * Copy the messages into /tmp
  51: 	 * and set pointers.
  52: 	 */
  53: 
  54:     readonly = 0;
  55:     if ((i = open(name, 1)) < 0)
  56:         readonly++;
  57:     else
  58:         close(i);
  59:     if (shudclob) {
  60:         fclose(itf);
  61:         fclose(otf);
  62:     }
  63:     shudclob = 1;
  64:     edit = isedit;
  65:     strncpy(efile, name, 128);
  66:     editfile = efile;
  67:     if (name != mailname)
  68:         strcpy(mailname, name);
  69:     mailsize = fsize(ibuf);
  70:     if ((otf = fopen(tempMesg, "w")) == NULL) {
  71:         perror(tempMesg);
  72:         exit(1);
  73:     }
  74:     if ((itf = fopen(tempMesg, "r")) == NULL) {
  75:         perror(tempMesg);
  76:         exit(1);
  77:     }
  78:     remove(tempMesg);
  79:     setptr(ibuf);
  80:     setmsize(msgCount);
  81:     fclose(ibuf);
  82:     relsesigs();
  83:     sawcom = 0;
  84:     return(0);
  85: }
  86: 
  87: /*
  88:  * Interpret user commands one by one.  If standard input is not a tty,
  89:  * print no prompt.
  90:  */
  91: 
  92: int *msgvec;
  93: 
  94: commands()
  95: {
  96:     int eofloop, shudprompt, stop();
  97:     register int n;
  98:     char linebuf[LINESIZE];
  99:     int hangup(), contin();
 100: 
 101: # ifdef VMUNIX
 102:     sigset(SIGCONT, SIG_DFL);
 103: # endif VMUNIX
 104:     if (rcvmode && !sourcing) {
 105:         if (sigset(SIGINT, SIG_IGN) != SIG_IGN)
 106:             sigset(SIGINT, stop);
 107:         if (sigset(SIGHUP, SIG_IGN) != SIG_IGN)
 108:             sigset(SIGHUP, hangup);
 109:     }
 110:     shudprompt = intty && !sourcing;
 111:     for (;;) {
 112:         setexit();
 113: 
 114:         /*
 115: 		 * Print the prompt, if needed.  Clear out
 116: 		 * string space, and flush the output.
 117: 		 */
 118: 
 119:         if (!rcvmode && !sourcing)
 120:             return;
 121:         eofloop = 0;
 122: top:
 123:         if (shudprompt) {
 124:             printf(prompt);
 125:             flush();
 126: # ifdef VMUNIX
 127:             sigset(SIGCONT, contin);
 128: # endif VMUNIX
 129:         } else
 130:             flush();
 131:         sreset();
 132: 
 133:         /*
 134: 		 * Read a line of commands from the current input
 135: 		 * and handle end of file specially.
 136: 		 */
 137: 
 138:         n = 0;
 139:         for (;;) {
 140:             if (readline(input, &linebuf[n]) <= 0) {
 141:                 if (n != 0)
 142:                     break;
 143:                 if (loading)
 144:                     return;
 145:                 if (sourcing) {
 146:                     unstack();
 147:                     goto more;
 148:                 }
 149:                 if (value("ignoreeof") != NOSTR && shudprompt) {
 150:                     if (++eofloop < 25) {
 151:                         printf("Use \"quit\" to quit.\n");
 152:                         goto top;
 153:                     }
 154:                 }
 155:                 if (edit)
 156:                     edstop();
 157:                 return;
 158:             }
 159:             if ((n = strlen(linebuf)) == 0)
 160:                 break;
 161:             n--;
 162:             if (linebuf[n] != '\\')
 163:                 break;
 164:             linebuf[n++] = ' ';
 165:         }
 166: # ifdef VMUNIX
 167:         sigset(SIGCONT, SIG_DFL);
 168: # endif VMUNIX
 169:         if (execute(linebuf, 0))
 170:             return;
 171: more:       ;
 172:     }
 173: }
 174: 
 175: /*
 176:  * Execute a single command.  If the command executed
 177:  * is "quit," then return non-zero so that the caller
 178:  * will know to return back to main, if he cares.
 179:  * Contxt is non-zero if called while composing mail.
 180:  */
 181: 
 182: execute(linebuf, contxt)
 183:     char linebuf[];
 184: {
 185:     char word[LINESIZE];
 186:     char *arglist[MAXARGC];
 187:     struct cmd *com;
 188:     register char *cp, *cp2;
 189:     register int c;
 190:     int muvec[2];
 191:     int edstop(), e;
 192: 
 193:     /*
 194: 	 * Strip the white space away from the beginning
 195: 	 * of the command, then scan out a word, which
 196: 	 * consists of anything except digits and white space.
 197: 	 *
 198: 	 * Handle ! escapes differently to get the correct
 199: 	 * lexical conventions.
 200: 	 */
 201: 
 202:     cp = linebuf;
 203:     while (any(*cp, " \t"))
 204:         cp++;
 205:     if (*cp == '!') {
 206:         if (sourcing) {
 207:             printf("Can't \"!\" while sourcing\n");
 208:             unstack();
 209:             return(0);
 210:         }
 211:         shell(cp+1);
 212:         return(0);
 213:     }
 214:     cp2 = word;
 215:     while (*cp && !any(*cp, " \t0123456789$^.:/-+*'\""))
 216:         *cp2++ = *cp++;
 217:     *cp2 = '\0';
 218: 
 219:     /*
 220: 	 * Look up the command; if not found, bitch.
 221: 	 * Normally, a blank command would map to the
 222: 	 * first command in the table; while sourcing,
 223: 	 * however, we ignore blank lines to eliminate
 224: 	 * confusion.
 225: 	 */
 226: 
 227:     if (sourcing && equal(word, ""))
 228:         return(0);
 229:     com = lex(word);
 230:     if (com == NONE) {
 231:         printf("Unknown command: \"%s\"\n", word);
 232:         if (loading)
 233:             return(1);
 234:         if (sourcing)
 235:             unstack();
 236:         return(0);
 237:     }
 238: 
 239:     /*
 240: 	 * See if we should execute the command -- if a conditional
 241: 	 * we always execute it, otherwise, check the state of cond.
 242: 	 */
 243: 
 244:     if ((com->c_argtype & F) == 0)
 245:         if (cond == CRCV && !rcvmode || cond == CSEND && rcvmode)
 246:             return(0);
 247: 
 248:     /*
 249: 	 * Special case so that quit causes a return to
 250: 	 * main, who will call the quit code directly.
 251: 	 * If we are in a source file, just unstack.
 252: 	 */
 253: 
 254:     if (com->c_func == edstop && sourcing) {
 255:         if (loading)
 256:             return(1);
 257:         unstack();
 258:         return(0);
 259:     }
 260:     if (!edit && com->c_func == edstop) {
 261:         sigset(SIGINT, SIG_IGN);
 262:         return(1);
 263:     }
 264: 
 265:     /*
 266: 	 * Process the arguments to the command, depending
 267: 	 * on the type he expects.  Default to an error.
 268: 	 * If we are sourcing an interactive command, it's
 269: 	 * an error.
 270: 	 */
 271: 
 272:     if (!rcvmode && (com->c_argtype & M) == 0) {
 273:         printf("May not execute \"%s\" while sending\n",
 274:             com->c_name);
 275:         if (loading)
 276:             return(1);
 277:         if (sourcing)
 278:             unstack();
 279:         return(0);
 280:     }
 281:     if (sourcing && com->c_argtype & I) {
 282:         printf("May not execute \"%s\" while sourcing\n",
 283:             com->c_name);
 284:         if (loading)
 285:             return(1);
 286:         unstack();
 287:         return(0);
 288:     }
 289:     if (readonly && com->c_argtype & W) {
 290:         printf("May not execute \"%s\" -- message file is read only\n",
 291:            com->c_name);
 292:         if (loading)
 293:             return(1);
 294:         if (sourcing)
 295:             unstack();
 296:         return(0);
 297:     }
 298:     if (contxt && com->c_argtype & R) {
 299:         printf("Cannot recursively invoke \"%s\"\n", com->c_name);
 300:         return(0);
 301:     }
 302:     e = 1;
 303:     switch (com->c_argtype & ~(F|P|I|M|T|W|R)) {
 304:     case MSGLIST:
 305:         /*
 306: 		 * A message list defaulting to nearest forward
 307: 		 * legal message.
 308: 		 */
 309:         if (msgvec == 0) {
 310:             printf("Illegal use of \"message list\"\n");
 311:             return(-1);
 312:         }
 313:         if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0)
 314:             break;
 315:         if (c  == 0) {
 316:             *msgvec = first(com->c_msgflag,
 317:                 com->c_msgmask);
 318:             msgvec[1] = NULL;
 319:         }
 320:         if (*msgvec == NULL) {
 321:             printf("No applicable messages\n");
 322:             break;
 323:         }
 324:         e = (*com->c_func)(msgvec);
 325:         break;
 326: 
 327:     case NDMLIST:
 328:         /*
 329: 		 * A message list with no defaults, but no error
 330: 		 * if none exist.
 331: 		 */
 332:         if (msgvec == 0) {
 333:             printf("Illegal use of \"message list\"\n");
 334:             return(-1);
 335:         }
 336:         if (getmsglist(cp, msgvec, com->c_msgflag) < 0)
 337:             break;
 338:         e = (*com->c_func)(msgvec);
 339:         break;
 340: 
 341:     case STRLIST:
 342:         /*
 343: 		 * Just the straight string, with
 344: 		 * leading blanks removed.
 345: 		 */
 346:         while (any(*cp, " \t"))
 347:             cp++;
 348:         e = (*com->c_func)(cp);
 349:         break;
 350: 
 351:     case RAWLIST:
 352:         /*
 353: 		 * A vector of strings, in shell style.
 354: 		 */
 355:         if ((c = getrawlist(cp, arglist)) < 0)
 356:             break;
 357:         if (c < com->c_minargs) {
 358:             printf("%s requires at least %d arg(s)\n",
 359:                 com->c_name, com->c_minargs);
 360:             break;
 361:         }
 362:         if (c > com->c_maxargs) {
 363:             printf("%s takes no more than %d arg(s)\n",
 364:                 com->c_name, com->c_maxargs);
 365:             break;
 366:         }
 367:         e = (*com->c_func)(arglist);
 368:         break;
 369: 
 370:     case NOLIST:
 371:         /*
 372: 		 * Just the constant zero, for exiting,
 373: 		 * eg.
 374: 		 */
 375:         e = (*com->c_func)(0);
 376:         break;
 377: 
 378:     default:
 379:         panic("Unknown argtype");
 380:     }
 381: 
 382:     /*
 383: 	 * Exit the current source file on
 384: 	 * error.
 385: 	 */
 386: 
 387:     if (e && loading)
 388:         return(1);
 389:     if (e && sourcing)
 390:         unstack();
 391:     if (com->c_func == edstop)
 392:         return(1);
 393:     if (value("autoprint") != NOSTR && com->c_argtype & P)
 394:         if ((dot->m_flag & MDELETED) == 0) {
 395:             muvec[0] = dot - &message[0] + 1;
 396:             muvec[1] = 0;
 397:             type(muvec);
 398:         }
 399:     if (!sourcing && (com->c_argtype & T) == 0)
 400:         sawcom = 1;
 401:     return(0);
 402: }
 403: 
 404: /*
 405:  * When we wake up after ^Z, reprint the prompt.
 406:  */
 407: contin(s)
 408: {
 409: 
 410:     printf(prompt);
 411:     fflush(stdout);
 412: }
 413: 
 414: /*
 415:  * Branch here on hangup signal and simulate quit.
 416:  */
 417: hangup()
 418: {
 419: 
 420:     holdsigs();
 421:     if (edit) {
 422:         if (setexit())
 423:             exit(0);
 424:         edstop();
 425:     }
 426:     else
 427:         quit();
 428:     exit(0);
 429: }
 430: 
 431: /*
 432:  * Set the size of the message vector used to construct argument
 433:  * lists to message list functions.
 434:  */
 435: 
 436: setmsize(sz)
 437: {
 438: 
 439:     if (msgvec != (int *) 0)
 440:         cfree(msgvec);
 441:     msgvec = (int *) calloc((unsigned) (sz + 1), sizeof *msgvec);
 442: }
 443: 
 444: /*
 445:  * Find the correct command in the command table corresponding
 446:  * to the passed command "word"
 447:  */
 448: 
 449: struct cmd *
 450: lex(word)
 451:     char word[];
 452: {
 453:     register struct cmd *cp;
 454:     extern struct cmd cmdtab[];
 455: 
 456:     for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++)
 457:         if (isprefix(word, cp->c_name))
 458:             return(cp);
 459:     return(NONE);
 460: }
 461: 
 462: /*
 463:  * Determine if as1 is a valid prefix of as2.
 464:  * Return true if yep.
 465:  */
 466: 
 467: isprefix(as1, as2)
 468:     char *as1, *as2;
 469: {
 470:     register char *s1, *s2;
 471: 
 472:     s1 = as1;
 473:     s2 = as2;
 474:     while (*s1++ == *s2)
 475:         if (*s2++ == '\0')
 476:             return(1);
 477:     return(*--s1 == '\0');
 478: }
 479: 
 480: /*
 481:  * The following gets called on receipt of a rubout.  This is
 482:  * to abort printout of a command, mainly.
 483:  * Dispatching here when command() is inactive crashes rcv.
 484:  * Close all open files except 0, 1, 2, and the temporary.
 485:  * The special call to getuserid() is needed so it won't get
 486:  * annoyed about losing its open file.
 487:  * Also, unstack all source files.
 488:  */
 489: 
 490: int inithdr;            /* am printing startup headers */
 491: 
 492: stop(s)
 493: {
 494:     register FILE *fp;
 495: 
 496: # ifndef VMUNIX
 497:     s = SIGINT;
 498: # endif VMUNIX
 499:     noreset = 0;
 500:     if (!inithdr)
 501:         sawcom++;
 502:     inithdr = 0;
 503:     while (sourcing)
 504:         unstack();
 505:     getuserid((char *) -1);
 506:     for (fp = &_iob[0]; fp < &_iob[_NFILE]; fp++) {
 507:         if (fp == stdin || fp == stdout)
 508:             continue;
 509:         if (fp == itf || fp == otf)
 510:             continue;
 511:         if (fp == stderr)
 512:             continue;
 513:         if (fp == pipef) {
 514:             pclose(pipef);
 515:             pipef = NULL;
 516:             continue;
 517:         }
 518:         fclose(fp);
 519:     }
 520:     if (image >= 0) {
 521:         close(image);
 522:         image = -1;
 523:     }
 524:     clrbuf(stdout);
 525:     printf("Interrupt\n");
 526: # ifdef VMUNIX
 527:     sigrelse(s);
 528: # else
 529:     signal(s, stop);
 530: # endif
 531:     reset(0);
 532: }
 533: 
 534: /*
 535:  * Announce the presence of the current Mail version,
 536:  * give the message count, and print a header listing.
 537:  */
 538: 
 539: char    *greeting   = "Mail version %s.  Type ? for help.\n";
 540: 
 541: announce(pr)
 542: {
 543:     int vec[2], mdot;
 544:     extern char *version;
 545: 
 546:     if (pr && value("quiet") == NOSTR)
 547:         printf(greeting, version);
 548:     mdot = newfileinfo();
 549:     vec[0] = mdot;
 550:     vec[1] = 0;
 551:     dot = &message[mdot - 1];
 552:     if (msgCount > 0 && !noheader) {
 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: strace() {}
 619: 
 620: /*
 621:  * Print the current version number.
 622:  */
 623: 
 624: pversion(e)
 625: {
 626:     printf("Version %s\n", version);
 627:     return(0);
 628: }
 629: 
 630: /*
 631:  * Load a file of user definitions.
 632:  */
 633: load(name)
 634:     char *name;
 635: {
 636:     register FILE *in, *oldin;
 637: 
 638:     if ((in = fopen(name, "r")) == NULL)
 639:         return;
 640:     oldin = input;
 641:     input = in;
 642:     loading = 1;
 643:     sourcing = 1;
 644:     commands();
 645:     loading = 0;
 646:     sourcing = 0;
 647:     input = oldin;
 648:     fclose(in);
 649: }

Defined functions

announce defined in line 541; used 1 times
commands defined in line 94; used 2 times
contin defined in line 407; used 2 times
execute defined in line 182; used 2 times
hangup defined in line 417; used 3 times
isprefix defined in line 467; used 1 times
lex defined in line 449; used 2 times
load defined in line 633; used 2 times
newfileinfo defined in line 563; used 4 times
pversion defined in line 624; used 2 times
setfile defined in line 22; used 2 times
setmsize defined in line 436; used 1 times
  • in line 80
stop defined in line 492; used 4 times
strace defined in line 618; used 1 times

Defined variables

SccsId defined in line 11; never used
greeting defined in line 539; used 1 times
inithdr defined in line 490; used 4 times
msgvec defined in line 92; used 13 times
prompt defined in line 13; used 2 times
Last modified: 1983-07-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1385
Valid CSS Valid XHTML 1.0 Strict