|
|
1.1 ! root 1: # ! 2: ! 3: #include "rcv.h" ! 4: ! 5: /* ! 6: * Mail -- a mail program ! 7: * ! 8: * Lexical processing of commands. ! 9: */ ! 10: ! 11: /* ! 12: * Interpret user commands one by one. If standard input is not a tty, ! 13: * print no prompt. ! 14: */ ! 15: ! 16: int *msgvec; ! 17: ! 18: commands() ! 19: { ! 20: int prompt, firstsw, stop(); ! 21: register int n; ! 22: char linebuf[LINESIZE]; ! 23: ! 24: msgvec = (int *) calloc((unsigned) (msgCount + 1), sizeof *msgvec); ! 25: if (rcvmode) ! 26: if (signal(SIGINT, SIG_IGN) == SIG_DFL) ! 27: signal(SIGINT, stop); ! 28: input = stdin; ! 29: prompt = 1; ! 30: if (!intty) ! 31: prompt = 0; ! 32: firstsw = 1; ! 33: for (;;) { ! 34: setexit(); ! 35: if (firstsw > 0) { ! 36: firstsw = 0; ! 37: source1(mailrc); ! 38: if (!nosrc) ! 39: source1(MASTER); ! 40: } ! 41: ! 42: /* ! 43: * How's this for obscure: after we ! 44: * finish sourcing for the first time, ! 45: * go off and print the headers! ! 46: */ ! 47: ! 48: if (firstsw == 0 && !sourcing) { ! 49: firstsw = -1; ! 50: if (rcvmode) ! 51: announce(); ! 52: } ! 53: ! 54: /* ! 55: * Print the prompt, if needed. Clear out ! 56: * string space, and flush the output. ! 57: */ ! 58: ! 59: if (!rcvmode && !sourcing) ! 60: return; ! 61: if (prompt && !sourcing) ! 62: printf("_\r"); ! 63: flush(); ! 64: sreset(); ! 65: ! 66: /* ! 67: * Read a line of commands from the current input ! 68: * and handle end of file specially. ! 69: */ ! 70: ! 71: n = 0; ! 72: for (;;) { ! 73: if (readline(input, &linebuf[n]) <= 0) { ! 74: if (n != 0) ! 75: break; ! 76: if (sourcing) { ! 77: unstack(); ! 78: goto more; ! 79: } ! 80: if (!edit) { ! 81: signal(SIGINT, SIG_IGN); ! 82: return; ! 83: } ! 84: edstop(); ! 85: return; ! 86: } ! 87: if ((n = strlen(linebuf)) == 0) ! 88: break; ! 89: n--; ! 90: if (linebuf[n] != '\\') ! 91: break; ! 92: linebuf[n++] = ' '; ! 93: } ! 94: if (execute(linebuf)) ! 95: return; ! 96: more: ; ! 97: } ! 98: } ! 99: ! 100: /* ! 101: * Execute a single command. If the command executed ! 102: * is "quit," then return non-zero so that the caller ! 103: * will know to return back to main, if he cares. ! 104: */ ! 105: ! 106: execute(linebuf) ! 107: char linebuf[]; ! 108: { ! 109: char word[LINESIZE]; ! 110: char *arglist[MAXARGC]; ! 111: struct cmd *com; ! 112: register char *cp, *cp2; ! 113: register int c; ! 114: int edstop(), e; ! 115: ! 116: /* ! 117: * Strip the white space away from the beginning ! 118: * of the command, then scan out a word, which ! 119: * consists of anything except digits and white space. ! 120: * ! 121: * Handle ! escapes differently to get the correct ! 122: * lexical conventions. ! 123: */ ! 124: ! 125: cp = linebuf; ! 126: while (any(*cp, " \t")) ! 127: cp++; ! 128: if (*cp == '!') { ! 129: if (sourcing) { ! 130: printf("Can't \"!\" while sourcing\n"); ! 131: unstack(); ! 132: return(0); ! 133: } ! 134: shell(cp+1); ! 135: return(0); ! 136: } ! 137: cp2 = word; ! 138: while (*cp && !any(*cp, " \t0123456789$^.-+*'\"")) ! 139: *cp2++ = *cp++; ! 140: *cp2 = '\0'; ! 141: ! 142: /* ! 143: * Look up the command; if not found, bitch. ! 144: * Normally, a blank command would map to the ! 145: * first command in the table; while sourcing, ! 146: * however, we ignore blank lines to eliminate ! 147: * confusion. ! 148: */ ! 149: ! 150: if (sourcing && equal(word, "")) ! 151: return(0); ! 152: com = lex(word); ! 153: if (com == NONE) { ! 154: printf("What?\n"); ! 155: if (sourcing) ! 156: unstack(); ! 157: return(0); ! 158: } ! 159: ! 160: /* ! 161: * Special case so that quit causes a return to ! 162: * main, who will call the quit code directly. ! 163: * If we are in a source file, just unstack. ! 164: */ ! 165: ! 166: if (com->c_func == edstop && sourcing) { ! 167: unstack(); ! 168: return(0); ! 169: } ! 170: if (!edit && com->c_func == edstop) { ! 171: signal(SIGINT, SIG_IGN); ! 172: return(1); ! 173: } ! 174: ! 175: /* ! 176: * Process the arguments to the command, depending ! 177: * on the type he expects. Default to an error. ! 178: * If we are sourcing an interactive command, it's ! 179: * an error. ! 180: */ ! 181: ! 182: if (!rcvmode && (com->c_argtype & M) == 0) { ! 183: printf("May not execute \"%s\" while sending\n", ! 184: com->c_name); ! 185: unstack(); ! 186: return(0); ! 187: } ! 188: if (sourcing && com->c_argtype & I) { ! 189: printf("May not execute \"%s\" while sourcing\n", ! 190: com->c_name); ! 191: unstack(); ! 192: return(0); ! 193: } ! 194: e = 1; ! 195: switch (com->c_argtype & ~(P|I|M)) { ! 196: case MSGLIST: ! 197: /* ! 198: * A message list defaulting to nearest forward ! 199: * legal message. ! 200: */ ! 201: if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0) ! 202: break; ! 203: if (c == 0) { ! 204: *msgvec = first(com->c_msgflag, ! 205: com->c_msgmask); ! 206: msgvec[1] = NULL; ! 207: } ! 208: if (*msgvec == NULL) { ! 209: printf("No applicable messages\n"); ! 210: break; ! 211: } ! 212: e = (*com->c_func)(msgvec); ! 213: break; ! 214: ! 215: case NDMLIST: ! 216: /* ! 217: * A message list with no defaults, but no error ! 218: * if none exist. ! 219: */ ! 220: if (getmsglist(cp, msgvec, com->c_msgflag) < 0) ! 221: break; ! 222: e = (*com->c_func)(msgvec); ! 223: break; ! 224: ! 225: case STRLIST: ! 226: /* ! 227: * Just the straight string, with ! 228: * leading blanks removed. ! 229: */ ! 230: while (any(*cp, " \t")) ! 231: cp++; ! 232: e = (*com->c_func)(cp); ! 233: break; ! 234: ! 235: case RAWLIST: ! 236: /* ! 237: * A vector of strings, in shell style. ! 238: */ ! 239: if ((c = getrawlist(cp, arglist)) < 0) ! 240: break; ! 241: if (c < com->c_minargs) { ! 242: printf("%s requires at least %d arg(s)\n", ! 243: com->c_name, com->c_minargs); ! 244: break; ! 245: } ! 246: if (c > com->c_maxargs) { ! 247: printf("%s takes no more than %d arg(s)\n", ! 248: com->c_name, com->c_maxargs); ! 249: break; ! 250: } ! 251: e = (*com->c_func)(arglist); ! 252: break; ! 253: ! 254: case NOLIST: ! 255: /* ! 256: * Just the constant zero, for exiting, ! 257: * eg. ! 258: */ ! 259: e = (*com->c_func)(0); ! 260: break; ! 261: ! 262: default: ! 263: panic("Unknown argtype"); ! 264: } ! 265: ! 266: /* ! 267: * Exit the current source file on ! 268: * error. ! 269: */ ! 270: ! 271: if (e && sourcing) ! 272: unstack(); ! 273: if (com->c_func == edstop) ! 274: return(1); ! 275: if (value("autoprint") != NOSTR && com->c_argtype & P) ! 276: if ((dot->m_flag & MDELETED) == 0) ! 277: print(dot); ! 278: if (!sourcing) ! 279: sawcom = 1; ! 280: return(0); ! 281: } ! 282: ! 283: /* ! 284: * Find the correct command in the command table corresponding ! 285: * to the passed command "word" ! 286: */ ! 287: ! 288: struct cmd * ! 289: lex(word) ! 290: char word[]; ! 291: { ! 292: register struct cmd *cp; ! 293: extern struct cmd cmdtab[]; ! 294: ! 295: for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++) ! 296: if (isprefix(word, cp->c_name)) ! 297: return(cp); ! 298: return(NONE); ! 299: } ! 300: ! 301: /* ! 302: * Determine if as1 is a valid prefix of as2. ! 303: * Return true if yep. ! 304: */ ! 305: ! 306: isprefix(as1, as2) ! 307: char *as1, *as2; ! 308: { ! 309: register char *s1, *s2; ! 310: ! 311: s1 = as1; ! 312: s2 = as2; ! 313: while (*s1++ == *s2) ! 314: if (*s2++ == '\0') ! 315: return(1); ! 316: return(*--s1 == '\0'); ! 317: } ! 318: ! 319: /* ! 320: * The following gets called on receipt of a rubout. This is ! 321: * to abort printout of a command, mainly. ! 322: * Dispatching here when command() is inactive crashes rcv. ! 323: * Close all open files except 0, 1, 2, and the temporary. ! 324: * The special call to getuserid() is needed so it won't get ! 325: * annoyed about losing its open file. ! 326: * Also, unstack all source files. ! 327: */ ! 328: ! 329: stop() ! 330: { ! 331: register FILE *fp; ! 332: ! 333: noreset = 0; ! 334: signal(SIGINT, SIG_IGN); ! 335: sawcom++; ! 336: while (sourcing) ! 337: unstack(); ! 338: getuserid((char *) -1); ! 339: for (fp = &_iob[0]; fp < &_iob[_NFILE]; fp++) { ! 340: if (fp == stdin || fp == stdout) ! 341: continue; ! 342: if (fp == itf || fp == otf) ! 343: continue; ! 344: if (fp == stderr) ! 345: continue; ! 346: fclose(fp); ! 347: } ! 348: if (image >= 0) { ! 349: close(image); ! 350: image = -1; ! 351: } ! 352: clrbuf(stdout); ! 353: printf("Interrupt\n"); ! 354: signal(SIGINT, stop); ! 355: reset(0); ! 356: } ! 357: ! 358: /* ! 359: * Announce the presence of the current Mail version, ! 360: * give the message count, and print a header listing. ! 361: */ ! 362: ! 363: char *greeting = "Mail version 2.0 %s. Type ? for help.\n"; ! 364: ! 365: announce() ! 366: { ! 367: int vec[2]; ! 368: extern char *version; ! 369: register struct message *mp; ! 370: ! 371: if (value("hold") != NOSTR) ! 372: for (mp = &message[0]; mp < &message[msgCount]; mp++) ! 373: mp->m_flag |= MPRESERVE; ! 374: vec[0] = 1; ! 375: vec[1] = 0; ! 376: if (value("quiet") == NOSTR) ! 377: printf(greeting, version); ! 378: if (msgCount == 1) ! 379: printf("1 message:\n"); ! 380: else ! 381: printf("%d messages:\n", msgCount); ! 382: headers(vec); ! 383: } ! 384: ! 385: strace() {} ! 386: ! 387: /* ! 388: * Print the current version number. ! 389: */ ! 390: ! 391: pversion(e) ! 392: { ! 393: printf(greeting, version); ! 394: return(0); ! 395: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.