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

Annotation of src/usr.bin/mail/fio.c, Revision 1.3

1.3     ! millert     1: /*     $OpenBSD: fio.c,v 1.2 1996/06/11 12:53:39 deraadt Exp $ */
1.2       deraadt     2: /*     $NetBSD: fio.c,v 1.5 1996/06/08 19:48:22 christos Exp $ */
                      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
                     39: static char sccsid[] = "@(#)fio.c      8.1 (Berkeley) 6/6/93";
                     40: #else
1.3     ! millert    41: static char rcsid[] = "$OpenBSD: fio.c,v 1.2 1996/06/11 12:53:39 deraadt Exp $";
1.2       deraadt    42: #endif
1.1       deraadt    43: #endif /* not lint */
                     44:
                     45: #include "rcv.h"
                     46: #include <sys/file.h>
                     47: #include <sys/wait.h>
                     48:
                     49: #include <unistd.h>
                     50: #include <paths.h>
                     51: #include <errno.h>
                     52: #include "extern.h"
                     53:
                     54: /*
                     55:  * Mail -- a mail program
                     56:  *
                     57:  * File I/O.
                     58:  */
                     59:
                     60: /*
                     61:  * Set up the input pointers while copying the mail file into /tmp.
                     62:  */
                     63: void
                     64: setptr(ibuf)
                     65:        register FILE *ibuf;
                     66: {
                     67:        extern char *tmpdir;
                     68:        register int c, count;
                     69:        register char *cp, *cp2;
                     70:        struct message this;
                     71:        FILE *mestmp;
                     72:        off_t offset;
                     73:        int maybe, inhead;
                     74:        char linebuf[LINESIZE];
                     75:
                     76:        /* Get temporary file. */
                     77:        (void)sprintf(linebuf, "%s/mail.XXXXXX", tmpdir);
                     78:        if ((c = mkstemp(linebuf)) == -1 ||
                     79:            (mestmp = Fdopen(c, "r+")) == NULL) {
                     80:                (void)fprintf(stderr, "mail: can't open %s\n", linebuf);
                     81:                exit(1);
                     82:        }
                     83:        (void)unlink(linebuf);
                     84:
                     85:        msgCount = 0;
                     86:        maybe = 1;
                     87:        inhead = 0;
                     88:        offset = 0;
                     89:        this.m_flag = MUSED|MNEW;
                     90:        this.m_size = 0;
                     91:        this.m_lines = 0;
                     92:        this.m_block = 0;
                     93:        this.m_offset = 0;
                     94:        for (;;) {
                     95:                if (fgets(linebuf, LINESIZE, ibuf) == NULL) {
                     96:                        if (append(&this, mestmp)) {
                     97:                                perror("temporary file");
                     98:                                exit(1);
                     99:                        }
                    100:                        makemessage(mestmp);
                    101:                        return;
                    102:                }
                    103:                count = strlen(linebuf);
                    104:                (void) fwrite(linebuf, sizeof *linebuf, count, otf);
                    105:                if (ferror(otf)) {
                    106:                        perror("/tmp");
                    107:                        exit(1);
                    108:                }
                    109:                linebuf[count - 1] = 0;
                    110:                if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
                    111:                        msgCount++;
                    112:                        if (append(&this, mestmp)) {
                    113:                                perror("temporary file");
                    114:                                exit(1);
                    115:                        }
                    116:                        this.m_flag = MUSED|MNEW;
                    117:                        this.m_size = 0;
                    118:                        this.m_lines = 0;
                    119:                        this.m_block = blockof(offset);
                    120:                        this.m_offset = offsetof(offset);
                    121:                        inhead = 1;
                    122:                } else if (linebuf[0] == 0) {
                    123:                        inhead = 0;
                    124:                } else if (inhead) {
                    125:                        for (cp = linebuf, cp2 = "status";; cp++) {
                    126:                                if ((c = *cp2++) == 0) {
                    127:                                        while (isspace(*cp++))
                    128:                                                ;
                    129:                                        if (cp[-1] != ':')
                    130:                                                break;
1.2       deraadt   131:                                        while ((c = *cp++) != '\0')
1.1       deraadt   132:                                                if (c == 'R')
                    133:                                                        this.m_flag |= MREAD;
                    134:                                                else if (c == 'O')
                    135:                                                        this.m_flag &= ~MNEW;
                    136:                                        inhead = 0;
                    137:                                        break;
                    138:                                }
                    139:                                if (*cp != c && *cp != toupper(c))
                    140:                                        break;
                    141:                        }
                    142:                }
                    143:                offset += count;
                    144:                this.m_size += count;
                    145:                this.m_lines++;
                    146:                maybe = linebuf[0] == 0;
                    147:        }
                    148: }
                    149:
                    150: /*
                    151:  * Drop the passed line onto the passed output buffer.
                    152:  * If a write error occurs, return -1, else the count of
                    153:  * characters written, including the newline.
                    154:  */
                    155: int
                    156: putline(obuf, linebuf)
                    157:        FILE *obuf;
                    158:        char *linebuf;
                    159: {
                    160:        register int c;
                    161:
                    162:        c = strlen(linebuf);
                    163:        (void) fwrite(linebuf, sizeof *linebuf, c, obuf);
                    164:        (void) putc('\n', obuf);
                    165:        if (ferror(obuf))
                    166:                return (-1);
                    167:        return (c + 1);
                    168: }
                    169:
                    170: /*
                    171:  * Read up a line from the specified input into the line
                    172:  * buffer.  Return the number of characters read.  Do not
                    173:  * include the newline at the end.
                    174:  */
                    175: int
                    176: readline(ibuf, linebuf, linesize)
                    177:        FILE *ibuf;
                    178:        char *linebuf;
                    179:        int linesize;
                    180: {
                    181:        register int n;
                    182:
                    183:        clearerr(ibuf);
                    184:        if (fgets(linebuf, linesize, ibuf) == NULL)
                    185:                return -1;
                    186:        n = strlen(linebuf);
                    187:        if (n > 0 && linebuf[n - 1] == '\n')
                    188:                linebuf[--n] = '\0';
                    189:        return n;
                    190: }
                    191:
                    192: /*
                    193:  * Return a file buffer all ready to read up the
                    194:  * passed message pointer.
                    195:  */
                    196: FILE *
                    197: setinput(mp)
                    198:        register struct message *mp;
                    199: {
                    200:
                    201:        fflush(otf);
                    202:        if (fseek(itf, (long)positionof(mp->m_block, mp->m_offset), 0) < 0) {
                    203:                perror("fseek");
                    204:                panic("temporary file seek");
                    205:        }
                    206:        return (itf);
                    207: }
                    208:
                    209: /*
                    210:  * Take the data out of the passed ghost file and toss it into
                    211:  * a dynamically allocated message structure.
                    212:  */
                    213: void
                    214: makemessage(f)
                    215:        FILE *f;
                    216: {
                    217:        register size = (msgCount + 1) * sizeof (struct message);
                    218:
                    219:        if (message != 0)
                    220:                free((char *) message);
                    221:        if ((message = (struct message *) malloc((unsigned) size)) == 0)
                    222:                panic("Insufficient memory for %d messages", msgCount);
                    223:        dot = message;
                    224:        size -= sizeof (struct message);
                    225:        fflush(f);
                    226:        (void) lseek(fileno(f), (off_t)sizeof *message, 0);
                    227:        if (read(fileno(f), (char *) message, size) != size)
                    228:                panic("Message temporary file corrupted");
                    229:        message[msgCount].m_size = 0;
                    230:        message[msgCount].m_lines = 0;
                    231:        Fclose(f);
                    232: }
                    233:
                    234: /*
                    235:  * Append the passed message descriptor onto the temp file.
                    236:  * If the write fails, return 1, else 0
                    237:  */
                    238: int
                    239: append(mp, f)
                    240:        struct message *mp;
                    241:        FILE *f;
                    242: {
                    243:        return fwrite((char *) mp, sizeof *mp, 1, f) != 1;
                    244: }
                    245:
                    246: /*
                    247:  * Delete a file, but only if the file is a plain file.
                    248:  */
                    249: int
                    250: rm(name)
                    251:        char *name;
                    252: {
                    253:        struct stat sb;
                    254:
                    255:        if (stat(name, &sb) < 0)
                    256:                return(-1);
                    257:        if (!S_ISREG(sb.st_mode)) {
                    258:                errno = EISDIR;
                    259:                return(-1);
                    260:        }
                    261:        return(unlink(name));
                    262: }
                    263:
                    264: static int sigdepth;           /* depth of holdsigs() */
