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

Annotation of src/usr.bin/mail/cmd3.c, Revision 1.16

1.16    ! millert     1: /*     $OpenBSD: cmd3.c,v 1.15 2001/01/19 04:11:28 millert Exp $       */
1.5       millert     2: /*     $NetBSD: cmd3.c,v 1.8 1997/07/09 05:29:49 mikel Exp $   */
1.2       deraadt     3:
1.1       deraadt     4: /*
                      5:  * Copyright (c) 1980, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *     This product includes software developed by the University of
                     19:  *     California, Berkeley and its contributors.
                     20:  * 4. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  */
                     36:
                     37: #ifndef lint
1.2       deraadt    38: #if 0
1.5       millert    39: static char sccsid[] = "@(#)cmd3.c     8.2 (Berkeley) 4/20/95";
1.2       deraadt    40: #else
1.16    ! millert    41: static char rcsid[] = "$OpenBSD: cmd3.c,v 1.15 2001/01/19 04:11:28 millert Exp $";
1.2       deraadt    42: #endif
1.1       deraadt    43: #endif /* not lint */
                     44:
                     45: #include "rcv.h"
                     46: #include "extern.h"
                     47:
                     48: /*
                     49:  * Mail -- a mail program
                     50:  *
                     51:  * Still more user commands.
                     52:  */
1.2       deraadt    53: static int diction __P((const void *, const void *));
1.1       deraadt    54:
                     55: /*
                     56:  * Process a shell escape by saving signals, ignoring signals,
                     57:  * and forking a sh -c
                     58:  */
                     59: int
1.2       deraadt    60: shell(v)
                     61:        void *v;
1.1       deraadt    62: {
1.2       deraadt    63:        char *str = v;
1.1       deraadt    64:        char *shell;
                     65:        char cmd[BUFSIZ];
1.16    ! millert    66:        struct sigaction oact;
        !            67:        sigset_t oset;
1.1       deraadt    68:
1.16    ! millert    69:        (void)ignoresig(SIGINT, &oact, &oset);
        !            70:        (void)strlcpy(cmd, str, sizeof(cmd));
1.8       millert    71:        if (bangexp(cmd, sizeof(cmd)) < 0)
1.5       millert    72:                return(1);
1.14      millert    73:        shell = value("SHELL");
1.15      millert    74:        (void)run_command(shell, 0, 0, -1, "-c", cmd, NULL);
1.16    ! millert    75:        (void)sigprocmask(SIG_SETMASK, &oset, NULL);
        !            76:        (void)sigaction(SIGINT, &oact, NULL);
1.5       millert    77:        puts("!");
                     78:        return(0);
1.1       deraadt    79: }
                     80:
                     81: /*
                     82:  * Fork an interactive shell.
                     83:  */
                     84: /*ARGSUSED*/
                     85: int
1.2       deraadt    86: dosh(v)
                     87:        void *v;
1.1       deraadt    88: {
                     89:        char *shell;
1.16    ! millert    90:        struct sigaction oact;
        !            91:        sigset_t oset;
1.1       deraadt    92:
1.14      millert    93:        shell = value("SHELL");
1.16    ! millert    94:        (void)ignoresig(SIGINT, &oact, &oset);
1.15      millert    95:        (void)run_command(shell, 0, 0, -1, NULL, NULL, NULL);
1.16    ! millert    96:        (void)sigprocmask(SIG_SETMASK, &oset, NULL);
        !            97:        (void)sigaction(SIGINT, &oact, NULL);
1.1       deraadt    98:        putchar('\n');
1.5       millert    99:        return(0);
1.1       deraadt   100: }
                    101:
                    102: /*
                    103:  * Expand the shell escape by expanding unescaped !'s into the
                    104:  * last issued command where possible.
                    105:  */
                    106: int
