Annotation of 43BSDTahoe/ucb/Mail/list.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted
                      6:  * provided that this notice is preserved and that due credit is given
                      7:  * to the University of California at Berkeley. The name of the University
                      8:  * may not be used to endorse or promote products derived from this
                      9:  * software without specific prior written permission. This software
                     10:  * is provided ``as is'' without express or implied warranty.
                     11:  */
                     12: 
                     13: #ifdef notdef
                     14: static char sccsid[] = "@(#)list.c     5.6 (Berkeley) 2/18/88";
                     15: #endif /* notdef */
                     16: 
                     17: #include "rcv.h"
                     18: #include <ctype.h>
                     19: 
                     20: /*
                     21:  * Mail -- a mail program
                     22:  *
                     23:  * Message list handling.
                     24:  */
                     25: 
                     26: /*
                     27:  * Convert the user string of message numbers and
                     28:  * store the numbers into vector.
                     29:  *
                     30:  * Returns the count of messages picked up or -1 on error.
                     31:  */
                     32: 
                     33: getmsglist(buf, vector, flags)
                     34:        char *buf;
                     35:        int *vector;
                     36: {
                     37:        register int *ip;
                     38:        register struct message *mp;
                     39: 
                     40:        if (markall(buf, flags) < 0)
                     41:                return(-1);
                     42:        ip = vector;
                     43:        for (mp = &message[0]; mp < &message[msgCount]; mp++)
                     44:                if (mp->m_flag & MMARK)
                     45:                        *ip++ = mp - &message[0] + 1;
                     46:        *ip = NULL;
                     47:        return(ip - vector);
                     48: }
                     49: 
                     50: /*
                     51:  * Mark all messages that the user wanted from the command
                     52:  * line in the message structure.  Return 0 on success, -1
                     53:  * on error.
                     54:  */
                     55: 
                     56: /*
                     57:  * Bit values for colon modifiers.
                     58:  */
                     59: 
                     60: #define        CMNEW           01              /* New messages */
                     61: #define        CMOLD           02              /* Old messages */
                     62: #define        CMUNREAD        04              /* Unread messages */
                     63: #define        CMDELETED       010             /* Deleted messages */
                     64: #define        CMREAD          020             /* Read messages */
                     65: 
                     66: /*
                     67:  * The following table describes the letters which can follow
                     68:  * the colon and gives the corresponding modifier bit.
                     69:  */
                     70: 
                     71: struct coltab {
                     72:        char    co_char;                /* What to find past : */
                     73:        int     co_bit;                 /* Associated modifier bit */
                     74:        int     co_mask;                /* m_status bits to mask */
                     75:        int     co_equal;               /* ... must equal this */
                     76: } coltab[] = {
                     77:        'n',            CMNEW,          MNEW,           MNEW,
                     78:        'o',            CMOLD,          MNEW,           0,
                     79:        'u',            CMUNREAD,       MREAD,          0,
                     80:        'd',            CMDELETED,      MDELETED,       MDELETED,
                     81:        'r',            CMREAD,         MREAD,          MREAD,
                     82:        0,              0,              0,              0
                     83: };
                     84: 
                     85: static int     lastcolmod;
                     86: 
                     87: markall(buf, f)
                     88:        char buf[];
                     89: {
                     90:        register char **np;
                     91:        register int i;
                     92:        register struct message *mp;
                     93:        char *namelist[NMLSIZE], *bufp;
                     94:        int tok, beg, mc, star, other, valdot, colmod, colresult;
                     95: 
                     96:        valdot = dot - &message[0] + 1;
                     97:        colmod = 0;
                     98:        for (i = 1; i <= msgCount; i++)
                     99:                unmark(i);
                    100:        bufp = buf;
                    101:        mc = 0;
                    102:        np = &namelist[0];
                    103:        scaninit();
                    104:        tok = scan(&bufp);
                    105:        star = 0;
                    106:        other = 0;
                    107:        beg = 0;
                    108:        while (tok != TEOL) {
                    109:                switch (tok) {
                    110:                case TNUMBER:
                    111: number:
                    112:                        if (star) {
                    113:                                printf("No numbers mixed with *\n");
                    114:                                return(-1);
                    115:                        }
                    116:                        mc++;
                    117:                        other++;
                    118:                        if (beg != 0) {
                    119:                                if (check(lexnumber, f))
                    120:                                        return(-1);
                    121:                                for (i = beg; i <= lexnumber; i++)
                    122:                                        if ((message[i - 1].m_flag & MDELETED) == f)
                    123:                                                mark(i);
                    124:                                beg = 0;
                    125:                                break;
                    126:                        }
                    127:                        beg = lexnumber;
                    128:                        if (check(beg, f))
                    129:                                return(-1);
                    130:                        tok = scan(&bufp);
                    131:                        regret(tok);
                    132:                        if (tok != TDASH) {
                    133:                                mark(beg);
                    134:                                beg = 0;
                    135:                        }
                    136:                        break;
                    137: 
                    138:                case TPLUS:
                    139:                        if (beg != 0) {
                    140:                                printf("Non-numeric second argument\n");
                    141:                                return(-1);
                    142:                        }
                    143:                        i = valdot;
                    144:                        do {
                    145:                                i++;
                    146:                                if (i > msgCount) {
                    147:                                        printf("Referencing beyond EOF\n");
                    148:                                        return(-1);
                    149:                                }
                    150:                        } while ((message[i - 1].m_flag & MDELETED) != f);
                    151:                        mark(i);
                    152:                        break;
                    153: 
                    154:                case TDASH:
                    155:                        if (beg == 0) {
                    156:                                i = valdot;
                    157:                                do {
                    158:                                        i--;
                    159:                                        if (i <= 0) {
                    160:                                                printf("Referencing before 1\n");
                    161:                                                return(-1);
                    162:                                        }
                    163:                                } while ((message[i - 1].m_flag & MDELETED) != f);
                    164:                                mark(i);
                    165:                        }
                    166:                        break;
                    167: 
                    168:                case TSTRING:
                    169:                        if (beg != 0) {
                    170:                                printf("Non-numeric second argument\n");
                    171:                                return(-1);
                    172:                        }
                    173:                        other++;
                    174:                        if (lexstring[0] == ':') {
                    175:                                colresult = evalcol(lexstring[1]);
                    176:                                if (colresult == 0) {
                    177:                                        printf("Unknown colon modifier \"%s\"\n",
                    178:                                            lexstring);
                    179:                                        return(-1);
                    180:                                }
                    181:                                colmod |= colresult;
                    182:                        }
                    183:                        else
                    184:                                *np++ = savestr(lexstring);
                    185:                        break;
                    186: 
                    187:                case TDOLLAR:
                    188:                case TUP:
                    189:                case TDOT:
                    190:                        lexnumber = metamess(lexstring[0], f);
                    191:                        if (lexnumber == -1)
                    192:                                return(-1);
                    193:                        goto number;
                    194: 
                    195:                case TSTAR:
                    196:                        if (other) {
                    197:                                printf("Can't mix \"*\" with anything\n");
                    198:                                return(-1);
                    199:                        }
                    200:                        star++;
                    201:                        break;
                    202:                }
                    203:                tok = scan(&bufp);
                    204:        }
                    205:        lastcolmod = colmod;
                    206:        *np = NOSTR;
                    207:        mc = 0;
                    208:        if (star) {
                    209:                for (i = 0; i < msgCount; i++)
                    210:                        if ((message[i].m_flag & MDELETED) == f) {
                    211:                                mark(i+1);
                    212:                                mc++;
                    213:                        }
                    214:                if (mc == 0) {
                    215:                        printf("No applicable messages.\n");
                    216:                        return(-1);
                    217:                }
                    218:                return(0);
                    219:        }
                    220: 
                    221:        /*
                    222:         * If no numbers were given, mark all of the messages,
                    223:         * so that we can unmark any whose sender was not selected
                    224:         * if any user names were given.
                    225:         */
                    226: 
                    227:        if ((np > namelist || colmod != 0) && mc == 0)
                    228:                for (i = 1; i <= msgCount; i++)
                    229:                        if ((message[i-1].m_flag & MDELETED) == f)
                    230:                                mark(i);
                    231: 
                    232:        /*
                    233:         * If any names were given, go through and eliminate any
                    234:         * messages whose senders were not requested.
                    235:         */
                    236: 
                    237:        if (np > namelist) {
                    238:                for (i = 1; i <= msgCount; i++) {
                    239:                        for (mc = 0, np = &namelist[0]; *np != NOSTR; np++)
                    240:                                if (**np == '/') {
                    241:                                        if (matchsubj(*np, i)) {
                    242:                                                mc++;
                    243:                                                break;
                    244:                                        }
                    245:                                }
                    246:                                else {
                    247:                                        if (sender(*np, i)) {
                    248:                                                mc++;
                    249:                                                break;
                    250:                                        }
                    251:                                }
                    252:                        if (mc == 0)
                    253:                                unmark(i);
                    254:                }
                    255: 
                    256:                /*
                    257:                 * Make sure we got some decent messages.
                    258:                 */
                    259: 
                    260:                mc = 0;
                    261:                for (i = 1; i <= msgCount; i++)
                    262:                        if (message[i-1].m_flag & MMARK) {
                    263:                                mc++;
                    264:                                break;
                    265:                        }
                    266:                if (mc == 0) {
                    267:                        printf("No applicable messages from {%s",
                    268:                                namelist[0]);
                    269:                        for (np = &namelist[1]; *np != NOSTR; np++)
                    270:                                printf(", %s", *np);
                    271:                        printf("}\n");
                    272:                        return(-1);
                    273:                }
                    274:        }
                    275: 
                    276:        /*
                    277:         * If any colon modifiers were given, go through and
                    278:         * unmark any messages which do not satisfy the modifiers.
                    279:         */
                    280: 
                    281:        if (colmod != 0) {
                    282:                for (i = 1; i <= msgCount; i++) {
                    283:                        register struct coltab *colp;
                    284: 
                    285:                        mp = &message[i - 1];
                    286:                        for (colp = &coltab[0]; colp->co_char; colp++)
                    287:                                if (colp->co_bit & colmod)
                    288:                                        if ((mp->m_flag & colp->co_mask)
                    289:                                            != colp->co_equal)
                    290:                                                unmark(i);
                    291:                        
                    292:                }
                    293:                for (mp = &message[0]; mp < &message[msgCount]; mp++)
                    294:                        if (mp->m_flag & MMARK)
                    295:                                break;
                    296:                if (mp >= &message[msgCount]) {
                    297:                        register struct coltab *colp;
                    298: 
                    299:                        printf("No messages satisfy");
                    300:                        for (colp = &coltab[0]; colp->co_char; colp++)
                    301:                                if (colp->co_bit & colmod)
                    302:                                        printf(" :%c", colp->co_char);
                    303:                        printf("\n");
                    304:                        return(-1);
                    305:                }
                    306:        }
                    307:        return(0);
                    308: }
                    309: 
                    310: /*
                    311:  * Turn the character after a colon modifier into a bit
                    312:  * value.
                    313:  */
                    314: evalcol(col)
                    315: {
                    316:        register struct coltab *colp;
                    317: 
                    318:        if (col == 0)
                    319:                return(lastcolmod);
                    320:        for (colp = &coltab[0]; colp->co_char; colp++)
                    321:                if (colp->co_char == col)
                    322:                        return(colp->co_bit);
                    323:        return(0);
                    324: }
                    325: 
                    326: /*
                    327:  * Check the passed message number for legality and proper flags.
                    328:  */
                    329: 
                    330: check(mesg, f)
                    331: {
                    332:        register struct message *mp;
                    333: 
                    334:        if (mesg < 1 || mesg > msgCount) {
                    335:                printf("%d: Invalid message number\n", mesg);
                    336:                return(-1);
                    337:        }
                    338:        mp = &message[mesg-1];
                    339:        if ((mp->m_flag & MDELETED) != f) {
                    340:                printf("%d: Inappropriate message\n", mesg);
                    341:                return(-1);
                    342:        }
                    343:        return(0);
                    344: }
                    345: 
                    346: /*
                    347:  * Scan out the list of string arguments, shell style
                    348:  * for a RAWLIST.
                    349:  */
                    350: 
                    351: getrawlist(line, argv, argc)
                    352:        char line[];
                    353:        char **argv;
                    354:        int  argc;
                    355: {
                    356:        register char **ap, *cp, *cp2;
                    357:        char linebuf[BUFSIZ], quotec;
                    358:        register char **last;
                    359: 
                    360:        ap = argv;
                    361:        cp = line;
                    362:        last = argv + argc - 1;
                    363:        while (*cp != '\0') {
                    364:                while (any(*cp, " \t"))
                    365:                        cp++;
                    366:                cp2 = linebuf;
                    367:                quotec = 0;
                    368:                if (any(*cp, "'\""))
                    369:                        quotec = *cp++;
                    370:                if (quotec == 0)
                    371:                        while (*cp != '\0' && !any(*cp, " \t"))
                    372:                                *cp2++ = *cp++;
                    373:                else {
                    374:                        while (*cp != '\0' && *cp != quotec)
                    375:                                *cp2++ = *cp++;
                    376:                        if (*cp != '\0')
                    377:                                cp++;
                    378:                }
                    379:                *cp2 = '\0';
                    380:                if (cp2 == linebuf)
                    381:                        break;
                    382:                if (ap >= last) {
                    383:                        printf("Too many elements in the list; excess discarded\n");
                    384:                        break;
                    385:                }
                    386:                *ap++ = savestr(linebuf);
                    387:        }
                    388:        *ap = NOSTR;
                    389:        return(ap-argv);
                    390: }
                    391: 
                    392: /*
                    393:  * scan out a single lexical item and return its token number,
                    394:  * updating the string pointer passed **p.  Also, store the value
                    395:  * of the number or string scanned in lexnumber or lexstring as
                    396:  * appropriate.  In any event, store the scanned `thing' in lexstring.
                    397:  */
                    398: 
                    399: struct lex {
                    400:        char    l_char;
                    401:        char    l_token;
                    402: } singles[] = {
                    403:        '$',    TDOLLAR,
                    404:        '.',    TDOT,
                    405:        '^',    TUP,
                    406:        '*',    TSTAR,
                    407:        '-',    TDASH,
                    408:        '+',    TPLUS,
                    409:        '(',    TOPEN,
                    410:        ')',    TCLOSE,
                    411:        0,      0
                    412: };
                    413: 
                    414: scan(sp)
                    415:        char **sp;
                    416: {
                    417:        register char *cp, *cp2;
                    418:        register int c;
                    419:        register struct lex *lp;
                    420:        int quotec;
                    421: 
                    422:        if (regretp >= 0) {
                    423:                strcpy(lexstring, stringstack[regretp]);
                    424:                lexnumber = numberstack[regretp];
                    425:                return(regretstack[regretp--]);
                    426:        }
                    427:        cp = *sp;
                    428:        cp2 = lexstring;
                    429:        c = *cp++;
                    430: 
                    431:        /*
                    432:         * strip away leading white space.
                    433:         */
                    434: 
                    435:        while (any(c, " \t"))
                    436:                c = *cp++;
                    437: 
                    438:        /*
                    439:         * If no characters remain, we are at end of line,
                    440:         * so report that.
                    441:         */
                    442: 
                    443:        if (c == '\0') {
                    444:                *sp = --cp;
                    445:                return(TEOL);
                    446:        }
                    447: 
                    448:        /*
                    449:         * If the leading character is a digit, scan
                    450:         * the number and convert it on the fly.
                    451:         * Return TNUMBER when done.
                    452:         */
                    453: 
                    454:        if (isdigit(c)) {
                    455:                lexnumber = 0;
                    456:                while (isdigit(c)) {
                    457:                        lexnumber = lexnumber*10 + c - '0';
                    458:                        *cp2++ = c;
                    459:                        c = *cp++;
                    460:                }
                    461:                *cp2 = '\0';
                    462:                *sp = --cp;
                    463:                return(TNUMBER);
                    464:        }
                    465: 
                    466:        /*
                    467:         * Check for single character tokens; return such
                    468:         * if found.
                    469:         */
                    470: 
                    471:        for (lp = &singles[0]; lp->l_char != 0; lp++)
                    472:                if (c == lp->l_char) {
                    473:                        lexstring[0] = c;
                    474:                        lexstring[1] = '\0';
                    475:                        *sp = cp;
                    476:                        return(lp->l_token);
                    477:                }
                    478: 
                    479:        /*
                    480:         * We've got a string!  Copy all the characters
                    481:         * of the string into lexstring, until we see
                    482:         * a null, space, or tab.
                    483:         * If the lead character is a " or ', save it
                    484:         * and scan until you get another.
                    485:         */
                    486: 
                    487:        quotec = 0;
                    488:        if (any(c, "'\"")) {
                    489:                quotec = c;
                    490:                c = *cp++;
                    491:        }
                    492:        while (c != '\0') {
                    493:                if (c == quotec)
                    494:                        break;
                    495:                if (quotec == 0 && any(c, " \t"))
                    496:                        break;
                    497:                if (cp2 - lexstring < STRINGLEN-1)
                    498:                        *cp2++ = c;
                    499:                c = *cp++;
                    500:        }
                    501:        if (quotec && c == 0)
                    502:                fprintf(stderr, "Missing %c\n", quotec);
                    503:        *sp = --cp;
                    504:        *cp2 = '\0';
                    505:        return(TSTRING);
                    506: }
                    507: 
                    508: /*
                    509:  * Unscan the named token by pushing it onto the regret stack.
                    510:  */
                    511: 
                    512: regret(token)
                    513: {
                    514:        if (++regretp >= REGDEP)
                    515:                panic("Too many regrets");
                    516:        regretstack[regretp] = token;
                    517:        lexstring[STRINGLEN-1] = '\0';
                    518:        stringstack[regretp] = savestr(lexstring);
                    519:        numberstack[regretp] = lexnumber;
                    520: }
                    521: 
                    522: /*
                    523:  * Reset all the scanner global variables.
                    524:  */
                    525: 
                    526: scaninit()
                    527: {
                    528:        regretp = -1;
                    529: }
                    530: 
                    531: /*
                    532:  * Find the first message whose flags & m == f  and return
                    533:  * its message number.
                    534:  */
                    535: 
                    536: first(f, m)
                    537: {
                    538:        register int mesg;
                    539:        register struct message *mp;
                    540: 
                    541:        mesg = dot - &message[0] + 1;
                    542:        f &= MDELETED;
                    543:        m &= MDELETED;
                    544:        for (mp = dot; mp < &message[msgCount]; mp++) {
                    545:                if ((mp->m_flag & m) == f)
                    546:                        return(mesg);
                    547:                mesg++;
                    548:        }
                    549:        mesg = dot - &message[0];
                    550:        for (mp = dot-1; mp >= &message[0]; mp--) {
                    551:                if ((mp->m_flag & m) == f)
                    552:                        return(mesg);
                    553:                mesg--;
                    554:        }
                    555:        return(NULL);
                    556: }
                    557: 
                    558: /*
                    559:  * See if the passed name sent the passed message number.  Return true
                    560:  * if so.
                    561:  */
                    562: 
                    563: sender(str, mesg)
                    564:        char *str;
                    565: {
                    566:        register struct message *mp;
                    567:        register char *cp, *cp2, *backup;
                    568: 
                    569:        mp = &message[mesg-1];
                    570:        backup = cp2 = nameof(mp, 0);
                    571:        cp = str;
                    572:        while (*cp2) {
                    573:                if (*cp == 0)
                    574:                        return(1);
                    575:                if (raise(*cp++) != raise(*cp2++)) {
                    576:                        cp2 = ++backup;
                    577:                        cp = str;
                    578:                }
                    579:        }
                    580:        return(*cp == 0);
                    581: }
                    582: 
                    583: /*
                    584:  * See if the given string matches inside the subject field of the
                    585:  * given message.  For the purpose of the scan, we ignore case differences.
                    586:  * If it does, return true.  The string search argument is assumed to
                    587:  * have the form "/search-string."  If it is of the form "/," we use the
                    588:  * previous search string.
                    589:  */
                    590: 
                    591: char lastscan[128];
                    592: 
                    593: matchsubj(str, mesg)
                    594:        char *str;
                    595: {
                    596:        register struct message *mp;
                    597:        register char *cp, *cp2, *backup;
                    598: 
                    599:        str++;
                    600:        if (strlen(str) == 0)
                    601:                str = lastscan;
                    602:        else
                    603:                strcpy(lastscan, str);
                    604:        mp = &message[mesg-1];
                    605:        
                    606:        /*
                    607:         * Now look, ignoring case, for the word in the string.
                    608:         */
                    609: 
                    610:        cp = str;
                    611:        cp2 = hfield("subject", mp);
                    612:        if (cp2 == NOSTR)
                    613:                return(0);
                    614:        backup = cp2;
                    615:        while (*cp2) {
                    616:                if (*cp == 0)
                    617:                        return(1);
                    618:                if (raise(*cp++) != raise(*cp2++)) {
                    619:                        cp2 = ++backup;
                    620:                        cp = str;
                    621:                }
                    622:        }
                    623:        return(*cp == 0);
                    624: }
                    625: 
                    626: /*
                    627:  * Mark the named message by setting its mark bit.
                    628:  */
                    629: 
                    630: mark(mesg)
                    631: {
                    632:        register int i;
                    633: 
                    634:        i = mesg;
                    635:        if (i < 1 || i > msgCount)
                    636:                panic("Bad message number to mark");
                    637:        message[i-1].m_flag |= MMARK;
                    638: }
                    639: 
                    640: /*
                    641:  * Unmark the named message.
                    642:  */
                    643: 
                    644: unmark(mesg)
                    645: {
                    646:        register int i;
                    647: 
                    648:        i = mesg;
                    649:        if (i < 1 || i > msgCount)
                    650:                panic("Bad message number to unmark");
                    651:        message[i-1].m_flag &= ~MMARK;
                    652: }
                    653: 
                    654: /*
                    655:  * Return the message number corresponding to the passed meta character.
                    656:  */
                    657: 
                    658: metamess(meta, f)
                    659: {
                    660:        register int c, m;
                    661:        register struct message *mp;
                    662: 
                    663:        c = meta;
                    664:        switch (c) {
                    665:        case '^':
                    666:                /*
                    667:                 * First 'good' message left.
                    668:                 */
                    669:                for (mp = &message[0]; mp < &message[msgCount]; mp++)
                    670:                        if ((mp->m_flag & MDELETED) == f)
                    671:                                return(mp - &message[0] + 1);
                    672:                printf("No applicable messages\n");
                    673:                return(-1);
                    674: 
                    675:        case '$':
                    676:                /*
                    677:                 * Last 'good message left.
                    678:                 */
                    679:                for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
                    680:                        if ((mp->m_flag & MDELETED) == f)
                    681:                                return(mp - &message[0] + 1);
                    682:                printf("No applicable messages\n");
                    683:                return(-1);
                    684: 
                    685:        case '.':
                    686:                /* 
                    687:                 * Current message.
                    688:                 */
                    689:                m = dot - &message[0] + 1;
                    690:                if ((dot->m_flag & MDELETED) != f) {
                    691:                        printf("%d: Inappropriate message\n", m);
                    692:                        return(-1);
                    693:                }
                    694:                return(m);
                    695: 
                    696:        default:
                    697:                printf("Unknown metachar (%c)\n", c);
                    698:                return(-1);
                    699:        }
                    700: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.