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