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

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

1.20    ! deraadt     1: /*     $OpenBSD: quit.c,v 1.19 2007/09/10 14:29:53 tobias Exp $        */
1.4       millert     2: /*     $NetBSD: quit.c,v 1.6 1996/12/28 07:11:07 tls 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.
1.17      millert    16:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    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:  * Rcv -- receive mail rationally.
                     39:  *
                     40:  * Termination processing.
                     41:  */
                     42:
                     43: /*
                     44:  * The "quit" command.
                     45:  */
                     46: int
1.16      millert    47: quitcmd(void *v)
1.1       deraadt    48: {
                     49:        /*
                     50:         * If we are sourcing, then return 1 so execute() can handle it.
                     51:         * Otherwise, return -1 to abort command loop.
                     52:         */
                     53:        if (sourcing)
1.4       millert    54:                return(1);
                     55:        return(-1);
1.1       deraadt    56: }
                     57:
                     58: /*
                     59:  * Save all of the undetermined messages at the top of "mbox"
                     60:  * Save all untouched messages back in the system mailbox.
                     61:  * Remove the system mailbox, if none saved there.
                     62:  */
1.15      millert    63: int
1.16      millert    64: quit(void)
1.1       deraadt    65: {
                     66:        int mcount, p, modify, autohold, anystat, holdbit, nohold;
1.2       deraadt    67:        FILE *ibuf = NULL, *obuf, *fbuf, *rbuf, *readstat = NULL, *abuf;
1.9       millert    68:        struct message *mp;
1.7       millert    69:        int c, fd;
1.1       deraadt    70:        struct stat minfo;
1.8       millert    71:        char *mbox, tempname[PATHSIZE];
1.1       deraadt    72:
                     73:        /*
                     74:         * If we are read only, we can't do anything,
                     75:         * so just return quickly.
                     76:         */
                     77:        if (readonly)
1.15      millert    78:                return(0);
1.16      millert    79:
1.1       deraadt    80:        /*
                     81:         * If editing (not reading system mail box), then do the work
                     82:         * in edstop()
                     83:         */
1.15      millert    84:        if (edit)
                     85:                return(edstop());
1.1       deraadt    86:
                     87:        /*
                     88:         * See if there any messages to save in mbox.  If no, we
                     89:         * can save copying mbox to /tmp and back.
                     90:         *
                     91:         * Check also to see if any files need to be preserved.
                     92:         * Delete all untouched messages to keep them out of mbox.
                     93:         * If all the messages are to be preserved, just exit with
                     94:         * a message.
                     95:         */
1.14      millert    96:        fbuf = Fopen(mailname, "r+");
1.1       deraadt    97:        if (fbuf == NULL)
                     98:                goto newmail;
1.2       deraadt    99:        if (flock(fileno(fbuf), LOCK_EX) == -1) {
1.4       millert   100:                warn("Unable to lock mailbox");
                    101:                (void)Fclose(fbuf);
1.15      millert   102:                return(-1);
1.2       deraadt   103:        }
1.3       millert   104:        if (!spool_lock()) {
1.4       millert   105:                (void)Fclose(fbuf);
1.16      millert   106:                return(-1);             /* lockspool printed the error for us */
1.3       millert   107:        }
1.1       deraadt   108:        rbuf = NULL;
                    109:        if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
1.4       millert   110:                puts("New mail has arrived.");
1.7       millert   111:                (void)snprintf(tempname, sizeof(tempname),
                    112:                    "%s/mail.RqXXXXXXXXXX", tmpdir);
                    113:                if ((fd = mkstemp(tempname)) == -1 ||
                    114:                    (rbuf = Fdopen(fd, "w")) == NULL)
1.1       deraadt   115:                        goto newmail;
                    116: #ifdef APPEND
1.19      tobias    117:                fseek(fbuf, (long)mailsize, SEEK_SET);
1.1       deraadt   118:                while ((c = getc(fbuf)) != EOF)
1.5       millert   119:                        (void)putc(c, rbuf);
1.1       deraadt   120: #else
                    121:                p = minfo.st_size - mailsize;
                    122:                while (p-- > 0) {
                    123:                        c = getc(fbuf);
                    124:                        if (c == EOF)
                    125:                                goto newmail;
1.5       millert   126:                        (void)putc(c, rbuf);
1.1       deraadt   127:                }
                    128: #endif
1.4       millert   129:                (void)Fclose(rbuf);
1.7       millert   130:                if ((rbuf = Fopen(tempname, "r")) == NULL)
1.1       deraadt   131:                        goto newmail;
1.8       millert   132:                (void)rm(tempname);
1.1       deraadt   133:        }
                    134:
                    135:        /*
                    136:         * Adjust the message flags in each message.
                    137:         */
                    138:        anystat = 0;
