[BACK]Return to util.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mail

Annotation of src/usr.bin/mail/util.c, Revision 1.1

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