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

Annotation of src/usr.bin/mail/aux.c, Revision 1.20

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