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