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