[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.9

1.9     ! millert     1: /*     $OpenBSD: list.c,v 1.8 1997/08/04 17:30:22 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.9     ! millert    41: static char rcsid[] = "$OpenBSD: list.c,v 1.8 1997/08/04 17:30:22 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;
                    219:                        }
                    220:                        else
                    221:                                *np++ = savestr(lexstring);
                    222:                        break;
                    223:
                    224:                case TDOLLAR:
                    225:                case TUP:
                    226:                case TDOT:
                    227:                        lexnumber = metamess(lexstring[0], f);
                    228:                        if (lexnumber == -1)
                    229:                                return(-1);
                    230:                        goto number;
                    231:
                    232:                case TSTAR:
                    233:                        if (other) {
1.5       millert   234:                                puts("Can't mix \"*\" with anything");
1.1       deraadt   235:                                return(-1);
                    236:                        }
                    237:                        star++;
                    238:                        break;
                    239:
                    240:                case TERROR:
1.5       millert   241:                        return(-1);
1.1       deraadt   242:                }
                    243:                tok = scan(&bufp);
                    244:        }
                    245:        lastcolmod = colmod;
1.6       millert   246:        *np = NULL;
1.1       deraadt   247:        mc = 0;
                    248:        if (star) {
                    249:                for (i = 0; i < msgCount; i++)
                    250:                        if ((message[i].m_flag & MDELETED) == f) {
                    251:                                mark(i+1);
                    252:                                mc++;
                    253:                        }
                    254:                if (mc == 0) {
1.5       millert   255:                        puts("No applicable messages.");
1.1       deraadt   256:                        return(-1);
                    257:                }
                    258:                return(0);
                    259:        }
                    260:
                    261:        /*
                    262:         * If no numbers were given, mark all of the messages,
                    263:         * so that we can unmark any whose sender was not selected
                    264:         * if any user names were given.
                    265:         */
                    266:
                    267:        if ((np > namelist || colmod != 0) && mc == 0)
                    268:                for (i = 1; i <= msgCount; i++)
                    269:                        if ((message[i-1].m_flag & MDELETED) == f)
                    270:                                mark(i);
                    271:
                    272:        /*
                    273:         * If any names were given, go through and eliminate any
                    274:         * messages whose senders were not requested.
                    275:         */
                    276:
                    277:        if (np > namelist) {
                    278:                for (i = 1; i <= msgCount; i++) {
1.6       millert   279:                        for (mc = 0, np = &namelist[0]; *np != NULL; np++)
1.1       deraadt   280:                                if (**np == '/') {
                    281:                                        if (matchsubj(*np, i)) {
                    282:                                                mc++;
                    283:                                                break;
                    284:                                        }
                    285:                                }
                    286:                                else {
                    287:                                        if (matchsender(*np, i)) {
                    288:                                                mc++;
                    289:                                                break;
                    290:                                        }
                    291:                                }
                    292:                        if (mc == 0)
                    293:                                unmark(i);
                    294:                }
                    295:
                    296:                /*
                    297:                 * Make sure we got some decent messages.
                    298:                 */
                    299:
                    300:                mc = 0;
                    301:                for (i = 1; i <= msgCount; i++)
                    302:                        if (message[i-1].m_flag & MMARK) {
                    303:                                mc++;
                    304:                                break;
                    305:                        }
                    306:                if (mc == 0) {
                    307:                        printf("No applicable messages from {%s",
                    308:                                namelist[0]);
1.6       millert   309:                        for (np = &namelist[1]; *np != NULL; np++)
1.1       deraadt   310:                                printf(", %s", *np);
1.5       millert   311:                        puts("}");
1.1       deraadt   312:                        return(-1);
                    313:                }
                    314:        }
                    315:
                    316:        /*
                    317:         * If any colon modifiers were given, go through and
                    318:         * unmark any messages which do not satisfy the modifiers.
                    319:         */
                    320:
                    321:        if (colmod != 0) {
                    322:                for (i = 1; i <= msgCount; i++) {
1.9     ! millert   323:                        struct coltab *colp;
1.1       deraadt   324:
                    325:                        mp = &message[i - 1];
                    326:                        for (colp = &coltab[0]; colp->co_char; colp++)
                    327:                                if (colp->co_bit & colmod)
                    328:                                        if ((mp->m_flag & colp->co_mask)
                    329:                                            != colp->co_equal)
                    330:                                                unmark(i);
                    331:
                    332:                }
                    333:                for (mp = &message[0]; mp < &message[msgCount]; mp++)
                    334:                        if (mp->m_flag & MMARK)
                    335:                                break;
                    336:                if (mp >= &message[msgCount]) {
1.9     ! millert   337:                        struct coltab *colp;
1.1       deraadt   338:
1.5       millert   339:                        fputs("No messages satisfy", stdout);
1.1       deraadt   340:                        for (colp = &coltab[0]; colp->co_char; colp++)
                    341:                                if (colp->co_bit & colmod)
                    342:                                        printf(" :%c", colp->co_char);
1.5       millert   343:                        putchar('\n');
1.1       deraadt   344:                        return(-1);
                    345:                }
                    346:        }
                    347:        return(0);
                    348: }
                    349:
                    350: /*
                    351:  * Turn the character after a colon modifier into a bit
                    352:  * value.
                    353:  */
                    354: int
                    355: evalcol(col)
                    356:        int col;
                    357: {
1.9     ! millert   358:        struct coltab *colp;
1.1       deraadt   359:
                    360:        if (col == 0)
                    361:                return(lastcolmod);
                    362:        for (colp = &coltab[0]; colp->co_char; colp++)
                    363:                if (colp->co_char == col)
                    364:                        return(colp->co_bit);
                    365:        return(0);
                    366: }
                    367:
                    368: /*
                    369:  * Check the passed message number for legality and proper flags.
                    370:  * If f is MDELETED, then either kind will do.  Otherwise, the message
                    371:  * has to be undeleted.
                    372:  */
                    373: int
                    374: check(mesg, f)
                    375:        int mesg, f;
                    376: {
1.9     ! millert   377:        struct message *mp;
1.1       deraadt   378:
                    379:        if (mesg < 1 || mesg > msgCount) {
                    380:                printf("%d: Invalid message number\n", mesg);
                    381:                return(-1);
                    382:        }
                    383:        mp = &message[mesg-1];
                    384:        if (f != MDELETED && (mp->m_flag & MDELETED) != 0) {
                    385:                printf("%d: Inappropriate message\n", mesg);
                    386:                return(-1);
                    387:        }
                    388:        return(0);
                    389: }
                    390:
                    391: /*
                    392:  * Scan out the list of string arguments, shell style
                    393:  * for a RAWLIST.
                    394:  */
                    395: int
                    396: getrawlist(line, argv, argc)
                    397:        char line[];
                    398:        char **argv;
                    399:        int  argc;
                    400: {
1.9     ! millert   401:        char c, *cp, *cp2, quotec;
1.1       deraadt   402:        int argn;
1.7       millert   403:        char *linebuf;
                    404:        size_t linebufsize = BUFSIZ;
                    405:
                    406:        if ((linebuf = (char *)malloc(linebufsize)) == NULL)
1.9     ! millert   407:                errx(1, "Out of memory");
1.1       deraadt   408:
                    409:        argn = 0;
                    410:        cp = line;
                    411:        for (;;) {
                    412:                for (; *cp == ' ' || *cp == '\t'; cp++)
                    413:                        ;
                    414:                if (*cp == '\0')
                    415:                        break;
                    416:                if (argn >= argc - 1) {
1.5       millert   417:                        puts("Too many elements in the list; excess discarded.");
1.1       deraadt   418:                        break;
                    419:                }
                    420:                cp2 = linebuf;
                    421:                quotec = '\0';
                    422:                while ((c = *cp) != '\0') {
1.7       millert   423:                        /* Alloc more space if necessary */
                    424:                        if (cp2 - linebuf == linebufsize - 1) {
                    425:                                linebufsize += BUFSIZ;
1.8       millert   426:                                linebuf = (char *)realloc(linebuf, linebufsize);
                    427:                                if (linebuf == NULL)
1.9     ! millert   428:                                        errx(1, "Out of memory");
1.8       millert   429:                                cp2 = linebuf + linebufsize - BUFSIZ - 1;
1.7       millert   430:                        }
1.1       deraadt   431:                        cp++;
                    432:                        if (quotec != '\0') {
                    433:                                if (c == quotec)
                    434:                                        quotec = '\0';
                    435:                                else if (c == '\\')
                    436:                                        switch (c = *cp++) {
                    437:                                        case '\0':
                    438:                                                *cp2++ = '\\';
                    439:                                                cp--;
                    440:                                                break;
                    441:                                        case '0': case '1': case '2': case '3':
                    442:                                        case '4': case '5': case '6': case '7':
                    443:                                                c -= '0';
                    444:                                                if (*cp >= '0' && *cp <= '7')
                    445:                                                        c = c * 8 + *cp++ - '0';
                    446:                                                if (*cp >= '0' && *cp <= '7')
                    447:                                                        c = c * 8 + *cp++ - '0';
                    448:                                                *cp2++ = c;
                    449:                                                break;
                    450:                                        case 'b':
                    451:                                                *cp2++ = '\b';
                    452:                                                break;
                    453:                                        case 'f':
                    454:                                                *cp2++ = '\f';
                    455:                                                break;
                    456:                                        case 'n':
                    457:                                                *cp2++ = '\n';
                    458:                                                break;
                    459:                                        case 'r':
                    460:                                                *cp2++ = '\r';
                    461:                                                break;
                    462:                                        case 't':
                    463:                                                *cp2++ = '\t';
                    464:                                                break;
                    465:                                        case 'v':
                    466:                                                *cp2++ = '\v';
                    467:                                                break;
                    468:                                        default:
                    469:                                                *cp2++ = c;
                    470:                                        }
                    471:                                else if (c == '^') {
                    472:                                        c = *cp++;
                    473:                                        if (c == '?')
                    474:                                                *cp2++ = '\177';
                    475:                                        /* null doesn't show up anyway */
1.2       deraadt   476:                                        else if ((c >= 'A' && c <= '_') ||
                    477:                                                 (c >= 'a' && c <= 'z'))
1.1       deraadt   478:                                                *cp2++ = c & 037;
                    479:                                        else {
                    480:                                                *cp2++ = '^';
                    481:                                                cp--;
                    482:                                        }
                    483:                                } else
                    484:                                        *cp2++ = c;
                    485:                        } else if (c == '"' || c == '\'')
                    486:                                quotec = c;
                    487:                        else if (c == ' ' || c == '\t')
                    488:                                break;
                    489:                        else
                    490:                                *cp2++ = c;
                    491:                }
                    492:                *cp2 = '\0';
                    493:                argv[argn++] = savestr(linebuf);
                    494:        }
1.6       millert   495:        argv[argn] = NULL;
1.7       millert   496:        (void)free(linebuf);
1.5       millert   497:        return(argn);
1.1       deraadt   498: }
                    499:
                    500: /*
                    501:  * scan out a single lexical item and return its token number,
                    502:  * updating the string pointer passed **p.  Also, store the value
                    503:  * of the number or string scanned in lexnumber or lexstring as
                    504:  * appropriate.  In any event, store the scanned `thing' in lexstring.
                    505:  */
                    506:
                    507: struct lex {
                    508:        char    l_char;
                    509:        char    l_token;
                    510: } singles[] = {
1.2       deraadt   511:        { '$',  TDOLLAR },
                    512:        { '.',  TDOT },
                    513:        { '^',  TUP },
                    514:        { '*',  TSTAR },
                    515:        { '-',  TDASH },
                    516:        { '+',  TPLUS },
                    517:        { '(',  TOPEN },
                    518:        { ')',  TCLOSE },
                    519:        { 0,    0 }
1.1       deraadt   520: };
                    521:
                    522: int
                    523: scan(sp)
                    524:        char **sp;
                    525: {
1.9     ! millert   526:        char *cp, *cp2;
        !           527:        int c;
        !           528:        struct lex *lp;
1.1       deraadt   529:        int quotec;
                    530:
                    531:        if (regretp >= 0) {
                    532:                strcpy(lexstring, string_stack[regretp]);
                    533:                lexnumber = numberstack[regretp];
                    534:                return(regretstack[regretp--]);
                    535:        }
                    536:        cp = *sp;
                    537:        cp2 = lexstring;
                    538:        c = *cp++;
                    539:
                    540:        /*
                    541:         * strip away leading white space.
                    542:         */
                    543:
                    544:        while (c == ' ' || c == '\t')
                    545:                c = *cp++;
                    546:
                    547:        /*
                    548:         * If no characters remain, we are at end of line,
                    549:         * so report that.
                    550:         */
                    551:
                    552:        if (c == '\0') {
                    553:                *sp = --cp;
                    554:                return(TEOL);
                    555:        }
                    556:
                    557:        /*
                    558:         * If the leading character is a digit, scan
                    559:         * the number and convert it on the fly.
                    560:         * Return TNUMBER when done.
                    561:         */
                    562:
                    563:        if (isdigit(c)) {
                    564:                lexnumber = 0;
                    565:                while (isdigit(c)) {
                    566:                        lexnumber = lexnumber*10 + c - '0';
                    567:                        *cp2++ = c;
                    568:                        c = *cp++;
                    569:                }
                    570:                *cp2 = '\0';
                    571:                *sp = --cp;
                    572:                return(TNUMBER);
                    573:        }
                    574:
                    575:        /*
                    576:         * Check for single character tokens; return such
                    577:         * if found.
                    578:         */
                    579:
                    580:        for (lp = &singles[0]; lp->l_char != 0; lp++)
                    581:                if (c == lp->l_char) {
                    582:                        lexstring[0] = c;
                    583:                        lexstring[1] = '\0';
                    584:                        *sp = cp;
                    585:                        return(lp->l_token);
                    586:                }
                    587:
                    588:        /*
                    589:         * We've got a string!  Copy all the characters
                    590:         * of the string into lexstring, until we see
                    591:         * a null, space, or tab.
                    592:         * If the lead character is a " or ', save it
                    593:         * and scan until you get another.
                    594:         */
                    595:
                    596:        quotec = 0;
                    597:        if (c == '\'' || c == '"') {
                    598:                quotec = c;
                    599:                c = *cp++;
                    600:        }
                    601:        while (c != '\0') {
                    602:                if (c == quotec) {
                    603:                        cp++;
                    604:                        break;
                    605:                }
                    606:                if (quotec == 0 && (c == ' ' || c == '\t'))
                    607:                        break;
                    608:                if (cp2 - lexstring < STRINGLEN-1)
                    609:                        *cp2++ = c;
                    610:                c = *cp++;
                    611:        }
                    612:        if (quotec && c == 0) {
                    613:                fprintf(stderr, "Missing %c\n", quotec);
1.5       millert   614:                return(TERROR);
1.1       deraadt   615:        }
                    616:        *sp = --cp;
                    617:        *cp2 = '\0';
                    618:        return(TSTRING);
                    619: }
                    620:
                    621: /*
                    622:  * Unscan the named token by pushing it onto the regret stack.
                    623:  */
                    624: void
                    625: regret(token)
                    626:        int token;
                    627: {
                    628:        if (++regretp >= REGDEP)
1.9     ! millert   629:                errx(1, "Too many regrets");
1.1       deraadt   630:        regretstack[regretp] = token;
                    631:        lexstring[STRINGLEN-1] = '\0';
                    632:        string_stack[regretp] = savestr(lexstring);
                    633:        numberstack[regretp] = lexnumber;
                    634: }
                    635:
                    636: /*
                    637:  * Reset all the scanner global variables.
                    638:  */
                    639: void
                    640: scaninit()
                    641: {
                    642:        regretp = -1;
                    643: }
                    644:
                    645: /*
                    646:  * Find the first message whose flags & m == f  and return
                    647:  * its message number.
                    648:  */
                    649: int
                    650: first(f, m)
                    651:        int f, m;
                    652: {
1.9     ! millert   653:        struct message *mp;
1.1       deraadt   654:
                    655:        if (msgCount == 0)
1.5       millert   656:                return(0);
1.1       deraadt   657:        f &= MDELETED;
                    658:        m &= MDELETED;
                    659:        for (mp = dot; mp < &message[msgCount]; mp++)
                    660:                if ((mp->m_flag & m) == f)
1.5       millert   661:                        return(mp - message + 1);
1.1       deraadt   662:        for (mp = dot-1; mp >= &message[0]; mp--)
                    663:                if ((mp->m_flag & m) == f)
1.5       millert   664:                        return(mp - message + 1);
                    665:        return(0);
1.1       deraadt   666: }
                    667:
                    668: /*
                    669:  * See if the passed name sent the passed message number.  Return true
                    670:  * if so.
                    671:  */
                    672: int
                    673: matchsender(str, mesg)
                    674:        char *str;
                    675:        int mesg;
                    676: {
1.9     ! millert   677:        char *cp, *cp2, *backup;
1.1       deraadt   678:
                    679:        if (!*str)      /* null string matches nothing instead of everything */
1.5       millert   680:                return(0);
1.1       deraadt   681:        backup = cp2 = nameof(&message[mesg - 1], 0);
                    682:        cp = str;
                    683:        while (*cp2) {
                    684:                if (*cp == 0)
                    685:                        return(1);
                    686:                if (raise(*cp++) != raise(*cp2++)) {
                    687:                        cp2 = ++backup;
                    688:                        cp = str;
                    689:                }
                    690:        }
                    691:        return(*cp == 0);
                    692: }
                    693:
                    694: /*
1.5       millert   695:  * See if the passed name received the passed message number.  Return true
                    696:  * if so.
                    697:  */
                    698:
                    699: static char *to_fields[] = { "to", "cc", "bcc", NULL };
                    700:
                    701: int
                    702: matchto(str, mesg)
                    703:        char *str;
                    704: {
1.9     ! millert   705:        struct message *mp;
        !           706:        char *cp, *cp2, *backup, **to;
1.5       millert   707:
                    708:        str++;
                    709:
                    710:        if (*str == 0)  /* null string matches nothing instead of everything */
                    711:                return(0);
                    712:
                    713:        mp = &message[mesg-1];
                    714:
                    715:        for (to = to_fields; *to; to++) {
                    716:                cp = str;
                    717:                cp2 = hfield(*to, mp);
1.6       millert   718:                if (cp2 != NULL) {
1.5       millert   719:                        backup = cp2;
                    720:                        while (*cp2) {
                    721:                                if (*cp == 0)
                    722:                                        return(1);
                    723:                                if (raise(*cp++) != raise(*cp2++)) {
                    724:                                        cp2 = ++backup;
                    725:                                        cp = str;
                    726:                                }
                    727:                        }
                    728:                        if (*cp == 0)
                    729:                                return(1);
                    730:                }
                    731:        }
                    732:        return(0);
                    733: }
                    734:
                    735: /*
1.1       deraadt   736:  * See if the given string matches inside the subject field of the
                    737:  * given message.  For the purpose of the scan, we ignore case differences.
                    738:  * If it does, return true.  The string search argument is assumed to
                    739:  * have the form "/search-string."  If it is of the form "/," we use the
                    740:  * previous search string.
                    741:  */
                    742:
