date and time created 80/10/08 09:49:26 by kas
[unix-history] / usr / src / usr.bin / mail / cmd3.c
CommitLineData
ca6bb034
KS
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
12static char *SccsId = "@(#)cmd3.c 1.1 %G%";
13
14/*
15 * Process a shell escape by saving signals, ignoring signals,
16 * and forking a sh -c
17 */
18
19shell(str)
20 char *str;
21{
22 int (*sig[2])(), stat[1];
23 register int t;
24 char *Shell;
25
26 if ((Shell = value("SHELL")) == NOSTR)
27 Shell = SHELL;
28 for (t = 2; t < 4; t++)
29 sig[t-2] = signal(t, SIG_IGN);
30 t = vfork();
31 if (t == 0) {
32 for (t = 2; t < 4; t++)
33 if (sig[t-2] != SIG_IGN)
34 signal(t, SIG_DFL);
35 execl(Shell, Shell, "-c", str, 0);
36 perror(Shell);
37 _exit(1);
38 }
39 while (wait(stat) != t)
40 ;
41 if (t == -1)
42 perror("fork");
43 for (t = 2; t < 4; t++)
44 signal(t, sig[t-2]);
45 printf("!\n");
46 return(0);
47}
48
49/*
50 * Fork an interactive shell.
51 */
52
53dosh(str)
54 char *str;
55{
56 int (*sig[2])(), stat[1];
57 register int t;
58 char *Shell;
59
60 if ((Shell = value("SHELL")) == NOSTR)
61 Shell = SHELL;
62 for (t = 2; t < 4; t++)
63 sig[t-2] = signal(t, SIG_IGN);
64 t = vfork();
65 if (t == 0) {
66 for (t = 2; t < 4; t++)
67 if (sig[t-2] != SIG_IGN)
68 signal(t, SIG_DFL);
69 execl(Shell, Shell, 0);
70 perror(Shell);
71 _exit(1);
72 }
73 while (wait(stat) != t)
74 ;
75 if (t == -1)
76 perror("fork");
77 for (t = 2; t < 4; t++)
78 signal(t, sig[t-2]);
79 putchar('\n');
80 return(0);
81}
82
83/*
84 * Print out a nice help message from some file or another.
85 */
86
87help()
88{
89 register c;
90 register FILE *f;
91
92 if ((f = fopen(HELPFILE, "r")) == NULL) {
93 printf("No help just now.\n");
94 return(1);
95 }
96 while ((c = getc(f)) != EOF)
97 putchar(c);
98 fclose(f);
99 return(0);
100}
101
102/*
103 * Change user's working directory.
104 */
105
106schdir(str)
107 char *str;
108{
109 register char *cp;
110
111 for (cp = str; *cp == ' '; cp++)
112 ;
113 if (*cp == '\0')
114 cp = homedir;
115 else
116 if ((cp = expand(cp)) == NOSTR)
117 return(1);
118 if (chdir(cp) < 0) {
119 perror(cp);
120 return(1);
121 }
122 return(0);
123}
124
125/*
126 * Reply to a list of messages. Extract each name from the
127 * message header and send them off to mail1()
128 */
129
130respond(msgvec)
131 int *msgvec;
132{
133 struct message *mp;
134 char *cp, buf[2 * LINESIZE], *rcv;
135 struct name *np;
136 struct header head;
137 char *netmap();
138
139 if (msgvec[1] != 0) {
140 printf("Sorry, can't reply to multiple messages at once\n");
141 return(1);
142 }
143 mp = &message[msgvec[0] - 1];
144 dot = mp;
145 rcv = nameof(mp);
146 strcpy(buf, "");
147 cp = hfield("to", mp);
148 if (cp != NOSTR)
149 strcpy(buf, cp);
150 np = elide(extract(buf, GTO));
151 /* rcv = rename(rcv); */
152 mapf(np, rcv);
153 np = delname(np, myname);
154 head.h_seq = 1;
155 cp = detract(np, 0);
156 if (cp != NOSTR) {
157 strcpy(buf, cp);
158 strcat(buf, " ");
159 strcat(buf, rcv);
160 }
161 else
162 strcpy(buf, rcv);
163 head.h_to = buf;
164 head.h_subject = hfield("subject", mp);
165 if (head.h_subject == NOSTR)
166 head.h_subject = hfield("subj", mp);
167 head.h_cc = NOSTR;
168 cp = hfield("cc", mp);
169 if (cp != NOSTR) {
170 np = elide(extract(cp, GCC));
171 mapf(np, rcv);
172 np = delname(np, myname);
173 head.h_cc = detract(np, 0);
174 }
175 head.h_bcc = NOSTR;
176 mail1(&head);
177 return(0);
178}
179
180/*
181 * Preserve the named messages, so that they will be sent
182 * back to the system mailbox.
183 */
184
185preserve(msgvec)
186 int *msgvec;
187{
188 register struct message *mp;
189 register int *ip, mesg;
190
191 if (edit) {
192 printf("Cannot \"preserve\" in edit mode\n");
193 return(1);
194 }
195 for (ip = msgvec; *ip != NULL; ip++) {
196 mesg = *ip;
197 mp = &message[mesg-1];
198 mp->m_flag |= MPRESERVE;
199 dot = mp;
200 }
201 return(0);
202}
203
204/*
205 * Print the size of each message.
206 */
207
208messize(msgvec)
209 int *msgvec;
210{
211 register struct message *mp;
212 register int *ip, mesg;
213
214 for (ip = msgvec; *ip != NULL; ip++) {
215 mesg = *ip;
216 mp = &message[mesg-1];
217 printf("%d: %d\n", mesg, msize(mp));
218 }
219 return(0);
220}
221
222/*
223 * Quit quickly. If we are sourcing, just pop the input level
224 * by returning an error.
225 */
226
227rexit(e)
228{
229 if (sourcing)
230 return(1);
231 exit(e);
232}
233
234/*
235 * Set or display a variable value. Syntax is similar to that
236 * of csh.
237 */
238
239set(arglist)
240 char **arglist;
241{
242 register struct var *vp;
243 register char *cp, *cp2;
244 char varbuf[BUFSIZ], **ap, **p;
245 int errs, h, s;
246
247 if (argcount(arglist) == 0) {
248 for (h = 0, s = 1; h < HSHSIZE; h++)
249 for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
250 s++;
251 ap = (char **) salloc(s * sizeof *ap);
252 for (h = 0, p = ap; h < HSHSIZE; h++)
253 for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
254 *p++ = vp->v_name;
255 *p = NOSTR;
256 sort(ap);
257 for (p = ap; *p != NOSTR; p++)
258 printf("%s\t%s\n", *p, value(*p));
259 return(0);
260 }
261 errs = 0;
262 for (ap = arglist; *ap != NOSTR; ap++) {
263 cp = *ap;
264 cp2 = varbuf;
265 while (*cp != '=' && *cp != '\0')
266 *cp2++ = *cp++;
267 *cp2 = '\0';
268 if (*cp == '\0')
269 cp = "";
270 else
271 cp++;
272 if (equal(varbuf, "")) {
273 printf("Non-null variable name required\n");
274 errs++;
275 continue;
276 }
277 assign(varbuf, cp);
278 }
279 return(errs);
280}
281
282/*
283 * Unset a bunch of variable values.
284 */
285
286unset(arglist)
287 char **arglist;
288{
289 register struct var *vp, *vp2;
290 register char *cp;
291 int errs, h;
292 char **ap;
293
294 errs = 0;
295 for (ap = arglist; *ap != NOSTR; ap++) {
296 if ((vp2 = lookup(*ap)) == NOVAR) {
297 if (!sourcing) {
298 printf("\"%s\": undefined variable\n", *ap);
299 errs++;
300 }
301 continue;
302 }
303 h = hash(*ap);
304 if (vp2 == variables[h]) {
305 variables[h] = variables[h]->v_link;
306 vfree(vp2->v_name);
307 vfree(vp2->v_value);
308 cfree(vp2);
309 continue;
310 }
311 for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
312 ;
313 vp->v_link = vp2->v_link;
314 vfree(vp2->v_name);
315 vfree(vp2->v_value);
316 cfree(vp2);
317 }
318 return(errs);
319}
320
321/*
322 * Put add users to a group.
323 */
324
325group(argv)
326 char **argv;
327{
328 register struct grouphead *gh;
329 register struct group *gp;
330 register int h;
331 int s;
332 char **ap, *gname, **p;
333
334 if (argcount(argv) == 0) {
335 for (h = 0, s = 1; h < HSHSIZE; h++)
336 for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
337 s++;
338 ap = (char **) salloc(s * sizeof *ap);
339 for (h = 0, p = ap; h < HSHSIZE; h++)
340 for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
341 *p++ = gh->g_name;
342 *p = NOSTR;
343 sort(ap);
344 for (p = ap; *p != NOSTR; p++)
345 printgroup(*p);
346 return(0);
347 }
348 if (argcount(argv) == 1) {
349 printgroup(*argv);
350 return(0);
351 }
352 gname = *argv;
353 h = hash(gname);
354 if ((gh = findgroup(gname)) == NOGRP) {
355 gh = (struct grouphead *) calloc(sizeof *gh, 1);
356 gh->g_name = vcopy(gname);
357 gh->g_list = NOGE;
358 gh->g_link = groups[h];
359 groups[h] = gh;
360 }
361
362 /*
363 * Insert names from the command list into the group.
364 * Who cares if there are duplicates? They get tossed
365 * later anyway.
366 */
367
368 for (ap = argv+1; *ap != NOSTR; ap++) {
369 gp = (struct group *) calloc(sizeof *gp, 1);
370 gp->ge_name = vcopy(*ap);
371 gp->ge_link = gh->g_list;
372 gh->g_list = gp;
373 }
374 return(0);
375}
376
377/*
378 * Sort the passed string vecotor into ascending dictionary
379 * order.
380 */
381
382sort(list)
383 char **list;
384{
385 register char **ap;
386 int diction();
387
388 for (ap = list; *ap != NOSTR; ap++)
389 ;
390 if (ap-list < 2)
391 return;
392 qsort(list, ap-list, sizeof *list, diction);
393}
394
395/*
396 * Do a dictionary order comparison of the arguments from
397 * qsort.
398 */
399
400diction(a, b)
401 register char **a, **b;
402{
403 return(strcmp(*a, *b));
404}
405
406/*
407 * The do nothing command for comments.
408 */
409
410null(e)
411{
412 return(0);
413}
414
415/*
416 * Print out the current edit file, if we are editting.
417 * Otherwise, print the name of the person who's mail
418 * we are reading.
419 */
420
421file(e)
422{
423 register char *cp;
424
425 if (edit)
426 printf("Reading \"%s\"\n", editfile);
427 else
428 printf("Reading %s's mail\n", rindex(mailname, '/') + 1);
429 return(0);
430}
431
432/*
433 * Expand file names like echo
434 */
435
436echo(argv)
437 char **argv;
438{
439 register char **ap;
440 register char *cp;
441
442 for (ap = argv; *ap != NOSTR; ap++) {
443 cp = *ap;
444 if ((cp = expand(cp)) != NOSTR)
445 printf("%s\n", cp);
446 }
447 return(0);
448}
449
450/*
451 * Reply to a series of messages by simply mailing to the senders
452 * and not messing around with the To: and Cc: lists as in normal
453 * reply.
454 */
455
456Respond(msgvec)
457 int msgvec[];
458{
459 struct header head;
460 struct message *mp;
461 register int s, *ap;
462 register char *cp, *subject;
463
464 for (s = 0, ap = msgvec; *ap != 0; ap++) {
465 mp = &message[*ap - 1];
466 dot = mp;
467 s += strlen(nameof(mp)) + 1;
468 }
469 if (s == 0)
470 return(0);
471 cp = salloc(s + 2);
472 head.h_to = cp;
473 for (ap = msgvec; *ap != 0; ap++) {
474 mp = &message[*ap - 1];
475 cp = copy(nameof(mp), cp);
476 *cp++ = ' ';
477 }
478 *--cp = 0;
479 mp = &message[msgvec[0] - 1];
480 subject = hfield("subject", mp);
481 head.h_seq = 0;
482 if (subject == NOSTR)
483 subject = hfield("subj", mp);
484 head.h_subject = subject;
485 if (subject != NOSTR)
486 head.h_seq++;
487 head.h_cc = NOSTR;
488 head.h_bcc = NOSTR;
489 mail1(&head);
490 return(0);
491}