fixed # in file() command -- prevfile is now set up right
[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
d344b00c 12static char *SccsId = "@(#)cmd3.c 1.5 %G%";
ca6bb034
KS
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;
e8adee6e 25 char cmd[BUFSIZ];
ca6bb034 26
e8adee6e
KS
27 strcpy(cmd, str);
28 if (bangexp(cmd) < 0)
29 return(-1);
ca6bb034
KS
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);
e8adee6e 39 execl(Shell, Shell, "-c", cmd, 0);
ca6bb034
KS
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
57dosh(str)
58 char *str;
59{
60 int (*sig[2])(), stat[1];
61 register int t;
62 char *Shell;
ca6bb034
KS
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
e8adee6e
KS
86/*
87 * Expand the shell escape by expanding unescaped !'s into the
88 * last issued command where possible.
89 */
90
91char lastbang[128];
92
93bangexp(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)) {
107overf:
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
ca6bb034
KS
140/*
141 * Print out a nice help message from some file or another.
142 */
143
144help()
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
163schdir(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
187respond(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
242preserve(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
265messize(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
284rexit(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
296set(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
343unset(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
382group(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
439sort(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
457diction(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
467null(e)
468{
469 return(0);
470}
471
472/*
1031a04a 473 * Print out the current edit file, if we are editing.
ca6bb034
KS
474 * Otherwise, print the name of the person who's mail
475 * we are reading.
476 */
477
1031a04a
KS
478file(argv)
479 char **argv;
ca6bb034
KS
480{
481 register char *cp;
1031a04a 482 char fname[BUFSIZ];
ca6bb034 483
1031a04a
KS
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
c953e015 500 * & -- gets invoker's mbox file
1031a04a
KS
501 * string -- reads the given file
502 */
503
504 cp = getfilename(argv[0]);
505 if (cp == NOSTR)
506 return(-1);
507 return(setfile(cp, 1));
508}
509
510/*
511 * Evaluate the string given as a new mailbox name.
512 * Ultimately, we want this to support a number of meta characters.
513 * Possibly:
514 * % -- for my system mail box
515 * %user -- for user's system mail box
516 * # -- for previous file
c953e015 517 * & -- get's invoker's mbox file
1031a04a
KS
518 * file name -- for any other file
519 */
520
d344b00c 521char prevfile[PATHSIZE];
c953e015 522
1031a04a
KS
523char *
524getfilename(name)
525 char *name;
526{
527 register char *cp;
c953e015
KS
528 char savename[BUFSIZ];
529
530 switch (*name) {
531 case '%':
d344b00c 532 strcpy(prevfile, mailname);
c953e015
KS
533 if (name[1] != 0) {
534 strcpy(savename, myname);
535 strncpy(myname, name+1, PATHSIZE-1);
536 myname[PATHSIZE-1] = 0;
537 findmail();
538 cp = mailname;
539 strcpy(myname, savename);
540 return(cp);
541 }
542 findmail();
543 return(mailname);
544
545 case '#':
546 if (name[1] != 0)
547 goto regular;
548 if (prevfile[0] == 0) {
549 printf("No previous file\n");
550 return(NOSTR);
551 }
d344b00c
KS
552 strcpy(savename, prevfile);
553 strcpy(prevfile, mailname);
554 strcpy(mailname, savename);
555 return(mailname);
1031a04a 556
c953e015 557 case '&':
d344b00c 558 strcpy(prevfile, mailname);
c953e015
KS
559 if (name[1] == 0)
560 return(mbox);
561 /* Fall into . . . */
562
563 default:
564regular:
d344b00c 565 strcpy(prevfile, mailname);
c953e015
KS
566 cp = expand(name);
567 return(cp);
568 }
ca6bb034
KS
569}
570
571/*
572 * Expand file names like echo
573 */
574
575echo(argv)
576 char **argv;
577{
578 register char **ap;
579 register char *cp;
580
581 for (ap = argv; *ap != NOSTR; ap++) {
582 cp = *ap;
583 if ((cp = expand(cp)) != NOSTR)
584 printf("%s\n", cp);
585 }
586 return(0);
587}
588
589/*
590 * Reply to a series of messages by simply mailing to the senders
591 * and not messing around with the To: and Cc: lists as in normal
592 * reply.
593 */
594
595Respond(msgvec)
596 int msgvec[];
597{
598 struct header head;
599 struct message *mp;
600 register int s, *ap;
601 register char *cp, *subject;
602
603 for (s = 0, ap = msgvec; *ap != 0; ap++) {
604 mp = &message[*ap - 1];
605 dot = mp;
606 s += strlen(nameof(mp)) + 1;
607 }
608 if (s == 0)
609 return(0);
610 cp = salloc(s + 2);
611 head.h_to = cp;
612 for (ap = msgvec; *ap != 0; ap++) {
613 mp = &message[*ap - 1];
614 cp = copy(nameof(mp), cp);
615 *cp++ = ' ';
616 }
617 *--cp = 0;
618 mp = &message[msgvec[0] - 1];
619 subject = hfield("subject", mp);
620 head.h_seq = 0;
621 if (subject == NOSTR)
622 subject = hfield("subj", mp);
623 head.h_subject = subject;
624 if (subject != NOSTR)
625 head.h_seq++;
626 head.h_cc = NOSTR;
627 head.h_bcc = NOSTR;
628 mail1(&head);
629 return(0);
630}
d344b00c
KS
631
632/*
633 * Conditional commands. These allow one to parameterize one's
634 * .mailrc and do some things if sending, others if receiving.
635 */
636
637ifcmd(argv)
638 char **argv;
639{
640 register char *cp;
641
642 if (cond != CANY) {
643 printf("Illegal nested \"if\"\n");
644 return(1);
645 }
646 cond = CANY;
647 cp = argv[0];
648 switch (*cp) {
649 case 'r': case 'R':
650 cond = CRCV;
651 break;
652
653 case 's': case 'S':
654 cond = CSEND;
655 break;
656
657 default:
658 printf("Unrecognized if-keyword: \"%s\"\n", cp);
659 return(1);
660 }
661 return(0);
662}
663
664/*
665 * Implement 'else'. This is pretty simple -- we just
666 * flip over the conditional flag.
667 */
668
669elsecmd()
670{
671
672 switch (cond) {
673 case CANY:
674 printf("\"Else\" without matching \"if\"\n");
675 return(1);
676
677 case CSEND:
678 cond = CRCV;
679 break;
680
681 case CRCV:
682 cond = CSEND;
683 break;
684
685 default:
686 printf("Mail's idea of conditions is screwed up\n");
687 cond = CANY;
688 break;
689 }
690 return(0);
691}
692
693/*
694 * End of if statement. Just set cond back to anything.
695 */
696
697endifcmd()
698{
699
700 if (cond == CANY) {
701 printf("\"Endif\" without matching \"if\"\n");
702 return(1);
703 }
704 cond = CANY;
705 return(0);
706}