Annotation of src/usr.bin/mail/list.c, Revision 1.9
1.9 ! millert 1: /* $OpenBSD: list.c,v 1.8 1997/08/04 17:30:22 millert Exp $ */
1.5 millert 2: /* $NetBSD: list.c,v 1.7 1997/07/09 05:23:36 mikel Exp $ */
1.2 deraadt 3:
1.1 deraadt 4: /*
5: * Copyright (c) 1980, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
1.2 deraadt 38: #if 0
1.5 millert 39: static char sccsid[] = "@(#)list.c 8.4 (Berkeley) 5/1/95";
1.2 deraadt 40: #else
1.9 ! millert 41: static char rcsid[] = "$OpenBSD: list.c,v 1.8 1997/08/04 17:30:22 millert Exp $";
1.2 deraadt 42: #endif
1.1 deraadt 43: #endif /* not lint */
44:
45: #include "rcv.h"
46: #include <ctype.h>
47: #include "extern.h"
48:
1.9 ! millert 49: int matchto __P((char *, int));
! 50:
1.1 deraadt 51: /*
52: * Mail -- a mail program
53: *
54: * Message list handling.
55: */
56:
57: /*
58: * Convert the user string of message numbers and
59: * store the numbers into vector.
60: *
61: * Returns the count of messages picked up or -1 on error.
62: */
63: int
64: getmsglist(buf, vector, flags)
65: char *buf;
66: int *vector, flags;
67: {
1.9 ! millert 68: int *ip;
! 69: struct message *mp;
1.1 deraadt 70:
71: if (msgCount == 0) {
72: *vector = 0;
1.5 millert 73: return(0);
1.1 deraadt 74: }
75: if (markall(buf, flags) < 0)
76: return(-1);
77: ip = vector;
78: for (mp = &message[0]; mp < &message[msgCount]; mp++)
79: if (mp->m_flag & MMARK)
80: *ip++ = mp - &message[0] + 1;
81: *ip = 0;
82: return(ip - vector);
83: }
84:
85: /*
86: * Mark all messages that the user wanted from the command
87: * line in the message structure. Return 0 on success, -1
88: * on error.
89: */
90:
91: /*
92: * Bit values for colon modifiers.
93: */
94:
95: #define CMNEW 01 /* New messages */
96: #define CMOLD 02 /* Old messages */
97: #define CMUNREAD 04 /* Unread messages */
98: #define CMDELETED 010 /* Deleted messages */
99: #define CMREAD 020 /* Read messages */
100:
101: /*
102: * The following table describes the letters which can follow
103: * the colon and gives the corresponding modifier bit.
104: */
105:
106: struct coltab {
107: char co_char; /* What to find past : */
108: int co_bit; /* Associated modifier bit */
109: int co_mask; /* m_status bits to mask */
110: int co_equal; /* ... must equal this */
111: } coltab[] = {
1.2 deraadt 112: { 'n', CMNEW, MNEW, MNEW },
113: { 'o', CMOLD, MNEW, 0 },
114: { 'u', CMUNREAD, MREAD, 0 },
115: { 'd', CMDELETED, MDELETED, MDELETED },
116: { 'r', CMREAD, MREAD, MREAD },
117: { 0, 0, 0, 0 }
1.1 deraadt 118: };
119:
120: static int lastcolmod;
121:
122: int
123: markall(buf, f)
124: char buf[];
125: int f;
126: {
1.9 ! millert 127: char **np;
! 128: int i;
! 129: struct message *mp;
1.1 deraadt 130: char *namelist[NMLSIZE], *bufp;
131: int tok, beg, mc, star, other, valdot, colmod, colresult;
132:
133: valdot = dot - &message[0] + 1;
134: colmod = 0;
135: for (i = 1; i <= msgCount; i++)
136: unmark(i);
137: bufp = buf;
138: mc = 0;
139: np = &namelist[0];
140: scaninit();
141: tok = scan(&bufp);
142: star = 0;
143: other = 0;
144: beg = 0;
145: while (tok != TEOL) {
146: switch (tok) {
147: case TNUMBER:
148: number:
149: if (star) {
1.5 millert 150: puts("No numbers mixed with *");
1.1 deraadt 151: return(-1);
152: }
153: mc++;
154: other++;
155: if (beg != 0) {
156: if (check(lexnumber, f))
157: return(-1);
158: for (i = beg; i <= lexnumber; i++)
159: if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0)
160: mark(i);
161: beg = 0;
162: break;
163: }
164: beg = lexnumber;
165: if (check(beg, f))
166: return(-1);
167: tok = scan(&bufp);
168: regret(tok);
169: if (tok != TDASH) {
170: mark(beg);
171: beg = 0;
172: }
173: break;
174:
175: case TPLUS:
176: if (beg != 0) {
1.5 millert 177: puts("Non-numeric second argument");
1.1 deraadt 178: return(-1);
179: }
180: i = valdot;
181: do {
182: i++;
183: if (i > msgCount) {
1.5 millert 184: puts("Referencing beyond EOF");
1.1 deraadt 185: return(-1);
186: }
187: } while ((message[i - 1].m_flag & MDELETED) != f);
188: mark(i);
189: break;
190:
191: case TDASH:
192: if (beg == 0) {
193: i = valdot;
194: do {
195: i--;
196: if (i <= 0) {
1.5 millert 197: puts("Referencing before 1");
1.1 deraadt 198: return(-1);
199: }
200: } while ((message[i - 1].m_flag & MDELETED) != f);
201: mark(i);
202: }
203: break;
204:
205: case TSTRING:
206: if (beg != 0) {
1.5 millert 207: puts("Non-numeric second argument");
1.1 deraadt 208: return(-1);
209: }
210: other++;
211: if (lexstring[0] == ':') {
212: colresult = evalcol(lexstring[1]);
213: if (colresult == 0) {
214: printf("Unknown colon modifier \"%s\"\n",
215: lexstring);
216: return(-1);
217: }
218: colmod |= colresult;
219: }
220: else
221: *np++ = savestr(lexstring);
222: break;
223:
224: case TDOLLAR:
225: case TUP:
226: case TDOT:
227: lexnumber = metamess(lexstring[0], f);
228: if (lexnumber == -1)
229: return(-1);
230: goto number;
231:
232: case TSTAR:
233: if (other) {
1.5 millert 234: puts("Can't mix \"*\" with anything");
1.1 deraadt 235: return(-1);
236: }
237: star++;
238: break;
239:
240: case TERROR:
1.5 millert 241: return(-1);
1.1 deraadt 242: }
243: tok = scan(&bufp);
244: }
245: lastcolmod = colmod;
1.6 millert 246: *np = NULL;
1.1 deraadt 247: mc = 0;
248: if (star) {
249: for (i = 0; i < msgCount; i++)
250: if ((message[i].m_flag & MDELETED) == f) {
251: mark(i+1);
252: mc++;
253: }
254: if (mc == 0) {
1.5 millert 255: puts("No applicable messages.");
1.1 deraadt 256: return(-1);
257: }
258: return(0);
259: }
260:
261: /*
262: * If no numbers were given, mark all of the messages,
263: * so that we can unmark any whose sender was not selected
264: * if any user names were given.
265: */
266:
267: if ((np > namelist || colmod != 0) && mc == 0)
268: for (i = 1; i <= msgCount; i++)
269: if ((message[i-1].m_flag & MDELETED) == f)
270: mark(i);
271:
272: /*
273: * If any names were given, go through and eliminate any
274: * messages whose senders were not requested.
275: */
276:
277: if (np > namelist) {
278: for (i = 1; i <= msgCount; i++) {
1.6 millert 279: for (mc = 0, np = &namelist[0]; *np != NULL; np++)
1.1 deraadt 280: if (**np == '/') {
281: if (matchsubj(*np, i)) {
282: mc++;
283: break;
284: }
285: }
286: else {
287: if (matchsender(*np, i)) {
288: mc++;
289: break;
290: }
291: }
292: if (mc == 0)
293: unmark(i);
294: }
295:
296: /*
297: * Make sure we got some decent messages.
298: */
299:
300: mc = 0;
301: for (i = 1; i <= msgCount; i++)
302: if (message[i-1].m_flag & MMARK) {
303: mc++;
304: break;
305: }
306: if (mc == 0) {
307: printf("No applicable messages from {%s",
308: namelist[0]);
1.6 millert 309: for (np = &namelist[1]; *np != NULL; np++)
1.1 deraadt 310: printf(", %s", *np);
1.5 millert 311: puts("}");
1.1 deraadt 312: return(-1);
313: }
314: }
315:
316: /*
317: * If any colon modifiers were given, go through and
318: * unmark any messages which do not satisfy the modifiers.
319: */
320:
321: if (colmod != 0) {
322: for (i = 1; i <= msgCount; i++) {
1.9 ! millert 323: struct coltab *colp;
1.1 deraadt 324:
325: mp = &message[i - 1];
326: for (colp = &coltab[0]; colp->co_char; colp++)
327: if (colp->co_bit & colmod)
328: if ((mp->m_flag & colp->co_mask)
329: != colp->co_equal)
330: unmark(i);
331:
332: }
333: for (mp = &message[0]; mp < &message[msgCount]; mp++)
334: if (mp->m_flag & MMARK)
335: break;
336: if (mp >= &message[msgCount]) {
1.9 ! millert 337: struct coltab *colp;
1.1 deraadt 338:
1.5 millert 339: fputs("No messages satisfy", stdout);
1.1 deraadt 340: for (colp = &coltab[0]; colp->co_char; colp++)
341: if (colp->co_bit & colmod)
342: printf(" :%c", colp->co_char);
1.5 millert 343: putchar('\n');
1.1 deraadt 344: return(-1);
345: }
346: }
347: return(0);
348: }
349:
350: /*
351: * Turn the character after a colon modifier into a bit
352: * value.
353: */
354: int
355: evalcol(col)
356: int col;
357: {
1.9 ! millert 358: struct coltab *colp;
1.1 deraadt 359:
360: if (col == 0)
361: return(lastcolmod);
362: for (colp = &coltab[0]; colp->co_char; colp++)
363: if (colp->co_char == col)
364: return(colp->co_bit);
365: return(0);
366: }
367:
368: /*
369: * Check the passed message number for legality and proper flags.
370: * If f is MDELETED, then either kind will do. Otherwise, the message
371: * has to be undeleted.
372: */
373: int
374: check(mesg, f)
375: int mesg, f;
376: {
1.9 ! millert 377: struct message *mp;
1.1 deraadt 378:
379: if (mesg < 1 || mesg > msgCount) {
380: printf("%d: Invalid message number\n", mesg);
381: return(-1);
382: }
383: mp = &message[mesg-1];
384: if (f != MDELETED && (mp->m_flag & MDELETED) != 0) {
385: printf("%d: Inappropriate message\n", mesg);
386: return(-1);
387: }
388: return(0);
389: }
390:
391: /*
392: * Scan out the list of string arguments, shell style
393: * for a RAWLIST.
394: */
395: int
396: getrawlist(line, argv, argc)
397: char line[];
398: char **argv;
399: int argc;
400: {
1.9 ! millert 401: char c, *cp, *cp2, quotec;
1.1 deraadt 402: int argn;
1.7 millert 403: char *linebuf;
404: size_t linebufsize = BUFSIZ;
405:
406: if ((linebuf = (char *)malloc(linebufsize)) == NULL)
1.9 ! millert 407: errx(1, "Out of memory");
1.1 deraadt 408:
409: argn = 0;
410: cp = line;
411: for (;;) {
412: for (; *cp == ' ' || *cp == '\t'; cp++)
413: ;
414: if (*cp == '\0')
415: break;
416: if (argn >= argc - 1) {
1.5 millert 417: puts("Too many elements in the list; excess discarded.");
1.1 deraadt 418: break;
419: }
420: cp2 = linebuf;
421: quotec = '\0';
422: while ((c = *cp) != '\0') {
1.7 millert 423: /* Alloc more space if necessary */
424: if (cp2 - linebuf == linebufsize - 1) {
425: linebufsize += BUFSIZ;
1.8 millert 426: linebuf = (char *)realloc(linebuf, linebufsize);
427: if (linebuf == NULL)
1.9 ! millert 428: errx(1, "Out of memory");
1.8 millert 429: cp2 = linebuf + linebufsize - BUFSIZ - 1;
1.7 millert 430: }
1.1 deraadt 431: cp++;
432: if (quotec != '\0') {
433: if (c == quotec)
434: quotec = '\0';
435: else if (c == '\\')
436: switch (c = *cp++) {
437: case '\0':
438: *cp2++ = '\\';
439: cp--;
440: break;
441: case '0': case '1': case '2': case '3':
442: case '4': case '5': case '6': case '7':
443: c -= '0';
444: if (*cp >= '0' && *cp <= '7')
445: c = c * 8 + *cp++ - '0';
446: if (*cp >= '0' && *cp <= '7')
447: c = c * 8 + *cp++ - '0';
448: *cp2++ = c;
449: break;
450: case 'b':
451: *cp2++ = '\b';
452: break;
453: case 'f':
454: *cp2++ = '\f';
455: break;
456: case 'n':
457: *cp2++ = '\n';
458: break;
459: case 'r':
460: *cp2++ = '\r';
461: break;
462: case 't':
463: *cp2++ = '\t';
464: break;
465: case 'v':
466: *cp2++ = '\v';
467: break;
468: default:
469: *cp2++ = c;
470: }
471: else if (c == '^') {
472: c = *cp++;
473: if (c == '?')
474: *cp2++ = '\177';
475: /* null doesn't show up anyway */
1.2 deraadt 476: else if ((c >= 'A' && c <= '_') ||
477: (c >= 'a' && c <= 'z'))
1.1 deraadt 478: *cp2++ = c & 037;
479: else {
480: *cp2++ = '^';
481: cp--;
482: }
483: } else
484: *cp2++ = c;
485: } else if (c == '"' || c == '\'')
486: quotec = c;
487: else if (c == ' ' || c == '\t')
488: break;
489: else
490: *cp2++ = c;
491: }
492: *cp2 = '\0';
493: argv[argn++] = savestr(linebuf);
494: }
1.6 millert 495: argv[argn] = NULL;
1.7 millert 496: (void)free(linebuf);
1.5 millert 497: return(argn);
1.1 deraadt 498: }
499:
500: /*
501: * scan out a single lexical item and return its token number,
502: * updating the string pointer passed **p. Also, store the value
503: * of the number or string scanned in lexnumber or lexstring as
504: * appropriate. In any event, store the scanned `thing' in lexstring.
505: */
506:
507: struct lex {
508: char l_char;
509: char l_token;
510: } singles[] = {
1.2 deraadt 511: { '$', TDOLLAR },
512: { '.', TDOT },
513: { '^', TUP },
514: { '*', TSTAR },
515: { '-', TDASH },
516: { '+', TPLUS },
517: { '(', TOPEN },
518: { ')', TCLOSE },
519: { 0, 0 }
1.1 deraadt 520: };
521:
522: int
523: scan(sp)
524: char **sp;
525: {
1.9 ! millert 526: char *cp, *cp2;
! 527: int c;
! 528: struct lex *lp;
1.1 deraadt 529: int quotec;
530:
531: if (regretp >= 0) {
532: strcpy(lexstring, string_stack[regretp]);
533: lexnumber = numberstack[regretp];
534: return(regretstack[regretp--]);
535: }
536: cp = *sp;
537: cp2 = lexstring;
538: c = *cp++;
539:
540: /*
541: * strip away leading white space.
542: */
543:
544: while (c == ' ' || c == '\t')
545: c = *cp++;
546:
547: /*
548: * If no characters remain, we are at end of line,
549: * so report that.
550: */
551:
552: if (c == '\0') {
553: *sp = --cp;
554: return(TEOL);
555: }
556:
557: /*
558: * If the leading character is a digit, scan
559: * the number and convert it on the fly.
560: * Return TNUMBER when done.
561: */
562:
563: if (isdigit(c)) {
564: lexnumber = 0;
565: while (isdigit(c)) {
566: lexnumber = lexnumber*10 + c - '0';
567: *cp2++ = c;
568: c = *cp++;
569: }
570: *cp2 = '\0';
571: *sp = --cp;
572: return(TNUMBER);
573: }
574:
575: /*
576: * Check for single character tokens; return such
577: * if found.
578: */
579:
580: for (lp = &singles[0]; lp->l_char != 0; lp++)
581: if (c == lp->l_char) {
582: lexstring[0] = c;
583: lexstring[1] = '\0';
584: *sp = cp;
585: return(lp->l_token);
586: }
587:
588: /*
589: * We've got a string! Copy all the characters
590: * of the string into lexstring, until we see
591: * a null, space, or tab.
592: * If the lead character is a " or ', save it
593: * and scan until you get another.
594: */
595:
596: quotec = 0;
597: if (c == '\'' || c == '"') {
598: quotec = c;
599: c = *cp++;
600: }
601: while (c != '\0') {
602: if (c == quotec) {
603: cp++;
604: break;
605: }
606: if (quotec == 0 && (c == ' ' || c == '\t'))
607: break;
608: if (cp2 - lexstring < STRINGLEN-1)
609: *cp2++ = c;
610: c = *cp++;
611: }
612: if (quotec && c == 0) {
613: fprintf(stderr, "Missing %c\n", quotec);
1.5 millert 614: return(TERROR);
1.1 deraadt 615: }
616: *sp = --cp;
617: *cp2 = '\0';
618: return(TSTRING);
619: }
620:
621: /*
622: * Unscan the named token by pushing it onto the regret stack.
623: */
624: void
625: regret(token)
626: int token;
627: {
628: if (++regretp >= REGDEP)
1.9 ! millert 629: errx(1, "Too many regrets");
1.1 deraadt 630: regretstack[regretp] = token;
631: lexstring[STRINGLEN-1] = '\0';
632: string_stack[regretp] = savestr(lexstring);
633: numberstack[regretp] = lexnumber;
634: }
635:
636: /*
637: * Reset all the scanner global variables.
638: */
639: void
640: scaninit()
641: {
642: regretp = -1;
643: }
644:
645: /*
646: * Find the first message whose flags & m == f and return
647: * its message number.
648: */
649: int
650: first(f, m)
651: int f, m;
652: {
1.9 ! millert 653: struct message *mp;
1.1 deraadt 654:
655: if (msgCount == 0)
1.5 millert 656: return(0);
1.1 deraadt 657: f &= MDELETED;
658: m &= MDELETED;
659: for (mp = dot; mp < &message[msgCount]; mp++)
660: if ((mp->m_flag & m) == f)
1.5 millert 661: return(mp - message + 1);
1.1 deraadt 662: for (mp = dot-1; mp >= &message[0]; mp--)
663: if ((mp->m_flag & m) == f)
1.5 millert 664: return(mp - message + 1);
665: return(0);
1.1 deraadt 666: }
667:
668: /*
669: * See if the passed name sent the passed message number. Return true
670: * if so.
671: */
672: int
673: matchsender(str, mesg)
674: char *str;
675: int mesg;
676: {
1.9 ! millert 677: char *cp, *cp2, *backup;
1.1 deraadt 678:
679: if (!*str) /* null string matches nothing instead of everything */
1.5 millert 680: return(0);
1.1 deraadt 681: backup = cp2 = nameof(&message[mesg - 1], 0);
682: cp = str;
683: while (*cp2) {
684: if (*cp == 0)
685: return(1);
686: if (raise(*cp++) != raise(*cp2++)) {
687: cp2 = ++backup;
688: cp = str;
689: }
690: }
691: return(*cp == 0);
692: }
693:
694: /*
1.5 millert 695: * See if the passed name received the passed message number. Return true
696: * if so.
697: */
698:
699: static char *to_fields[] = { "to", "cc", "bcc", NULL };
700:
701: int
702: matchto(str, mesg)
703: char *str;
704: {
1.9 ! millert 705: struct message *mp;
! 706: char *cp, *cp2, *backup, **to;
1.5 millert 707:
708: str++;
709:
710: if (*str == 0) /* null string matches nothing instead of everything */
711: return(0);
712:
713: mp = &message[mesg-1];
714:
715: for (to = to_fields; *to; to++) {
716: cp = str;
717: cp2 = hfield(*to, mp);
1.6 millert 718: if (cp2 != NULL) {
1.5 millert 719: backup = cp2;
720: while (*cp2) {
721: if (*cp == 0)
722: return(1);
723: if (raise(*cp++) != raise(*cp2++)) {
724: cp2 = ++backup;
725: cp = str;
726: }
727: }
728: if (*cp == 0)
729: return(1);
730: }
731: }
732: return(0);
733: }
734:
735: /*
1.1 deraadt 736: * See if the given string matches inside the subject field of the
737: * given message. For the purpose of the scan, we ignore case differences.
738: * If it does, return true. The string search argument is assumed to
739: * have the form "/search-string." If it is of the form "/," we use the
740: * previous search string.
741: */
742:
1.4 deraadt 743: char lastscan[STRINGLEN];
1.1 deraadt 744: int
745: matchsubj(str, mesg)
746: char *str;
747: int mesg;
748: {
1.9 ! millert 749: struct message *mp;
! 750: char *cp, *cp2, *backup;
1.1 deraadt 751:
752: str++;
1.5 millert 753: if (*str == '\0')
1.1 deraadt 754: str = lastscan;
1.4 deraadt 755: else {
1.5 millert 756: strncpy(lastscan, str, sizeof(lastscan) - 1);
757: lastscan[sizeof(lastscan) - 1] = '\0';
1.4 deraadt 758: }
1.1 deraadt 759: mp = &message[mesg-1];
760:
761: /*
762: * Now look, ignoring case, for the word in the string.
763: */
764:
1.3 millert 765: if (value("searchheaders") && (cp = strchr(str, ':'))) {
1.5 millert 766: /* Check for special case "/To:" */
767: if (raise(str[0]) == 'T' && raise(str[1]) == 'O' &&
768: str[2] == ':')
769: return(matchto(cp, mesg));
1.1 deraadt 770: *cp++ = '\0';
1.5 millert 771: cp2 = hfield(*str ? str : "subject", mp);
1.1 deraadt 772: cp[-1] = ':';
773: str = cp;
774: } else {
775: cp = str;
776: cp2 = hfield("subject", mp);
777: }
1.6 millert 778: if (cp2 == NULL)
1.1 deraadt 779: return(0);
780: backup = cp2;
781: while (*cp2) {
782: if (*cp == 0)
783: return(1);
784: if (raise(*cp++) != raise(*cp2++)) {
785: cp2 = ++backup;
786: cp = str;
787: }
788: }
789: return(*cp == 0);
790: }
791:
792: /*
793: * Mark the named message by setting its mark bit.
794: */
795: void
796: mark(mesg)
797: int mesg;
798: {
1.9 ! millert 799: int i;
1.1 deraadt 800:
801: i = mesg;
802: if (i < 1 || i > msgCount)
1.9 ! millert 803: errx(1, "Bad message number to mark");
1.1 deraadt 804: message[i-1].m_flag |= MMARK;
805: }
806:
807: /*
808: * Unmark the named message.
809: */
810: void
811: unmark(mesg)
812: int mesg;
813: {
1.9 ! millert 814: int i;
1.1 deraadt 815:
816: i = mesg;
817: if (i < 1 || i > msgCount)
1.9 ! millert 818: errx(1, "Bad message number to unmark");
1.1 deraadt 819: message[i-1].m_flag &= ~MMARK;
820: }
821:
822: /*
823: * Return the message number corresponding to the passed meta character.
824: */
825: int
826: metamess(meta, f)
827: int meta, f;
828: {
1.9 ! millert 829: int c, m;
! 830: struct message *mp;
1.1 deraadt 831:
832: c = meta;
833: switch (c) {
834: case '^':
835: /*
836: * First 'good' message left.
837: */
838: for (mp = &message[0]; mp < &message[msgCount]; mp++)
839: if ((mp->m_flag & MDELETED) == f)
840: return(mp - &message[0] + 1);
1.5 millert 841: puts("No applicable messages");
1.1 deraadt 842: return(-1);
843:
844: case '$':
845: /*
846: * Last 'good message left.
847: */
848: for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
849: if ((mp->m_flag & MDELETED) == f)
850: return(mp - &message[0] + 1);
1.5 millert 851: puts("No applicable messages");
1.1 deraadt 852: return(-1);
853:
854: case '.':
1.5 millert 855: /*
1.1 deraadt 856: * Current message.
857: */
858: m = dot - &message[0] + 1;
859: if ((dot->m_flag & MDELETED) != f) {
860: printf("%d: Inappropriate message\n", m);
861: return(-1);
862: }
863: return(m);
864:
865: default:
866: printf("Unknown metachar (%c)\n", c);
867: return(-1);
868: }
869: }