1.2       deraadt   265: static sigset_t nset, oset;
1.1       deraadt   266: /*
                    267:  * Hold signals SIGHUP, SIGINT, and SIGQUIT.
                    268:  */
                    269: void
                    270: holdsigs()
                    271: {
                    272:
1.2       deraadt   273:        if (sigdepth++ == 0) {
                    274:                sigemptyset(&nset);
                    275:                sigaddset(&nset, SIGHUP);
                    276:                sigaddset(&nset, SIGINT);
                    277:                sigaddset(&nset, SIGQUIT);
                    278:                sigprocmask(SIG_BLOCK, &nset, &oset);
                    279:        }
1.1       deraadt   280: }
                    281:
                    282: /*
                    283:  * Release signals SIGHUP, SIGINT, and SIGQUIT.
                    284:  */
                    285: void
                    286: relsesigs()
                    287: {
                    288:
                    289:        if (--sigdepth == 0)
1.2       deraadt   290:                sigprocmask(SIG_SETMASK, &oset, NULL);
1.1       deraadt   291: }
                    292:
                    293: /*
                    294:  * Determine the size of the file possessed by
                    295:  * the passed buffer.
                    296:  */
                    297: off_t
                    298: fsize(iob)
                    299:        FILE *iob;
                    300: {
                    301:        struct stat sbuf;
                    302:
                    303:        if (fstat(fileno(iob), &sbuf) < 0)
                    304:                return 0;
                    305:        return sbuf.st_size;
                    306: }
                    307:
                    308: /*
                    309:  * Evaluate the string given as a new mailbox name.
                    310:  * Supported meta characters:
                    311:  *     %       for my system mail box
                    312:  *     %user   for user's system mail box
                    313:  *     #       for previous file
                    314:  *     &       invoker's mbox file
                    315:  *     +file   file in folder directory
                    316:  *     any shell meta character
                    317:  * Return the file name as a dynamic string.
                    318:  */
                    319: char *
                    320: expand(name)
                    321:        register char *name;
                    322: {
                    323:        char xname[PATHSIZE];
                    324:        char cmdbuf[PATHSIZE];          /* also used for file names */
                    325:        register int pid, l;
                    326:        register char *cp, *shell;
                    327:        int pivec[2];
                    328:        struct stat sbuf;
                    329:        extern union wait wait_status;
                    330:
                    331:        /*
                    332:         * The order of evaluation is "%" and "#" expand into constants.
                    333:         * "&" can expand into "+".  "+" can expand into shell meta characters.
                    334:         * Shell meta characters expand into constants.
                    335:         * This way, we make no recursive expansion.
                    336:         */
                    337:        switch (*name) {
                    338:        case '%':
                    339:                findmail(name[1] ? name + 1 : myname, xname);
                    340:                return savestr(xname);
                    341:        case '#':
                    342:                if (name[1] != 0)
                    343:                        break;
                    344:                if (prevfile[0] == 0) {
                    345:                        printf("No previous file\n");
                    346:                        return NOSTR;
                    347:                }
                    348:                return savestr(prevfile);
                    349:        case '&':
                    350:                if (name[1] == 0 && (name = value("MBOX")) == NOSTR)
                    351:                        name = "~/mbox";
                    352:                /* fall through */
                    353:        }
                    354:        if (name[0] == '+' && getfold(cmdbuf) >= 0) {
                    355:                sprintf(xname, "%s/%s", cmdbuf, name + 1);
                    356:                name = savestr(xname);
                    357:        }
                    358:        /* catch the most common shell meta character */
                    359:        if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) {
                    360:                sprintf(xname, "%s%s", homedir, name + 1);
                    361:                name = savestr(xname);
                    362:        }
                    363:        if (!anyof(name, "~{[*?$`'\"\\"))
                    364:                return name;
                    365:        if (pipe(pivec) < 0) {
                    366:                perror("pipe");
                    367:                return name;
                    368:        }
                    369:        sprintf(cmdbuf, "echo %s", name);
                    370:        if ((shell = value("SHELL")) == NOSTR)
                    371:                shell = _PATH_CSHELL;
                    372:        pid = start_command(shell, 0, -1, pivec[1], "-c", cmdbuf, NOSTR);
                    373:        if (pid < 0) {
                    374:                close(pivec[0]);
                    375:                close(pivec[1]);
                    376:                return NOSTR;
                    377:        }
                    378:        close(pivec[1]);
                    379:        l = read(pivec[0], xname, BUFSIZ);
                    380:        close(pivec[0]);
                    381:        if (wait_child(pid) < 0 && wait_status.w_termsig != SIGPIPE) {
                    382:                fprintf(stderr, "\"%s\": Expansion failed.\n", name);
                    383:                return NOSTR;
                    384:        }
                    385:        if (l < 0) {
                    386:                perror("read");
                    387:                return NOSTR;
                    388:        }
                    389:        if (l == 0) {
                    390:                fprintf(stderr, "\"%s\": No match.\n", name);
                    391:                return NOSTR;
                    392:        }
                    393:        if (l == BUFSIZ) {
                    394:                fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name);
                    395:                return NOSTR;
                    396:        }
                    397:        xname[l] = 0;
                    398:        for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
                    399:                ;
                    400:        cp[1] = '\0';
