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: #if !defined(lint) && defined(DOSCCS)
  35: static char sccsid[] = "@(#)cmd3.c	5.24 (Berkeley) 6/25/90";
  36: #endif
  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, 0L, -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, 0L, -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: }

Defined functions

Respond defined in line 565; used 3 times
_Respond defined in line 579; used 2 times
_respond defined in line 192; used 2 times
alternates defined in line 688; used 2 times
bangexp defined in line 93; used 1 times
  • in line 58
diction defined in line 510; used 2 times
dosh defined in line 72; used 2 times
echo defined in line 547; used 2 times
elsecmd defined in line 646; used 2 times
endifcmd defined in line 674; used 2 times
file defined in line 530; used 3 times
group defined in line 435; used 3 times
help defined in line 144; used 3 times
ifcmd defined in line 614; used 2 times
messize defined in line 318; used 2 times
null defined in line 521; used 2 times
preserve defined in line 278; used 3 times
reedit defined in line 255; used 3 times
respond defined in line 179; used 3 times
rexit defined in line 337; used 3 times
schdir defined in line 162; used 3 times
set defined in line 350; used 2 times
shell defined in line 50; used 12 times
sort defined in line 492; used 2 times
unread defined in line 301; used 2 times
unset defined in line 397; used 2 times

Defined variables

lastbang defined in line 91; used 6 times
sccsid defined in line 35; never used
Last modified: 1993-02-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4024
Valid CSS Valid XHTML 1.0 Strict