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