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

unix.superglobalmegacorp.com

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