home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / metamail / tahoe / cmd3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-30  |  15.3 KB  |  870 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #ifdef notdef
  14. static char sccsid[] = "@(#)cmd3.c    5.5 (Berkeley) 2/18/88";
  15. #endif /* notdef */
  16.  
  17. #include "rcv.h"
  18. #include <sys/stat.h>
  19. #include <sys/wait.h>
  20.  
  21. /*
  22.  * Mail -- a mail program
  23.  *
  24.  * Still more user commands.
  25.  */
  26.  
  27. /*
  28.  * Process a shell escape by saving signals, ignoring signals,
  29.  * and forking a sh -c
  30.  */
  31.  
  32. shell(str)
  33.     char *str;
  34. {
  35.     int (*sigint)(), (*sigquit)();
  36.     union wait stat;
  37.     register int t;
  38.     char *Shell;
  39.     char cmd[BUFSIZ];
  40.  
  41.     strcpy(cmd, str);
  42.     if (bangexp(cmd) < 0)
  43.         return(-1);
  44.     if ((Shell = value("SHELL")) == NOSTR)
  45.         Shell = SHELL;
  46.     sigint = signal(SIGINT, SIG_IGN);
  47.     sigquit = signal(SIGQUIT, SIG_IGN);
  48.     t = vfork();
  49.     if (t == 0) {
  50.         if (sigint != SIG_IGN)
  51.             signal(SIGINT, SIG_DFL);
  52.         if (sigquit != SIG_IGN)
  53.             signal(SIGQUIT, SIG_DFL);
  54.         execl(Shell, Shell, "-c", cmd, (char *)0);
  55.         perror(Shell);
  56.         _exit(1);
  57.     }
  58.     while (wait(&stat) != t)
  59.         ;
  60.     if (t == -1)
  61.         perror("fork");
  62.     signal(SIGINT, sigint);
  63.     signal(SIGQUIT, sigquit);
  64.     printf("!\n");
  65.     return(0);
  66. }
  67.  
  68. /*
  69.  * Fork an interactive shell.
  70.  */
  71.  
  72. /*ARGSUSED*/
  73. dosh(str)
  74.     char *str;
  75. {
  76.     int (*sigint)(), (*sigquit)();
  77.     union wait stat;
  78.     register int t;
  79.     char *Shell;
  80.  
  81.     if ((Shell = value("SHELL")) == NOSTR)
  82.         Shell = SHELL;
  83.     sigint = signal(SIGINT, SIG_IGN);
  84.     sigquit = signal(SIGQUIT, SIG_IGN);
  85.     t = vfork();
  86.     if (t == 0) {
  87.         if (sigint != SIG_IGN)
  88.             signal(SIGINT, SIG_DFL);
  89.         if (sigquit != SIG_IGN)
  90.             signal(SIGQUIT, SIG_DFL);
  91.         execl(Shell, Shell, (char *)0);
  92.         perror(Shell);
  93.         _exit(1);
  94.     }
  95.     while (wait(&stat) != t)
  96.         ;
  97.     if (t == -1)
  98.         perror("fork");
  99.     signal(SIGINT, sigint);
  100.     signal(SIGQUIT, sigquit);
  101.     putchar('\n');
  102.     return(0);
  103. }
  104.  
  105. /*
  106.  * Expand the shell escape by expanding unescaped !'s into the
  107.  * last issued command where possible.
  108.  */
  109.  
  110. char    lastbang[128];
  111.  
  112. bangexp(str)
  113.     char *str;
  114. {
  115.     char bangbuf[BUFSIZ];
  116.     register char *cp, *cp2;
  117.     register int n;
  118.     int changed = 0;
  119.  
  120.     cp = str;
  121.     cp2 = bangbuf;
  122.     n = BUFSIZ;
  123.     while (*cp) {
  124.         if (*cp == '!') {
  125.             if (n < strlen(lastbang)) {
  126. overf:
  127.                 printf("Command buffer overflow\n");
  128.                 return(-1);
  129.             }
  130.             changed++;
  131.             strcpy(cp2, lastbang);
  132.             cp2 += strlen(lastbang);
  133.             n -= strlen(lastbang);
  134.             cp++;
  135.             continue;
  136.         }
  137.         if (*cp == '\\' && cp[1] == '!') {
  138.             if (--n <= 1)
  139.                 goto overf;
  140.             *cp2++ = '!';
  141.             cp += 2;
  142.             changed++;
  143.         }
  144.         if (--n <= 1)
  145.             goto overf;
  146.         *cp2++ = *cp++;
  147.     }
  148.     *cp2 = 0;
  149.     if (changed) {
  150.         printf("!%s\n", bangbuf);
  151.         fflush(stdout);
  152.     }
  153.     strcpy(str, bangbuf);
  154.     strncpy(lastbang, bangbuf, 128);
  155.     lastbang[127] = 0;
  156.     return(0);
  157. }
  158.  
  159. /*
  160.  * Print out a nice help message from some file or another.
  161.  */
  162.  
  163. help()
  164. {
  165.     register c;
  166.     register FILE *f;
  167.  
  168.     if ((f = fopen(HELPFILE, "r")) == NULL) {
  169.         perror(HELPFILE);
  170.         return(1);
  171.     }
  172.     while ((c = getc(f)) != EOF)
  173.         putchar(c);
  174.     fclose(f);
  175.     return(0);
  176. }
  177.  
  178. /*
  179.  * Change user's working directory.
  180.  */
  181.  
  182. schdir(str)
  183.     char *str;
  184. {
  185.     register char *cp;
  186.  
  187.     for (cp = str; *cp == ' '; cp++)
  188.         ;
  189.     if (*cp == '\0')
  190.         cp = homedir;
  191.     else
  192.         if ((cp = expand(cp)) == NOSTR)
  193.             return(1);
  194.     if (chdir(cp) < 0) {
  195.         perror(cp);
  196.         return(1);
  197.     }
  198.     return(0);
  199. }
  200.  
  201. respond(msgvec)
  202.     int *msgvec;
  203. {
  204.     if (value("Replyall") == NOSTR)
  205.         return (_respond(msgvec));
  206.     else
  207.         return (_Respond(msgvec));
  208. }
  209.  
  210. /*
  211.  * Reply to a list of messages.  Extract each name from the
  212.  * message header and send them off to mail1()
  213.  */
  214.  
  215. _respond(msgvec)
  216.     int *msgvec;
  217. {
  218.     struct message *mp;
  219.     char *cp, *rcv, *replyto;
  220.     char buf[2 * LINESIZE], **ap;
  221.     struct name *np;
  222.     struct header head;
  223.  
  224.     if (msgvec[1] != 0) {
  225.         printf("Sorry, can't reply to multiple messages at once\n");
  226.         return(1);
  227.     }
  228.     mp = &message[msgvec[0] - 1];
  229.     dot = mp;
  230.     rcv = NOSTR;
  231.     cp = skin(nameof(mp, 1));
  232.     if (cp != NOSTR)
  233.         rcv = cp;
  234.     cp = skin(hfield("from", mp));
  235.     if (cp != NOSTR)
  236.         rcv = cp;
  237.     replyto = skin(hfield("reply-to", mp));
  238.     strcpy(buf, "");
  239.     if (replyto != NOSTR)
  240.         strcpy(buf, replyto);
  241.     else {
  242.         cp = skin(hfield("to", mp));
  243.         if (cp != NOSTR)
  244.             strcpy(buf, cp);
  245.     }
  246.     np = elide(extract(buf, GTO));
  247.     mapf(np, rcv);
  248.     /*
  249.      * Delete my name from the reply list,
  250.      * and with it, all my alternate names.
  251.      */
  252.     np = delname(np, myname, icequal);
  253.     if (altnames)
  254.         for (ap = altnames; *ap; ap++)
  255.             np = delname(np, *ap, icequal);
  256.     head.h_seq = 1;
  257.     cp = detract(np, 0);
  258.     if (cp != NOSTR && replyto == NOSTR) {
  259.         strcpy(buf, cp);
  260.         strcat(buf, " ");
  261.         strcat(buf, rcv);
  262.     }
  263.     else {
  264.         if (cp == NOSTR && replyto != NOSTR)
  265.             printf("Empty reply-to field -- replying to author\n");
  266.         if (cp == NOSTR)
  267.             strcpy(buf, rcv);
  268.         else
  269.             strcpy(buf, cp);
  270.     }
  271.     head.h_to = buf;
  272.     head.h_subject = hfield("subject", mp);
  273.     if (head.h_subject == NOSTR)
  274.         head.h_subject = hfield("subj", mp);
  275.     head.h_subject = reedit(head.h_subject);
  276.     head.h_cc = NOSTR;
  277.     if (replyto == NOSTR) {
  278.         cp = skin(hfield("cc", mp));
  279.         if (cp != NOSTR) {
  280.             np = elide(extract(cp, GCC));
  281.             mapf(np, rcv);
  282.             np = delname(np, myname, icequal);
  283.             if (altnames != 0)
  284.                 for (ap = altnames; *ap; ap++)
  285.                     np = delname(np, *ap, icequal);
  286.             head.h_cc = detract(np, 0);
  287.         }
  288.     }
  289.     head.h_bcc = NOSTR;
  290.     mail1(&head);
  291.     return(0);
  292. }
  293.  
  294. /*
  295.  * Modify the subject we are replying to to begin with Re: if
  296.  * it does not already.
  297.  */
  298.  
  299. char *
  300. reedit(subj)
  301.     char *subj;
  302. {
  303.     char sbuf[10];
  304.     register char *newsubj;
  305.  
  306.     if (subj == NOSTR)
  307.         return(NOSTR);
  308.     strncpy(sbuf, subj, 3);
  309.     sbuf[3] = 0;
  310.     if (icequal(sbuf, "re:"))
  311.         return(subj);
  312.     newsubj = salloc(strlen(subj) + 6);
  313.     sprintf(newsubj, "Re: %s", subj);
  314.     return(newsubj);
  315. }
  316.  
  317. /*
  318.  * Preserve the named messages, so that they will be sent
  319.  * back to the system mailbox.
  320.  */
  321.  
  322. preserve(msgvec)
  323.     int *msgvec;
  324. {
  325.     register struct message *mp;
  326.     register int *ip, mesg;
  327.  
  328.     if (edit) {
  329.         printf("Cannot \"preserve\" in edit mode\n");
  330.         return(1);
  331.     }
  332.     for (ip = msgvec; *ip != NULL; ip++) {
  333.         mesg = *ip;
  334.         mp = &message[mesg-1];
  335.         mp->m_flag |= MPRESERVE;
  336.         mp->m_flag &= ~MBOX;
  337.         dot = mp;
  338.     }
  339.     return(0);
  340. }
  341.  
  342. /*
  343.  * Mark all given messages as unread.
  344.  */
  345. unread(msgvec)
  346.     int    msgvec[];
  347. {
  348.     register int *ip;
  349.  
  350.     for (ip = msgvec; *ip != NULL; ip++) {
  351.         dot = &message[*ip-1];
  352.         dot->m_flag &= ~(MREAD|MTOUCH);
  353.         dot->m_flag |= MSTATUS;
  354.     }
  355.     return(0);
  356. }
  357.  
  358. /*
  359.  * Print the size of each message.
  360.  */
  361.  
  362. messize(msgvec)
  363.     int *msgvec;
  364. {
  365.     register struct message *mp;
  366.     register int *ip, mesg;
  367.  
  368.     for (ip = msgvec; *ip != NULL; ip++) {
  369.         mesg = *ip;
  370.         mp = &message[mesg-1];
  371.         printf("%d: %d/%ld\n", mesg, mp->m_lines, mp->m_size);
  372.     }
  373.     return(0);
  374. }
  375.  
  376. /*
  377.  * Quit quickly.  If we are sourcing, just pop the input level
  378.  * by returning an error.
  379.  */
  380.  
  381. rexit(e)
  382. {
  383.     if (sourcing)
  384.         return(1);
  385.     if (Tflag != NOSTR)
  386.         close(creat(Tflag, 0600));
  387.     exit(e);
  388.     /*NOTREACHED*/
  389. }
  390.  
  391. /*
  392.  * Set or display a variable value.  Syntax is similar to that
  393.  * of csh.
  394.  */
  395.  
  396. set(arglist)
  397.     char **arglist;
  398. {
  399.     register struct var *vp;
  400.     register char *cp, *cp2;
  401.     char varbuf[BUFSIZ], **ap, **p;
  402.     int errs, h, s;
  403.  
  404.     if (argcount(arglist) == 0) {
  405.         for (h = 0, s = 1; h < HSHSIZE; h++)
  406.             for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
  407.                 s++;
  408.         ap = (char **) salloc(s * sizeof *ap);
  409.         for (h = 0, p = ap; h < HSHSIZE; h++)
  410.             for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
  411.                 *p++ = vp->v_name;
  412.         *p = NOSTR;
  413.         sort(ap);
  414.         for (p = ap; *p != NOSTR; p++)
  415.             printf("%s\t%s\n", *p, value(*p));
  416.         return(0);
  417.     }
  418.     errs = 0;
  419.     for (ap = arglist; *ap != NOSTR; ap++) {
  420.         cp = *ap;
  421.         cp2 = varbuf;
  422.         while (*cp != '=' && *cp != '\0')
  423.             *cp2++ = *cp++;
  424.         *cp2 = '\0';
  425.         if (*cp == '\0')
  426.             cp = "";
  427.         else
  428.             cp++;
  429.         if (equal(varbuf, "")) {
  430.             printf("Non-null variable name required\n");
  431.             errs++;
  432.             continue;
  433.         }
  434.         assign(varbuf, cp);
  435.     }
  436.     return(errs);
  437. }
  438.  
  439. /*
  440.  * Unset a bunch of variable values.
  441.  */
  442.  
  443. unset(arglist)
  444.     char **arglist;
  445. {
  446.     register struct var *vp, *vp2;
  447.     int errs, h;
  448.     char **ap;
  449.  
  450.     errs = 0;
  451.     for (ap = arglist; *ap != NOSTR; ap++) {
  452.         if ((vp2 = lookup(*ap)) == NOVAR) {
  453.             if (!sourcing) {
  454.                 printf("\"%s\": undefined variable\n", *ap);
  455.                 errs++;
  456.             }
  457.             continue;
  458.         }
  459.         h = hash(*ap);
  460.         if (vp2 == variables[h]) {
  461.             variables[h] = variables[h]->v_link;
  462.             vfree(vp2->v_name);
  463.             vfree(vp2->v_value);
  464.             cfree((char *)vp2);
  465.             continue;
  466.         }
  467.         for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
  468.             ;
  469.         vp->v_link = vp2->v_link;
  470.         vfree(vp2->v_name);
  471.         vfree(vp2->v_value);
  472.         cfree((char *) vp2);
  473.     }
  474.     return(errs);
  475. }
  476.  
  477. /*
  478.  * Put add users to a group.
  479.  */
  480.  
  481. group(argv)
  482.     char **argv;
  483. {
  484.     register struct grouphead *gh;
  485.     register struct group *gp;
  486.     register int h;
  487.     int s;
  488.     char **ap, *gname, **p;
  489.  
  490.     if (argcount(argv) == 0) {
  491.         for (h = 0, s = 1; h < HSHSIZE; h++)
  492.             for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
  493.                 s++;
  494.         ap = (char **) salloc(s * sizeof *ap);
  495.         for (h = 0, p = ap; h < HSHSIZE; h++)
  496.             for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
  497.                 *p++ = gh->g_name;
  498.         *p = NOSTR;
  499.         sort(ap);
  500.         for (p = ap; *p != NOSTR; p++)
  501.             printgroup(*p);
  502.         return(0);
  503.     }
  504.     if (argcount(argv) == 1) {
  505.         printgroup(*argv);
  506.         return(0);
  507.     }
  508.     gname = *argv;
  509.     h = hash(gname);
  510.     if ((gh = findgroup(gname)) == NOGRP) {
  511.         gh = (struct grouphead *) calloc(sizeof *gh, 1);
  512.         gh->g_name = vcopy(gname);
  513.         gh->g_list = NOGE;
  514.         gh->g_link = groups[h];
  515.         groups[h] = gh;
  516.     }
  517.  
  518.     /*
  519.      * Insert names from the command list into the group.
  520.      * Who cares if there are duplicates?  They get tossed
  521.      * later anyway.
  522.      */
  523.  
  524.     for (ap = argv+1; *ap != NOSTR; ap++) {
  525.         gp = (struct group *) calloc(sizeof *gp, 1);
  526.         gp->ge_name = vcopy(*ap);
  527.         gp->ge_link = gh->g_list;
  528.         gh->g_list = gp;
  529.     }
  530.     return(0);
  531. }
  532.  
  533. /*
  534.  * Sort the passed string vecotor into ascending dictionary
  535.  * order.
  536.  */
  537.  
  538. sort(list)
  539.     char **list;
  540. {
  541.     register char **ap;
  542.     int diction();
  543.  
  544.     for (ap = list; *ap != NOSTR; ap++)
  545.         ;
  546.     if (ap-list < 2)
  547.         return;
  548.     qsort((char *)list, ap-list, sizeof *list, diction);
  549. }
  550.  
  551. /*
  552.  * Do a dictionary order comparison of the arguments from
  553.  * qsort.
  554.  */
  555.  
  556. diction(a, b)
  557.     register char **a, **b;
  558. {
  559.     return(strcmp(*a, *b));
  560. }
  561.  
  562. /*
  563.  * The do nothing command for comments.
  564.  */
  565.  
  566. /*ARGSUSED*/
  567. null(e)
  568. {
  569.     return 0;
  570. }
  571.  
  572. /*
  573.  * Print out the current edit file, if we are editing.
  574.  * Otherwise, print the name of the person who's mail
  575.  * we are reading.
  576.  */
  577.  
  578. file(argv)
  579.     char **argv;
  580. {
  581.     register char *cp;
  582.     int edit;
  583.  
  584.     if (argv[0] == NOSTR) {
  585.         newfileinfo();
  586.         return(0);
  587.     }
  588.  
  589.     /*
  590.      * Acker's!  Must switch to the new file.
  591.      * We use a funny interpretation --
  592.      *    # -- gets the previous file
  593.      *    % -- gets the invoker's post office box
  594.      *    %user -- gets someone else's post office box
  595.      *    & -- gets invoker's mbox file
  596.      *    string -- reads the given file
  597.      */
  598.  
  599.     cp = getfilename(argv[0], &edit);
  600.     if (cp == NOSTR)
  601.         return(-1);
  602.     if (setfile(cp, edit)) {
  603.         perror(cp);
  604.         return(-1);
  605.     }
  606.     announce(0);
  607.     return 0;
  608. }
  609.  
  610. /*
  611.  * Evaluate the string given as a new mailbox name.
  612.  * Ultimately, we want this to support a number of meta characters.
  613.  * Possibly:
  614.  *    % -- for my system mail box
  615.  *    %user -- for user's system mail box
  616.  *    # -- for previous file
  617.  *    & -- get's invoker's mbox file
  618.  *    file name -- for any other file
  619.  */
  620.  
  621. char    prevfile[PATHSIZE];
  622.  
  623. char *
  624. getfilename(name, aedit)
  625.     char *name;
  626.     int *aedit;
  627. {
  628.     register char *cp;
  629.     char savename[BUFSIZ];
  630.     char oldmailname[BUFSIZ];
  631.  
  632.     /*
  633.      * Assume we will be in "edit file" mode, until
  634.      * proven wrong.
  635.      */
  636.     *aedit = 1;
  637.     switch (*name) {
  638.     case '%':
  639.         *aedit = 0;
  640.         strcpy(prevfile, mailname);
  641.         if (name[1] != 0) {
  642.             strcpy(savename, myname);
  643.             strcpy(oldmailname, mailname);
  644.             strncpy(myname, name+1, PATHSIZE-1);
  645.             myname[PATHSIZE-1] = 0;
  646.             findmail();
  647.             cp = savestr(mailname);
  648.             strcpy(myname, savename);
  649.             strcpy(mailname, oldmailname);
  650.             return(cp);
  651.         }
  652.         strcpy(oldmailname, mailname);
  653.         findmail();
  654.         cp = savestr(mailname);
  655.         strcpy(mailname, oldmailname);
  656.         return(cp);
  657.  
  658.     case '#':
  659.         if (name[1] != 0)
  660.             goto regular;
  661.         if (prevfile[0] == 0) {
  662.             printf("No previous file\n");
  663.             return(NOSTR);
  664.         }
  665.         cp = savestr(prevfile);
  666.         strcpy(prevfile, mailname);
  667.         return(cp);
  668.  
  669.     case '&':
  670.         strcpy(prevfile, mailname);
  671.         if (name[1] == 0)
  672.             return(mbox);
  673.         /* Fall into . . . */
  674.  
  675.     default:
  676. regular:
  677.         strcpy(prevfile, mailname);
  678.         cp = expand(name);
  679.         return(cp);
  680.     }
  681. }
  682.  
  683. /*
  684.  * Expand file names like echo
  685.  */
  686.  
  687. echo(argv)
  688.     char **argv;
  689. {
  690.     register char **ap;
  691.     register char *cp;
  692.  
  693.     for (ap = argv; *ap != NOSTR; ap++) {
  694.         cp = *ap;
  695.         if ((cp = expand(cp)) != NOSTR)
  696.             printf("%s ", cp);
  697.     }
  698.     return(0);
  699. }
  700.  
  701. Respond(msgvec)
  702.     int *msgvec;
  703. {
  704.     if (value("Replyall") == NOSTR)
  705.         return (_Respond(msgvec));
  706.     else
  707.         return (_respond(msgvec));
  708. }
  709.  
  710. /*
  711.  * Reply to a series of messages by simply mailing to the senders
  712.  * and not messing around with the To: and Cc: lists as in normal
  713.  * reply.
  714.  */
  715.  
  716. _Respond(msgvec)
  717.     int msgvec[];
  718. {
  719.     struct header head;
  720.     struct message *mp;
  721.     register int s, *ap;
  722.     register char *cp, *cp2, *subject;
  723.  
  724.     for (s = 0, ap = msgvec; *ap != 0; ap++) {
  725.         mp = &message[*ap - 1];
  726.         dot = mp;
  727.         if ((cp = skin(hfield("from", mp))) != NOSTR)
  728.             s+= strlen(cp) + 1;
  729.         else
  730.             s += strlen(skin(nameof(mp, 2))) + 1;
  731.     }
  732.     if (s == 0)
  733.         return(0);
  734.     cp = salloc(s + 2);
  735.     head.h_to = cp;
  736.     for (ap = msgvec; *ap != 0; ap++) {
  737.         mp = &message[*ap - 1];
  738.         if ((cp2 = skin(hfield("from", mp))) == NOSTR)
  739.             cp2 = skin(nameof(mp, 2));
  740.         cp = copy(cp2, cp);
  741.         *cp++ = ' ';
  742.     }
  743.     *--cp = 0;
  744.     mp = &message[msgvec[0] - 1];
  745.     subject = hfield("subject", mp);
  746.     head.h_seq = 0;
  747.     if (subject == NOSTR)
  748.         subject = hfield("subj", mp);
  749.     head.h_subject = reedit(subject);
  750.     if (subject != NOSTR)
  751.         head.h_seq++;
  752.     head.h_cc = NOSTR;
  753.     head.h_bcc = NOSTR;
  754.     mail1(&head);
  755.     return(0);
  756. }
  757.  
  758. /*
  759.  * Conditional commands.  These allow one to parameterize one's
  760.  * .mailrc and do some things if sending, others if receiving.
  761.  */
  762.  
  763. ifcmd(argv)
  764.     char **argv;
  765. {
  766.     register char *cp;
  767.  
  768.     if (cond != CANY) {
  769.         printf("Illegal nested \"if\"\n");
  770.         return(1);
  771.     }
  772.     cond = CANY;
  773.     cp = argv[0];
  774.     switch (*cp) {
  775.     case 'r': case 'R':
  776.         cond = CRCV;
  777.         break;
  778.  
  779.     case 's': case 'S':
  780.         cond = CSEND;
  781.         break;
  782.  
  783.     case 't':
  784.         if (isatty(0))
  785.             cond = rcvmode ? CRCV : CSEND;
  786.         else
  787.             cond = rcvmode ? CSEND : CRCV;
  788.         break;
  789.  
  790.     default:
  791.         printf("Unrecognized if-keyword: \"%s\"\n", cp);
  792.         return(1);
  793.     }
  794.     return(0);
  795. }
  796.  
  797. /*
  798.  * Implement 'else'.  This is pretty simple -- we just
  799.  * flip over the conditional flag.
  800.  */
  801.  
  802. elsecmd()
  803. {
  804.  
  805.     switch (cond) {
  806.     case CANY:
  807.         printf("\"Else\" without matching \"if\"\n");
  808.         return(1);
  809.  
  810.     case CSEND:
  811.         cond = CRCV;
  812.         break;
  813.  
  814.     case CRCV:
  815.         cond = CSEND;
  816.         break;
  817.  
  818.     default:
  819.         printf("Mail's idea of conditions is screwed up\n");
  820.         cond = CANY;
  821.         break;
  822.     }
  823.     return(0);
  824. }
  825.  
  826. /*
  827.  * End of if statement.  Just set cond back to anything.
  828.  */
  829.  
  830. endifcmd()
  831. {
  832.  
  833.     if (cond == CANY) {
  834.         printf("\"Endif\" without matching \"if\"\n");
  835.         return(1);
  836.     }
  837.     cond = CANY;
  838.     return(0);
  839. }
  840.  
  841. /*
  842.  * Set the list of alternate names.
  843.  */
  844. alternates(namelist)
  845.     char **namelist;
  846. {
  847.     register int c;
  848.     register char **ap, **ap2, *cp;
  849.  
  850.     c = argcount(namelist) + 1;
  851.     if (c == 1) {
  852.         if (altnames == 0)
  853.             return(0);
  854.         for (ap = altnames; *ap; ap++)
  855.             printf("%s ", *ap);
  856.         printf("\n");
  857.         return(0);
  858.     }
  859.     if (altnames != 0)
  860.         cfree((char *) altnames);
  861.     altnames = (char **) calloc((unsigned) c, sizeof (char *));
  862.     for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) {
  863.         cp = (char *) calloc((unsigned) strlen(*ap) + 1, sizeof (char));
  864.         strcpy(cp, *ap);
  865.         *ap2 = cp;
  866.     }
  867.     *ap2 = 0;
  868.     return(0);
  869. }
  870.