1.6       millert   139:        autohold = value("hold") != NULL;
1.1       deraadt   140:        holdbit = autohold ? MPRESERVE : MBOX;
                    141:        nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
1.6       millert   142:        if (value("keepsave") != NULL)
1.1       deraadt   143:                nohold &= ~MSAVED;
                    144:        for (mp = &message[0]; mp < &message[msgCount]; mp++) {
                    145:                if (mp->m_flag & MNEW) {
                    146:                        mp->m_flag &= ~MNEW;
                    147:                        mp->m_flag |= MSTATUS;
                    148:                }
                    149:                if (mp->m_flag & MSTATUS)
                    150:                        anystat++;
                    151:                if ((mp->m_flag & MTOUCH) == 0)
                    152:                        mp->m_flag |= MPRESERVE;
                    153:                if ((mp->m_flag & nohold) == 0)
                    154:                        mp->m_flag |= holdbit;
                    155:        }
                    156:        modify = 0;
1.6       millert   157:        if (Tflag != NULL) {
1.1       deraadt   158:                if ((readstat = Fopen(Tflag, "w")) == NULL)
1.6       millert   159:                        Tflag = NULL;
1.1       deraadt   160:        }
                    161:        for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
                    162:                if (mp->m_flag & MBOX)
                    163:                        c++;
                    164:                if (mp->m_flag & MPRESERVE)
                    165:                        p++;
                    166:                if (mp->m_flag & MODIFY)
                    167:                        modify++;
1.6       millert   168:                if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) {
1.1       deraadt   169:                        char *id;
                    170:
1.6       millert   171:                        if ((id = hfield("article-id", mp)) != NULL)
1.1       deraadt   172:                                fprintf(readstat, "%s\n", id);
                    173:                }
                    174:        }
1.6       millert   175:        if (Tflag != NULL)
1.4       millert   176:                (void)Fclose(readstat);
1.1       deraadt   177:        if (p == msgCount && !modify && !anystat) {
                    178:                printf("Held %d message%s in %s\n",
                    179:                        p, p == 1 ? "" : "s", mailname);
1.4       millert   180:                (void)Fclose(fbuf);
1.3       millert   181:                spool_unlock();
1.15      millert   182:                return(0);
1.1       deraadt   183:        }
                    184:        if (c == 0) {
                    185:                if (p != 0) {
                    186:                        writeback(rbuf);
1.4       millert   187:                        (void)Fclose(fbuf);
1.3       millert   188:                        spool_unlock();
1.15      millert   189:                        return(0);
1.1       deraadt   190:                }
                    191:                goto cream;
                    192:        }
                    193:
                    194:        /*
                    195:         * Create another temporary file and copy user's mbox file
                    196:         * darin.  If there is no mbox, copy nothing.
                    197:         * If he has specified "append" don't copy his mailbox,
                    198:         * just copy saveable entries at the end.
                    199:         */
                    200:        mbox = expand("&");
                    201:        mcount = c;
