Annotation of src/usr.bin/mail/list.c, Revision 1.15
1.15 ! deraadt 1: /* $OpenBSD: list.c,v 1.14 2003/10/13 00:46:08 tedu 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.15 ! deraadt 37: static const char rcsid[] = "$OpenBSD: list.c,v 1.14 2003/10/13 00:46:08 tedu 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';
546: *cp2++ = c;
547: c = *cp++;
548: }
549: *cp2 = '\0';
550: *sp = --cp;
551: return(TNUMBER);
552: }
553:
554: /*
555: * Check for single character tokens; return such
556: * if found.
557: */
558: for (lp = &singles[0]; lp->l_char != 0; lp++)
559: if (c == lp->l_char) {
560: lexstring[0] = c;
561: lexstring[1] = '\0';
562: *sp = cp;
563: return(lp->l_token);
564: }
565:
566: /*
567: * We've got a string! Copy all the characters
568: * of the string into lexstring, until we see
569: * a null, space, or tab.
570: * If the lead character is a " or ', save it
571: * and scan until you get another.
572: */
573: quotec = 0;
574: if (c == '\'' || c == '"') {
575: quotec = c;
576: c = *cp++;
577: }
578: while (c != '\0') {
579: if (c == quotec) {
580: cp++;
581: break;
582: }
583: if (quotec == 0 && (c == ' ' || c == '\t'))
584: break;
585: if (cp2 - lexstring < STRINGLEN-1)
586: *cp2++ = c;
587: c = *cp++;
588: }
589: if (quotec && c == 0) {
590: fprintf(stderr, "Missing %c\n", quotec);
1.5 millert 591: return(TERROR);
1.1 deraadt 592: }
593: *sp = --cp;
594: *cp2 = '\0';
595: return(TSTRING);
596: }
597:
598: /*
599: * Unscan the named token by pushing it onto the regret stack.
600: */
601: void
1.11 millert 602: regret(int token)
1.1 deraadt 603: {
1.11 millert 604:
1.1 deraadt 605: if (++regretp >= REGDEP)
1.9 millert 606: errx(1, "Too many regrets");
1.1 deraadt 607: regretstack[regretp] = token;
608: lexstring[STRINGLEN-1] = '\0';
609: string_stack[regretp] = savestr(lexstring);
610: numberstack[regretp] = lexnumber;
611: }
612:
613: /*
614: * Reset all the scanner global variables.
615: */
616: void
1.11 millert 617: scaninit(void)
1.1 deraadt 618: {
1.11 millert 619:
1.1 deraadt 620: regretp = -1;
621: }
622:
623: /*
624: * Find the first message whose flags & m == f and return
625: * its message number.
626: */
627: int
1.11 millert 628: first(int f, int m)
1.1 deraadt 629: {
1.9 millert 630: struct message *mp;
1.1 deraadt 631:
632: if (msgCount == 0)
1.5 millert 633: return(0);
1.1 deraadt 634: f &= MDELETED;
635: m &= MDELETED;
636: for (mp = dot; mp < &message[msgCount]; mp++)
637: if ((mp->m_flag & m) == f)
1.5 millert 638: return(mp - message + 1);
1.1 deraadt 639: for (mp = dot-1; mp >= &message[0]; mp--)
640: if ((mp->m_flag & m) == f)
1.5 millert 641: return(mp - message + 1);
642: return(0);
1.1 deraadt 643: }
644:
645: /*
646: * See if the passed name sent the passed message number. Return true
647: * if so.
648: */
649: int
1.11 millert 650: matchsender(char *str, int mesg)
1.1 deraadt 651: {
1.9 millert 652: char *cp, *cp2, *backup;
1.1 deraadt 653:
654: if (!*str) /* null string matches nothing instead of everything */
1.5 millert 655: return(0);
1.1 deraadt 656: backup = cp2 = nameof(&message[mesg - 1], 0);
657: cp = str;
658: while (*cp2) {
659: if (*cp == 0)
660: return(1);
1.15 ! deraadt 661: if (chraise(*cp++) != chraise(*cp2++)) {
1.1 deraadt 662: cp2 = ++backup;
663: cp = str;
664: }
665: }
666: return(*cp == 0);
667: }
668:
669: /*
1.5 millert 670: * See if the passed name received the passed message number. Return true
671: * if so.
672: */
673: static char *to_fields[] = { "to", "cc", "bcc", NULL };
674:
675: int
1.11 millert 676: matchto(char *str, int mesg)
1.5 millert 677: {
1.9 millert 678: struct message *mp;
679: char *cp, *cp2, *backup, **to;
1.5 millert 680:
681: str++;
682:
683: if (*str == 0) /* null string matches nothing instead of everything */
684: return(0);
685:
686: mp = &message[mesg-1];
687:
688: for (to = to_fields; *to; to++) {
689: cp = str;
690: cp2 = hfield(*to, mp);
1.6 millert 691: if (cp2 != NULL) {
1.5 millert 692: backup = cp2;
693: while (*cp2) {
694: if (*cp == 0)
695: return(1);
1.15 ! deraadt 696: if (chraise(*cp++) != chraise(*cp2++)) {
1.5 millert 697: cp2 = ++backup;
698: cp = str;
699: }
700: }
701: if (*cp == 0)
702: return(1);
703: }
704: }
705: return(0);
706: }
707:
708: /*
1.1 deraadt 709: * See if the given string matches inside the subject field of the
710: * given message. For the purpose of the scan, we ignore case differences.
711: * If it does, return true. The string search argument is assumed to
712: * have the form "/search-string." If it is of the form "/," we use the
713: * previous search string.
714: */
1.11 millert 715: char lastscan[STRINGLEN];
1.1 deraadt 716:
717: int
1.11 millert 718: matchsubj(char *str, int mesg)
1.1 deraadt 719: {
1.9 millert 720: struct message *mp;
721: char *cp, *cp2, *backup;
1.1 deraadt 722:
723: str++;
1.5 millert 724: if (*str == '\0')
1.1 deraadt 725: str = lastscan;
1.11 millert 726: else
727: strlcpy(lastscan, str, sizeof(lastscan));
1.1 deraadt 728: mp = &message[mesg-1];
729:
730: /*
731: * Now look, ignoring case, for the word in the string.
732: */
1.3 millert 733: if (value("searchheaders") && (cp = strchr(str, ':'))) {
1.5 millert 734: /* Check for special case "/To:" */
1.15 ! deraadt 735: if (chraise(str[0]) == 'T' && chraise(str[1]) == 'O' &&
1.5 millert 736: str[2] == ':')
737: return(matchto(cp, mesg));
1.1 deraadt 738: *cp++ = '\0';
1.5 millert 739: cp2 = hfield(*str ? str : "subject", mp);
1.1 deraadt 740: cp[-1] = ':';
741: str = cp;
742: } else {
743: cp = str;
744: cp2 = hfield("subject", mp);
745: }
1.6 millert 746: if (cp2 == NULL)
1.1 deraadt 747: return(0);
748: backup = cp2;
749: while (*cp2) {
750: if (*cp == 0)
751: return(1);
1.15 ! deraadt 752: if (chraise(*cp++) != chraise(*cp2++)) {
1.1 deraadt 753: cp2 = ++backup;
754: cp = str;
755: }
756: }
757: return(*cp == 0);
758: }
759:
760: /*
761: * Mark the named message by setting its mark bit.
762: */
763: void
1.11 millert 764: mark(int mesg)
1.1 deraadt 765: {
1.9 millert 766: int i;
1.1 deraadt 767:
768: i = mesg;
769: if (i < 1 || i > msgCount)
1.9 millert 770: errx(1, "Bad message number to mark");
1.1 deraadt 771: message[i-1].m_flag |= MMARK;
772: }
773:
774: /*
775: * Unmark the named message.
776: */
777: void
1.11 millert 778: unmark(int mesg)
1.1 deraadt 779: {
1.9 millert 780: int i;
1.1 deraadt 781:
782: i = mesg;
783: if (i < 1 || i > msgCount)
1.9 millert 784: errx(1, "Bad message number to unmark");
1.1 deraadt 785: message[i-1].m_flag &= ~MMARK;
786: }
787:
788: /*
789: * Return the message number corresponding to the passed meta character.
790: */
791: int
1.11 millert 792: metamess(int meta, int f)
1.1 deraadt 793: {
1.9 millert 794: int c, m;
795: struct message *mp;
1.1 deraadt 796:
797: c = meta;
798: switch (c) {
799: case '^':
800: /*
801: * First 'good' message left.
802: */
803: for (mp = &message[0]; mp < &message[msgCount]; mp++)
804: if ((mp->m_flag & MDELETED) == f)
805: return(mp - &message[0] + 1);
1.5 millert 806: puts("No applicable messages");
1.1 deraadt 807: return(-1);
808:
809: case '$':
810: /*
811: * Last 'good message left.
812: */
813: for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
814: if ((mp->m_flag & MDELETED) == f)
815: return(mp - &message[0] + 1);
1.5 millert 816: puts("No applicable messages");
1.1 deraadt 817: return(-1);
818:
819: case '.':
1.5 millert 820: /*
1.1 deraadt 821: * Current message.
822: */
823: m = dot - &message[0] + 1;
824: if ((dot->m_flag & MDELETED) != f) {
825: printf("%d: Inappropriate message\n", m);
826: return(-1);
827: }
828: return(m);
829:
830: default:
831: printf("Unknown metachar (%c)\n", c);
832: return(-1);
833: }
834: }