|
|
1.1 root 1: #
2:
3: #include "rcv.h"
4: #include <ctype.h>
5:
6: /*
7: * Mail -- a mail program
8: *
9: * Message list handling.
10: */
11:
12: /*
13: * Convert the user string of message numbers and
14: * store the numbers into vector.
15: *
16: * Returns the count of messages picked up or -1 on error.
17: */
18:
19: getmsglist(buf, vector, flags)
20: char *buf;
21: int *vector;
22: {
23: register int *ip;
24: register struct message *mp;
25:
26: if (markall(buf, flags) < 0)
27: return(-1);
28: ip = vector;
29: for (mp = &message[0]; mp < &message[msgCount]; mp++)
30: if (mp->m_flag & MMARK)
31: *ip++ = mp - &message[0] + 1;
32: *ip = NULL;
33: return(ip - vector);
34: }
35:
36: /*
37: * Mark all messages that the user wanted from the command
38: * line in the message structure. Return 0 on success, -1
39: * on error.
40: */
41:
42: markall(buf, f)
43: char buf[];
44: {
45: register char **np;
46: register int i;
47: char *namelist[NMLSIZE], *bufp;
48: int tok, beg, mc, star, other;
49:
50: for (i = 1; i <= msgCount; i++)
51: unmark(i);
52: bufp = buf;
53: mc = 0;
54: np = &namelist[0];
55: scaninit();
56: tok = scan(&bufp);
57: star = 0;
58: other = 0;
59: beg = 0;
60: while (tok != TEOL) {
61: switch (tok) {
62: case TNUMBER:
63: number:
64: if (star) {
65: printf("No numbers mixed with *\n");
66: return(-1);
67: }
68: mc++;
69: other++;
70: if (beg != 0) {
71: if (check(lexnumber, f))
72: return(-1);
73: for (i = beg; i <= lexnumber; i++)
74: mark(i);
75: beg = 0;
76: break;
77: }
78: beg = lexnumber;
79: if (check(beg, f))
80: return(-1);
81: tok = scan(&bufp);
82: regret(tok);
83: if (tok != TDASH) {
84: mark(beg);
85: beg = 0;
86: }
87: break;
88:
89: case TDASH:
90: if (beg == 0) {
91: printf("Unexpected leading dash\n");
92: return(-1);
93: }
94: break;
95:
96: case TSTRING:
97: if (beg != 0) {
98: printf("Non-numeric second argument\n");
99: return(-1);
100: }
101: other++;
102: *np++ = savestr(lexstring);
103: break;
104:
105: case TDOLLAR:
106: case TUP:
107: case TDOT:
108: lexnumber = metamess(lexstring[0], f);
109: if (lexnumber == -1)
110: return(-1);
111: goto number;
112:
113: case TSTAR:
114: if (other) {
115: printf("Can't mix \"*\" with anything\n");
116: return(-1);
117: }
118: star++;
119: break;
120: }
121: tok = scan(&bufp);
122: }
123: *np = NOSTR;
124: mc = 0;
125: if (star) {
126: for (i = 0; i < msgCount; i++)
127: if ((message[i].m_flag & MDELETED) == f) {
128: mark(i+1);
129: mc++;
130: }
131: if (mc == 0) {
132: printf("No applicable messages.\n");
133: return(-1);
134: }
135: return(0);
136: }
137:
138: /*
139: * If no numbers were given, mark all of the messages,
140: * so that we can unmark any whose sender was not selected
141: * if any user names were given.
142: */
143:
144: if (np > namelist && mc == 0)
145: for (i = 1; i <= msgCount; i++)
146: if ((message[i-1].m_flag & (MSAVED|MDELETED)) == f)
147: mark(i);
148:
149: /*
150: * If any names were given, go through and eliminate any
151: * messages whose senders were not requested.
152: */
153:
154: if (np > namelist) {
155: for (i = 1; i <= msgCount; i++) {
156: for (mc = 0, np = &namelist[0]; *np != NOSTR; np++)
157: if (sender(*np, i)) {
158: mc++;
159: break;
160: }
161: if (mc == 0)
162: unmark(i);
163: }
164:
165: /*
166: * Make sure we got some decent messages.
167: */
168:
169: mc = 0;
170: for (i = 1; i <= msgCount; i++)
171: if (message[i-1].m_flag & MMARK) {
172: mc++;
173: break;
174: }
175: if (mc == 0) {
176: printf("No applicable messages from {%s",
177: namelist[0]);
178: for (np = &namelist[1]; *np != NOSTR; np++)
179: printf(", %s", *np);
180: printf("}\n");
181: return(-1);
182: }
183: }
184: return(0);
185: }
186:
187: /*
188: * Check the passed message number for legality and proper flags.
189: */
190:
191: check(mesg, f)
192: {
193: register struct message *mp;
194:
195: if (mesg < 1 || mesg > msgCount) {
196: printf("%d: Invalid message number\n", mesg);
197: return(-1);
198: }
199: mp = &message[mesg-1];
200: if ((mp->m_flag & MDELETED) != f) {
201: printf("%d: Inappropriate message\n", mesg);
202: return(-1);
203: }
204: return(0);
205: }
206:
207: /*
208: * Scan out the list of string arguments, shell style
209: * for a RAWLIST.
210: */
211:
212: getrawlist(line, argv)
213: char line[];
214: char **argv;
215: {
216: register char **ap, *cp, *cp2;
217: char linebuf[BUFSIZ], quotec;
218:
219: ap = argv;
220: cp = line;
221: while (*cp != '\0') {
222: while (any(*cp, " \t"))
223: cp++;
224: cp2 = linebuf;
225: quotec = 0;
226: if (any(*cp, "'\""))
227: quotec = *cp++;
228: if (quotec == 0)
229: while (*cp != '\0' && !any(*cp, " \t"))
230: *cp2++ = *cp++;
231: else {
232: while (*cp != '\0' && *cp != quotec)
233: *cp2++ = *cp++;
234: if (*cp != '\0')
235: cp++;
236: }
237: *cp2 = '\0';
238: if (cp2 == linebuf)
239: break;
240: *ap++ = savestr(linebuf);
241: }
242: *ap = NOSTR;
243: return(ap-argv);
244: }
245:
246: /*
247: * scan out a single lexical item and return its token number,
248: * updating the string pointer passed **p. Also, store the value
249: * of the number or string scanned in lexnumber or lexstring as
250: * appropriate. In any event, store the scanned `thing' in lexstring.
251: */
252:
253: struct lex {
254: char l_char;
255: char l_token;
256: } singles[] = {
257: '$', TDOLLAR,
258: '.', TDOT,
259: '^', TUP,
260: '*', TSTAR,
261: '-', TDASH,
262: '(', TOPEN,
263: ')', TCLOSE,
264: 0, 0
265: };
266:
267: scan(sp)
268: char **sp;
269: {
270: register char *cp, *cp2;
271: register int c;
272: register struct lex *lp;
273: int quotec;
274:
275: if (regretp >= 0) {
276: copy(stringstack[regretp], lexstring);
277: lexnumber = numberstack[regretp];
278: return(regretstack[regretp--]);
279: }
280: cp = *sp;
281: cp2 = lexstring;
282: c = *cp++;
283:
284: /*
285: * strip away leading white space.
286: */
287:
288: while (any(c, " \t"))
289: c = *cp++;
290:
291: /*
292: * If no characters remain, we are at end of line,
293: * so report that.
294: */
295:
296: if (c == '\0') {
297: *sp = --cp;
298: return(TEOL);
299: }
300:
301: /*
302: * If the leading character is a digit, scan
303: * the number and convert it on the fly.
304: * Return TNUMBER when done.
305: */
306:
307: if (isdigit(c)) {
308: lexnumber = 0;
309: while (isdigit(c)) {
310: lexnumber = lexnumber*10 + c - '0';
311: *cp2++ = c;
312: c = *cp++;
313: }
314: *cp2 = '\0';
315: *sp = --cp;
316: return(TNUMBER);
317: }
318:
319: /*
320: * Check for single character tokens; return such
321: * if found.
322: */
323:
324: for (lp = &singles[0]; lp->l_char != 0; lp++)
325: if (c == lp->l_char) {
326: lexstring[0] = c;
327: lexstring[1] = '\0';
328: *sp = cp;
329: return(lp->l_token);
330: }
331:
332: /*
333: * We've got a string! Copy all the characters
334: * of the string into lexstring, until we see
335: * a null, space, or tab.
336: * If the lead character is a " or ', save it
337: * and scan until you get another.
338: */
339:
340: quotec = 0;
341: if (any(c, "'\"")) {
342: quotec = c;
343: c = *cp++;
344: }
345: while (c != '\0') {
346: if (c == quotec)
347: break;
348: if (quotec == 0 && any(c, " \t"))
349: break;
350: if (cp2 - lexstring < STRINGLEN-1)
351: *cp2++ = c;
352: c = *cp++;
353: }
354: if (quotec && c == 0)
355: fprintf(stderr, "Missing %c\n", quotec);
356: *sp = --cp;
357: *cp2 = '\0';
358: return(TSTRING);
359: }
360:
361: /*
362: * Unscan the named token by pushing it onto the regret stack.
363: */
364:
365: regret(token)
366: {
367: if (++regretp >= REGDEP)
368: panic("Too many regrets");
369: regretstack[regretp] = token;
370: lexstring[STRINGLEN-1] = '\0';
371: stringstack[regretp] = savestr(lexstring);
372: numberstack[regretp] = lexnumber;
373: }
374:
375: /*
376: * Reset all the scanner global variables.
377: */
378:
379: scaninit()
380: {
381: regretp = -1;
382: }
383:
384: /*
385: * Find the first message whose flags & m == f and return
386: * its message number.
387: */
388:
389: first(f, m)
390: {
391: register int mesg;
392: register struct message *mp;
393:
394: mesg = dot - &message[0] + 1;
395: f &= MDELETED;
396: m &= MDELETED;
397: for (mp = dot; mp < &message[msgCount]; mp++) {
398: if ((mp->m_flag & m) == f)
399: return(mesg);
400: mesg++;
401: }
402: mesg = dot - &message[0];
403: for (mp = dot-1; mp >= &message[0]; mp--) {
404: if ((mp->m_flag & m) == f)
405: return(mesg);
406: mesg--;
407: }
408: return(NULL);
409: }
410:
411: /*
412: * See if the passed name sent the passed message number. Return true
413: * if so.
414: */
415:
416: sender(str, mesg)
417: char *str;
418: {
419: register struct message *mp;
420: register char *cp;
421:
422: mp = &message[mesg-1];
423: cp = nameof(mp);
424: return(icequal(cp, str));
425: }
426:
427: /*
428: * Mark the named message by setting its mark bit.
429: */
430:
431: mark(mesg)
432: {
433: register int i;
434:
435: i = mesg;
436: if (i < 1 || i > msgCount)
437: panic("Bad message number to mark");
438: message[i-1].m_flag |= MMARK;
439: }
440:
441: /*
442: * Unmark the named message.
443: */
444:
445: unmark(mesg)
446: {
447: register int i;
448:
449: i = mesg;
450: if (i < 1 || i > msgCount)
451: panic("Bad message number to unmark");
452: message[i-1].m_flag &= ~MMARK;
453: }
454:
455: /*
456: * Return the message number corresponding to the passed meta character.
457: */
458:
459: metamess(meta, f)
460: {
461: register int c, m;
462: register struct message *mp;
463:
464: c = meta;
465: switch (c) {
466: case '^':
467: /*
468: * First 'good' message left.
469: */
470: for (mp = &message[0]; mp < &message[msgCount]; mp++)
471: if ((mp->m_flag & MDELETED) == f)
472: return(mp - &message[0] + 1);
473: printf("No applicable messages\n");
474: return(-1);
475:
476: case '$':
477: /*
478: * Last 'good message left.
479: */
480: for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
481: if ((mp->m_flag & MDELETED) == f)
482: return(mp - &message[0] + 1);
483: printf("No applicable messages\n");
484: return(-1);
485:
486: case '.':
487: /*
488: * Current message.
489: */
490: m = dot - &message[0] + 1;
491: if ((dot->m_flag & MDELETED) != f) {
492: printf("%d: Inappropriate message\n", m);
493: return(-1);
494: }
495: return(m);
496:
497: default:
498: printf("Unknown metachar (%c)\n", c);
499: return(-1);
500: }
501: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.