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