[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.1

1.1     ! deraadt     1: /*
        !             2:  * Copyright (c) 1980, 1993
        !             3:  *     The Regents of the University of California.  All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. All advertising materials mentioning features or use of this software
        !            14:  *    must display the following acknowledgement:
        !            15:  *     This product includes software developed by the University of
        !            16:  *     California, Berkeley and its contributors.
        !            17:  * 4. Neither the name of the University nor the names of its contributors
        !            18:  *    may be used to endorse or promote products derived from this software
        !            19:  *    without specific prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            31:  * SUCH DAMAGE.
        !            32:  */
        !            33:
        !            34: #ifndef lint
        !            35: static char sccsid[] = "from: @(#)fio.c        8.1 (Berkeley) 6/6/93";
        !            36: static char rcsid[] = "$Id: fio.c,v 1.4 1994/06/29 05:09:22 deraadt Exp $";
        !            37: #endif /* not lint */
        !            38:
        !            39: #include "rcv.h"
        !            40: #include <sys/file.h>
        !            41: #include <sys/wait.h>
        !            42:
        !            43: #include <unistd.h>
        !            44: #include <paths.h>
        !            45: #include <errno.h>
        !            46: #include "extern.h"
        !            47:
        !            48: /*
        !            49:  * Mail -- a mail program
        !            50:  *
        !            51:  * File I/O.
        !            52:  */
        !            53:
        !            54: /*
        !            55:  * Set up the input pointers while copying the mail file into /tmp.
        !            56:  */
        !            57: void
        !            58: setptr(ibuf)
        !            59:        register FILE *ibuf;
        !            60: {
        !            61:        extern char *tmpdir;
        !            62:        register int c, count;
        !            63:        register char *cp, *cp2;
        !            64:        struct message this;
        !            65:        FILE *mestmp;
        !            66:        off_t offset;
        !            67:        int maybe, inhead;
        !            68:        char linebuf[LINESIZE];
        !            69:
        !            70:        /* Get temporary file. */
        !            71:        (void)sprintf(linebuf, "%s/mail.XXXXXX", tmpdir);
        !            72:        if ((c = mkstemp(linebuf)) == -1 ||
        !            73:            (mestmp = Fdopen(c, "r+")) == NULL) {
        !            74:                (void)fprintf(stderr, "mail: can't open %s\n", linebuf);
        !            75:                exit(1);
        !            76:        }
        !            77:        (void)unlink(linebuf);
        !            78:
        !            79:        msgCount = 0;
        !            80:        maybe = 1;
        !            81:        inhead = 0;
        !            82:        offset = 0;
        !            83:        this.m_flag = MUSED|MNEW;
        !            84:        this.m_size = 0;
        !            85:        this.m_lines = 0;
        !            86:        this.m_block = 0;
        !            87:        this.m_offset = 0;
        !            88:        for (;;) {
        !            89:                if (fgets(linebuf, LINESIZE, ibuf) == NULL) {
        !            90:                        if (append(&this, mestmp)) {
        !            91:                                perror("temporary file");
        !            92:                                exit(1);
        !            93:                        }
        !            94:                        makemessage(mestmp);
        !            95:                        return;
        !            96:                }
        !            97:                count = strlen(linebuf);
        !            98:                (void) fwrite(linebuf, sizeof *linebuf, count, otf);
        !            99:                if (ferror(otf)) {
        !           100:                        perror("/tmp");
        !           101:                        exit(1);
        !           102:                }
        !           103:                linebuf[count - 1] = 0;
        !           104:                if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
        !           105:                        msgCount++;
        !           106:                        if (append(&this, mestmp)) {
        !           107:                                perror("temporary file");
        !           108:                                exit(1);
        !           109:                        }
        !           110:                        this.m_flag = MUSED|MNEW;
        !           111:                        this.m_size = 0;
        !           112:                        this.m_lines = 0;
        !           113:                        this.m_block = blockof(offset);
        !           114:                        this.m_offset = offsetof(offset);
        !           115:                        inhead = 1;
        !           116:                } else if (linebuf[0] == 0) {
        !           117:                        inhead = 0;
        !           118:                } else if (inhead) {
        !           119:                        for (cp = linebuf, cp2 = "status";; cp++) {
        !           120:                                if ((c = *cp2++) == 0) {
        !           121:                                        while (isspace(*cp++))
        !           122:                                                ;
        !           123:                                        if (cp[-1] != ':')
        !           124:                                                break;
        !           125:                                        while (c = *cp++)
        !           126:                                                if (c == 'R')
        !           127:                                                        this.m_flag |= MREAD;
        !           128:                                                else if (c == 'O')
        !           129:                                                        this.m_flag &= ~MNEW;
        !           130:                                        inhead = 0;
        !           131:                                        break;
        !           132:                                }
        !           133:                                if (*cp != c && *cp != toupper(c))
        !           134:                                        break;
        !           135:                        }
        !           136:                }
        !           137:                offset += count;
        !           138:                this.m_size += count;
        !           139:                this.m_lines++;
        !           140:                maybe = linebuf[0] == 0;
        !           141:        }
        !           142: }
        !           143:
        !           144: /*
        !           145:  * Drop the passed line onto the passed output buffer.
        !           146:  * If a write error occurs, return -1, else the count of
        !           147:  * characters written, including the newline.
        !           148:  */
        !           149: int
        !           150: putline(obuf, linebuf)
        !           151:        FILE *obuf;
        !           152:        char *linebuf;
        !           153: {
        !           154:        register int c;
        !           155:
        !           156:        c = strlen(linebuf);
        !           157:        (void) fwrite(linebuf, sizeof *linebuf, c, obuf);
        !           158:        (void) putc('\n', obuf);
        !           159:        if (ferror(obuf))
        !           160:                return (-1);
        !           161:        return (c + 1);
        !           162: }
        !           163:
        !           164: /*
        !           165:  * Read up a line from the specified input into the line
        !           166:  * buffer.  Return the number of characters read.  Do not
        !           167:  * include the newline at the end.
        !           168:  */
        !           169: int
        !           170: readline(ibuf, linebuf, linesize)
        !           171:        FILE *ibuf;
        !           172:        char *linebuf;
        !           173:        int linesize;
        !           174: {
        !           175:        register int n;
        !           176:
        !           177:        clearerr(ibuf);
        !           178:        if (fgets(linebuf, linesize, ibuf) == NULL)
        !           179:                return -1;
        !           180:        n = strlen(linebuf);
        !           181:        if (n > 0 && linebuf[n - 1] == '\n')
        !           182:                linebuf[--n] = '\0';
        !           183:        return n;
        !           184: }
        !           185:
        !           186: /*
        !           187:  * Return a file buffer all ready to read up the
        !           188:  * passed message pointer.
        !           189:  */
        !           190: FILE *
        !           191: setinput(mp)
        !           192:        register struct message *mp;
        !           193: {
        !           194:
        !           195:        fflush(otf);
        !           196:        if (fseek(itf, (long)positionof(mp->m_block, mp->m_offset), 0) < 0) {
        !           197:                perror("fseek");
        !           198:                panic("temporary file seek");
        !           199:        }
        !           200:        return (itf);
        !           201: }
        !           202:
        !           203: /*
        !           204:  * Take the data out of the passed ghost file and toss it into
        !           205:  * a dynamically allocated message structure.
        !           206:  */
        !           207: void
        !           208: makemessage(f)
        !           209:        FILE *f;
        !           210: {
        !           211:        register size = (msgCount + 1) * sizeof (struct message);
        !           212:
        !           213:        if (message != 0)
        !           214:                free((char *) message);
        !           215:        if ((message = (struct message *) malloc((unsigned) size)) == 0)
        !           216:                panic("Insufficient memory for %d messages", msgCount);
        !           217:        dot = message;
        !           218:        size -= sizeof (struct message);
        !           219:        fflush(f);
        !           220:        (void) lseek(fileno(f), (off_t)sizeof *message, 0);
        !           221:        if (read(fileno(f), (char *) message, size) != size)
        !           222:                panic("Message temporary file corrupted");
        !           223:        message[msgCount].m_size = 0;
        !           224:        message[msgCount].m_lines = 0;
        !           225:        Fclose(f);
        !           226: }
        !           227:
        !           228: /*
        !           229:  * Append the passed message descriptor onto the temp file.
        !           230:  * If the write fails, return 1, else 0
        !           231:  */
        !           232: int
        !           233: append(mp, f)
        !           234:        struct message *mp;
        !           235:        FILE *f;
        !           236: {
        !           237:        return fwrite((char *) mp, sizeof *mp, 1, f) != 1;
        !           238: }
        !           239:
        !           240: /*
        !           241:  * Delete a file, but only if the file is a plain file.
        !           242:  */
        !           243: int
        !           244: rm(name)
        !           245:        char *name;
        !           246: {
        !           247:        struct stat sb;
        !           248:
        !           249:        if (stat(name, &sb) < 0)
        !           250:                return(-1);
        !           251:        if (!S_ISREG(sb.st_mode)) {
        !           252:                errno = EISDIR;
        !           253:                return(-1);
        !           254:        }
        !           255:        return(unlink(name));
        !           256: }
        !           257:
        !           258: static int sigdepth;           /* depth of holdsigs() */
        !           259: static int omask;
        !           260: /*
        !           261:  * Hold signals SIGHUP, SIGINT, and SIGQUIT.
        !           262:  */
        !           263: void
        !           264: holdsigs()
        !           265: {
        !           266:
        !           267:        if (sigdepth++ == 0)
        !           268:                omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT));
        !           269: }
        !           270:
        !           271: /*
        !           272:  * Release signals SIGHUP, SIGINT, and SIGQUIT.
        !           273:  */
        !           274: void
        !           275: relsesigs()
        !           276: {
        !           277:
        !           278:        if (--sigdepth == 0)
        !           279:                sigsetmask(omask);
        !           280: }
        !           281:
        !           282: /*
        !           283:  * Determine the size of the file possessed by
        !           284:  * the passed buffer.
        !           285:  */
        !           286: off_t
        !           287: fsize(iob)
        !           288:        FILE *iob;
        !           289: {
        !           290:        struct stat sbuf;
        !           291:
        !           292:        if (fstat(fileno(iob), &sbuf) < 0)
        !           293:                return 0;
        !           294:        return sbuf.st_size;
        !           295: }
        !           296:
        !           297: /*
        !           298:  * Evaluate the string given as a new mailbox name.
        !           299:  * Supported meta characters:
        !           300:  *     %       for my system mail box
        !           301:  *     %user   for user's system mail box
        !           302:  *     #       for previous file
        !           303:  *     &       invoker's mbox file
        !           304:  *     +file   file in folder directory
        !           305:  *     any shell meta character
        !           306:  * Return the file name as a dynamic string.
        !           307:  */
        !           308: char *
        !           309: expand(name)
        !           310:        register char *name;
        !           311: {
        !           312:        char xname[PATHSIZE];
        !           313:        char cmdbuf[PATHSIZE];          /* also used for file names */
        !           314:        register int pid, l;
        !           315:        register char *cp, *shell;
        !           316:        int pivec[2];
        !           317:        struct stat sbuf;
        !           318:        extern union wait wait_status;
        !           319:
        !           320:        /*
        !           321:         * The order of evaluation is "%" and "#" expand into constants.
        !           322:         * "&" can expand into "+".  "+" can expand into shell meta characters.
        !           323:         * Shell meta characters expand into constants.
        !           324:         * This way, we make no recursive expansion.
        !           325:         */
        !           326:        switch (*name) {
        !           327:        case '%':
        !           328:                findmail(name[1] ? name + 1 : myname, xname);
        !           329:                return savestr(xname);
        !           330:        case '#':
        !           331:                if (name[1] != 0)
        !           332:                        break;
        !           333:                if (prevfile[0] == 0) {
        !           334:                        printf("No previous file\n");
        !           335:                        return NOSTR;
        !           336:                }
        !           337:                return savestr(prevfile);
        !           338:        case '&':
        !           339:                if (name[1] == 0 && (name = value("MBOX")) == NOSTR)
        !           340:                        name = "~/mbox";
        !           341:                /* fall through */
        !           342:        }
        !           343:        if (name[0] == '+' && getfold(cmdbuf) >= 0) {
        !           344:                sprintf(xname, "%s/%s", cmdbuf, name + 1);
        !           345:                name = savestr(xname);
        !           346:        }
        !           347:        /* catch the most common shell meta character */
        !           348:        if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) {
        !           349:                sprintf(xname, "%s%s", homedir, name + 1);
        !           350:                name = savestr(xname);
        !           351:        }
        !           352:        if (!anyof(name, "~{[*?$`'\"\\"))
        !           353:                return name;
        !           354:        if (pipe(pivec) < 0) {
        !           355:                perror("pipe");
        !           356:                return name;
        !           357:        }
        !           358:        sprintf(cmdbuf, "echo %s", name);
        !           359:        if ((shell = value("SHELL")) == NOSTR)
        !           360:                shell = _PATH_CSHELL;
        !           361:        pid = start_command(shell, 0, -1, pivec[1], "-c", cmdbuf, NOSTR);
        !           362:        if (pid < 0) {
        !           363:                close(pivec[0]);
        !           364:                close(pivec[1]);
        !           365:                return NOSTR;
        !           366:        }
        !           367:        close(pivec[1]);
        !           368:        l = read(pivec[0], xname, BUFSIZ);
        !           369:        close(pivec[0]);
        !           370:        if (wait_child(pid) < 0 && wait_status.w_termsig != SIGPIPE) {
        !           371:                fprintf(stderr, "\"%s\": Expansion failed.\n", name);
        !           372:                return NOSTR;
        !           373:        }
        !           374:        if (l < 0) {
        !           375:                perror("read");
        !           376:                return NOSTR;
        !           377:        }
        !           378:        if (l == 0) {
        !           379:                fprintf(stderr, "\"%s\": No match.\n", name);
        !           380:                return NOSTR;
        !           381:        }
        !           382:        if (l == BUFSIZ) {
        !           383:                fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name);
        !           384:                return NOSTR;
        !           385:        }
        !           386:        xname[l] = 0;
        !           387:        for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
        !           388:                ;
        !           389:        cp[1] = '\0';
        !           390:        if (index(xname, ' ') && stat(xname, &sbuf) < 0) {
        !           391:                fprintf(stderr, "\"%s\": Ambiguous.\n", name);
        !           392:                return NOSTR;
        !           393:        }
        !           394:        return savestr(xname);
        !           395: }
        !           396:
        !           397: /*
        !           398:  * Determine the current folder directory name.
        !           399:  */
        !           400: int
        !           401: getfold(name)
        !           402:        char *name;
        !           403: {
        !           404:        char *folder;
        !           405:
        !           406:        if ((folder = value("folder")) == NOSTR)
        !           407:                return (-1);
        !           408:        if (*folder == '/')
        !           409:                strcpy(name, folder);
        !           410:        else
        !           411:                sprintf(name, "%s/%s", homedir, folder);
        !           412:        return (0);
        !           413: }
        !           414:
        !           415: /*
        !           416:  * Return the name of the dead.letter file.
        !           417:  */
        !           418: char *
        !           419: getdeadletter()
        !           420: {
        !           421:        register char *cp;
        !           422:
        !           423:        if ((cp = value("DEAD")) == NOSTR || (cp = expand(cp)) == NOSTR)
        !           424:                cp = expand("~/dead.letter");
        !           425:        else if (*cp != '/') {
        !           426:                char buf[PATHSIZE];
        !           427:
        !           428:                (void) sprintf(buf, "~/%s", cp);
        !           429:                cp = expand(buf);
        !           430:        }
        !           431:        return cp;
        !           432: }