1.3     ! millert   401:        if (strchr(xname, ' ') && stat(xname, &sbuf) < 0) {
1.1       deraadt   402:                fprintf(stderr, "\"%s\": Ambiguous.\n", name);
                    403:                return NOSTR;
                    404:        }
                    405:        return savestr(xname);
                    406: }
                    407:
                    408: /*
                    409:  * Determine the current folder directory name.
                    410:  */
                    411: int
                    412: getfold(name)
                    413:        char *name;
                    414: {
                    415:        char *folder;
                    416:
                    417:        if ((folder = value("folder")) == NOSTR)
                    418:                return (-1);
                    419:        if (*folder == '/')
                    420:                strcpy(name, folder);
                    421:        else
                    422:                sprintf(name, "%s/%s", homedir, folder);
                    423:        return (0);
                    424: }
                    425:
                    426: /*
                    427:  * Return the name of the dead.letter file.
                    428:  */
                    429: char *
                    430: getdeadletter()
                    431: {
                    432:        register char *cp;
                    433:
                    434:        if ((cp = value("DEAD")) == NOSTR || (cp = expand(cp)) == NOSTR)
                    435:                cp = expand("~/dead.letter");
                    436:        else if (*cp != '/') {
                    437:                char buf[PATHSIZE];
                    438:
                    439:                (void) sprintf(buf, "~/%s", cp);
                    440:                cp = expand(buf);
                    441:        }
                    442:        return cp;
                    443: }