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