|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that this notice is preserved and that due credit is given
7: * to the University of California at Berkeley. The name of the University
8: * may not be used to endorse or promote products derived from this
9: * software without specific prior written permission. This software
10: * is provided ``as is'' without express or implied warranty.
11: */
12:
13: #ifdef notdef
14: static char sccsid[] = "@(#)list.c 5.6 (Berkeley) 2/18/88";
15: #endif /* notdef */
16:
17: #include "rcv.h"
18: #include <ctype.h>
19:
20: /*
21: * Mail -- a mail program
22: *
23: * Message list handling.
24: */
25:
26: /*
27: * Convert the user string of message numbers and
28: * store the numbers into vector.
29: *
30: * Returns the count of messages picked up or -1 on error.
31: */
32:
33: getmsglist(buf, vector, flags)
34: char *buf;
35: int *vector;
36: {
37: register int *ip;
38: register struct message *mp;
39:
40: if (markall(buf, flags) < 0)
41: return(-1);
42: ip = vector;
43: for (mp = &message[0]; mp < &message[msgCount]; mp++)
44: if (mp->m_flag & MMARK)
45: *ip++ = mp - &message[0] + 1;
46: *ip = NULL;
47: return(ip - vector);
48: }
49:
50: /*
51: * Mark all messages that the user wanted from the command
52: * line in the message structure. Return 0 on success, -1
53: * on error.
54: */
55:
56: /*
57: * Bit values for colon modifiers.
58: */
59:
60: #define CMNEW 01 /* New messages */
61: #define CMOLD 02 /* Old messages */
62: #define CMUNREAD 04 /* Unread messages */
63: #define CMDELETED 010 /* Deleted messages */
64: #define CMREAD 020 /* Read messages */
65:
66: /*
67: * The following table describes the letters which can follow
68: * the colon and gives the corresponding modifier bit.
69: */
70:
71: struct coltab {
72: char co_char; /* What to find past : */
73: int co_bit; /* Associated modifier bit */
74: int co_mask; /* m_status bits to mask */
75: int co_equal; /* ... must equal this */
76: } coltab[] = {
77: 'n', CMNEW, MNEW, MNEW,
78: 'o', CMOLD, MNEW, 0,
79: 'u', CMUNREAD, MREAD, 0,
80: 'd', CMDELETED, MDELETED, MDELETED,
81: 'r', CMREAD, MREAD, MREAD,
82: 0, 0, 0, 0
83: };
84:
85: static int lastcolmod;
86:
87: markall(buf, f)
88: char buf[];
89: {
90: register char **np;
91: register int i;
92: register struct message *mp;
93: char *namelist[NMLSIZE], *bufp;
94: int tok, beg, mc, star, other, valdot, colmod, colresult;
95:
96: valdot = dot - &message[0] + 1;
97: colmod = 0;
98: for (i = 1; i <= msgCount; i++)
99: unmark(i);
100: bufp = buf;
101: mc = 0;
102: np = &namelist[0];
103: scaninit();
104: tok = scan(&bufp);
105: star = 0;
106: other = 0;
107: beg = 0;
108: while (tok != TEOL) {
109: switch (tok) {
110: case TNUMBER:
111: number:
112: if (star) {
113: printf("No numbers mixed with *\n");
114: return(-1);
115: }
116: mc++;
117: other++;
118: if (beg != 0) {
119: if (check(lexnumber, f))
120: return(-1);
121: for (i = beg; i <= lexnumber; i++)
122: if ((message[i - 1].m_flag & MDELETED) == f)
123: mark(i);
124: beg = 0;
125: break;
126: }
127: beg = lexnumber;
128: if (check(beg, f))
129: return(-1);
130: tok = scan(&bufp);
131: regret(tok);
132: if (tok != TDASH) {
133: mark(beg);
134: beg = 0;
135: }
136: break;
137:
138: case TPLUS:
139: if (beg != 0) {
140: printf("Non-numeric second argument\n");
141: return(-1);
142: }
143: i = valdot;
144: do {
145: i++;
146: if (i > msgCount) {
147: printf("Referencing beyond EOF\n");
148: return(-1);
149: }
150: } while ((message[i - 1].m_flag & MDELETED) != f);
151: mark(i);
152: break;
153:
154: case TDASH:
155: if (beg == 0) {
156: i = valdot;
157: do {
158: i--;
159: if (i <= 0) {
160: printf("Referencing before 1\n");
161: return(-1);
162: }
163: } while ((message[i - 1].m_flag & MDELETED) != f);
164: mark(i);
165: }
166: break;
167:
168: case TSTRING:
169: if (beg != 0) {
170: printf("Non-numeric second argument\n");
171: return(-1);
172: }
173: other++;
174: if (lexstring[0] == ':') {
175: colresult = evalcol(lexstring[1]);
176: if (colresult == 0) {
177: printf("Unknown colon modifier \"%s\"\n",
178: lexstring);
179: return(-1);
180: }
181: colmod |= colresult;
182: }
183: else
184: *np++ = savestr(lexstring);
185: break;
186:
187: case TDOLLAR:
188: case TUP:
189: case TDOT:
190: lexnumber = metamess(lexstring[0], f);
191: if (lexnumber == -1)
192: return(-1);
193: goto number;
194:
195: case TSTAR:
196: if (other) {
197: printf("Can't mix \"*\" with anything\n");
198: return(-1);
199: }
200: star++;
201: break;
202: }
203: tok = scan(&bufp);
204: }
205: lastcolmod = colmod;
206: *np = NOSTR;
207: mc = 0;
208: if (star) {
209: for (i = 0; i < msgCount; i++)
210: if ((message[i].m_flag & MDELETED) == f) {
211: mark(i+1);
212: mc++;
213: }
214: if (mc == 0) {
215: printf("No applicable messages.\n");
216: return(-1);
217: }
218: return(0);
219: }
220:
221: /*
222: * If no numbers were given, mark all of the messages,
223: * so that we can unmark any whose sender was not selected
224: * if any user names were given.
225: */
226:
227: if ((np > namelist || colmod != 0) && mc == 0)
228: for (i = 1; i <= msgCount; i++)
229: if ((message[i-1].m_flag & MDELETED) == f)
230: mark(i);
231:
232: /*
233: * If any names were given, go through and eliminate any
234: * messages whose senders were not requested.
235: */
236:
237: if (np > namelist) {
238: for (i = 1; i <= msgCount; i++) {
239: for (mc = 0, np = &namelist[0]; *np != NOSTR; np++)
240: if (**np == '/') {
241: if (matchsubj(*np, i)) {
242: mc++;
243: break;
244: }
245: }
246: else {
247: if (sender(*np, i)) {
248: mc++;
249: break;
250: }
251: }
252: if (mc == 0)
253: unmark(i);
254: }
255:
256: /*
257: * Make sure we got some decent messages.
258: */
259:
260: mc = 0;
261: for (i = 1; i <= msgCount; i++)
262: if (message[i-1].m_flag & MMARK) {
263: mc++;
264: break;
265: }
266: if (mc == 0) {
267: printf("No applicable messages from {%s",
268: namelist[0]);
269: for (np = &namelist[1]; *np != NOSTR; np++)
270: printf(", %s", *np);
271: printf("}\n");
272: return(-1);
273: }
274: }
275:
276: /*
277: * If any colon modifiers were given, go through and
278: * unmark any messages which do not satisfy the modifiers.
279: */
280:
281: if (colmod != 0) {
282: for (i = 1; i <= msgCount; i++) {
283: register struct coltab *colp;
284:
285: mp = &message[i - 1];
286: for (colp = &coltab[0]; colp->co_char; colp++)
287: if (colp->co_bit & colmod)
288: if ((mp->m_flag & colp->co_mask)
289: != colp->co_equal)
290: unmark(i);
291:
292: }
293: for (mp = &message[0]; mp < &message[msgCount]; mp++)
294: if (mp->m_flag & MMARK)
295: break;
296: if (mp >= &message[msgCount]) {
297: register struct coltab *colp;
298:
299: printf("No messages satisfy");
300: for (colp = &coltab[0]; colp->co_char; colp++)
301: if (colp->co_bit & colmod)
302: printf(" :%c", colp->co_char);
303: printf("\n");
304: return(-1);
305: }
306: }
307: return(0);
308: }
309:
310: /*
311: * Turn the character after a colon modifier into a bit
312: * value.
313: */
314: evalcol(col)
315: {
316: register struct coltab *colp;
317:
318: if (col == 0)
319: return(lastcolmod);
320: for (colp = &coltab[0]; colp->co_char; colp++)
321: if (colp->co_char == col)
322: return(colp->co_bit);
323: return(0);
324: }
325:
326: /*
327: * Check the passed message number for legality and proper flags.
328: */
329:
330: check(mesg, f)
331: {
332: register struct message *mp;
333:
334: if (mesg < 1 || mesg > msgCount) {
335: printf("%d: Invalid message number\n", mesg);
336: return(-1);
337: }
338: mp = &message[mesg-1];
339: if ((mp->m_flag & MDELETED) != f) {
340: printf("%d: Inappropriate message\n", mesg);
341: return(-1);
342: }
343: return(0);
344: }
345:
346: /*
347: * Scan out the list of string arguments, shell style
348: * for a RAWLIST.
349: */
350:
351: getrawlist(line, argv, argc)
352: char line[];
353: char **argv;
354: int argc;
355: {
356: register char **ap, *cp, *cp2;
357: char linebuf[BUFSIZ], quotec;
358: register char **last;
359:
360: ap = argv;
361: cp = line;
362: last = argv + argc - 1;
363: while (*cp != '\0') {
364: while (any(*cp, " \t"))
365: cp++;
366: cp2 = linebuf;
367: quotec = 0;
368: if (any(*cp, "'\""))
369: quotec = *cp++;
370: if (quotec == 0)
371: while (*cp != '\0' && !any(*cp, " \t"))
372: *cp2++ = *cp++;
373: else {
374: while (*cp != '\0' && *cp != quotec)
375: *cp2++ = *cp++;
376: if (*cp != '\0')
377: cp++;
378: }
379: *cp2 = '\0';
380: if (cp2 == linebuf)
381: break;
382: if (ap >= last) {
383: printf("Too many elements in the list; excess discarded\n");
384: break;
385: }
386: *ap++ = savestr(linebuf);
387: }
388: *ap = NOSTR;
389: return(ap-argv);
390: }
391:
392: /*
393: * scan out a single lexical item and return its token number,
394: * updating the string pointer passed **p. Also, store the value
395: * of the number or string scanned in lexnumber or lexstring as
396: * appropriate. In any event, store the scanned `thing' in lexstring.
397: */
398:
399: struct lex {
400: char l_char;
401: char l_token;
402: } singles[] = {
403: '$', TDOLLAR,
404: '.', TDOT,
405: '^', TUP,
406: '*', TSTAR,
407: '-', TDASH,
408: '+', TPLUS,
409: '(', TOPEN,
410: ')', TCLOSE,
411: 0, 0
412: };
413:
414: scan(sp)
415: char **sp;
416: {
417: register char *cp, *cp2;
418: register int c;
419: register struct lex *lp;
420: int quotec;
421:
422: if (regretp >= 0) {
423: strcpy(lexstring, stringstack[regretp]);
424: lexnumber = numberstack[regretp];
425: return(regretstack[regretp--]);
426: }
427: cp = *sp;
428: cp2 = lexstring;
429: c = *cp++;
430:
431: /*
432: * strip away leading white space.
433: */
434:
435: while (any(c, " \t"))
436: c = *cp++;
437:
438: /*
439: * If no characters remain, we are at end of line,
440: * so report that.
441: */
442:
443: if (c == '\0') {
444: *sp = --cp;
445: return(TEOL);
446: }
447:
448: /*
449: * If the leading character is a digit, scan
450: * the number and convert it on the fly.
451: * Return TNUMBER when done.
452: */
453:
454: if (isdigit(c)) {
455: lexnumber = 0;
456: while (isdigit(c)) {
457: lexnumber = lexnumber*10 + c - '0';
458: *cp2++ = c;
459: c = *cp++;
460: }
461: *cp2 = '\0';
462: *sp = --cp;
463: return(TNUMBER);
464: }
465:
466: /*
467: * Check for single character tokens; return such
468: * if found.
469: */
470:
471: for (lp = &singles[0]; lp->l_char != 0; lp++)
472: if (c == lp->l_char) {
473: lexstring[0] = c;
474: lexstring[1] = '\0';
475: *sp = cp;
476: return(lp->l_token);
477: }
478:
479: /*
480: * We've got a string! Copy all the characters
481: * of the string into lexstring, until we see
482: * a null, space, or tab.
483: * If the lead character is a " or ', save it
484: * and scan until you get another.
485: */
486:
487: quotec = 0;
488: if (any(c, "'\"")) {
489: quotec = c;
490: c = *cp++;
491: }
492: while (c != '\0') {
493: if (c == quotec)
494: break;
495: if (quotec == 0 && any(c, " \t"))
496: break;
497: if (cp2 - lexstring < STRINGLEN-1)
498: *cp2++ = c;
499: c = *cp++;
500: }
501: if (quotec && c == 0)
502: fprintf(stderr, "Missing %c\n", quotec);
503: *sp = --cp;
504: *cp2 = '\0';
505: return(TSTRING);
506: }
507:
508: /*
509: * Unscan the named token by pushing it onto the regret stack.
510: */
511:
512: regret(token)
513: {
514: if (++regretp >= REGDEP)
515: panic("Too many regrets");
516: regretstack[regretp] = token;
517: lexstring[STRINGLEN-1] = '\0';
518: stringstack[regretp] = savestr(lexstring);
519: numberstack[regretp] = lexnumber;
520: }
521:
522: /*
523: * Reset all the scanner global variables.
524: */
525:
526: scaninit()
527: {
528: regretp = -1;
529: }
530:
531: /*
532: * Find the first message whose flags & m == f and return
533: * its message number.
534: */
535:
536: first(f, m)
537: {
538: register int mesg;
539: register struct message *mp;
540:
541: mesg = dot - &message[0] + 1;
542: f &= MDELETED;
543: m &= MDELETED;
544: for (mp = dot; mp < &message[msgCount]; mp++) {
545: if ((mp->m_flag & m) == f)
546: return(mesg);
547: mesg++;
548: }
549: mesg = dot - &message[0];
550: for (mp = dot-1; mp >= &message[0]; mp--) {
551: if ((mp->m_flag & m) == f)
552: return(mesg);
553: mesg--;
554: }
555: return(NULL);
556: }
557:
558: /*
559: * See if the passed name sent the passed message number. Return true
560: * if so.
561: */
562:
563: sender(str, mesg)
564: char *str;
565: {
566: register struct message *mp;
567: register char *cp, *cp2, *backup;
568:
569: mp = &message[mesg-1];
570: backup = cp2 = nameof(mp, 0);
571: cp = str;
572: while (*cp2) {
573: if (*cp == 0)
574: return(1);
575: if (raise(*cp++) != raise(*cp2++)) {
576: cp2 = ++backup;
577: cp = str;
578: }
579: }
580: return(*cp == 0);
581: }
582:
583: /*
584: * See if the given string matches inside the subject field of the
585: * given message. For the purpose of the scan, we ignore case differences.
586: * If it does, return true. The string search argument is assumed to
587: * have the form "/search-string." If it is of the form "/," we use the
588: * previous search string.
589: */
590:
591: char lastscan[128];
592:
593: matchsubj(str, mesg)
594: char *str;
595: {
596: register struct message *mp;
597: register char *cp, *cp2, *backup;
598:
599: str++;
600: if (strlen(str) == 0)
601: str = lastscan;
602: else
603: strcpy(lastscan, str);
604: mp = &message[mesg-1];
605:
606: /*
607: * Now look, ignoring case, for the word in the string.
608: */
609:
610: cp = str;
611: cp2 = hfield("subject", mp);
612: if (cp2 == NOSTR)
613: return(0);
614: backup = cp2;
615: while (*cp2) {
616: if (*cp == 0)
617: return(1);
618: if (raise(*cp++) != raise(*cp2++)) {
619: cp2 = ++backup;
620: cp = str;
621: }
622: }
623: return(*cp == 0);
624: }
625:
626: /*
627: * Mark the named message by setting its mark bit.
628: */
629:
630: mark(mesg)
631: {
632: register int i;
633:
634: i = mesg;
635: if (i < 1 || i > msgCount)
636: panic("Bad message number to mark");
637: message[i-1].m_flag |= MMARK;
638: }
639:
640: /*
641: * Unmark the named message.
642: */
643:
644: unmark(mesg)
645: {
646: register int i;
647:
648: i = mesg;
649: if (i < 1 || i > msgCount)
650: panic("Bad message number to unmark");
651: message[i-1].m_flag &= ~MMARK;
652: }
653:
654: /*
655: * Return the message number corresponding to the passed meta character.
656: */
657:
658: metamess(meta, f)
659: {
660: register int c, m;
661: register struct message *mp;
662:
663: c = meta;
664: switch (c) {
665: case '^':
666: /*
667: * First 'good' message left.
668: */
669: for (mp = &message[0]; mp < &message[msgCount]; mp++)
670: if ((mp->m_flag & MDELETED) == f)
671: return(mp - &message[0] + 1);
672: printf("No applicable messages\n");
673: return(-1);
674:
675: case '$':
676: /*
677: * Last 'good message left.
678: */
679: for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
680: if ((mp->m_flag & MDELETED) == f)
681: return(mp - &message[0] + 1);
682: printf("No applicable messages\n");
683: return(-1);
684:
685: case '.':
686: /*
687: * Current message.
688: */
689: m = dot - &message[0] + 1;
690: if ((dot->m_flag & MDELETED) != f) {
691: printf("%d: Inappropriate message\n", m);
692: return(-1);
693: }
694: return(m);
695:
696: default:
697: printf("Unknown metachar (%c)\n", c);
698: return(-1);
699: }
700: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.