|
|
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.