rationalized handling of child processes, cleaned up mail1 some more
[unix-history] / usr / src / usr.bin / mail / cmd2.c
CommitLineData
d0aeaf5a
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
0c5f72fb
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
acfc7e9b
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
d0aeaf5a
DF
16 */
17
acfc7e9b 18#ifndef lint
322c8626 19static char sccsid[] = "@(#)cmd2.c 5.9 (Berkeley) %G%";
acfc7e9b 20#endif /* not lint */
a13d1f28
KS
21
22#include "rcv.h"
828615a1 23#include <sys/wait.h>
a13d1f28
KS
24
25/*
26 * Mail -- a mail program
27 *
28 * More user commands.
29 */
30
a13d1f28
KS
31/*
32 * If any arguments were given, go to the next applicable argument
33 * following dot, otherwise, go to the next applicable message.
34 * If given as first command with no arguments, print first message.
35 */
36
37next(msgvec)
38 int *msgvec;
39{
40 register struct message *mp;
41 register int *ip, *ip2;
42 int list[2], mdot;
43
44 if (*msgvec != NULL) {
45
46 /*
47 * If some messages were supplied, find the
48 * first applicable one following dot using
49 * wrap around.
50 */
51
52 mdot = dot - &message[0] + 1;
30629819
KS
53
54 /*
55 * Find the first message in the supplied
56 * message list which follows dot.
57 */
58
a13d1f28
KS
59 for (ip = msgvec; *ip != NULL; ip++)
60 if (*ip > mdot)
61 break;
62 if (*ip == NULL)
63 ip = msgvec;
64 ip2 = ip;
65 do {
a13d1f28
KS
66 mp = &message[*ip2 - 1];
67 if ((mp->m_flag & MDELETED) == 0) {
68 dot = mp;
69 goto hitit;
70 }
30629819
KS
71 if (*ip2 != NULL)
72 ip2++;
73 if (*ip2 == NULL)
74 ip2 = msgvec;
a13d1f28
KS
75 } while (ip2 != ip);
76 printf("No messages applicable\n");
77 return(1);
78 }
79
80 /*
81 * If this is the first command, select message 1.
82 * Note that this must exist for us to get here at all.
83 */
84
799afc8f 85 if (!sawcom)
a13d1f28 86 goto hitit;
a13d1f28
KS
87
88 /*
89 * Just find the next good message after dot, no
90 * wraparound.
91 */
92
93 for (mp = dot+1; mp < &message[msgCount]; mp++)
94 if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
95 break;
96 if (mp >= &message[msgCount]) {
97 printf("At EOF\n");
98 return(0);
99 }
100 dot = mp;
101hitit:
102 /*
103 * Print dot.
104 */
105
106 list[0] = dot - &message[0] + 1;
107 list[1] = NULL;
108 return(type(list));
109}
110
111/*
c7db23a4
KS
112 * Save a message in a file. Mark the message as saved
113 * so we can discard when the user quits.
a13d1f28 114 */
a13d1f28
KS
115save(str)
116 char str[];
117{
c7db23a4 118
2de8fc95 119 return save1(str, 1, "save", saveignore);
c7db23a4
KS
120}
121
122/*
123 * Copy a message to a file without affected its saved-ness
124 */
125copycmd(str)
126 char str[];
127{
128
2de8fc95 129 return save1(str, 0, "copy", saveignore);
c7db23a4
KS
130}
131
132/*
133 * Save/copy the indicated messages at the end of the passed file name.
134 * If mark is true, mark the message "saved."
135 */
2de8fc95 136save1(str, mark, cmd, ignore)
c7db23a4 137 char str[];
2de8fc95
EW
138 char *cmd;
139 struct ignoretab *ignore;
c7db23a4 140{
a13d1f28
KS
141 register int *ip, mesg;
142 register struct message *mp;
2de8fc95
EW
143 char *file, *disp;
144 int f, *msgvec;
a13d1f28 145 FILE *obuf;
a13d1f28
KS
146
147 msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
148 if ((file = snarf(str, &f)) == NOSTR)
149 return(1);
150 if (!f) {
151 *msgvec = first(0, MMNORM);
152 if (*msgvec == NULL) {
c7db23a4 153 printf("No messages to %s.\n", cmd);
a13d1f28
KS
154 return(1);
155 }
156 msgvec[1] = NULL;
157 }
158 if (f && getmsglist(str, msgvec, 0) < 0)
159 return(1);
160 if ((file = expand(file)) == NOSTR)
161 return(1);
162 printf("\"%s\" ", file);
80187484 163 fflush(stdout);
2de8fc95 164 if (access(file, 0) >= 0)
a13d1f28
KS
165 disp = "[Appended]";
166 else
167 disp = "[New file]";
168 if ((obuf = fopen(file, "a")) == NULL) {
169 perror(NOSTR);
170 return(1);
171 }
a13d1f28
KS
172 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
173 mesg = *ip;
174 touch(mesg);
175 mp = &message[mesg-1];
2de8fc95 176 if (send(mp, obuf, ignore, NOSTR) < 0) {
a13d1f28
KS
177 perror(file);
178 fclose(obuf);
179 return(1);
180 }
c7db23a4
KS
181 if (mark)
182 mp->m_flag |= MSAVED;
a13d1f28
KS
183 }
184 fflush(obuf);
185 if (ferror(obuf))
186 perror(file);
187 fclose(obuf);
2de8fc95 188 printf("%s\n", disp);
a13d1f28
KS
189 return(0);
190}
191
192/*
193 * Write the indicated messages at the end of the passed
194 * file name, minus header and trailing blank line.
195 */
196
197swrite(str)
198 char str[];
199{
a13d1f28 200
2de8fc95 201 return save1(str, 1, "write", ignoreall);
a13d1f28
KS
202}
203
204/*
205 * Snarf the file from the end of the command line and
206 * return a pointer to it. If there is no file attached,
207 * just return NOSTR. Put a null in front of the file
208 * name so that the message list processing won't see it,
209 * unless the file name is the only thing on the line, in
210 * which case, return 0 in the reference flag variable.
211 */
212
213char *
214snarf(linebuf, flag)
215 char linebuf[];
216 int *flag;
217{
218 register char *cp;
219
220 *flag = 1;
221 cp = strlen(linebuf) + linebuf - 1;
222
223 /*
224 * Strip away trailing blanks.
225 */
226
828615a1 227 while (cp > linebuf && isspace(*cp))
a13d1f28
KS
228 cp--;
229 *++cp = 0;
230
231 /*
232 * Now search for the beginning of the file name.
233 */
234
828615a1 235 while (cp > linebuf && !isspace(*cp))
a13d1f28
KS
236 cp--;
237 if (*cp == '\0') {
238 printf("No file specified.\n");
239 return(NOSTR);
240 }
828615a1 241 if (isspace(*cp))
a13d1f28
KS
242 *cp++ = 0;
243 else
244 *flag = 0;
245 return(cp);
246}
247
248/*
249 * Delete messages.
250 */
251
252delete(msgvec)
253 int msgvec[];
254{
255 return(delm(msgvec));
256}
257
258/*
259 * Delete messages, then type the new dot.
260 */
261
262deltype(msgvec)
263 int msgvec[];
264{
265 int list[2];
12c002da 266 int lastdot;
a13d1f28 267
12c002da 268 lastdot = dot - &message[0] + 1;
a13d1f28
KS
269 if (delm(msgvec) >= 0) {
270 list[0] = dot - &message[0];
271 list[0]++;
12c002da
KS
272 if (list[0] > lastdot) {
273 touch(list[0]);
274 list[1] = NULL;
275 return(type(list));
276 }
277 printf("At EOF\n");
278 return(0);
a13d1f28
KS
279 }
280 else {
281 printf("No more messages\n");
282 return(0);
283 }
284}
285
286/*
287 * Delete the indicated messages.
288 * Set dot to some nice place afterwards.
289 * Internal interface.
290 */
291
292delm(msgvec)
293 int *msgvec;
294{
295 register struct message *mp;
296 register *ip, mesg;
297 int last;
298
299 last = NULL;
300 for (ip = msgvec; *ip != NULL; ip++) {
301 mesg = *ip;
302 touch(mesg);
303 mp = &message[mesg-1];
3c139aaf
KS
304 mp->m_flag |= MDELETED|MTOUCH;
305 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
a13d1f28
KS
306 last = mesg;
307 }
308 if (last != NULL) {
309 dot = &message[last-1];
310 last = first(0, MDELETED);
311 if (last != NULL) {
312 dot = &message[last-1];
313 return(0);
314 }
315 else {
316 dot = &message[0];
317 return(-1);
318 }
319 }
320
321 /*
322 * Following can't happen -- it keeps lint happy
323 */
324
325 return(-1);
326}
327
328/*
329 * Undelete the indicated messages.
330 */
331
332undelete(msgvec)
333 int *msgvec;
334{
335 register struct message *mp;
336 register *ip, mesg;
337
338 for (ip = msgvec; ip-msgvec < msgCount; ip++) {
339 mesg = *ip;
340 if (mesg == 0)
341 return;
342 touch(mesg);
343 mp = &message[mesg-1];
344 dot = mp;
345 mp->m_flag &= ~MDELETED;
346 }
347}
348
349/*
350 * Interactively dump core on "core"
351 */
352
353core()
354{
322c8626
EW
355 int pid;
356 extern union wait wait_status;
a13d1f28 357
322c8626
EW
358 switch (pid = vfork()) {
359 case -1:
a13d1f28
KS
360 perror("fork");
361 return(1);
322c8626 362 case 0:
a13d1f28
KS
363 abort();
364 _exit(1);
365 }
366 printf("Okie dokie");
367 fflush(stdout);
322c8626
EW
368 wait_child(pid);
369 if (wait_status.w_coredump)
370 printf(" -- Core dumped.\n");
a13d1f28 371 else
322c8626 372 printf(" -- Can't dump core.\n");
828615a1 373 return 0;
a13d1f28 374}
47e37b8b
KS
375
376/*
377 * Clobber as many bytes of stack as the user requests.
378 */
379clobber(argv)
380 char **argv;
381{
382 register int times;
383
384 if (argv[0] == 0)
385 times = 1;
386 else
387 times = (atoi(argv[0]) + 511) / 512;
ab61fde0 388 clob1(times);
47e37b8b
KS
389}
390
391/*
392 * Clobber the stack.
393 */
ab61fde0 394clob1(n)
47e37b8b
KS
395{
396 char buf[512];
397 register char *cp;
398
399 if (n <= 0)
400 return;
401 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
402 ;
ab61fde0 403 clob1(n - 1);
47e37b8b 404}
eed74ec1 405
46053c99
S
406/*
407 * Add the given header fields to the retained list.
408 * If no arguments, print the current list of retained fields.
409 */
410retfield(list)
411 char *list[];
412{
46053c99 413
887efe38 414 return ignore1(list, ignore + 1, "retained");
46053c99
S
415}
416
417/*
887efe38
EW
418 * Add the given header fields to the ignored list.
419 * If no arguments, print the current list of ignored fields.
46053c99 420 */
887efe38
EW
421igfield(list)
422 char *list[];
46053c99 423{
46053c99 424
887efe38 425 return ignore1(list, ignore, "ignored");
46053c99
S
426}
427
887efe38
EW
428saveretfield(list)
429 char *list[];
430{
431
432 return ignore1(list, saveignore + 1, "retained");
433}
434
435saveigfield(list)
eed74ec1
KS
436 char *list[];
437{
887efe38
EW
438
439 return ignore1(list, saveignore, "ignored");
440}
441
442ignore1(list, tab, which)
443 char *list[];
444 struct ignoretab *tab;
445 char *which;
446{
eed74ec1
KS
447 char field[BUFSIZ];
448 register int h;
449 register struct ignore *igp;
450 char **ap;
451
452 if (argcount(list) == 0)
887efe38 453 return igshow(tab, which);
eed74ec1
KS
454 for (ap = list; *ap != 0; ap++) {
455 istrcpy(field, *ap);
887efe38
EW
456 if (member(field, tab))
457 continue;
eed74ec1
KS
458 h = hash(field);
459 igp = (struct ignore *) calloc(1, sizeof (struct ignore));
828615a1
EW
460 igp->i_field = calloc((unsigned) strlen(field) + 1,
461 sizeof (char));
eed74ec1 462 strcpy(igp->i_field, field);
887efe38
EW
463 igp->i_link = tab->i_head[h];
464 tab->i_head[h] = igp;
465 tab->i_count++;
eed74ec1 466 }
887efe38 467 return 0;
eed74ec1
KS
468}
469
470/*
887efe38 471 * Print out all currently retained fields.
eed74ec1 472 */
887efe38
EW
473igshow(tab, which)
474 struct ignoretab *tab;
475 char *which;
eed74ec1 476{
887efe38 477 register int h;
eed74ec1 478 struct ignore *igp;
93be40ac
KS
479 char **ap, **ring;
480 int igcomp();
eed74ec1 481
887efe38
EW
482 if (tab->i_count == 0) {
483 printf("No fields currently being %s.\n", which);
484 return 0;
93be40ac 485 }
887efe38 486 ring = (char **) salloc((tab->i_count + 1) * sizeof (char *));
93be40ac
KS
487 ap = ring;
488 for (h = 0; h < HSHSIZE; h++)
887efe38 489 for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
93be40ac
KS
490 *ap++ = igp->i_field;
491 *ap = 0;
887efe38 492 qsort((char *) ring, tab->i_count, sizeof (char *), igcomp);
93be40ac
KS
493 for (ap = ring; *ap != 0; ap++)
494 printf("%s\n", *ap);
887efe38 495 return 0;
eed74ec1 496}
93be40ac
KS
497
498/*
499 * Compare two names for sorting ignored field list.
500 */
501igcomp(l, r)
502 char **l, **r;
503{
504
887efe38 505 return strcmp(*l, *r);
93be40ac 506}