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