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