1.8       millert   107: bangexp(str, strsize)
1.1       deraadt   108:        char *str;
1.8       millert   109:        size_t strsize;
1.1       deraadt   110: {
                    111:        char bangbuf[BUFSIZ];
1.8       millert   112:        static char lastbang[BUFSIZ];
1.10      millert   113:        char *cp, *cp2;
                    114:        int n, changed = 0;
1.1       deraadt   115:
                    116:        cp = str;
                    117:        cp2 = bangbuf;
                    118:        n = BUFSIZ;
                    119:        while (*cp) {
                    120:                if (*cp == '!') {
                    121:                        if (n < strlen(lastbang)) {
                    122: overf:
1.5       millert   123:                                puts("Command buffer overflow");
1.1       deraadt   124:                                return(-1);
                    125:                        }
                    126:                        changed++;
1.9       millert   127:                        strncpy(cp2, lastbang, sizeof(bangbuf) - (cp2 - bangbuf) - 1);
                    128:                        bangbuf[sizeof(bangbuf) - 1] = '\0';
1.1       deraadt   129:                        cp2 += strlen(lastbang);
                    130:                        n -= strlen(lastbang);
                    131:                        cp++;
                    132:                        continue;
                    133:                }
                    134:                if (*cp == '\\' && cp[1] == '!') {
                    135:                        if (--n <= 1)
                    136:                                goto overf;
                    137:                        *cp2++ = '!';
                    138:                        cp += 2;
                    139:                        changed++;
                    140:                }
                    141:                if (--n <= 1)
                    142:                        goto overf;
                    143:                *cp2++ = *cp++;
                    144:        }
                    145:        *cp2 = 0;
                    146:        if (changed) {
1.8       millert   147:                (void)printf("!%s\n", bangbuf);
                    148:                (void)fflush(stdout);
1.1       deraadt   149:        }
1.8       millert   150:        (void)strncpy(str, bangbuf, strsize - 1);
                    151:        str[strsize - 1]  = '\0';
                    152:        (void)strncpy(lastbang, bangbuf, sizeof(lastbang) - 1);
1.5       millert   153:        lastbang[sizeof(lastbang) - 1] = '\0';
1.1       deraadt   154:        return(0);
                    155: }
                    156:
                    157: /*
                    158:  * Print out a nice help message from some file or another.
                    159:  */
                    160: int
1.2       deraadt   161: help(v)
                    162:        void *v;
1.1       deraadt   163: {
                    164:
1.14      millert   165:        (void)run_command(value("PAGER"), 0, -1, -1, _PATH_HELP, NULL);
1.1       deraadt   166:        return(0);
                    167: }
                    168:
                    169: /*
                    170:  * Change user's working directory.
                    171:  */
                    172: int
1.2       deraadt   173: schdir(v)
                    174:        void *v;
1.1       deraadt   175: {
1.2       deraadt   176:        char **arglist = v;
1.1       deraadt   177:        char *cp;
                    178:
1.13      millert   179:        if (*arglist == NULL) {
                    180:                if (homedir == NULL)
                    181:                        return(1);
1.1       deraadt   182:                cp = homedir;
1.13      millert   183:        } else {
1.7       millert   184:                if ((cp = expand(*arglist)) == NULL)
1.1       deraadt   185:                        return(1);
1.13      millert   186:        }
1.1       deraadt   187:        if (chdir(cp) < 0) {
1.12      millert   188:                warn("%s", cp);
1.1       deraadt   189:                return(1);
                    190:        }
1.5       millert   191:        return(0);
1.1       deraadt   192: }
                    193:
                    194: int
1.2       deraadt   195: respond(v)
                    196:        void *v;
