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

Annotation of src/usr.bin/mail/cmd2.c, Revision 1.12

1.12    ! millert     1: /*     $OpenBSD: cmd2.c,v 1.11 2001/11/21 20:41:55 millert Exp $       */
1.3       millert     2: /*     $NetBSD: cmd2.c,v 1.7 1997/05/17 19:55:10 pk 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.12    ! 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: #ifndef lint
1.2       deraadt    34: #if 0
1.10      millert    35: static const char sccsid[] = "@(#)cmd2.c       8.1 (Berkeley) 6/6/93";
1.2       deraadt    36: #else
1.12    ! millert    37: static const char rcsid[] = "$OpenBSD: cmd2.c,v 1.11 2001/11/21 20:41:55 millert Exp $";
1.2       deraadt    38: #endif
1.1       deraadt    39: #endif /* not lint */
                     40:
                     41: #include "rcv.h"
                     42: #include <sys/wait.h>
                     43: #include "extern.h"
                     44:
                     45: /*
                     46:  * Mail -- a mail program
                     47:  *
                     48:  * More user commands.
                     49:  */
1.10      millert    50: static int igcomp(const void *, const void *);
1.1       deraadt    51:
                     52: /*
                     53:  * If any arguments were given, go to the next applicable argument
                     54:  * following dot, otherwise, go to the next applicable message.
                     55:  * If given as first command with no arguments, print first message.
                     56:  */
                     57: int
1.10      millert    58: next(void *v)
1.1       deraadt    59: {
1.8       millert    60:        struct message *mp;
1.2       deraadt    61:        int *msgvec = v;
1.8       millert    62:        int *ip, *ip2, list[2], mdot;
1.1       deraadt    63:
                     64:        if (*msgvec != NULL) {
                     65:                /*
1.3       millert    66:                 * If some messages were supplied, find the
1.1       deraadt    67:                 * first applicable one following dot using
                     68:                 * wrap around.
                     69:                 */
                     70:                mdot = dot - &message[0] + 1;
                     71:
                     72:                /*
                     73:                 * Find the first message in the supplied
                     74:                 * message list which follows dot.
                     75:                 */
                     76:                for (ip = msgvec; *ip != NULL; ip++)
                     77:                        if (*ip > mdot)
                     78:                                break;
                     79:                if (*ip == NULL)
                     80:                        ip = msgvec;
                     81:                ip2 = ip;
                     82:                do {
                     83:                        mp = &message[*ip2 - 1];
                     84:                        if ((mp->m_flag & MDELETED) == 0) {
                     85:                                dot = mp;
                     86:                                goto hitit;
                     87:                        }
                     88:                        if (*ip2 != NULL)
                     89:                                ip2++;
                     90:                        if (*ip2 == NULL)
                     91:                                ip2 = msgvec;
                     92:                } while (ip2 != ip);
1.3       millert    93:                puts("No messages applicable");
1.1       deraadt    94:                return(1);
                     95:        }
                     96:
                     97:        /*
                     98:         * If this is the first command, select message 1.
                     99:         * Note that this must exist for us to get here at all.
                    100:         */
                    101:        if (!sawcom)
                    102:                goto hitit;
                    103:
                    104:        /*
                    105:         * Just find the next good message after dot, no
                    106:         * wraparound.
                    107:         */
                    108:        for (mp = dot+1; mp < &message[msgCount]; mp++)
                    109:                if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
                    110:                        break;
                    111:        if (mp >= &message[msgCount]) {
1.3       millert   112:                puts("At EOF");
1.1       deraadt   113:                return(0);
                    114:        }
                    115:        dot = mp;
                    116: hitit:
                    117:        /*
                    118:         * Print dot.
                    119:         */
                    120:        list[0] = dot - &message[0] + 1;
                    121:        list[1] = NULL;
                    122:        return(type(list));
                    123: }
                    124:
                    125: /*
                    126:  * Save a message in a file.  Mark the message as saved
                    127:  * so we can discard when the user quits.
                    128:  */
                    129: int
1.10      millert   130: save(void *v)
1.1       deraadt   131: {
1.2       deraadt   132:        char *str = v;
1.1       deraadt   133:
1.3       millert   134:        return(save1(str, 1, "save", saveignore));
1.1       deraadt   135: }
                    136:
                    137: /*
                    138:  * Copy a message to a file without affected its saved-ness
                    139:  */
                    140: int
