Annotation of researchv10no/lbin/Mail/list.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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