1.6       millert   202:        if (value("append") == NULL) {
1.7       millert   203:                (void)snprintf(tempname, sizeof(tempname),
                    204:                    "%s/mail.RmXXXXXXXXXX", tmpdir);
                    205:                if ((fd = mkstemp(tempname)) == -1 ||
                    206:                    (obuf = Fdopen(fd, "w")) == NULL) {
1.13      millert   207:                        warn("%s", tempname);
1.4       millert   208:                        (void)Fclose(fbuf);
1.3       millert   209:                        spool_unlock();
1.15      millert   210:                        return(-1);
1.1       deraadt   211:                }
1.7       millert   212:                if ((ibuf = Fopen(tempname, "r")) == NULL) {
1.13      millert   213:                        warn("%s", tempname);
1.8       millert   214:                        (void)rm(tempname);
1.4       millert   215:                        (void)Fclose(obuf);
                    216:                        (void)Fclose(fbuf);
1.3       millert   217:                        spool_unlock();
1.15      millert   218:                        return(-1);
1.1       deraadt   219:                }
1.8       millert   220:                (void)rm(tempname);
1.1       deraadt   221:                if ((abuf = Fopen(mbox, "r")) != NULL) {
                    222:                        while ((c = getc(abuf)) != EOF)
1.5       millert   223:                                (void)putc(c, obuf);
1.4       millert   224:                        (void)Fclose(abuf);
1.1       deraadt   225:                }
                    226:                if (ferror(obuf)) {
1.13      millert   227:                        warn("%s", tempname);
1.4       millert   228:                        (void)Fclose(ibuf);
                    229:                        (void)Fclose(obuf);
                    230:                        (void)Fclose(fbuf);
1.3       millert   231:                        spool_unlock();
1.15      millert   232:                        return(-1);
1.1       deraadt   233:                }
1.4       millert   234:                (void)Fclose(obuf);
                    235:                (void)close(creat(mbox, 0600));
1.1       deraadt   236:                if ((obuf = Fopen(mbox, "r+")) == NULL) {
1.13      millert   237:                        warn("%s", mbox);
1.4       millert   238:                        (void)Fclose(ibuf);
                    239:                        (void)Fclose(fbuf);
1.3       millert   240:                        spool_unlock();
1.15      millert   241:                        return(-1);
1.1       deraadt   242:                }
1.15      millert   243:        } else {
1.1       deraadt   244:                if ((obuf = Fopen(mbox, "a")) == NULL) {
1.13      millert   245:                        warn("%s", mbox);
1.4       millert   246:                        (void)Fclose(fbuf);
1.3       millert   247:                        spool_unlock();
1.15      millert   248:                        return(-1);
1.1       deraadt   249:                }
                    250:                fchmod(fileno(obuf), 0600);
                    251:        }
                    252:        for (mp = &message[0]; mp < &message[msgCount]; mp++)
                    253:                if (mp->m_flag & MBOX)
1.12      millert   254:                        if (sendmessage(mp, obuf, saveignore, NULL) < 0) {
1.13      millert   255:                                warn("%s", mbox);
1.4       millert   256:                                (void)Fclose(ibuf);
                    257:                                (void)Fclose(obuf);
                    258:                                (void)Fclose(fbuf);
1.3       millert   259:                                spool_unlock();
1.15      millert   260:                                return(-1);
1.1       deraadt   261:                        }
                    262:
                    263:        /*
                    264:         * Copy the user's old mbox contents back
                    265:         * to the end of the stuff we just saved.
                    266:         * If we are appending, this is unnecessary.
                    267:         */
1.6       millert   268:        if (value("append") == NULL) {
1.1       deraadt   269:                rewind(ibuf);
                    270:                c = getc(ibuf);
                    271:                while (c != EOF) {
1.5       millert   272:                        (void)putc(c, obuf);
1.1       deraadt   273:                        if (ferror(obuf))
                    274:                                break;
                    275:                        c = getc(ibuf);
                    276:                }
1.4       millert   277:                (void)Fclose(ibuf);
1.1       deraadt   278:                fflush(obuf);
                    279:        }
                    280:        trunc(obuf);
                    281:        if (ferror(obuf)) {
1.13      millert   282:                warn("%s", mbox);
1.4       millert   283:                (void)Fclose(obuf);
                    284:                (void)Fclose(fbuf);
1.3       millert   285:                spool_unlock();
1.15      millert   286:                return(-1);
1.1       deraadt   287:        }
1.4       millert   288:        (void)Fclose(obuf);
1.1       deraadt   289:        if (mcount == 1)
1.4       millert   290:                puts("Saved 1 message in mbox");
1.1       deraadt   291:        else
                    292:                printf("Saved %d messages in mbox\n", mcount);
                    293:
                    294:        /*
                    295:         * Now we are ready to copy back preserved files to
                    296:         * the system mailbox, if any were requested.
                    297:         */
                    298:        if (p != 0) {
                    299:                writeback(rbuf);
1.4       millert   300:                (void)Fclose(fbuf);
1.3       millert   301:                spool_unlock();
1.15      millert   302:                return(0);
1.1       deraadt   303:        }
                    304:
                    305:        /*
1.10      millert   306:         * Finally, remove his /var/mail file.
1.1       deraadt   307:         * If new mail has arrived, copy it back.
                    308:         */
                    309: cream:
                    310:        if (rbuf != NULL) {
                    311:                abuf = Fopen(mailname, "r+");
                    312:                if (abuf == NULL)
                    313:                        goto newmail;
                    314:                while ((c = getc(rbuf)) != EOF)
1.5       millert   315:                        (void)putc(c, abuf);
1.4       millert   316:                (void)Fclose(rbuf);
1.1       deraadt   317:                trunc(abuf);
1.4       millert   318:                (void)Fclose(abuf);
1.1       deraadt   319:                alter(mailname);
1.4       millert   320:                (void)Fclose(fbuf);
1.3       millert   321:                spool_unlock();
1.15      millert   322:                return(0);
1.1       deraadt   323:        }
                    324:        demail();