1.10      millert   141: copycmd(void *v)
1.1       deraadt   142: {
1.2       deraadt   143:        char *str = v;
1.1       deraadt   144:
1.3       millert   145:        return(save1(str, 0, "copy", saveignore));
1.1       deraadt   146: }
                    147:
                    148: /*
                    149:  * Save/copy the indicated messages at the end of the passed file name.
                    150:  * If mark is true, mark the message "saved."
                    151:  */
                    152: int
1.10      millert   153: save1(char *str, int mark, char *cmd, struct ignoretab *ignore)
1.1       deraadt   154: {
1.8       millert   155:        struct message *mp;
1.1       deraadt   156:        char *file, *disp;
1.8       millert   157:        int f, *msgvec, *ip;
1.1       deraadt   158:        FILE *obuf;
                    159:
1.4       millert   160:        msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec));
1.5       millert   161:        if ((file = snarf(str, &f)) == NULL)
1.1       deraadt   162:                return(1);
                    163:        if (!f) {
                    164:                *msgvec = first(0, MMNORM);
                    165:                if (*msgvec == NULL) {
                    166:                        printf("No messages to %s.\n", cmd);
                    167:                        return(1);
                    168:                }
                    169:                msgvec[1] = NULL;
                    170:        }
                    171:        if (f && getmsglist(str, msgvec, 0) < 0)
                    172:                return(1);
1.5       millert   173:        if ((file = expand(file)) == NULL)
1.1       deraadt   174:                return(1);
                    175:        printf("\"%s\" ", file);
                    176:        fflush(stdout);
                    177:        if (access(file, 0) >= 0)
                    178:                disp = "[Appended]";
                    179:        else
                    180:                disp = "[New file]";
                    181:        if ((obuf = Fopen(file, "a")) == NULL) {
1.5       millert   182:                warn(NULL);
1.1       deraadt   183:                return(1);
                    184:        }
                    185:        for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
                    186:                mp = &message[*ip - 1];
                    187:                touch(mp);
1.9       millert   188:                if (sendmessage(mp, obuf, ignore, NULL) < 0) {
1.8       millert   189:                        warn("%s", file);
1.3       millert   190:                        (void)Fclose(obuf);
1.1       deraadt   191:                        return(1);
                    192:                }
                    193:                if (mark)
                    194:                        mp->m_flag |= MSAVED;
                    195:        }
                    196:        fflush(obuf);
                    197:        if (ferror(obuf))
1.8       millert   198:                warn("%s", file);
1.3       millert   199:        (void)Fclose(obuf);
1.1       deraadt   200:        printf("%s\n", disp);
                    201:        return(0);
                    202: }
                    203:
                    204: /*
                    205:  * Write the indicated messages at the end of the passed
                    206:  * file name, minus header and trailing blank line.
                    207:  */
                    208: int
1.10      millert   209: swrite(void *v)
1.1       deraadt   210: {
1.2       deraadt   211:        char *str = v;
1.1       deraadt   212:
1.3       millert   213:        return(save1(str, 1, "write", ignoreall));
1.1       deraadt   214: }
                    215:
                    216: /*
                    217:  * Snarf the file from the end of the command line and
                    218:  * return a pointer to it.  If there is no file attached,
1.5       millert   219:  * just return NULL.  Put a null in front of the file
1.1       deraadt   220:  * name so that the message list processing won't see it,
                    221:  * unless the file name is the only thing on the line, in
                    222:  * which case, return 0 in the reference flag variable.
                    223:  */
                    224: char *
1.10      millert   225: snarf(char *linebuf, int *flag)
1.1       deraadt   226: {
1.8       millert   227:        char *cp;
1.1       deraadt   228:
                    229:        *flag = 1;
                    230:        cp = strlen(linebuf) + linebuf - 1;
                    231:
                    232:        /*
                    233:         * Strip away trailing blanks.
                    234:         */
                    235:        while (cp > linebuf && isspace(*cp))
                    236:                cp--;
                    237:        *++cp = 0;
                    238:
                    239:        /*
                    240:         * Now search for the beginning of the file name.
                    241:         */
                    242:        while (cp > linebuf && !isspace(*cp))
                    243:                cp--;
                    244:        if (*cp == '\0') {
1.3       millert   245:                puts("No file specified.");
1.5       millert   246:                return(NULL);
1.1       deraadt   247:        }
                    248:        if (isspace(*cp))
                    249:                *cp++ = 0;
                    250:        else
                    251:                *flag = 0;
                    252:        return(cp);
                    253: }
                    254:
                    255: /*
                    256:  * Delete messages.
                    257:  */
                    258: int