1.1       deraadt   197: {
1.2       deraadt   198:        int *msgvec = v;
1.7       millert   199:        if (value("Replyall") == NULL)
1.5       millert   200:                return(_respond(msgvec));
1.1       deraadt   201:        else
1.5       millert   202:                return(_Respond(msgvec));
1.1       deraadt   203: }
                    204:
                    205: /*
                    206:  * Reply to a list of messages.  Extract each name from the
                    207:  * message header and send them off to mail1()
                    208:  */
                    209: int
                    210: _respond(msgvec)
                    211:        int *msgvec;
                    212: {
                    213:        struct message *mp;
                    214:        char *cp, *rcv, *replyto;
                    215:        char **ap;
                    216:        struct name *np;
                    217:        struct header head;
                    218:
                    219:        if (msgvec[1] != 0) {
1.5       millert   220:                puts("Sorry, can't reply to multiple messages at once");
1.1       deraadt   221:                return(1);
                    222:        }
                    223:        mp = &message[msgvec[0] - 1];
                    224:        touch(mp);
                    225:        dot = mp;
1.7       millert   226:        if ((rcv = skin(hfield("from", mp))) == NULL)
1.1       deraadt   227:                rcv = skin(nameof(mp, 1));
1.7       millert   228:        if ((replyto = skin(hfield("reply-to", mp))) != NULL)
1.1       deraadt   229:                np = extract(replyto, GTO);
1.7       millert   230:        else if ((cp = skin(hfield("to", mp))) != NULL)
1.1       deraadt   231:                np = extract(cp, GTO);
                    232:        else
                    233:                np = NIL;
                    234:        np = elide(np);
                    235:        /*
                    236:         * Delete my name from the reply list,
                    237:         * and with it, all my alternate names.
                    238:         */
                    239:        np = delname(np, myname);
                    240:        if (altnames)
                    241:                for (ap = altnames; *ap; ap++)
                    242:                        np = delname(np, *ap);
1.7       millert   243:        if (np != NIL && replyto == NULL)
1.1       deraadt   244:                np = cat(np, extract(rcv, GTO));
                    245:        else if (np == NIL) {
1.7       millert   246:                if (replyto != NULL)
1.5       millert   247:                        puts("Empty reply-to field -- replying to author");
1.1       deraadt   248:                np = extract(rcv, GTO);
                    249:        }
                    250:        head.h_to = np;
1.7       millert   251:        if ((head.h_subject = hfield("subject", mp)) == NULL)
1.1       deraadt   252:                head.h_subject = hfield("subj", mp);
                    253:        head.h_subject = reedit(head.h_subject);
1.7       millert   254:        if (replyto == NULL && (cp = skin(hfield("cc", mp))) != NULL) {
1.1       deraadt   255:                np = elide(extract(cp, GCC));
                    256:                np = delname(np, myname);
                    257:                if (altnames != 0)
                    258:                        for (ap = altnames; *ap; ap++)
                    259:                                np = delname(np, *ap);
                    260:                head.h_cc = np;
                    261:        } else
                    262:                head.h_cc = NIL;
                    263:        head.h_bcc = NIL;
                    264:        head.h_smopts = NIL;
                    265:        mail1(&head, 1);
                    266:        return(0);
                    267: }
                    268:
                    269: /*
                    270:  * Modify the subject we are replying to to begin with Re: if
                    271:  * it does not already.
                    272:  */
                    273: char *
                    274: reedit(subj)
1.10      millert   275:        char *subj;
1.1       deraadt   276: {
                    277:        char *newsubj;
                    278:
1.7       millert   279:        if (subj == NULL)
                    280:                return(NULL);
1.1       deraadt   281:        if ((subj[0] == 'r' || subj[0] == 'R') &&
                    282:            (subj[1] == 'e' || subj[1] == 'E') &&
                    283:            subj[2] == ':')
1.5       millert   284:                return(subj);
1.1       deraadt   285:        newsubj = salloc(strlen(subj) + 5);
                    286:        strcpy(newsubj, "Re: ");
                    287:        strcpy(newsubj + 4, subj);
1.5       millert   288:        return(newsubj);
1.1       deraadt   289: }
                    290:
                    291: /*
1.14      millert   292:  * Mark new the named messages, so that they will be left in the system
                    293:  * mailbox as unread.
                    294:  */
                    295: int
                    296: marknew(v)
                    297:        void *v;
                    298: {
                    299:        int *msgvec = v;
                    300:        int *ip;
                    301:
                    302:        for (ip = msgvec; *ip != NULL; ip++) {
                    303:                dot = &message[*ip-1];
                    304:                dot->m_flag &= ~(MBOX|MREAD|MTOUCH);
                    305:                dot->m_flag |= MNEW|MSTATUS;
                    306:        }
                    307:        return(0);
                    308: }
                    309:
                    310: /*
1.1       deraadt   311:  * Preserve the named messages, so that they will be sent
                    312:  * back to the system mailbox.
                    313:  */
                    314: int
1.2       deraadt   315: preserve(v)
                    316:        void *v;
