|
|
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: sigset(SIGCONT, SIG_DFL); ! 102: if (rcvmode && !sourcing) { ! 103: if (sigset(SIGINT, SIG_IGN) != SIG_IGN) ! 104: sigset(SIGINT, stop); ! 105: if (sigset(SIGHUP, SIG_IGN) != SIG_IGN) ! 106: sigset(SIGHUP, hangup); ! 107: } ! 108: shudprompt = intty && !sourcing; ! 109: for (;;) { ! 110: setexit(); ! 111: ! 112: /* ! 113: * Print the prompt, if needed. Clear out ! 114: * string space, and flush the output. ! 115: */ ! 116: ! 117: if (!rcvmode && !sourcing) ! 118: return; ! 119: eofloop = 0; ! 120: top: ! 121: if (shudprompt) { ! 122: printf(prompt); ! 123: flush(); ! 124: sigset(SIGCONT, contin); ! 125: } else ! 126: flush(); ! 127: sreset(); ! 128: ! 129: /* ! 130: * Read a line of commands from the current input ! 131: * and handle end of file specially. ! 132: */ ! 133: ! 134: n = 0; ! 135: for (;;) { ! 136: if (readline(input, &linebuf[n]) <= 0) { ! 137: if (n != 0) ! 138: break; ! 139: if (loading) ! 140: return; ! 141: if (sourcing) { ! 142: unstack(); ! 143: goto more; ! 144: } ! 145: if (value("ignoreeof") != NOSTR && shudprompt) { ! 146: if (++eofloop < 25) { ! 147: printf("Use \"quit\" to quit.\n"); ! 148: goto top; ! 149: } ! 150: } ! 151: if (edit) ! 152: edstop(); ! 153: return; ! 154: } ! 155: if ((n = strlen(linebuf)) == 0) ! 156: break; ! 157: n--; ! 158: if (linebuf[n] != '\\') ! 159: break; ! 160: linebuf[n++] = ' '; ! 161: } ! 162: sigset(SIGCONT, SIG_DFL); ! 163: if (execute(linebuf, 0)) ! 164: return; ! 165: more: ; ! 166: } ! 167: } ! 168: ! 169: /* ! 170: * Execute a single command. If the command executed ! 171: * is "quit," then return non-zero so that the caller ! 172: * will know to return back to main, if he cares. ! 173: * Contxt is non-zero if called while composing mail. ! 174: */ ! 175: ! 176: execute(linebuf, contxt) ! 177: char linebuf[]; ! 178: { ! 179: char word[LINESIZE]; ! 180: char *arglist[MAXARGC]; ! 181: struct cmd *com; ! 182: register char *cp, *cp2; ! 183: register int c; ! 184: int muvec[2]; ! 185: int edstop(), e; ! 186: ! 187: /* ! 188: * Strip the white space away from the beginning ! 189: * of the command, then scan out a word, which ! 190: * consists of anything except digits and white space. ! 191: * ! 192: * Handle ! escapes differently to get the correct ! 193: * lexical conventions. ! 194: */ ! 195: ! 196: cp = linebuf; ! 197: while (any(*cp, " \t")) ! 198: cp++; ! 199: if (*cp == '!') { ! 200: if (sourcing) { ! 201: printf("Can't \"!\" while sourcing\n"); ! 202: unstack(); ! 203: return(0); ! 204: } ! 205: shell(cp+1); ! 206: return(0); ! 207: } ! 208: cp2 = word; ! 209: while (*cp && !any(*cp, " \t0123456789$^.:/-+*'\"")) ! 210: *cp2++ = *cp++; ! 211: *cp2 = '\0'; ! 212: ! 213: /* ! 214: * Look up the command; if not found, bitch. ! 215: * Normally, a blank command would map to the ! 216: * first command in the table; while sourcing, ! 217: * however, we ignore blank lines to eliminate ! 218: * confusion. ! 219: */ ! 220: ! 221: if (sourcing && equal(word, "")) ! 222: return(0); ! 223: com = lex(word); ! 224: if (com == NONE) { ! 225: printf("Unknown command: \"%s\"\n", word); ! 226: if (loading) ! 227: return(1); ! 228: if (sourcing) ! 229: unstack(); ! 230: return(0); ! 231: } ! 232: ! 233: /* ! 234: * See if we should execute the command -- if a conditional ! 235: * we always execute it, otherwise, check the state of cond. ! 236: */ ! 237: ! 238: if ((com->c_argtype & F) == 0) ! 239: if (cond == CRCV && !rcvmode || cond == CSEND && rcvmode) ! 240: return(0); ! 241: ! 242: /* ! 243: * Special case so that quit causes a return to ! 244: * main, who will call the quit code directly. ! 245: * If we are in a source file, just unstack. ! 246: */ ! 247: ! 248: if (com->c_func == edstop && sourcing) { ! 249: if (loading) ! 250: return(1); ! 251: unstack(); ! 252: return(0); ! 253: } ! 254: if (!edit && com->c_func == edstop) { ! 255: sigset(SIGINT, SIG_IGN); ! 256: return(1); ! 257: } ! 258: ! 259: /* ! 260: * Process the arguments to the command, depending ! 261: * on the type he expects. Default to an error. ! 262: * If we are sourcing an interactive command, it's ! 263: * an error. ! 264: */ ! 265: ! 266: if (!rcvmode && (com->c_argtype & M) == 0) { ! 267: printf("May not execute \"%s\" while sending\n", ! 268: com->c_name); ! 269: if (loading) ! 270: return(1); ! 271: if (sourcing) ! 272: unstack(); ! 273: return(0); ! 274: } ! 275: if (sourcing && com->c_argtype & I) { ! 276: printf("May not execute \"%s\" while sourcing\n", ! 277: com->c_name); ! 278: if (loading) ! 279: return(1); ! 280: unstack(); ! 281: return(0); ! 282: } ! 283: if (readonly && com->c_argtype & W) { ! 284: printf("May not execute \"%s\" -- message file is read only\n", ! 285: com->c_name); ! 286: if (loading) ! 287: return(1); ! 288: if (sourcing) ! 289: unstack(); ! 290: return(0); ! 291: } ! 292: if (contxt && com->c_argtype & R) { ! 293: printf("Cannot recursively invoke \"%s\"\n", com->c_name); ! 294: return(0); ! 295: } ! 296: e = 1; ! 297: switch (com->c_argtype & ~(F|P|I|M|T|W|R)) { ! 298: case MSGLIST: ! 299: /* ! 300: * A message list defaulting to nearest forward ! 301: * legal message. ! 302: */ ! 303: if (msgvec == 0) { ! 304: printf("Illegal use of \"message list\"\n"); ! 305: return(-1); ! 306: } ! 307: if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0) ! 308: break; ! 309: if (c == 0) { ! 310: *msgvec = first(com->c_msgflag, ! 311: com->c_msgmask); ! 312: msgvec[1] = NULL; ! 313: } ! 314: if (*msgvec == NULL) { ! 315: printf("No applicable messages\n"); ! 316: break; ! 317: } ! 318: e = (*com->c_func)(msgvec); ! 319: break; ! 320: ! 321: case NDMLIST: ! 322: /* ! 323: * A message list with no defaults, but no error ! 324: * if none exist. ! 325: */ ! 326: if (msgvec == 0) { ! 327: printf("Illegal use of \"message list\"\n"); ! 328: return(-1); ! 329: } ! 330: if (getmsglist(cp, msgvec, com->c_msgflag) < 0) ! 331: break; ! 332: e = (*com->c_func)(msgvec); ! 333: break; ! 334: ! 335: case STRLIST: ! 336: /* ! 337: * Just the straight string, with ! 338: * leading blanks removed. ! 339: */ ! 340: while (any(*cp, " \t")) ! 341: cp++; ! 342: e = (*com->c_func)(cp); ! 343: break; ! 344: ! 345: case RAWLIST: ! 346: /* ! 347: * A vector of strings, in shell style. ! 348: */ ! 349: if ((c = getrawlist(cp, arglist)) < 0) ! 350: break; ! 351: if (c < com->c_minargs) { ! 352: printf("%s requires at least %d arg(s)\n", ! 353: com->c_name, com->c_minargs); ! 354: break; ! 355: } ! 356: if (c > com->c_maxargs) { ! 357: printf("%s takes no more than %d arg(s)\n", ! 358: com->c_name, com->c_maxargs); ! 359: break; ! 360: } ! 361: e = (*com->c_func)(arglist); ! 362: break; ! 363: ! 364: case NOLIST: ! 365: /* ! 366: * Just the constant zero, for exiting, ! 367: * eg. ! 368: */ ! 369: e = (*com->c_func)(0); ! 370: break; ! 371: ! 372: default: ! 373: panic("Unknown argtype"); ! 374: } ! 375: ! 376: /* ! 377: * Exit the current source file on ! 378: * error. ! 379: */ ! 380: ! 381: if (e && loading) ! 382: return(1); ! 383: if (e && sourcing) ! 384: unstack(); ! 385: if (com->c_func == edstop) ! 386: return(1); ! 387: if (value("autoprint") != NOSTR && com->c_argtype & P) ! 388: if ((dot->m_flag & MDELETED) == 0) { ! 389: muvec[0] = dot - &message[0] + 1; ! 390: muvec[1] = 0; ! 391: type(muvec); ! 392: } ! 393: if (!sourcing && (com->c_argtype & T) == 0) ! 394: sawcom = 1; ! 395: return(0); ! 396: } ! 397: ! 398: /* ! 399: * When we wake up after ^Z, reprint the prompt. ! 400: */ ! 401: contin(s) ! 402: { ! 403: ! 404: printf(prompt); ! 405: fflush(stdout); ! 406: } ! 407: ! 408: /* ! 409: * Branch here on hangup signal and simulate quit. ! 410: */ ! 411: hangup() ! 412: { ! 413: ! 414: holdsigs(); ! 415: if (edit) { ! 416: if (setexit()) ! 417: exit(0); ! 418: edstop(); ! 419: } ! 420: else ! 421: quit(); ! 422: exit(0); ! 423: } ! 424: ! 425: /* ! 426: * Set the size of the message vector used to construct argument ! 427: * lists to message list functions. ! 428: */ ! 429: ! 430: setmsize(sz) ! 431: { ! 432: ! 433: if (msgvec != (int *) 0) ! 434: cfree(msgvec); ! 435: msgvec = (int *) calloc((unsigned) (sz + 1), sizeof *msgvec); ! 436: } ! 437: ! 438: /* ! 439: * Find the correct command in the command table corresponding ! 440: * to the passed command "word" ! 441: */ ! 442: ! 443: struct cmd * ! 444: lex(word) ! 445: char word[]; ! 446: { ! 447: register struct cmd *cp; ! 448: extern struct cmd cmdtab[]; ! 449: ! 450: for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++) ! 451: if (isprefix(word, cp->c_name)) ! 452: return(cp); ! 453: return(NONE); ! 454: } ! 455: ! 456: /* ! 457: * Determine if as1 is a valid prefix of as2. ! 458: * Return true if yep. ! 459: */ ! 460: ! 461: isprefix(as1, as2) ! 462: char *as1, *as2; ! 463: { ! 464: register char *s1, *s2; ! 465: ! 466: s1 = as1; ! 467: s2 = as2; ! 468: while (*s1++ == *s2) ! 469: if (*s2++ == '\0') ! 470: return(1); ! 471: return(*--s1 == '\0'); ! 472: } ! 473: ! 474: /* ! 475: * The following gets called on receipt of a rubout. This is ! 476: * to abort printout of a command, mainly. ! 477: * Dispatching here when command() is inactive crashes rcv. ! 478: * Close all open files except 0, 1, 2, and the temporary. ! 479: * The special call to getuserid() is needed so it won't get ! 480: * annoyed about losing its open file. ! 481: * Also, unstack all source files. ! 482: */ ! 483: ! 484: int inithdr; /* am printing startup headers */ ! 485: ! 486: stop(s) ! 487: { ! 488: register FILE *fp; ! 489: ! 490: s = SIGINT; ! 491: noreset = 0; ! 492: if (!inithdr) ! 493: sawcom++; ! 494: inithdr = 0; ! 495: while (sourcing) ! 496: unstack(); ! 497: getuserid((char *) -1); ! 498: for (fp = &_iob[0]; fp < &_iob[_NFILE]; fp++) { ! 499: if (fp == stdin || fp == stdout) ! 500: continue; ! 501: if (fp == itf || fp == otf) ! 502: continue; ! 503: if (fp == stderr) ! 504: continue; ! 505: if (fp == pipef) { ! 506: pclose(pipef); ! 507: pipef = NULL; ! 508: continue; ! 509: } ! 510: fclose(fp); ! 511: } ! 512: if (image >= 0) { ! 513: close(image); ! 514: image = -1; ! 515: } ! 516: clrbuf(stdout); ! 517: printf("Interrupt\n"); ! 518: signal(s, stop); ! 519: reset(0); ! 520: } ! 521: ! 522: /* ! 523: * Announce the presence of the current Mail version, ! 524: * give the message count, and print a header listing. ! 525: */ ! 526: ! 527: char *greeting = "Mail version %s. Type ? for help.\n"; ! 528: ! 529: announce(pr) ! 530: { ! 531: int vec[2], mdot; ! 532: extern char *version; ! 533: ! 534: if (pr && value("quiet") == NOSTR) ! 535: printf(greeting, version); ! 536: mdot = newfileinfo(); ! 537: vec[0] = mdot; ! 538: vec[1] = 0; ! 539: dot = &message[mdot - 1]; ! 540: if (msgCount > 0 && !noheader) { ! 541: inithdr++; ! 542: headers(vec); ! 543: inithdr = 0; ! 544: } ! 545: } ! 546: ! 547: /* ! 548: * Announce information about the file we are editing. ! 549: * Return a likely place to set dot. ! 550: */ ! 551: newfileinfo() ! 552: { ! 553: register struct message *mp; ! 554: register int u, n, mdot, d, s; ! 555: char fname[BUFSIZ], zname[BUFSIZ], *ename; ! 556: ! 557: for (mp = &message[0]; mp < &message[msgCount]; mp++) ! 558: if (mp->m_flag & MNEW) ! 559: break; ! 560: if (mp >= &message[msgCount]) ! 561: for (mp = &message[0]; mp < &message[msgCount]; mp++) ! 562: if ((mp->m_flag & MREAD) == 0) ! 563: break; ! 564: if (mp < &message[msgCount]) ! 565: mdot = mp - &message[0] + 1; ! 566: else ! 567: mdot = 1; ! 568: s = d = 0; ! 569: for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) { ! 570: if (mp->m_flag & MNEW) ! 571: n++; ! 572: if ((mp->m_flag & MREAD) == 0) ! 573: u++; ! 574: if (mp->m_flag & MDELETED) ! 575: d++; ! 576: if (mp->m_flag & MSAVED) ! 577: s++; ! 578: } ! 579: ename = mailname; ! 580: if (getfold(fname) >= 0) { ! 581: strcat(fname, "/"); ! 582: if (strncmp(fname, mailname, strlen(fname)) == 0) { ! 583: sprintf(zname, "+%s", mailname + strlen(fname)); ! 584: ename = zname; ! 585: } ! 586: } ! 587: printf("\"%s\": ", ename); ! 588: if (msgCount == 1) ! 589: printf("1 message"); ! 590: else ! 591: printf("%d messages", msgCount); ! 592: if (n > 0) ! 593: printf(" %d new", n); ! 594: if (u-n > 0) ! 595: printf(" %d unread", u); ! 596: if (d > 0) ! 597: printf(" %d deleted", d); ! 598: if (s > 0) ! 599: printf(" %d saved", s); ! 600: if (readonly) ! 601: printf(" [Read only]"); ! 602: printf("\n"); ! 603: return(mdot); ! 604: } ! 605: ! 606: strace() {} ! 607: ! 608: /* ! 609: * Print the current version number. ! 610: */ ! 611: ! 612: pversion(e) ! 613: { ! 614: printf("Version %s\n", version); ! 615: return(0); ! 616: } ! 617: ! 618: /* ! 619: * Load a file of user definitions. ! 620: */ ! 621: load(name) ! 622: char *name; ! 623: { ! 624: register FILE *in, *oldin; ! 625: ! 626: if ((in = fopen(name, "r")) == NULL) ! 627: return; ! 628: oldin = input; ! 629: input = in; ! 630: loading = 1; ! 631: sourcing = 1; ! 632: commands(); ! 633: loading = 0; ! 634: sourcing = 0; ! 635: input = oldin; ! 636: fclose(in); ! 637: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.