1.10      millert   259: delete(void *v)
1.1       deraadt   260: {
1.2       deraadt   261:        int *msgvec = v;
1.10      millert   262:
1.1       deraadt   263:        delm(msgvec);
1.3       millert   264:        return(0);
1.1       deraadt   265: }
                    266:
                    267: /*
                    268:  * Delete messages, then type the new dot.
                    269:  */
                    270: int
1.10      millert   271: deltype(void *v)
1.1       deraadt   272: {
1.2       deraadt   273:        int *msgvec = v;
1.1       deraadt   274:        int list[2];
                    275:        int lastdot;
                    276:
                    277:        lastdot = dot - &message[0] + 1;
                    278:        if (delm(msgvec) >= 0) {
                    279:                list[0] = dot - &message[0] + 1;
                    280:                if (list[0] > lastdot) {
                    281:                        touch(dot);
                    282:                        list[1] = NULL;
                    283:                        return(type(list));
                    284:                }
1.3       millert   285:                puts("At EOF");
1.1       deraadt   286:        } else
1.3       millert   287:                puts("No more messages");
1.1       deraadt   288:        return(0);
                    289: }
                    290:
                    291: /*
                    292:  * Delete the indicated messages.
                    293:  * Set dot to some nice place afterwards.
                    294:  * Internal interface.
                    295:  */
                    296: int
1.10      millert   297: delm(int *msgvec)
1.1       deraadt   298: {
1.8       millert   299:        struct message *mp;
                    300:        int *ip, last;
1.1       deraadt   301:
                    302:        last = NULL;
                    303:        for (ip = msgvec; *ip != NULL; ip++) {
                    304:                mp = &message[*ip - 1];
                    305:                touch(mp);
                    306:                mp->m_flag |= MDELETED|MTOUCH;
                    307:                mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
                    308:                last = *ip;
                    309:        }
                    310:        if (last != NULL) {
                    311:                dot = &message[last-1];
                    312:                last = first(0, MDELETED);
                    313:                if (last != NULL) {
                    314:                        dot = &message[last-1];
                    315:                        return(0);
                    316:                }
                    317:                else {
                    318:                        dot = &message[0];
                    319:                        return(-1);
                    320:                }
                    321:        }
                    322:
                    323:        /*
                    324:         * Following can't happen -- it keeps lint happy
                    325:         */
                    326:        return(-1);
                    327: }
                    328:
                    329: /*
                    330:  * Undelete the indicated messages.
                    331:  */
                    332: int
1.10      millert   333: undeletecmd(void *v)
1.1       deraadt   334: {
1.2       deraadt   335:        int *msgvec = v;
1.8       millert   336:        int *ip;
                    337:        struct message *mp;
1.1       deraadt   338:
                    339:        for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
                    340:                mp = &message[*ip - 1];
                    341:                touch(mp);
                    342:                dot = mp;
                    343:                mp->m_flag &= ~MDELETED;
                    344:        }
1.3       millert   345:        return(0);
1.1       deraadt   346: }
                    347:
                    348: /*
                    349:  * Interactively dump core on "core"
                    350:  */
                    351: int
1.10      millert   352: core(void *v)
1.1       deraadt   353: {
1.10      millert   354:        pid_t pid;
1.7       millert   355:        extern int wait_status;
1.1       deraadt   356:
                    357:        switch (pid = vfork()) {
                    358:        case -1:
1.8       millert   359:                warn("vfork");
1.1       deraadt   360:                return(1);
                    361:        case 0:
                    362:                abort();
                    363:                _exit(1);
                    364:        }
1.3       millert   365:        fputs("Okie dokie", stdout);
1.1       deraadt   366:        fflush(stdout);
                    367:        wait_child(pid);
1.7       millert   368:        if (WIFSIGNALED(wait_status) && WCOREDUMP(wait_status))
1.3       millert   369:                puts(" -- Core dumped.");
1.1       deraadt   370:        else
1.3       millert   371:                puts(" -- Can't dump core.");
                    372:        return(0);
1.1       deraadt   373: }
                    374:
                    375: /*
                    376:  * Clobber as many bytes of stack as the user requests.
                    377:  */
                    378: int
1.10      millert   379: clobber(void *v)
1.1       deraadt   380: {
1.2       deraadt   381:        char **argv = v;
1.8       millert   382:        int times;
1.1       deraadt   383:
                    384:        if (argv[0] == 0)
                    385:                times = 1;
                    386:        else
                    387:                times = (atoi(argv[0]) + 511) / 512;
                    388:        clob1(times);
1.3       millert   389:        return(0);
1.1       deraadt   390: }
                    391:
                    392: /*
                    393:  * Clobber the stack.
                    394:  */
                    395: void
                    396: clob1(n)
                    397:        int n;
                    398: {
                    399:        char buf[512];
1.8       millert   400:        char *cp;
1.1       deraadt   401:
                    402:        if (n <= 0)
                    403:                return;
                    404:        for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
                    405:                ;
                    406:        clob1(n - 1);
                    407: }
                    408:
                    409: /*
                    410:  * Add the given header fields to the retained list.
                    411:  * If no arguments, print the current list of retained fields.
                    412:  */
                    413: int
