xref: /original-bsd/usr.bin/mail/cmd3.c (revision ba72ef4c)
1 #
2 
3 #include "rcv.h"
4 #include <sys/stat.h>
5 
6 /*
7  * Mail -- a mail program
8  *
9  * Still more user commands.
10  */
11 
12 static char *SccsId = "@(#)cmd3.c	1.3 10/09/80";
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] = signal(t, SIG_IGN);
34 	t = vfork();
35 	if (t == 0) {
36 		for (t = 2; t < 4; t++)
37 			if (sig[t-2] != SIG_IGN)
38 				signal(t, SIG_DFL);
39 		execl(Shell, Shell, "-c", cmd, 0);
40 		perror(Shell);
41 		_exit(1);
42 	}
43 	while (wait(stat) != t)
44 		;
45 	if (t == -1)
46 		perror("fork");
47 	for (t = 2; t < 4; t++)
48 		signal(t, sig[t-2]);
49 	printf("!\n");
50 	return(0);
51 }
52 
53 /*
54  * Fork an interactive shell.
55  */
56 
57 dosh(str)
58 	char *str;
59 {
60 	int (*sig[2])(), stat[1];
61 	register int t;
62 	char *Shell;
63 	if ((Shell = value("SHELL")) == NOSTR)
64 		Shell = SHELL;
65 	for (t = 2; t < 4; t++)
66 		sig[t-2] = signal(t, SIG_IGN);
67 	t = vfork();
68 	if (t == 0) {
69 		for (t = 2; t < 4; t++)
70 			if (sig[t-2] != SIG_IGN)
71 				signal(t, SIG_DFL);
72 		execl(Shell, Shell, 0);
73 		perror(Shell);
74 		_exit(1);
75 	}
76 	while (wait(stat) != t)
77 		;
78 	if (t == -1)
79 		perror("fork");
80 	for (t = 2; t < 4; t++)
81 		signal(t, sig[t-2]);
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(HELPFILE, "r")) == NULL) {
150 		printf("No help just now.\n");
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 
163 schdir(str)
164 	char *str;
165 {
166 	register char *cp;
167 
168 	for (cp = str; *cp == ' '; cp++)
169 		;
170 	if (*cp == '\0')
171 		cp = homedir;
172 	else
173 		if ((cp = expand(cp)) == NOSTR)
174 			return(1);
175 	if (chdir(cp) < 0) {
176 		perror(cp);
177 		return(1);
178 	}
179 	return(0);
180 }
181 
182 /*
183  * Reply to a list of messages.  Extract each name from the
184  * message header and send them off to mail1()
185  */
186 
187 respond(msgvec)
188 	int *msgvec;
189 {
190 	struct message *mp;
191 	char *cp, buf[2 * LINESIZE], *rcv;
192 	struct name *np;
193 	struct header head;
194 	char *netmap();
195 
196 	if (msgvec[1] != 0) {
197 		printf("Sorry, can't reply to multiple messages at once\n");
198 		return(1);
199 	}
200 	mp = &message[msgvec[0] - 1];
201 	dot = mp;
202 	rcv = nameof(mp);
203 	strcpy(buf, "");
204 	cp = hfield("to", mp);
205 	if (cp != NOSTR)
206 		strcpy(buf, cp);
207 	np = elide(extract(buf, GTO));
208 	/* rcv = rename(rcv); */
209 	mapf(np, rcv);
210 	np = delname(np, myname);
211 	head.h_seq = 1;
212 	cp = detract(np, 0);
213 	if (cp != NOSTR) {
214 		strcpy(buf, cp);
215 		strcat(buf, " ");
216 		strcat(buf, rcv);
217 	}
218 	else
219 		strcpy(buf, rcv);
220 	head.h_to = buf;
221 	head.h_subject = hfield("subject", mp);
222 	if (head.h_subject == NOSTR)
223 		head.h_subject = hfield("subj", mp);
224 	head.h_cc = NOSTR;
225 	cp = hfield("cc", mp);
226 	if (cp != NOSTR) {
227 		np = elide(extract(cp, GCC));
228 		mapf(np, rcv);
229 		np = delname(np, myname);
230 		head.h_cc = detract(np, 0);
231 	}
232 	head.h_bcc = NOSTR;
233 	mail1(&head);
234 	return(0);
235 }
236 
237 /*
238  * Preserve the named messages, so that they will be sent
239  * back to the system mailbox.
240  */
241 
242 preserve(msgvec)
243 	int *msgvec;
244 {
245 	register struct message *mp;
246 	register int *ip, mesg;
247 
248 	if (edit) {
249 		printf("Cannot \"preserve\" in edit mode\n");
250 		return(1);
251 	}
252 	for (ip = msgvec; *ip != NULL; ip++) {
253 		mesg = *ip;
254 		mp = &message[mesg-1];
255 		mp->m_flag |= MPRESERVE;
256 		dot = mp;
257 	}
258 	return(0);
259 }
260 
261 /*
262  * Print the size of each message.
263  */
264 
265 messize(msgvec)
266 	int *msgvec;
267 {
268 	register struct message *mp;
269 	register int *ip, mesg;
270 
271 	for (ip = msgvec; *ip != NULL; ip++) {
272 		mesg = *ip;
273 		mp = &message[mesg-1];
274 		printf("%d: %d\n", mesg, msize(mp));
275 	}
276 	return(0);
277 }
278 
279 /*
280  * Quit quickly.  If we are sourcing, just pop the input level
281  * by returning an error.
282  */
283 
284 rexit(e)
285 {
286 	if (sourcing)
287 		return(1);
288 	exit(e);
289 }
290 
291 /*
292  * Set or display a variable value.  Syntax is similar to that
293  * of csh.
294  */
295 
296 set(arglist)
297 	char **arglist;
298 {
299 	register struct var *vp;
300 	register char *cp, *cp2;
301 	char varbuf[BUFSIZ], **ap, **p;
302 	int errs, h, s;
303 
304 	if (argcount(arglist) == 0) {
305 		for (h = 0, s = 1; h < HSHSIZE; h++)
306 			for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
307 				s++;
308 		ap = (char **) salloc(s * sizeof *ap);
309 		for (h = 0, p = ap; h < HSHSIZE; h++)
310 			for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
311 				*p++ = vp->v_name;
312 		*p = NOSTR;
313 		sort(ap);
314 		for (p = ap; *p != NOSTR; p++)
315 			printf("%s\t%s\n", *p, value(*p));
316 		return(0);
317 	}
318 	errs = 0;
319 	for (ap = arglist; *ap != NOSTR; ap++) {
320 		cp = *ap;
321 		cp2 = varbuf;
322 		while (*cp != '=' && *cp != '\0')
323 			*cp2++ = *cp++;
324 		*cp2 = '\0';
325 		if (*cp == '\0')
326 			cp = "";
327 		else
328 			cp++;
329 		if (equal(varbuf, "")) {
330 			printf("Non-null variable name required\n");
331 			errs++;
332 			continue;
333 		}
334 		assign(varbuf, cp);
335 	}
336 	return(errs);
337 }
338 
339 /*
340  * Unset a bunch of variable values.
341  */
342 
343 unset(arglist)
344 	char **arglist;
345 {
346 	register struct var *vp, *vp2;
347 	register char *cp;
348 	int errs, h;
349 	char **ap;
350 
351 	errs = 0;
352 	for (ap = arglist; *ap != NOSTR; ap++) {
353 		if ((vp2 = lookup(*ap)) == NOVAR) {
354 			if (!sourcing) {
355 				printf("\"%s\": undefined variable\n", *ap);
356 				errs++;
357 			}
358 			continue;
359 		}
360 		h = hash(*ap);
361 		if (vp2 == variables[h]) {
362 			variables[h] = variables[h]->v_link;
363 			vfree(vp2->v_name);
364 			vfree(vp2->v_value);
365 			cfree(vp2);
366 			continue;
367 		}
368 		for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
369 			;
370 		vp->v_link = vp2->v_link;
371 		vfree(vp2->v_name);
372 		vfree(vp2->v_value);
373 		cfree(vp2);
374 	}
375 	return(errs);
376 }
377 
378 /*
379  * Put add users to a group.
380  */
381 
382 group(argv)
383 	char **argv;
384 {
385 	register struct grouphead *gh;
386 	register struct group *gp;
387 	register int h;
388 	int s;
389 	char **ap, *gname, **p;
390 
391 	if (argcount(argv) == 0) {
392 		for (h = 0, s = 1; h < HSHSIZE; h++)
393 			for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
394 				s++;
395 		ap = (char **) salloc(s * sizeof *ap);
396 		for (h = 0, p = ap; h < HSHSIZE; h++)
397 			for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
398 				*p++ = gh->g_name;
399 		*p = NOSTR;
400 		sort(ap);
401 		for (p = ap; *p != NOSTR; p++)
402 			printgroup(*p);
403 		return(0);
404 	}
405 	if (argcount(argv) == 1) {
406 		printgroup(*argv);
407 		return(0);
408 	}
409 	gname = *argv;
410 	h = hash(gname);
411 	if ((gh = findgroup(gname)) == NOGRP) {
412 		gh = (struct grouphead *) calloc(sizeof *gh, 1);
413 		gh->g_name = vcopy(gname);
414 		gh->g_list = NOGE;
415 		gh->g_link = groups[h];
416 		groups[h] = gh;
417 	}
418 
419 	/*
420 	 * Insert names from the command list into the group.
421 	 * Who cares if there are duplicates?  They get tossed
422 	 * later anyway.
423 	 */
424 
425 	for (ap = argv+1; *ap != NOSTR; ap++) {
426 		gp = (struct group *) calloc(sizeof *gp, 1);
427 		gp->ge_name = vcopy(*ap);
428 		gp->ge_link = gh->g_list;
429 		gh->g_list = gp;
430 	}
431 	return(0);
432 }
433 
434 /*
435  * Sort the passed string vecotor into ascending dictionary
436  * order.
437  */
438 
439 sort(list)
440 	char **list;
441 {
442 	register char **ap;
443 	int diction();
444 
445 	for (ap = list; *ap != NOSTR; ap++)
446 		;
447 	if (ap-list < 2)
448 		return;
449 	qsort(list, ap-list, sizeof *list, diction);
450 }
451 
452 /*
453  * Do a dictionary order comparison of the arguments from
454  * qsort.
455  */
456 
457 diction(a, b)
458 	register char **a, **b;
459 {
460 	return(strcmp(*a, *b));
461 }
462 
463 /*
464  * The do nothing command for comments.
465  */
466 
467 null(e)
468 {
469 	return(0);
470 }
471 
472 /*
473  * Print out the current edit file, if we are editing.
474  * Otherwise, print the name of the person who's mail
475  * we are reading.
476  */
477 
478 file(argv)
479 	char **argv;
480 {
481 	register char *cp;
482 	char fname[BUFSIZ];
483 
484 	if (argv[0] == NOSTR) {
485 		if (edit)
486 			printf("Reading \"%s\"", editfile);
487 		else
488 			printf("Reading %s's mail",
489 			    rindex(mailname, '/') + 1);
490 		printf("; %d message(s)\n", msgCount);
491 		return(0);
492 	}
493 
494 	/*
495 	 * Acker's!  Must switch to the new file.
496 	 * We use a funny interpretation --
497 	 *	# -- gets the previous file
498 	 *	% -- gets the invoker's post office box
499 	 *	%user -- gets someone else's post office box
500 	 *	string -- reads the given file
501 	 */
502 
503 	cp = getfilename(argv[0]);
504 	if (cp == NOSTR)
505 		return(-1);
506 	return(setfile(cp, 1));
507 }
508 
509 /*
510  * Evaluate the string given as a new mailbox name.
511  * Ultimately, we want this to support a number of meta characters.
512  * Possibly:
513  *	% -- for my system mail box
514  *	%user -- for user's system mail box
515  *	# -- for previous file
516  *	file name -- for any other file
517  */
518 
519 char *
520 getfilename(name)
521 	char *name;
522 {
523 	register char *cp;
524 
525 	cp = expand(name);
526 	return(cp);
527 }
528 
529 /*
530  * Expand file names like echo
531  */
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 			printf("%s\n", cp);
543 	}
544 	return(0);
545 }
546 
547 /*
548  * Reply to a series of messages by simply mailing to the senders
549  * and not messing around with the To: and Cc: lists as in normal
550  * reply.
551  */
552 
553 Respond(msgvec)
554 	int msgvec[];
555 {
556 	struct header head;
557 	struct message *mp;
558 	register int s, *ap;
559 	register char *cp, *subject;
560 
561 	for (s = 0, ap = msgvec; *ap != 0; ap++) {
562 		mp = &message[*ap - 1];
563 		dot = mp;
564 		s += strlen(nameof(mp)) + 1;
565 	}
566 	if (s == 0)
567 		return(0);
568 	cp = salloc(s + 2);
569 	head.h_to = cp;
570 	for (ap = msgvec; *ap != 0; ap++) {
571 		mp = &message[*ap - 1];
572 		cp = copy(nameof(mp), cp);
573 		*cp++ = ' ';
574 	}
575 	*--cp = 0;
576 	mp = &message[msgvec[0] - 1];
577 	subject = hfield("subject", mp);
578 	head.h_seq = 0;
579 	if (subject == NOSTR)
580 		subject = hfield("subj", mp);
581 	head.h_subject = subject;
582 	if (subject != NOSTR)
583 		head.h_seq++;
584 	head.h_cc = NOSTR;
585 	head.h_bcc = NOSTR;
586 	mail1(&head);
587 	return(0);
588 }
589