1.4       deraadt   743: char lastscan[STRINGLEN];
1.1       deraadt   744: int
                    745: matchsubj(str, mesg)
                    746:        char *str;
                    747:        int mesg;
                    748: {
1.9     ! millert   749:        struct message *mp;
        !           750:        char *cp, *cp2, *backup;
1.1       deraadt   751:
                    752:        str++;
1.5       millert   753:        if (*str == '\0')
1.1       deraadt   754:                str = lastscan;
1.4       deraadt   755:        else {
1.5       millert   756:                strncpy(lastscan, str, sizeof(lastscan) - 1);
                    757:                lastscan[sizeof(lastscan) - 1] = '\0';
1.4       deraadt   758:        }
1.1       deraadt   759:        mp = &message[mesg-1];
                    760:
                    761:        /*
                    762:         * Now look, ignoring case, for the word in the string.
                    763:         */
                    764:
1.3       millert   765:        if (value("searchheaders") && (cp = strchr(str, ':'))) {
1.5       millert   766:                /* Check for special case "/To:" */
                    767:                if (raise(str[0]) == 'T' && raise(str[1]) == 'O' &&
                    768:                    str[2] == ':')
                    769:                        return(matchto(cp, mesg));
1.1       deraadt   770:                *cp++ = '\0';
1.5       millert   771:                cp2 = hfield(*str ? str : "subject", mp);
1.1       deraadt   772:                cp[-1] = ':';
                    773:                str = cp;
                    774:        } else {
                    775:                cp = str;
                    776:                cp2 = hfield("subject", mp);
                    777:        }
1.6       millert   778:        if (cp2 == NULL)
1.1       deraadt   779:                return(0);
                    780:        backup = cp2;
                    781:        while (*cp2) {
                    782:                if (*cp == 0)
                    783:                        return(1);
                    784:                if (raise(*cp++) != raise(*cp2++)) {
                    785:                        cp2 = ++backup;
                    786:                        cp = str;
                    787:                }
                    788:        }
                    789:        return(*cp == 0);
                    790: }
                    791:
                    792: /*
                    793:  * Mark the named message by setting its mark bit.
                    794:  */
                    795: void
                    796: mark(mesg)
                    797:        int mesg;
                    798: {
1.9     ! millert   799:        int i;
1.1       deraadt   800:
                    801:        i = mesg;
                    802:        if (i < 1 || i > msgCount)
1.9     ! millert   803:                errx(1, "Bad message number to mark");
1.1       deraadt   804:        message[i-1].m_flag |= MMARK;
                    805: }
                    806:
                    807: /*
                    808:  * Unmark the named message.
                    809:  */
                    810: void
                    811: unmark(mesg)
                    812:        int mesg;
                    813: {
1.9     ! millert   814:        int i;
1.1       deraadt   815:
                    816:        i = mesg;
                    817:        if (i < 1 || i > msgCount)
1.9     ! millert   818:                errx(1, "Bad message number to unmark");
1.1       deraadt   819:        message[i-1].m_flag &= ~MMARK;
                    820: }
                    821:
                    822: /*
                    823:  * Return the message number corresponding to the passed meta character.
                    824:  */
                    825: int
                    826: metamess(meta, f)
                    827:        int meta, f;
                    828: {
1.9     ! millert   829:        int c, m;
        !           830:        struct message *mp;
1.1       deraadt   831:
                    832:        c = meta;
                    833:        switch (c) {
                    834:        case '^':
                    835:                /*
                    836:                 * First 'good' message left.
                    837:                 */
                    838:                for (mp = &message[0]; mp < &message[msgCount]; mp++)
                    839:                        if ((mp->m_flag & MDELETED) == f)
                    840:                                return(mp - &message[0] + 1);
1.5       millert   841:                puts("No applicable messages");
1.1       deraadt   842:                return(-1);
                    843:
                    844:        case '$':
                    845:                /*
                    846:                 * Last 'good message left.
                    847:                 */
                    848:                for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
                    849:                        if ((mp->m_flag & MDELETED) == f)
                    850:                                return(mp - &message[0] + 1);
1.5       millert   851:                puts("No applicable messages");
1.1       deraadt   852:                return(-1);
                    853:
                    854:        case '.':
1.5       millert   855:                /*
1.1       deraadt   856:                 * Current message.
                    857:                 */
                    858:                m = dot - &message[0] + 1;
                    859:                if ((dot->m_flag & MDELETED) != f) {
                    860:                        printf("%d: Inappropriate message\n", m);
                    861:                        return(-1);
                    862:                }
                    863:                return(m);
                    864:
                    865:        default:
                    866:                printf("Unknown metachar (%c)\n", c);
                    867:                return(-1);
                    868:        }
                    869: }