1.10      millert   414: retfield(void *v)
1.1       deraadt   415: {
1.2       deraadt   416:        char **list = v;
1.1       deraadt   417:
1.3       millert   418:        return(ignore1(list, ignore + 1, "retained"));
1.1       deraadt   419: }
                    420:
                    421: /*
                    422:  * Add the given header fields to the ignored list.
                    423:  * If no arguments, print the current list of ignored fields.
                    424:  */
                    425: int
1.10      millert   426: igfield(void *v)
1.1       deraadt   427: {
1.2       deraadt   428:        char **list = v;
1.1       deraadt   429:
1.3       millert   430:        return(ignore1(list, ignore, "ignored"));
1.1       deraadt   431: }
                    432:
                    433: int
1.10      millert   434: saveretfield(void *v)
1.1       deraadt   435: {
1.2       deraadt   436:        char **list = v;
1.1       deraadt   437:
1.3       millert   438:        return(ignore1(list, saveignore + 1, "retained"));
1.1       deraadt   439: }
                    440:
                    441: int
1.10      millert   442: saveigfield(void *v)
1.1       deraadt   443: {
1.2       deraadt   444:        char **list = v;
1.1       deraadt   445:
1.3       millert   446:        return(ignore1(list, saveignore, "ignored"));
1.1       deraadt   447: }
                    448:
                    449: int
1.10      millert   450: ignore1(char **list, struct ignoretab *tab, char *which)
1.1       deraadt   451: {
1.3       millert   452:        char field[LINESIZE];
1.1       deraadt   453:        char **ap;
1.8       millert   454:        struct ignore *igp;
                    455:        int h;
1.1       deraadt   456:
1.5       millert   457:        if (*list == NULL)
1.3       millert   458:                return(igshow(tab, which));
1.1       deraadt   459:        for (ap = list; *ap != 0; ap++) {
1.10      millert   460:                istrlcpy(field, *ap, sizeof(field));
1.1       deraadt   461:                if (member(field, tab))
                    462:                        continue;
                    463:                h = hash(field);
1.4       millert   464:                igp = (struct ignore *)calloc(1, sizeof(struct ignore));
1.11      millert   465:                if (igp == NULL)
                    466:                        errx(1, "Out of memory");
                    467:                igp->i_field = strdup(field);
                    468:                if (igp->i_field == NULL)
                    469:                        errx(1, "Out of memory");
1.1       deraadt   470:                igp->i_link = tab->i_head[h];
                    471:                tab->i_head[h] = igp;
                    472:                tab->i_count++;
                    473:        }
1.3       millert   474:        return(0);
1.1       deraadt   475: }
                    476:
                    477: /*
                    478:  * Print out all currently retained fields.
                    479:  */
                    480: int
1.10      millert   481: igshow(struct ignoretab *tab, char *which)
1.1       deraadt   482: {
1.8       millert   483:        int h;
1.1       deraadt   484:        struct ignore *igp;
                    485:        char **ap, **ring;
                    486:
                    487:        if (tab->i_count == 0) {
                    488:                printf("No fields currently being %s.\n", which);
1.3       millert   489:                return(0);
1.1       deraadt   490:        }
1.4       millert   491:        ring = (char **)salloc((tab->i_count + 1) * sizeof(char *));
1.1       deraadt   492:        ap = ring;
                    493:        for (h = 0; h < HSHSIZE; h++)
                    494:                for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
                    495:                        *ap++ = igp->i_field;
                    496:        *ap = 0;
1.3       millert   497:        qsort(ring, tab->i_count, sizeof(char *), igcomp);
1.1       deraadt   498:        for (ap = ring; *ap != 0; ap++)
1.3       millert   499:                puts(*ap);
                    500:        return(0);
1.1       deraadt   501: }
                    502:
                    503: /*
                    504:  * Compare two names for sorting ignored field list.
                    505:  */
1.2       deraadt   506: static int
1.10      millert   507: igcomp(const void *l, const void *r)
1.1       deraadt   508: {
1.10      millert   509:
1.3       millert   510:        return(strcmp(*(char **)l, *(char **)r));
1.1       deraadt   511: }