1.1       deraadt   317: {
1.2       deraadt   318:        int *msgvec = v;
1.10      millert   319:        int *ip, mesg;
                    320:        struct message *mp;
1.1       deraadt   321:
                    322:        if (edit) {
1.5       millert   323:                puts("Cannot \"preserve\" in edit mode");
1.1       deraadt   324:                return(1);
                    325:        }
                    326:        for (ip = msgvec; *ip != NULL; ip++) {
                    327:                mesg = *ip;
                    328:                mp = &message[mesg-1];
                    329:                mp->m_flag |= MPRESERVE;
                    330:                mp->m_flag &= ~MBOX;
                    331:                dot = mp;
                    332:        }
                    333:        return(0);
                    334: }
                    335:
                    336: /*
                    337:  * Mark all given messages as unread.
                    338:  */
                    339: int
1.2       deraadt   340: unread(v)
                    341:        void *v;
1.1       deraadt   342: {
1.14      millert   343:        int *msgvec = v;
1.10      millert   344:        int *ip;
1.1       deraadt   345:
                    346:        for (ip = msgvec; *ip != NULL; ip++) {
                    347:                dot = &message[*ip-1];
                    348:                dot->m_flag &= ~(MREAD|MTOUCH);
                    349:                dot->m_flag |= MSTATUS;
                    350:        }
                    351:        return(0);
                    352: }
                    353:
                    354: /*
                    355:  * Print the size of each message.
                    356:  */
                    357: int
1.2       deraadt   358: messize(v)
                    359:        void *v;
1.1       deraadt   360: {
1.2       deraadt   361:        int *msgvec = v;
1.10      millert   362:        struct message *mp;
                    363:        int *ip, mesg;
1.1       deraadt   364:
                    365:        for (ip = msgvec; *ip != NULL; ip++) {
                    366:                mesg = *ip;
                    367:                mp = &message[mesg-1];
1.3       millert   368:                printf("%d: %d/%d\n", mesg, mp->m_lines, mp->m_size);
1.1       deraadt   369:        }
                    370:        return(0);
                    371: }
                    372:
                    373: /*
                    374:  * Quit quickly.  If we are sourcing, just pop the input level
                    375:  * by returning an error.
                    376:  */
                    377: int
1.2       deraadt   378: rexit(v)
                    379:        void *v;
1.1       deraadt   380: {
                    381:        if (sourcing)
                    382:                return(1);
1.2       deraadt   383:        exit(0);
1.1       deraadt   384:        /*NOTREACHED*/
                    385: }
                    386:
                    387: /*
                    388:  * Set or display a variable value.  Syntax is similar to that
                    389:  * of csh.
                    390:  */
                    391: int
1.2       deraadt   392: set(v)
                    393:        void *v;
1.1       deraadt   394: {
1.2       deraadt   395:        char **arglist = v;
1.10      millert   396:        struct var *vp;
                    397:        char *cp, *cp2;
1.1       deraadt   398:        char varbuf[BUFSIZ], **ap, **p;
                    399:        int errs, h, s;
                    400:
1.7       millert   401:        if (*arglist == NULL) {
1.1       deraadt   402:                for (h = 0, s = 1; h < HSHSIZE; h++)
                    403:                        for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
                    404:                                s++;
1.6       millert   405:                ap = (char **)salloc(s * sizeof(*ap));
1.1       deraadt   406:                for (h = 0, p = ap; h < HSHSIZE; h++)
                    407:                        for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
                    408:                                *p++ = vp->v_name;
1.7       millert   409:                *p = NULL;
1.1       deraadt   410:                sort(ap);
1.7       millert   411:                for (p = ap; *p != NULL; p++)
1.1       deraadt   412:                        printf("%s\t%s\n", *p, value(*p));
                    413:                return(0);
                    414:        }
                    415:        errs = 0;
1.7       millert   416:        for (ap = arglist; *ap != NULL; ap++) {
1.1       deraadt   417:                cp = *ap;
                    418:                cp2 = varbuf;
                    419:                while (*cp != '=' && *cp != '\0')
                    420:                        *cp2++ = *cp++;
                    421:                *cp2 = '\0';
                    422:                if (*cp == '\0')
                    423:                        cp = "";
                    424:                else
                    425:                        cp++;
                    426:                if (equal(varbuf, "")) {
1.5       millert   427:                        puts("Non-null variable name required");
1.1       deraadt   428:                        errs++;
                    429:                        continue;
                    430:                }
                    431:                assign(varbuf, cp);
                    432:        }
                    433:        return(errs);
                    434: }
                    435:
                    436: /*
                    437:  * Unset a bunch of variable values.
                    438:  */
                    439: int
