[BACK]Return to list.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mail

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: }