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