Annotation of src/usr.bin/mail/list.c, Revision 1.10
1.10 ! millert 1: /* $OpenBSD: list.c,v 1.9 1997/11/14 00:23:49 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.10 ! millert 41: static char rcsid[] = "$OpenBSD: list.c,v 1.9 1997/11/14 00:23:49 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;
1.10 ! millert 219: } else {
! 220: if ((com->c_argtype & ~(F|P|I|M|T|W|R))
! 221: != (MSGLIST|STRLIST))
! 222: *np++ = savestr(lexstring);
1.1 deraadt 223: }
224: break;
225:
226: case TDOLLAR:
227: case TUP:
228: case TDOT:
229: lexnumber = metamess(lexstring[0], f);
230: if (lexnumber == -1)
231: return(-1);
232: goto number;
233:
234: case TSTAR:
235: if (other) {
1.5 millert 236: puts("Can't mix \"*\" with anything");
1.1 deraadt 237: return(-1);
238: }
239: star++;
240: break;
241:
242: case TERROR:
1.5 millert 243: return(-1);
1.1 deraadt 244: }
245: tok = scan(&bufp);
246: }
247: lastcolmod = colmod;
1.6 millert 248: *np = NULL;
1.1 deraadt 249: mc = 0;
250: if (star) {
251: for (i = 0; i < msgCount; i++)
252: if ((message[i].m_flag & MDELETED) == f) {
253: mark(i+1);
254: mc++;
255: }
256: if (mc == 0) {
1.5 millert 257: puts("No applicable messages.");
1.1 deraadt 258: return(-1);
259: }
260: return(0);
261: }
262:
263: /*
264: * If no numbers were given, mark all of the messages,
265: * so that we can unmark any whose sender was not selected
266: * if any user names were given.
267: */
268:
269: if ((np > namelist || colmod != 0) && mc == 0)
270: for (i = 1; i <= msgCount; i++)
271: if ((message[i-1].m_flag & MDELETED) == f)
272: mark(i);
273:
274: /*
275: * If any names were given, go through and eliminate any
276: * messages whose senders were not requested.
277: */
278:
279: if (np > namelist) {
280: for (i = 1; i <= msgCount; i++) {
1.6 millert 281: for (mc = 0, np = &namelist[0]; *np != NULL; np++)
1.1 deraadt 282: if (**np == '/') {
283: if (matchsubj(*np, i)) {
284: mc++;
285: break;
286: }
287: }
288: else {
289: if (matchsender(*np, i)) {
290: mc++;
291: break;
292: }
293: }
294: if (mc == 0)
295: unmark(i);
296: }
297:
298: /*
299: * Make sure we got some decent messages.
300: */
301:
302: mc = 0;
303: for (i = 1; i <= msgCount; i++)
304: if (message[i-1].m_flag & MMARK) {
305: mc++;
306: break;
307: }
308: if (mc == 0) {
309: printf("No applicable messages from {%s",
310: namelist[0]);
1.6 millert 311: for (np = &namelist[1]; *np != NULL; np++)
1.1 deraadt 312: printf(", %s", *np);
1.5 millert 313: puts("}");
1.1 deraadt 314: return(-1);
315: }
316: }
317:
318: /*
319: * If any colon modifiers were given, go through and
320: * unmark any messages which do not satisfy the modifiers.
321: */
322:
323: if (colmod != 0) {
324: for (i = 1; i <= msgCount; i++) {
1.9 millert 325: struct coltab *colp;
1.1 deraadt 326:
327: mp = &message[i - 1];
328: for (colp = &coltab[0]; colp->co_char; colp++)
329: if (colp->co_bit & colmod)
330: if ((mp->m_flag & colp->co_mask)
331: != colp->co_equal)
332: unmark(i);
333:
334: }
335: for (mp = &message[0]; mp < &message[msgCount]; mp++)
336: if (mp->m_flag & MMARK)
337: break;
338: if (mp >= &message[msgCount]) {
1.9 millert 339: struct coltab *colp;
1.1 deraadt 340:
1.5 millert 341: fputs("No messages satisfy", stdout);
1.1 deraadt 342: for (colp = &coltab[0]; colp->co_char; colp++)
343: if (colp->co_bit & colmod)
344: printf(" :%c", colp->co_char);
1.5 millert 345: putchar('\n');
1.1 deraadt 346: return(-1);
347: }
348: }
349: return(0);
350: }
351:
352: /*
353: * Turn the character after a colon modifier into a bit
354: * value.
355: */
356: int
357: evalcol(col)
358: int col;
359: {
1.9 millert 360: struct coltab *colp;
1.1 deraadt 361:
362: if (col == 0)
363: return(lastcolmod);
364: for (colp = &coltab[0]; colp->co_char; colp++)
365: if (colp->co_char == col)
366: return(colp->co_bit);
367: return(0);
368: }
369:
370: /*
371: * Check the passed message number for legality and proper flags.
372: * If f is MDELETED, then either kind will do. Otherwise, the message
373: * has to be undeleted.
374: */
375: int
376: check(mesg, f)
377: int mesg, f;
378: {
1.9 millert 379: struct message *mp;
1.1 deraadt 380:
381: if (mesg < 1 || mesg > msgCount) {
382: printf("%d: Invalid message number\n", mesg);
383: return(-1);
384: }
385: mp = &message[mesg-1];
386: if (f != MDELETED && (mp->m_flag & MDELETED) != 0) {
387: printf("%d: Inappropriate message\n", mesg);
388: return(-1);
389: }
390: return(0);
391: }
392:
393: /*
394: * Scan out the list of string arguments, shell style
395: * for a RAWLIST.
396: */
397: int
398: getrawlist(line, argv, argc)
399: char line[];
400: char **argv;
401: int argc;
402: {
1.9 millert 403: char c, *cp, *cp2, quotec;
1.1 deraadt 404: int argn;
1.7 millert 405: char *linebuf;
406: size_t linebufsize = BUFSIZ;
407:
408: if ((linebuf = (char *)malloc(linebufsize)) == NULL)
1.9 millert 409: errx(1, "Out of memory");
1.1 deraadt 410:
411: argn = 0;
412: cp = line;
413: for (;;) {
414: for (; *cp == ' ' || *cp == '\t'; cp++)
415: ;
416: if (*cp == '\0')
417: break;
418: if (argn >= argc - 1) {
1.5 millert 419: puts("Too many elements in the list; excess discarded.");
1.1 deraadt 420: break;
421: }
422: cp2 = linebuf;
423: quotec = '\0';
424: while ((c = *cp) != '\0') {
1.7 millert 425: /* Alloc more space if necessary */
426: if (cp2 - linebuf == linebufsize - 1) {
427: linebufsize += BUFSIZ;
1.8 millert 428: linebuf = (char *)realloc(linebuf, linebufsize);
429: if (linebuf == NULL)
1.9 millert 430: errx(1, "Out of memory");
1.8 millert 431: cp2 = linebuf + linebufsize - BUFSIZ - 1;
1.7 millert 432: }
1.1 deraadt 433: cp++;
434: if (quotec != '\0') {
435: if (c == quotec)
436: quotec = '\0';
437: else if (c == '\\')
438: switch (c = *cp++) {
439: case '\0':
440: *cp2++ = '\\';
441: cp--;
442: break;
443: case '0': case '1': case '2': case '3':
444: case '4': case '5': case '6': case '7':
445: c -= '0';
446: if (*cp >= '0' && *cp <= '7')
447: c = c * 8 + *cp++ - '0';
448: if (*cp >= '0' && *cp <= '7')
449: c = c * 8 + *cp++ - '0';
450: *cp2++ = c;
451: break;
452: case 'b':
453: *cp2++ = '\b';
454: break;
455: case 'f':
456: *cp2++ = '\f';
457: break;
458: case 'n':
459: *cp2++ = '\n';
460: break;
461: case 'r':
462: *cp2++ = '\r';
463: break;
464: case 't':
465: *cp2++ = '\t';
466: break;
467: case 'v':
468: *cp2++ = '\v';
469: break;
470: default:
471: *cp2++ = c;
472: }
473: else if (c == '^') {
474: c = *cp++;
475: if (c == '?')
476: *cp2++ = '\177';
477: /* null doesn't show up anyway */
1.2 deraadt 478: else if ((c >= 'A' && c <= '_') ||
479: (c >= 'a' && c <= 'z'))
1.1 deraadt 480: *cp2++ = c & 037;
481: else {
482: *cp2++ = '^';
483: cp--;
484: }
485: } else
486: *cp2++ = c;
487: } else if (c == '"' || c == '\'')
488: quotec = c;
489: else if (c == ' ' || c == '\t')
490: break;
491: else
492: *cp2++ = c;
493: }
494: *cp2 = '\0';
495: argv[argn++] = savestr(linebuf);
496: }
1.6 millert 497: argv[argn] = NULL;
1.7 millert 498: (void)free(linebuf);
1.5 millert 499: return(argn);
1.1 deraadt 500: }
501:
502: /*
503: * scan out a single lexical item and return its token number,
504: * updating the string pointer passed **p. Also, store the value
505: * of the number or string scanned in lexnumber or lexstring as
506: * appropriate. In any event, store the scanned `thing' in lexstring.
507: */
508:
509: struct lex {
510: char l_char;
511: char l_token;
512: } singles[] = {
1.2 deraadt 513: { '$', TDOLLAR },
514: { '.', TDOT },
515: { '^', TUP },
516: { '*', TSTAR },
517: { '-', TDASH },
518: { '+', TPLUS },
519: { '(', TOPEN },
520: { ')', TCLOSE },
521: { 0, 0 }
1.1 deraadt 522: };
523:
524: int
525: scan(sp)
526: char **sp;
527: {
1.9 millert 528: char *cp, *cp2;
529: int c;
530: struct lex *lp;
1.1 deraadt 531: int quotec;
532:
533: if (regretp >= 0) {
534: strcpy(lexstring, string_stack[regretp]);
535: lexnumber = numberstack[regretp];
536: return(regretstack[regretp--]);
537: }
538: cp = *sp;
539: cp2 = lexstring;
540: c = *cp++;
541:
542: /*
543: * strip away leading white space.
544: */
545:
546: while (c == ' ' || c == '\t')
547: c = *cp++;
548:
549: /*
550: * If no characters remain, we are at end of line,
551: * so report that.
552: */
553:
554: if (c == '\0') {
555: *sp = --cp;
556: return(TEOL);
557: }
558:
559: /*
560: * If the leading character is a digit, scan
561: * the number and convert it on the fly.
562: * Return TNUMBER when done.
563: */
564:
565: if (isdigit(c)) {
566: lexnumber = 0;
567: while (isdigit(c)) {
568: lexnumber = lexnumber*10 + c - '0';
569: *cp2++ = c;
570: c = *cp++;
571: }
572: *cp2 = '\0';
573: *sp = --cp;
574: return(TNUMBER);
575: }
576:
577: /*
578: * Check for single character tokens; return such
579: * if found.
580: */
581:
582: for (lp = &singles[0]; lp->l_char != 0; lp++)
583: if (c == lp->l_char) {
584: lexstring[0] = c;
585: lexstring[1] = '\0';
586: *sp = cp;
587: return(lp->l_token);
588: }
589:
590: /*
591: * We've got a string! Copy all the characters
592: * of the string into lexstring, until we see
593: * a null, space, or tab.
594: * If the lead character is a " or ', save it
595: * and scan until you get another.
596: */
597:
598: quotec = 0;
599: if (c == '\'' || c == '"') {
600: quotec = c;
601: c = *cp++;
602: }
603: while (c != '\0') {
604: if (c == quotec) {
605: cp++;
606: break;
607: }
608: if (quotec == 0 && (c == ' ' || c == '\t'))
609: break;
610: if (cp2 - lexstring < STRINGLEN-1)
611: *cp2++ = c;
612: c = *cp++;
613: }
614: if (quotec && c == 0) {
615: fprintf(stderr, "Missing %c\n", quotec);
1.5 millert 616: return(TERROR);
1.1 deraadt 617: }
618: *sp = --cp;
619: *cp2 = '\0';
620: return(TSTRING);
621: }
622:
623: /*
624: * Unscan the named token by pushing it onto the regret stack.
625: */
626: void
627: regret(token)
628: int token;
629: {
630: if (++regretp >= REGDEP)
1.9 millert 631: errx(1, "Too many regrets");
1.1 deraadt 632: regretstack[regretp] = token;
633: lexstring[STRINGLEN-1] = '\0';
634: string_stack[regretp] = savestr(lexstring);
635: numberstack[regretp] = lexnumber;
636: }
637:
638: /*
639: * Reset all the scanner global variables.
640: */
641: void
642: scaninit()
643: {
644: regretp = -1;
645: }
646:
647: /*
648: * Find the first message whose flags & m == f and return
649: * its message number.
650: */
651: int
652: first(f, m)
653: int f, m;
654: {
1.9 millert 655: struct message *mp;
1.1 deraadt 656:
657: if (msgCount == 0)
1.5 millert 658: return(0);
1.1 deraadt 659: f &= MDELETED;
660: m &= MDELETED;
661: for (mp = dot; mp < &message[msgCount]; mp++)
662: if ((mp->m_flag & m) == f)
1.5 millert 663: return(mp - message + 1);
1.1 deraadt 664: for (mp = dot-1; mp >= &message[0]; mp--)
665: if ((mp->m_flag & m) == f)
1.5 millert 666: return(mp - message + 1);
667: return(0);
1.1 deraadt 668: }
669:
670: /*
671: * See if the passed name sent the passed message number. Return true
672: * if so.
673: */
674: int
675: matchsender(str, mesg)
676: char *str;
677: int mesg;
678: {
1.9 millert 679: char *cp, *cp2, *backup;
1.1 deraadt 680:
681: if (!*str) /* null string matches nothing instead of everything */
1.5 millert 682: return(0);
1.1 deraadt 683: backup = cp2 = nameof(&message[mesg - 1], 0);
684: cp = str;
685: while (*cp2) {
686: if (*cp == 0)
687: return(1);
688: if (raise(*cp++) != raise(*cp2++)) {
689: cp2 = ++backup;
690: cp = str;
691: }
692: }
693: return(*cp == 0);
694: }
695:
696: /*
1.5 millert 697: * See if the passed name received the passed message number. Return true
698: * if so.
699: */
700:
701: static char *to_fields[] = { "to", "cc", "bcc", NULL };
702:
703: int
704: matchto(str, mesg)
705: char *str;
706: {
1.9 millert 707: struct message *mp;
708: char *cp, *cp2, *backup, **to;
1.5 millert 709:
710: str++;
711:
712: if (*str == 0) /* null string matches nothing instead of everything */
713: return(0);
714:
715: mp = &message[mesg-1];
716:
717: for (to = to_fields; *to; to++) {
718: cp = str;
719: cp2 = hfield(*to, mp);
1.6 millert 720: if (cp2 != NULL) {
1.5 millert 721: backup = cp2;
722: while (*cp2) {
723: if (*cp == 0)
724: return(1);
725: if (raise(*cp++) != raise(*cp2++)) {
726: cp2 = ++backup;
727: cp = str;
728: }
729: }
730: if (*cp == 0)
731: return(1);
732: }
733: }
734: return(0);
735: }
736:
737: /*
1.1 deraadt 738: * See if the given string matches inside the subject field of the
739: * given message. For the purpose of the scan, we ignore case differences.
740: * If it does, return true. The string search argument is assumed to
741: * have the form "/search-string." If it is of the form "/," we use the
742: * previous search string.
743: */
744:
1.4 deraadt 745: char lastscan[STRINGLEN];
1.1 deraadt 746: int
747: matchsubj(str, mesg)
748: char *str;
749: int mesg;
750: {
1.9 millert 751: struct message *mp;
752: char *cp, *cp2, *backup;
1.1 deraadt 753:
754: str++;
1.5 millert 755: if (*str == '\0')
1.1 deraadt 756: str = lastscan;
1.4 deraadt 757: else {
1.5 millert 758: strncpy(lastscan, str, sizeof(lastscan) - 1);
759: lastscan[sizeof(lastscan) - 1] = '\0';
1.4 deraadt 760: }
1.1 deraadt 761: mp = &message[mesg-1];
762:
763: /*
764: * Now look, ignoring case, for the word in the string.
765: */
766:
1.3 millert 767: if (value("searchheaders") && (cp = strchr(str, ':'))) {
1.5 millert 768: /* Check for special case "/To:" */
769: if (raise(str[0]) == 'T' && raise(str[1]) == 'O' &&
770: str[2] == ':')
771: return(matchto(cp, mesg));
1.1 deraadt 772: *cp++ = '\0';
1.5 millert 773: cp2 = hfield(*str ? str : "subject", mp);
1.1 deraadt 774: cp[-1] = ':';
775: str = cp;
776: } else {
777: cp = str;
778: cp2 = hfield("subject", mp);
779: }
1.6 millert 780: if (cp2 == NULL)
1.1 deraadt 781: return(0);
782: backup = cp2;
783: while (*cp2) {
784: if (*cp == 0)
785: return(1);
786: if (raise(*cp++) != raise(*cp2++)) {
787: cp2 = ++backup;
788: cp = str;
789: }
790: }
791: return(*cp == 0);
792: }
793:
794: /*
795: * Mark the named message by setting its mark bit.
796: */
797: void
798: mark(mesg)
799: int mesg;
800: {
1.9 millert 801: int i;
1.1 deraadt 802:
803: i = mesg;
804: if (i < 1 || i > msgCount)
1.9 millert 805: errx(1, "Bad message number to mark");
1.1 deraadt 806: message[i-1].m_flag |= MMARK;
807: }
808:
809: /*
810: * Unmark the named message.
811: */
812: void
813: unmark(mesg)
814: int mesg;
815: {
1.9 millert 816: int i;
1.1 deraadt 817:
818: i = mesg;
819: if (i < 1 || i > msgCount)
1.9 millert 820: errx(1, "Bad message number to unmark");
1.1 deraadt 821: message[i-1].m_flag &= ~MMARK;
822: }
823:
824: /*
825: * Return the message number corresponding to the passed meta character.
826: */
827: int
828: metamess(meta, f)
829: int meta, f;
830: {
1.9 millert 831: int c, m;
832: struct message *mp;
1.1 deraadt 833:
834: c = meta;
835: switch (c) {
836: case '^':
837: /*
838: * First 'good' message left.
839: */
840: for (mp = &message[0]; mp < &message[msgCount]; mp++)
841: if ((mp->m_flag & MDELETED) == f)
842: return(mp - &message[0] + 1);
1.5 millert 843: puts("No applicable messages");
1.1 deraadt 844: return(-1);
845:
846: case '$':
847: /*
848: * Last 'good message left.
849: */
850: for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
851: if ((mp->m_flag & MDELETED) == f)
852: return(mp - &message[0] + 1);
1.5 millert 853: puts("No applicable messages");
1.1 deraadt 854: return(-1);
855:
856: case '.':
1.5 millert 857: /*
1.1 deraadt 858: * Current message.
859: */
860: m = dot - &message[0] + 1;
861: if ((dot->m_flag & MDELETED) != f) {
862: printf("%d: Inappropriate message\n", m);
863: return(-1);
864: }
865: return(m);
866:
867: default:
868: printf("Unknown metachar (%c)\n", c);
869: return(-1);
870: }
871: }