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

unix.superglobalmegacorp.com

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