1.2       deraadt   440: unset(v)
                    441:        void *v;
1.1       deraadt   442: {
1.2       deraadt   443:        char **arglist = v;
1.10      millert   444:        struct var *vp, *vp2;
1.1       deraadt   445:        int errs, h;
                    446:        char **ap;
                    447:
                    448:        errs = 0;
1.7       millert   449:        for (ap = arglist; *ap != NULL; ap++) {
1.1       deraadt   450:                if ((vp2 = lookup(*ap)) == NOVAR) {
                    451:                        if (!sourcing) {
                    452:                                printf("\"%s\": undefined variable\n", *ap);
                    453:                                errs++;
                    454:                        }
                    455:                        continue;
                    456:                }
                    457:                h = hash(*ap);
                    458:                if (vp2 == variables[h]) {
                    459:                        variables[h] = variables[h]->v_link;
                    460:                        vfree(vp2->v_name);
                    461:                        vfree(vp2->v_value);
1.6       millert   462:                        (void)free(vp2);
1.1       deraadt   463:                        continue;
                    464:                }
                    465:                for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
                    466:                        ;
                    467:                vp->v_link = vp2->v_link;
                    468:                vfree(vp2->v_name);
                    469:                vfree(vp2->v_value);
1.6       millert   470:                (void)free(vp2);
1.1       deraadt   471:        }
                    472:        return(errs);
                    473: }
                    474:
                    475: /*
                    476:  * Put add users to a group.
                    477:  */
                    478: int
1.2       deraadt   479: group(v)
                    480:        void *v;
1.1       deraadt   481: {
1.2       deraadt   482:        char **argv = v;
1.10      millert   483:        struct grouphead *gh;
                    484:        struct group *gp;
1.1       deraadt   485:        char **ap, *gname, **p;
1.10      millert   486:        int h, s;
1.1       deraadt   487:
1.7       millert   488:        if (*argv == NULL) {
1.1       deraadt   489:                for (h = 0, s = 1; h < HSHSIZE; h++)
                    490:                        for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
                    491:                                s++;
1.6       millert   492:                ap = (char **)salloc(s * sizeof(*ap));
1.1       deraadt   493:                for (h = 0, p = ap; h < HSHSIZE; h++)
                    494:                        for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
                    495:                                *p++ = gh->g_name;
1.7       millert   496:                *p = NULL;
1.1       deraadt   497:                sort(ap);
1.7       millert   498:                for (p = ap; *p != NULL; p++)
1.1       deraadt   499:                        printgroup(*p);
                    500:                return(0);
                    501:        }
1.7       millert   502:        if (argv[1] == NULL) {
1.1       deraadt   503:                printgroup(*argv);
                    504:                return(0);
                    505:        }
                    506:        gname = *argv;
                    507:        h = hash(gname);
                    508:        if ((gh = findgroup(gname)) == NOGRP) {
1.6       millert   509:                gh = (struct grouphead *)calloc(sizeof(*gh), 1);
1.1       deraadt   510:                gh->g_name = vcopy(gname);
                    511:                gh->g_list = NOGE;
                    512:                gh->g_link = groups[h];
                    513:                groups[h] = gh;
                    514:        }
                    515:
                    516:        /*
                    517:         * Insert names from the command list into the group.
                    518:         * Who cares if there are duplicates?  They get tossed
                    519:         * later anyway.
                    520:         */
                    521:
1.7       millert   522:        for (ap = argv+1; *ap != NULL; ap++) {
1.6       millert   523:                gp = (struct group *)calloc(sizeof(*gp), 1);
1.1       deraadt   524:                gp->ge_name = vcopy(*ap);
                    525:                gp->ge_link = gh->g_list;
                    526:                gh->g_list = gp;
                    527:        }
                    528:        return(0);
                    529: }
                    530:
                    531: /*
                    532:  * Sort the passed string vecotor into ascending dictionary
                    533:  * order.
                    534:  */
                    535: void
                    536: sort(list)
                    537:        char **list;
                    538: {
1.10      millert   539:        char **ap;
1.1       deraadt   540:
1.7       millert   541:        for (ap = list; *ap != NULL; ap++)
1.1       deraadt   542:                ;
                    543:        if (ap-list < 2)
                    544:                return;
                    545:        qsort(list, ap-list, sizeof(*list), diction);
                    546: }
                    547:
                    548: /*
                    549:  * Do a dictionary order comparison of the arguments from
                    550:  * qsort.
                    551:  */
