Annotation of 43BSDReno/usr.bin/mail/aux.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted provided
                      6:  * that: (1) source distributions retain this entire copyright notice and
                      7:  * comment, and (2) distributions including binaries display the following
                      8:  * acknowledgement:  ``This product includes software developed by the
                      9:  * University of California, Berkeley and its contributors'' in the
                     10:  * documentation or other materials provided with the distribution and in
                     11:  * all advertising materials mentioning features or use of this software.
                     12:  * Neither the name of the University nor the names of its contributors may
                     13:  * be used to endorse or promote products derived from this software without
                     14:  * specific prior written permission.
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     18:  */
                     19: 
                     20: #ifndef lint
                     21: static char sccsid[] = "@(#)aux.c      5.20 (Berkeley) 6/25/90";
                     22: #endif /* not lint */
                     23: 
                     24: #include "rcv.h"
                     25: #include <sys/stat.h>
                     26: #include <sys/time.h>
                     27: 
                     28: /*
                     29:  * Mail -- a mail program
                     30:  *
                     31:  * Auxiliary functions.
                     32:  */
                     33: 
                     34: /*
                     35:  * Return a pointer to a dynamic copy of the argument.
                     36:  */
                     37: char *
                     38: savestr(str)
                     39:        char *str;
                     40: {
                     41:        char *new;
                     42:        int size = strlen(str) + 1;
                     43: 
                     44:        if ((new = salloc(size)) != NOSTR)
                     45:                bcopy(str, new, size);
                     46:        return new;
                     47: }
                     48: 
                     49: /*
                     50:  * Announce a fatal error and die.
                     51:  */
                     52: 
                     53: /*VARARGS1*/
                     54: panic(fmt, a, b)
                     55:        char *fmt;
                     56: {
                     57:        fprintf(stderr, "panic: ");
                     58:        fprintf(stderr, fmt, a, b);
                     59:        putc('\n', stderr);
                     60:        fflush(stdout);
                     61:        abort();
                     62: }
                     63: 
                     64: /*
                     65:  * Touch the named message by setting its MTOUCH flag.
                     66:  * Touched messages have the effect of not being sent
                     67:  * back to the system mailbox on exit.
                     68:  */
                     69: touch(mp)
                     70:        register struct message *mp;
                     71: {
                     72: 
                     73:        mp->m_flag |= MTOUCH;
                     74:        if ((mp->m_flag & MREAD) == 0)
                     75:                mp->m_flag |= MREAD|MSTATUS;
                     76: }
                     77: 
                     78: /*
                     79:  * Test to see if the passed file name is a directory.
                     80:  * Return true if it is.
                     81:  */
                     82: isdir(name)
                     83:        char name[];
                     84: {
                     85:        struct stat sbuf;
                     86: 
                     87:        if (stat(name, &sbuf) < 0)
                     88:                return(0);
                     89:        return((sbuf.st_mode & S_IFMT) == S_IFDIR);
                     90: }
                     91: 
                     92: /*
                     93:  * Count the number of arguments in the given string raw list.
                     94:  */
                     95: argcount(argv)
                     96:        char **argv;
                     97: {
                     98:        register char **ap;
                     99: 
                    100:        for (ap = argv; *ap++ != NOSTR;)
                    101:                ;       
                    102:        return ap - argv - 1;
                    103: }
                    104: 
                    105: /*
                    106:  * Return the desired header line from the passed message
                    107:  * pointer (or NOSTR if the desired header field is not available).
                    108:  */
                    109: char *
                    110: hfield(field, mp)
                    111:        char field[];
                    112:        struct message *mp;
                    113: {
                    114:        register FILE *ibuf;
                    115:        char linebuf[LINESIZE];
                    116:        register int lc;
                    117:        register char *hfield;
                    118:        char *colon;
                    119: 
                    120:        ibuf = setinput(mp);
                    121:        if ((lc = mp->m_lines - 1) < 0)
                    122:                return NOSTR;
                    123:        if (readline(ibuf, linebuf, LINESIZE) < 0)
                    124:                return NOSTR;
                    125:        while (lc > 0) {
                    126:                if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
                    127:                        return NOSTR;
                    128:                if (hfield = ishfield(linebuf, colon, field))
                    129:                        return savestr(hfield);
                    130:        }
                    131:        return NOSTR;
                    132: }
                    133: 
                    134: /*
                    135:  * Return the next header field found in the given message.
                    136:  * Return >= 0 if something found, < 0 elsewise.
                    137:  * "colon" is set to point to the colon in the header.
                    138:  * Must deal with \ continuations & other such fraud.
                    139:  */
                    140: gethfield(f, linebuf, rem, colon)
                    141:        register FILE *f;
                    142:        char linebuf[];
                    143:        register int rem;
                    144:        char **colon;
                    145: {
                    146:        char line2[LINESIZE];
                    147:        register char *cp, *cp2;
                    148:        register int c;
                    149: 
                    150:        for (;;) {
                    151:                if (--rem < 0)
                    152:                        return -1;
                    153:                if ((c = readline(f, linebuf, LINESIZE)) <= 0)
                    154:                        return -1;
                    155:                for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
                    156:                     cp++)
                    157:                        ;
                    158:                if (*cp != ':' || cp == linebuf)
                    159:                        continue;
                    160:                /*
                    161:                 * I guess we got a headline.
                    162:                 * Handle wraparounding
                    163:                 */
                    164:                *colon = cp;
                    165:                cp = linebuf + c;
                    166:                for (;;) {
                    167:                        while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
                    168:                                ;
                    169:                        cp++;
                    170:                        if (rem <= 0)
                    171:                                break;
                    172:                        ungetc(c = getc(f), f);
                    173:                        if (c != ' ' && c != '\t')
                    174:                                break;
                    175:                        if ((c = readline(f, line2, LINESIZE)) < 0)
                    176:                                break;
                    177:                        rem--;
                    178:                        for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
                    179:                                ;
                    180:                        c -= cp2 - line2;
                    181:                        if (cp + c >= linebuf + LINESIZE - 2)
                    182:                                break;
                    183:                        *cp++ = ' ';
                    184:                        bcopy(cp2, cp, c);
                    185:                        cp += c;
                    186:                }
                    187:                *cp = 0;
                    188:                return rem;
                    189:        }
                    190:        /* NOTREACHED */
                    191: }
                    192: 
                    193: /*
                    194:  * Check whether the passed line is a header line of
                    195:  * the desired breed.  Return the field body, or 0.
                    196:  */
                    197: 
                    198: char*
                    199: ishfield(linebuf, colon, field)
                    200:        char linebuf[], field[];
                    201:        char *colon;
                    202: {
                    203:        register char *cp = colon;
                    204: 
                    205:        *cp = 0;
                    206:        if (strcasecmp(linebuf, field) != 0) {
                    207:                *cp = ':';
                    208:                return 0;
                    209:        }
                    210:        *cp = ':';
                    211:        for (cp++; *cp == ' ' || *cp == '\t'; cp++)
                    212:                ;
                    213:        return cp;
                    214: }
                    215: 
                    216: /*
                    217:  * Copy a string, lowercasing it as we go.
                    218:  */
                    219: istrcpy(dest, src)
                    220:        register char *dest, *src;
                    221: {
                    222: 
                    223:        do {
                    224:                if (isupper(*src))
                    225:                        *dest++ = tolower(*src);
                    226:                else
                    227:                        *dest++ = *src;
                    228:        } while (*src++ != 0);
                    229: }
                    230: 
                    231: /*
                    232:  * The following code deals with input stacking to do source
                    233:  * commands.  All but the current file pointer are saved on
                    234:  * the stack.
                    235:  */
                    236: 
                    237: static int     ssp;                    /* Top of file stack */
                    238: struct sstack {
                    239:        FILE    *s_file;                /* File we were in. */
                    240:        int     s_cond;                 /* Saved state of conditionals */
                    241:        int     s_loading;              /* Loading .mailrc, etc. */
                    242: } sstack[NOFILE];
                    243: 
                    244: /*
                    245:  * Pushdown current input file and switch to a new one.
                    246:  * Set the global flag "sourcing" so that others will realize
                    247:  * that they are no longer reading from a tty (in all probability).
                    248:  */
                    249: source(arglist)
                    250:        char **arglist;
                    251: {
                    252:        FILE *fi;
                    253:        char *cp;
                    254: 
                    255:        if ((cp = expand(*arglist)) == NOSTR)
                    256:                return(1);
                    257:        if ((fi = Fopen(cp, "r")) == NULL) {
                    258:                perror(cp);
                    259:                return(1);
                    260:        }
                    261:        if (ssp >= NOFILE - 1) {
                    262:                printf("Too much \"sourcing\" going on.\n");
                    263:                Fclose(fi);
                    264:                return(1);
                    265:        }
                    266:        sstack[ssp].s_file = input;
                    267:        sstack[ssp].s_cond = cond;
                    268:        sstack[ssp].s_loading = loading;
                    269:        ssp++;
                    270:        loading = 0;
                    271:        cond = CANY;
                    272:        input = fi;
                    273:        sourcing++;
                    274:        return(0);
                    275: }
                    276: 
                    277: /*
                    278:  * Pop the current input back to the previous level.
                    279:  * Update the "sourcing" flag as appropriate.
                    280:  */
                    281: unstack()
                    282: {
                    283:        if (ssp <= 0) {
                    284:                printf("\"Source\" stack over-pop.\n");
                    285:                sourcing = 0;
                    286:                return(1);
                    287:        }
                    288:        Fclose(input);
                    289:        if (cond != CANY)
                    290:                printf("Unmatched \"if\"\n");
                    291:        ssp--;
                    292:        cond = sstack[ssp].s_cond;
                    293:        loading = sstack[ssp].s_loading;
                    294:        input = sstack[ssp].s_file;
                    295:        if (ssp == 0)
                    296:                sourcing = loading;
                    297:        return(0);
                    298: }
                    299: 
                    300: /*
                    301:  * Touch the indicated file.
                    302:  * This is nifty for the shell.
                    303:  */
                    304: alter(name)
                    305:        char *name;
                    306: {
                    307:        struct stat sb;
                    308:        struct timeval tv[2];
                    309:        time_t time();
                    310: 
                    311:        if (stat(name, &sb))
                    312:                return;
                    313:        tv[0].tv_sec = time((time_t *)0) + 1;
                    314:        tv[1].tv_sec = sb.st_mtime;
                    315:        tv[0].tv_usec = tv[1].tv_usec = 0;
                    316:        (void)utimes(name, tv);
                    317: }
                    318: 
                    319: /*
                    320:  * Examine the passed line buffer and
                    321:  * return true if it is all blanks and tabs.
                    322:  */
                    323: blankline(linebuf)
                    324:        char linebuf[];
                    325: {
                    326:        register char *cp;
                    327: 
                    328:        for (cp = linebuf; *cp; cp++)
                    329:                if (*cp != ' ' && *cp != '\t')
                    330:                        return(0);
                    331:        return(1);
                    332: }
                    333: 
                    334: /*
                    335:  * Get sender's name from this message.  If the message has
                    336:  * a bunch of arpanet stuff in it, we may have to skin the name
                    337:  * before returning it.
                    338:  */
                    339: char *
                    340: nameof(mp, reptype)
                    341:        register struct message *mp;
                    342: {
                    343:        register char *cp, *cp2;
                    344: 
                    345:        cp = skin(name1(mp, reptype));
                    346:        if (reptype != 0 || charcount(cp, '!') < 2)
                    347:                return(cp);
                    348:        cp2 = rindex(cp, '!');
                    349:        cp2--;
                    350:        while (cp2 > cp && *cp2 != '!')
                    351:                cp2--;
                    352:        if (*cp2 == '!')
                    353:                return(cp2 + 1);
                    354:        return(cp);
                    355: }
                    356: 
                    357: /*
                    358:  * Start of a "comment".
                    359:  * Ignore it.
                    360:  */
                    361: char *
                    362: skip_comment(cp)
                    363:        register char *cp;
                    364: {
                    365:        register nesting = 1;
                    366: 
                    367:        for (; nesting > 0 && *cp; cp++) {
                    368:                switch (*cp) {
                    369:                case '\\':
                    370:                        if (cp[1])
                    371:                                cp++;
                    372:                        break;
                    373:                case '(':
                    374:                        nesting++;
                    375:                        break;
                    376:                case ')':
                    377:                        nesting--;
                    378:                        break;
                    379:                }
                    380:        }
                    381:        return cp;
                    382: }
                    383: 
                    384: /*
                    385:  * Skin an arpa net address according to the RFC 822 interpretation
                    386:  * of "host-phrase."
                    387:  */
                    388: char *
                    389: skin(name)
                    390:        char *name;
                    391: {
                    392:        register int c;
                    393:        register char *cp, *cp2;
                    394:        char *bufend;
                    395:        int gotlt, lastsp;
                    396:        char nbuf[BUFSIZ];
                    397: 
                    398:        if (name == NOSTR)
                    399:                return(NOSTR);
                    400:        if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
                    401:            && index(name, ' ') == NOSTR)
                    402:                return(name);
                    403:        gotlt = 0;
                    404:        lastsp = 0;
                    405:        bufend = nbuf;
                    406:        for (cp = name, cp2 = bufend; c = *cp++; ) {
                    407:                switch (c) {
                    408:                case '(':
                    409:                        cp = skip_comment(cp);
                    410:                        lastsp = 0;
                    411:                        break;
                    412: 
                    413:                case '"':
                    414:                        /*
                    415:                         * Start of a "quoted-string".
                    416:                         * Copy it in its entirety.
                    417:                         */
                    418:                        while (c = *cp) {
                    419:                                cp++;
                    420:                                if (c == '"')
                    421:                                        break;
                    422:                                if (c != '\\')
                    423:                                        *cp2++ = c;
                    424:                                else if (c = *cp) {
                    425:                                        *cp2++ = c;
                    426:                                        cp++;
                    427:                                }
                    428:                        }
                    429:                        lastsp = 0;
                    430:                        break;
                    431: 
                    432:                case ' ':
                    433:                        if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
                    434:                                cp += 3, *cp2++ = '@';
                    435:                        else
                    436:                        if (cp[0] == '@' && cp[1] == ' ')
                    437:                                cp += 2, *cp2++ = '@';
                    438:                        else
                    439:                                lastsp = 1;
                    440:                        break;
                    441: 
                    442:                case '<':
                    443:                        cp2 = bufend;
                    444:                        gotlt++;
                    445:                        lastsp = 0;
                    446:                        break;
                    447: 
                    448:                case '>':
                    449:                        if (gotlt) {
                    450:                                gotlt = 0;
                    451:                                while ((c = *cp) && c != ',') {
                    452:                                        cp++;
                    453:                                        if (c == '(')
                    454:                                                cp = skip_comment(cp);
                    455:                                        else if (c == '"')
                    456:                                                while (c = *cp) {
                    457:                                                        cp++;
                    458:                                                        if (c == '"')
                    459:                                                                break;
                    460:                                                        if (c == '\\' && *cp)
                    461:                                                                cp++;
                    462:                                                }
                    463:                                }
                    464:                                lastsp = 0;
                    465:                                break;
                    466:                        }
                    467:                        /* Fall into . . . */
                    468: 
                    469:                default:
                    470:                        if (lastsp) {
                    471:                                lastsp = 0;
                    472:                                *cp2++ = ' ';
                    473:                        }
                    474:                        *cp2++ = c;
                    475:                        if (c == ',' && !gotlt) {
                    476:                                *cp2++ = ' ';
                    477:                                for (; *cp == ' '; cp++)
                    478:                                        ;
                    479:                                lastsp = 0;
                    480:                                bufend = cp2;
                    481:                        }
                    482:                }
                    483:        }
                    484:        *cp2 = 0;
                    485: 
                    486:        return(savestr(nbuf));
                    487: }
                    488: 
                    489: /*
                    490:  * Fetch the sender's name from the passed message.
                    491:  * Reptype can be
                    492:  *     0 -- get sender's name for display purposes
                    493:  *     1 -- get sender's name for reply
                    494:  *     2 -- get sender's name for Reply
                    495:  */
                    496: char *
                    497: name1(mp, reptype)
                    498:        register struct message *mp;
                    499: {
                    500:        char namebuf[LINESIZE];
                    501:        char linebuf[LINESIZE];
                    502:        register char *cp, *cp2;
                    503:        register FILE *ibuf;
                    504:        int first = 1;
                    505: 
                    506:        if ((cp = hfield("from", mp)) != NOSTR)
                    507:                return cp;
                    508:        if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
                    509:                return cp;
                    510:        ibuf = setinput(mp);
                    511:        namebuf[0] = 0;
                    512:        if (readline(ibuf, linebuf, LINESIZE) < 0)
                    513:                return(savestr(namebuf));
                    514: newname:
                    515:        for (cp = linebuf; *cp && *cp != ' '; cp++)
                    516:                ;
                    517:        for (; *cp == ' ' || *cp == '\t'; cp++)
                    518:                ;
                    519:        for (cp2 = &namebuf[strlen(namebuf)];
                    520:             *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
                    521:                *cp2++ = *cp++;
                    522:        *cp2 = '\0';
                    523:        if (readline(ibuf, linebuf, LINESIZE) < 0)
                    524:                return(savestr(namebuf));
                    525:        if ((cp = index(linebuf, 'F')) == NULL)
                    526:                return(savestr(namebuf));
                    527:        if (strncmp(cp, "From", 4) != 0)
                    528:                return(savestr(namebuf));
                    529:        while ((cp = index(cp, 'r')) != NULL) {
                    530:                if (strncmp(cp, "remote", 6) == 0) {
                    531:                        if ((cp = index(cp, 'f')) == NULL)
                    532:                                break;
                    533:                        if (strncmp(cp, "from", 4) != 0)
                    534:                                break;
                    535:                        if ((cp = index(cp, ' ')) == NULL)
                    536:                                break;
                    537:                        cp++;
                    538:                        if (first) {
                    539:                                strcpy(namebuf, cp);
                    540:                                first = 0;
                    541:                        } else
                    542:                                strcpy(rindex(namebuf, '!')+1, cp);
                    543:                        strcat(namebuf, "!");
                    544:                        goto newname;
                    545:                }
                    546:                cp++;
                    547:        }
                    548:        return(savestr(namebuf));
                    549: }
                    550: 
                    551: /*
                    552:  * Count the occurances of c in str
                    553:  */
                    554: charcount(str, c)
                    555:        char *str;
                    556: {
                    557:        register char *cp;
                    558:        register int i;
                    559: 
                    560:        for (i = 0, cp = str; *cp; cp++)
                    561:                if (*cp == c)
                    562:                        i++;
                    563:        return(i);
                    564: }
                    565: 
                    566: /*
                    567:  * Are any of the characters in the two strings the same?
                    568:  */
                    569: anyof(s1, s2)
                    570:        register char *s1, *s2;
                    571: {
                    572: 
                    573:        while (*s1)
                    574:                if (index(s2, *s1++))
                    575:                        return 1;
                    576:        return 0;
                    577: }
                    578: 
                    579: /*
                    580:  * Convert c to upper case
                    581:  */
                    582: raise(c)
                    583:        register c;
                    584: {
                    585: 
                    586:        if (islower(c))
                    587:                return toupper(c);
                    588:        return c;
                    589: }
                    590: 
                    591: /*
                    592:  * Copy s1 to s2, return pointer to null in s2.
                    593:  */
                    594: char *
                    595: copy(s1, s2)
                    596:        register char *s1, *s2;
                    597: {
                    598: 
                    599:        while (*s2++ = *s1++)
                    600:                ;
                    601:        return s2 - 1;
                    602: }
                    603: 
                    604: /*
                    605:  * See if the given header field is supposed to be ignored.
                    606:  */
                    607: isign(field, ignore)
                    608:        char *field;
                    609:        struct ignoretab ignore[2];
                    610: {
                    611:        char realfld[BUFSIZ];
                    612: 
                    613:        if (ignore == ignoreall)
                    614:                return 1;
                    615:        /*
                    616:         * Lower-case the string, so that "Status" and "status"
                    617:         * will hash to the same place.
                    618:         */
                    619:        istrcpy(realfld, field);
                    620:        if (ignore[1].i_count > 0)
                    621:                return (!member(realfld, ignore + 1));
                    622:        else
                    623:                return (member(realfld, ignore));
                    624: }
                    625: 
                    626: member(realfield, table)
                    627:        register char *realfield;
                    628:        struct ignoretab *table;
                    629: {
                    630:        register struct ignore *igp;
                    631: 
                    632:        for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
                    633:                if (*igp->i_field == *realfield &&
                    634:                    equal(igp->i_field, realfield))
                    635:                        return (1);
                    636:        return (0);
                    637: }

unix.superglobalmegacorp.com

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