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