1.2       deraadt   552: static int
1.1       deraadt   553: diction(a, b)
                    554:        const void *a, *b;
                    555: {
                    556:        return(strcmp(*(char **)a, *(char **)b));
                    557: }
                    558:
                    559: /*
                    560:  * The do nothing command for comments.
                    561:  */
                    562:
                    563: /*ARGSUSED*/
                    564: int
1.2       deraadt   565: null(v)
                    566:        void *v;
1.1       deraadt   567: {
1.5       millert   568:        return(0);
1.1       deraadt   569: }
                    570:
                    571: /*
                    572:  * Change to another file.  With no argument, print information about
                    573:  * the current file.
                    574:  */
                    575: int
1.2       deraadt   576: file(v)
                    577:        void *v;
1.1       deraadt   578: {
1.2       deraadt   579:        char **argv = v;
1.1       deraadt   580:
1.7       millert   581:        if (argv[0] == NULL) {
1.5       millert   582:                newfileinfo(0);
1.11      millert   583:                clearnew();
1.5       millert   584:                return(0);
1.1       deraadt   585:        }
                    586:        if (setfile(*argv) < 0)
1.5       millert   587:                return(1);
1.1       deraadt   588:        announce();
1.5       millert   589:        return(0);
1.1       deraadt   590: }
                    591:
                    592: /*
                    593:  * Expand file names like echo
                    594:  */
                    595: int
1.2       deraadt   596: echo(v)
                    597:        void *v;
1.1       deraadt   598: {
1.2       deraadt   599:        char **argv = v;
1.10      millert   600:        char **ap, *cp;
1.1       deraadt   601:
1.7       millert   602:        for (ap = argv; *ap != NULL; ap++) {
1.1       deraadt   603:                cp = *ap;
1.7       millert   604:                if ((cp = expand(cp)) != NULL) {
1.1       deraadt   605:                        if (ap != argv)
                    606:                                putchar(' ');
1.5       millert   607:                        fputs(cp, stdout);
1.1       deraadt   608:                }
                    609:        }
                    610:        putchar('\n');
1.5       millert   611:        return(0);
1.1       deraadt   612: }
                    613:
                    614: int
1.2       deraadt   615: Respond(v)
                    616:        void *v;
1.1       deraadt   617: {
1.2       deraadt   618:        int *msgvec = v;
1.7       millert   619:        if (value("Replyall") == NULL)
1.5       millert   620:                return(_Respond(msgvec));
1.1       deraadt   621:        else
1.5       millert   622:                return(_respond(msgvec));
1.1       deraadt   623: }
                    624:
                    625: /*
                    626:  * Reply to a series of messages by simply mailing to the senders
                    627:  * and not messing around with the To: and Cc: lists as in normal
                    628:  * reply.
                    629:  */
                    630: int
                    631: _Respond(msgvec)
                    632:        int msgvec[];
                    633: {
                    634:        struct header head;
                    635:        struct message *mp;
1.10      millert   636:        int *ap;
                    637:        char *cp;
1.1       deraadt   638:
                    639:        head.h_to = NIL;
                    640:        for (ap = msgvec; *ap != 0; ap++) {
                    641:                mp = &message[*ap - 1];
                    642:                touch(mp);
                    643:                dot = mp;
1.7       millert   644:                if ((cp = skin(hfield("from", mp))) == NULL)
1.1       deraadt   645:                        cp = skin(nameof(mp, 2));
                    646:                head.h_to = cat(head.h_to, extract(cp, GTO));
                    647:        }
                    648:        if (head.h_to == NIL)
1.5       millert   649:                return(0);
1.1       deraadt   650:        mp = &message[msgvec[0] - 1];
1.7       millert   651:        if ((head.h_subject = hfield("subject", mp)) == NULL)
1.1       deraadt   652:                head.h_subject = hfield("subj", mp);
                    653:        head.h_subject = reedit(head.h_subject);
                    654:        head.h_cc = NIL;
                    655:        head.h_bcc = NIL;
                    656:        head.h_smopts = NIL;
                    657:        mail1(&head, 1);
1.5       millert   658:        return(0);
1.1       deraadt   659: }
                    660:
                    661: /*
                    662:  * Conditional commands.  These allow one to parameterize one's
                    663:  * .mailrc and do some things if sending, others if receiving.
                    664:  */
                    665: int
