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