1.4       millert   325:        (void)Fclose(fbuf);
1.3       millert   326:        spool_unlock();
1.18      otto      327:        return(0);
1.1       deraadt   328:
                    329: newmail:
1.4       millert   330:        puts("Thou hast new mail.");
1.2       deraadt   331:        if (fbuf != NULL) {
1.4       millert   332:                (void)Fclose(fbuf);
1.3       millert   333:                spool_unlock();
1.2       deraadt   334:        }
1.15      millert   335:        return(0);
1.1       deraadt   336: }
                    337:
                    338: /*
                    339:  * Preserve all the appropriate messages back in the system
                    340:  * mailbox, and print a nice message indicated how many were
                    341:  * saved.  On any error, just return -1.  Else return 0.
                    342:  * Incorporate the any new mail that we found.
                    343:  */
                    344: int
1.16      millert   345: writeback(FILE *res)
1.1       deraadt   346: {
1.9       millert   347:        struct message *mp;
                    348:        int p, c;
1.1       deraadt   349:        FILE *obuf;
                    350:
                    351:        p = 0;
                    352:        if ((obuf = Fopen(mailname, "r+")) == NULL) {
1.13      millert   353:                warn("%s", mailname);
1.1       deraadt   354:                return(-1);
                    355:        }
                    356: #ifndef APPEND
                    357:        if (res != NULL)
                    358:                while ((c = getc(res)) != EOF)
1.5       millert   359:                        (void)putc(c, obuf);
1.1       deraadt   360: #endif
                    361:        for (mp = &message[0]; mp < &message[msgCount]; mp++)
                    362:                if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
                    363:                        p++;
1.12      millert   364:                        if (sendmessage(mp, obuf, NULL, NULL) < 0) {
1.13      millert   365:                                warn("%s", mailname);
1.4       millert   366:                                (void)Fclose(obuf);
1.1       deraadt   367:                                return(-1);
                    368:                        }
                    369:                }
                    370: #ifdef APPEND
                    371:        if (res != NULL)
                    372:                while ((c = getc(res)) != EOF)
1.5       millert   373:                        (void)putc(c, obuf);
1.1       deraadt   374: #endif
                    375:        fflush(obuf);
                    376:        trunc(obuf);
                    377:        if (ferror(obuf)) {
1.13      millert   378:                warn("%s", mailname);
1.4       millert   379:                (void)Fclose(obuf);
1.1       deraadt   380:                return(-1);
                    381:        }
                    382:        if (res != NULL)
1.4       millert   383:                (void)Fclose(res);
                    384:        (void)Fclose(obuf);
1.1       deraadt   385:        alter(mailname);
                    386:        if (p == 1)
                    387:                printf("Held 1 message in %s\n", mailname);
                    388:        else
                    389:                printf("Held %d messages in %s\n", p, mailname);
                    390:        return(0);
                    391: }
                    392:
                    393: /*
                    394:  * Terminate an editing session by attempting to write out the user's
                    395:  * file from the temporary.  Save any new stuff appended to the file.
                    396:  */
1.15      millert   397: int
1.16      millert   398: edstop(void)
1.1       deraadt   399: {
1.9       millert   400:        int gotcha, c;
                    401:        struct message *mp;
1.2       deraadt   402:        FILE *obuf, *ibuf, *readstat = NULL;
1.1       deraadt   403:        struct stat statb;
1.8       millert   404:        char tempname[PATHSIZE];
1.1       deraadt   405:
                    406:        if (readonly)
1.15      millert   407:                return(0);
1.1       deraadt   408:        holdsigs();
1.6       millert   409:        if (Tflag != NULL) {
1.1       deraadt   410:                if ((readstat = Fopen(Tflag, "w")) == NULL)
1.6       millert   411:                        Tflag = NULL;
1.1       deraadt   412:        }
                    413:        for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
                    414:                if (mp->m_flag & MNEW) {
                    415:                        mp->m_flag &= ~MNEW;
                    416:                        mp->m_flag |= MSTATUS;
                    417:                }
                    418:                if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
                    419:                        gotcha++;
1.6       millert   420:                if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) {
1.1       deraadt   421:                        char *id;
                    422:
1.6       millert   423:                        if ((id = hfield("article-id", mp)) != NULL)
1.1       deraadt   424:                                fprintf(readstat, "%s\n", id);
                    425:                }
                    426:        }
