|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)lex.c 2.14 (Berkeley) 8/11/83"; ! 3: #endif ! 4: ! 5: #include "rcv.h" ! 6: ! 7: /* ! 8: * Mail -- a mail program ! 9: * ! 10: * Lexical processing of commands. ! 11: */ ! 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: # ifndef VMUNIX ! 527: signal(s, stop); ! 528: # endif ! 529: reset(0); ! 530: } ! 531: ! 532: /* ! 533: * Announce the presence of the current Mail version, ! 534: * give the message count, and print a header listing. ! 535: */ ! 536: ! 537: char *greeting = "Mail version %s. Type ? for help.\n"; ! 538: ! 539: announce(pr) ! 540: { ! 541: int vec[2], mdot; ! 542: extern char *version; ! 543: ! 544: if (pr && value("quiet") == NOSTR) ! 545: printf(greeting, version); ! 546: mdot = newfileinfo(); ! 547: vec[0] = mdot; ! 548: vec[1] = 0; ! 549: dot = &message[mdot - 1]; ! 550: if (msgCount > 0 && !noheader) { ! 551: inithdr++; ! 552: headers(vec); ! 553: inithdr = 0; ! 554: } ! 555: } ! 556: ! 557: /* ! 558: * Announce information about the file we are editing. ! 559: * Return a likely place to set dot. ! 560: */ ! 561: newfileinfo() ! 562: { ! 563: register struct message *mp; ! 564: register int u, n, mdot, d, s; ! 565: char fname[BUFSIZ], zname[BUFSIZ], *ename; ! 566: ! 567: for (mp = &message[0]; mp < &message[msgCount]; mp++) ! 568: if (mp->m_flag & MNEW) ! 569: break; ! 570: if (mp >= &message[msgCount]) ! 571: for (mp = &message[0]; mp < &message[msgCount]; mp++) ! 572: if ((mp->m_flag & MREAD) == 0) ! 573: break; ! 574: if (mp < &message[msgCount]) ! 575: mdot = mp - &message[0] + 1; ! 576: else ! 577: mdot = 1; ! 578: s = d = 0; ! 579: for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) { ! 580: if (mp->m_flag & MNEW) ! 581: n++; ! 582: if ((mp->m_flag & MREAD) == 0) ! 583: u++; ! 584: if (mp->m_flag & MDELETED) ! 585: d++; ! 586: if (mp->m_flag & MSAVED) ! 587: s++; ! 588: } ! 589: ename = mailname; ! 590: if (getfold(fname) >= 0) { ! 591: strcat(fname, "/"); ! 592: if (strncmp(fname, mailname, strlen(fname)) == 0) { ! 593: sprintf(zname, "+%s", mailname + strlen(fname)); ! 594: ename = zname; ! 595: } ! 596: } ! 597: printf("\"%s\": ", ename); ! 598: if (msgCount == 1) ! 599: printf("1 message"); ! 600: else ! 601: printf("%d messages", msgCount); ! 602: if (n > 0) ! 603: printf(" %d new", n); ! 604: if (u-n > 0) ! 605: printf(" %d unread", u); ! 606: if (d > 0) ! 607: printf(" %d deleted", d); ! 608: if (s > 0) ! 609: printf(" %d saved", s); ! 610: if (readonly) ! 611: printf(" [Read only]"); ! 612: printf("\n"); ! 613: return(mdot); ! 614: } ! 615: ! 616: strace() {} ! 617: ! 618: /* ! 619: * Print the current version number. ! 620: */ ! 621: ! 622: pversion(e) ! 623: { ! 624: printf("Version %s\n", version); ! 625: return(0); ! 626: } ! 627: ! 628: /* ! 629: * Load a file of user definitions. ! 630: */ ! 631: load(name) ! 632: char *name; ! 633: { ! 634: register FILE *in, *oldin; ! 635: ! 636: if ((in = fopen(name, "r")) == NULL) ! 637: return; ! 638: oldin = input; ! 639: input = in; ! 640: loading = 1; ! 641: sourcing = 1; ! 642: commands(); ! 643: loading = 0; ! 644: sourcing = 0; ! 645: input = oldin; ! 646: fclose(in); ! 647: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.