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

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

unix.superglobalmegacorp.com

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