1.6       millert   427:        if (Tflag != NULL)
1.4       millert   428:                (void)Fclose(readstat);
1.6       millert   429:        if (!gotcha || Tflag != NULL)
1.1       deraadt   430:                goto done;
                    431:        ibuf = NULL;
                    432:        if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
1.3       millert   433:                int fd;
1.1       deraadt   434:
1.8       millert   435:                (void)snprintf(tempname, sizeof(tempname), "%s/mbox.XXXXXXXXXX",
1.7       millert   436:                    tmpdir);
1.3       millert   437:                if ((fd = mkstemp(tempname)) == -1 ||
                    438:                    (obuf = Fdopen(fd, "w")) == NULL) {
1.13      millert   439:                        warn("%s", tempname);
1.16      millert   440:                        if (fd != -1)
                    441:                                close(fd);
1.1       deraadt   442:                        relsesigs();
1.15      millert   443:                        return(-1);
1.1       deraadt   444:                }
                    445:                if ((ibuf = Fopen(mailname, "r")) == NULL) {
1.13      millert   446:                        warn("%s", mailname);
1.4       millert   447:                        (void)Fclose(obuf);
1.8       millert   448:                        (void)rm(tempname);
1.1       deraadt   449:                        relsesigs();
1.15      millert   450:                        return(-1);
1.1       deraadt   451:                }
1.19      tobias    452:                fseek(ibuf, (long)mailsize, SEEK_SET);
1.1       deraadt   453:                while ((c = getc(ibuf)) != EOF)
1.5       millert   454:                        (void)putc(c, obuf);
1.4       millert   455:                (void)Fclose(ibuf);
                    456:                (void)Fclose(obuf);
1.1       deraadt   457:                if ((ibuf = Fopen(tempname, "r")) == NULL) {
1.13      millert   458:                        warn("%s", tempname);
1.8       millert   459:                        (void)rm(tempname);
1.1       deraadt   460:                        relsesigs();
1.15      millert   461:                        return(-1);
1.1       deraadt   462:                }
1.8       millert   463:                (void)rm(tempname);
1.1       deraadt   464:        }
                    465:        printf("\"%s\" ", mailname);
                    466:        fflush(stdout);
                    467:        if ((obuf = Fopen(mailname, "r+")) == NULL) {
1.13      millert   468:                warn("%s", mailname);
1.1       deraadt   469:                relsesigs();
1.15      millert   470:                return(-1);
1.1       deraadt   471:        }
                    472:        trunc(obuf);
                    473:        c = 0;
                    474:        for (mp = &message[0]; mp < &message[msgCount]; mp++) {
                    475:                if ((mp->m_flag & MDELETED) != 0)
                    476:                        continue;
                    477:                c++;
1.12      millert   478:                if (sendmessage(mp, obuf, NULL, NULL) < 0) {
1.13      millert   479:                        warn("%s", mailname);
1.1       deraadt   480:                        relsesigs();
1.15      millert   481:                        return(-1);
1.1       deraadt   482:                }
                    483:        }
                    484:        gotcha = (c == 0 && ibuf == NULL);
                    485:        if (ibuf != NULL) {
                    486:                while ((c = getc(ibuf)) != EOF)
1.5       millert   487:                        (void)putc(c, obuf);
1.4       millert   488:                (void)Fclose(ibuf);
1.1       deraadt   489:        }
                    490:        fflush(obuf);
                    491:        if (ferror(obuf)) {
1.13      millert   492:                warn("%s", mailname);
1.1       deraadt   493:                relsesigs();
1.15      millert   494:                return(-1);
1.1       deraadt   495:        }
1.4       millert   496:        (void)Fclose(obuf);
1.1       deraadt   497:        if (gotcha) {
1.8       millert   498:                (void)rm(mailname);
1.4       millert   499:                puts("removed");
1.1       deraadt   500:        } else
1.4       millert   501:                puts("complete");
1.1       deraadt   502:        fflush(stdout);
                    503:
                    504: done:
                    505:        relsesigs();
1.15      millert   506:        return(0);
1.1       deraadt   507: }