1.2       deraadt   666: ifcmd(v)
                    667:        void *v;
1.1       deraadt   668: {
1.2       deraadt   669:        char **argv = v;
1.10      millert   670:        char *cp;
1.1       deraadt   671:
                    672:        if (cond != CANY) {
1.5       millert   673:                puts("Illegal nested \"if\"");
1.1       deraadt   674:                return(1);
                    675:        }
                    676:        cond = CANY;
                    677:        cp = argv[0];
                    678:        switch (*cp) {
                    679:        case 'r': case 'R':
                    680:                cond = CRCV;
                    681:                break;
                    682:
                    683:        case 's': case 'S':
                    684:                cond = CSEND;
                    685:                break;
                    686:
                    687:        default:
                    688:                printf("Unrecognized if-keyword: \"%s\"\n", cp);
                    689:                return(1);
                    690:        }
                    691:        return(0);
                    692: }
                    693:
                    694: /*
                    695:  * Implement 'else'.  This is pretty simple -- we just
                    696:  * flip over the conditional flag.
                    697:  */
                    698: int
1.2       deraadt   699: elsecmd(v)
                    700:        void *v;
1.1       deraadt   701: {
                    702:
                    703:        switch (cond) {
                    704:        case CANY:
1.5       millert   705:                puts("\"Else\" without matching \"if\"");
1.1       deraadt   706:                return(1);
                    707:
                    708:        case CSEND:
                    709:                cond = CRCV;
                    710:                break;
                    711:
                    712:        case CRCV:
                    713:                cond = CSEND;
                    714:                break;
                    715:
                    716:        default:
1.5       millert   717:                puts("mail's idea of conditions is screwed up");
1.1       deraadt   718:                cond = CANY;
                    719:                break;
                    720:        }
                    721:        return(0);
                    722: }
                    723:
                    724: /*
                    725:  * End of if statement.  Just set cond back to anything.
                    726:  */
                    727: int
1.2       deraadt   728: endifcmd(v)
                    729:        void *v;
1.1       deraadt   730: {
                    731:
                    732:        if (cond == CANY) {
1.5       millert   733:                puts("\"Endif\" without matching \"if\"");
1.1       deraadt   734:                return(1);
                    735:        }
                    736:        cond = CANY;
                    737:        return(0);
                    738: }
                    739:
                    740: /*
                    741:  * Set the list of alternate names.
                    742:  */
                    743: int
1.2       deraadt   744: alternates(v)
                    745:        void *v;
1.1       deraadt   746: {
1.2       deraadt   747:        char **namelist = v;
1.10      millert   748:        char **ap, **ap2, *cp;
                    749:        int c;
1.1       deraadt   750:
                    751:        c = argcount(namelist) + 1;
                    752:        if (c == 1) {
                    753:                if (altnames == 0)
                    754:                        return(0);
                    755:                for (ap = altnames; *ap; ap++)
                    756:                        printf("%s ", *ap);
1.5       millert   757:                putchar('\n');
1.1       deraadt   758:                return(0);
                    759:        }
                    760:        if (altnames != 0)
1.6       millert   761:                (void)free(altnames);
                    762:        altnames = (char **)calloc(c, sizeof(char *));
1.1       deraadt   763:        for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) {
1.6       millert   764:                cp = (char *)calloc(strlen(*ap) + 1, sizeof(char));
1.1       deraadt   765:                strcpy(cp, *ap);
                    766:                *ap2 = cp;
                    767:        }
                    768:        *ap2 = 0;
                    769:        return(0);
                    770: }